Merge tag 'regulator-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 17:22:19 +0000 (09:22 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 17:22:19 +0000 (09:22 -0800)
Pull regulator updates from Mark Brown:
 "A fairly quiet release for the regulator API, the bulk of the changes
  being lots of small cleanups and API updates contributed by Axel Lin
  with just a small set of larger changes:

   - New driver for LP8755

   - DT support for S5M8767, TPS51632, TPS6507x and TPS65090

   - Support for writing a "commit changes" bit in the regmap helper
     functions."

* tag 'regulator-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (60 commits)
  regulator: Fix memory garbage dev_err printout.
  regulator: max77686: Reuse rdev_get_id() function.
  regulator: tps51632: Use regulator_[get|set]_voltage_sel_regmap
  regulator: as3711: Fix checking if no platform initialization data
  regulator: s5m8767: Prevent possible NULL pointer dereference
  regulator: s5m8767: Fix dev argument for devm_kzalloc and of_get_regulator_init_data
  regulator: core: Optimize _regulator_do_set_voltage if voltage does not change
  regulator: max8998: Let regulator core handle the case selector == old_selector
  regulator: s5m8767: Use of_get_child_count()
  regulator: anatop: improve precision of delay time
  regulator: show state for GPIO-controlled regulators
  regulator: s5m8767: Fix build in non-DT case
  regulator: add device tree support for s5m8767
  regulator: palmas: Remove a redundant setting for warm_reset
  regulator: mc13xxx: Use of_get_child_count()
  regulator: max8997: Use of_get_child_count()
  regulator: tps65090: Fix using wrong dev argument for calling of_regulator_match
  regulators: anatop: add set_voltage_time_sel interface
  regulator: Add missing of_node_put()
  regulator: tps6507x: Fix using wrong dev argument for calling of_regulator_match
  ...

41 files changed:
Documentation/devicetree/bindings/mfd/tps6507x.txt [new file with mode: 0755]
Documentation/devicetree/bindings/regulator/anatop-regulator.txt
Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps51632-regulator.txt [new file with mode: 0644]
drivers/mfd/sec-core.c
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/as3711-regulator.c
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9055-regulator.c
drivers/regulator/gpio-regulator.c
drivers/regulator/lp3971.c
drivers/regulator/lp3972.c
drivers/regulator/lp872x.c
drivers/regulator/lp8755.c [new file with mode: 0644]
drivers/regulator/lp8788-buck.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686.c
drivers/regulator/max8907-regulator.c
drivers/regulator/max8925-regulator.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/mc13xxx.h
drivers/regulator/palmas-regulator.c
drivers/regulator/s5m8767.c
drivers/regulator/tps51632-regulator.c
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps6586x-regulator.c
drivers/regulator/tps65910-regulator.c
include/linux/mfd/samsung/core.h
include/linux/platform_data/lp8755.h [new file with mode: 0644]
include/linux/regulator/driver.h
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c

diff --git a/Documentation/devicetree/bindings/mfd/tps6507x.txt b/Documentation/devicetree/bindings/mfd/tps6507x.txt
new file mode 100755 (executable)
index 0000000..8fffa3c
--- /dev/null
@@ -0,0 +1,91 @@
+TPS6507x Power Management Integrated Circuit
+
+Required properties:
+- compatible: "ti,tps6507x"
+- reg: I2C slave address
+- regulators: This is the list of child nodes that specify the regulator
+  initialization data for defined regulators. Not all regulators for the
+  given device need to be present. The definition for each of these nodes
+  is defined using the standard binding for regulators found at
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+  The regulator is matched with the regulator-compatible.
+
+  The valid regulator-compatible values are:
+  tps6507x: vdcdc1, vdcdc2, vdcdc3, vldo1, vldo2
+- xxx-supply: Input voltage supply regulator.
+  These entries are required if regulators are enabled for a device.
+  Missing of these properties can cause the regulator registration
+  fails.
+  If some of input supply is powered through battery or always-on
+  supply then also it is require to have these parameters with proper
+  node handle of always on power supply.
+  tps6507x:
+       vindcdc1_2-supply: VDCDC1 and VDCDC2 input.
+       vindcdc3-supply  : VDCDC3 input.
+       vldo1_2-supply   : VLDO1 and VLDO2 input.
+
+Regulator Optional properties:
+- defdcdc_default: It's property of DCDC2 and DCDC3 regulators.
+                       0: If defdcdc pin of DCDC2/DCDC3 is pulled to GND.
+                       1: If defdcdc pin of DCDC2/DCDC3 is driven HIGH.
+  If this property is not defined, it defaults to 0 (not enabled).
+
+Example:
+
+       pmu: tps6507x@48 {
+               compatible = "ti,tps6507x";
+               reg = <0x48>;
+
+               vindcdc1_2-supply = <&vbat>;
+               vindcdc3-supply = <...>;
+               vinldo1_2-supply = <...>;
+
+               regulators {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vdcdc1_reg: regulator@0 {
+                               regulator-compatible = "VDCDC1";
+                               reg = <0>;
+                               regulator-min-microvolt = <3150000>;
+                               regulator-max-microvolt = <3450000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+                       vdcdc2_reg: regulator@1 {
+                               regulator-compatible = "VDCDC2";
+                               reg = <1>;
+                               regulator-min-microvolt = <1710000>;
+                               regulator-max-microvolt = <3450000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               defdcdc_default = <1>;
+                       };
+                       vdcdc3_reg: regulator@2 {
+                               regulator-compatible = "VDCDC3";
+                               reg = <2>;
+                               regulator-min-microvolt = <950000>
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               defdcdc_default = <1>;
+                       };
+                       ldo1_reg: regulator@3 {
+                               regulator-compatible = "LDO1";
+                               reg = <3>;
+                               regulator-min-microvolt = <1710000>;
+                               regulator-max-microvolt = <1890000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+                       ldo2_reg: regulator@4 {
+                               regulator-compatible = "LDO2";
+                               reg = <4>;
+                               regulator-min-microvolt = <1140000>;
+                               regulator-max-microvolt = <1320000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+
+       };
index 357758c..758eae2 100644 (file)
@@ -9,6 +9,11 @@ Required properties:
 - anatop-min-voltage: Minimum voltage of this regulator
 - anatop-max-voltage: Maximum voltage of this regulator
 
+Optional properties:
+- anatop-delay-reg-offset: Anatop MFD step time register offset
+- anatop-delay-bit-shift: Bit shift for the step time register
+- anatop-delay-bit-width: Number of bits used in the step time register
+
 Any property defined as part of the core regulator
 binding, defined in regulator.txt, can also be used.
 
@@ -23,6 +28,9 @@ Example:
                anatop-reg-offset = <0x140>;
                anatop-vol-bit-shift = <9>;
                anatop-vol-bit-width = <5>;
+               anatop-delay-reg-offset = <0x170>;
+               anatop-delay-bit-shift = <24>;
+               anatop-delay-bit-width = <2>;
                anatop-min-bit-val = <1>;
                anatop-min-voltage = <725000>;
                anatop-max-voltage = <1300000>;
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
new file mode 100644 (file)
index 0000000..a35ff99
--- /dev/null
@@ -0,0 +1,152 @@
+* Samsung S5M8767 Voltage and Current Regulator
+
+The Samsung S5M8767 is a multi-function device which includes volatage and
+current regulators, rtc, charger controller and other sub-blocks. It is
+interfaced to the host controller using a i2c interface. Each sub-block is
+addressed by the host system using different i2c slave address. This document
+describes the bindings for 'pmic' sub-block of s5m8767.
+
+Required properties:
+- compatible: Should be "samsung,s5m8767-pmic".
+- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
+
+- s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck2 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+- s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck3 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+- s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck4 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+- s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
+  for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
+
+[1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+    property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
+    property should specify atleast one voltage level (which would be a
+    safe operating voltage).
+
+    If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+    property is specified, then all the eight voltage values for the
+    's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the interrupts from s5m8767 are delivered to.
+- interrupts: Interrupt specifiers for two interrupt sources.
+  - First interrupt specifier is for 'irq1' interrupt.
+  - Second interrupt specifier is for 'alert' interrupt.
+- s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
+- s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
+- s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
+
+Additional properties required if either of the optional properties are used:
+
+- s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
+  the possible 8 options selectable by the dvs gpios. The value of this
+  property should be between 0 and 7. If not specified or if out of range, the
+  default value of this property is set to 0.
+
+- s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used
+  for dvs. The format of the gpio specifier depends in the gpio controller.
+
+Regulators: The regulators of s5m8767 that have to be instantiated should be
+included in a sub-node named 'regulators'. Regulator nodes included in this
+sub-node should be of the format as listed below.
+
+       regulator_name {
+               ldo1_reg: LDO1 {
+                       regulator-name = "VDD_ALIVE_1.0V";
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       op_mode = <1>; /* Normal Mode */
+               };
+       };
+The above regulator entries are defined in regulator bindings documentation
+except op_mode description.
+       - 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
+
+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
+as per the datasheet of s5m8767.
+
+       - LDOn
+                 - valid values for n are 1 to 28
+                 - Example: LDO0, LD01, LDO28
+       - BUCKn
+                 - valid values for n are 1 to 9.
+                 - Example: BUCK1, BUCK2, BUCK9
+
+The bindings inside the regulator nodes use the standard regulator bindings
+which are documented elsewhere.
+
+Example:
+
+       s5m8767_pmic@66 {
+               compatible = "samsung,s5m8767-pmic";
+               reg = <0x66>;
+
+               s5m8767,pmic-buck2-uses-gpio-dvs;
+               s5m8767,pmic-buck3-uses-gpio-dvs;
+               s5m8767,pmic-buck4-uses-gpio-dvs;
+
+               s5m8767,pmic-buck-default-dvs-idx = <0>;
+
+               s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */
+                                                <&gpx0 1 1 0 0>, /* DVS2 */
+                                                <&gpx0 2 1 0 0>; /* DVS3 */
+
+               s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
+                                               <&gpx2 4 1 0 0>, /* SET2 */
+                                               <&gpx2 5 1 0 0>; /* SET3 */
+
+               s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
+                                                <1250000>, <1200000>,
+                                                <1150000>, <1100000>,
+                                                <1000000>, <950000>;
+
+               s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+                                                <1100000>, <1100000>,
+                                                <1000000>, <1000000>,
+                                                <1000000>, <1000000>;
+
+               s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+                                                <1200000>, <1200000>,
+                                                <1200000>, <1200000>,
+                                                <1200000>, <1200000>;
+
+               regulators {
+                       ldo1_reg: LDO1 {
+                               regulator-name = "VDD_ABB_3.3V";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               op_mode = <1>; /* Normal Mode */
+                       };
+
+                       ldo2_reg: LDO2 {
+                               regulator-name = "VDD_ALIVE_1.1V";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                       };
+
+                       buck1_reg: BUCK1 {
+                               regulator-name = "VDD_MIF_1.2V";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/regulator/tps51632-regulator.txt b/Documentation/devicetree/bindings/regulator/tps51632-regulator.txt
new file mode 100644 (file)
index 0000000..2f7e44a
--- /dev/null
@@ -0,0 +1,27 @@
+TPS51632 Voltage regulators
+
+Required properties:
+- compatible: Must be "ti,tps51632"
+- reg: I2C slave address
+
+Optional properties:
+- ti,enable-pwm-dvfs: Enable the DVFS voltage control through the PWM interface.
+- ti,dvfs-step-20mV: The 20mV step voltage when PWM DVFS enabled. Missing this
+       will set 10mV step voltage in PWM DVFS mode. In normal mode, the voltage
+       step is 10mV as per datasheet.
+
+Any property defined as part of the core regulator binding, defined in
+regulator.txt, can also be used.
+
+Example:
+
+       tps51632 {
+               compatible = "ti,tps51632";
+               reg =  <0x43>;
+               regulator-name = "tps51632-vout";
+               regulator-min-microvolt = <500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-boot-on;
+               ti,enable-pwm-dvfs;
+               ti,dvfs-step-20mV;
+       };
index 49d361a..77ee26e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/of_irq.h>
 #include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
@@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = {
        },
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id sec_dt_match[] = {
+       {       .compatible = "samsung,s5m8767-pmic",
+               .data = (void *)S5M8767X,
+       },
+       {},
+};
+#endif
+
 int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
 {
        return regmap_read(sec_pmic->regmap, reg, dest);
@@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = {
        .val_bits = 8,
 };
 
+
+#ifdef CONFIG_OF
+/*
+ * Only the common platform data elements for s5m8767 are parsed here from the
+ * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
+ * others have to parse their own platform data elements from device tree.
+ *
+ * The s5m8767 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+                                       struct device *dev)
+{
+       struct sec_platform_data *pd;
+
+       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+       if (!pd) {
+               dev_err(dev, "could not allocate memory for pdata\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /*
+        * ToDo: the 'wakeup' member in the platform data is more of a linux
+        * specfic information. Hence, there is no binding for that yet and
+        * not parsed here.
+        */
+
+       return pd;
+}
+#else
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+                                       struct device *dev)
+{
+       return 0;
+}
+#endif
+
+static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+                                               const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+       if (i2c->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(sec_dt_match, i2c->dev.of_node);
+               return (int)match->data;
+       }
+#endif
+       return (int)id->driver_data;
+}
+
 static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        sec_pmic->dev = &i2c->dev;
        sec_pmic->i2c = i2c;
        sec_pmic->irq = i2c->irq;
-       sec_pmic->type = id->driver_data;
-
+       sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
+
+       if (sec_pmic->dev->of_node) {
+               pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
+               if (IS_ERR(pdata)) {
+                       ret = PTR_ERR(pdata);
+                       return ret;
+               }
+               pdata->device_type = sec_pmic->type;
+       }
        if (pdata) {
                sec_pmic->device_type = pdata->device_type;
                sec_pmic->ono = pdata->ono;
                sec_pmic->irq_base = pdata->irq_base;
                sec_pmic->wakeup = pdata->wakeup;
+               sec_pmic->pdata = pdata;
        }
 
        sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
@@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = {
        .driver = {
                   .name = "sec_pmic",
                   .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(sec_dt_match),
        },
        .probe = sec_pmic_probe,
        .remove = sec_pmic_remove,
index 2b55711..c79ab84 100644 (file)
@@ -30,8 +30,6 @@ struct pm8607_regulator_info {
        unsigned int    *vol_table;
        unsigned int    *vol_suspend;
 
-       int     update_reg;
-       int     update_bit;
        int     slope_double;
 };
 
@@ -222,29 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
        return ret;
 }
 
-static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
-{
-       struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-       uint8_t val;
-       int ret;
-
-       val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
-
-       ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
-                             rdev->desc->vsel_mask, val);
-       if (ret)
-               return ret;
-       switch (info->desc.id) {
-       case PM8607_ID_BUCK1:
-       case PM8607_ID_BUCK3:
-               ret = pm860x_set_bits(info->i2c, info->update_reg,
-                                     1 << info->update_bit,
-                                     1 << info->update_bit);
-               break;
-       }
-       return ret;
-}
-
 static int pm8606_preg_enable(struct regulator_dev *rdev)
 {
        struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
@@ -276,7 +251,7 @@ static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
 
 static struct regulator_ops pm8607_regulator_ops = {
        .list_voltage   = pm8607_list_voltage,
-       .set_voltage_sel = pm8607_set_voltage_sel,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -313,11 +288,11 @@ static struct regulator_ops pm8606_preg_ops = {
                .n_voltages = ARRAY_SIZE(vreg##_table),                 \
                .vsel_reg = PM8607_##vreg,                              \
                .vsel_mask = ARRAY_SIZE(vreg##_table) - 1,              \
+               .apply_reg = PM8607_##ureg,                             \
+               .apply_bit = (ubit),                                    \
                .enable_reg = PM8607_##ereg,                            \
                .enable_mask = 1 << (ebit),                             \
        },                                                              \
-       .update_reg     = PM8607_##ureg,                                \
-       .update_bit     = (ubit),                                       \
        .slope_double   = (0),                                          \
        .vol_table      = (unsigned int *)&vreg##_table,                \
        .vol_suspend    = (unsigned int *)&vreg##_suspend_table,        \
@@ -343,9 +318,9 @@ static struct regulator_ops pm8606_preg_ops = {
 }
 
 static struct pm8607_regulator_info pm8607_regulator_info[] = {
-       PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
-       PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
-       PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
+       PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0),
+       PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1),
+       PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2),
 
        PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
        PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
@@ -372,7 +347,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
                                    struct regulator_config *config)
 {
        struct device_node *nproot, *np;
-       nproot = pdev->dev.parent->of_node;
+       nproot = of_node_get(pdev->dev.parent->of_node);
        if (!nproot)
                return -ENODEV;
        nproot = of_find_node_by_name(nproot, "regulators");
@@ -388,6 +363,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
                        break;
                }
        }
+       of_node_put(nproot);
        return 0;
 }
 #else
index 551a22b..a5d97ea 100644 (file)
@@ -91,6 +91,7 @@ config REGULATOR_AAT2870
 config REGULATOR_ARIZONA
        tristate "Wolfson Arizona class devices"
        depends on MFD_ARIZONA
+       depends on SND_SOC
        help
          Support for the regulators found on Wolfson Arizona class
          devices.
@@ -277,6 +278,15 @@ config REGULATOR_LP872X
        help
          This driver supports LP8720/LP8725 PMIC
 
+config REGULATOR_LP8755
+       tristate "TI LP8755 High Performance PMU driver"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This driver supports LP8755 High Performance PMU driver. This
+         chip contains six step-down DC/DC converters which can support
+         9 mode multiphase configuration.
+
 config REGULATOR_LP8788
        bool "TI LP8788 Power Regulators"
        depends on MFD_LP8788
index b802b0c..6e82503 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
 obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
 obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
 obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
+obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)        += max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
index 8f39cac..0d4a8cc 100644 (file)
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 
+#define LDO_RAMP_UP_UNIT_IN_CYCLES      64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */
+
 struct anatop_regulator {
        const char *name;
        u32 control_reg;
        struct regmap *anatop;
        int vol_bit_shift;
        int vol_bit_width;
+       u32 delay_reg;
+       int delay_bit_shift;
+       int delay_bit_width;
        int min_bit_val;
        int min_voltage;
        int max_voltage;
@@ -55,6 +61,32 @@ static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
        return regulator_set_voltage_sel_regmap(reg, selector);
 }
 
+static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
+       unsigned int old_sel,
+       unsigned int new_sel)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       u32 val;
+       int ret = 0;
+
+       /* check whether need to care about LDO ramp up speed */
+       if (anatop_reg->delay_bit_width && new_sel > old_sel) {
+               /*
+                * the delay for LDO ramp up time is
+                * based on the register setting, we need
+                * to calculate how many steps LDO need to
+                * ramp up, and how much delay needed. (us)
+                */
+               regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val);
+               val = (val >> anatop_reg->delay_bit_shift) &
+                       ((1 << anatop_reg->delay_bit_width) - 1);
+               ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES <<
+                       val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1;
+       }
+
+       return ret;
+}
+
 static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
