Commit 3dc06c1b authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'regulator/topic/gpio' into v3.9-rc8

parents 5f19a85b 407945fd
...@@ -51,6 +51,7 @@ ...@@ -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 { ...@@ -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
* *
...@@ -1465,6 +1479,101 @@ void devm_regulator_put(struct regulator *regulator) ...@@ -1465,6 +1479,101 @@ 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, &regulator_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, &regulator_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, &regulator_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--;
}
}
}
}
/**
* Balance enable_count of each GPIO and actual GPIO pin control.
* GPIO is enabled in case of initial use. (enable_count is 0)
* GPIO is disabled when it is not shared any more. (enable_count <= 1)
*/
static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
{
struct regulator_enable_gpio *pin = rdev->ena_pin;
if (!pin)
return -EINVAL;
if (enable) {
/* Enable GPIO at initial use */
if (pin->enable_count == 0)
gpio_set_value_cansleep(pin->gpio,
!pin->ena_gpio_invert);
pin->enable_count++;
} else {
if (pin->enable_count > 1) {
pin->enable_count--;
return 0;
}
/* Disable GPIO if not used */
if (pin->enable_count <= 1) {
gpio_set_value_cansleep(pin->gpio,
pin->ena_gpio_invert);
pin->enable_count = 0;
}
}
return 0;
}
static int _regulator_do_enable(struct regulator_dev *rdev) static int _regulator_do_enable(struct regulator_dev *rdev)
{ {
int ret, delay; int ret, delay;
...@@ -1480,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev) ...@@ -1480,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable(rdev_get_name(rdev)); trace_regulator_enable(rdev_get_name(rdev));
if (rdev->ena_gpio) { if (rdev->ena_pin) {
gpio_set_value_cansleep(rdev->ena_gpio, ret = regulator_ena_gpio_ctrl(rdev, true);
!rdev->ena_gpio_invert); if (ret < 0)
return ret;
rdev->ena_gpio_state = 1; rdev->ena_gpio_state = 1;
} else if (rdev->desc->ops->enable) { } else if (rdev->desc->ops->enable) {
ret = rdev->desc->ops->enable(rdev); ret = rdev->desc->ops->enable(rdev);
...@@ -1584,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev) ...@@ -1584,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable(rdev_get_name(rdev)); trace_regulator_disable(rdev_get_name(rdev));
if (rdev->ena_gpio) { if (rdev->ena_pin) {
gpio_set_value_cansleep(rdev->ena_gpio, ret = regulator_ena_gpio_ctrl(rdev, false);
rdev->ena_gpio_invert); if (ret < 0)
return ret;
rdev->ena_gpio_state = 0; rdev->ena_gpio_state = 0;
} else if (rdev->desc->ops->disable) { } else if (rdev->desc->ops->disable) {
...@@ -1859,7 +1970,7 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap); ...@@ -1859,7 +1970,7 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
static int _regulator_is_enabled(struct regulator_dev *rdev) static int _regulator_is_enabled(struct regulator_dev *rdev)
{ {
/* A GPIO control always takes precedence */ /* A GPIO control always takes precedence */
if (rdev->ena_gpio) if (rdev->ena_pin)
return rdev->ena_gpio_state; return rdev->ena_gpio_state;
/* If we don't know then assume that the regulator is always on */ /* If we don't know then assume that the regulator is always on */
...@@ -3293,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) ...@@ -3293,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0) if (status < 0)
return status; return status;
} }
if (rdev->ena_gpio || ops->is_enabled) { if (rdev->ena_pin || ops->is_enabled) {
status = device_create_file(dev, &dev_attr_state); status = device_create_file(dev, &dev_attr_state);
if (status < 0) if (status < 0)
return status; return status;
...@@ -3495,22 +3606,17 @@ regulator_register(const struct regulator_desc *regulator_desc, ...@@ -3495,22 +3606,17 @@ 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;
if (rdev->ena_gpio_invert) if (config->ena_gpio_invert)
rdev->ena_gpio_state = !rdev->ena_gpio_state; rdev->ena_gpio_state = !rdev->ena_gpio_state;
} }
...@@ -3590,8 +3696,7 @@ regulator_register(const struct regulator_desc *regulator_desc, ...@@ -3590,8 +3696,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
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);
...@@ -3626,8 +3731,7 @@ void regulator_unregister(struct regulator_dev *rdev) ...@@ -3626,8 +3731,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(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
} }
......
...@@ -184,40 +184,6 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = { ...@@ -184,40 +184,6 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
ALDO10, ALDO10,
}; };
static int lp8788_ldo_enable(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
if (ldo->en_pin) {
gpio_set_value(ldo->en_pin->gpio, ENABLE);
return 0;
} else {
return regulator_enable_regmap(rdev);
}
}
static int lp8788_ldo_disable(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
if (ldo->en_pin) {
gpio_set_value(ldo->en_pin->gpio, DISABLE);
return 0;
} else {
return regulator_disable_regmap(rdev);
}
}
static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
if (ldo->en_pin)
return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
else
return regulator_is_enabled_regmap(rdev);
}
static int lp8788_ldo_enable_time(struct regulator_dev *rdev) static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
{ {
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
...@@ -253,17 +219,17 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = { ...@@ -253,17 +219,17 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = {
.list_voltage = regulator_list_voltage_table, .list_voltage = regulator_list_voltage_table,
.set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = lp8788_ldo_enable, .enable = regulator_enable_regmap,
.disable = lp8788_ldo_disable, .disable = regulator_disable_regmap,
.is_enabled = lp8788_ldo_is_enabled, .is_enabled = regulator_is_enabled_regmap,
.enable_time = lp8788_ldo_enable_time, .enable_time = lp8788_ldo_enable_time,
}; };
static struct regulator_ops lp8788_ldo_voltage_fixed_ops = { static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
.get_voltage = lp8788_ldo_fixed_get_voltage, .get_voltage = lp8788_ldo_fixed_get_voltage,
.enable = lp8788_ldo_enable, .enable = regulator_enable_regmap,
.disable = lp8788_ldo_disable, .disable = regulator_disable_regmap,
.is_enabled = lp8788_ldo_is_enabled, .is_enabled = regulator_is_enabled_regmap,
.enable_time = lp8788_ldo_enable_time, .enable_time = lp8788_ldo_enable_time,
}; };
...@@ -535,43 +501,10 @@ static struct regulator_desc lp8788_aldo_desc[] = { ...@@ -535,43 +501,10 @@ static struct regulator_desc lp8788_aldo_desc[] = {
}, },
}; };
static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
struct lp8788_ldo *ldo,
enum lp8788_ext_ldo_en_id id)
{
struct device *dev = &pdev->dev;
struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
int ret, gpio, pinstate;
char *name[] = {
[EN_ALDO1] = "LP8788_EN_ALDO1",
[EN_ALDO234] = "LP8788_EN_ALDO234",
[EN_ALDO5] = "LP8788_EN_ALDO5",
[EN_ALDO7] = "LP8788_EN_ALDO7",
[EN_DLDO7] = "LP8788_EN_DLDO7",
[EN_DLDO911] = "LP8788_EN_DLDO911",
};
gpio = pin->gpio;
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio: %d\n", gpio);
return -EINVAL;
}
pinstate = pin->init_state;
ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]);
if (ret == -EBUSY) {
dev_warn(dev, "gpio%d already used\n", gpio);
return 0;
}
return ret;
}
static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
struct lp8788_ldo *ldo, struct lp8788_ldo *ldo,
enum lp8788_ldo_id id) enum lp8788_ldo_id id)
{ {
int ret;
struct lp8788 *lp = ldo->lp; struct lp8788 *lp = ldo->lp;
struct lp8788_platform_data *pdata = lp->pdata; struct lp8788_platform_data *pdata = lp->pdata;
enum lp8788_ext_ldo_en_id enable_id; enum lp8788_ext_ldo_en_id enable_id;
...@@ -613,14 +546,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, ...@@ -613,14 +546,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
goto set_default_ldo_enable_mode; goto set_default_ldo_enable_mode;
ldo->en_pin = pdata->ldo_pin[enable_id]; ldo->en_pin = pdata->ldo_pin[enable_id];
return 0;
ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
if (ret) {
ldo->en_pin = NULL;
goto set_default_ldo_enable_mode;
}
return ret;
set_default_ldo_enable_mode: set_default_ldo_enable_mode:
return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0); return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0);
...@@ -644,6 +570,11 @@ static int lp8788_dldo_probe(struct platform_device *pdev) ...@@ -644,6 +570,11 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
if (ldo->en_pin) {
cfg.ena_gpio = ldo->en_pin->gpio;
cfg.ena_gpio_flags = ldo->en_pin->init_state;
}
cfg.dev = pdev->dev.parent; cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
cfg.driver_data = ldo; cfg.driver_data = ldo;
...@@ -700,6 +631,11 @@ static int lp8788_aldo_probe(struct platform_device *pdev) ...@@ -700,6 +631,11 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
if (ldo->en_pin) {
cfg.ena_gpio = ldo->en_pin->gpio;
cfg.ena_gpio_flags = ldo->en_pin->init_state;
}
cfg.dev = pdev->dev.parent; cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
cfg.driver_data = ldo; cfg.driver_data = ldo;
......
...@@ -22,6 +22,7 @@ ...@@ -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,
...@@ -305,8 +306,7 @@ struct regulator_dev { ...@@ -305,8 +306,7 @@ struct regulator_dev {
struct dentry *debugfs; struct dentry *debugfs;
int ena_gpio; struct regulator_enable_gpio *ena_pin;
unsigned int ena_gpio_invert:1;
unsigned int ena_gpio_state:1; unsigned int ena_gpio_state:1;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment