diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index f36d1c5ebaab..059cf3330bfa 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include /* Voltage setting */ #define FAN53555_VSEL0 0x00 @@ -106,6 +108,8 @@ struct fan53555_device_info { unsigned int mode_mask; /* 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) @@ -151,6 +155,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(rdev->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(rdev->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(rdev->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); @@ -223,9 +275,9 @@ static const 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, @@ -410,6 +462,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->vsel_reg = di->vol_reg; rdesc->vsel_mask = di->vsel_count - 1; rdesc->owner = THIS_MODULE; + rdesc->enable_time = 400; rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(rdev); @@ -425,7 +478,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); @@ -433,12 +486,27 @@ 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); + pdata->vsel_gpio = NULL; + } + return pdata; } @@ -487,6 +555,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) { di->vendor = diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h index ce8df21863f0..9270fd7bd8da 100644 --- a/include/linux/regulator/fan53555.h +++ b/include/linux/regulator/fan53555.h @@ -52,6 +52,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__ */