]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge remote-tracking branches 'regulator/topic/s5m8767', 'regulator/topic/st-pwm...
authorMark Brown <broonie@linaro.org>
Wed, 26 Mar 2014 16:58:18 +0000 (16:58 +0000)
committerMark Brown <broonie@linaro.org>
Wed, 26 Mar 2014 16:58:18 +0000 (16:58 +0000)
14 files changed:
Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/s5m8767.c
drivers/regulator/st-pwm.c [new file with mode: 0644]
drivers/regulator/ti-abb-regulator.c
drivers/regulator/tps51632-regulator.c
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps65217-regulator.c
include/linux/mfd/samsung/core.h
include/linux/mfd/samsung/s5m8767.h

index fc6b38f035bd4b8a4e369e67d6eb25bb4d87edf9..d290988ed975fee4883ff6a49a0e5d79ae82feee 100644 (file)
@@ -69,13 +69,16 @@ sub-node should be of the format as listed below.
                };
        };
 The above regulator entries are defined in regulator bindings documentation
-except op_mode description.
+except these properties:
        - op_mode: describes the different operating modes of the LDO's with
                power mode change in SOC. The different possible values are,
                0 - always off mode
                1 - on in normal mode
                2 - low power mode
                3 - suspend mode
+       - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
+               GPIO controlling this regulator (enable/disable); This is
+               valid only for buck9.
 
 The following are the names of the regulators that the s5m8767 pmic block
 supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
@@ -148,5 +151,13 @@ Example:
                                regulator-always-on;
                                regulator-boot-on;
                        };
+
+                       vemmc_reg: BUCK9 {
+                               regulator-name = "VMEM_VDD_2.8V";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               op_mode = <3>; /* Standby Mode */
+                               s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
+                       };
                };
        };
index 2e57a33e9029a39fa80c2da517e7d4bb8df4aa4d..c58db75f959e601fcf326a0637d79617253a8206 100644 (file)
@@ -4,10 +4,14 @@ Required Properties:
 - compatible: Should be one of:
   - "ti,abb-v1" for older SoCs like OMAP3
   - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+  - "ti,abb-v3" for a generic definition where setup and control registers are
+     provided (example: DRA7)
 - reg: Address and length of the register set for the device. It contains
   the information of registers in the same order as described by reg-names
 - reg-names: Should contain the reg names
-  - "base-address"     - contains base address of ABB module
+  - "base-address"     - contains base address of ABB module (ti,abb-v1,ti,abb-v2)
+  - "control-address"  - contains control register address of ABB module (ti,abb-v3)
+  - "setup-address"    - contains setup register address of ABB module (ti,abb-v3)
   - "int-address"      - contains address of interrupt register for ABB module
   (also see Optional properties)
 - #address-cell: should be 0
index e5e4017b10112624582d61ef6aac4af608b03a84..8f3866c44a3fd031841cdc90cdee99af58ebb8a7 100644 (file)
@@ -448,6 +448,12 @@ config REGULATOR_S5M8767
         via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
         supports DVS mode with 8bits of output voltage control.
 
+config REGULATOR_ST_PWM
+       tristate "STMicroelectronics PWM voltage regulator"
+       depends on ARCH_STI
+       help
+        This driver supports ST's PWM controlled voltage regulators.
+
 config REGULATOR_TI_ABB
        tristate "TI Adaptive Body Bias on-chip LDO"
        depends on ARCH_OMAP
index c3416728c14d505685a6daeae905741bdb31b95e..0cfca37941ec4aa6d97ff77a531ac202550893e3 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
index d958dfa051254866808fe6c36cf9db7184627b94..f05badabd69e99169a0adcb9f4d4d335891cafb8 100644 (file)
  *
  */
 
-#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>
@@ -170,12 +167,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:
@@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
        return 0;
 }
 
-static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg;
-       int enable_ctrl;
-       unsigned int val;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret == -EINVAL)
-               return 1;
-       else if (ret)
-               return ret;
-
-       ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val);
-       if (ret)
-               return ret;
-
-       return (val & S5M8767_ENCTRL_MASK) == enable_ctrl;
-}
-
-static int s5m8767_reg_enable(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg;
-       int enable_ctrl;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret)
-               return ret;
-
-       return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
-                       S5M8767_ENCTRL_MASK, enable_ctrl);
-}
-
-static int s5m8767_reg_disable(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg, enable_ctrl;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret)
-               return ret;
-
-       return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
-                       S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK);
-}
-
 static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
 {
        int reg;
@@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
 
 static 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,
@@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = {
 
 static struct regulator_ops s5m8767_buck78_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        = regulator_set_voltage_sel_regmap,
 };
@@ -483,6 +432,66 @@ 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 id = rdev_get_id(rdev);
+       int ret, reg, enable_ctrl;
+
+       if (id != S5M8767_BUCK9)
+               return -EINVAL;
+
+       ret = s5m8767_get_register(s5m8767, id, &reg, &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 +529,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)
 {
@@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
 
        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");
+       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");
+       if (!rmode)
                return -ENOMEM;
-       }
 
        pdata->regulators = rdata;
        pdata->opmode = rmode;
@@ -574,6 +587,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);
@@ -922,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
        for (i = 0; i < pdata->num_regulators; i++) {
                const struct sec_voltage_desc *desc;
                int id = pdata->regulators[i].id;
+               int enable_reg, enable_val;
 
                desc = reg_voltage_map[id];
                if (desc) {
@@ -935,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                                regulators[id].vsel_mask = 0x3f;
                        else
                                regulators[id].vsel_mask = 0xff;
+
+                       s5m8767_get_register(s5m8767, id, &enable_reg,
+                                            &enable_val);
+                       regulators[id].enable_reg = enable_reg;
+                       regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
+                       regulators[id].enable_val = enable_val;
                }
 
                config.dev = s5m8767->dev;
@@ -942,6 +964,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, &regulators[id],
                                                  &config);
