regulator: core: support shared enable GPIO concept
A Regulator can be enabled by external GPIO pin. This is configurable in the regulator_config. At this moment, the GPIO can be owned by only one regulator device. In some devices, multiple regulators are enabled by shared one GPIO pin. This patch extends this limitation, enabling shared enable GPIO of regulators. New list for enable GPIO: 'regulator_ena_gpio_list' This manages enable GPIO list. New structure for supporting shared enable GPIO: 'regulator_enable_gpio' The enable count is used for balancing GPIO control count. This count is incremented when GPIO is enabled. On the other hand, it's decremented when GPIO is disabled. Reference count: 'request_count' The reference count, 'request_count' is incremented/decremented on requesting/freeing the GPIO. This count makes sure only free the GPIO when it has no users. How it works If the GPIO is already used, skip requesting new GPIO usage. The GPIO is new one, request GPIO function and add it to the list of enable GPIO. This list is used for balancing enable GPIO count and pin control. Updating a GPIO and invert code moved 'ena_gpio' and 'ena_gpio_invert' of the regulator_config were moved to new function, regulator_ena_gpio_request(). Use regulator_enable_pin structure rather than regulator_dev. Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com> Reviewed-by: Axel Lin <axel.lin@ingics.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
6dbe51c251
commit
f19b00da8e
|
@ -51,6 +51,7 @@
|
||||||
static DEFINE_MUTEX(regulator_list_mutex);
|
static DEFINE_MUTEX(regulator_list_mutex);
|
||||||
static LIST_HEAD(regulator_list);
|
static LIST_HEAD(regulator_list);
|
||||||
static LIST_HEAD(regulator_map_list);
|
static LIST_HEAD(regulator_map_list);
|
||||||
|
static LIST_HEAD(regulator_ena_gpio_list);
|
||||||
static bool has_full_constraints;
|
static bool has_full_constraints;
|
||||||
static bool board_wants_dummy_regulator;
|
static bool board_wants_dummy_regulator;
|
||||||
|
|
||||||
|
@ -68,6 +69,19 @@ struct regulator_map {
|
||||||
struct regulator_dev *regulator;
|
struct regulator_dev *regulator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct regulator_enable_gpio
|
||||||
|
*
|
||||||
|
* Management for shared enable GPIO pin
|
||||||
|
*/
|
||||||
|
struct regulator_enable_gpio {
|
||||||
|
struct list_head list;
|
||||||
|
int gpio;
|
||||||
|
u32 enable_count; /* a number of enabled shared GPIO */
|
||||||
|
u32 request_count; /* a number of requested shared GPIO */
|
||||||
|
unsigned int ena_gpio_invert:1;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct regulator
|
* struct regulator
|
||||||
*
|
*
|
||||||
|
@ -1456,6 +1470,65 @@ void devm_regulator_put(struct regulator *regulator)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devm_regulator_put);
|
EXPORT_SYMBOL_GPL(devm_regulator_put);
|
||||||
|
|
||||||
|
/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
|
||||||
|
static int regulator_ena_gpio_request(struct regulator_dev *rdev,
|
||||||
|
const struct regulator_config *config)
|
||||||
|
{
|
||||||
|
struct regulator_enable_gpio *pin;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
list_for_each_entry(pin, ®ulator_ena_gpio_list, list) {
|
||||||
|
if (pin->gpio == config->ena_gpio) {
|
||||||
|
rdev_dbg(rdev, "GPIO %d is already used\n",
|
||||||
|
config->ena_gpio);
|
||||||
|
goto update_ena_gpio_to_rdev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_request_one(config->ena_gpio,
|
||||||
|
GPIOF_DIR_OUT | config->ena_gpio_flags,
|
||||||
|
rdev_get_name(rdev));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
|
||||||
|
if (pin == NULL) {
|
||||||
|
gpio_free(config->ena_gpio);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pin->gpio = config->ena_gpio;
|
||||||
|
pin->ena_gpio_invert = config->ena_gpio_invert;
|
||||||
|
list_add(&pin->list, ®ulator_ena_gpio_list);
|
||||||
|
|
||||||
|
update_ena_gpio_to_rdev:
|
||||||
|
pin->request_count++;
|
||||||
|
rdev->ena_pin = pin;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void regulator_ena_gpio_free(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct regulator_enable_gpio *pin, *n;
|
||||||
|
|
||||||
|
if (!rdev->ena_pin)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Free the GPIO only in case of no use */
|
||||||
|
list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) {
|
||||||
|
if (pin->gpio == rdev->ena_pin->gpio) {
|
||||||
|
if (pin->request_count <= 1) {
|
||||||
|
pin->request_count = 0;
|
||||||
|
gpio_free(pin->gpio);
|
||||||
|
list_del(&pin->list);
|
||||||
|
kfree(pin);
|
||||||
|
} else {
|
||||||
|
pin->request_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int _regulator_do_enable(struct regulator_dev *rdev)
|
static int _regulator_do_enable(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
int ret, delay;
|
int ret, delay;
|
||||||
|
@ -3435,18 +3508,13 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||||
dev_set_drvdata(&rdev->dev, rdev);
|
dev_set_drvdata(&rdev->dev, rdev);
|
||||||
|
|
||||||
if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
|
if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
|
||||||
ret = gpio_request_one(config->ena_gpio,
|
ret = regulator_ena_gpio_request(rdev, config);
|
||||||
GPIOF_DIR_OUT | config->ena_gpio_flags,
|
|
||||||
rdev_get_name(rdev));
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
|
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
|
||||||
config->ena_gpio, ret);
|
config->ena_gpio, ret);
|
||||||
goto wash;
|
goto wash;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdev->ena_gpio = config->ena_gpio;
|
|
||||||
rdev->ena_gpio_invert = config->ena_gpio_invert;
|
|
||||||
|
|
||||||
if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
|
if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
|
||||||
rdev->ena_gpio_state = 1;
|
rdev->ena_gpio_state = 1;
|
||||||
|
|
||||||
|
@ -3522,8 +3590,7 @@ unset_supplies:
|
||||||
scrub:
|
scrub:
|
||||||
if (rdev->supply)
|
if (rdev->supply)
|
||||||
_regulator_put(rdev->supply);
|
_regulator_put(rdev->supply);
|
||||||
if (rdev->ena_gpio)
|
regulator_ena_gpio_free(rdev);
|
||||||
gpio_free(rdev->ena_gpio);
|
|
||||||
kfree(rdev->constraints);
|
kfree(rdev->constraints);
|
||||||
wash:
|
wash:
|
||||||
device_unregister(&rdev->dev);
|
device_unregister(&rdev->dev);
|
||||||
|
@ -3558,8 +3625,7 @@ void regulator_unregister(struct regulator_dev *rdev)
|
||||||
unset_regulator_supplies(rdev);
|
unset_regulator_supplies(rdev);
|
||||||
list_del(&rdev->list);
|
list_del(&rdev->list);
|
||||||
kfree(rdev->constraints);
|
kfree(rdev->constraints);
|
||||||
if (rdev->ena_gpio)
|
regulator_ena_gpio_free(rdev);
|
||||||
gpio_free(rdev->ena_gpio);
|
|
||||||
device_unregister(&rdev->dev);
|
device_unregister(&rdev->dev);
|
||||||
mutex_unlock(®ulator_list_mutex);
|
mutex_unlock(®ulator_list_mutex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
struct regmap;
|
struct regmap;
|
||||||
struct regulator_dev;
|
struct regulator_dev;
|
||||||
struct regulator_init_data;
|
struct regulator_init_data;
|
||||||
|
struct regulator_enable_gpio;
|
||||||
|
|
||||||
enum regulator_status {
|
enum regulator_status {
|
||||||
REGULATOR_STATUS_OFF,
|
REGULATOR_STATUS_OFF,
|
||||||
|
@ -300,6 +301,7 @@ struct regulator_dev {
|
||||||
|
|
||||||
struct dentry *debugfs;
|
struct dentry *debugfs;
|
||||||
|
|
||||||
|
struct regulator_enable_gpio *ena_pin;
|
||||||
int ena_gpio;
|
int ena_gpio;
|
||||||
unsigned int ena_gpio_invert:1;
|
unsigned int ena_gpio_invert:1;
|
||||||
unsigned int ena_gpio_state:1;
|
unsigned int ena_gpio_state:1;
|
||||||
|
|
Loading…
Reference in New Issue