@@ -67,6 +99,7 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
 
 static struct regulator_ops anatop_rops = {
        .set_voltage_sel = anatop_regmap_set_voltage_sel,
+       .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
        .get_voltage_sel = anatop_regmap_get_voltage_sel,
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
@@ -143,6 +176,14 @@ static int anatop_regulator_probe(struct platform_device *pdev)
                goto anatop_probe_end;
        }
 
+       /* read LDO ramp up setting, only for core reg */
+       of_property_read_u32(np, "anatop-delay-reg-offset",
+                            &sreg->delay_reg);
+       of_property_read_u32(np, "anatop-delay-bit-width",
+                            &sreg->delay_bit_width);
+       of_property_read_u32(np, "anatop-delay-bit-shift",
+                            &sreg->delay_bit_shift);
+
        rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
                            + sreg->min_bit_val;
        rdesc->min_uV = sreg->min_voltage;
index a6d040c..e87536b 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/pdata.h>
@@ -34,6 +36,8 @@ struct arizona_micsupp {
 
        struct regulator_consumer_supply supply;
        struct regulator_init_data init_data;
+
+       struct work_struct check_cp_work;
 };
 
 static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
@@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
        return selector;
 }
 
+static void arizona_micsupp_check_cp(struct work_struct *work)
+{
+       struct arizona_micsupp *micsupp =
+               container_of(work, struct arizona_micsupp, check_cp_work);
+       struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
+       struct arizona *arizona = micsupp->arizona;
+       struct regmap *regmap = arizona->regmap;
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
+               return;
+       }
+
+       if (dapm) {
+               if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
+                   ARIZONA_CPMIC_ENA)
+                       snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
+               else
+                       snd_soc_dapm_disable_pin(dapm, "MICSUPP");
+
+               snd_soc_dapm_sync(dapm);
+       }
+}
+
+static int arizona_micsupp_enable(struct regulator_dev *rdev)
+{
+       struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = regulator_enable_regmap(rdev);
+
+       if (ret == 0)
+               schedule_work(&micsupp->check_cp_work);
+
+       return ret;
+}
+
+static int arizona_micsupp_disable(struct regulator_dev *rdev)
+{
+       struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = regulator_disable_regmap(rdev);
+       if (ret == 0)
+               schedule_work(&micsupp->check_cp_work);
+
+       return ret;
+}
+
+static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
+{
+       struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = regulator_set_bypass_regmap(rdev, ena);
+       if (ret == 0)
+               schedule_work(&micsupp->check_cp_work);
+
+       return ret;
+}
+
 static struct regulator_ops arizona_micsupp_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
+       .enable = arizona_micsupp_enable,
+       .disable = arizona_micsupp_disable,
        .is_enabled = regulator_is_enabled_regmap,
 
        .list_voltage = arizona_micsupp_list_voltage,
@@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 
        .get_bypass = regulator_get_bypass_regmap,
-       .set_bypass = regulator_set_bypass_regmap,
+       .set_bypass = arizona_micsupp_set_bypass,
 };
 
 static const struct regulator_desc arizona_micsupp = {
@@ -109,7 +177,8 @@ static const struct regulator_desc arizona_micsupp = {
 static const struct regulator_init_data arizona_micsupp_default = {
        .constraints = {
                .valid_ops_mask = REGULATOR_CHANGE_STATUS |
-                               REGULATOR_CHANGE_VOLTAGE,
+                               REGULATOR_CHANGE_VOLTAGE |
+                               REGULATOR_CHANGE_BYPASS,
                .min_uV = 1700000,
                .max_uV = 3300000,
        },
@@ -131,6 +200,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
        }
 
        micsupp->arizona = arizona;
+       INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
 
        /*
         * Since the chip usually supplies itself we provide some
index 2f1341d..f0ba8c4 100644 (file)
@@ -303,7 +303,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
                reg_data = pdata ? pdata->init_data[id] : NULL;
 
                /* No need to register if there is no regulator data */
-               if (!ri->desc.name)
+               if (!reg_data)
                        continue;
 
                reg = &regs[id];
index 2785843..da9782b 100644 (file)
@@ -200,8 +200,8 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
        }
 
        if (*min_uV > *max_uV) {
-               dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n",
-                       regulator->min_uV, regulator->max_uV);
+               rdev_err(rdev, "Restricting voltage, %u-%uuV\n",
+                       *min_uV, *max_uV);
                return -EINVAL;
        }
 
@@ -2080,10 +2080,20 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
  */
 int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
 {
+       int ret;
+
        sel <<= ffs(rdev->desc->vsel_mask) - 1;
 
-       return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+       ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
                                  rdev->desc->vsel_mask, sel);
+       if (ret)
+               return ret;
+
+       if (rdev->desc->apply_bit)
+               ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+                                        rdev->desc->apply_bit,
+                                        rdev->desc->apply_bit);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
 
@@ -2229,8 +2239,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                        best_val = rdev->desc->ops->list_voltage(rdev, ret);
                        if (min_uV <= best_val && max_uV >= best_val) {
                                selector = ret;
-                               ret = rdev->desc->ops->set_voltage_sel(rdev,
-                                                                      ret);
+                               if (old_selector == selector)
+                                       ret = 0;
+                               else
+                                       ret = rdev->desc->ops->set_voltage_sel(
+                                                               rdev, ret);
                        } else {
                                ret = -EINVAL;
                        }
@@ -2241,7 +2254,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 
        /* Call set_voltage_time_sel if successfully obtained old_selector */
        if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
-           rdev->desc->ops->set_voltage_time_sel) {
+           old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
 
                delay = rdev->desc->ops->set_voltage_time_sel(rdev,
                                                old_selector, selector);
@@ -2294,6 +2307,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
 {
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
+       int old_min_uV, old_max_uV;
 
        mutex_lock(&rdev->mutex);
 
@@ -2315,18 +2329,29 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
        if (ret < 0)
                goto out;
+       
+       /* restore original values in case of error */
+       old_min_uV = regulator->min_uV;
+       old_max_uV = regulator->max_uV;
        regulator->min_uV = min_uV;
        regulator->max_uV = max_uV;
 
        ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
        if (ret < 0)
-               goto out;
+               goto out2;
 
        ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
-
+       if (ret < 0)
+               goto out2;
+       
 out:
        mutex_unlock(&rdev->mutex);
        return ret;
+out2:
+       regulator->min_uV = old_min_uV;
+       regulator->max_uV = old_max_uV;
+       mutex_unlock(&rdev->mutex);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage);
 
@@ -3208,7 +3233,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
                if (status < 0)
                        return status;
        }
-       if (ops->is_enabled) {
+       if (rdev->ena_gpio || ops->is_enabled) {
                status = device_create_file(dev, &dev_attr_state);
                if (status < 0)
                        return status;
index d096309..96b569a 100644 (file)
@@ -70,7 +70,6 @@ struct da9052_regulator_info {
        int step_uV;
        int min_uV;
        int max_uV;
-       unsigned char activate_bit;
 };
 
 struct da9052_regulator {
@@ -210,36 +209,6 @@ static int da9052_map_voltage(struct regulator_dev *rdev,
        return sel;
 }
 
-static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
-                                           unsigned int selector)
-{
-       struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
-       struct da9052_regulator_info *info = regulator->info;
-       int id = rdev_get_id(rdev);
-       int ret;
-
-       ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
-                               rdev->desc->vsel_mask, selector);
-       if (ret < 0)
-               return ret;
-
-       /* Some LDOs and DCDCs are DVC controlled which requires enabling of
-        * the activate bit to implment the changes on the output.
-        */
-       switch (id) {
-       case DA9052_ID_BUCK1:
-       case DA9052_ID_BUCK2:
-       case DA9052_ID_BUCK3:
-       case DA9052_ID_LDO2:
-       case DA9052_ID_LDO3:
-               ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
-                                       info->activate_bit, info->activate_bit);
-               break;
-       }
-
-       return ret;
-}
-
 static struct regulator_ops da9052_dcdc_ops = {
        .get_current_limit = da9052_dcdc_get_current_limit,
        .set_current_limit = da9052_dcdc_set_current_limit,
@@ -247,7 +216,7 @@ static struct regulator_ops da9052_dcdc_ops = {
        .list_voltage = da9052_list_voltage,
        .map_voltage = da9052_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_sel = da9052_regulator_set_voltage_sel,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -257,7 +226,7 @@ static struct regulator_ops da9052_ldo_ops = {
        .list_voltage = da9052_list_voltage,
        .map_voltage = da9052_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_sel = da9052_regulator_set_voltage_sel,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -274,13 +243,14 @@ static struct regulator_ops da9052_ldo_ops = {
                .owner = THIS_MODULE,\
                .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
                .vsel_mask = (1 << (sbits)) - 1,\
+               .apply_reg = DA9052_SUPPLY_REG, \
+               .apply_bit = (abits), \
                .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
                .enable_mask = 1 << (ebits),\
        },\
        .min_uV = (min) * 1000,\
        .max_uV = (max) * 1000,\
        .step_uV = (step) * 1000,\
-       .activate_bit = (abits),\
 }
 
 #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
@@ -294,13 +264,14 @@ static struct regulator_ops da9052_ldo_ops = {
                .owner = THIS_MODULE,\
                .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
                .vsel_mask = (1 << (sbits)) - 1,\
+               .apply_reg = DA9052_SUPPLY_REG, \
+               .apply_bit = (abits), \
                .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
                .enable_mask = 1 << (ebits),\
        },\
        .min_uV = (min) * 1000,\
        .max_uV = (max) * 1000,\
        .step_uV = (step) * 1000,\
-       .activate_bit = (abits),\
 }
 
 static struct da9052_regulator_info da9052_regulator_info[] = {
@@ -395,9 +366,9 @@ static int da9052_regulator_probe(struct platform_device *pdev)
                config.init_data = pdata->regulators[pdev->id];
        } else {
 #ifdef CONFIG_OF
-               struct device_node *nproot = da9052->dev->of_node;
-               struct device_node *np;
+               struct device_node *nproot, *np;
 
+               nproot = of_node_get(da9052->dev->of_node);
                if (!nproot)
                        return -ENODEV;
 
@@ -414,6 +385,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
                                break;
                        }
                }
