diff --git a/drivers/power/supply/regulator.c b/drivers/power/supply/regulator.c index 91fee66a6e..35f9b74ec2 100644 --- a/drivers/power/supply/regulator.c +++ b/drivers/power/supply/regulator.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include /**************************************************************************** @@ -78,15 +78,43 @@ static int _regulator_is_enabled(FAR struct regulator_dev_s *rdev) static int _regulator_do_enable(FAR struct regulator_dev_s *rdev) { + FAR struct regulator_s *supply = NULL; int ret = 0; + if (rdev->desc->supply_name && rdev->supply == NULL) + { + supply = regulator_get(rdev->desc->supply_name); + if (supply == NULL) + { + pwrerr("get supply %s failed \n", rdev->desc->supply_name); + return -ENODEV; + } + + rdev->supply = supply; + } + + if (rdev->supply) + { + ret = regulator_enable(rdev->supply); + if (ret < 0) + { + pwrerr("failed to enable supply %d\n", ret); + goto err; + } + } + if (rdev->ops->enable) { ret = rdev->ops->enable(rdev); if (ret < 0) { pwrerr("failed to enable %d\n", ret); - return ret; + if (rdev->supply) + { + regulator_disable(rdev->supply); + } + + goto err; } } @@ -96,6 +124,15 @@ static int _regulator_do_enable(FAR struct regulator_dev_s *rdev) } return ret; + +err: + if (supply) + { + regulator_put(supply); + rdev->supply = NULL; + } + + return ret; } static int _regulator_do_disable(FAR struct regulator_dev_s *rdev) @@ -108,6 +145,20 @@ static int _regulator_do_disable(FAR struct regulator_dev_s *rdev) if (ret < 0) { pwrerr("failed to disable %d\n", ret); + return ret; + } + } + + if (rdev->supply) + { + ret = regulator_disable(rdev->supply); + if (ret < 0) + { + pwrerr("failed to disable supply %d\n", ret); + if (rdev->ops->enable) + { + rdev->ops->enable(rdev); + } } } @@ -165,7 +216,7 @@ static FAR struct regulator_dev_s *regulator_dev_lookup(const char *supply) nxmutex_unlock(&g_reg_lock); #if defined(CONFIG_REGULATOR_RPMSG) - if (rdev_found == NULL) + if (rdev_found == NULL && strchr(supply, '/')) { rdev_found = regulator_rpmsg_get(supply); } @@ -561,7 +612,7 @@ int regulator_enable(FAR struct regulator_s *regulator) rdev = regulator->rdev; nxmutex_lock(&rdev->regulator_lock); - if (rdev->use_count == 0) + if (rdev->use_count == 0 && !rdev->desc->always_on) { ret = _regulator_do_enable(rdev); if (ret < 0) @@ -767,6 +818,7 @@ regulator_register(FAR const struct regulator_desc_s *regulator_desc, FAR void *priv) { FAR struct regulator_dev_s *rdev; + int ret = 0; if (regulator_desc == NULL) { @@ -818,10 +870,15 @@ regulator_register(FAR const struct regulator_desc_s *regulator_desc, list_initialize(&rdev->consumer_list); list_initialize(&rdev->list); - if ((rdev->desc->boot_on || rdev->desc->always_on) - && !_regulator_is_enabled(rdev)) + if (rdev->desc->boot_on || rdev->desc->always_on) { - _regulator_do_enable(rdev); + ret = _regulator_do_enable(rdev); + if (ret < 0) + { + pwrerr("failed to enable regulator\n"); + kmm_free(rdev); + return NULL; + } } else if (!rdev->desc->boot_on && !rdev->desc->always_on && _regulator_is_enabled(rdev)) @@ -877,6 +934,10 @@ void regulator_unregister(FAR struct regulator_dev_s *rdev) list_delete(&rdev->list); nxmutex_unlock(&g_reg_lock); + if (rdev->supply) + { + regulator_put(rdev->supply); + } kmm_free(rdev); } diff --git a/include/nuttx/power/regulator.h b/include/nuttx/power/regulator.h index c973fa2a54..06f3a5c697 100644 --- a/include/nuttx/power/regulator.h +++ b/include/nuttx/power/regulator.h @@ -74,30 +74,32 @@ struct regulator_ops_s struct regulator_desc_s { - const char *name; /* Regulator output name */ - unsigned int id; /* Numerical id for a given regulator of - * a device - */ - unsigned int n_voltages; /* Number of discrete voltages */ - unsigned int vsel_reg; /* Device register for voltage selection */ - unsigned int vsel_mask; /* Register mask, for voltage selection */ - unsigned int enable_reg; /* Device register for enable/disable */ - unsigned int enable_mask; /* Register mask for enable/disable */ - unsigned int enable_time; /* Time for initial enable of regulator */ - unsigned int ramp_delay; /* Rate of change for setting new voltage */ - unsigned int uv_step; /* Voltage per step if linear mapping_uv */ - unsigned int min_uv; /* Minimum acceptable voltage */ - unsigned int max_uv; /* Maximum acceptable voltage */ - unsigned int pulldown; /* Enable pulldown when disabled */ - unsigned int pulldown_reg; /* Device register, for pulldown enable */ - unsigned int pulldown_mask; /* Register mask, for pulldown enable */ - unsigned int apply_uv; /* If true, the voltage specifed (between) * min_uv and max_uv will be applied during - * initialisation. - */ - unsigned int boot_on; /* true if this regulator is to be enabled - * at power up/reset - */ - unsigned int always_on; + FAR const char *name; /* Regulator output name */ + unsigned int id; /* Numerical id for a given regulator of + * a device + */ + unsigned int n_voltages; /* Number of discrete voltages */ + unsigned int vsel_reg; /* Device register for voltage selection */ + unsigned int vsel_mask; /* Register mask, for voltage selection */ + unsigned int enable_reg; /* Device register for enable/disable */ + unsigned int enable_mask; /* Register mask for enable/disable */ + unsigned int enable_time; /* Time for initial enable of regulator */ + unsigned int ramp_delay; /* Rate of change for setting new voltage */ + unsigned int uv_step; /* Voltage per step if linear mapping_uv */ + unsigned int min_uv; /* Minimum acceptable voltage */ + unsigned int max_uv; /* Maximum acceptable voltage */ + unsigned int pulldown; /* Enable pulldown when disabled */ + unsigned int pulldown_reg; /* Device register, for pulldown enable */ + unsigned int pulldown_mask; /* Register mask, for pulldown enable */ + unsigned int apply_uv; /* If true, the voltage specifed (between) + * min_uv and max_uv will be applied during + * initialisation. + */ + unsigned int boot_on; /* true if this regulator is to be enabled + * at power up/reset + */ + unsigned int always_on; + FAR const char *supply_name; }; struct regulator_dev_s @@ -109,6 +111,7 @@ struct regulator_dev_s mutex_t regulator_lock; struct list_node list; struct list_node consumer_list; + FAR struct regulator_s *supply; FAR void *priv; }; @@ -147,7 +150,7 @@ extern "C" * ****************************************************************************/ -struct regulator_dev_s * +FAR struct regulator_dev_s * regulator_register(FAR const struct regulator_desc_s *desc, FAR const struct regulator_ops_s *ops, FAR void *priv);