mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
regulator: s5m8767: Use GPIO for controlling Buck9/eMMC
Add support for GPIO control (enable/disable) over Buck9. The Buck9 Converter is used as a supply for eMMC Host Controller. BUCK9EN GPIO of S5M8767 chip may be used by application processor to enable or disable the Buck9. This has two benefits: - It is faster than toggling it over I2C bus. - It allows disabling the regulator during suspend to RAM; The AP will enable it during resume; Without the patch the regulator supplying eMMC must be defined as fixed-regulator. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
parent
07b1980848
commit
ee1e0994ab
@ -11,11 +11,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
@ -483,6 +480,65 @@ static struct regulator_desc regulators[] = {
|
||||
s5m8767_regulator_desc(BUCK9),
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable GPIO control over BUCK9 in regulator_config for that regulator.
|
||||
*/
|
||||
static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
|
||||
struct sec_regulator_data *rdata,
|
||||
struct regulator_config *config)
|
||||
{
|
||||
int i, mode = 0;
|
||||
|
||||
if (rdata->id != S5M8767_BUCK9)
|
||||
return;
|
||||
|
||||
/* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
|
||||
for (i = 0; i < s5m8767->num_regulators; i++) {
|
||||
const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
|
||||
if (opmode->id == rdata->id) {
|
||||
mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mode != S5M8767_ENCTRL_USE_GPIO) {
|
||||
dev_warn(s5m8767->dev,
|
||||
"ext-control for %s: mismatched op_mode (%x), ignoring\n",
|
||||
rdata->reg_node->name, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gpio_is_valid(rdata->ext_control_gpio)) {
|
||||
dev_warn(s5m8767->dev,
|
||||
"ext-control for %s: GPIO not valid, ignoring\n",
|
||||
rdata->reg_node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
config->ena_gpio = rdata->ext_control_gpio;
|
||||
config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn on GPIO control over BUCK9.
|
||||
*/
|
||||
static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
|
||||
struct regulator_dev *rdev)
|
||||
{
|
||||
int ret, reg, enable_ctrl;
|
||||
|
||||
if (rdev_get_id(rdev) != S5M8767_BUCK9)
|
||||
return -EINVAL;
|
||||
|
||||
ret = s5m8767_get_register(rdev, ®, &enable_ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(s5m8767->iodev->regmap_pmic,
|
||||
reg, S5M8767_ENCTRL_MASK,
|
||||
S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
|
||||
struct sec_platform_data *pdata,
|
||||
@ -520,6 +576,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
|
||||
struct sec_regulator_data *rdata,
|
||||
struct device_node *reg_np)
|
||||
{
|
||||
rdata->ext_control_gpio = of_get_named_gpio(reg_np,
|
||||
"s5m8767,pmic-ext-control-gpios", 0);
|
||||
if (!gpio_is_valid(rdata->ext_control_gpio))
|
||||
rdata->ext_control_gpio = 0;
|
||||
}
|
||||
|
||||
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||
struct sec_platform_data *pdata)
|
||||
{
|
||||
@ -574,6 +640,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||
continue;
|
||||
}
|
||||
|
||||
s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
|
||||
|
||||
rdata->id = i;
|
||||
rdata->initdata = of_get_regulator_init_data(
|
||||
&pdev->dev, reg_np);
|
||||
@ -940,6 +1008,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
||||
config.driver_data = s5m8767;
|
||||
config.regmap = iodev->regmap_pmic;
|
||||
config.of_node = pdata->regulators[i].reg_node;
|
||||
if (pdata->regulators[i].ext_control_gpio)
|
||||
s5m8767_regulator_config_ext_control(s5m8767,
|
||||
&pdata->regulators[i], &config);
|
||||
|
||||
rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id],
|
||||
&config);
|
||||
@ -949,6 +1020,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
||||
id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata->regulators[i].ext_control_gpio) {
|
||||
ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
|
||||
if (ret < 0) {
|
||||
dev_err(s5m8767->dev,
|
||||
"failed to enable gpio control over %s: %d\n",
|
||||
rdev[i]->desc->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -119,7 +119,8 @@ struct sec_platform_data {
|
||||
struct sec_regulator_data {
|
||||
int id;
|
||||
struct regulator_init_data *initdata;
|
||||
struct device_node *reg_node;
|
||||
struct device_node *reg_node;
|
||||
int ext_control_gpio;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -183,9 +183,16 @@ enum s5m8767_regulators {
|
||||
S5M8767_REG_MAX,
|
||||
};
|
||||
|
||||
/* LDO_EN/BUCK_EN field in registers */
|
||||
#define S5M8767_ENCTRL_SHIFT 6
|
||||
#define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT)
|
||||
|
||||
/*
|
||||
* LDO_EN/BUCK_EN register value for controlling this Buck or LDO
|
||||
* by GPIO (PWREN, BUCKEN).
|
||||
*/
|
||||
#define S5M8767_ENCTRL_USE_GPIO 0x1
|
||||
|
||||
/*
|
||||
* Values for BUCK_RAMP field in DVS_RAMP register, matching raw values
|
||||
* in mV/us.
|
||||
|
Loading…
Reference in New Issue
Block a user