+               of_node_put(nproot);
 #endif
        }
 
index 1a05ac6..3022109 100644 (file)
@@ -58,7 +58,6 @@ struct da9055_volt_reg {
        int reg_b;
        int sl_shift;
        int v_mask;
-       int v_shift;
 };
 
 struct da9055_mode_reg {
@@ -388,7 +387,6 @@ static struct regulator_ops da9055_ldo_ops = {
                .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
                .sl_shift = 7,\
                .v_mask = (1 << (vbits)) - 1,\
-               .v_shift = (vbits),\
        },\
 }
 
@@ -417,7 +415,6 @@ static struct regulator_ops da9055_ldo_ops = {
                .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
                .sl_shift = 7,\
                .v_mask = (1 << (vbits)) - 1,\
-               .v_shift = (vbits),\
        },\
        .mode = {\
                .reg = DA9055_REG_BCORE_MODE,\
index bae681c..9d39eb4 100644 (file)
@@ -132,7 +132,7 @@ static struct regulator_ops gpio_regulator_voltage_ops = {
        .list_voltage = gpio_regulator_list_voltage,
 };
 
-struct gpio_regulator_config *
+static struct gpio_regulator_config *
 of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
 {
        struct gpio_regulator_config *config;
@@ -163,10 +163,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
        config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
 
        /* Fetch GPIOs. */
-       for (i = 0; ; i++)
-               if (of_get_named_gpio(np, "gpios", i) < 0)
-                       break;
-       config->nr_gpios = i;
+       config->nr_gpios = of_gpio_count(np);
 
        config->gpios = devm_kzalloc(dev,
                                sizeof(struct gpio) * config->nr_gpios,
index 5f68ff1..9cb2c0f 100644 (file)
@@ -73,8 +73,6 @@ static const unsigned int buck_voltage_map[] = {
 };
 
 #define BUCK_TARGET_VOL_MASK 0x3f
-#define BUCK_TARGET_VOL_MIN_IDX 0x01
-#define BUCK_TARGET_VOL_MAX_IDX 0x19
 
 #define LP3971_BUCK_RAMP_REG(x)        (buck_base_addr[x]+2)
 
@@ -140,7 +138,7 @@ static int lp3971_ldo_disable(struct regulator_dev *dev)
        return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
 }
 
-static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
 {
        struct lp3971 *lp3971 = rdev_get_drvdata(dev);
        int ldo = rdev_get_id(dev) - LP3971_LDO1;
@@ -149,7 +147,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
        reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
        val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
 
-       return dev->desc->volt_table[val];
+       return val;
 }
 
 static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -168,7 +166,7 @@ static struct regulator_ops lp3971_ldo_ops = {
        .is_enabled = lp3971_ldo_is_enabled,
        .enable = lp3971_ldo_enable,
        .disable = lp3971_ldo_disable,
-       .get_voltage = lp3971_ldo_get_voltage,
+       .get_voltage_sel = lp3971_ldo_get_voltage_sel,
        .set_voltage_sel = lp3971_ldo_set_voltage_sel,
 };
 
@@ -201,24 +199,16 @@ static int lp3971_dcdc_disable(struct regulator_dev *dev)
        return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
 }
 
-static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
        struct lp3971 *lp3971 = rdev_get_drvdata(dev);
        int buck = rdev_get_id(dev) - LP3971_DCDC1;
        u16 reg;
-       int val;
 
        reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
        reg &= BUCK_TARGET_VOL_MASK;
 
-       if (reg <= BUCK_TARGET_VOL_MAX_IDX)
-               val = buck_voltage_map[reg];
-       else {
-               val = 0;
-               dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
-       }
-
-       return val;
+       return reg;
 }
 
 static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -249,7 +239,7 @@ static struct regulator_ops lp3971_dcdc_ops = {
        .is_enabled = lp3971_dcdc_is_enabled,
        .enable = lp3971_dcdc_enable,
        .disable = lp3971_dcdc_disable,
-       .get_voltage = lp3971_dcdc_get_voltage,
+       .get_voltage_sel = lp3971_dcdc_get_voltage_sel,
        .set_voltage_sel = lp3971_dcdc_set_voltage_sel,
 };
 
index 69c42c3..0baabcf 100644 (file)
@@ -165,8 +165,6 @@ static const int buck_base_addr[] = {
 #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
 #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
 #define LP3972_BUCK_VOL_MASK 0x1f
-#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
-#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)
 
 static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
        u16 *dest)
@@ -257,7 +255,7 @@ static int lp3972_ldo_disable(struct regulator_dev *dev)
                                mask, 0);
 }
 
-static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
 {
        struct lp3972 *lp3972 = rdev_get_drvdata(dev);
        int ldo = rdev_get_id(dev) - LP3972_LDO1;
@@ -267,7 +265,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
        reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
        val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
 
-       return dev->desc->volt_table[val];
+       return val;
 }
 
 static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -314,7 +312,7 @@ static struct regulator_ops lp3972_ldo_ops = {
        .is_enabled = lp3972_ldo_is_enabled,
        .enable = lp3972_ldo_enable,
        .disable = lp3972_ldo_disable,
-       .get_voltage = lp3972_ldo_get_voltage,
+       .get_voltage_sel = lp3972_ldo_get_voltage_sel,
        .set_voltage_sel = lp3972_ldo_set_voltage_sel,
 };
 
@@ -353,24 +351,16 @@ static int lp3972_dcdc_disable(struct regulator_dev *dev)
        return val;
 }
 
-static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
        struct lp3972 *lp3972 = rdev_get_drvdata(dev);
        int buck = rdev_get_id(dev) - LP3972_DCDC1;
        u16 reg;
-       int val;
 
        reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
        reg &= LP3972_BUCK_VOL_MASK;
-       if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
-               val = dev->desc->volt_table[reg];
-       else {
-               val = 0;
-               dev_warn(&dev->dev, "chip reported incorrect voltage value."
-                                   " reg = %d\n", reg);
-       }
 
-       return val;
+       return reg;
 }
 
 static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -402,7 +392,7 @@ static struct regulator_ops lp3972_dcdc_ops = {
        .is_enabled = lp3972_dcdc_is_enabled,
        .enable = lp3972_dcdc_enable,
        .disable = lp3972_dcdc_disable,
-       .get_voltage = lp3972_dcdc_get_voltage,
+       .get_voltage_sel = lp3972_dcdc_get_voltage_sel,
        .set_voltage_sel = lp3972_dcdc_set_voltage_sel,
 };
 
index 9289ead..8e3c7ae 100644 (file)
@@ -181,20 +181,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
        return regmap_update_bits(lp->regmap, addr, mask, data);
 }
 