@@ -951,6 +976,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;
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
new file mode 100644 (file)
index 0000000..e367af1
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Regulator driver for ST's PWM Regulators
+ *
+ * Copyright (C) 2014 - STMicroelectronics Inc.
+ *
+ * Author: Lee Jones <lee.jones@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pwm.h>
+
+#define ST_PWM_REG_PERIOD 8448
+
+struct st_pwm_regulator_pdata {
+       const struct regulator_desc *desc;
+       struct st_pwm_voltages *duty_cycle_table;
+};
+
+struct st_pwm_regulator_data {
+       const struct st_pwm_regulator_pdata *pdata;
+       struct pwm_device *pwm;
+       bool enabled;
+       int state;
+};
+
+struct st_pwm_voltages {
+       unsigned int uV;
+       unsigned int dutycycle;
+};
+
+static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+       return drvdata->state;
+}
+
+static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
+                                           unsigned selector)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+       int dutycycle;
+       int ret;
+
+       dutycycle = (ST_PWM_REG_PERIOD / 100) *
+               drvdata->pdata->duty_cycle_table[selector].dutycycle;
+
+       ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
+       if (ret) {
+               dev_err(&dev->dev, "Failed to configure PWM\n");
+               return ret;
+       }
+
+       drvdata->state = selector;
+
+       if (!drvdata->enabled) {
+               ret = pwm_enable(drvdata->pwm);
+               if (ret) {
+                       dev_err(&dev->dev, "Failed to enable PWM\n");
+                       return ret;
+               }
+               drvdata->enabled = true;
+       }
+
+       return 0;
+}
+
+static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
+                                        unsigned selector)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+       if (selector >= dev->desc->n_voltages)
+               return -EINVAL;
+
+       return drvdata->pdata->duty_cycle_table[selector].uV;
+}
+
+static struct regulator_ops st_pwm_regulator_voltage_ops = {
+       .set_voltage_sel = st_pwm_regulator_set_voltage_sel,
+       .get_voltage_sel = st_pwm_regulator_get_voltage_sel,
+       .list_voltage    = st_pwm_regulator_list_voltage,
+       .map_voltage     = regulator_map_voltage_iterate,
+};
+
+static struct st_pwm_voltages b2105_duty_cycle_table[] = {
+       { .uV = 1114000, .dutycycle = 0,  },
+       { .uV = 1095000, .dutycycle = 10, },
+       { .uV = 1076000, .dutycycle = 20, },
+       { .uV = 1056000, .dutycycle = 30, },
+       { .uV = 1036000, .dutycycle = 40, },
+       { .uV = 1016000, .dutycycle = 50, },
+       /* WARNING: Values above 50% duty-cycle cause boot failures. */
+};
+
+static const struct regulator_desc b2105_desc = {
+       .name           = "b2105-pwm-regulator",
+       .ops            = &st_pwm_regulator_voltage_ops,
+       .type           = REGULATOR_VOLTAGE,
+       .owner          = THIS_MODULE,
+       .n_voltages     = ARRAY_SIZE(b2105_duty_cycle_table),
+       .supply_name    = "pwm",
+};
+
+static const struct st_pwm_regulator_pdata b2105_info = {
+       .desc             = &b2105_desc,
+       .duty_cycle_table = b2105_duty_cycle_table,
+};
+
+static struct of_device_id st_pwm_of_match[] = {
+       { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
+       { },
+};
+MODULE_DEVICE_TABLE(of, st_pwm_of_match);
+
+static int st_pwm_regulator_probe(struct platform_device *pdev)
+{
+       struct st_pwm_regulator_data *drvdata;
+       struct regulator_dev *regulator;
+       struct regulator_config config = { };
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_match;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Device Tree node missing\n");
+               return -EINVAL;
+       }
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       of_match = of_match_device(st_pwm_of_match, &pdev->dev);
+       if (!of_match) {
+               dev_err(&pdev->dev, "failed to match of device\n");
+               return -ENODEV;
+       }
+       drvdata->pdata = of_match->data;
+
+       config.init_data = of_get_regulator_init_data(&pdev->dev, np);
+       if (!config.init_data)
+               return -ENOMEM;
+
+       config.of_node = np;
+       config.dev = &pdev->dev;
+       config.driver_data = drvdata;
+
+       drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
+       if (IS_ERR(drvdata->pwm)) {
+               dev_err(&pdev->dev, "Failed to get PWM\n");
+               return PTR_ERR(drvdata->pwm);
+       }
+
+       regulator = devm_regulator_register(&pdev->dev,
+                                           drvdata->pdata->desc, &config);
+       if (IS_ERR(regulator)) {
+               dev_err(&pdev->dev, "Failed to register regulator %s\n",
+                       drvdata->pdata->desc->name);
+               return PTR_ERR(regulator);
+       }
+
+       return 0;
+}
+
+static struct platform_driver st_pwm_regulator_driver = {
+       .driver = {
+               .name           = "st-pwm-regulator",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(st_pwm_of_match),
+       },
+       .probe = st_pwm_regulator_probe,
+};
+
+module_platform_driver(st_pwm_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
+MODULE_DESCRIPTION("ST PWM Regulator Driver");
+MODULE_ALIAS("platform:st_pwm-regulator");
index b187b6bba7ad485a9a8d97ba248b0a70de89c5c8..a2dabb575b97d6260837da1deca24e821accc4f0 100644 (file)
@@ -54,8 +54,8 @@ struct ti_abb_info {
 
 /**
  * struct ti_abb_reg - Register description for ABB block
- * @setup_reg:                 setup register offset from base
- * @control_reg:               control register offset from base
+ * @setup_off:                 setup register offset from base
+ * @control_off:               control register offset from base
  * @sr2_wtcnt_value_mask:      setup register- sr2_wtcnt_value mask
  * @fbb_sel_mask:              setup register- FBB sel mask
  * @rbb_sel_mask:              setup register- RBB sel mask
@@ -64,8 +64,8 @@ struct ti_abb_info {
  * @opp_sel_mask:              control register - mask for mode to operate
  */
 struct ti_abb_reg {
-       u32 setup_reg;
-       u32 control_reg;
+       u32 setup_off;
+       u32 control_off;
 
        /* Setup register fields */
        u32 sr2_wtcnt_value_mask;
@@ -83,6 +83,8 @@ struct ti_abb_reg {
  * @rdesc:                     regulator descriptor
  * @clk:                       clock(usually sysclk) supplying ABB block
  * @base:                      base address of ABB block
+ * @setup_reg:                 setup register of ABB block
+ * @control_reg:               control register of ABB block
  * @int_base:                  interrupt register base address
  * @efuse_base:                        (optional) efuse base address for ABB modes
  * @ldo_base:                  (optional) LDOVBB vset override base address
@@ -99,6 +101,8 @@ struct ti_abb {
        struct regulator_desc rdesc;
        struct clk *clk;
        void __iomem *base;
+       void __iomem *setup_reg;
+       void __iomem *control_reg;
        void __iomem *int_base;
        void __iomem *efuse_base;
        void __iomem *ldo_base;
@@ -118,20 +122,18 @@ struct ti_abb {
  * ti_abb_rmw() - handy wrapper to set specific register bits
  * @mask:      mask for register field
  * @value:     value shifted to mask location and written
- * @offset:    offset of register
- * @base:      base address
+ * @reg:       register address
  *
  * Return: final register value (may be unused)
  */
-static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset,
-                            void __iomem *base)
+static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg)
 {
        u32 val;
 
-       val = readl(base + offset);
+       val = readl(reg);
        val &= ~mask;
        val |= (value << __ffs(mask)) & mask;
-       writel(val, base + offset);
+       writel(val, reg);
 
        return val;
 }
@@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        if (ret)
                goto out;
 
-       ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg,
-                  abb->base);
+       ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg);
 
        switch (info->opp_sel) {
        case TI_ABB_SLOW_OPP:
-               ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base);
+               ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg);
                break;
        case TI_ABB_FAST_OPP:
-               ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base);
+               ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg);
                break;
        }
 
        /* program next state of ABB ldo */
