regulator: fan53555: fix up the dcdc is disabled when reboot
authorElaine Zhang <zhangqing@rock-chips.com>
Tue, 16 Aug 2016 10:44:04 +0000 (18:44 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 30 Aug 2016 07:21:02 +0000 (15:21 +0800)
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 <zhangqing@rock-chips.com>
drivers/regulator/fan53555.c
include/linux/regulator/fan53555.h

index 1ddb9d12dda3d7ebfb5de1fd720e3b56223d7b32..f6ded702419581163d1c989578cc922ad6010d90 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/regulator/fan53555.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 /* 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;
index f13880e84d859817ec4a8c9fb2deccc21f347b4d..4e8184c5e8049bec75030711dbad2fcd4ce54726 100644 (file)
@@ -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__ */