-static int _rdev_to_offset(struct regulator_dev *rdev)
-{
-       enum lp872x_regulator_id id = rdev_get_id(rdev);
-
-       switch (id) {
-       case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
-               return id;
-       case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
-               return id - LP8725_ID_BASE;
-       default:
-               return -EINVAL;
-       }
-}
-
 static int lp872x_get_timestep_usec(struct lp872x *lp)
 {
        enum lp872x_id chip = lp->chipid;
@@ -234,28 +220,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
 static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
 {
        struct lp872x *lp = rdev_get_drvdata(rdev);
-       enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+       enum lp872x_regulator_id rid = rdev_get_id(rdev);
        int time_step_us = lp872x_get_timestep_usec(lp);
-       int ret, offset;
+       int ret;
        u8 addr, val;
 
        if (time_step_us < 0)
                return -EINVAL;
 
-       switch (regulator) {
-       case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
-       case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
-               offset = _rdev_to_offset(rdev);
-               if (offset < 0)
-                       return -EINVAL;
-
-               addr = LP872X_LDO1_VOUT + offset;
-               break;
-       case LP8720_ID_BUCK:
-               addr = LP8720_BUCK_VOUT1;
+       switch (rid) {
+       case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+               addr = LP872X_LDO1_VOUT + rid;
                break;
-       case LP8725_ID_BUCK1:
-               addr = LP8725_BUCK1_VOUT1;
+       case LP8725_ID_LDO1 ... LP8725_ID_BUCK1:
+               addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE;
                break;
        case LP8725_ID_BUCK2:
                addr = LP8725_BUCK2_VOUT1;
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
new file mode 100644 (file)
index 0000000..f0f6ea0
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * LP8755 High Performance Power Management Unit : System Interface Driver
+ * (based on rev. 0.26)
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/platform_data/lp8755.h>
+
+#define LP8755_REG_BUCK0       0x00
+#define LP8755_REG_BUCK1       0x03
+#define LP8755_REG_BUCK2       0x04
+#define LP8755_REG_BUCK3       0x01
+#define LP8755_REG_BUCK4       0x05
+#define LP8755_REG_BUCK5       0x02
+#define LP8755_REG_MAX         0xFF
+
+#define LP8755_BUCK_EN_M       BIT(7)
+#define LP8755_BUCK_LINEAR_OUT_MAX     0x76
+#define LP8755_BUCK_VOUT_M     0x7F
+
+struct lp8755_mphase {
+       int nreg;
+       int buck_num[LP8755_BUCK_MAX];
+};
+
+struct lp8755_chip {
+       struct device *dev;
+       struct regmap *regmap;
+       struct lp8755_platform_data *pdata;
+
+       int irq;
+       unsigned int irqmask;
+
+       int mphase;
+       struct regulator_dev *rdev[LP8755_BUCK_MAX];
+};
+
+/**
+ *lp8755_read : read a single register value from lp8755.
+ *@pchip : device to read from
+ *@reg   : register to read from
+ *@val   : pointer to store read value
+ */
+static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg,
+                      unsigned int *val)
+{
+       return regmap_read(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_write : write a single register value to lp8755.
+ *@pchip : device to write to
+ *@reg   : register to write to
+ *@val   : value to be written
+ */
+static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg,
+                       unsigned int val)
+{
+       return regmap_write(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_update_bits : set the values of bit fields in lp8755 register.
+ *@pchip : device to read from
+ *@reg   : register to update
+ *@mask  : bitmask to be changed
+ *@val   : value for bitmask
+ */
+static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg,
+                             unsigned int mask, unsigned int val)
+{
+       return regmap_update_bits(pchip->regmap, reg, mask, val);
+}
+
+static int lp8755_buck_enable_time(struct regulator_dev *rdev)
+{
+       int ret;
+       unsigned int regval;
+       enum lp8755_bucks id = rdev_get_id(rdev);
+       struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+       ret = lp8755_read(pchip, 0x12 + id, &regval);
+       if (ret < 0) {
+               dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+               return ret;
+       }
+       return (regval & 0xff) * 100;
+}
+
+static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       int ret;
+       unsigned int regbval = 0x0;
+       enum lp8755_bucks id = rdev_get_id(rdev);
+       struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               /* forced pwm mode */
+               regbval = (0x01 << id);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               /* enable automatic pwm/pfm mode */
+               ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00);
+               if (ret < 0)
+                       goto err_i2c;
+               break;
+       case REGULATOR_MODE_IDLE:
+               /* enable automatic pwm/pfm/lppfm mode */
+               ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20);
+               if (ret < 0)
+                       goto err_i2c;
+
+               ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01);
+               if (ret < 0)
+                       goto err_i2c;
+               break;
+       default:
+               dev_err(pchip->dev, "Not supported buck mode %s\n", __func__);
+               /* forced pwm mode */
+               regbval = (0x01 << id);
+       }
+
+       ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval);
+       if (ret < 0)
+               goto err_i2c;
+       return ret;
+err_i2c:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return ret;
+}
+
+static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev)
+{
+       int ret;
+       unsigned int regval;
+       enum lp8755_bucks id = rdev_get_id(rdev);
+       struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+       ret = lp8755_read(pchip, 0x06, &regval);
+       if (ret < 0)
+               goto err_i2c;
+
+       /* mode fast means forced pwm mode */
+       if (regval & (0x01 << id))
+               return REGULATOR_MODE_FAST;
+
+       ret = lp8755_read(pchip, 0x08 + id, &regval);
+       if (ret < 0)
+               goto err_i2c;
+
+       /* mode idle means automatic pwm/pfm/lppfm mode */
+       if (regval & 0x20)
+               return REGULATOR_MODE_IDLE;
+
+       /* mode normal means automatic pwm/pfm mode */
+       return REGULATOR_MODE_NORMAL;
+
+err_i2c:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return 0;
+}
+
+static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
+{
+       int ret;
+       unsigned int regval = 0x00;
+       enum lp8755_bucks id = rdev_get_id(rdev);
+       struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+       /* uV/us */
+       switch (ramp) {
+       case 0 ... 230:
+               regval = 0x07;
+               break;
+       case 231 ... 470:
+               regval = 0x06;
+               break;
+       case 471 ... 940:
+               regval = 0x05;
+               break;
+       case 941 ... 1900:
+               regval = 0x04;
+               break;
+       case 1901 ... 3800:
+               regval = 0x03;
+               break;
+       case 3801 ... 7500:
+               regval = 0x02;
+               break;
+       case 7501 ... 15000:
+               regval = 0x01;
+               break;
+       case 15001 ... 30000:
+               regval = 0x00;
+               break;
+       default:
+               dev_err(pchip->dev,
+                       "Not supported ramp value %d %s\n", ramp, __func__);
+               return -EINVAL;
+       }
+
+       ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval);
+       if (ret < 0)
+               goto err_i2c;
+       return ret;
+err_i2c:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return ret;
+}
+
+static struct regulator_ops lp8755_buck_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp8755_buck_enable_time,
+       .set_mode = lp8755_buck_set_mode,
+       .get_mode = lp8755_buck_get_mode,
+       .set_ramp_delay = lp8755_buck_set_ramp,
+};
+
+#define lp8755_rail(_id) "lp8755_buck"#_id
+#define lp8755_buck_init(_id)\
+{\
+       .constraints = {\
+               .name = lp8755_rail(_id),\
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\
+               .min_uV = 500000,\
+               .max_uV = 1675000,\
+       },\
+}
+
+static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = {
+       [LP8755_BUCK0] = lp8755_buck_init(0),
+       [LP8755_BUCK1] = lp8755_buck_init(1),
+       [LP8755_BUCK2] = lp8755_buck_init(2),
+       [LP8755_BUCK3] = lp8755_buck_init(3),
+       [LP8755_BUCK4] = lp8755_buck_init(4),
+       [LP8755_BUCK5] = lp8755_buck_init(5),
+};
+
+static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = {
+       { 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } },
+       { 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3,
+              LP8755_BUCK4, LP8755_BUCK5 } },
+       { 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4,
+              LP8755_BUCK5} },
+       { 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} },
+       { 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} },
+       { 2, { LP8755_BUCK0, LP8755_BUCK5} },
+       { 1, { LP8755_BUCK0} },
+       { 2, { LP8755_BUCK0, LP8755_BUCK3} },
+       { 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} },
+};
+
+static int lp8755_init_data(struct lp8755_chip *pchip)
+{
+       unsigned int regval;
+       int ret, icnt, buck_num;
+       struct lp8755_platform_data *pdata = pchip->pdata;
+
+       /* read back  muti-phase configuration */
+       ret = lp8755_read(pchip, 0x3D, &regval);
+       if (ret < 0)
+               goto out_i2c_error;
+       pchip->mphase = regval & 0x0F;
+
+       /* set default data based on multi-phase config */
+       for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+               buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+               pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num];
+       }
+       return ret;
+
+out_i2c_error:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return ret;
+}
+
+#define lp8755_buck_desc(_id)\
+{\
+       .name = lp8755_rail(_id),\
+       .id   = LP8755_BUCK##_id,\
+       .ops  = &lp8755_buck_ops,\
+       .n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\
+       .uV_step = 10000,\
+       .min_uV = 500000,\
+       .type = REGULATOR_VOLTAGE,\
+       .owner = THIS_MODULE,\
+       .enable_reg = LP8755_REG_BUCK##_id,\
+       .enable_mask = LP8755_BUCK_EN_M,\
+       .vsel_reg = LP8755_REG_BUCK##_id,\
+       .vsel_mask = LP8755_BUCK_VOUT_M,\
+}
+
+static struct regulator_desc lp8755_regulators[] = {
+       lp8755_buck_desc(0),
+       lp8755_buck_desc(1),
+       lp8755_buck_desc(2),
+       lp8755_buck_desc(3),
+       lp8755_buck_desc(4),
+       lp8755_buck_desc(5),
+};
+
+static int lp8755_regulator_init(struct lp8755_chip *pchip)
+{
+       int ret, icnt, buck_num;
+       struct lp8755_platform_data *pdata = pchip->pdata;
+       struct regulator_config rconfig = { };
+
+       rconfig.regmap = pchip->regmap;
+       rconfig.dev = pchip->dev;
+       rconfig.driver_data = pchip;
+
+       for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+               buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+               rconfig.init_data = pdata->buck_data[buck_num];
+               rconfig.of_node = pchip->dev->of_node;
+               pchip->rdev[buck_num] =
+                   regulator_register(&lp8755_regulators[buck_num], &rconfig);
+               if (IS_ERR(pchip->rdev[buck_num])) {
+                       ret = PTR_ERR(pchip->rdev[buck_num]);
+                       pchip->rdev[buck_num] = NULL;
+                       dev_err(pchip->dev, "regulator init failed: buck %d\n",
+                               buck_num);
+                       goto err_buck;
+               }
+       }
+
+       return 0;
+
+err_buck:
+       for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+               regulator_unregister(pchip->rdev[icnt]);
+       return ret;
+}
+
+static irqreturn_t lp8755_irq_handler(int irq, void *data)
+{
+       int ret, icnt;
+       unsigned int flag0, flag1;
+       struct lp8755_chip *pchip = data;
+
+       /* read flag0 register */
+       ret = lp8755_read(pchip, 0x0D, &flag0);
+       if (ret < 0)
+               goto err_i2c;
+       /* clear flag register to pull up int. pin */
+       ret = lp8755_write(pchip, 0x0D, 0x00);
+       if (ret < 0)
+               goto err_i2c;
+
+       /* sent power fault detection event to specific regulator */
+       for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+               if ((flag0 & (0x4 << icnt))
+                   && (pchip->irqmask & (0x04 << icnt))
+                   && (pchip->rdev[icnt] != NULL))
+                       regulator_notifier_call_chain(pchip->rdev[icnt],
+                                                     LP8755_EVENT_PWR_FAULT,
+                                                     NULL);
+
+       /* read flag1 register */
+       ret = lp8755_read(pchip, 0x0E, &flag1);
+       if (ret < 0)
+               goto err_i2c;
+       /* clear flag register to pull up int. pin */
+       ret = lp8755_write(pchip, 0x0E, 0x00);
+       if (ret < 0)
+               goto err_i2c;
+
+       /* send OCP event to all regualtor devices */
+       if ((flag1 & 0x01) && (pchip->irqmask & 0x01))
+               for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+                       if (pchip->rdev[icnt] != NULL)
+                               regulator_notifier_call_chain(pchip->rdev[icnt],
+                                                             LP8755_EVENT_OCP,
+                                                             NULL);
+
+       /* send OVP event to all regualtor devices */
+       if ((flag1 & 0x02) && (pchip->irqmask & 0x02))
+               for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+                       if (pchip->rdev[icnt] != NULL)
+                               regulator_notifier_call_chain(pchip->rdev[icnt],
+                                                             LP8755_EVENT_OVP,
+                                                             NULL);
+       return IRQ_HANDLED;
+
+err_i2c:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return IRQ_NONE;
+}
+
+static int lp8755_int_config(struct lp8755_chip *pchip)
+{
+       int ret;
+       unsigned int regval;
+
+       if (pchip->irq == 0) {
+               dev_warn(pchip->dev, "not use interrupt : %s\n", __func__);
+               return 0;
+       }
+
+       ret = lp8755_read(pchip, 0x0F, &regval);
+       if (ret < 0)
+               goto err_i2c;
+       pchip->irqmask = regval;
+       ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  "lp8755-irq", pchip);
+       if (ret)
+               return ret;
+
+       return ret;
+
+err_i2c:
+       dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+       return ret;
+}
+
+static const struct regmap_config lp8755_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = LP8755_REG_MAX,
+};
+
+static int lp8755_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int ret, icnt;
+       struct lp8755_chip *pchip;
+       struct lp8755_platform_data *pdata = client->dev.platform_data;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "i2c functionality check fail.\n");
+               return -EOPNOTSUPP;
+       }
+
+       pchip = devm_kzalloc(&client->dev,
+                            sizeof(struct lp8755_chip), GFP_KERNEL);
+       if (!pchip)
+               return -ENOMEM;
+
+       pchip->dev = &client->dev;
+       pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap);
+       if (IS_ERR(pchip->regmap)) {
+               ret = PTR_ERR(pchip->regmap);
+               dev_err(&client->dev, "fail to allocate regmap %d\n", ret);
+               return ret;
+       }
+       i2c_set_clientdata(client, pchip);
+
+       if (pdata != NULL) {
+               pchip->pdata = pdata;
+               pchip->mphase = pdata->mphase;
+       } else {
+               pchip->pdata = devm_kzalloc(pchip->dev,
+                                           sizeof(struct lp8755_platform_data),
+                                           GFP_KERNEL);
+               if (!pchip->pdata)
+                       return -ENOMEM;
+               ret = lp8755_init_data(pchip);
+               if (ret < 0) {
+                       dev_err(&client->dev, "fail to initialize chip\n");
+                       return ret;
+               }
+       }
+
+       ret = lp8755_regulator_init(pchip);
+       if (ret < 0) {
+               dev_err(&client->dev, "fail to initialize regulators\n");
+               goto err_regulator;
+       }
+
+       pchip->irq = client->irq;
+       ret = lp8755_int_config(pchip);
+       if (ret < 0) {
+               dev_err(&client->dev, "fail to irq config\n");
+               goto err_irq;
+       }
+
+       return ret;
+
+err_irq:
+       for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+               regulator_unregister(pchip->rdev[icnt]);
+
+err_regulator:
+       /* output disable */
+       for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+               lp8755_write(pchip, icnt, 0x00);
+
+       return ret;
+}
+
+static int lp8755_remove(struct i2c_client *client)
+{
+       int icnt;
+       struct lp8755_chip *pchip = i2c_get_clientdata(client);
+
+       for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+               regulator_unregister(pchip->rdev[icnt]);
+
+       for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+               lp8755_write(pchip, icnt, 0x00);
+
+       if (pchip->irq != 0)
+               free_irq(pchip->irq, pchip);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp8755_id[] = {
+       {LP8755_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp8755_id);
+
+static struct i2c_driver lp8755_i2c_driver = {
+       .driver = {
+                  .name = LP8755_NAME,
+                  },
+       .probe = lp8755_probe,
+       .remove = lp8755_remove,
+       .id_table = lp8755_id,
+};
+
+static int __init lp8755_init(void)
+{
+       return i2c_add_driver(&lp8755_i2c_driver);
+}
+
+subsys_initcall(lp8755_init);
+
+static void __exit lp8755_exit(void)
+{
+       i2c_del_driver(&lp8755_i2c_driver);
+}
+
+module_exit(lp8755_exit);
+
+MODULE_DESCRIPTION("Texas Instruments lp8755 driver");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL v2");
index aef3f2b..97891a7 100644 (file)
@@ -103,16 +103,6 @@ static const int lp8788_buck_vtbl[] = {
        1950000, 2000000,
 };
 
-static const u8 buck1_vout_addr[] = {
-       LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
-       LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
-};
-
-static const u8 buck2_vout_addr[] = {
-       LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
-       LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
-};
-
 static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
 {
        struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
@@ -235,7 +225,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
                        idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
                }
-               addr = buck1_vout_addr[idx];
+               addr = LP8788_BUCK1_VOUT0 + idx;
                break;
        case BUCK2:
                if (mode == EXTPIN) {
@@ -258,7 +248,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
                        idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
                }
-               addr = buck2_vout_addr[idx];
+               addr = LP8788_BUCK2_VOUT0 + idx;
                break;
        default:
                goto err;
@@ -429,7 +419,8 @@ static struct regulator_desc lp8788_buck_desc[] = {
        },
 };
 
-static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
+static int lp8788_dvs_gpio_request(struct platform_device *pdev,
+                               struct lp8788_buck *buck,
                                enum lp8788_buck_id id)
 {
        struct lp8788_platform_data *pdata = buck->lp->pdata;
@@ -440,7 +431,7 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
        switch (id) {
        case BUCK1:
                gpio = pdata->buck1_dvs->gpio;
-               ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW,
+               ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
                                            b1_name);
                if (ret)
                        return ret;
@@ -448,9 +439,9 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
                buck->dvs = pdata->buck1_dvs;
                break;
        case BUCK2:
-               for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
+               for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) {
                        gpio = pdata->buck2_dvs->gpio[i];
-                       ret = devm_gpio_request_one(buck->lp->dev, gpio,
+                       ret = devm_gpio_request_one(&pdev->dev, gpio,
                                                    DVS_LOW, b2_name[i]);
                        if (ret)
                                return ret;
@@ -464,7 +455,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
        return 0;
 }
 
-static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+static int lp8788_init_dvs(struct platform_device *pdev,
+                       struct lp8788_buck *buck, enum lp8788_buck_id id)
 {
        struct lp8788_platform_data *pdata = buck->lp->pdata;
        u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
@@ -472,7 +464,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
        u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 
        /* no dvs for buck3, 4 */
-       if (id == BUCK3 || id == BUCK4)
+       if (id > BUCK2)
                return 0;
 
        /* no dvs platform data, then dvs will be selected by I2C registers */
@@ -483,7 +475,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
                (id == BUCK2 && !pdata->buck2_dvs))
                goto set_default_dvs_mode;
 
-       if (lp8788_dvs_gpio_request(buck, id))
+       if (lp8788_dvs_gpio_request(pdev, buck, id))
                goto set_default_dvs_mode;
 
        return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
@@ -503,17 +495,20 @@ static int lp8788_buck_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
        int ret;
 
-       buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
+       if (id >= LP8788_NUM_BUCKS)
+               return -EINVAL;
+
+       buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
        if (!buck)
                return -ENOMEM;
 
        buck->lp = lp;
 
-       ret = lp8788_init_dvs(buck, id);
+       ret = lp8788_init_dvs(pdev, buck, id);
        if (ret)
                return ret;
 
-       cfg.dev = lp->dev;
+       cfg.dev = pdev->dev.parent;
        cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
        cfg.driver_data = buck;
        cfg.regmap = lp->regmap;
@@ -521,7 +516,7 @@ static int lp8788_buck_probe(struct platform_device *pdev)
        rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
        if (IS_ERR(rdev)) {
                ret = PTR_ERR(rdev);
-               dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
+               dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
                                id + 1, ret);
                return ret;
        }
index 3792741..cd5a14a 100644 (file)
 #define ENABLE                         GPIOF_OUT_INIT_HIGH
 #define DISABLE                                GPIOF_OUT_INIT_LOW
 
-enum lp8788_enable_mode {
-       REGISTER,
-       EXTPIN,
-};
-
 enum lp8788_ldo_id {
        DLDO1,
        DLDO2,
@@ -189,114 +184,38 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
        ALDO10,
 };
 
-/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
-   : can be enabled either by external pin or by i2c register */
-static enum lp8788_enable_mode
-lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
-{
-       int ret;
-       u8 val, mask;
-
-       ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
-       if (ret)
-               return ret;
-
-       switch (id) {
-       case DLDO7:
-               mask =  LP8788_EN_SEL_DLDO7_M;
-               break;
-       case DLDO9:
-       case DLDO11:
-               mask =  LP8788_EN_SEL_DLDO911_M;
-               break;
-       case ALDO1:
-               mask =  LP8788_EN_SEL_ALDO1_M;
-               break;
-       case ALDO2 ... ALDO4:
-               mask =  LP8788_EN_SEL_ALDO234_M;
-               break;
-       case ALDO5:
-               mask =  LP8788_EN_SEL_ALDO5_M;
-               break;
-       case ALDO7:
-               mask =  LP8788_EN_SEL_ALDO7_M;
-               break;
-       default:
-               return REGISTER;
-       }
-
-       return val & mask ? EXTPIN : REGISTER;
-}
-
-static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
-{
-       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
-       if (!pin)
-               return -EINVAL;
-
-       if (gpio_is_valid(pin->gpio))
-               gpio_set_value(pin->gpio, pinstate);
-
-       return 0;
-}
-
-static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
-{
-       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
-       if (!pin)
-               return -EINVAL;
-
-       return gpio_get_value(pin->gpio) ? 1 : 0;
-}
-
 static int lp8788_ldo_enable(struct regulator_dev *rdev)
 {
        struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-       enum lp8788_ldo_id id = rdev_get_id(rdev);
-       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-       switch (mode) {
-       case EXTPIN:
-               return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
-       case REGISTER:
+       if (ldo->en_pin) {
+               gpio_set_value(ldo->en_pin->gpio, ENABLE);
+               return 0;
+       } else {
                return regulator_enable_regmap(rdev);
-       default:
-               return -EINVAL;
        }
 }
 
 static int lp8788_ldo_disable(struct regulator_dev *rdev)
 {
        struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-       enum lp8788_ldo_id id = rdev_get_id(rdev);
-       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-       switch (mode) {
-       case EXTPIN:
-               return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
-       case REGISTER:
+       if (ldo->en_pin) {
+               gpio_set_value(ldo->en_pin->gpio, DISABLE);
+               return 0;
+       } else {
                return regulator_disable_regmap(rdev);
-       default:
-               return -EINVAL;
        }
 }
 
 static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
 {
        struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-       enum lp8788_ldo_id id = rdev_get_id(rdev);
-       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-       switch (mode) {
-       case EXTPIN:
-               return lp8788_ldo_is_enabled_by_extern_pin(ldo);
-       case REGISTER:
+       if (ldo->en_pin)
+               return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
+       else
                return regulator_is_enabled_regmap(rdev);
-       default:
-               return -EINVAL;
-       }
 }
 
 static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
@@ -616,10 +535,11 @@ static struct regulator_desc lp8788_aldo_desc[] = {
        },
 };
 
-static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
+static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
+                               struct lp8788_ldo *ldo,
                                enum lp8788_ext_ldo_en_id id)
 {
-       struct device *dev = ldo->lp->dev;
+       struct device *dev = &pdev->dev;
        struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
        int ret, gpio, pinstate;
        char *name[] = {
@@ -647,7 +567,8 @@ static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
        return ret;
 }
 
-static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
+static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
+                                       struct lp8788_ldo *ldo,
                                        enum lp8788_ldo_id id)
 {
        int ret;
@@ -693,9 +614,11 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
 
        ldo->en_pin = pdata->ldo_pin[enable_id];
 
-       ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
-       if (ret)
+       ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
+       if (ret) {
+               ldo->en_pin = NULL;
                goto set_default_ldo_enable_mode;
+       }
 
        return ret;
 
@@ -712,16 +635,16 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
        int ret;
 
-       ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+       ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
        if (!ldo)
                return -ENOMEM;
 
        ldo->lp = lp;
-       ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
+       ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]);
        if (ret)
                return ret;
 