-       ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
-                  abb->base);
+       ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg);
 
        /*
         * program LDO VBB vset override if needed for !bypass mode
@@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
                ti_abb_program_ldovbb(dev, abb, info);
 
        /* Initiate ABB ldo change */
-       ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base);
+       ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg);
 
        /* Wait for ABB LDO to complete transition to new Bias setting */
        ret = ti_abb_wait_txdone(dev, abb);
@@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)
        dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__,
                clk_get_rate(abb->clk), sr2_wt_cnt_val);
 
-       ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg,
-                  abb->base);
+       ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg);
 
        return 0;
 }
@@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
                             struct regulator_init_data *rinit_data)
 {
        struct ti_abb_info *info;
-       const struct property *prop;
-       const __be32 *abb_info;
        const u32 num_values = 6;
        char *pname = "ti,abb_info";
-       u32 num_entries, i;
+       u32 i;
        unsigned int *volt_table;
-       int min_uV = INT_MAX, max_uV = 0;
+       int num_entries, min_uV = INT_MAX, max_uV = 0;
        struct regulation_constraints *c = &rinit_data->constraints;
 
-       prop = of_find_property(dev->of_node, pname, NULL);
-       if (!prop) {
-               dev_err(dev, "No '%s' property?\n", pname);
-               return -ENODEV;
-       }
-
-       if (!prop->value) {
-               dev_err(dev, "Empty '%s' property?\n", pname);
-               return -ENODATA;
-       }
-
        /*
         * Each abb_info is a set of n-tuple, where n is num_values, consisting
         * of voltage and a set of detection logic for ABB information for that
         * voltage to apply.
         */
-       num_entries = prop->length / sizeof(u32);
+       num_entries = of_property_count_u32_elems(dev->of_node, pname);
+       if (num_entries < 0) {
+               dev_err(dev, "No '%s' property?\n", pname);
+               return num_entries;
+       }
+
        if (!num_entries || (num_entries % num_values)) {
                dev_err(dev, "All '%s' list entries need %d vals\n", pname,
                        num_values);
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
        num_entries /= num_values;
 
        info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL);
-       if (!info) {
-               dev_err(dev, "Can't allocate info table for '%s' property\n",
-                       pname);
+       if (!info)
                return -ENOMEM;
-       }
+
        abb->info = info;
 
        volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries,
                                  GFP_KERNEL);
-       if (!volt_table) {
-               dev_err(dev, "Can't allocate voltage table for '%s' property\n",
-                       pname);
+       if (!volt_table)
                return -ENOMEM;
-       }
 
        abb->rdesc.n_voltages = num_entries;
        abb->rdesc.volt_table = volt_table;
        /* We do not know where the OPP voltage is at the moment */
        abb->current_info_idx = -EINVAL;
 
