diff options
Diffstat (limited to 'drivers/regulator/s5m8767.c')
| -rw-r--r-- | drivers/regulator/s5m8767.c | 583 |
1 files changed, 273 insertions, 310 deletions
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index c24448bc43cf..fe2631378ccd 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -1,21 +1,12 @@ -/* - * s5m8767.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2011 Samsung Electronics Co., Ltd +// http://www.samsung.com -#include <linux/bug.h> +#include <linux/cleanup.h> #include <linux/err.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> -#include <linux/slab.h> +#include <linux/of.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> @@ -23,6 +14,7 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/s5m8767.h> #include <linux/regulator/of_regulator.h> +#include <linux/regmap.h> #define S5M8767_OPMODE_NORMAL_MODE 0x1 @@ -30,7 +22,6 @@ struct s5m8767_info { struct device *dev; struct sec_pmic_dev *iodev; int num_regulators; - struct regulator_dev **rdev; struct sec_opmode_data *opmode; int ramp_delay; @@ -44,8 +35,8 @@ struct s5m8767_info { u8 buck2_vol[8]; u8 buck3_vol[8]; u8 buck4_vol[8]; - int buck_gpios[3]; - int buck_ds[3]; + struct gpio_desc *buck_gpios[3]; + struct gpio_desc *buck_ds[3]; int buck_gpioindex; }; @@ -120,12 +111,12 @@ static const struct sec_voltage_desc *reg_voltage_map[] = { [S5M8767_BUCK4] = &buck_voltage_val2, [S5M8767_BUCK5] = &buck_voltage_val1, [S5M8767_BUCK6] = &buck_voltage_val1, - [S5M8767_BUCK7] = NULL, - [S5M8767_BUCK8] = NULL, + [S5M8767_BUCK7] = &buck_voltage_val3, + [S5M8767_BUCK8] = &buck_voltage_val3, [S5M8767_BUCK9] = &buck_voltage_val3, }; -static unsigned int s5m8767_opmode_reg[][4] = { +static const unsigned int s5m8767_opmode_reg[][4] = { /* {OFF, ON, LOWPOWER, SUSPEND} */ /* LDO1 ... LDO28 */ {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ @@ -169,12 +160,11 @@ static unsigned int s5m8767_opmode_reg[][4] = { {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ }; -static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, - int *enable_ctrl) +static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, + int *reg, int *enable_ctrl) { - int i, reg_id = rdev_get_id(rdev); + int i; unsigned int mode; - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); switch (reg_id) { case S5M8767_LDO1 ... S5M8767_LDO2: @@ -206,57 +196,12 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, } } - if (i < s5m8767->num_regulators) - *enable_ctrl = - s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; - - return 0; -} - -static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg; - int mask = 0xc0, enable_ctrl; - unsigned int val; - - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret == -EINVAL) - return 1; - else if (ret) - return ret; - - ret = sec_reg_read(s5m8767->iodev, reg, &val); - if (ret) - return ret; - - return (val & mask) == enable_ctrl; -} - -static int s5m8767_reg_enable(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg; - int mask = 0xc0, enable_ctrl; - - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret) - return ret; - - return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); -} - -static int s5m8767_reg_disable(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg; - int mask = 0xc0, enable_ctrl; + if (i >= s5m8767->num_regulators) + return -EINVAL; - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret) - return ret; + *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; - return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); + return 0; } static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) @@ -327,9 +272,9 @@ static inline int s5m8767_set_high(struct s5m8767_info *s5m8767) { int temp_index = s5m8767->buck_gpioindex; - gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); - gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); - gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); + gpiod_set_value(s5m8767->buck_gpios[0], !!(temp_index & BIT(2))); + gpiod_set_value(s5m8767->buck_gpios[1], !!(temp_index & BIT(1))); + gpiod_set_value(s5m8767->buck_gpios[2], !!(temp_index & BIT(0))); return 0; } @@ -338,9 +283,9 @@ static inline int s5m8767_set_low(struct s5m8767_info *s5m8767) { int temp_index = s5m8767->buck_gpioindex; - gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); - gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); - gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); + gpiod_set_value(s5m8767->buck_gpios[2], !!(temp_index & BIT(0))); + gpiod_set_value(s5m8767->buck_gpios[1], !!(temp_index & BIT(1))); + gpiod_set_value(s5m8767->buck_gpios[0], !!(temp_index & BIT(2))); return 0; } @@ -395,31 +340,30 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_sel) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - const struct sec_voltage_desc *desc; - int reg_id = rdev_get_id(rdev); - - desc = reg_voltage_map[reg_id]; if ((old_sel < new_sel) && s5m8767->ramp_delay) - return DIV_ROUND_UP(desc->step * (new_sel - old_sel), + return DIV_ROUND_UP(rdev->desc->uV_step * (new_sel - old_sel), s5m8767->ramp_delay * 1000); return 0; } -static struct regulator_ops s5m8767_ops = { +static const struct regulator_ops s5m8767_ops = { .list_voltage = regulator_list_voltage_linear, - .is_enabled = s5m8767_reg_is_enabled, - .enable = s5m8767_reg_enable, - .disable = s5m8767_reg_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = s5m8767_set_voltage_sel, .set_voltage_time_sel = s5m8767_set_voltage_time_sel, }; -static struct regulator_ops s5m8767_buck78_ops = { - .is_enabled = s5m8767_reg_is_enabled, - .enable = s5m8767_reg_enable, - .disable = s5m8767_reg_disable, +static const struct regulator_ops s5m8767_buck78_ops = { + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, }; #define s5m8767_regulator_desc(_name) { \ @@ -478,51 +422,74 @@ static struct regulator_desc regulators[] = { s5m8767_regulator_desc(BUCK9), }; -#ifdef CONFIG_OF -static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, - struct sec_platform_data *pdata, - struct device_node *pmic_np) +/* + * 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, gpio; + int i, mode = 0; - for (i = 0; i < 3; i++) { - gpio = of_get_named_gpio(pmic_np, - "s5m8767,pmic-buck-dvs-gpios", i); - if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); - return -EINVAL; + 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; } - pdata->buck_gpios[i] = gpio; } - return 0; + if (mode != S5M8767_ENCTRL_USE_GPIO) { + dev_warn(s5m8767->dev, + "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n", + rdata->reg_node, mode); + return; + } + + if (!rdata->ext_control_gpiod) { + dev_warn(s5m8767->dev, + "ext-control for %pOFn: GPIO not valid, ignoring\n", + rdata->reg_node); + return; + } + + config->ena_gpiod = rdata->ext_control_gpiod; } -static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, - struct sec_platform_data *pdata, - struct device_node *pmic_np) +/* + * Turn on GPIO control over BUCK9. + */ +static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767, + struct regulator_dev *rdev) { - int i, gpio; + int id = rdev_get_id(rdev); + int ret, reg, enable_ctrl; - for (i = 0; i < 3; i++) { - gpio = of_get_named_gpio(pmic_np, - "s5m8767,pmic-buck-ds-gpios", i); - if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); - return -EINVAL; - } - pdata->buck_ds[i] = gpio; - } - return 0; + if (id != S5M8767_BUCK9) + return -EINVAL; + + ret = s5m8767_get_register(s5m8767, id, ®, &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_pdata(struct platform_device *pdev, struct sec_platform_data *pdata) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct device_node *pmic_np, *regulators_np, *reg_np; + struct device_node *pmic_np, *reg_np; struct sec_regulator_data *rdata; struct sec_opmode_data *rmode; - unsigned int i, dvs_voltage_nr = 1, ret; + unsigned int i, dvs_voltage_nr = 8; pmic_np = iodev->dev->of_node; if (!pmic_np) { @@ -530,7 +497,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_find_node_by_name(pmic_np, "regulators"); + struct device_node *regulators_np __free(device_node) = of_get_child_by_name(pmic_np, + "regulators"); if (!regulators_np) { dev_err(iodev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -539,68 +507,98 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, /* count the number of regulators to be supported in pmic */ pdata->num_regulators = of_get_child_count(regulators_np); - rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); - if (!rdata) { - dev_err(iodev->dev, - "could not allocate memory for regulator data\n"); + rdata = devm_kcalloc(&pdev->dev, + pdata->num_regulators, sizeof(*rdata), + GFP_KERNEL); + if (!rdata) return -ENOMEM; - } - rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * - pdata->num_regulators, GFP_KERNEL); - if (!rmode) { - dev_err(iodev->dev, - "could not allocate memory for regulator mode\n"); + rmode = devm_kcalloc(&pdev->dev, + pdata->num_regulators, sizeof(*rmode), + GFP_KERNEL); + if (!rmode) return -ENOMEM; - } pdata->regulators = rdata; pdata->opmode = rmode; for_each_child_of_node(regulators_np, reg_np) { for (i = 0; i < ARRAY_SIZE(regulators); i++) - if (!of_node_cmp(reg_np->name, regulators[i].name)) + if (of_node_name_eq(reg_np, regulators[i].name)) break; if (i == ARRAY_SIZE(regulators)) { dev_warn(iodev->dev, - "don't know how to configure regulator %s\n", - reg_np->name); + "don't know how to configure regulator %pOFn\n", + reg_np); continue; } + rdata->ext_control_gpiod = devm_fwnode_gpiod_get( + &pdev->dev, + of_fwnode_handle(reg_np), + "s5m8767,pmic-ext-control", + GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "s5m8767"); + if (PTR_ERR(rdata->ext_control_gpiod) == -ENOENT) { + rdata->ext_control_gpiod = NULL; + } else if (IS_ERR(rdata->ext_control_gpiod)) { + of_node_put(reg_np); + return PTR_ERR(rdata->ext_control_gpiod); + } + rdata->id = i; rdata->initdata = of_get_regulator_init_data( - &pdev->dev, reg_np); + &pdev->dev, reg_np, + ®ulators[i]); rdata->reg_node = reg_np; rdata++; rmode->id = i; if (of_property_read_u32(reg_np, "op_mode", &rmode->mode)) { dev_warn(iodev->dev, - "no op_mode property property at %s\n", - reg_np->full_name); + "no op_mode property at %pOF\n", + reg_np); rmode->mode = S5M8767_OPMODE_NORMAL_MODE; } rmode++; } - if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) + if (of_property_read_bool(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs")) { pdata->buck2_gpiodvs = true; - if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck2-dvs-voltage", + pdata->buck2_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck2 voltages not specified\n"); + return -EINVAL; + } + } + + if (of_property_read_bool(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs")) { pdata->buck3_gpiodvs = true; - if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck3-dvs-voltage", + pdata->buck3_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck3 voltages not specified\n"); + return -EINVAL; + } + } + + if (of_property_read_bool(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs")) { pdata->buck4_gpiodvs = true; - if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || - pdata->buck4_gpiodvs) { - ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); - if (ret) + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck4-dvs-voltage", + pdata->buck4_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck4 voltages not specified\n"); return -EINVAL; + } + } + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || + pdata->buck4_gpiodvs) { if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-default-dvs-idx", &pdata->buck_default_idx)) { @@ -612,32 +610,17 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, "invalid value for default dvs index, use 0\n"); } } - dvs_voltage_nr = 8; } - ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); - if (ret) - return -EINVAL; - - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck2-dvs-voltage", - pdata->buck2_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck2 voltages not specified\n"); - return -EINVAL; - } + pdata->buck2_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck2-ramp-enable"); + pdata->buck3_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck3-ramp-enable"); + pdata->buck4_ramp_enable = of_property_read_bool(pmic_np, "s5m8767,pmic-buck4-ramp-enable"); - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck3-dvs-voltage", - pdata->buck3_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck3 voltages not specified\n"); - return -EINVAL; - } - - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck4-dvs-voltage", - pdata->buck4_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck4 voltages not specified\n"); - return -EINVAL; + if (pdata->buck2_ramp_enable || pdata->buck3_ramp_enable + || pdata->buck4_ramp_enable) { + if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-ramp-delay", + &pdata->buck_ramp_delay)) + pdata->buck_ramp_delay = 0; } return 0; @@ -655,9 +638,10 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; struct s5m8767_info *s5m8767; - int i, ret, size, buck_init; + int i, ret, buck_init; + const char *gpiods_names[3] = { "S5M8767 DS2", "S5M8767 DS3", "S5M8767 DS4" }; + const char *gpiodvs_names[3] = { "S5M8767 SET1", "S5M8767 SET2", "S5M8767 SET3" }; if (!pdata) { dev_err(pdev->dev.parent, "Platform data not supplied\n"); @@ -696,12 +680,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) if (!s5m8767) return -ENOMEM; - size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); - s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!s5m8767->rdev) - return -ENOMEM; - - rdev = s5m8767->rdev; s5m8767->dev = &pdev->dev; s5m8767->iodev = iodev; s5m8767->num_regulators = pdata->num_regulators; @@ -711,12 +689,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; - s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; - s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; - s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; - s5m8767->buck_ds[0] = pdata->buck_ds[0]; - s5m8767->buck_ds[1] = pdata->buck_ds[1]; - s5m8767->buck_ds[2] = pdata->buck_ds[2]; s5m8767->ramp_delay = pdata->buck_ramp_delay; s5m8767->buck2_ramp = pdata->buck2_ramp_enable; @@ -727,17 +699,20 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, pdata->buck2_init); - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); + regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK2DVS2, + buck_init); buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, pdata->buck3_init); - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); + regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK3DVS2, + buck_init); buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, pdata->buck4_init); - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); + regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK4DVS2, + buck_init); for (i = 0; i < 8; i++) { if (s5m8767->buck2_gpiodvs) { @@ -764,131 +739,117 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { + for (i = 0; i < 3; i++) { + enum gpiod_flags flags; - if (!gpio_is_valid(pdata->buck_gpios[0]) || - !gpio_is_valid(pdata->buck_gpios[1]) || - !gpio_is_valid(pdata->buck_gpios[2])) { - dev_err(&pdev->dev, "GPIO NOT VALID\n"); - return -EINVAL; - } - - ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], - "S5M8767 SET1"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1], - "S5M8767 SET2"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2], - "S5M8767 SET3"); - if (ret) - return ret; + if (s5m8767->buck_gpioindex & BIT(2 - i)) + flags = GPIOD_OUT_HIGH; + else + flags = GPIOD_OUT_LOW; + + s5m8767->buck_gpios[i] = devm_gpiod_get_index(iodev->dev, + "s5m8767,pmic-buck-dvs", i, + flags); + if (IS_ERR(s5m8767->buck_gpios[i])) { + return dev_err_probe(iodev->dev, PTR_ERR(s5m8767->buck_gpios[i]), + "invalid gpio[%d]\n", i); + } - /* SET1 GPIO */ - gpio_direction_output(pdata->buck_gpios[0], - (s5m8767->buck_gpioindex >> 2) & 0x1); - /* SET2 GPIO */ - gpio_direction_output(pdata->buck_gpios[1], - (s5m8767->buck_gpioindex >> 1) & 0x1); - /* SET3 GPIO */ - gpio_direction_output(pdata->buck_gpios[2], - (s5m8767->buck_gpioindex >> 0) & 0x1); + gpiod_set_consumer_name(s5m8767->buck_gpios[i], gpiodvs_names[i]); + } } - ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4"); - if (ret) - return ret; - - /* DS2 GPIO */ - gpio_direction_output(pdata->buck_ds[0], 0x0); - /* DS3 GPIO */ - gpio_direction_output(pdata->buck_ds[1], 0x0); - /* DS4 GPIO */ - gpio_direction_output(pdata->buck_ds[2], 0x0); - - if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || - pdata->buck4_gpiodvs) { - sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, - (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), - 1 << 1); - sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, - (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), - 1 << 1); - sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, - (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), - 1 << 1); + for (i = 0; i < 3; i++) { + s5m8767->buck_ds[i] = devm_gpiod_get_index(iodev->dev, + "s5m8767,pmic-buck-ds", i, + GPIOD_OUT_LOW); + if (IS_ERR(s5m8767->buck_ds[i])) { + return dev_err_probe(iodev->dev, PTR_ERR(s5m8767->buck_ds[i]), + "can't get GPIO %d\n", i); + } + gpiod_set_consumer_name(s5m8767->buck_ds[i], gpiods_names[i]); } + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK2CTRL, 1 << 1, + (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1)); + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK3CTRL, 1 << 1, + (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1)); + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK4CTRL, 1 << 1, + (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1)); + /* Initialize GPIO DVS registers */ for (i = 0; i < 8; i++) { if (s5m8767->buck2_gpiodvs) { - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, - s5m8767->buck2_vol[i]); + regmap_write(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK2DVS1 + i, + s5m8767->buck2_vol[i]); } if (s5m8767->buck3_gpiodvs) { - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, - s5m8767->buck3_vol[i]); + regmap_write(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK3DVS1 + i, + s5m8767->buck3_vol[i]); } if (s5m8767->buck4_gpiodvs) { - sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, - s5m8767->buck4_vol[i]); + regmap_write(s5m8767->iodev->regmap_pmic, + S5M8767_REG_BUCK4DVS1 + i, + s5m8767->buck4_vol[i]); } } if (s5m8767->buck2_ramp) - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_DVSRAMP, 0x08, 0x08); if (s5m8767->buck3_ramp) - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_DVSRAMP, 0x04, 0x04); if (s5m8767->buck4_ramp) - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_DVSRAMP, 0x02, 0x02); if (s5m8767->buck2_ramp || s5m8767->buck3_ramp || s5m8767->buck4_ramp) { + unsigned int val; switch (s5m8767->ramp_delay) { case 5: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x40, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_5; break; case 10: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x90, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_10; break; case 25: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xd0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_25; break; case 50: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xe0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_50; break; case 100: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xf0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_100; break; default: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x90, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_10; } + regmap_update_bits(s5m8767->iodev->regmap_pmic, + S5M8767_REG_DVSRAMP, + S5M8767_DVS_BUCK_RAMP_MASK, + val << S5M8767_DVS_BUCK_RAMP_SHIFT); } for (i = 0; i < pdata->num_regulators; i++) { const struct sec_voltage_desc *desc; - int id = pdata->regulators[i].id; + unsigned int id = pdata->regulators[i].id; + int enable_reg, enable_val; + struct regulator_dev *rdev; + + BUILD_BUG_ON(ARRAY_SIZE(regulators) != ARRAY_SIZE(reg_voltage_map)); + if (WARN_ON_ONCE(id >= ARRAY_SIZE(regulators))) + continue; desc = reg_voltage_map[id]; if (desc) { @@ -902,40 +863,54 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) regulators[id].vsel_mask = 0x3f; else regulators[id].vsel_mask = 0xff; + + ret = s5m8767_get_register(s5m8767, id, &enable_reg, + &enable_val); + if (ret) { + dev_err(s5m8767->dev, "error reading registers\n"); + return ret; + } + regulators[id].enable_reg = enable_reg; + regulators[id].enable_mask = S5M8767_ENCTRL_MASK; + regulators[id].enable_val = enable_val; } config.dev = s5m8767->dev; config.init_data = pdata->regulators[i].initdata; config.driver_data = s5m8767; - config.regmap = iodev->regmap; + config.regmap = iodev->regmap_pmic; config.of_node = pdata->regulators[i].reg_node; - - rdev[i] = regulator_register(®ulators[id], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + config.ena_gpiod = NULL; + if (pdata->regulators[i].ext_control_gpiod) { + /* Assigns config.ena_gpiod */ + s5m8767_regulator_config_ext_control(s5m8767, + &pdata->regulators[i], &config); + + /* + * Hand the GPIO descriptor management over to the + * regulator core, remove it from devres management. + */ + devm_gpiod_unhinge(s5m8767->dev, config.ena_gpiod); + } + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(s5m8767->dev, "regulator init failed for %d\n", id); - rdev[i] = NULL; - goto err; + return ret; } - } - - return 0; -err: - for (i = 0; i < s5m8767->num_regulators; i++) - regulator_unregister(rdev[i]); - - return ret; -} - -static int s5m8767_pmic_remove(struct platform_device *pdev) -{ - struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); - struct regulator_dev **rdev = s5m8767->rdev; - int i; - for (i = 0; i < s5m8767->num_regulators; i++) - regulator_unregister(rdev[i]); + if (pdata->regulators[i].ext_control_gpiod) { + ret = s5m8767_enable_ext_control(s5m8767, rdev); + if (ret < 0) { + dev_err(s5m8767->dev, + "failed to enable gpio control over %s: %d\n", + rdev->desc->name, ret); + return ret; + } + } + } return 0; } @@ -949,26 +924,14 @@ MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); static struct platform_driver s5m8767_pmic_driver = { .driver = { .name = "s5m8767-pmic", - .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = s5m8767_pmic_probe, - .remove = s5m8767_pmic_remove, .id_table = s5m8767_pmic_id, }; - -static int __init s5m8767_pmic_init(void) -{ - return platform_driver_register(&s5m8767_pmic_driver); -} -subsys_initcall(s5m8767_pmic_init); - -static void __exit s5m8767_pmic_exit(void) -{ - platform_driver_unregister(&s5m8767_pmic_driver); -} -module_exit(s5m8767_pmic_exit); +module_platform_driver(s5m8767_pmic_driver); /* Module information */ MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); +MODULE_DESCRIPTION("Samsung S5M8767 Regulator Driver"); MODULE_LICENSE("GPL"); |