-       cfg.dev = lp->dev;
+       cfg.dev = pdev->dev.parent;
        cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
        cfg.driver_data = ldo;
        cfg.regmap = lp->regmap;
@@ -729,7 +652,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
        rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
        if (IS_ERR(rdev)) {
                ret = PTR_ERR(rdev);
-               dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
+               dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n",
                                id + 1, ret);
                return ret;
        }
@@ -768,16 +691,16 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
        int ret;
 
-       ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+       ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
        if (!ldo)
                return -ENOMEM;
 
        ldo->lp = lp;
-       ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
+       ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]);
        if (ret)
                return ret;
 
-       cfg.dev = lp->dev;
+       cfg.dev = pdev->dev.parent;
        cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
        cfg.driver_data = ldo;
        cfg.regmap = lp->regmap;
@@ -785,7 +708,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
        rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
        if (IS_ERR(rdev)) {
                ret = PTR_ERR(rdev);
-               dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
+               dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n",
                                id + 1, ret);
                return ret;
        }
index cca18a3..e4586ee 100644 (file)
@@ -75,13 +75,14 @@ static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev)
 {
        unsigned int val;
        struct max77686_data *max77686 = rdev_get_drvdata(rdev);
+        int id = rdev_get_id(rdev);
 
-       if (rdev->desc->id == MAX77686_BUCK1)
+       if (id == MAX77686_BUCK1)
                val = 0x1;
        else
                val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
 
-       max77686->opmode[rdev->desc->id] = val;
+       max77686->opmode[id] = val;
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask,
                                  val);
@@ -93,9 +94,10 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
 {
        struct max77686_data *max77686 = rdev_get_drvdata(rdev);
        unsigned int val;
+        int id = rdev_get_id(rdev);
 
        /* BUCK[5-9] doesn't support this feature */
-       if (rdev->desc->id >= MAX77686_BUCK5)
+       if (id >= MAX77686_BUCK5)
                return 0;
 
        switch (mode) {
@@ -111,7 +113,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       max77686->opmode[rdev->desc->id] = val;
+       max77686->opmode[id] = val;
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask,
                                  val);
@@ -140,7 +142,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       max77686->opmode[rdev->desc->id] = val;
+       max77686->opmode[rdev_get_id(rdev)] = val;
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask,
                                  val);
@@ -152,7 +154,7 @@ static int max77686_enable(struct regulator_dev *rdev)
 
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask,
-                                 max77686->opmode[rdev->desc->id]);
+                                 max77686->opmode[rdev_get_id(rdev)]);
 }
 
 static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
index d40cf7f..4568c15 100644 (file)
@@ -224,11 +224,11 @@ static struct of_regulator_match max8907_matches[] = {
 
 static int max8907_regulator_parse_dt(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.parent->of_node;
-       struct device_node *regulators;
+       struct device_node *np, *regulators;
        int ret;
 
-       if (!pdev->dev.parent->of_node)
+       np = of_node_get(pdev->dev.parent->of_node);
+       if (!np)
                return 0;
 
        regulators = of_find_node_by_name(np, "regulators");
@@ -239,6 +239,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
 
        ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
                                 ARRAY_SIZE(max8907_matches));
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
                        ret);
index 446a854..0d5f64a 100644 (file)
@@ -252,7 +252,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
 {
        struct device_node *nproot, *np;
        int rcount;
-       nproot = pdev->dev.parent->of_node;
+       nproot = of_node_get(pdev->dev.parent->of_node);
        if (!nproot)
                return -ENODEV;
        np = of_find_node_by_name(nproot, "regulators");
@@ -263,6 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
 
        rcount = of_regulator_match(&pdev->dev, np,
                                &max8925_regulator_matches[ridx], 1);
+       of_node_put(np);
        if (rcount < 0)
                return -ENODEV;
        config->init_data =     max8925_regulator_matches[ridx].init_data;
index 836908c..0ac7a87 100644 (file)
@@ -54,6 +54,13 @@ struct max8997_data {
        u8 saved_states[MAX8997_REG_MAX];
 };
 
+static const unsigned int safeoutvolt[] = {
+       4850000,
+       4900000,
+       4950000,
+       3300000,
+};
+
 static inline void max8997_set_gpio(struct max8997_data *max8997)
 {
        int set3 = (max8997->buck125_gpioindex) & 0x1;
@@ -130,29 +137,6 @@ static const struct voltage_map_desc *reg_voltage_map[] = {
        [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
 };
 
-static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
-               unsigned int selector)
-{
-       int rid = rdev_get_id(rdev);
-
-       if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
-               switch (selector) {
-               case 0:
-                       return 4850000;
-               case 1:
-                       return 4900000;
-               case 2:
-                       return 4950000;
-               case 3:
-                       return 3300000;
-               default:
-                       return -EINVAL;
-               }
-       }
-
-       return -EINVAL;
-}
-
 static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
                unsigned int selector)
 {
@@ -522,7 +506,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
        return ret;
 }
 
-static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
+static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev,
                                                unsigned int old_selector,
                                                unsigned int new_selector)
 {
@@ -720,49 +704,23 @@ out:
        return 0;
 }
 
-static const int safeoutvolt[] = {
-       3300000,
-       4850000,
-       4900000,
-       4950000,
-};
-
 /* For SAFEOUT1 and SAFEOUT2 */
-static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
-               int min_uV, int max_uV, unsigned *selector)
+static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev,
+                                          unsigned selector)
 {
        struct max8997_data *max8997 = rdev_get_drvdata(rdev);
        struct i2c_client *i2c = max8997->iodev->i2c;
        int rid = rdev_get_id(rdev);
        int reg, shift = 0, mask, ret;
-       int i = 0;
-       u8 val;
 
        if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
                return -EINVAL;
 
-       for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
-               if (min_uV <= safeoutvolt[i] &&
-                               max_uV >= safeoutvolt[i])
-                       break;
-       }
-
-       if (i >= ARRAY_SIZE(safeoutvolt))
-               return -EINVAL;
-
-       if (i == 0)
-               val = 0x3;
-       else
-               val = i - 1;
-
        ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
        if (ret)
                return ret;
 
-       ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
-       *selector = val;
-
-       return ret;
+       return max8997_update_reg(i2c, reg, selector << shift, mask << shift);
 }
 
 static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
@@ -799,7 +757,6 @@ static struct regulator_ops max8997_ldo_ops = {
        .disable                = max8997_reg_disable,
        .get_voltage_sel        = max8997_get_voltage_sel,
        .set_voltage            = max8997_set_voltage_ldobuck,
-       .set_voltage_time_sel   = max8997_set_voltage_ldobuck_time_sel,
        .set_suspend_disable    = max8997_reg_disable_suspend,
 };
 
@@ -810,7 +767,7 @@ static struct regulator_ops max8997_buck_ops = {
        .disable                = max8997_reg_disable,
        .get_voltage_sel        = max8997_get_voltage_sel,
        .set_voltage            = max8997_set_voltage_buck,
-       .set_voltage_time_sel   = max8997_set_voltage_ldobuck_time_sel,
+       .set_voltage_time_sel   = max8997_set_voltage_buck_time_sel,
        .set_suspend_disable    = max8997_reg_disable_suspend,
 };
 
@@ -823,12 +780,12 @@ static struct regulator_ops max8997_fixedvolt_ops = {
 };
 
 static struct regulator_ops max8997_safeout_ops = {
-       .list_voltage           = max8997_list_voltage_safeout,
+       .list_voltage           = regulator_list_voltage_table,
        .is_enabled             = max8997_reg_is_enabled,
        .enable                 = max8997_reg_enable,
        .disable                = max8997_reg_disable,
        .get_voltage_sel        = max8997_get_voltage_sel,
-       .set_voltage            = max8997_set_voltage_safeout,
+       .set_voltage_sel        = max8997_set_voltage_safeout_sel,
        .set_suspend_disable    = max8997_reg_disable_suspend,
 };
 
@@ -960,7 +917,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
        struct max8997_regulator_data *rdata;
        unsigned int i, dvs_voltage_nr = 1, ret;
 
-       pmic_np = iodev->dev->of_node;
+       pmic_np = of_node_get(iodev->dev->of_node);
        if (!pmic_np) {
                dev_err(&pdev->dev, "could not find pmic sub-node\n");
                return -ENODEV;
@@ -973,13 +930,12 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
        }
 
        /* count the number of regulators to be supported in pmic */
-       pdata->num_regulators = 0;
-       for_each_child_of_node(regulators_np, reg_np)
-               pdata->num_regulators++;
+       pdata->num_regulators = of_get_child_count(regulators_np);
 
        rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
                                pdata->num_regulators, GFP_KERNEL);
        if (!rdata) {
+               of_node_put(regulators_np);
                dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
                return -ENOMEM;
        }
@@ -1002,6 +958,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                rdata->reg_node = reg_np;
                rdata++;
        }
+       of_node_put(regulators_np);
 
        if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
                pdata->buck1_gpiodvs = true;
@@ -1233,13 +1190,15 @@ static int max8997_pmic_probe(struct platform_device *pdev)
                int id = pdata->regulators[i].id;
 
                desc = reg_voltage_map[id];
-               if (desc)
+               if (desc) {
                        regulators[id].n_voltages =
                                (desc->max - desc->min) / desc->step + 1;
-               else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
-                       regulators[id].n_voltages = 4;
-               else if (id == MAX8997_CHARGER_CV)
+               } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) {
+                       regulators[id].volt_table = safeoutvolt;
+                       regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt);
+               } else if (id == MAX8997_CHARGER_CV) {
                        regulators[id].n_voltages = 16;
+               }
 
                config.dev = max8997->dev;
                config.init_data = pdata->regulators[i].initdata;
index 0a8dd1c..b588f07 100644 (file)
@@ -311,25 +311,13 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
                dev_get_platdata(max8998->iodev->dev);
        struct i2c_client *i2c = max8998->iodev->i2c;
        int buck = rdev_get_id(rdev);
-       int reg, shift = 0, mask, ret;
-       int j, previous_sel;
+       int reg, shift = 0, mask, ret, j;
        static u8 buck1_last_val;
 
        ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
        if (ret)
                return ret;
 