-       abb_info = prop->value;
        for (i = 0; i < num_entries; i++, info++, volt_table++) {
                u32 efuse_offset, rbb_mask, fbb_mask, vset_mask;
                u32 efuse_val;
 
                /* NOTE: num_values should equal to entries picked up here */
-               *volt_table = be32_to_cpup(abb_info++);
-               info->opp_sel = be32_to_cpup(abb_info++);
-               efuse_offset = be32_to_cpup(abb_info++);
-               rbb_mask = be32_to_cpup(abb_info++);
-               fbb_mask = be32_to_cpup(abb_info++);
-               vset_mask = be32_to_cpup(abb_info++);
+               of_property_read_u32_index(dev->of_node, pname, i * num_values,
+                                          volt_table);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 1, &info->opp_sel);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 2, &efuse_offset);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 3, &rbb_mask);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 4, &fbb_mask);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 5, &vset_mask);
 
                dev_dbg(dev,
                        "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n",
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = {
 /* Default ABB block offsets, IF this changes in future, create new one */
 static const struct ti_abb_reg abb_regs_v1 = {
        /* WARNING: registers are wrongly documented in TRM */
-       .setup_reg              = 0x04,
-       .control_reg            = 0x00,
+       .setup_off              = 0x04,
+       .control_off            = 0x00,
 
        .sr2_wtcnt_value_mask   = (0xff << 8),
        .fbb_sel_mask           = (0x01 << 2),
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = {
 };
 
 static const struct ti_abb_reg abb_regs_v2 = {
-       .setup_reg              = 0x00,
-       .control_reg            = 0x04,
+       .setup_off              = 0x00,
+       .control_off            = 0x04,
 
        .sr2_wtcnt_value_mask   = (0xff << 8),
        .fbb_sel_mask           = (0x01 << 2),
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = {
        .opp_sel_mask           = (0x03 << 0),
 };
 
+static const struct ti_abb_reg abb_regs_generic = {
+       .sr2_wtcnt_value_mask   = (0xff << 8),
+       .fbb_sel_mask           = (0x01 << 2),
+       .rbb_sel_mask           = (0x01 << 1),
+       .sr2_en_mask            = (0x01 << 0),
+
+       .opp_change_mask        = (0x01 << 2),
+       .opp_sel_mask           = (0x03 << 0),
+};
+
 static const struct of_device_id ti_abb_of_match[] = {
        {.compatible = "ti,abb-v1", .data = &abb_regs_v1},
        {.compatible = "ti,abb-v2", .data = &abb_regs_v2},
+       {.compatible = "ti,abb-v3", .data = &abb_regs_generic},
        { },
 };
 
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev)
        abb->regs = match->data;
 
        /* Map ABB resources */
-       pname = "base-address";
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
-       abb->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(abb->base))
-               return PTR_ERR(abb->base);
+       if (abb->regs->setup_off || abb->regs->control_off) {
+               pname = "base-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->base))
+                       return PTR_ERR(abb->base);
+
+               abb->setup_reg = abb->base + abb->regs->setup_off;
+               abb->control_reg = abb->base + abb->regs->control_off;
+
+       } else {
+               pname = "control-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->control_reg = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->control_reg))
+                       return PTR_ERR(abb->control_reg);
+
+               pname = "setup-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->setup_reg = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->setup_reg))
+                       return PTR_ERR(abb->setup_reg);
+       }
 
        pname = "int-address";
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
@@ -860,7 +880,7 @@ skip_opt:
        platform_set_drvdata(pdev, rdev);
 
        /* Enable the ldo if not already done by bootloader */
-       ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base);
+       ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg);
 
        return 0;
 }
index b3764f594ee933703394ebacd0e6610aa7c809bc..f31f22e3e1bd56c0b6f1e36a07152f8c3d0039bc 100644 (file)
@@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data *
        struct device_node *np = dev->of_node;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               dev_err(dev, "Memory alloc failed for platform data\n");
+       if (!pdata)
                return NULL;
-       }
 
        pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
        if (!pdata->reg_init_data) {
@@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client,
        }
 
        tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
-       if (!tps) {
-               dev_err(&client->dev, "Memory allocation failed\n");
+       if (!tps)
                return -ENOMEM;
-       }
 
        tps->dev = &client->dev;
        tps->desc.name = client->name;
index c3fa15a299b16fb4ea48cca9f4173a8e0b4d9c8a..a1672044e5195304095f5de99e5c4e01218cb828 100644 (file)
@@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data *
        struct device_node *np = dev->of_node;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               dev_err(dev, "Memory alloc failed for platform data\n");
+       if (!pdata)
                return NULL;
-       }
 
        pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
        if (!pdata->reg_init_data) {
@@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client,
        }
 
        tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
-       if (!tps) {
-               dev_err(&client->dev, "%s(): Memory allocation failed\n",
-                                               __func__);
+       if (!tps)
                return -ENOMEM;
-       }
 
        tps->en_discharge = pdata->en_discharge;
        tps->en_internal_pulldn = pdata->en_internal_pulldn;
index 162a0fae20b317bd0b4899e07520a45f496e43c6..98e66ce26723fac64c2cbd7b836f03c878465e28 100644 (file)
@@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = {
        .map_voltage = regulator_map_voltage_ascend,
 };
 
-#ifdef CONFIG_OF
 static struct of_regulator_match tps6507x_matches[] = {
        { .name = "VDCDC1"},
        { .name = "VDCDC2"},
@@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
                                        GFP_KERNEL);
-       if (!tps_board) {
-               dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+       if (!tps_board)
                return NULL;
-       }
 
