Merge remote-tracking branches 'regulator/topic/pv88090', 'regulator/topic/qcom-smd...
authorMark Brown <broonie@kernel.org>
Tue, 12 Jan 2016 18:26:10 +0000 (18:26 +0000)
committerMark Brown <broonie@kernel.org>
Tue, 12 Jan 2016 18:26:10 +0000 (18:26 +0000)
14 files changed:
Documentation/devicetree/bindings/regulator/pv88090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt [deleted file]
Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/pv88090-regulator.c [new file with mode: 0644]
drivers/regulator/pv88090-regulator.h [new file with mode: 0644]
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/tps6105x-regulator.c
drivers/regulator/tps65086-regulator.c [new file with mode: 0644]
drivers/regulator/tps65218-regulator.c
include/linux/mfd/tps65218.h
include/linux/regulator/driver.h

diff --git a/Documentation/devicetree/bindings/regulator/pv88090.txt b/Documentation/devicetree/bindings/regulator/pv88090.txt
new file mode 100644 (file)
index 0000000..e52b2a9
--- /dev/null
@@ -0,0 +1,65 @@
+* Powerventure Semiconductor PV88090 Voltage Regulator
+
+Required properties:
+- compatible: "pvs,pv88090".
+- reg: I2C slave address, usually 0x48.
+- interrupts: the interrupt outputs of the controller
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name, with valid
+  values listed below. The content of each sub-node is defined by the
+  standard binding for regulators; see regulator.txt.
+  BUCK1, BUCK2, BUCK3, LDO1, and LDO2.
+
+Optional properties:
+- Any optional property defined in regulator.txt
+
+Example
+
+       pmic: pv88090@48 {
+               compatible = "pvs,pv88090";
+               reg = <0x48>;
+               interrupt-parent = <&gpio>;
+               interrupts = <24 24>;
+
+               regulators {
+                       BUCK1 {
+                               regulator-name = "buck1";
+                               regulator-min-microvolt = < 600000>;
+                               regulator-max-microvolt = <1393750>;
+                               regulator-min-microamp  = < 220000>;
+                               regulator-max-microamp  = <7040000>;
+                               regulator-boot-on;
+                       };
+
+                       BUCK2 {
+                               regulator-name = "buck2";
+                               regulator-min-microvolt = < 600000>;
+                               regulator-max-microvolt = <1393750>;
+                               regulator-min-microamp  = <1496000>;
+                               regulator-max-microamp  = <4189000>;
+                       };
+
+                       BUCK3 {
+                               regulator-name = "buck3";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1393750>;
+                               regulator-min-microamp  = <1496000>;
+                               regulator-max-microamp  = <4189000>;
+                               regulator-boot-on;
+                       };
+
+                       LDO1 {
+                               regulator-name = "ldo1";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <4350000>;
+                               regulator-boot-on;
+                       };
+
+                       LDO2 {
+                               regulator-name = "ldo2";
+                               regulator-min-microvolt = < 650000>;
+                               regulator-max-microvolt = <2225000>;
+                               regulator-boot-on;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
new file mode 100644 (file)
index 0000000..1f8d6f8
--- /dev/null
@@ -0,0 +1,159 @@
+QCOM SMD RPM REGULATOR
+
+The Qualcomm RPM over SMD regulator is modelled as a subdevice of the RPM.
+Because SMD is used as the communication transport mechanism, the RPM resides as
+a subnode of the SMD.  As such, the SMD-RPM regulator requires that the SMD and
+RPM nodes be present.
+
+Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt for
+information pertaining to the SMD node.
+
+Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt for
+information regarding the RPM node.
+
+== Regulator
+
+Regulator nodes are identified by their compatible:
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,rpm-pm8841-regulators"
+                   "qcom,rpm-pm8916-regulators"
+                   "qcom,rpm-pm8941-regulators"
+                   "qcom,rpm-pma8084-regulators"
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_s6-supply:
+- vdd_s7-supply:
+- vdd_s8-supply:
+       Usage: optional (pm8841 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_l1_l2_l3-supply:
+- vdd_l4_l5_l6-supply:
+- vdd_l7-supply:
+- vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18-supply:
+       Usage: optional (pm8916 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_l1_l3-supply:
+- vdd_l2_lvs1_2_3-supply:
+- vdd_l4_l11-supply:
+- vdd_l5_l7-supply:
+- vdd_l6_l12_l14_l15-supply:
+- vdd_l8_l16_l18_l19-supply:
+- vdd_l9_l10_l17_l22-supply:
+- vdd_l13_l20_l23_l24-supply:
+- vdd_l21-supply:
+- vin_5vs-supply:
+       Usage: optional (pm8941 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_s6-supply:
+- vdd_s7-supply:
+- vdd_s8-supply:
+- vdd_s9-supply:
+- vdd_s10-supply:
+- vdd_s11-supply:
+- vdd_s12-supply:
+- vdd_l1_l11-supply:
+- vdd_l2_l3_l4_l27-supply:
+- vdd_l5_l7-supply:
+- vdd_l6_l12_l14_l15_l26-supply:
+- vdd_l8-supply:
+- vdd_l9_l10_l13_l20_l23_l24-supply:
+- vdd_l16_l25-supply:
+- vdd_l17-supply:
+- vdd_l18-supply:
+- vdd_l19-supply:
+- vdd_l21-supply:
+- vdd_l22-supply:
+       Usage: optional (pma8084 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
+The regulator node houses sub-nodes for each regulator within the device. Each
+sub-node is identified using the node's name, with valid values listed for each
+of the pmics below.
+
+pm8841:
+       s1, s2, s3, s4, s5, s6, s7, s8
+
+pm8916:
+       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+       l14, l15, l16, l17, l18
+
+pm8941:
+       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+       l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
+       lvs3, 5vs1, 5vs2
+
+pma8084:
+       s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
+       l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
+       l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
+
+The content of each sub-node is defined by the standard binding for regulators -
+see regulator.txt.
+
+= EXAMPLE
+
+       smd {
+               compatible = "qcom,smd";
+
+               rpm {
+                       interrupts = <0 168 1>;
+                       qcom,ipc = <&apcs 8 0>;
+                       qcom,smd-edge = <15>;
+
+                       rpm_requests {
+                               compatible = "qcom,rpm-msm8974";
+                               qcom,smd-channels = "rpm_requests";
+
+                               pm8941-regulators {
+                                       compatible = "qcom,rpm-pm8941-regulators";
+                                       vdd_l13_l20_l23_l24-supply = <&pm8941_boost>;
+
+                                       pm8941_s3: s3 {
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                       };
+
+                                       pm8941_boost: s4 {
+                                               regulator-min-microvolt = <5000000>;
+                                               regulator-max-microvolt = <5000000>;
+                                       };
+
+                                       pm8941_l20: l20 {
+                                               regulator-min-microvolt = <2950000>;
+                                               regulator-max-microvolt = <2950000>;
+                                       };
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom,smd-rpm.txt
deleted file mode 100644 (file)
index e27f5c4..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-Qualcomm Resource Power Manager (RPM) over SMD
-
-This driver is used to interface with the Resource Power Manager (RPM) found in
-various Qualcomm platforms. The RPM allows each component in the system to vote
-for state of the system resources, such as clocks, regulators and bus
-frequencies.
-
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be one of:
-                   "qcom,rpm-msm8974"
-
-- qcom,smd-channels:
-       Usage: required
-       Value type: <stringlist>
-       Definition: Shared Memory channel used for communication with the RPM
-
-= SUBDEVICES
-
-The RPM exposes resources to its subnodes. The below bindings specify the set
-of valid subnodes that can operate on these resources.
-
-== Regulators
-
-Regulator nodes are identified by their compatible:
-
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be one of:
-                   "qcom,rpm-pm8841-regulators"
-                   "qcom,rpm-pm8941-regulators"
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s5-supply:
-- vdd_s6-supply:
-- vdd_s7-supply:
-- vdd_s8-supply:
-       Usage: optional (pm8841 only)
-       Value type: <phandle>
-       Definition: reference to regulator supplying the input pin, as
-                   described in the data sheet
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_l1_l3-supply:
-- vdd_l2_lvs1_2_3-supply:
-- vdd_l4_l11-supply:
-- vdd_l5_l7-supply:
-- vdd_l6_l12_l14_l15-supply:
-- vdd_l8_l16_l18_l19-supply:
-- vdd_l9_l10_l17_l22-supply:
-- vdd_l13_l20_l23_l24-supply:
-- vdd_l21-supply:
-- vin_5vs-supply:
-       Usage: optional (pm8941 only)
-       Value type: <phandle>
-       Definition: reference to regulator supplying the input pin, as
-                   described in the data sheet
-
-The regulator node houses sub-nodes for each regulator within the device. Each
-sub-node is identified using the node's name, with valid values listed for each
-of the pmics below.
-
-pm8841:
-       s1, s2, s3, s4, s5, s6, s7, s8
-
-pm8941:
-       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
-       l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
-       lvs3, 5vs1, 5vs2
-
-The content of each sub-node is defined by the standard binding for regulators -
-see regulator.txt.
-
-= EXAMPLE
-
-       smd {
-               compatible = "qcom,smd";
-
-               rpm {
-                       interrupts = <0 168 1>;
-                       qcom,ipc = <&apcs 8 0>;
-                       qcom,smd-edge = <15>;
-
-                       rpm_requests {
-                               compatible = "qcom,rpm-msm8974";
-                               qcom,smd-channels = "rpm_requests";
-
-                               pm8941-regulators {
-                                       compatible = "qcom,rpm-pm8941-regulators";
-                                       vdd_l13_l20_l23_l24-supply = <&pm8941_boost>;
-
-                                       pm8941_s3: s3 {
-                                               regulator-min-microvolt = <1800000>;
-                                               regulator-max-microvolt = <1800000>;
-                                       };
-
-                                       pm8941_boost: s4 {
-                                               regulator-min-microvolt = <5000000>;
-                                               regulator-max-microvolt = <5000000>;
-                                       };
-
-                                       pm8941_l20: l20 {
-                                               regulator-min-microvolt = <2950000>;
-                                               regulator-max-microvolt = <2950000>;
-                                       };
-                               };
-                       };
-               };
-       };
-
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
new file mode 100644 (file)
index 0000000..a48049c
--- /dev/null
@@ -0,0 +1,58 @@
+Qualcomm Resource Power Manager (RPM) over SMD
+
+This driver is used to interface with the Resource Power Manager (RPM) found in
+various Qualcomm platforms. The RPM allows each component in the system to vote
+for state of the system resources, such as clocks, regulators and bus
+frequencies.
+
+The SMD information for the RPM edge should be filled out.  See qcom,smd.txt for
+the required edge properties.  All SMD related properties will reside within the
+RPM node itself.
+
+= SUBDEVICES
+
+The RPM exposes resources to its subnodes.  The rpm_requests node must be
+present and this subnode may contain children that designate regulator
+resources.
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,rpm-apq8084"
+                   "qcom,rpm-msm8916"
+                   "qcom,rpm-msm8974"
+
+- qcom,smd-channels:
+       Usage: required
+       Value type: <string>
+       Definition: must be "rpm_requests"
+
+Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
+for information on the regulator subnodes that can exist under the rpm_requests.
+
+Example:
+
+       soc {
+               apcs: syscon@f9011000 {
+                       compatible = "syscon";
+                       reg = <0xf9011000 0x1000>;
+               };
+       };
+
+       smd {
+               compatible = "qcom,smd";
+
+               rpm {
+                       interrupts = <0 168 1>;
+                       qcom,ipc = <&apcs 8 0>;
+                       qcom,smd-edge = <15>;
+
+                       rpm_requests {
+                               compatible = "qcom,rpm-msm8974";
+                               qcom,smd-channels = "rpm_requests";
+
+                               ...
+                       };
+               };
+       };
index bfa4944..3904dc0 100644 (file)
@@ -522,6 +522,14 @@ config REGULATOR_PV88060
          Say y here to support the voltage regulators and convertors
          PV88060
 
+config REGULATOR_PV88090
+       tristate "Powerventure Semiconductor PV88090 regulator"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Say y here to support the voltage regulators and convertors
+         on PV88090
+
 config REGULATOR_PWM
        tristate "PWM voltage regulator"
        depends on PWM
@@ -698,6 +706,13 @@ config REGULATOR_TPS6507X
          three step-down converters and two general-purpose LDO voltage regulators.
          It supports TI's software based Class-2 SmartReflex implementation.
 
+config REGULATOR_TPS65086
+       tristate "TI TPS65086 Power regulators"
+       depends on MFD_TPS65086
+       help
+         This driver provides support for the voltage regulators on
+         TI TPS65086 PMICs.
+
 config REGULATOR_TPS65090
        tristate "TI TPS65090 Power regulator"
        depends on MFD_TPS65090
index 3f6a6a6..980b194 100644 (file)
@@ -68,6 +68,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
+obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o
 obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
 obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
@@ -87,6 +88,7 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65086) += tps65086-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c
new file mode 100644 (file)
index 0000000..ac15f31
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * pv88090-regulator.c - Regulator device driver for PV88090
+ * Copyright (C) 2015  Powerventure Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include "pv88090-regulator.h"
+
+#define PV88090_MAX_REGULATORS 5
+
+/* PV88090 REGULATOR IDs */
+enum {
+       /* BUCKs */
+       PV88090_ID_BUCK1,
+       PV88090_ID_BUCK2,
+       PV88090_ID_BUCK3,
+
+       /* LDOs */
+       PV88090_ID_LDO1,
+       PV88090_ID_LDO2,
+};
+
+struct pv88090_regulator {
+       struct regulator_desc desc;
+       /* Current limiting */
+       unsigned        n_current_limits;
+       const int       *current_limits;
+       unsigned int limit_mask;
+       unsigned int conf;
+       unsigned int conf2;
+};
+
+struct pv88090 {
+       struct device *dev;
+       struct regmap *regmap;
+       struct regulator_dev *rdev[PV88090_MAX_REGULATORS];
+};
+
+struct pv88090_buck_voltage {
+       int min_uV;
+       int max_uV;
+       int uV_step;
+};
+
+static const struct regmap_config pv88090_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
+ *  Entry indexes corresponds to register values.
+ */
+
+static const int pv88090_buck1_limits[] = {
+        220000,  440000,  660000,  880000, 1100000, 1320000, 1540000, 1760000,
+       1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000,
+       3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000,
+       5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000
+};
+
+static const int pv88090_buck23_limits[] = {
+       1496000, 2393000, 3291000, 4189000
+};
+
+static const struct pv88090_buck_voltage pv88090_buck_vol[3] = {
+       {
+               .min_uV = 600000,
+               .max_uV = 1393750,
+               .uV_step = 6250,
+       },
+
+       {
+               .min_uV = 1400000,
+               .max_uV = 2193750,
+               .uV_step = 6250,
+       },
+       {
+               .min_uV = 1250000,
+               .max_uV = 2837500,
+               .uV_step = 12500,
+       },
+};
+
+static unsigned int pv88090_buck_get_mode(struct regulator_dev *rdev)
+{
+       struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+       unsigned int data;
+       int ret, mode = 0;
+
+       ret = regmap_read(rdev->regmap, info->conf, &data);
+       if (ret < 0)
+               return ret;
+
+       switch (data & PV88090_BUCK1_MODE_MASK) {
+       case PV88090_BUCK_MODE_SYNC:
+               mode = REGULATOR_MODE_FAST;
+               break;
+       case PV88090_BUCK_MODE_AUTO:
+               mode = REGULATOR_MODE_NORMAL;
+               break;
+       case PV88090_BUCK_MODE_SLEEP:
+               mode = REGULATOR_MODE_STANDBY;
+               break;
+       }
+
+       return mode;
+}
+
+static int pv88090_buck_set_mode(struct regulator_dev *rdev,
+                                       unsigned int mode)
+{
+       struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+       int val = 0;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               val = PV88090_BUCK_MODE_SYNC;
+               break;
+       case REGULATOR_MODE_NORMAL:
+               val = PV88090_BUCK_MODE_AUTO;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               val = PV88090_BUCK_MODE_SLEEP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(rdev->regmap, info->conf,
+                                       PV88090_BUCK1_MODE_MASK, val);
+}
+
+static int pv88090_set_current_limit(struct regulator_dev *rdev, int min,
+                                   int max)
+{
+       struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+       int i;
+
+       /* search for closest to maximum */
+       for (i = info->n_current_limits; i >= 0; i--) {
+               if (min <= info->current_limits[i]
+                       && max >= info->current_limits[i]) {
+                       return regmap_update_bits(rdev->regmap,
+                               info->conf,
+                               info->limit_mask,
+                               i << PV88090_BUCK1_ILIM_SHIFT);
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int pv88090_get_current_limit(struct regulator_dev *rdev)
+{
+       struct pv88090_regulator *info = rdev_get_drvdata(rdev);
+       unsigned int data;
+       int ret;
+
+       ret = regmap_read(rdev->regmap, info->conf, &data);
+       if (ret < 0)
+               return ret;
+
+       data = (data & info->limit_mask) >> PV88090_BUCK1_ILIM_SHIFT;
+       return info->current_limits[data];
+}
+
+static struct regulator_ops pv88090_buck_ops = {
+       .get_mode = pv88090_buck_get_mode,
+       .set_mode = pv88090_buck_set_mode,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_current_limit = pv88090_set_current_limit,
+       .get_current_limit = pv88090_get_current_limit,
+};
+
+static struct regulator_ops pv88090_ldo_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PV88090_BUCK(chip, regl_name, min, step, max, limits_array) \
+{\
+       .desc   =       {\
+               .id = chip##_ID_##regl_name,\
+               .name = __stringify(chip##_##regl_name),\
+               .of_match = of_match_ptr(#regl_name),\
+               .regulators_node = of_match_ptr("regulators"),\
+               .type = REGULATOR_VOLTAGE,\
+               .owner = THIS_MODULE,\
+               .ops = &pv88090_buck_ops,\
+               .min_uV = min, \
+               .uV_step = step, \
+               .n_voltages = ((max) - (min))/(step) + 1, \
+               .enable_reg = PV88090_REG_##regl_name##_CONF0, \
+               .enable_mask = PV88090_##regl_name##_EN, \
+               .vsel_reg = PV88090_REG_##regl_name##_CONF0, \
+               .vsel_mask = PV88090_V##regl_name##_MASK, \
+       },\
+       .current_limits = limits_array, \
+       .n_current_limits = ARRAY_SIZE(limits_array), \
+       .limit_mask = PV88090_##regl_name##_ILIM_MASK, \
+       .conf = PV88090_REG_##regl_name##_CONF1, \
+       .conf2 = PV88090_REG_##regl_name##_CONF2, \
+}
+
+#define PV88090_LDO(chip, regl_name, min, step, max) \
+{\
+       .desc   =       {\
+               .id = chip##_ID_##regl_name,\
+               .name = __stringify(chip##_##regl_name),\
+               .of_match = of_match_ptr(#regl_name),\
+               .regulators_node = of_match_ptr("regulators"),\
+               .type = REGULATOR_VOLTAGE,\
+               .owner = THIS_MODULE,\
+               .ops = &pv88090_ldo_ops,\
+               .min_uV = min, \
+               .uV_step = step, \
+               .n_voltages = ((max) - (min))/(step) + 1, \
+               .enable_reg = PV88090_REG_##regl_name##_CONT, \
+               .enable_mask = PV88090_##regl_name##_EN, \
+               .vsel_reg = PV88090_REG_##regl_name##_CONT, \
+               .vsel_mask = PV88090_V##regl_name##_MASK, \
+       },\
+}
+
+static struct pv88090_regulator pv88090_regulator_info[] = {
+       PV88090_BUCK(PV88090, BUCK1, 600000, 6250, 1393750,
+               pv88090_buck1_limits),
+       PV88090_BUCK(PV88090, BUCK2, 600000, 6250, 1393750,
+               pv88090_buck23_limits),
+       PV88090_BUCK(PV88090, BUCK3, 600000, 6250, 1393750,
+               pv88090_buck23_limits),
+       PV88090_LDO(PV88090, LDO1, 1200000, 50000, 4350000),
+       PV88090_LDO(PV88090, LDO2,  650000, 25000, 2225000),
+};
+
+static irqreturn_t pv88090_irq_handler(int irq, void *data)
+{
+       struct pv88090 *chip = data;
+       int i, reg_val, err, ret = IRQ_NONE;
+
+       err = regmap_read(chip->regmap, PV88090_REG_EVENT_A, &reg_val);
+       if (err < 0)
+               goto error_i2c;
+
+       if (reg_val & PV88090_E_VDD_FLT) {
+               for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+                       if (chip->rdev[i] != NULL) {
+                               regulator_notifier_call_chain(chip->rdev[i],
+                                       REGULATOR_EVENT_UNDER_VOLTAGE,
+                                       NULL);
+                       }
+               }
+
+               err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
+                       PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
+               if (err < 0)
+                       goto error_i2c;
+
+               ret = IRQ_HANDLED;
+       }
+
+       if (reg_val & PV88090_E_OVER_TEMP) {
+               for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+                       if (chip->rdev[i] != NULL) {
+                               regulator_notifier_call_chain(chip->rdev[i],
+                                       REGULATOR_EVENT_OVER_TEMP,
+                                       NULL);
+                       }
+               }
+
+               err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
+                       PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
+               if (err < 0)
+                       goto error_i2c;
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+
+error_i2c:
+       dev_err(chip->dev, "I2C error : %d\n", err);
+       return IRQ_NONE;
+}
+
+/*
+ * I2C driver interface functions
+ */
+static int pv88090_i2c_probe(struct i2c_client *i2c,
+               const struct i2c_device_id *id)
+{
+       struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
+       struct pv88090 *chip;
+       struct regulator_config config = { };
+       int error, i, ret = 0;
+       unsigned int conf2, range, index;
+
+       chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = &i2c->dev;
+       chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
+       if (IS_ERR(chip->regmap)) {
+               error = PTR_ERR(chip->regmap);
+               dev_err(chip->dev, "Failed to allocate register map: %d\n",
+                       error);
+               return error;
+       }
+
+       i2c_set_clientdata(i2c, chip);
+
+       if (i2c->irq != 0) {
+               ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
+               if (ret < 0) {
+                       dev_err(chip->dev,
+                               "Failed to mask A reg: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
+               if (ret < 0) {
+                       dev_err(chip->dev,
+                               "Failed to mask B reg: %d\n", ret);
+                       return ret;
+               }
+
+               ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+                                       pv88090_irq_handler,
+                                       IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+                                       "pv88090", chip);
+               if (ret != 0) {
+                       dev_err(chip->dev, "Failed to request IRQ: %d\n",
+                               i2c->irq);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
+                       PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
+               if (ret < 0) {
+                       dev_err(chip->dev,
+                               "Failed to update mask reg: %d\n", ret);
+                       return ret;
+               }
+
+       } else {
+               dev_warn(chip->dev, "No IRQ configured\n");
+       }
+
+       config.dev = chip->dev;
+       config.regmap = chip->regmap;
+
+       for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
+               if (init_data)
+                       config.init_data = &init_data[i];
+
+               if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
+                       ret = regmap_read(chip->regmap,
+                               pv88090_regulator_info[i].conf2, &conf2);
+                       if (ret < 0)
+                               return ret;
+
+                       conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
+                               PV88090_BUCK_VDAC_RANGE_MASK;
+
+                       ret = regmap_read(chip->regmap,
+                               PV88090_REG_BUCK_FOLD_RANGE, &range);
+                       if (ret < 0)
+                               return ret;
+
+                       range = (range >>
+                                (PV88080_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
+                               PV88080_BUCK_VRANGE_GAIN_MASK;
+                       index = ((range << 1) | conf2);
+
+                       pv88090_regulator_info[i].desc.min_uV
+                               = pv88090_buck_vol[index].min_uV;
+                       pv88090_regulator_info[i].desc.uV_step
+                               = pv88090_buck_vol[index].uV_step;
+                       pv88090_regulator_info[i].desc.n_voltages
+                               = ((pv88090_buck_vol[index].max_uV)
+                               - (pv88090_buck_vol[index].min_uV))
+                               /(pv88090_buck_vol[index].uV_step) + 1;
+               }
+
+               config.driver_data = (void *)&pv88090_regulator_info[i];
+               chip->rdev[i] = devm_regulator_register(chip->dev,
+                       &pv88090_regulator_info[i].desc, &config);
+               if (IS_ERR(chip->rdev[i])) {
+                       dev_err(chip->dev,
+                               "Failed to register PV88090 regulator\n");
+                       return PTR_ERR(chip->rdev[i]);
+               }
+       }
+
+       return 0;
+}
+
+static const struct i2c_device_id pv88090_i2c_id[] = {
+       {"pv88090", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pv88090_dt_ids[] = {
+       { .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
+#endif
+
+static struct i2c_driver pv88090_regulator_driver = {
+       .driver = {
+               .name = "pv88090",
+               .of_match_table = of_match_ptr(pv88090_dt_ids),
+       },
+       .probe = pv88090_i2c_probe,
+       .id_table = pv88090_i2c_id,
+};
+
+module_i2c_driver(pv88090_regulator_driver);
+
+MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pv88090-regulator.h b/drivers/regulator/pv88090-regulator.h
new file mode 100644 (file)
index 0000000..d7aca8d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * pv88090-regulator.h - Regulator definitions for PV88090
+ * Copyright (C) 2015 Powerventure Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PV88090_REGISTERS_H__
+#define __PV88090_REGISTERS_H__
+
+/* System Control and Event Registers */
+#define        PV88090_REG_EVENT_A                     0x03
+#define        PV88090_REG_MASK_A                      0x06
+#define        PV88090_REG_MASK_B                      0x07
+
+/* Regulator Registers */
+#define        PV88090_REG_BUCK1_CONF0                 0x18
+#define        PV88090_REG_BUCK1_CONF1                 0x19
+#define        PV88090_REG_BUCK1_CONF2                 0x1a
+#define        PV88090_REG_BUCK2_CONF0                 0x1b
+#define        PV88090_REG_BUCK2_CONF1                 0x1c
+#define        PV88090_REG_BUCK2_CONF2                 0x58
+#define        PV88090_REG_BUCK3_CONF0                 0x1d
+#define        PV88090_REG_BUCK3_CONF1                 0x1e
+#define        PV88090_REG_BUCK3_CONF2                 0x5c
+
+#define        PV88090_REG_LDO1_CONT                   0x1f
+#define        PV88090_REG_LDO2_CONT                   0x20
+#define        PV88090_REG_LDO3_CONT                   0x21
+#define        PV88090_REG_BUCK_FOLD_RANGE                     0x61
+
+/* PV88090_REG_EVENT_A (addr=0x03) */
+#define        PV88090_E_VDD_FLT                               0x01
+#define        PV88090_E_OVER_TEMP                     0x02
+
+/* PV88090_REG_MASK_A (addr=0x06) */
+#define        PV88090_M_VDD_FLT                               0x01
+#define        PV88090_M_OVER_TEMP                     0x02
+
+/* PV88090_REG_BUCK1_CONF0 (addr=0x18) */
+#define        PV88090_BUCK1_EN                                0x80
+#define PV88090_VBUCK1_MASK                    0x7F
+/* PV88090_REG_BUCK2_CONF0 (addr=0x1b) */
+#define        PV88090_BUCK2_EN                                0x80
+#define PV88090_VBUCK2_MASK                    0x7F
+/* PV88090_REG_BUCK3_CONF0 (addr=0x1d) */
+#define        PV88090_BUCK3_EN                                0x80
+#define PV88090_VBUCK3_MASK                    0x7F
+/* PV88090_REG_LDO1_CONT (addr=0x1f) */
+#define        PV88090_LDO1_EN                         0x40
+#define PV88090_VLDO1_MASK                     0x3F
+/* PV88090_REG_LDO2_CONT (addr=0x20) */
+#define        PV88090_LDO2_EN                         0x40
+#define PV88090_VLDO2_MASK                     0x3F
+
+/* PV88090_REG_BUCK1_CONF1 (addr=0x19) */
+#define PV88090_BUCK1_ILIM_SHIFT                       2
+#define PV88090_BUCK1_ILIM_MASK                        0x7C
+#define PV88090_BUCK1_MODE_MASK                        0x03
+
+/* PV88090_REG_BUCK2_CONF1 (addr=0x1c) */
+#define PV88090_BUCK2_ILIM_SHIFT                       2
+#define PV88090_BUCK2_ILIM_MASK                        0x0C
+#define PV88090_BUCK2_MODE_MASK                        0x03
+
+/* PV88090_REG_BUCK3_CONF1 (addr=0x1e) */
+#define PV88090_BUCK3_ILIM_SHIFT                       2
+#define PV88090_BUCK3_ILIM_MASK                        0x0C
+#define PV88090_BUCK3_MODE_MASK                        0x03
+
+#define        PV88090_BUCK_MODE_SLEEP                 0x00
+#define        PV88090_BUCK_MODE_AUTO                  0x01
+#define        PV88090_BUCK_MODE_SYNC                  0x02
+
+/* PV88090_REG_BUCK2_CONF2 (addr=0x58) */
+/* PV88090_REG_BUCK3_CONF2 (addr=0x5c) */
+#define PV88090_BUCK_VDAC_RANGE_SHIFT                  7
+#define PV88090_BUCK_VDAC_RANGE_MASK                   0x01
+
+#define PV88090_BUCK_VDAC_RANGE_1                      0x00
+#define PV88090_BUCK_VDAC_RANGE_2                      0x01
+
+/* PV88090_REG_BUCK_FOLD_RANGE (addr=0x61) */
+#define PV88080_BUCK_VRANGE_GAIN_SHIFT                 3
+#define PV88080_BUCK_VRANGE_GAIN_MASK                  0x01
+
+#define PV88080_BUCK_VRANGE_GAIN_1                     0x00
+#define PV88080_BUCK_VRANGE_GAIN_2                     0x01
+
+#endif /* __PV88090_REGISTERS_H__ */
index 6fa0c7d..56a17ec 100644 (file)
@@ -153,6 +153,49 @@ static const struct regulator_ops rpm_switch_ops = {
        .is_enabled = rpm_reg_is_enabled,
 };
 
+static const struct regulator_desc pma8084_hfsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(375000,  0,  95, 12500),
+               REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 159,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_ftsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(350000,  0, 184, 5000),
+               REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 340,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_pldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000,  0,  30, 25000),
+               REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 100,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_nldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 64,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pma8084_switch = {
+       .ops = &rpm_switch_ops,
+};
+
 static const struct regulator_desc pm8x41_hfsmps = {
        .linear_ranges = (struct regulator_linear_range[]) {
                REGULATOR_LINEAR_RANGE( 375000,  0,  95, 12500),
@@ -211,6 +254,43 @@ static const struct regulator_desc pm8941_switch = {
        .ops = &rpm_switch_ops,
 };
 
+static const struct regulator_desc pm8916_pldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 209,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_nldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(375000, 0, 93, 12500),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 94,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_buck_lvo_smps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
+               REGULATOR_LINEAR_RANGE(750000, 96, 127, 25000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 128,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8916_buck_hvo_smps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(1550000, 0, 31, 25000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 32,
+       .ops = &rpm_smps_ldo_ops,
+};
+
 struct rpm_regulator_data {
        const char *name;
        u32 type;
@@ -231,6 +311,32 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" },
+       { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8916_buck_lvo_smps, "vdd_s3" },
+       { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8916_buck_hvo_smps, "vdd_s4" },
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1_l2_l3" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l1_l2_l3" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l1_l2_l3" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l5_l6" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8916_pldo, "vdd_l4_l5_l6" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8916_pldo, "vdd_l4_l5_l6" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8916_pldo, "vdd_l7" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
+       {}
+};
+
 static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
        { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
        { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
@@ -272,9 +378,62 @@ static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pma8084_ftsmps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pma8084_ftsmps, "vdd_s2" },
+       { "s3", QCOM_SMD_RPM_SMPA, 3, &pma8084_hfsmps, "vdd_s3" },
+       { "s4", QCOM_SMD_RPM_SMPA, 4, &pma8084_hfsmps, "vdd_s4" },
+       { "s5", QCOM_SMD_RPM_SMPA, 5, &pma8084_hfsmps, "vdd_s5" },
+       { "s6", QCOM_SMD_RPM_SMPA, 6, &pma8084_ftsmps, "vdd_s6" },
+       { "s7", QCOM_SMD_RPM_SMPA, 7, &pma8084_ftsmps, "vdd_s7" },
+       { "s8", QCOM_SMD_RPM_SMPA, 8, &pma8084_ftsmps, "vdd_s8" },
+       { "s9", QCOM_SMD_RPM_SMPA, 9, &pma8084_ftsmps, "vdd_s9" },
+       { "s10", QCOM_SMD_RPM_SMPA, 10, &pma8084_ftsmps, "vdd_s10" },
+       { "s11", QCOM_SMD_RPM_SMPA, 11, &pma8084_ftsmps, "vdd_s11" },
+       { "s12", QCOM_SMD_RPM_SMPA, 12, &pma8084_ftsmps, "vdd_s12" },
+
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pma8084_nldo, "vdd_l1_l11" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pma8084_pldo, "vdd_l5_l7" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pma8084_pldo, "vdd_l5_l7" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pma8084_pldo, "vdd_l8" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pma8084_nldo, "vdd_l1_l11" },
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l14", QCOM_SMD_RPM_LDOA, 14, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+       { "l15", QCOM_SMD_RPM_LDOA, 15, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+       { "l16", QCOM_SMD_RPM_LDOA, 16, &pma8084_pldo, "vdd_l16_l25" },
+       { "l17", QCOM_SMD_RPM_LDOA, 17, &pma8084_pldo, "vdd_l17" },
+       { "l18", QCOM_SMD_RPM_LDOA, 18, &pma8084_pldo, "vdd_l18" },
+       { "l19", QCOM_SMD_RPM_LDOA, 19, &pma8084_pldo, "vdd_l19" },
+       { "l20", QCOM_SMD_RPM_LDOA, 20, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l21", QCOM_SMD_RPM_LDOA, 21, &pma8084_pldo, "vdd_l21" },
+       { "l22", QCOM_SMD_RPM_LDOA, 22, &pma8084_pldo, "vdd_l22" },
+       { "l23", QCOM_SMD_RPM_LDOA, 23, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l24", QCOM_SMD_RPM_LDOA, 24, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
+       { "l25", QCOM_SMD_RPM_LDOA, 25, &pma8084_pldo, "vdd_l16_l25" },
+       { "l26", QCOM_SMD_RPM_LDOA, 26, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
+       { "l27", QCOM_SMD_RPM_LDOA, 27, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
+
+       { "lvs1", QCOM_SMD_RPM_VSA, 1, &pma8084_switch },
+       { "lvs2", QCOM_SMD_RPM_VSA, 2, &pma8084_switch },
+       { "lvs3", QCOM_SMD_RPM_VSA, 3, &pma8084_switch },
+       { "lvs4", QCOM_SMD_RPM_VSA, 4, &pma8084_switch },
+       { "5vs1", QCOM_SMD_RPM_VSA, 5, &pma8084_switch },
+
+       {}
+};
+
 static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
+       { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
        { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
+       { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
        {}
 };
 MODULE_DEVICE_TABLE(of, rpm_of_match);
index ddc4f10..584ef3d 100644 (file)
@@ -27,90 +27,12 @@ static const unsigned int tps6105x_voltages[] = {
        5000000, /* There is an additional 5V */
 };
 
-static int tps6105x_regulator_enable(struct regulator_dev *rdev)
-{
-       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
-       int ret;
-
-       /* Activate voltage mode */
-       ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
-               TPS6105X_REG0_MODE_MASK,
-               TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int tps6105x_regulator_disable(struct regulator_dev *rdev)
-{
-       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
-       int ret;
-
-       /* Set into shutdown mode */
-       ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
-               TPS6105X_REG0_MODE_MASK,
-               TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
-{
-       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
-       unsigned int regval;
-       int ret;
-
-       ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
-       if (ret)
-               return ret;
-       regval &= TPS6105X_REG0_MODE_MASK;
-       regval >>= TPS6105X_REG0_MODE_SHIFT;
-
-       if (regval == TPS6105X_REG0_MODE_VOLTAGE)
-               return 1;
-
-       return 0;
-}
-
-static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
-       unsigned int regval;
-       int ret;
-
-       ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
-       if (ret)
-               return ret;
-
-       regval &= TPS6105X_REG0_VOLTAGE_MASK;
-       regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
-       return (int) regval;
-}
-
-static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
-                                             unsigned selector)
-{
-       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
-       int ret;
-
-       ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
-                                   TPS6105X_REG0_VOLTAGE_MASK,
-                                   selector << TPS6105X_REG0_VOLTAGE_SHIFT);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 static struct regulator_ops tps6105x_regulator_ops = {
-       .enable         = tps6105x_regulator_enable,
-       .disable        = tps6105x_regulator_disable,
-       .is_enabled     = tps6105x_regulator_is_enabled,
-       .get_voltage_sel = tps6105x_regulator_get_voltage_sel,
-       .set_voltage_sel = tps6105x_regulator_set_voltage_sel,
+       .enable         = regulator_enable_regmap,
+       .disable        = regulator_disable_regmap,
+       .is_enabled     = regulator_is_enabled_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .list_voltage   = regulator_list_voltage_table,
 };
 
@@ -122,6 +44,12 @@ static const struct regulator_desc tps6105x_regulator_desc = {
        .owner          = THIS_MODULE,
        .n_voltages     = ARRAY_SIZE(tps6105x_voltages),
        .volt_table     = tps6105x_voltages,
+       .vsel_reg       = TPS6105X_REG_0,
+       .vsel_mask      = TPS6105X_REG0_VOLTAGE_MASK,
+       .enable_reg     = TPS6105X_REG_0,
+       .enable_mask    = TPS6105X_REG0_MODE_MASK,
+       .enable_val     = TPS6105X_REG0_MODE_VOLTAGE <<
+                         TPS6105X_REG0_MODE_SHIFT,
 };
 
 /*
@@ -144,6 +72,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)
        config.dev = &tps6105x->client->dev;
        config.init_data = pdata->regulator_data;
        config.driver_data = tps6105x;
+       config.regmap = tps6105x->regmap;
 
        /* Register regulator with framework */
        tps6105x->regulator = devm_regulator_register(&pdev->dev,
diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c
new file mode 100644 (file)
index 0000000..33f389d
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Author: Andrew F. Davis <afd@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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.
+ *
+ * Based on the TPS65912 driver
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+#include <linux/mfd/tps65086.h>
+
+enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
+       LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
+
+#define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm)    \
+       [_id] = {                                                       \
+               .desc = {                                               \
+                       .name                   = _name,                \
+                       .of_match               = of_match_ptr(_of),    \
+                       .regulators_node        = "regulators",         \
+                       .of_parse_cb            = tps65086_of_parse_cb, \
+                       .id                     = _id,                  \
+                       .ops                    = &reg_ops,             \
+                       .n_voltages             = _nv,                  \
+                       .type                   = REGULATOR_VOLTAGE,    \
+                       .owner                  = THIS_MODULE,          \
+                       .vsel_reg               = _vr,                  \
+                       .vsel_mask              = _vm,                  \
+                       .enable_reg             = _er,                  \
+                       .enable_mask            = _em,                  \
+                       .volt_table             = NULL,                 \
+                       .linear_ranges          = _lr,                  \
+                       .n_linear_ranges        = ARRAY_SIZE(_lr),      \
+               },                                                      \
+               .decay_reg = _dr,                                       \
+               .decay_mask = _dm,                                      \
+       }
+
+#define TPS65086_SWITCH(_name, _of, _id, _er, _em)                     \
+       [_id] = {                                                       \
+               .desc = {                                               \
+                       .name                   = _name,                \
+                       .of_match               = of_match_ptr(_of),    \
+                       .regulators_node        = "regulators",         \
+                       .of_parse_cb            = tps65086_of_parse_cb, \
+                       .id                     = _id,                  \
+                       .ops                    = &switch_ops,          \
+                       .type                   = REGULATOR_VOLTAGE,    \
+                       .owner                  = THIS_MODULE,          \
+                       .enable_reg             = _er,                  \
+                       .enable_mask            = _em,                  \
+               },                                                      \
+       }
+
+struct tps65086_regulator {
+       struct regulator_desc desc;
+       unsigned int decay_reg;
+       unsigned int decay_mask;
+};
+
+static const struct regulator_linear_range tps65086_buck126_10mv_ranges[] = {
+       REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+       REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
+};
+
+static const struct regulator_linear_range tps65086_buck126_25mv_ranges[] = {
+       REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+       REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x18, 0),
+       REGULATOR_LINEAR_RANGE(1025000, 0x19, 0x7F, 25000),
+};
+
+static const struct regulator_linear_range tps65086_buck345_ranges[] = {
+       REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
+       REGULATOR_LINEAR_RANGE(425000, 0x1, 0x7F, 25000),
+};
+
+static const struct regulator_linear_range tps65086_ldoa1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0),
+       REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000),
+       REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000),
+       REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000),
+       REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0),
+};
+
+static const struct regulator_linear_range tps65086_ldoa23_ranges[] = {
+       REGULATOR_LINEAR_RANGE(700000, 0x0, 0xD, 50000),
+       REGULATOR_LINEAR_RANGE(1400000, 0xE, 0xF, 100000),
+};
+
+/* Operations permitted on regulators */
+static struct regulator_ops reg_ops = {
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .map_voltage            = regulator_map_voltage_linear_range,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .list_voltage           = regulator_list_voltage_linear_range,
+};
+
+/* Operations permitted on load switches */
+static struct regulator_ops switch_ops = {
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+};
+
+static int tps65086_of_parse_cb(struct device_node *dev,
+                               const struct regulator_desc *desc,
+                               struct regulator_config *config);
+
+static struct tps65086_regulator regulators[] = {
+       TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
+                          BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
+                          tps65086_buck126_10mv_ranges, TPS65086_BUCK1CTRL,
+                          BIT(0)),
+       TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
+                          BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
+                          tps65086_buck126_10mv_ranges, TPS65086_BUCK2CTRL,
+                          BIT(0)),
+       TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
+                          BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
+                          tps65086_buck345_ranges, TPS65086_BUCK3DECAY,
+                          BIT(0)),
+       TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
+                          BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
+                          tps65086_buck345_ranges, TPS65086_BUCK4VID,
+                          BIT(0)),
+       TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
+                          BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
+                          tps65086_buck345_ranges, TPS65086_BUCK5CTRL,
+                          BIT(0)),
+       TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
+                          BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
+                          tps65086_buck126_10mv_ranges, TPS65086_BUCK6CTRL,
+                          BIT(0)),
+       TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
+                          VDOA1_VID_MASK, TPS65086_LDOA1CTRL, BIT(0),
+                          tps65086_ldoa1_ranges, 0, 0),
+       TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
+                          VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
+                          tps65086_ldoa23_ranges, 0, 0),
+       TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
+                          VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
+                          tps65086_ldoa23_ranges, 0, 0),
+       TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
+       TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+       TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)),
+       TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+};
+
+static inline bool has_25mv_mode(int id)
+{
+       switch (id) {
+       case BUCK1:
+       case BUCK2:
+       case BUCK6:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int tps65086_of_parse_cb(struct device_node *dev,
+                               const struct regulator_desc *desc,
+                               struct regulator_config *config)
+{
+       int ret;
+
+       /* Check for 25mV step mode */
+       if (has_25mv_mode(desc->id) &&
+                       of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) {
+               regulators[desc->id].desc.linear_ranges =
+                               tps65086_buck126_25mv_ranges;
+               regulators[desc->id].desc.n_linear_ranges =
+                               ARRAY_SIZE(tps65086_buck126_25mv_ranges);
+       }
+
+       /* Check for decay mode */
+       if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) {
+               ret = regmap_write_bits(config->regmap,
+                                       regulators[desc->id].decay_reg,
+                                       regulators[desc->id].decay_mask,
+                                       regulators[desc->id].decay_mask);
+               if (ret) {
+                       dev_err(config->dev, "Error setting decay\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int tps65086_regulator_probe(struct platform_device *pdev)
+{
+       struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = { };
+       struct regulator_dev *rdev;
+       int i;
+
+       platform_set_drvdata(pdev, tps);
+
+       config.dev = &pdev->dev;
+       config.dev->of_node = tps->dev->of_node;
+       config.driver_data = tps;
+       config.regmap = tps->regmap;
+
+       for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+               rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps->dev, "failed to register %s regulator\n",
+                               pdev->name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id tps65086_regulator_id_table[] = {
+       { "tps65086-regulator", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table);
+
+static struct platform_driver tps65086_regulator_driver = {
+       .driver = {
+               .name = "tps65086-regulator",
+       },
+       .probe = tps65086_regulator_probe,
+       .id_table = tps65086_regulator_id_table,
+};
+module_platform_driver(tps65086_regulator_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("TPS65086 Regulator driver");
+MODULE_LICENSE("GPL v2");
index a02c1b9..a5e5634 100644 (file)
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps65218.h>
 
-enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
+enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
+                          DCDC5, DCDC6, LDO1, LS3 };
 
-#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, \
-                           _lr, _nlr, _delay, _fuv)            \
+#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
+                           _cr, _cm, _lr, _nlr, _delay, _fuv)          \
        {                                                       \
                .name                   = _name,                \
                .id                     = _id,                  \
                .ops                    = &_ops,                \
                .n_voltages             = _n,                   \
-               .type                   = REGULATOR_VOLTAGE,    \
+               .type                   = _type,        \
                .owner                  = THIS_MODULE,          \
                .vsel_reg               = _vr,                  \
                .vsel_mask              = _vm,                  \
+               .csel_reg               = _cr,                  \
+               .csel_mask              = _cm,                  \
                .enable_reg             = _er,                  \
                .enable_mask            = _em,                  \
                .volt_table             = NULL,                 \
@@ -80,6 +83,7 @@ static struct tps_info tps65218_pmic_regs[] = {
        TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
        TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
        TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
+       TPS65218_INFO(LS3, "LS3", -1, -1),
 };
 
 #define TPS65218_OF_MATCH(comp, label) \
@@ -96,6 +100,7 @@ static const struct of_device_id tps65218_of_match[] = {
        TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
        TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
        TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
+       TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
        { }
 };
 MODULE_DEVICE_TABLE(of, tps65218_of_match);
@@ -175,6 +180,68 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
        .map_voltage            = regulator_map_voltage_linear_range,
 };
 
+static const int ls3_currents[] = { 100, 200, 500, 1000 };
+
+static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev,
+                                              int lim_uA)
+{
+       unsigned int index = 0;
+       unsigned int num_currents = ARRAY_SIZE(ls3_currents);
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+
+       while (index < num_currents && ls3_currents[index] != lim_uA)
+               index++;
+
+       if (index == num_currents)
+               return -EINVAL;
+
+       return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
+                                index << 2, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_set_current_limit(struct regulator_dev *dev,
+                                          int min_uA, int max_uA)
+{
+       int index = 0;
+       unsigned int num_currents = ARRAY_SIZE(ls3_currents);
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+
+       while (index < num_currents && ls3_currents[index] < max_uA)
+               index++;
+
+       index--;
+
+       if (index < 0 || ls3_currents[index] < min_uA)
+               return -EINVAL;
+
+       return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
+                                index << 2, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
+{
+       int retval;
+       unsigned int index;
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+
+       retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
+       if (retval < 0)
+               return retval;
+
+       index = (index & dev->desc->csel_mask) >> 2;
+
+       return ls3_currents[index];
+}
+
+static struct regulator_ops tps65218_ls3_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = tps65218_pmic_enable,
+       .disable                = tps65218_pmic_disable,
+       .set_input_current_limit = tps65218_pmic_set_input_current_lim,
+       .set_current_limit      = tps65218_pmic_set_current_limit,
+       .get_current_limit      = tps65218_pmic_get_current_limit,
+};
+
 /* Operations permitted on DCDC5, DCDC6 */
 static struct regulator_ops tps65218_dcdc56_pmic_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
@@ -183,36 +250,46 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
 };
 
 static const struct regulator_desc regulators[] = {
-       TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
-                          TPS65218_REG_CONTROL_DCDC1,
-                          TPS65218_CONTROL_DCDC1_MASK,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN,
-                          dcdc1_dcdc2_ranges, 2, 4000, 0),
-       TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
-                          TPS65218_REG_CONTROL_DCDC2,
-                          TPS65218_CONTROL_DCDC2_MASK,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN,
-                          dcdc1_dcdc2_ranges, 2, 4000, 0),
-       TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
-                          64, TPS65218_REG_CONTROL_DCDC3,
+       TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
+                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
+                          TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
+                          2, 4000, 0),
+       TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
+                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
+                          TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
+                          2, 4000, 0),
+       TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
+                          tps65218_ldo1_dcdc34_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC3,
                           TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
-                          TPS65218_ENABLE1_DC3_EN, ldo1_dcdc3_ranges, 2, 0, 0),
-       TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
-                          53, TPS65218_REG_CONTROL_DCDC4,
-                          TPS65218_CONTROL_DCDC4_MASK,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN,
-                          dcdc4_ranges, 2, 0, 0),
-       TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
-                          1, -1, -1, TPS65218_REG_ENABLE1,
-                          TPS65218_ENABLE1_DC5_EN, NULL, 0, 0, 1000000),
-       TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
-                          1, -1, -1, TPS65218_REG_ENABLE1,
-                          TPS65218_ENABLE1_DC6_EN, NULL, 0, 0, 1800000),
-       TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
+                          TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
+                          0, 0),
+       TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
+                          tps65218_ldo1_dcdc34_ops, 53,
+                          TPS65218_REG_CONTROL_DCDC4,
+                          TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
+                          0, 0),
+       TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
+                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
+                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
+                          NULL, 0, 0, 1000000),
+       TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
+                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
+                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
+                          NULL, 0, 0, 1800000),
+       TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
+                          tps65218_ldo1_dcdc34_ops, 64,
                           TPS65218_REG_CONTROL_LDO1,
                           TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
-                          TPS65218_ENABLE2_LDO1_EN, ldo1_dcdc3_ranges,
+                          TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
                           2, 0, 0),
+       TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
+                          tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
+                          TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
+                          TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0),
 };
 
 static int tps65218_regulator_probe(struct platform_device *pdev)
index 2f9b593..d58f3b5 100644 (file)
@@ -200,6 +200,8 @@ enum tps65218_regulator_id {
        TPS65218_DCDC_4,
        TPS65218_DCDC_5,
        TPS65218_DCDC_6,
+       /* LS's */
+       TPS65218_LS_3,
        /* LDOs */
        TPS65218_LDO_1,
 };
@@ -210,8 +212,11 @@ enum tps65218_regulator_id {
 #define TPS65218_NUM_DCDC              6
 /* Number of LDO voltage regulators available */
 #define TPS65218_NUM_LDO               1
+/* Number of total LS current regulators available */
+#define TPS65218_NUM_LS                        1
 /* Number of total regulators available */
-#define TPS65218_NUM_REGULATOR         (TPS65218_NUM_DCDC + TPS65218_NUM_LDO)
+#define TPS65218_NUM_REGULATOR         (TPS65218_NUM_DCDC + TPS65218_NUM_LDO \
+                                        + TPS65218_NUM_LS)
 
 /* Define the TPS65218 IRQ numbers */
 enum tps65218_irqs {
index 9c2903e..16ac9e1 100644 (file)
@@ -302,6 +302,8 @@ struct regulator_desc {
 
        unsigned int vsel_reg;
        unsigned int vsel_mask;
+       unsigned int csel_reg;
+       unsigned int csel_mask;
        unsigned int apply_reg;
        unsigned int apply_bit;
        unsigned int enable_reg;