-       previous_sel = max8998_get_voltage_sel(rdev);
-
-       /* Check if voltage needs to be changed */
-       /* if previous_voltage equal new voltage, return */
-       if (previous_sel == selector) {
-               dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
-                       regulator_list_voltage_linear(rdev, previous_sel),
-                       regulator_list_voltage_linear(rdev, selector));
-               return ret;
-       }
-
        switch (buck) {
        case MAX8998_BUCK1:
                dev_dbg(max8998->dev,
index 0d84b1f..9891aec 100644 (file)
@@ -164,6 +164,14 @@ static const unsigned int mc13892_sw1[] = {
        1350000, 1375000
 };
 
+/*
+ * Note: this table is used to derive SWxVSEL by index into
+ * the array. Offset the values by the index of 1100000uV
+ * to get the actual register value for that voltage selector
+ * if the HI bit is to be set as well.
+ */
+#define MC13892_SWxHI_SEL_OFFSET               20
+
 static const unsigned int mc13892_sw[] = {
        600000,   625000,  650000,  675000,  700000,  725000,
        750000,   775000,  800000,  825000,  850000,  875000,
@@ -239,7 +247,6 @@ static const unsigned int mc13892_pwgtdrv[] = {
 };
 
 static struct regulator_ops mc13892_gpo_regulator_ops;
-/* sw regulators need special care due to the "hi bit" */
 static struct regulator_ops mc13892_sw_regulator_ops;
 
 
@@ -396,7 +403,7 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        int ret, id = rdev_get_id(rdev);
-       unsigned int val;
+       unsigned int val, selector;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
@@ -407,12 +414,28 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
        if (ret)
                return ret;
 
-       val = (val & mc13892_regulators[id].vsel_mask)
-               >> mc13892_regulators[id].vsel_shift;
+       /*
+        * Figure out if the HI bit is set inside the switcher mode register
+        * since this means the selector value we return is at a different
+        * offset into the selector table.
+        *
+        * According to the MC13892 documentation note 59 (Table 47) the SW1
+        * buck switcher does not support output range programming therefore
+        * the HI bit must always remain 0. So do not do anything strange if
+        * our register is MC13892_SWITCHERS0.
+        */
+
+       selector = val & mc13892_regulators[id].vsel_mask;
+
+       if ((mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) &&
+           (val & MC13892_SWITCHERS0_SWxHI)) {
+               selector += MC13892_SWxHI_SEL_OFFSET;
+       }
 
-       dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+       dev_dbg(rdev_get_dev(rdev), "%s id: %d val: 0x%08x selector: %d\n",
+                       __func__, id, val, selector);
 
-       return val;
+       return selector;
 }
 
 static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
@@ -425,18 +448,35 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
 
        volt = rdev->desc->volt_table[selector];
        mask = mc13892_regulators[id].vsel_mask;
-       reg_value = selector << mc13892_regulators[id].vsel_shift;
-
-       if (volt > 1375000) {
-               mask |= MC13892_SWITCHERS0_SWxHI;
-               reg_value |= MC13892_SWITCHERS0_SWxHI;
-       } else if (volt < 1100000) {
-               mask |= MC13892_SWITCHERS0_SWxHI;
-               reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+       reg_value = selector;
+
+       /*
+        * Don't mess with the HI bit or support HI voltage offsets for SW1.
+        *
+        * Since the get_voltage_sel callback has given a fudged value for
+        * the selector offset, we need to back out that offset if HI is
+        * to be set so we write the correct value to the register.
+        *
+        * The HI bit addition and selector offset handling COULD be more
+        * complicated by shifting and masking off the voltage selector part
+        * of the register then logical OR it back in, but since the selector
+        * is at bits 4:0 there is very little point. This makes the whole
+        * thing more readable and we do far less work.
+        */
+
+       if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) {
+               if (volt > 1375000) {
+                       reg_value -= MC13892_SWxHI_SEL_OFFSET;
+                       reg_value |= MC13892_SWITCHERS0_SWxHI;
+                       mask |= MC13892_SWITCHERS0_SWxHI;
+               } else if (volt < 1100000) {
+                       reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+                       mask |= MC13892_SWITCHERS0_SWxHI;
+               }
        }
 
        mc13xxx_lock(priv->mc13xxx);
-       ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
+       ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask,
                              reg_value);
        mc13xxx_unlock(priv->mc13xxx);
 
@@ -495,15 +535,18 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
        struct mc13xxx_regulator_init_data *mc13xxx_data;
        struct regulator_config config = { };
        int i, ret;
-       int num_regulators = 0;
+       int num_regulators = 0, num_parsed;
        u32 val;
 
        num_regulators = mc13xxx_get_num_regulators_dt(pdev);
+
        if (num_regulators <= 0 && pdata)
                num_regulators = pdata->num_regulators;
        if (num_regulators <= 0)
                return -EINVAL;
 
+       num_parsed = num_regulators;
+
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
                num_regulators * sizeof(priv->regulators[0]),
                GFP_KERNEL);
@@ -520,7 +563,7 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
        if (ret)
                goto err_unlock;
 
-       /* enable switch auto mode */
+       /* enable switch auto mode (on 2.0A silicon only) */
        if ((val & 0x0000FFFF) == 0x45d0) {
                ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
                        MC13892_SWITCHERS4_SW1MODE_M |
@@ -546,7 +589,39 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
                = mc13892_vcam_get_mode;
 
        mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
-                                       ARRAY_SIZE(mc13892_regulators));
+                                       ARRAY_SIZE(mc13892_regulators),
+                                       &num_parsed);
+
+       /*
+        * Perform a little sanity check on the regulator tree - if we found
+        * a number of regulators from mc13xxx_get_num_regulators_dt and
+        * then parsed a smaller number in mc13xxx_parse_regulators_dt then
+        * there is a regulator defined in the regulators node which has
+        * not matched any usable regulator in the driver. In this case,
+        * there is one missing and what will happen is the first regulator
+        * will get registered again.
+        *
+        * Fix this by basically making our number of registerable regulators
+        * equal to the number of regulators we parsed. We are allocating
+        * too much memory for priv, but this is unavoidable at this point.
+        *
+        * As an example of how this can happen, try making a typo in your
+        * regulators node (vviohi {} instead of viohi {}) so that the name
+        * does not match..
+        *
+        * The check will basically pass for platform data (non-DT) because
+        * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
+        *
+        */
+       if (num_parsed != num_regulators) {
+               dev_warn(&pdev->dev,
+               "parsed %d != regulators %d - check your device tree!\n",
+                       num_parsed, num_regulators);
+
+               num_regulators = num_parsed;
+               priv->num_regulators = num_regulators;
+       }
+
        for (i = 0; i < num_regulators; i++) {
                struct regulator_init_data *init_data;
                struct regulator_desc *desc;
index 4ed89c6..23cf9f9 100644 (file)
@@ -164,29 +164,30 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
 #ifdef CONFIG_OF
 int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
-       struct device_node *parent, *child;
-       int num = 0;
+       struct device_node *parent;
+       int num;
 
        of_node_get(pdev->dev.parent->of_node);
        parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
        if (!parent)
                return -ENODEV;
 
-       for_each_child_of_node(parent, child)
-               num++;
-
+       num = of_get_child_count(parent);
+       of_node_put(parent);
        return num;
 }
 EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
 
 struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
        struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-       int num_regulators)
+       int num_regulators, int *num_parsed)
 {
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
        struct mc13xxx_regulator_init_data *data, *p;
        struct device_node *parent, *child;
-       int i;
+       int i, parsed = 0;
+
+       *num_parsed = 0;
 
        of_node_get(pdev->dev.parent->of_node);
        parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
@@ -195,24 +196,32 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators,
                            GFP_KERNEL);
-       if (!data)
+       if (!data) {
+               of_node_put(parent);
                return NULL;
+       }
+
        p = data;
 
        for_each_child_of_node(parent, child) {
                for (i = 0; i < num_regulators; i++) {
                        if (!of_node_cmp(child->name,
                                         regulators[i].desc.name)) {
+
                                p->id = i;
                                p->init_data = of_get_regulator_init_data(
                                                        &pdev->dev, child);
                                p->node = child;
                                p++;
+
+                               parsed++;
                                break;
                        }
                }
        }
+       of_node_put(parent);
 
+       *num_parsed = parsed;
        return data;
 }
 EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
index 06c8903..007f833 100644 (file)
@@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
 extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
 extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
        struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-       int num_regulators);
+       int num_regulators, int *num_parsed);
 #else
 static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
@@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 
 static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
        struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-       int num_regulators)
+       int num_regulators, int *num_parsed)
 {
        return NULL;
 }
index c9e912f..cde13bb 100644 (file)
@@ -527,6 +527,7 @@ static void palmas_dt_to_pdata(struct device *dev,
        u32 prop;
        int idx, ret;
 
+       node = of_node_get(node);
        regulators = of_find_node_by_name(node, "regulators");
        if (!regulators) {
                dev_info(dev, "regulator node not found\n");
@@ -535,6 +536,7 @@ static void palmas_dt_to_pdata(struct device *dev,
 
        ret = of_regulator_match(dev, regulators, palmas_matches,
                        PALMAS_NUM_REGS);
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(dev, "Error parsing regulator init data: %d\n", ret);
                return;
@@ -565,11 +567,6 @@ static void palmas_dt_to_pdata(struct device *dev,
                if (!ret)
                        pdata->reg_init[idx]->mode_sleep = prop;
 
-               ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,warm_reset", &prop);
-               if (!ret)
-                       pdata->reg_init[idx]->warm_reset = prop;
-
                ret = of_property_read_u32(palmas_matches[idx].of_node,
                                "ti,tstep", &prop);
                if (!ret)
index 33b65c9..8a83194 100644 (file)
@@ -14,6 +14,7 @@
 #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>
@@ -21,6 +22,9 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s5m8767.h>
+#include <linux/regulator/of_regulator.h>
+
+#define S5M8767_OPMODE_NORMAL_MODE 0x1
 
 struct s5m8767_info {
        struct device *dev;
@@ -255,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev)
        return sec_reg_update(s5m8767->iodev, reg, ~mask, mask);
 }
 
-static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
 {
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int reg_id = rdev_get_id(rdev);
        int reg;
 
        switch (reg_id) {
@@ -296,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
                return -EINVAL;
        }
 
-       *_reg = reg;
-
-       return 0;
-}
-
-static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int reg, mask, ret;
-       int reg_id = rdev_get_id(rdev);
-       unsigned int val;
-
-       ret = s5m8767_get_voltage_register(rdev, &reg);
-       if (ret)
-               return ret;
-
-       mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
-
-       ret = sec_reg_read(s5m8767->iodev, reg, &val);
-       if (ret)
-               return ret;
-
-       val &= mask;
-
-       return val;
+       return reg;
 }
 
-static int s5m8767_convert_voltage_to_sel(
-               const struct sec_voltage_desc *desc,
-               int min_vol, int max_vol)
+static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc,
+                                         int min_vol)
 {
        int selector = 0;
 
        if (desc == NULL)
                return -EINVAL;
 
-       if (max_vol < desc->min || min_vol > desc->max)
+       if (min_vol > desc->max)
                return -EINVAL;
 
        if (min_vol < desc->min)
@@ -340,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel(
 
        selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
 
-       if (desc->min + desc->step * selector > max_vol)
+       if (desc->min + desc->step * selector > desc->max)
                return -EINVAL;
 
        return selector;
@@ -373,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int reg_id = rdev_get_id(rdev);
-       int reg, mask, ret = 0, old_index, index = 0;
+       int old_index, index = 0;
        u8 *buck234_vol = NULL;
 
        switch (reg_id) {
        case S5M8767_LDO1 ... S5M8767_LDO28:
-               mask = 0x3f;
                break;
        case S5M8767_BUCK1 ... S5M8767_BUCK6:
-               mask = 0xff;
                if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
                        buck234_vol = &s5m8767->buck2_vol[0];
                else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
@@ -392,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
        case S5M8767_BUCK7 ... S5M8767_BUCK8:
                return -EINVAL;
        case S5M8767_BUCK9:
-               mask = 0xff;
                break;
        default:
                return -EINVAL;
@@ -412,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
                else
                        return s5m8767_set_low(s5m8767);
        } else {
-               ret = s5m8767_get_voltage_register(rdev, &reg);
-               if (ret)
-                       return ret;
-
-               return sec_reg_update(s5m8767->iodev, reg, selector, mask);
+               return regulator_set_voltage_sel_regmap(rdev, selector);
        }
 }
 
@@ -441,7 +411,7 @@ static struct regulator_ops s5m8767_ops = {
        .is_enabled             = s5m8767_reg_is_enabled,
        .enable                 = s5m8767_reg_enable,
        .disable                = s5m8767_reg_disable,
-       .get_voltage_sel        = s5m8767_get_voltage_sel,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = s5m8767_set_voltage_sel,
        .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
 };
@@ -508,10 +478,182 @@ 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)
+{
+       int i, gpio;
+
+       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;
+               }
+               pdata->buck_gpios[i] = gpio;
+       }
+       return 0;
+}
+
+static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
+                       struct sec_platform_data *pdata,
+                       struct device_node *pmic_np)
+{
+       int i, gpio;
+
+       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;
+}
+
+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 sec_regulator_data *rdata;
+       struct sec_opmode_data *rmode;
+       unsigned int i, dvs_voltage_nr = 1, ret;
+
+       pmic_np = iodev->dev->of_node;
+       if (!pmic_np) {
+               dev_err(iodev->dev, "could not find pmic sub-node\n");
+               return -ENODEV;
+       }
+
+       regulators_np = of_find_node_by_name(pmic_np, "regulators");
+       if (!regulators_np) {
+               dev_err(iodev->dev, "could not find regulators sub-node\n");
+               return -EINVAL;
+       }
+
+       /* 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");
+               return -ENOMEM;
+       }
+
+       rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
+                               pdata->num_regulators, GFP_KERNEL);
+       if (!rdata) {
+               dev_err(iodev->dev,
+                       "could not allocate memory for regulator mode\n");
+               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))
+                               break;
+
+               if (i == ARRAY_SIZE(regulators)) {
+                       dev_warn(iodev->dev,
+                       "don't know how to configure regulator %s\n",
+                       reg_np->name);
+                       continue;
+               }
+
+               rdata->id = i;
+               rdata->initdata = of_get_regulator_init_data(
+                                               &pdev->dev, reg_np);
+               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);
+
+                       rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
+               }
+               rmode++;
+       }
+
+       if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL))
+               pdata->buck2_gpiodvs = true;
+
+       if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL))
+               pdata->buck3_gpiodvs = true;
+
+       if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL))
+               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)
+                       return -EINVAL;
+
+               if (of_property_read_u32(pmic_np,
+                               "s5m8767,pmic-buck-default-dvs-idx",
+                               &pdata->buck_default_idx)) {
+                       pdata->buck_default_idx = 0;
+               } else {
+                       if (pdata->buck_default_idx >= 8) {
+                               pdata->buck_default_idx = 0;
+                               dev_info(iodev->dev,
+                               "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;
+       }
+
+       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;
+       }
+
+       return 0;
+}
+#else
+static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
+                                       struct sec_platform_data *pdata)
+{
+       return 0;
+}
+#endif /* CONFIG_OF */
+
 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 = dev_get_platdata(iodev->dev);