-       regulators = of_find_node_by_name(np, "regulators");
+       regulators = of_get_child_by_name(np, "regulators");
        if (!regulators) {
                dev_err(&pdev->dev, "regulator node not found\n");
                return NULL;
@@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
        matches = tps6507x_matches;
 
        ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
                        ret);
@@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
                                        * TPS6507X_NUM_REGULATOR), GFP_KERNEL);
-       if (!reg_data) {
-               dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+       if (!reg_data)
                return NULL;
-       }
 
        tps_board->tps6507x_pmic_init_data = reg_data;
 
@@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        return tps_board;
 }
-#else
-static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
-                       struct platform_device *pdev,
-                       struct of_regulator_match **tps6507x_reg_matches)
-{
-       *tps6507x_reg_matches = NULL;
-       return NULL;
-}
-#endif
+
 static int tps6507x_pmic_probe(struct platform_device *pdev)
 {
        struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
         */
 
        tps_board = dev_get_platdata(tps6507x_dev->dev);
-       if (!tps_board && tps6507x_dev->dev->of_node)
+       if (IS_ENABLED(CONFIG_OF) && !tps_board &&
+               tps6507x_dev->dev->of_node)
                tps_board = tps6507x_parse_dt_reg_data(pdev,
-                                               &tps6507x_reg_matches);
+                               &tps6507x_reg_matches);
        if (!tps_board)
                return -EINVAL;
 
@@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
                tps->info[i] = info;
                if (init_data->driver_data) {
                        struct tps6507x_reg_platform_data *data =
-                                                       init_data->driver_data;
+                                       init_data->driver_data;
                        tps->info[i]->defdcdc_default = data->defdcdc_default;
                }
 
index 676f75548f0028435b6795bc0371490c462a641e..2e92ef68574da733e6fd81d3aed1760e627d5bc4 100644 (file)
@@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 
        tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
                                GFP_KERNEL);
-       if (!tps65090_pdata) {
-               dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+       if (!tps65090_pdata)
                return ERR_PTR(-ENOMEM);
-       }
 
        reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
                                sizeof(*reg_pdata), GFP_KERNEL);
-       if (!reg_pdata) {
-               dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+       if (!reg_pdata)
                return ERR_PTR(-ENOMEM);
-       }
 
        regulators = of_get_child_by_name(np, "regulators");
        if (!regulators) {
@@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 
        ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
                        ARRAY_SIZE(tps65090_matches));
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "Error parsing regulator init data: %d\n", ret);
@@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
 
        pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
                        GFP_KERNEL);
-       if (!pmic) {
-               dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+       if (!pmic)
                return -ENOMEM;
-       }
 
        for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
                tps_pdata = tps65090_pdata->reg_pdata[num];
index 9ea1bf26bd137b4b4e33dcede0c6c1551ff6d79c..10b78d2b766aa3394b1ee51b2bf47e616f6f95d4 100644 (file)
@@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
        struct device_node *regs;
        int i, count;
 
-       regs = of_find_node_by_name(node, "regulators");
+       regs = of_get_child_by_name(node, "regulators");
        if (!regs)
                return NULL;
 
@@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
                return NULL;
 
        for (i = 0; i < count; i++) {
-               if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+               if (!reg_matches[i].of_node)
                        continue;
 
                pdata->tps65217_init_data[i] = reg_matches[i].init_data;
@@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
 {
        struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
        struct tps65217_board *pdata = dev_get_platdata(tps->dev);
-       struct regulator_init_data *reg_data;
        struct regulator_dev *rdev;
        struct regulator_config config = { };
        int i;
@@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, tps);
 
        for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
-
-               reg_data = pdata->tps65217_init_data[i];
-
-               /*
-                * Regulator API handles empty constraints but not NULL
-                * constraints
-                */
-               if (!reg_data)
-                       continue;
-
                /* Register the regulators */
                config.dev = tps->dev;
-               config.init_data = reg_data;
+               config.init_data = pdata->tps65217_init_data[i];
                config.driver_data = tps;
                config.regmap = tps->regmap;
                if (tps->dev->of_node)
index 900bc9e1888b1d369c3caff0d5c05bbd8c9f14c1..157e32b6ca28790fccbc2a3d47d30c9b210d6ec4 100644 (file)
@@ -126,7 +126,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;
 };
 
 /*
index 2ab0b0f03641334077cc16c4bbd8ec8c9159619c..243b58fec33dacd3fa053e10bf7ca2e2a9c027a3 100644 (file)
@@ -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.