From 4336ef5f14af07f39e736cb337543abc2d7a003f Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 16 Aug 2016 18:44:04 +0800 Subject: [PATCH] regulator: fan53555: fix up the dcdc is disabled when reboot Before reboot if the DCDC is disabled, the DCDC is still disabled after restart. We have an method to workaround: Use vsel pin to switch the voltage between value in FAN53555_VSEL0 and FAN53555_VSEL1. If VSEL pin is inactive, the voltage of DCDC are controlled by FAN53555_VSEL0, when we pull vsel pin to active, they would be controlled by FAN53555_VSEL1. In this case, we can set FAN53555_VSEL1 to disable dcdc, So we can make vsel pin to active to disable dcdc, VSEL pin is inactive to enable DCDC. Change-Id: I14c823ed11dc3369044ad2ed0b53a6027acbccd0 Signed-off-by: Elaine Zhang --- drivers/regulator/fan53555.c | 78 ++++++++++++++++++++++++++++-- include/linux/regulator/fan53555.h | 1 + 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 1ddb9d12dda3..f6ded7024195 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include /* Voltage setting */ #define FAN53555_VSEL0 0x00 @@ -91,6 +93,8 @@ struct fan53555_device_info { unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; + struct gpio_desc *vsel_gpio; + unsigned int sleep_vsel_id; }; static unsigned int fan53555_map_mode(unsigned int mode) @@ -136,6 +140,54 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) VSEL_BUCK_EN, 0); } +static int fan53555_set_enable(struct regulator_dev *rdev) +{ + struct fan53555_device_info *di = rdev_get_drvdata(rdev); + + if (di->vsel_gpio) { + gpiod_set_raw_value(di->vsel_gpio, !di->sleep_vsel_id); + return 0; + } + + return regmap_update_bits(di->regmap, di->vol_reg, + VSEL_BUCK_EN, VSEL_BUCK_EN); +} + +static int fan53555_set_disable(struct regulator_dev *rdev) +{ + struct fan53555_device_info *di = rdev_get_drvdata(rdev); + + if (di->vsel_gpio) { + gpiod_set_raw_value(di->vsel_gpio, di->sleep_vsel_id); + return 0; + } + + return regmap_update_bits(di->regmap, di->vol_reg, + VSEL_BUCK_EN, 0); +} + +static int fan53555_is_enabled(struct regulator_dev *rdev) +{ + struct fan53555_device_info *di = rdev_get_drvdata(rdev); + unsigned int val; + int ret = 0; + + if (di->vsel_gpio) { + if (di->sleep_vsel_id) + return !gpiod_get_raw_value(di->vsel_gpio); + else + return gpiod_get_raw_value(di->vsel_gpio); + } + + ret = regmap_read(di->regmap, di->vol_reg, &val); + if (ret < 0) + return ret; + if (val & VSEL_BUCK_EN) + return 1; + else + return 0; +} + static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); @@ -208,9 +260,9 @@ static struct regulator_ops fan53555_regulator_ops = { .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_suspend_voltage = fan53555_set_suspend_voltage, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, + .enable = fan53555_set_enable, + .disable = fan53555_set_disable, + .is_enabled = fan53555_is_enabled, .set_mode = fan53555_set_mode, .get_mode = fan53555_get_mode, .set_ramp_delay = fan53555_set_ramp, @@ -316,6 +368,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->vsel_reg = di->vol_reg; rdesc->vsel_mask = VSEL_NSEL_MASK; rdesc->owner = THIS_MODULE; + rdesc->enable_time = 400; di->rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(di->rdev); @@ -331,7 +384,7 @@ static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, const struct regulator_desc *desc) { struct fan53555_platform_data *pdata; - int ret; + int ret, flag; u32 tmp; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -339,12 +392,26 @@ static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, return NULL; pdata->regulator = of_get_regulator_init_data(dev, np, desc); + pdata->regulator->constraints.initial_state = PM_SUSPEND_MEM; ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &tmp); if (!ret) pdata->sleep_vsel_id = tmp; + if (pdata->sleep_vsel_id) + flag = GPIOD_OUT_LOW; + else + flag = GPIOD_OUT_HIGH; + + pdata->vsel_gpio = + devm_gpiod_get_index_optional(dev, "vsel", 0, + flag); + if (IS_ERR(pdata->vsel_gpio)) { + ret = PTR_ERR(pdata->vsel_gpio); + dev_err(dev, "failed to get vesl gpio (%d)\n", ret); + } + return pdata; } @@ -389,6 +456,9 @@ static int fan53555_regulator_probe(struct i2c_client *client, return -ENODEV; } + di->vsel_gpio = pdata->vsel_gpio; + di->sleep_vsel_id = pdata->sleep_vsel_id; + di->regulator = pdata->regulator; if (client->dev.of_node) { const struct of_device_id *match; diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h index f13880e84d85..4e8184c5e804 100644 --- a/include/linux/regulator/fan53555.h +++ b/include/linux/regulator/fan53555.h @@ -56,6 +56,7 @@ struct fan53555_platform_data { unsigned int slew_rate; /* Sleep VSEL ID */ unsigned int sleep_vsel_id; + struct gpio_desc *vsel_gpio; }; #endif /* __FAN53555_H__ */ -- 2.34.1