+       struct sec_platform_data *pdata = iodev->pdata;
        struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
@@ -522,6 +664,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       if (iodev->dev->of_node) {
+               ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata);
+               if (ret)
+                       return ret;
+       }
+
        if (pdata->buck2_gpiodvs) {
                if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
                        dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
@@ -577,23 +725,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
        s5m8767->opmode = pdata->opmode;
 
        buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-                                               pdata->buck2_init,
-                                               pdata->buck2_init +
-                                               buck_voltage_val2.step);
+                                                  pdata->buck2_init);
 
        sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
 
        buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-                                               pdata->buck3_init,
-                                               pdata->buck3_init +
-                                               buck_voltage_val2.step);
+                                                  pdata->buck3_init);
 
        sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
 
        buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-                                               pdata->buck4_init,
-                                               pdata->buck4_init +
-                                               buck_voltage_val2.step);
+                                                  pdata->buck4_init);
 
        sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
 
@@ -602,27 +744,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                        s5m8767->buck2_vol[i] =
                                s5m8767_convert_voltage_to_sel(
                                                &buck_voltage_val2,
-                                               pdata->buck2_voltage[i],
-                                               pdata->buck2_voltage[i] +
-                                               buck_voltage_val2.step);
+                                               pdata->buck2_voltage[i]);
                }
 
                if (s5m8767->buck3_gpiodvs) {
                        s5m8767->buck3_vol[i] =
                                s5m8767_convert_voltage_to_sel(
                                                &buck_voltage_val2,
-                                               pdata->buck3_voltage[i],
-                                               pdata->buck3_voltage[i] +
-                                               buck_voltage_val2.step);
+                                               pdata->buck3_voltage[i]);
                }
 
                if (s5m8767->buck4_gpiodvs) {
                        s5m8767->buck4_vol[i] =
                                s5m8767_convert_voltage_to_sel(
                                                &buck_voltage_val2,
-                                               pdata->buck4_voltage[i],
-                                               pdata->buck4_voltage[i] +
-                                               buck_voltage_val2.step);
+                                               pdata->buck4_voltage[i]);
                }
        }
 
@@ -760,11 +896,19 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                                (desc->max - desc->min) / desc->step + 1;
                        regulators[id].min_uV = desc->min;
                        regulators[id].uV_step = desc->step;
+                       regulators[id].vsel_reg =
+                               s5m8767_get_vsel_reg(id, s5m8767);
+                       if (id < S5M8767_BUCK1)
+                               regulators[id].vsel_mask = 0x3f;
+                       else
+                               regulators[id].vsel_mask = 0xff;
                }
 
                config.dev = s5m8767->dev;
                config.init_data = pdata->regulators[i].initdata;
                config.driver_data = s5m8767;
+               config.regmap = iodev->regmap;
+               config.of_node = pdata->regulators[i].reg_node;
 
                rdev[i] = regulator_register(&regulators[id], &config);
                if (IS_ERR(rdev[i])) {
index ab21133..6e67be7 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/regulator/tps51632-regulator.h>
 #include <linux/slab.h>
 
@@ -85,49 +88,8 @@ struct tps51632_chip {
        struct regulator_desc desc;
        struct regulator_dev *rdev;
        struct regmap *regmap;
-       bool enable_pwm_dvfs;
 };
 
-static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct tps51632_chip *tps = rdev_get_drvdata(rdev);
-       unsigned int data;
-       int ret;
-       unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
-       int vsel;
-
-       if (tps->enable_pwm_dvfs)
-               reg = TPS51632_VOLTAGE_BASE_REG;
-
-       ret = regmap_read(tps->regmap, reg, &data);
-       if (ret < 0) {
-               dev_err(tps->dev, "reg read failed, err %d\n", ret);
-               return ret;
-       }
-
-       vsel = data & TPS51632_VOUT_MASK;
-       return vsel;
-}
-
-static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev,
-               unsigned selector)
-{
-       struct tps51632_chip *tps = rdev_get_drvdata(rdev);
-       int ret;
-       unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
-
-       if (tps->enable_pwm_dvfs)
-               reg = TPS51632_VOLTAGE_BASE_REG;
-
-       if (selector > TPS51632_MAX_VSEL)
-               return -EINVAL;
-
-       ret = regmap_write(tps->regmap, reg, selector);
-       if (ret < 0)
-               dev_err(tps->dev, "reg write failed, err %d\n", ret);
-       return ret;
-}
-
 static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
                int ramp_delay)
 {
@@ -144,8 +106,8 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops tps51632_dcdc_ops = {
-       .get_voltage_sel        = tps51632_dcdc_get_voltage_sel,
-       .set_voltage_sel        = tps51632_dcdc_set_voltage_sel,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
        .set_ramp_delay         = tps51632_dcdc_set_ramp_delay,
@@ -162,7 +124,6 @@ static int tps51632_init_dcdc(struct tps51632_chip *tps,
                goto skip_pwm_config;
 
        control |= TPS51632_DVFS_PWMEN;
-       tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs;
        vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV);
        ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel);
        if (ret < 0) {
@@ -205,22 +166,96 @@ skip_pwm_config:
        return ret;
 }
 
-static bool rd_wr_reg(struct device *dev, unsigned int reg)
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TPS51632_OFFSET_REG:
+       case TPS51632_FAULT_REG:
+       case TPS51632_IMON_REG:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool is_read_reg(struct device *dev, unsigned int reg)
 {
-       if ((reg >= 0x8) && (reg <= 0x10))
+       switch (reg) {
+       case 0x08 ... 0x0F:
                return false;
-       return true;
+       default:
+               return true;
+       }
+}
+
+static bool is_write_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TPS51632_VOLTAGE_SELECT_REG:
+       case TPS51632_VOLTAGE_BASE_REG:
+       case TPS51632_VMAX_REG:
+       case TPS51632_DVFS_CONTROL_REG:
+       case TPS51632_POWER_STATE_REG:
+       case TPS51632_SLEW_REGS:
+               return true;
+       default:
+               return false;
+       }
 }
 
 static const struct regmap_config tps51632_regmap_config = {
        .reg_bits               = 8,
        .val_bits               = 8,
-       .writeable_reg          = rd_wr_reg,
-       .readable_reg           = rd_wr_reg,
+       .writeable_reg          = is_write_reg,
+       .readable_reg           = is_read_reg,
+       .volatile_reg           = is_volatile_reg,
        .max_register           = TPS51632_MAX_REG - 1,
        .cache_type             = REGCACHE_RBTREE,
 };
 
