diff options
| author | Michal Meloun <mmel@FreeBSD.org> | 2018-08-13 08:47:54 +0000 |
|---|---|---|
| committer | Michal Meloun <mmel@FreeBSD.org> | 2018-08-13 08:47:54 +0000 |
| commit | dcf4b76db04146a639799b06d1e2c0ff8134e0fe (patch) | |
| tree | 0e6a6fc28d5d46346b8fddb47bef782272d8092b /sys/dev/extres | |
| parent | f66e7834318defce616592f6a87b04c7f02f3c54 (diff) | |
Notes
Diffstat (limited to 'sys/dev/extres')
| -rw-r--r-- | sys/dev/extres/regulator/regnode_if.m | 18 | ||||
| -rw-r--r-- | sys/dev/extres/regulator/regulator.c | 4 | ||||
| -rw-r--r-- | sys/dev/extres/regulator/regulator_fixed.c | 47 |
3 files changed, 65 insertions, 4 deletions
diff --git a/sys/dev/extres/regulator/regnode_if.m b/sys/dev/extres/regulator/regnode_if.m index d92f26f29fcc..dfe59544a24e 100644 --- a/sys/dev/extres/regulator/regnode_if.m +++ b/sys/dev/extres/regulator/regnode_if.m @@ -31,6 +31,15 @@ HEADER { struct regnode; } +CODE { + static int + regnode_default_stop(struct regnode *regnode, int *udelay) + { + + return(REGNODE_ENABLE(regnode, false, udelay)); + } +} + # # Initialize regulator # Returns 0 on success or a standard errno value. @@ -80,3 +89,12 @@ METHOD int get_voltage { struct regnode *regnode; int *uvolt; }; + +# +# Stop (shutdown) regulator +# Returns 0 on success or a standard errno value. +# +METHOD int stop { + struct regnode *regnode; + int *udelay; +} DEFAULT regnode_default_stop; diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/extres/regulator/regulator.c index 10307b135dea..f441df3226ca 100644 --- a/sys/dev/extres/regulator/regulator.c +++ b/sys/dev/extres/regulator/regulator.c @@ -515,7 +515,7 @@ regnode_stop(struct regnode *regnode, int depth) /* Disable regulator for each node in chain, starting from consumer */ if ((regnode->enable_cnt == 0) && ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) { - rv = REGNODE_ENABLE(regnode, false, &udelay); + rv = REGNODE_STOP(regnode, &udelay); if (rv != 0) { REGNODE_UNLOCK(regnode); return (rv); @@ -527,7 +527,7 @@ regnode_stop(struct regnode *regnode, int depth) rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); - if (regnode->parent != NULL) + if (regnode->parent != NULL && regnode->parent->enable_cnt == 0) rv = regnode_stop(regnode->parent, depth + 1); return (rv); } diff --git a/sys/dev/extres/regulator/regulator_fixed.c b/sys/dev/extres/regulator/regulator_fixed.c index 1438181eafe5..1362d3a236cc 100644 --- a/sys/dev/extres/regulator/regulator_fixed.c +++ b/sys/dev/extres/regulator/regulator_fixed.c @@ -56,6 +56,7 @@ struct gpio_entry { struct gpiobus_pin gpio_pin; int use_cnt; int enable_cnt; + bool always_on; }; static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list); static struct mtx gpio_list_mtx; @@ -71,12 +72,14 @@ static int regnode_fixed_init(struct regnode *regnode); static int regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay); static int regnode_fixed_status(struct regnode *regnode, int *status); +static int regnode_fixed_stop(struct regnode *regnode, int *udelay); static regnode_method_t regnode_fixed_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, regnode_fixed_init), REGNODEMETHOD(regnode_enable, regnode_fixed_enable), REGNODEMETHOD(regnode_status, regnode_fixed_status), + REGNODEMETHOD(regnode_stop, regnode_fixed_stop), REGNODEMETHOD_END }; DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods, @@ -188,8 +191,6 @@ regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) dev = regnode_get_device(regnode); *udelay = 0; - if (sc->param->always_on && !enable) - return (0); if (sc->gpio_entry == NULL) return (0); pin = &sc->gpio_entry->gpio_pin; @@ -204,6 +205,8 @@ regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) if (sc->gpio_entry->enable_cnt >= 1) return (0); } + if (sc->gpio_entry->always_on && !enable) + return (0); if (!sc->param->enable_active_high) enable = !enable; rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); @@ -215,6 +218,42 @@ regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) return (0); } +/* + * Stop (physicaly shutdown) regulator. + * Take shared GPIO pins in account + */ +static int +regnode_fixed_stop(struct regnode *regnode, int *udelay) +{ + device_t dev; + struct regnode_fixed_sc *sc; + struct gpiobus_pin *pin; + int rv; + + sc = regnode_get_softc(regnode); + dev = regnode_get_device(regnode); + + *udelay = 0; + if (sc->gpio_entry == NULL) + return (0); + if (sc->gpio_entry->always_on) + return (0); + pin = &sc->gpio_entry->gpio_pin; + if (sc->gpio_entry->enable_cnt > 0) { + /* Other regulator(s) are enabled. */ + /* XXXX Any diagnostic message? Or error? */ + return (0); + } + rv = GPIO_PIN_SET(pin->dev, pin->pin, + sc->param->enable_active_high ? false: true); + if (rv != 0) { + device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); + return (rv); + } + *udelay = sc->param->enable_delay; + return (0); +} + static int regnode_fixed_status(struct regnode *regnode, int *status) { @@ -264,6 +303,10 @@ regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def) device_printf(dev, "Cannot register regulator.\n"); return(ENXIO); } + + if (sc->gpio_entry != NULL) + sc->gpio_entry->always_on |= sc->param->always_on; + return (0); } |