+#if defined(CONFIG_OF)
+static const struct of_device_id tps51632_of_match[] = {
+       { .compatible = "ti,tps51632",},
+       {},
+};
+MODULE_DEVICE_TABLE(of, tps51632_of_match);
+
+static struct tps51632_regulator_platform_data *
+       of_get_tps51632_platform_data(struct device *dev)
+{
+       struct tps51632_regulator_platform_data *pdata;
+       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");
+               return NULL;
+       }
+
+       pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+       if (!pdata->reg_init_data) {
+               dev_err(dev, "Not able to get OF regulator init data\n");
+               return NULL;
+       }
+
+       pdata->enable_pwm_dvfs =
+                       of_property_read_bool(np, "ti,enable-pwm-dvfs");
+       pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV");
+
+       pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? :
+                                       TPS51632_MIN_VOLATGE;
+       pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? :
+                                       TPS51632_MAX_VOLATGE;
+       return pdata;
+}
+#else
+static struct tps51632_regulator_platform_data *
+       of_get_tps51632_platform_data(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int tps51632_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
@@ -230,7 +265,19 @@ static int tps51632_probe(struct i2c_client *client,
        int ret;
        struct regulator_config config = { };
 
+       if (client->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_device(of_match_ptr(tps51632_of_match),
+                               &client->dev);
+               if (!match) {
+                       dev_err(&client->dev, "Error: No device match found\n");
+                       return -ENODEV;
+               }
+       }
+
        pdata = client->dev.platform_data;
+       if (!pdata && client->dev.of_node)
+               pdata = of_get_tps51632_platform_data(&client->dev);
        if (!pdata) {
                dev_err(&client->dev, "No Platform data\n");
                return -EINVAL;
@@ -269,6 +316,12 @@ static int tps51632_probe(struct i2c_client *client,
        tps->desc.type = REGULATOR_VOLTAGE;
        tps->desc.owner = THIS_MODULE;
 
+       if (pdata->enable_pwm_dvfs)
+               tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG;
+       else
+               tps->desc.vsel_reg = TPS51632_VOLTAGE_SELECT_REG;
+       tps->desc.vsel_mask = TPS51632_VOUT_MASK;
+
        tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config);
        if (IS_ERR(tps->regmap)) {
                ret = PTR_ERR(tps->regmap);
@@ -319,6 +372,7 @@ static struct i2c_driver tps51632_i2c_driver = {
        .driver = {
                .name = "tps51632",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(tps51632_of_match),
        },
        .probe = tps51632_probe,
        .remove = tps51632_remove,
index 0233cfb..54aa2da 100644 (file)
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6507x.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/mfd/tps6507x.h>
+#include <linux/regulator/of_regulator.h>
 
 /* DCDC's */
 #define TPS6507X_DCDC_1                                0
@@ -356,6 +358,80 @@ static struct regulator_ops tps6507x_pmic_ops = {
        .list_voltage = regulator_list_voltage_table,
 };
 
+#ifdef CONFIG_OF
+static struct of_regulator_match tps6507x_matches[] = {
+       { .name = "VDCDC1"},
+       { .name = "VDCDC2"},
+       { .name = "VDCDC3"},
+       { .name = "LDO1"},
+       { .name = "LDO2"},
+};
+
+static struct tps6507x_board *tps6507x_parse_dt_reg_data(
+               struct platform_device *pdev,
+               struct of_regulator_match **tps6507x_reg_matches)
+{
+       struct tps6507x_board *tps_board;
+       struct device_node *np = pdev->dev.parent->of_node;
+       struct device_node *regulators;
+       struct of_regulator_match *matches;
+       static struct regulator_init_data *reg_data;
+       int idx = 0, count, ret;
+
+       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");
+               return NULL;
+       }
+
+       regulators = of_find_node_by_name(np, "regulators");
+       if (!regulators) {
+               dev_err(&pdev->dev, "regulator node not found\n");
+               return NULL;
+       }
+
+       count = ARRAY_SIZE(tps6507x_matches);
+       matches = tps6507x_matches;
+
+       ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+                       ret);
+               return NULL;
+       }
+
+       *tps6507x_reg_matches = matches;
+
+       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");
+               return NULL;
+       }
+
+       tps_board->tps6507x_pmic_init_data = reg_data;
+
+       for (idx = 0; idx < count; idx++) {
+               if (!matches[idx].init_data || !matches[idx].of_node)
+                       continue;
+
+               memcpy(&reg_data[idx], matches[idx].init_data,
+                               sizeof(struct regulator_init_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);
@@ -365,8 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
        struct tps6507x_pmic *tps;
        struct tps6507x_board *tps_board;
+       struct of_regulator_match *tps6507x_reg_matches = NULL;
        int i;
        int error;
+       unsigned int prop;
 
        /**
         * tps_board points to pmic related constants
@@ -374,6 +452,9 @@ 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)
+               tps_board = tps6507x_parse_dt_reg_data(pdev,
+                                               &tps6507x_reg_matches);
        if (!tps_board)
                return -EINVAL;
 
@@ -415,6 +496,17 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
                config.init_data = init_data;
                config.driver_data = tps;
 
+               if (tps6507x_reg_matches) {
+                       error = of_property_read_u32(
+                               tps6507x_reg_matches[i].of_node,
+                                       "ti,defdcdc_default", &prop);
+
+                       if (!error)
+                               tps->info[i]->defdcdc_default = prop;
+
+                       config.of_node = tps6507x_reg_matches[i].of_node;
+               }
+
                rdev = regulator_register(&tps->desc[i], &config);
                if (IS_ERR(rdev)) {
                        dev_err(tps6507x_dev->dev,
index 41c3917..c8e7045 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/tps65090.h>
 
 struct tps65090_regulator {
@@ -67,8 +69,8 @@ static struct regulator_desc tps65090_regulator_desc[] = {
        tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
        tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
        tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
-       tps65090_REG_DESC(LDO1,  "vsys_l1", 0,    tps65090_ldo_ops),
-       tps65090_REG_DESC(LDO2,  "vsys_l2", 0,    tps65090_ldo_ops),
+       tps65090_REG_DESC(LDO1,  "vsys-l1", 0,    tps65090_ldo_ops),
+       tps65090_REG_DESC(LDO2,  "vsys-l2", 0,    tps65090_ldo_ops),
 };
 
 static inline bool is_dcdc(int id)
@@ -138,6 +140,92 @@ static void tps65090_configure_regulator_config(
        }
 }
 
+#ifdef CONFIG_OF
+static struct of_regulator_match tps65090_matches[] = {
+       { .name = "dcdc1", },
+       { .name = "dcdc2", },
+       { .name = "dcdc3", },
+       { .name = "fet1",  },
+       { .name = "fet2",  },
+       { .name = "fet3",  },
+       { .name = "fet4",  },
+       { .name = "fet5",  },
+       { .name = "fet6",  },
+       { .name = "fet7",  },
+       { .name = "ldo1",  },
+       { .name = "ldo2",  },
+};
+
+static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+               struct platform_device *pdev,
+               struct of_regulator_match **tps65090_reg_matches)
+{
+       struct tps65090_platform_data *tps65090_pdata;
+       struct device_node *np = pdev->dev.parent->of_node;
+       struct device_node *regulators;
+       int idx = 0, ret;
+       struct tps65090_regulator_plat_data *reg_pdata;
+
+       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");
+               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");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       regulators = of_find_node_by_name(np, "regulators");
+       if (!regulators) {
+               dev_err(&pdev->dev, "regulator node not found\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
+                       ARRAY_SIZE(tps65090_matches));
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Error parsing regulator init data: %d\n", ret);
+               return ERR_PTR(ret);
+       }
+
+       *tps65090_reg_matches = tps65090_matches;
+       for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) {
+               struct regulator_init_data *ri_data;
+               struct tps65090_regulator_plat_data *rpdata;
+
+               rpdata = &reg_pdata[idx];
+               ri_data = tps65090_matches[idx].init_data;
+               if (!ri_data || !tps65090_matches[idx].of_node)
+                       continue;
+
+               rpdata->reg_init_data = ri_data;
+               rpdata->enable_ext_control = of_property_read_bool(
+                                       tps65090_matches[idx].of_node,
+                                       "ti,enable-ext-control");
+               if (rpdata->enable_ext_control)
+                       rpdata->gpio = of_get_named_gpio(np,
+                                       "dcdc-ext-control-gpios", 0);
+
+               tps65090_pdata->reg_pdata[idx] = rpdata;
+       }
+       return tps65090_pdata;
+}
+#else
+static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+                       struct platform_device *pdev,
+                       struct of_regulator_match **tps65090_reg_matches)
+{
+       *tps65090_reg_matches = NULL;
+       return NULL;
+}
+#endif
+
 static int tps65090_regulator_probe(struct platform_device *pdev)
 {
        struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
@@ -147,15 +235,19 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
        struct tps65090_regulator_plat_data *tps_pdata;
        struct tps65090_regulator *pmic;
        struct tps65090_platform_data *tps65090_pdata;
+       struct of_regulator_match *tps65090_reg_matches = NULL;
        int num;
        int ret;
 
        dev_dbg(&pdev->dev, "Probing regulator\n");
 
        tps65090_pdata = dev_get_platdata(pdev->dev.parent);
-       if (!tps65090_pdata) {
+       if (!tps65090_pdata && tps65090_mfd->dev->of_node)
+               tps65090_pdata = tps65090_parse_dt_reg_data(pdev,
+                                       &tps65090_reg_matches);
+       if (IS_ERR_OR_NULL(tps65090_pdata)) {
                dev_err(&pdev->dev, "Platform data missing\n");
-               return -EINVAL;
+               return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL;
        }
 
        pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
@@ -192,13 +284,17 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
                        }
                }
 
-               config.dev = &pdev->dev;
+               config.dev = pdev->dev.parent;
                config.driver_data = ri;
                config.regmap = tps65090_mfd->rmap;
                if (tps_pdata)
                        config.init_data = tps_pdata->reg_init_data;
                else
                        config.init_data = NULL;
+               if (tps65090_reg_matches)
+                       config.of_node = tps65090_reg_matches[num].of_node;
+               else
+                       config.of_node = NULL;
 
                rdev = regulator_register(ri->desc, &config);
                if (IS_ERR(rdev)) {
index f86da67..e68382d 100644 (file)
@@ -61,10 +61,6 @@ struct tps6586x_regulator {
 
        int enable_bit[2];
        int enable_reg[2];
-
-       /* for DVM regulators */
-       int go_reg;
-       int go_bit;
 };
 
 static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
@@ -72,37 +68,10 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
        return rdev_get_dev(rdev)->parent;
 }
 
-static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
-                                   unsigned selector)
-{
-       struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6586x_dev(rdev);
-       int ret, val, rid = rdev_get_id(rdev);
-       uint8_t mask;
-
-       val = selector << (ffs(rdev->desc->vsel_mask) - 1);
-       mask = rdev->desc->vsel_mask;
-
-       ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
-       if (ret)
-               return ret;
-
-       /* Update go bit for DVM regulators */
-       switch (rid) {
-       case TPS6586X_ID_LDO_2:
-       case TPS6586X_ID_LDO_4:
-       case TPS6586X_ID_SM_0:
-       case TPS6586X_ID_SM_1:
-               ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
-               break;
-       }
-       return ret;
-}
-
 static struct regulator_ops tps6586x_regulator_ops = {
        .list_voltage = regulator_list_voltage_table,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage_sel = tps6586x_set_voltage_sel,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
 
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
@@ -142,7 +111,7 @@ static const unsigned int tps6586x_dvm_voltages[] = {
 };
 
 #define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits,  \
-                          ereg0, ebit0, ereg1, ebit1)                  \
+                          ereg0, ebit0, ereg1, ebit1, goreg, gobit)    \
        .desc   = {                                                     \
                .supply_name = _pin_name,                               \
                .name   = "REG-" #_id,                                  \
@@ -156,29 +125,26 @@ static const unsigned int tps6586x_dvm_voltages[] = {
                .enable_mask = 1 << (ebit0),                            \
                .vsel_reg = TPS6586X_##vreg,                            \
                .vsel_mask = ((1 << (nbits)) - 1) << (shift),           \
+               .apply_reg = (goreg),                           \
+               .apply_bit = (gobit),                           \
        },                                                              \
        .enable_reg[0]  = TPS6586X_SUPPLY##ereg0,                       \
        .enable_bit[0]  = (ebit0),                                      \
        .enable_reg[1]  = TPS6586X_SUPPLY##ereg1,                       \
        .enable_bit[1]  = (ebit1),
 
-#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)                     \
-       .go_reg = TPS6586X_##goreg,                                     \
-       .go_bit = (gobit),
-
 #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits,           \
                     ereg0, ebit0, ereg1, ebit1)                        \
 {                                                                      \
        TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,      \
-                          ereg0, ebit0, ereg1, ebit1)                  \
+                          ereg0, ebit0, ereg1, ebit1, 0, 0)            \
 }
 
 #define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits,           \
                     ereg0, ebit0, ereg1, ebit1, goreg, gobit)          \
 {                                                                      \
        TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,      \
-                          ereg0, ebit0, ereg1, ebit1)                  \
-       TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)                      \
+                          ereg0, ebit0, ereg1, ebit1, goreg, gobit)    \
 }
 
 #define TPS6586X_SYS_REGULATOR()                                       \
@@ -207,13 +173,13 @@ static struct tps6586x_regulator tps6586x_regulator[] = {
        TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
 
        TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
-                                       ENB, 3, VCC2, 6),
+                                       ENB, 3, TPS6586X_VCC2, BIT(6)),
        TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
-                                       END, 3, VCC1, 6),
+                                       END, 3, TPS6586X_VCC1, BIT(6)),
        TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
-                                       ENB, 1, VCC1, 2),
+                                       ENB, 1, TPS6586X_VCC1, BIT(2)),
        TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
-                                       ENB, 0, VCC1, 0),
+                                       ENB, 0, TPS6586X_VCC1, BIT(0)),
 };
 
 /*
index b0e4c0b..6ba6931 100644 (file)
@@ -964,8 +964,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
 {
        struct tps65910_board *pmic_plat_data;
        struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
-       struct device_node *np = pdev->dev.parent->of_node;
-       struct device_node *regulators;
+       struct device_node *np, *regulators;
        struct of_regulator_match *matches;
        unsigned int prop;
        int idx = 0, ret, count;
@@ -978,6 +977,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
                return NULL;
        }
 
+       np = of_node_get(pdev->dev.parent->of_node);
        regulators = of_find_node_by_name(np, "regulators");
        if (!regulators) {
                dev_err(&pdev->dev, "regulator node not found\n");
@@ -994,11 +994,13 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
                matches = tps65911_matches;
                break;
        default:
+               of_node_put(regulators);
                dev_err(&pdev->dev, "Invalid tps chip version\n");
                return NULL;
        }
 
        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);
index b50c38f..f0f4de3 100644 (file)
@@ -26,6 +26,7 @@ enum sec_device_type {
 /**
  * struct sec_pmic_dev - s5m87xx master device for sub-drivers
  * @dev: master device of the chip (can be used to access platform data)
+ * @pdata: pointer to private data used to pass platform data to child
  * @i2c: i2c client private data for regulator
  * @rtc: i2c client private data for rtc
  * @iolock: mutex for serializing io access
@@ -39,6 +40,7 @@ enum sec_device_type {
  */
 struct sec_pmic_dev {
        struct device *dev;
+       struct sec_platform_data *pdata;
        struct regmap *regmap;
        struct i2c_client *i2c;
        struct i2c_client *rtc;
@@ -82,11 +84,11 @@ struct sec_platform_data {
 
        int                             buck_gpios[3];
        int                             buck_ds[3];
-       int                             buck2_voltage[8];
+       unsigned int                    buck2_voltage[8];
        bool                            buck2_gpiodvs;
-       int                             buck3_voltage[8];
+       unsigned int                    buck3_voltage[8];
        bool                            buck3_gpiodvs;
-       int                             buck4_voltage[8];
+       unsigned int                    buck4_voltage[8];
        bool                            buck4_gpiodvs;
 
        int                             buck_set1;
@@ -127,6 +129,7 @@ struct sec_platform_data {
 struct sec_regulator_data {
        int                             id;
        struct regulator_init_data      *initdata;
+       struct device_node *reg_node;
 };
 
 /*
@@ -136,7 +139,7 @@ struct sec_regulator_data {
  */
 struct sec_opmode_data {
        int id;
-       int mode;
+       unsigned int mode;
 };
 
 /*
diff --git a/include/linux/platform_data/lp8755.h b/include/linux/platform_data/lp8755.h
new file mode 100644 (file)
index 0000000..a7fd077
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * LP8755 High Performance Power Management Unit Driver:System Interface Driver
+ *
+ *                     Copyright (C) 2012 Texas Instruments
+ *
+ * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
+ *             G.Shark Jeong <gshark.jeong@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LP8755_H
+#define _LP8755_H
+
+#include <linux/regulator/consumer.h>
+
+#define LP8755_NAME "lp8755-regulator"
+/*
+ *PWR FAULT : power fault detected
+ *OCP : over current protect activated
+ *OVP : over voltage protect activated
+ *TEMP_WARN : thermal warning
+ *TEMP_SHDN : thermal shutdonw detected
+ *I_LOAD : current measured
+ */
+#define LP8755_EVENT_PWR_FAULT REGULATOR_EVENT_FAIL
+#define LP8755_EVENT_OCP REGULATOR_EVENT_OVER_CURRENT
+#define LP8755_EVENT_OVP 0x10000
+#define LP8755_EVENT_TEMP_WARN 0x2000
+#define LP8755_EVENT_TEMP_SHDN REGULATOR_EVENT_OVER_TEMP
+#define LP8755_EVENT_I_LOAD    0x40000
+
+enum lp8755_bucks {
+       LP8755_BUCK0 = 0,
+       LP8755_BUCK1,
+       LP8755_BUCK2,
+       LP8755_BUCK3,
+       LP8755_BUCK4,
+       LP8755_BUCK5,
+       LP8755_BUCK_MAX,
+};
+
+/**
+ * multiphase configuration options
+ */
+enum lp8755_mphase_config {
+       MPHASE_CONF0,
+       MPHASE_CONF1,
+       MPHASE_CONF2,
+       MPHASE_CONF3,
+       MPHASE_CONF4,
+       MPHASE_CONF5,
+       MPHASE_CONF6,
+       MPHASE_CONF7,
+       MPHASE_CONF8,
+       MPHASE_CONF_MAX
+};
+
+/**
+ * struct lp8755_platform_data
+ * @mphase_type : Multiphase Switcher Configurations.
+ * @buck_data   : buck0~6 init voltage in uV
+ */
+struct lp8755_platform_data {
+       int mphase;
+       struct regulator_init_data *buck_data[LP8755_BUCK_MAX];
+};
+#endif
index d10bb0f..23070fd 100644 (file)
@@ -193,6 +193,10 @@ enum regulator_type {
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
  * @vsel_mask: Mask for register bitfield used for selector
+ * @apply_reg: Register for initiate voltage change on the output when
+ *                using regulator_set_voltage_sel_regmap
+ * @apply_bit: Register bitfield used for initiate voltage change on the
+ *                output when using regulator_set_voltage_sel_regmap
  * @enable_reg: Register for control when using regmap enable/disable ops
  * @enable_mask: Mask for control when using regmap enable/disable ops
  *
@@ -218,6 +222,8 @@ struct regulator_desc {
 
        unsigned int vsel_reg;
        unsigned int vsel_mask;
+       unsigned int apply_reg;
+       unsigned int apply_bit;
        unsigned int enable_reg;
        unsigned int enable_mask;
        unsigned int bypass_reg;
index 1440b3f..988e817 100644 (file)
@@ -1152,6 +1152,8 @@ SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
 SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
 SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
 SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
 };
 
 #define ARIZONA_MIXER_INPUT_ROUTES(name)       \
@@ -1364,6 +1366,8 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "AEC Loopback", "SPKDAT1R", "OUT5R" },
        { "SPKDAT1L", NULL, "OUT5L" },
        { "SPKDAT1R", NULL, "OUT5R" },
+
+       { "MICSUPP", NULL, "SYSCLK" },
 };
 
 static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
index 7a09096..0320a32 100644 (file)
@@ -624,6 +624,8 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
 SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
 SND_SOC_DAPM_OUTPUT("SPKDAT2L"),
 SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
 };
 
 #define ARIZONA_MIXER_INPUT_ROUTES(name)       \
@@ -832,6 +834,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 
        { "SPKDAT2L", NULL, "OUT6L" },
        { "SPKDAT2R", NULL, "OUT6R" },
+
+       { "MICSUPP", NULL, "SYSCLK" },
 };
 
 static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,