]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'regulator-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Feb 2015 21:46:28 +0000 (13:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Feb 2015 21:46:28 +0000 (13:46 -0800)
Pull regulator updates from Mark Brown:
 "This has not been a busy release for the regulator framework, though
  we do have the first parts of some ongoing work from Bjorn Andersson
  to allow us to support more complex modern systems with dynamic
  configuration of regulators in suspend and idle states.

   - Support for device-specific properties on regulator nodes when
     using simplified DT parsing in the core from Krzysztof Kozlowski.

   - Restructuring of the load tracking code, intended to support future
     improvements in this area for more complex system designs.

   - New drivers for Maxim MAX77843 and Mediatek MT6397.

   - Lots of smaller fixes and improvements"

* tag 'regulator-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (29 commits)
  regulator: max77843: Add max77843 regulator driver
  regulator: Fix build breakage on !REGULATOR
  regulator: Build sysfs entries with static attribute groups
  regulator: qcom-rpm: Make it possible to specify supply
  regulator: core: Consolidate drms update handling
  regulator: qcom-rpm: signedness bug in probe()
  regulator: da9211: Add gpio control for enable/disable of buck
  regulator: qcom_rpm: Don't update vreg->uV/mV if rpm_reg_write fails
  regulator: lp872x: Remove **regulators from struct lp872x
  regulator: da9211: fix unmatched of_node
  regulator: Update documentation after renaming function argument
  regulator: axp20x: Migrate to regulator core's simplified DT parsing code
  regulator: axp20x: Fill regulators_node and of_match descriptor fields
  regulator: pfuze100-regulator: add pfuze3000 support
  regulator: max77686: Document gpio properties
  regulator: Allow parsing custom properties when using simplified DT parsing
  regulator: max77686: Add GPIO control
  regulator: Copy config passed during registration
  regulator: tps65023: Constify struct regmap_config and regulator_ops
  regulator: max8649: Constify struct regmap_config and regulator_ops
  ...

30 files changed:
Documentation/devicetree/bindings/mfd/max77686.txt
Documentation/devicetree/bindings/regulator/da9211.txt
Documentation/devicetree/bindings/regulator/isl9305.txt
Documentation/devicetree/bindings/regulator/mt6397-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/pfuze100.txt
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/axp20x-regulator.c
drivers/regulator/core.c
drivers/regulator/da9211-regulator.c
drivers/regulator/fan53555.c
drivers/regulator/internal.h
drivers/regulator/isl9305.c
drivers/regulator/lp872x.c
drivers/regulator/max14577.c
drivers/regulator/max77686.c
drivers/regulator/max77843.c [new file with mode: 0644]
drivers/regulator/max8649.c
drivers/regulator/mt6397-regulator.c [new file with mode: 0644]
drivers/regulator/of_regulator.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/qcom_rpm-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/rt5033-regulator.c
drivers/regulator/tps65023-regulator.c
include/linux/regulator/da9211.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/regulator/mt6397-regulator.h [new file with mode: 0644]
include/linux/regulator/pfuze100.h

index 75fdfaf41831d9fcd76be1b5706dadf1e2a2cb7d..e39f0bc1f55e02ccd705b85ae96714fd0a7e5263 100644 (file)
@@ -39,6 +39,12 @@ to get matched with their hardware counterparts as follow:
        -BUCKn  :       1-4.
   Use standard regulator bindings for it ('regulator-off-in-suspend').
 
+  LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable
+  control. To turn this feature on this property must be added to the regulator
+  sub-node:
+       - maxim,ena-gpios :     one GPIO specifier enable control (the gpio
+                               flags are actually ignored and always
+                               ACTIVE_HIGH is used)
 
 Example:
 
@@ -65,4 +71,12 @@ Example:
                                regulator-always-on;
                                regulator-boot-on;
                        };
+
+                       buck9_reg {
+                               regulator-compatible = "BUCK9";
+                               regulator-name = "CAM_ISP_CORE_1.2V";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1200000>;
+                               maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
+                       };
        }
index 240019a82f9a57083f4f06402250f2fbf41ec4ce..eb618907c7dee35446ae8b2153cf566e91cdb689 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
   BUCKA and BUCKB.
 
 Optional properties:
+- enable-gpios: platform gpio for control of BUCKA/BUCKB.
 - Any optional property defined in regulator.txt
 
 Example 1) DA9211
@@ -27,6 +28,7 @@ Example 1) DA9211
                                regulator-max-microvolt = <1570000>;
                                regulator-min-microamp  = <2000000>;
                                regulator-max-microamp  = <5000000>;
+                               enable-gpios = <&gpio 27 0>;
                        };
                        BUCKB {
                                regulator-name = "VBUCKB";
@@ -34,11 +36,12 @@ Example 1) DA9211
                                regulator-max-microvolt = <1570000>;
                                regulator-min-microamp  = <2000000>;
                                regulator-max-microamp  = <5000000>;
+                               enable-gpios = <&gpio 17 0>;
                        };
                };
        };
 
-Example 2) DA92113
+Example 2) DA9213
        pmic: da9213@68 {
                compatible = "dlg,da9213";
                reg = <0x68>;
@@ -51,6 +54,7 @@ Example 2) DA92113
                                regulator-max-microvolt = <1570000>;
                                regulator-min-microamp  = <3000000>;
                                regulator-max-microamp  = <6000000>;
+                               enable-gpios = <&gpio 27 0>;
                        };
                        BUCKB {
                                regulator-name = "VBUCKB";
@@ -58,6 +62,7 @@ Example 2) DA92113
                                regulator-max-microvolt = <1570000>;
                                regulator-min-microamp  = <3000000>;
                                regulator-max-microamp  = <6000000>;
+                               enable-gpios = <&gpio 17 0>;
                        };
                };
        };
index a626fc1bbf0d0bd1797191e91e31959e09c338a3..d6e7c9ec9413c0ddb0d6c66ee25812cce1683702 100644 (file)
@@ -2,7 +2,7 @@ Intersil ISL9305/ISL9305H voltage regulator
 
 Required properties:
 
-- compatible: "isl,isl9305" or "isl,isl9305h"
+- compatible: "isil,isl9305" or "isil,isl9305h"
 - reg: I2C slave address, usually 0x68.
 - 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
@@ -19,7 +19,7 @@ Optional properties:
 Example
 
        pmic: isl9305@68 {
-               compatible = "isl,isl9305";
+               compatible = "isil,isl9305";
                reg = <0x68>;
 
                VINDCD1-supply = <&system_power>;
diff --git a/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt
new file mode 100644 (file)
index 0000000..a42b1d6
--- /dev/null
@@ -0,0 +1,217 @@
+Mediatek MT6397 Regulator Driver
+
+Required properties:
+- compatible: "mediatek,mt6397-regulator"
+- mt6397regulator: List of regulators provided by this controller. It is named
+  according to its regulator type, buck_<name> and ldo_<name>.
+  The definition for each of these nodes is defined using the standard binding
+  for regulators at Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vpca15, buck_vpca7, buck_vsramca15, buck_vsramca7, buck_vcore, buck_vgpu,
+  buck_vdrm, buck_vio18
+LDO:
+  ldo_vtcxo, ldo_va28, ldo_vcama, ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch,
+  ldo_vemc3v3, ldo_vgp1, ldo_vgp2, ldo_vgp3, ldo_vgp4, ldo_vgp5, ldo_vgp6,
+  ldo_vibr
+
+Example:
+       pmic {
+               compatible = "mediatek,mt6397";
+
+               mt6397regulator: mt6397regulator {
+                       compatible = "mediatek,mt6397-regulator";
+
+                       mt6397_vpca15_reg: buck_vpca15 {
+                               regulator-compatible = "buck_vpca15";
+                               regulator-name = "vpca15";
+                               regulator-min-microvolt = < 850000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <200>;
+                       };
+
+                       mt6397_vpca7_reg: buck_vpca7 {
+                               regulator-compatible = "buck_vpca7";
+                               regulator-name = "vpca7";
+                               regulator-min-microvolt = < 850000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <115>;
+                       };
+
+                       mt6397_vsramca15_reg: buck_vsramca15 {
+                               regulator-compatible = "buck_vsramca15";
+                               regulator-name = "vsramca15";
+                               regulator-min-microvolt = < 850000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <115>;
+
+                       };
+
+                       mt6397_vsramca7_reg: buck_vsramca7 {
+                               regulator-compatible = "buck_vsramca7";
+                               regulator-name = "vsramca7";
+                               regulator-min-microvolt = < 850000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <115>;
+
+                       };
+
+                       mt6397_vcore_reg: buck_vcore {
+                               regulator-compatible = "buck_vcore";
+                               regulator-name = "vcore";
+                               regulator-min-microvolt = < 850000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <115>;
+                       };
+
+                       mt6397_vgpu_reg: buck_vgpu {
+                               regulator-compatible = "buck_vgpu";
+                               regulator-name = "vgpu";
+                               regulator-min-microvolt = < 700000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <115>;
+                       };
+
+                       mt6397_vdrm_reg: buck_vdrm {
+                               regulator-compatible = "buck_vdrm";
+                               regulator-name = "vdrm";
+                               regulator-min-microvolt = < 800000>;
+                               regulator-max-microvolt = <1400000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <500>;
+                       };
+
+                       mt6397_vio18_reg: buck_vio18 {
+                               regulator-compatible = "buck_vio18";
+                               regulator-name = "vio18";
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <2120000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <500>;
+                       };
+
+                       mt6397_vtcxo_reg: ldo_vtcxo {
+                               regulator-compatible = "ldo_vtcxo";
+                               regulator-name = "vtcxo";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <90>;
+                       };
+
+                       mt6397_va28_reg: ldo_va28 {
+                               regulator-compatible = "ldo_va28";
+                               regulator-name = "va28";
+                               /* fixed output 2.8 V */
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vcama_reg: ldo_vcama {
+                               regulator-compatible = "ldo_vcama";
+                               regulator-name = "vcama";
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vio28_reg: ldo_vio28 {
+                               regulator-compatible = "ldo_vio28";
+                               regulator-name = "vio28";
+                               /* fixed output 2.8 V */
+                               regulator-enable-ramp-delay = <240>;
+                       };
+
+                       mt6397_usb_reg: ldo_vusb {
+                               regulator-compatible = "ldo_vusb";
+                               regulator-name = "vusb";
+                               /* fixed output 3.3 V */
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vmc_reg: ldo_vmc {
+                               regulator-compatible = "ldo_vmc";
+                               regulator-name = "vmc";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vmch_reg: ldo_vmch {
+                               regulator-compatible = "ldo_vmch";
+                               regulator-name = "vmch";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vemc_3v3_reg: ldo_vemc3v3 {
+                               regulator-compatible = "ldo_vemc3v3";
+                               regulator-name = "vemc_3v3";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vgp1_reg: ldo_vgp1 {
+                               regulator-compatible = "ldo_vgp1";
+                               regulator-name = "vcamd";
+                               regulator-min-microvolt = <1220000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <240>;
+                       };
+
+                       mt6397_vgp2_reg: ldo_vgp2 {
+                               egulator-compatible = "ldo_vgp2";
+                               regulator-name = "vcamio";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vgp3_reg: ldo_vgp3 {
+                               regulator-compatible = "ldo_vgp3";
+                               regulator-name = "vcamaf";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vgp4_reg: ldo_vgp4 {
+                               regulator-compatible = "ldo_vgp4";
+                               regulator-name = "vgp4";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vgp5_reg: ldo_vgp5 {
+                               regulator-compatible = "ldo_vgp5";
+                               regulator-name = "vgp5";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vgp6_reg: ldo_vgp6 {
+                               regulator-compatible = "ldo_vgp6";
+                               regulator-name = "vgp6";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+
+                       mt6397_vibr_reg: ldo_vibr {
+                               regulator-compatible = "ldo_vibr";
+                               regulator-name = "vibr";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <218>;
+                       };
+               };
+       };
index 34ef5d16d0f1697c51b6759b8a572f33d6b85894..9b40db88f637bd9ed7f06c5eb809e7b16ddd660d 100644 (file)
@@ -1,7 +1,7 @@
 PFUZE100 family of regulators
 
 Required properties:
-- compatible: "fsl,pfuze100" or "fsl,pfuze200"
+- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000"
 - reg: I2C slave address
 
 Required child node:
@@ -14,6 +14,8 @@ Required child node:
   sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
   --PFUZE200
   sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6
+  --PFUZE3000
+  sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4
 
 Each regulator is defined using the standard binding for regulators.
 
@@ -205,3 +207,93 @@ Example 2: PFUZE200
                        };
                };
        };
+
+Example 3: PFUZE3000
+
+       pmic: pfuze3000@08 {
+               compatible = "fsl,pfuze3000";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1a {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1475000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+                       /* use sw1c_reg to align with pfuze100/pfuze200 */
+                       sw1c_reg: sw1b {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1475000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <2500000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1650000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vldo1 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen2_reg: vldo2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen3_reg: vccsd {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen4_reg: v33 {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vgen5_reg: vldo3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vldo4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+               };
+       };
index c3a60b57a865eae77b232ff6d94a2700df3fa5d7..a6f116aa523532b56194407438419c5bd5d238d9 100644 (file)
@@ -414,6 +414,14 @@ config REGULATOR_MAX77802
          Exynos5420/Exynos5800 SoCs to control various voltages.
          It includes support for control of voltage and ramp speed.
 
+config REGULATOR_MAX77843
+       tristate "Maxim 77843 regulator"
+       depends on MFD_MAX77843
+       help
+         This driver controls a Maxim 77843 regulator.
+         The regulator include two 'SAFEOUT' for USB(Universal Serial Bus)
+         This is suitable for Exynos5433 SoC chips.
+
 config REGULATOR_MC13XXX_CORE
        tristate
 
@@ -433,6 +441,15 @@ config REGULATOR_MC13892
          Say y here to support the regulators found on the Freescale MC13892
          PMIC.
 
+config REGULATOR_MT6397
+       tristate "MediaTek MT6397 PMIC"
+       depends on MFD_MT6397
+       help
+         Say y here to select this option to enable the power regulator of
+         MediaTek MT6397 PMIC.
+         This driver supports the control of different power rails of device
+         through regulator interface.
+
 config REGULATOR_PALMAS
        tristate "TI Palmas PMIC Regulators"
        depends on MFD_PALMAS
index 1f28ebfc6f3a09b3b555a23a2633a6402d1c141b..2c4da15e1545a71076616fbd94f3648ad453473a 100644 (file)
@@ -55,9 +55,11 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
 obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
+obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
index f23d7e1f2ee7c3602cd23bd8d30f305e5bf0d886..e4331f5e5d7d065e25fa835201359696c01bb2e9 100644 (file)
 
 #define AXP20X_FREQ_DCDC_MASK          0x0f
 
-#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,   \
-                      _emask, _enable_val, _disable_val)                       \
+#define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \
+                      _ereg, _emask, _enable_val, _disable_val)                \
        [AXP20X_##_id] = {                                                      \
                .name           = #_id,                                         \
                .supply_name    = (_supply),                                    \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
                .type           = REGULATOR_VOLTAGE,                            \
                .id             = AXP20X_##_id,                                 \
                .n_voltages     = (((_max) - (_min)) / (_step) + 1),            \
                .ops            = &axp20x_ops,                                  \
        }
 
-#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,     \
-                   _emask)                                                     \
+#define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask,    \
+                   _ereg, _emask)                                              \
        [AXP20X_##_id] = {                                                      \
                .name           = #_id,                                         \
                .supply_name    = (_supply),                                    \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
                .type           = REGULATOR_VOLTAGE,                            \
                .id             = AXP20X_##_id,                                 \
                .n_voltages     = (((_max) - (_min)) / (_step) + 1),            \
                .ops            = &axp20x_ops,                                  \
        }
 
-#define AXP20X_DESC_FIXED(_id, _supply, _volt)                                 \
+#define AXP20X_DESC_FIXED(_id, _match, _supply, _volt)                         \
        [AXP20X_##_id] = {                                                      \
                .name           = #_id,                                         \
                .supply_name    = (_supply),                                    \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
                .type           = REGULATOR_VOLTAGE,                            \
                .id             = AXP20X_##_id,                                 \
                .n_voltages     = 1,                                            \
                .ops            = &axp20x_ops_fixed                             \
        }
 
-#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask)  \
+#define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg,  \
+                         _emask)                                               \
        [AXP20X_##_id] = {                                                      \
                .name           = #_id,                                         \
                .supply_name    = (_supply),                                    \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
                .type           = REGULATOR_VOLTAGE,                            \
                .id             = AXP20X_##_id,                                 \
                .n_voltages     = ARRAY_SIZE(_table),                           \
@@ -127,36 +136,20 @@ static struct regulator_ops axp20x_ops = {
 };
 
 static const struct regulator_desc axp20x_regulators[] = {
-       AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
-                   AXP20X_PWR_OUT_CTRL, 0x10),
-       AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
-                   AXP20X_PWR_OUT_CTRL, 0x02),
-       AXP20X_DESC_FIXED(LDO1, "acin", 1300),
-       AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
-                   AXP20X_PWR_OUT_CTRL, 0x04),
-       AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
-                   AXP20X_PWR_OUT_CTRL, 0x40),
-       AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
-                         AXP20X_PWR_OUT_CTRL, 0x08),
-       AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
-                      AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED,
-                      AXP20X_IO_DISABLED),
-};
-
-#define AXP_MATCH(_name, _id) \
-       [AXP20X_##_id] = { \
-               .name           = #_name, \
-               .driver_data    = (void *) &axp20x_regulators[AXP20X_##_id], \
-       }
-
-static struct of_regulator_match axp20x_matches[] = {
-       AXP_MATCH(dcdc2, DCDC2),
-       AXP_MATCH(dcdc3, DCDC3),
-       AXP_MATCH(ldo1, LDO1),
-       AXP_MATCH(ldo2, LDO2),
-       AXP_MATCH(ldo3, LDO3),
-       AXP_MATCH(ldo4, LDO4),
-       AXP_MATCH(ldo5, LDO5),
+       AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT,
+                   0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
+       AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT,
+                   0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
+       AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300),
+       AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
+                   AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
+       AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT,
+                   0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
+       AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
+                         AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
+       AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
+                      AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
+                      AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
 };
 
 static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
@@ -193,13 +186,6 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
        if (!regulators) {
                dev_warn(&pdev->dev, "regulators node not found\n");
        } else {
-               ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
-                                        ARRAY_SIZE(axp20x_matches));
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
-                       return ret;
-               }
-
                dcdcfreq = 1500;
                of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
                ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
@@ -233,23 +219,17 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
 {
        struct regulator_dev *rdev;
        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
-       struct regulator_config config = { };
-       struct regulator_init_data *init_data;
+       struct regulator_config config = {
+               .dev = pdev->dev.parent,
+               .regmap = axp20x->regmap,
+       };
        int ret, i;
        u32 workmode;
 
-       ret = axp20x_regulator_parse_dt(pdev);
-       if (ret)
-               return ret;
+       /* This only sets the dcdc freq. Ignore any errors */
+       axp20x_regulator_parse_dt(pdev);
 
        for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
-               init_data = axp20x_matches[i].init_data;
-
-               config.dev = pdev->dev.parent;
-               config.init_data = init_data;
-               config.regmap = axp20x->regmap;
-               config.of_node = axp20x_matches[i].of_node;
-
                rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
                                               &config);
                if (IS_ERR(rdev)) {
@@ -259,7 +239,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
                        return PTR_ERR(rdev);
                }
 
-               ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode",
+               ret = of_property_read_u32(rdev->dev.of_node,
+                                          "x-powers,dcdc-workmode",
                                           &workmode);
                if (!ret) {
                        if (axp20x_set_dcdc_workmode(rdev, i, workmode))
index 9c48fb32f6601bf4065db65cd2a099bc57f3812d..b899947d839d87b03608d1f9bf4b4208cf57aa01 100644 (file)
@@ -632,49 +632,34 @@ static ssize_t regulator_bypass_show(struct device *dev,
 static DEVICE_ATTR(bypass, 0444,
                   regulator_bypass_show, NULL);
 
-/*
- * These are the only attributes are present for all regulators.
- * Other attributes are a function of regulator functionality.
- */
-static struct attribute *regulator_dev_attrs[] = {
-       &dev_attr_name.attr,
-       &dev_attr_num_users.attr,
-       &dev_attr_type.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(regulator_dev);
-
-static void regulator_dev_release(struct device *dev)
-{
-       struct regulator_dev *rdev = dev_get_drvdata(dev);
-       kfree(rdev);
-}
-
-static struct class regulator_class = {
-       .name = "regulator",
-       .dev_release = regulator_dev_release,
-       .dev_groups = regulator_dev_groups,
-};
-
 /* Calculate the new optimum regulator operating mode based on the new total
  * consumer load. All locks held by caller */
-static void drms_uA_update(struct regulator_dev *rdev)
+static int drms_uA_update(struct regulator_dev *rdev)
 {
        struct regulator *sibling;
        int current_uA = 0, output_uV, input_uV, err;
        unsigned int mode;
 
+       /*
+        * first check to see if we can set modes at all, otherwise just
+        * tell the consumer everything is OK.
+        */
        err = regulator_check_drms(rdev);
-       if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
-           (!rdev->desc->ops->get_voltage &&
-            !rdev->desc->ops->get_voltage_sel) ||
-           !rdev->desc->ops->set_mode)
-               return;
+       if (err < 0)
+               return 0;
+
+       if (!rdev->desc->ops->get_optimum_mode)
+               return 0;
+
+       if (!rdev->desc->ops->set_mode)
+               return -EINVAL;
 
        /* get output voltage */
        output_uV = _regulator_get_voltage(rdev);
-       if (output_uV <= 0)
-               return;
+       if (output_uV <= 0) {
+               rdev_err(rdev, "invalid output voltage found\n");
+               return -EINVAL;
+       }
 
        /* get input voltage */
        input_uV = 0;
@@ -682,8 +667,10 @@ static void drms_uA_update(struct regulator_dev *rdev)
                input_uV = regulator_get_voltage(rdev->supply);
        if (input_uV <= 0)
                input_uV = rdev->constraints->input_uV;
-       if (input_uV <= 0)
-               return;
+       if (input_uV <= 0) {
+               rdev_err(rdev, "invalid input voltage found\n");
+               return -EINVAL;
+       }
 
        /* calc total requested load */
        list_for_each_entry(sibling, &rdev->consumer_list, list)
@@ -695,8 +682,17 @@ static void drms_uA_update(struct regulator_dev *rdev)
 
        /* check the new mode is allowed */
        err = regulator_mode_constrain(rdev, &mode);
-       if (err == 0)
-               rdev->desc->ops->set_mode(rdev, mode);
+       if (err < 0) {
+               rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
+                        current_uA, input_uV, output_uV);
+               return err;
+       }
+
+       err = rdev->desc->ops->set_mode(rdev, mode);
+       if (err < 0)
+               rdev_err(rdev, "failed to set optimum mode %x\n", mode);
+
+       return err;
 }
 
 static int suspend_set_state(struct regulator_dev *rdev,
@@ -3026,75 +3022,13 @@ EXPORT_SYMBOL_GPL(regulator_get_mode);
 int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       struct regulator *consumer;
-       int ret, output_uV, input_uV = 0, total_uA_load = 0;
-       unsigned int mode;
-
-       if (rdev->supply)
-               input_uV = regulator_get_voltage(rdev->supply);
+       int ret;
 
        mutex_lock(&rdev->mutex);
-
-       /*
-        * first check to see if we can set modes at all, otherwise just
-        * tell the consumer everything is OK.
-        */
        regulator->uA_load = uA_load;
-       ret = regulator_check_drms(rdev);
-       if (ret < 0) {
-               ret = 0;
-               goto out;
-       }
-
-       if (!rdev->desc->ops->get_optimum_mode)
-               goto out;
-
-       /*
-        * we can actually do this so any errors are indicators of
-        * potential real failure.
-        */
-       ret = -EINVAL;
-
-       if (!rdev->desc->ops->set_mode)
-               goto out;
-
-       /* get output voltage */
-       output_uV = _regulator_get_voltage(rdev);
-       if (output_uV <= 0) {
-               rdev_err(rdev, "invalid output voltage found\n");
-               goto out;
-       }
-
-       /* No supply? Use constraint voltage */
-       if (input_uV <= 0)
-               input_uV = rdev->constraints->input_uV;
-       if (input_uV <= 0) {
-               rdev_err(rdev, "invalid input voltage found\n");
-               goto out;
-       }
-
-       /* calc total requested load for this regulator */
-       list_for_each_entry(consumer, &rdev->consumer_list, list)
-               total_uA_load += consumer->uA_load;
-
-       mode = rdev->desc->ops->get_optimum_mode(rdev,
-                                                input_uV, output_uV,
-                                                total_uA_load);
-       ret = regulator_mode_constrain(rdev, &mode);
-       if (ret < 0) {
-               rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
-                        total_uA_load, input_uV, output_uV);
-               goto out;
-       }
-
-       ret = rdev->desc->ops->set_mode(rdev, mode);
-       if (ret < 0) {
-               rdev_err(rdev, "failed to set optimum mode %x\n", mode);
-               goto out;
-       }
-       ret = mode;
-out:
+       ret = drms_uA_update(rdev);
        mutex_unlock(&rdev->mutex);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
@@ -3436,126 +3370,136 @@ int regulator_mode_to_status(unsigned int mode)
 }
 EXPORT_SYMBOL_GPL(regulator_mode_to_status);
 
+static struct attribute *regulator_dev_attrs[] = {
+       &dev_attr_name.attr,
+       &dev_attr_num_users.attr,
+       &dev_attr_type.attr,
+       &dev_attr_microvolts.attr,
+       &dev_attr_microamps.attr,
+       &dev_attr_opmode.attr,
+       &dev_attr_state.attr,
+       &dev_attr_status.attr,
+       &dev_attr_bypass.attr,
+       &dev_attr_requested_microamps.attr,
+       &dev_attr_min_microvolts.attr,
+       &dev_attr_max_microvolts.attr,
+       &dev_attr_min_microamps.attr,
+       &dev_attr_max_microamps.attr,
+       &dev_attr_suspend_standby_state.attr,
+       &dev_attr_suspend_mem_state.attr,
+       &dev_attr_suspend_disk_state.attr,
+       &dev_attr_suspend_standby_microvolts.attr,
+       &dev_attr_suspend_mem_microvolts.attr,
+       &dev_attr_suspend_disk_microvolts.attr,
+       &dev_attr_suspend_standby_mode.attr,
+       &dev_attr_suspend_mem_mode.attr,
+       &dev_attr_suspend_disk_mode.attr,
+       NULL
+};
+
 /*
  * To avoid cluttering sysfs (and memory) with useless state, only
  * create attributes that can be meaningfully displayed.
  */
-static int add_regulator_attributes(struct regulator_dev *rdev)
+static umode_t regulator_attr_is_visible(struct kobject *kobj,
+                                        struct attribute *attr, int idx)
 {
-       struct device *dev = &rdev->dev;
+       struct device *dev = kobj_to_dev(kobj);
+       struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev);
        const struct regulator_ops *ops = rdev->desc->ops;
-       int status = 0;
+       umode_t mode = attr->mode;
+
+       /* these three are always present */
+       if (attr == &dev_attr_name.attr ||
+           attr == &dev_attr_num_users.attr ||
+           attr == &dev_attr_type.attr)
+               return mode;
 
        /* some attributes need specific methods to be displayed */
-       if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
-           (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
-           (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) ||
-               (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) {
-               status = device_create_file(dev, &dev_attr_microvolts);
-               if (status < 0)
-                       return status;
-       }
-       if (ops->get_current_limit) {
-               status = device_create_file(dev, &dev_attr_microamps);
-               if (status < 0)
-                       return status;
-       }
-       if (ops->get_mode) {
-               status = device_create_file(dev, &dev_attr_opmode);
-               if (status < 0)
-                       return status;
-       }
-       if (rdev->ena_pin || ops->is_enabled) {
-               status = device_create_file(dev, &dev_attr_state);
-               if (status < 0)
-                       return status;
-       }
-       if (ops->get_status) {
-               status = device_create_file(dev, &dev_attr_status);
-               if (status < 0)
-                       return status;
-       }
-       if (ops->get_bypass) {
-               status = device_create_file(dev, &dev_attr_bypass);
-               if (status < 0)
-                       return status;
+       if (attr == &dev_attr_microvolts.attr) {
+               if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
+                   (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
+                   (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) ||
+                   (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1))
+                       return mode;
+               return 0;
        }
 
+       if (attr == &dev_attr_microamps.attr)
+               return ops->get_current_limit ? mode : 0;
+
+       if (attr == &dev_attr_opmode.attr)
+               return ops->get_mode ? mode : 0;
+
+       if (attr == &dev_attr_state.attr)
+               return (rdev->ena_pin || ops->is_enabled) ? mode : 0;
+
+       if (attr == &dev_attr_status.attr)
+               return ops->get_status ? mode : 0;
+
+       if (attr == &dev_attr_bypass.attr)
+               return ops->get_bypass ? mode : 0;
+
        /* some attributes are type-specific */
-       if (rdev->desc->type == REGULATOR_CURRENT) {
-               status = device_create_file(dev, &dev_attr_requested_microamps);
-               if (status < 0)
-                       return status;
-       }
+       if (attr == &dev_attr_requested_microamps.attr)
+               return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
 
        /* all the other attributes exist to support constraints;
         * don't show them if there are no constraints, or if the
         * relevant supporting methods are missing.
         */
        if (!rdev->constraints)
-               return status;
+               return 0;
 
        /* constraints need specific supporting methods */
-       if (ops->set_voltage || ops->set_voltage_sel) {
-               status = device_create_file(dev, &dev_attr_min_microvolts);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev, &dev_attr_max_microvolts);
-               if (status < 0)
-                       return status;
-       }
-       if (ops->set_current_limit) {
-               status = device_create_file(dev, &dev_attr_min_microamps);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev, &dev_attr_max_microamps);
-               if (status < 0)
-                       return status;
-       }
-
-       status = device_create_file(dev, &dev_attr_suspend_standby_state);
-       if (status < 0)
-               return status;
-       status = device_create_file(dev, &dev_attr_suspend_mem_state);
-       if (status < 0)
-               return status;
-       status = device_create_file(dev, &dev_attr_suspend_disk_state);
-       if (status < 0)
-               return status;
+       if (attr == &dev_attr_min_microvolts.attr ||
+           attr == &dev_attr_max_microvolts.attr)
+               return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0;
+
+       if (attr == &dev_attr_min_microamps.attr ||
+           attr == &dev_attr_max_microamps.attr)
+               return ops->set_current_limit ? mode : 0;
 
-       if (ops->set_suspend_voltage) {
-               status = device_create_file(dev,
-                               &dev_attr_suspend_standby_microvolts);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev,
-                               &dev_attr_suspend_mem_microvolts);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev,
-                               &dev_attr_suspend_disk_microvolts);
-               if (status < 0)
-                       return status;
-       }
-
-       if (ops->set_suspend_mode) {
-               status = device_create_file(dev,
-                               &dev_attr_suspend_standby_mode);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev,
-                               &dev_attr_suspend_mem_mode);
-               if (status < 0)
-                       return status;
-               status = device_create_file(dev,
-                               &dev_attr_suspend_disk_mode);
-               if (status < 0)
-                       return status;
-       }
-
-       return status;
+       if (attr == &dev_attr_suspend_standby_state.attr ||
+           attr == &dev_attr_suspend_mem_state.attr ||
+           attr == &dev_attr_suspend_disk_state.attr)
+               return mode;
+
+       if (attr == &dev_attr_suspend_standby_microvolts.attr ||
+           attr == &dev_attr_suspend_mem_microvolts.attr ||
+           attr == &dev_attr_suspend_disk_microvolts.attr)
+               return ops->set_suspend_voltage ? mode : 0;
+
+       if (attr == &dev_attr_suspend_standby_mode.attr ||
+           attr == &dev_attr_suspend_mem_mode.attr ||
+           attr == &dev_attr_suspend_disk_mode.attr)
+               return ops->set_suspend_mode ? mode : 0;
+
+       return mode;
 }
 
+static const struct attribute_group regulator_dev_group = {
+       .attrs = regulator_dev_attrs,
+       .is_visible = regulator_attr_is_visible,
+};
+
+static const struct attribute_group *regulator_dev_groups[] = {
+       &regulator_dev_group,
+       NULL
+};
+
+static void regulator_dev_release(struct device *dev)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       kfree(rdev);
+}
+
+static struct class regulator_class = {
+       .name = "regulator",
+       .dev_release = regulator_dev_release,
+       .dev_groups = regulator_dev_groups,
+};
+
 static void rdev_init_debugfs(struct regulator_dev *rdev)
 {
        rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
@@ -3575,7 +3519,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
 /**
  * regulator_register - register regulator
  * @regulator_desc: regulator to register
- * @config: runtime configuration for regulator
+ * @cfg: runtime configuration for regulator
  *
  * Called by regulator drivers to register a regulator.
  * Returns a valid pointer to struct regulator_dev on success
@@ -3583,20 +3527,21 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
  */
 struct regulator_dev *
 regulator_register(const struct regulator_desc *regulator_desc,
-                  const struct regulator_config *config)
+                  const struct regulator_config *cfg)
 {
        const struct regulation_constraints *constraints = NULL;
        const struct regulator_init_data *init_data;
-       static atomic_t regulator_no = ATOMIC_INIT(0);
+       struct regulator_config *config = NULL;
+       static atomic_t regulator_no = ATOMIC_INIT(-1);
        struct regulator_dev *rdev;
        struct device *dev;
        int ret, i;
        const char *supply = NULL;
 
-       if (regulator_desc == NULL || config == NULL)
+       if (regulator_desc == NULL || cfg == NULL)
                return ERR_PTR(-EINVAL);
 
-       dev = config->dev;
+       dev = cfg->dev;
        WARN_ON(!dev);
 
        if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
@@ -3626,7 +3571,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
        if (rdev == NULL)
                return ERR_PTR(-ENOMEM);
 
-       init_data = regulator_of_get_init_data(dev, regulator_desc,
+       /*
+        * Duplicate the config so the driver could override it after
+        * parsing init data.
+        */
+       config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
+       if (config == NULL) {
+               kfree(rdev);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       init_data = regulator_of_get_init_data(dev, regulator_desc, config,
                                               &rdev->dev.of_node);
        if (!init_data) {
                init_data = config->init_data;
@@ -3660,8 +3615,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
        /* register with sysfs */
        rdev->dev.class = &regulator_class;
        rdev->dev.parent = dev;
-       dev_set_name(&rdev->dev, "regulator.%d",
-                    atomic_inc_return(&regulator_no) - 1);
+       dev_set_name(&rdev->dev, "regulator.%lu",
+                   (unsigned long) atomic_inc_return(&regulator_no));
        ret = device_register(&rdev->dev);
        if (ret != 0) {
                put_device(&rdev->dev);
@@ -3694,11 +3649,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
        if (ret < 0)
                goto scrub;
 
-       /* add attributes supported by this regulator */
-       ret = add_regulator_attributes(rdev);
-       if (ret < 0)
-               goto scrub;
-
        if (init_data && init_data->supply_regulator)
                supply = init_data->supply_regulator;
        else if (regulator_desc->supply_name)
@@ -3754,6 +3704,7 @@ add_dev:
        rdev_init_debugfs(rdev);
 out:
        mutex_unlock(&regulator_list_mutex);
+       kfree(config);
        return rdev;
 
 unset_supplies:
index c78d2106d6cb66aa6b5ca1b8df25c244c73a3686..01343419555ee3363d7bc0d3c10df731fbd74587 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/of_gpio.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/da9211.h>
 #include "da9211-regulator.h"
@@ -276,7 +277,10 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
                        continue;
 
                pdata->init_data[n] = da9211_matches[i].init_data;
-
+               pdata->reg_node[n] = da9211_matches[i].of_node;
+               pdata->gpio_ren[n] =
+                       of_get_named_gpio(da9211_matches[i].of_node,
+                               "enable-gpios", 0);
                n++;
        }
 
@@ -364,7 +368,15 @@ static int da9211_regulator_init(struct da9211 *chip)
                config.dev = chip->dev;
                config.driver_data = chip;
                config.regmap = chip->regmap;
-               config.of_node = chip->dev->of_node;
+               config.of_node = chip->pdata->reg_node[i];
+
+               if (gpio_is_valid(chip->pdata->gpio_ren[i])) {
+                       config.ena_gpio = chip->pdata->gpio_ren[i];
+                       config.ena_gpio_initialized = true;
+               } else {
+                       config.ena_gpio = -EINVAL;
+                       config.ena_gpio_initialized = false;
+               }
 
                chip->rdev[i] = devm_regulator_register(chip->dev,
                        &da9211_regulators[i], &config);
index 6c43ab2d51211653eb1dd2374ff7844f6ff1c634..3c25db89a021af927f183b9f363b270b76e691c4 100644 (file)
@@ -147,7 +147,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
                return REGULATOR_MODE_NORMAL;
 }
 
-static int slew_rates[] = {
+static const int slew_rates[] = {
        64000,
        32000,
        16000,
@@ -296,7 +296,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
        return PTR_ERR_OR_ZERO(di->rdev);
 }
 
-static struct regmap_config fan53555_regmap_config = {
+static const struct regmap_config fan53555_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 };
index 80ba2a35a04bb3e6c7164380fe44d3220c54dafd..c74ac873402370b5057464b22a694672cccf4d73 100644 (file)
@@ -38,11 +38,13 @@ struct regulator {
 #ifdef CONFIG_OF
 struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
                                 const struct regulator_desc *desc,
+                                struct regulator_config *config,
                                 struct device_node **node);
 #else
 static inline struct regulator_init_data *
 regulator_of_get_init_data(struct device *dev,
                           const struct regulator_desc *desc,
+                          struct regulator_config *config,
                           struct device_node **node)
 {
        return NULL;
index 92fefd98da58e146755210cad01fa8639d1f5c02..6e3a15fe00f1ce37d51d47d0c66ee26c39a8b367 100644 (file)
@@ -177,8 +177,10 @@ static int isl9305_i2c_probe(struct i2c_client *i2c,
 
 #ifdef CONFIG_OF
 static const struct of_device_id isl9305_dt_ids[] = {
-       { .compatible = "isl,isl9305" },
-       { .compatible = "isl,isl9305h" },
+       { .compatible = "isl,isl9305" }, /* for backward compat., don't use */
+       { .compatible = "isil,isl9305" },
+       { .compatible = "isl,isl9305h" }, /* for backward compat., don't use */
+       { .compatible = "isil,isl9305h" },
        {},
 };
 #endif
index 021d64d856bb68d72745e83a8258d3c228412943..3de328ab41f3c69dde58349d6aa4fb0d18736617 100644 (file)
@@ -106,7 +106,6 @@ struct lp872x {
        struct device *dev;
        enum lp872x_id chipid;
        struct lp872x_platform_data *pdata;
-       struct regulator_dev **regulators;
        int num_regulators;
        enum lp872x_dvs_state dvs_pin;
        int dvs_gpio;
@@ -801,8 +800,6 @@ static int lp872x_regulator_register(struct lp872x *lp)
                        dev_err(lp->dev, "regulator register err");
                        return PTR_ERR(rdev);
                }
-
-               *(lp->regulators + i) = rdev;
        }
 
        return 0;
@@ -906,7 +903,7 @@ static struct lp872x_platform_data
 static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct lp872x *lp;
-       int ret, size, num_regulators;
+       int ret;
        const int lp872x_num_regulators[] = {
                [LP8720] = LP8720_NUM_REGULATORS,
                [LP8725] = LP8725_NUM_REGULATORS,
@@ -918,38 +915,27 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 
        lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
        if (!lp)
-               goto err_mem;
-
-       num_regulators = lp872x_num_regulators[id->driver_data];
-       size = sizeof(struct regulator_dev *) * num_regulators;
+               return -ENOMEM;
 
-       lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL);
-       if (!lp->regulators)
-               goto err_mem;
+       lp->num_regulators = lp872x_num_regulators[id->driver_data];
 
        lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config);
        if (IS_ERR(lp->regmap)) {
                ret = PTR_ERR(lp->regmap);
                dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
-               goto err_dev;
+               return ret;
        }
 
        lp->dev = &cl->dev;
        lp->pdata = dev_get_platdata(&cl->dev);
        lp->chipid = id->driver_data;
-       lp->num_regulators = num_regulators;
        i2c_set_clientdata(cl, lp);
 
        ret = lp872x_config(lp);
        if (ret)
-               goto err_dev;
+               return ret;
 
        return lp872x_regulator_register(lp);
-
-err_mem:
-       return -ENOMEM;
-err_dev:
-       return ret;
 }
 
 static const struct of_device_id lp872x_dt_ids[] = {
index bf9a44c5fdd299872a1015b50b097aa8dc0e9fc6..b3678d289619330ffca48f338b9ddf362cd76986 100644 (file)
@@ -103,6 +103,8 @@ static struct regulator_ops max14577_charger_ops = {
 static const struct regulator_desc max14577_supported_regulators[] = {
        [MAX14577_SAFEOUT] = {
                .name           = "SAFEOUT",
+               .of_match       = of_match_ptr("SAFEOUT"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX14577_SAFEOUT,
                .ops            = &max14577_safeout_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -114,6 +116,8 @@ static const struct regulator_desc max14577_supported_regulators[] = {
        },
        [MAX14577_CHARGER] = {
                .name           = "CHARGER",
+               .of_match       = of_match_ptr("CHARGER"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX14577_CHARGER,
                .ops            = &max14577_charger_ops,
                .type           = REGULATOR_CURRENT,
@@ -137,6 +141,8 @@ static struct regulator_ops max77836_ldo_ops = {
 static const struct regulator_desc max77836_supported_regulators[] = {
        [MAX14577_SAFEOUT] = {
                .name           = "SAFEOUT",
+               .of_match       = of_match_ptr("SAFEOUT"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX14577_SAFEOUT,
                .ops            = &max14577_safeout_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -148,6 +154,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
        },
        [MAX14577_CHARGER] = {
                .name           = "CHARGER",
+               .of_match       = of_match_ptr("CHARGER"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX14577_CHARGER,
                .ops            = &max14577_charger_ops,
                .type           = REGULATOR_CURRENT,
@@ -157,6 +165,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
        },
        [MAX77836_LDO1] = {
                .name           = "LDO1",
+               .of_match       = of_match_ptr("LDO1"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX77836_LDO1,
                .ops            = &max77836_ldo_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -171,6 +181,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
        },
        [MAX77836_LDO2] = {
                .name           = "LDO2",
+               .of_match       = of_match_ptr("LDO2"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = MAX77836_LDO2,
                .ops            = &max77836_ldo_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -198,43 +210,6 @@ static struct of_regulator_match max77836_regulator_matches[] = {
        { .name = "LDO2", },
 };
 
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
-               enum maxim_device_type dev_type)
-{
-       int ret;
-       struct device_node *np;
-       struct of_regulator_match *regulator_matches;
-       unsigned int regulator_matches_size;
-
-       np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
-       if (!np) {
-               dev_err(&pdev->dev, "Failed to get child OF node for regulators\n");
-               return -EINVAL;
-       }
-
-       switch (dev_type) {
-       case MAXIM_DEVICE_TYPE_MAX77836:
-               regulator_matches = max77836_regulator_matches;
-               regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
-               break;
-       case MAXIM_DEVICE_TYPE_MAX14577:
-       default:
-               regulator_matches = max14577_regulator_matches;
-               regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
-       }
-
-       ret = of_regulator_match(&pdev->dev, np, regulator_matches,
-                       regulator_matches_size);
-       if (ret < 0)
-               dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
-       else
-               ret = 0;
-
-       of_node_put(np);
-
-       return ret;
-}
-
 static inline struct regulator_init_data *match_init_data(int index,
                enum maxim_device_type dev_type)
 {
@@ -261,11 +236,6 @@ static inline struct device_node *match_of_node(int index,
        }
 }
 #else /* CONFIG_OF */
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
-               enum maxim_device_type dev_type)
-{
-       return 0;
-}
 static inline struct regulator_init_data *match_init_data(int index,
                enum maxim_device_type dev_type)
 {
@@ -308,16 +278,12 @@ static int max14577_regulator_probe(struct platform_device *pdev)
 {
        struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
        struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
-       int i, ret;
+       int i, ret = 0;
        struct regulator_config config = {};
        const struct regulator_desc *supported_regulators;
        unsigned int supported_regulators_size;
        enum maxim_device_type dev_type = max14577->dev_type;
 
-       ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
-       if (ret)
-               return ret;
-
        switch (dev_type) {
        case MAXIM_DEVICE_TYPE_MAX77836:
                supported_regulators = max77836_supported_regulators;
@@ -329,7 +295,7 @@ static int max14577_regulator_probe(struct platform_device *pdev)
                supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
        }
 
-       config.dev = &pdev->dev;
+       config.dev = max14577->dev;
        config.driver_data = max14577;
 
        for (i = 0; i < supported_regulators_size; i++) {
index 10d206266ac27770ec25efa16e94f5eb658a891b..15fb1416bfbde99c9724644dd25bf106695fda97 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/bug.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #define MAX77686_DVS_MINUV     600000
 #define MAX77686_DVS_UVSTEP    12500
 
+/*
+ * Value for configuring buck[89] and LDO{20,21,22} as GPIO control.
+ * It is the same as 'off' for other regulators.
+ */
+#define MAX77686_GPIO_CONTROL          0x0
 /*
  * Values used for configuring LDOs and bucks.
  * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26
@@ -82,6 +88,8 @@ enum max77686_ramp_rate {
 };
 
 struct max77686_data {
+       u64 gpio_enabled:MAX77686_REGULATORS;
+
        /* Array indexed by regulator id */
        unsigned int opmode[MAX77686_REGULATORS];
 };
@@ -100,6 +108,26 @@ static unsigned int max77686_get_opmode_shift(int id)
        }
 }
 
+/*
+ * When regulator is configured for GPIO control then it
+ * replaces "normal" mode. Any change from low power mode to normal
+ * should actually change to GPIO control.
+ * Map normal mode to proper value for such regulators.
+ */
+static unsigned int max77686_map_normal_mode(struct max77686_data *max77686,
+                                            int id)
+{
+       switch (id) {
+       case MAX77686_BUCK8:
+       case MAX77686_BUCK9:
+       case MAX77686_LDO20 ... MAX77686_LDO22:
+               if (max77686->gpio_enabled & (1 << id))
+                       return MAX77686_GPIO_CONTROL;
+       }
+
+       return MAX77686_NORMAL;
+}
+
 /* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */
 static int max77686_set_suspend_disable(struct regulator_dev *rdev)
 {
@@ -136,7 +164,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
                val = MAX77686_LDO_LOWPOWER_PWRREQ;
                break;
        case REGULATOR_MODE_NORMAL:                     /* ON in Normal Mode */
-               val = MAX77686_NORMAL;
+               val = max77686_map_normal_mode(max77686, id);
                break;
        default:
                pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -160,7 +188,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
 {
        unsigned int val;
        struct max77686_data *max77686 = rdev_get_drvdata(rdev);
-       int ret;
+       int ret, id = rdev_get_id(rdev);
 
        switch (mode) {
        case REGULATOR_MODE_STANDBY:                    /* switch off */
@@ -170,7 +198,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
                val = MAX77686_LDO_LOWPOWER_PWRREQ;
                break;
        case REGULATOR_MODE_NORMAL:                     /* ON in Normal Mode */
-               val = MAX77686_NORMAL;
+               val = max77686_map_normal_mode(max77686, id);
                break;
        default:
                pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -184,7 +212,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
        if (ret)
                return ret;
 
-       max77686->opmode[rdev_get_id(rdev)] = val;
+       max77686->opmode[id] = val;
        return 0;
 }
 
@@ -197,7 +225,7 @@ static int max77686_enable(struct regulator_dev *rdev)
        shift = max77686_get_opmode_shift(id);
 
        if (max77686->opmode[id] == MAX77686_OFF_PWRREQ)
-               max77686->opmode[id] = MAX77686_NORMAL;
+               max77686->opmode[id] = max77686_map_normal_mode(max77686, id);
 
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask,
@@ -229,6 +257,36 @@ static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
                                  MAX77686_RAMP_RATE_MASK, ramp_value << 6);
 }
 
+static int max77686_of_parse_cb(struct device_node *np,
+               const struct regulator_desc *desc,
+               struct regulator_config *config)
+{
+       struct max77686_data *max77686 = config->driver_data;
+
+       switch (desc->id) {
+       case MAX77686_BUCK8:
+       case MAX77686_BUCK9:
+       case MAX77686_LDO20 ... MAX77686_LDO22:
+               config->ena_gpio = of_get_named_gpio(np,
+                                       "maxim,ena-gpios", 0);
+               config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+               config->ena_gpio_initialized = true;
+               break;
+       default:
+               return 0;
+       }
+
+       if (gpio_is_valid(config->ena_gpio)) {
+               max77686->gpio_enabled |= (1 << desc->id);
+
+               return regmap_update_bits(config->regmap, desc->enable_reg,
+                                         desc->enable_mask,
+                                         MAX77686_GPIO_CONTROL);
+       }
+
+       return 0;
+}
+
 static struct regulator_ops max77686_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
@@ -283,6 +341,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
        .name           = "LDO"#num,                                    \
        .of_match       = of_match_ptr("LDO"#num),                      \
        .regulators_node        = of_match_ptr("voltage-regulators"),   \
+       .of_parse_cb    = max77686_of_parse_cb,                         \
        .id             = MAX77686_LDO##num,                            \
        .ops            = &max77686_ops,                                \
        .type           = REGULATOR_VOLTAGE,                            \
@@ -355,6 +414,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
        .name           = "BUCK"#num,                                   \
        .of_match       = of_match_ptr("BUCK"#num),                     \
        .regulators_node        = of_match_ptr("voltage-regulators"),   \
+       .of_parse_cb    = max77686_of_parse_cb,                         \
        .id             = MAX77686_BUCK##num,                           \
        .ops            = &max77686_ops,                                \
        .type           = REGULATOR_VOLTAGE,                            \
diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c
new file mode 100644 (file)
index 0000000..c132ef5
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * max77843.c - Regulator driver for the Maxim MAX77843
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ * Author: Beomho Seo <beomho.seo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/regulator/of_regulator.h>
+
+enum max77843_regulator_type {
+       MAX77843_SAFEOUT1 = 0,
+       MAX77843_SAFEOUT2,
+       MAX77843_CHARGER,
+
+       MAX77843_NUM,
+};
+
+static const unsigned int max77843_safeout_voltage_table[] = {
+       4850000,
+       4900000,
+       4950000,
+       3300000,
+};
+
+static int max77843_reg_is_enabled(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev->regmap;
+       int ret;
+       unsigned int reg;
+
+       ret = regmap_read(regmap, rdev->desc->enable_reg, &reg);
+       if (ret) {
+               dev_err(&rdev->dev, "Fialed to read charger register\n");
+               return ret;
+       }
+
+       return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask;
+}
+
+static int max77843_reg_get_current_limit(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev->regmap;
+       unsigned int chg_min_uA = rdev->constraints->min_uA;
+       unsigned int chg_max_uA = rdev->constraints->max_uA;
+       unsigned int val;
+       int ret;
+       unsigned int reg, sel;
+
+       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg);
+       if (ret) {
+               dev_err(&rdev->dev, "Failed to read charger register\n");
+               return ret;
+       }
+
+       sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK;
+
+       if (sel < 0x03)
+               sel = 0;
+       else
+               sel -= 2;
+
+       val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel;
+       if (val > chg_max_uA)
+               return -EINVAL;
+
+       return val;
+}
+
+static int max77843_reg_set_current_limit(struct regulator_dev *rdev,
+               int min_uA, int max_uA)
+{
+       struct regmap *regmap = rdev->regmap;
+       unsigned int chg_min_uA = rdev->constraints->min_uA;
+       int sel = 0;
+
+       while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA)
+               sel++;
+
+       if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA)
+               return -EINVAL;
+
+       sel += 2;
+
+       return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel);
+}
+
+static struct regulator_ops max77843_charger_ops = {
+       .is_enabled             = max77843_reg_is_enabled,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .get_current_limit      = max77843_reg_get_current_limit,
+       .set_current_limit      = max77843_reg_set_current_limit,
+};
+
+static struct regulator_ops max77843_regulator_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .list_voltage           = regulator_list_voltage_table,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc max77843_supported_regulators[] = {
+       [MAX77843_SAFEOUT1] = {
+               .name           = "SAFEOUT1",
+               .id             = MAX77843_SAFEOUT1,
+               .ops            = &max77843_regulator_ops,
+               .of_match       = of_match_ptr("SAFEOUT1"),
+               .regulators_node = of_match_ptr("regulators"),
+               .type           = REGULATOR_VOLTAGE,
+               .owner          = THIS_MODULE,
+               .n_voltages     = ARRAY_SIZE(max77843_safeout_voltage_table),
+               .volt_table     = max77843_safeout_voltage_table,
+               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
+               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1,
+               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
+               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK,
+       },
+       [MAX77843_SAFEOUT2] = {
+               .name           = "SAFEOUT2",
+               .id             = MAX77843_SAFEOUT2,
+               .ops            = &max77843_regulator_ops,
+               .of_match       = of_match_ptr("SAFEOUT2"),
+               .regulators_node = of_match_ptr("regulators"),
+               .type           = REGULATOR_VOLTAGE,
+               .owner          = THIS_MODULE,
+               .n_voltages     = ARRAY_SIZE(max77843_safeout_voltage_table),
+               .volt_table     = max77843_safeout_voltage_table,
+               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
+               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2,
+               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
+               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK,
+       },
+       [MAX77843_CHARGER] = {
+               .name           = "CHARGER",
+               .id             = MAX77843_CHARGER,
+               .ops            = &max77843_charger_ops,
+               .of_match       = of_match_ptr("CHARGER"),
+               .regulators_node = of_match_ptr("regulators"),
+               .type           = REGULATOR_CURRENT,
+               .owner          = THIS_MODULE,
+               .enable_reg     = MAX77843_CHG_REG_CHG_CNFG_00,
+               .enable_mask    = MAX77843_CHG_MASK,
+       },
+};
+
+static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id)
+{
+       switch (reg_id) {
+       case MAX77843_SAFEOUT1:
+       case MAX77843_SAFEOUT2:
+               return max77843->regmap;
+       case MAX77843_CHARGER:
+               return max77843->regmap_chg;
+       default:
+               return max77843->regmap;
+       }
+}
+
+static int max77843_regulator_probe(struct platform_device *pdev)
+{
+       struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = {};
+       int i;
+
+       config.dev = max77843->dev;
+       config.driver_data = max77843;
+
+       for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) {
+               struct regulator_dev *regulator;
+
+               config.regmap = max77843_get_regmap(max77843,
+                               max77843_supported_regulators[i].id);
+
+               regulator = devm_regulator_register(&pdev->dev,
+                               &max77843_supported_regulators[i], &config);
+               if (IS_ERR(regulator)) {
+                       dev_err(&pdev->dev,
+                                       "Failed to regiser regulator-%d\n", i);
+                       return PTR_ERR(regulator);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id max77843_regulator_id[] = {
+       { "max77843-regulator", },
+       { /* sentinel */ },
+};
+
+static struct platform_driver max77843_regulator_driver = {
+       .driver = {
+               .name = "max77843-regulator",
+       },
+       .probe          = max77843_regulator_probe,
+       .id_table       = max77843_regulator_id,
+};
+
+static int __init max77843_regulator_init(void)
+{
+       return platform_driver_register(&max77843_regulator_driver);
+}
+subsys_initcall(max77843_regulator_init);
+
+static void __exit max77843_regulator_exit(void)
+{
+       platform_driver_unregister(&max77843_regulator_driver);
+}
+module_exit(max77843_regulator_exit);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX77843 regulator driver");
+MODULE_LICENSE("GPL");
index c8bddcc8f911d11d90e32d18e0d191234bae1656..81229579ece9105846b4187d4e3ccacbfbf9a89c 100644 (file)
@@ -115,7 +115,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev)
        return REGULATOR_MODE_NORMAL;
 }
 
-static struct regulator_ops max8649_dcdc_ops = {
+static const struct regulator_ops max8649_dcdc_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .list_voltage   = regulator_list_voltage_linear,
@@ -143,7 +143,7 @@ static struct regulator_desc dcdc_desc = {
        .enable_is_inverted = true,
 };
 
-static struct regmap_config max8649_regmap_config = {
+static const struct regmap_config max8649_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 };
diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c
new file mode 100644 (file)
index 0000000..a5b2f47
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu <flora.fu@mediatek.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 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/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6397/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6397-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+/*
+ * MT6397 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6397_regulator_info {
+       struct regulator_desc desc;
+       u32 qi;
+       u32 vselon_reg;
+       u32 vselctrl_reg;
+       u32 vselctrl_mask;
+};
+
+#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg,   \
+               vosel, vosel_mask, voselon, vosel_ctrl)                 \
+[MT6397_ID_##vreg] = {                                                 \
+       .desc = {                                                       \
+               .name = #vreg,                                          \
+               .of_match = of_match_ptr(match),                        \
+               .ops = &mt6397_volt_range_ops,                          \
+               .type = REGULATOR_VOLTAGE,                              \
+               .id = MT6397_ID_##vreg,                                 \
+               .owner = THIS_MODULE,                                   \
+               .n_voltages = (max - min)/step + 1,                     \
+               .linear_ranges = volt_ranges,                           \
+               .n_linear_ranges = ARRAY_SIZE(volt_ranges),             \
+               .vsel_reg = vosel,                                      \
+               .vsel_mask = vosel_mask,                                \
+               .enable_reg = enreg,                                    \
+               .enable_mask = BIT(0),                                  \
+       },                                                              \
+       .qi = BIT(13),                                                  \
+       .vselon_reg = voselon,                                          \
+       .vselctrl_reg = vosel_ctrl,                                     \
+       .vselctrl_mask = BIT(1),                                        \
+}
+
+#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,   \
+               vosel_mask)                                             \
+[MT6397_ID_##vreg] = {                                                 \
+       .desc = {                                                       \
+               .name = #vreg,                                          \
+               .of_match = of_match_ptr(match),                        \
+               .ops = &mt6397_volt_table_ops,                          \
+               .type = REGULATOR_VOLTAGE,                              \
+               .id = MT6397_ID_##vreg,                                 \
+               .owner = THIS_MODULE,                                   \
+               .n_voltages = ARRAY_SIZE(ldo_volt_table),               \
+               .volt_table = ldo_volt_table,                           \
+               .vsel_reg = vosel,                                      \
+               .vsel_mask = vosel_mask,                                \
+               .enable_reg = enreg,                                    \
+               .enable_mask = BIT(enbit),                              \
+       },                                                              \
+       .qi = BIT(15),                                                  \
+}
+
+#define MT6397_REG_FIXED(match, vreg, enreg, enbit, volt)              \
+[MT6397_ID_##vreg] = {                                                 \
+       .desc = {                                                       \
+               .name = #vreg,                                          \
+               .of_match = of_match_ptr(match),                        \
+               .ops = &mt6397_volt_fixed_ops,                          \
+               .type = REGULATOR_VOLTAGE,                              \
+               .id = MT6397_ID_##vreg,                                 \
+               .owner = THIS_MODULE,                                   \
+               .n_voltages = 1,                                        \
+               .enable_reg = enreg,                                    \
+               .enable_mask = BIT(enbit),                              \
+               .min_uV = volt,                                         \
+       },                                                              \
+       .qi = BIT(15),                                                  \
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+       REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+       REGULATOR_LINEAR_RANGE(800000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+       REGULATOR_LINEAR_RANGE(1500000, 0, 0x1f, 20000),
+};
+
+static const u32 ldo_volt_table1[] = {
+       1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table2[] = {
+       1800000, 3300000,
+};
+
+static const u32 ldo_volt_table3[] = {
+       3000000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+       1220000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+       1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5_v2[] = {
+       1200000, 1000000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+       1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+       1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static int mt6397_get_status(struct regulator_dev *rdev)
+{
+       int ret;
+       u32 regval;
+       struct mt6397_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+               return ret;
+       }
+
+       return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static struct regulator_ops mt6397_volt_range_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6397_get_status,
+};
+
+static struct regulator_ops mt6397_volt_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6397_get_status,
+};
+
+static struct regulator_ops mt6397_volt_fixed_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6397_get_status,
+};
+
+/* The array is indexed by id(MT6397_ID_XXX) */
+static struct mt6397_regulator_info mt6397_regulators[] = {
+       MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250,
+               buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f,
+               MT6397_VCA15_CON10, MT6397_VCA15_CON5),
+       MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250,
+               buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f,
+               MT6397_VPCA7_CON10, MT6397_VPCA7_CON5),
+       MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250,
+               buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9,
+               0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5),
+       MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250,
+               buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9,
+               0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5),
+       MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250,
+               buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f,
+               MT6397_VCORE_CON10, MT6397_VCORE_CON5),
+       MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1,
+               MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f,
+               MT6397_VGPU_CON10, MT6397_VGPU_CON5),
+       MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2,
+               MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f,
+               MT6397_VDRM_CON10, MT6397_VDRM_CON5),
+       MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000,
+               buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f,
+               MT6397_VIO18_CON10, MT6397_VIO18_CON5),
+       MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000),
+       MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000),
+       MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1,
+               MT6397_ANALDO_CON2, 15, MT6397_ANALDO_CON6, 0xC0),
+       MT6397_REG_FIXED("ldo_vio28", VIO28, MT6397_DIGLDO_CON0, 14, 2800000),
+       MT6397_REG_FIXED("ldo_vusb", VUSB, MT6397_DIGLDO_CON1, 14, 3300000),
+       MT6397_LDO("ldo_vmc", VMC, ldo_volt_table2,
+               MT6397_DIGLDO_CON2, 12, MT6397_DIGLDO_CON29, 0x10),
+       MT6397_LDO("ldo_vmch", VMCH, ldo_volt_table3,
+               MT6397_DIGLDO_CON3, 14, MT6397_DIGLDO_CON17, 0x80),
+       MT6397_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table3,
+               MT6397_DIGLDO_CON4, 14, MT6397_DIGLDO_CON18, 0x10),
+       MT6397_LDO("ldo_vgp1", VGP1, ldo_volt_table4,
+               MT6397_DIGLDO_CON5, 15, MT6397_DIGLDO_CON19, 0xE0),
+       MT6397_LDO("ldo_vgp2", VGP2, ldo_volt_table5,
+               MT6397_DIGLDO_CON6, 15, MT6397_DIGLDO_CON20, 0xE0),
+       MT6397_LDO("ldo_vgp3", VGP3, ldo_volt_table5,
+               MT6397_DIGLDO_CON7, 15, MT6397_DIGLDO_CON21, 0xE0),
+       MT6397_LDO("ldo_vgp4", VGP4, ldo_volt_table5,
+               MT6397_DIGLDO_CON8, 15, MT6397_DIGLDO_CON22, 0xE0),
+       MT6397_LDO("ldo_vgp5", VGP5, ldo_volt_table6,
+               MT6397_DIGLDO_CON9, 15, MT6397_DIGLDO_CON23, 0xE0),
+       MT6397_LDO("ldo_vgp6", VGP6, ldo_volt_table5,
+               MT6397_DIGLDO_CON10, 15, MT6397_DIGLDO_CON33, 0xE0),
+       MT6397_LDO("ldo_vibr", VIBR, ldo_volt_table7,
+               MT6397_DIGLDO_CON24, 15, MT6397_DIGLDO_CON25, 0xE00),
+};
+
+static int mt6397_set_buck_vosel_reg(struct platform_device *pdev)
+{
+       struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+       int i;
+       u32 regval;
+
+       for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
+               if (mt6397_regulators[i].vselctrl_reg) {
+                       if (regmap_read(mt6397->regmap,
+                               mt6397_regulators[i].vselctrl_reg,
+                               &regval) < 0) {
+                               dev_err(&pdev->dev,
+                                       "Failed to read buck ctrl\n");
+                               return -EIO;
+                       }
+
+                       if (regval & mt6397_regulators[i].vselctrl_mask) {
+                               mt6397_regulators[i].desc.vsel_reg =
+                               mt6397_regulators[i].vselon_reg;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int mt6397_regulator_probe(struct platform_device *pdev)
+{
+       struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = {};
+       struct regulator_dev *rdev;
+       int i;
+       u32 reg_value, version;
+
+       /* Query buck controller to select activated voltage register part */
+       if (mt6397_set_buck_vosel_reg(pdev))
+               return -EIO;
+
+       /* Read PMIC chip revision to update constraints and voltage table */
+       if (regmap_read(mt6397->regmap, MT6397_CID, &reg_value) < 0) {
+               dev_err(&pdev->dev, "Failed to read Chip ID\n");
+               return -EIO;
+       }
+       dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+       version = (reg_value & 0xFF);
+       switch (version) {
+       case MT6397_REGULATOR_ID91:
+               mt6397_regulators[MT6397_ID_VGP2].desc.volt_table =
+               ldo_volt_table5_v2;
+               break;
+       default:
+               break;
+       }
+
+       for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
+               config.dev = &pdev->dev;
+               config.driver_data = &mt6397_regulators[i];
+               config.regmap = mt6397->regmap;
+               rdev = devm_regulator_register(&pdev->dev,
+                               &mt6397_regulators[i].desc, &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "failed to register %s\n",
+                               mt6397_regulators[i].desc.name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver mt6397_regulator_driver = {
+       .driver = {
+               .name = "mt6397-regulator",
+       },
+       .probe = mt6397_regulator_probe,
+};
+
+module_platform_driver(mt6397_regulator_driver);
+
+MODULE_AUTHOR("Flora Fu <flora.fu@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mt6397-regulator");
index 91eaaf01052494e6579a87890ac2875cce740018..24e812c48d93076a36039e991c51bb371fb26d6e 100644 (file)
@@ -270,6 +270,7 @@ EXPORT_SYMBOL_GPL(of_regulator_match);
 
 struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
                                            const struct regulator_desc *desc,
+                                           struct regulator_config *config,
                                            struct device_node **node)
 {
        struct device_node *search, *child;
@@ -307,6 +308,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
                        break;
                }
 
+               if (desc->of_parse_cb) {
+                       if (desc->of_parse_cb(child, desc, config)) {
+                               dev_err(dev,
+                                       "driver callback failed to parse DT for regulator %s\n",
+                                       child->name);
+                               init_data = NULL;
+                               break;
+                       }
+               }
+
                of_node_get(child);
                *node = child;
                break;
index c879dff597eeaba773468b66a71526a9ca1fb5e8..8cc8d1877c446a48737b5d337f9faf91dc6c37e1 100644 (file)
@@ -56,7 +56,7 @@
 #define PFUZE100_VGEN5VOL      0x70
 #define PFUZE100_VGEN6VOL      0x71
 
-enum chips { PFUZE100, PFUZE200 };
+enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 };
 
 struct pfuze_regulator {
        struct regulator_desc desc;
@@ -80,9 +80,18 @@ static const int pfuze100_vsnvs[] = {
        1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
 };
 
+static const int pfuze3000_sw2lo[] = {
+       1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
+};
+
+static const int pfuze3000_sw2hi[] = {
+       2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000,
+};
+
 static const struct i2c_device_id pfuze_device_id[] = {
        {.name = "pfuze100", .driver_data = PFUZE100},
        {.name = "pfuze200", .driver_data = PFUZE200},
+       {.name = "pfuze3000", .driver_data = PFUZE3000},
        { }
 };
 MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
@@ -90,6 +99,7 @@ MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
 static const struct of_device_id pfuze_dt_ids[] = {
        { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
        { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
+       { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000},
        { }
 };
 MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
@@ -219,6 +229,60 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
                .stby_mask = 0x20,      \
        }
 
+#define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step)  {       \
+       .desc = {       \
+               .name = #_name, \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .ops = &pfuze100_ldo_regulator_ops,     \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = _chip ## _ ## _name,      \
+               .owner = THIS_MODULE,   \
+               .min_uV = (min),        \
+               .uV_step = (step),      \
+               .vsel_reg = (base),     \
+               .vsel_mask = 0x3,       \
+               .enable_reg = (base),   \
+               .enable_mask = 0x10,    \
+       },      \
+       .stby_reg = (base),     \
+       .stby_mask = 0x20,      \
+}
+
+
+#define PFUZE3000_SW2_REG(_chip, _name, base, min, max, step)  {       \
+       .desc = {       \
+               .name = #_name,\
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .ops = &pfuze100_sw_regulator_ops,      \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = _chip ## _ ## _name,      \
+               .owner = THIS_MODULE,   \
+               .min_uV = (min),        \
+               .uV_step = (step),      \
+               .vsel_reg = (base) + PFUZE100_VOL_OFFSET,       \
+               .vsel_mask = 0x7,       \
+       },      \
+       .stby_reg = (base) + PFUZE100_STANDBY_OFFSET,   \
+       .stby_mask = 0x7,       \
+}
+
+#define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step)  {       \
+       .desc = {       \
+               .name = #_name,\
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .ops = &pfuze100_sw_regulator_ops,      \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = _chip ## _ ## _name,      \
+               .owner = THIS_MODULE,   \
+               .min_uV = (min),        \
+               .uV_step = (step),      \
+               .vsel_reg = (base) + PFUZE100_VOL_OFFSET,       \
+               .vsel_mask = 0xf,       \
+       },      \
+       .stby_reg = (base) + PFUZE100_STANDBY_OFFSET,   \
+       .stby_mask = 0xf,       \
+}
+
 /* PFUZE100 */
 static struct pfuze_regulator pfuze100_regulators[] = {
        PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
@@ -254,6 +318,22 @@ static struct pfuze_regulator pfuze200_regulators[] = {
        PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
 };
 
+static struct pfuze_regulator pfuze3000_regulators[] = {
+       PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000),
+       PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000),
+       PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
+       PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
+       PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst),
+       PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+       PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+       PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+       PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
+       PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
+       PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
 static struct pfuze_regulator *pfuze_regulators;
 
 #ifdef CONFIG_OF
@@ -294,6 +374,24 @@ static struct of_regulator_match pfuze200_matches[] = {
        { .name = "vgen6",      },
 };
 
+/* PFUZE3000 */
+static struct of_regulator_match pfuze3000_matches[] = {
+
+       { .name = "sw1a",       },
+       { .name = "sw1b",       },
+       { .name = "sw2",        },
+       { .name = "sw3",        },
+       { .name = "swbst",      },
+       { .name = "vsnvs",      },
+       { .name = "vrefddr",    },
+       { .name = "vldo1",      },
+       { .name = "vldo2",      },
+       { .name = "vccsd",      },
+       { .name = "v33",        },
+       { .name = "vldo3",      },
+       { .name = "vldo4",      },
+};
+
 static struct of_regulator_match *pfuze_matches;
 
 static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
@@ -313,6 +411,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
        }
 
        switch (chip->chip_id) {
+       case PFUZE3000:
+               pfuze_matches = pfuze3000_matches;
+               ret = of_regulator_match(dev, parent, pfuze3000_matches,
+                                        ARRAY_SIZE(pfuze3000_matches));
+               break;
        case PFUZE200:
                pfuze_matches = pfuze200_matches;
                ret = of_regulator_match(dev, parent, pfuze200_matches,
@@ -378,7 +481,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
                 * as ID=8 in PFUZE100
                 */
                dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
-       } else if ((value & 0x0f) != pfuze_chip->chip_id) {
+       } else if ((value & 0x0f) != pfuze_chip->chip_id &&
+                  (value & 0xf0) >> 4 != pfuze_chip->chip_id) {
                /* device id NOT match with your setting */
                dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
                return -ENODEV;
@@ -417,7 +521,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
        int i, ret;
        const struct of_device_id *match;
        u32 regulator_num;
-       u32 sw_check_start, sw_check_end;
+       u32 sw_check_start, sw_check_end, sw_hi = 0x40;
 
        pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
                        GFP_KERNEL);
@@ -458,13 +562,19 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
 
        /* use the right regulators after identify the right device */
        switch (pfuze_chip->chip_id) {
+       case PFUZE3000:
+               pfuze_regulators = pfuze3000_regulators;
+               regulator_num = ARRAY_SIZE(pfuze3000_regulators);
+               sw_check_start = PFUZE3000_SW2;
+               sw_check_end = PFUZE3000_SW2;
+               sw_hi = 1 << 3;
+               break;
        case PFUZE200:
                pfuze_regulators = pfuze200_regulators;
                regulator_num = ARRAY_SIZE(pfuze200_regulators);
                sw_check_start = PFUZE200_SW2;
                sw_check_end = PFUZE200_SW3B;
                break;
-
        case PFUZE100:
        default:
                pfuze_regulators = pfuze100_regulators;
@@ -474,7 +584,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                break;
        }
        dev_info(&client->dev, "pfuze%s found.\n",
-               (pfuze_chip->chip_id == PFUZE100) ? "100" : "200");
+               (pfuze_chip->chip_id == PFUZE100) ? "100" :
+               ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000"));
 
        memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
                sizeof(pfuze_chip->regulator_descs));
@@ -498,10 +609,15 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                /* SW2~SW4 high bit check and modify the voltage value table */
                if (i >= sw_check_start && i <= sw_check_end) {
                        regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
-                       if (val & 0x40) {
-                               desc->min_uV = 800000;
-                               desc->uV_step = 50000;
-                               desc->n_voltages = 51;
+                       if (val & sw_hi) {
+                               if (pfuze_chip->chip_id == PFUZE3000) {
+                                       desc->volt_table = pfuze3000_sw2hi;
+                                       desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi);
+                               } else {
+                                       desc->min_uV = 800000;
+                                       desc->uV_step = 50000;
+                                       desc->n_voltages = 51;
+                               }
                        }
                }
 
index 8364ff331a81838c6e84fe822b17d434bfb74aa7..e8647f7cf25e27378af00ec7799195c2a29e995a 100644 (file)
@@ -227,9 +227,11 @@ static int rpm_reg_set_mV_sel(struct regulator_dev *rdev,
                return uV;
 
        mutex_lock(&vreg->lock);
-       vreg->uV = uV;
        if (vreg->is_enabled)
-               ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
+               ret = rpm_reg_write(vreg, req, uV / 1000);
+
+       if (!ret)
+               vreg->uV = uV;
        mutex_unlock(&vreg->lock);
 
        return ret;
@@ -252,9 +254,11 @@ static int rpm_reg_set_uV_sel(struct regulator_dev *rdev,
                return uV;
 
        mutex_lock(&vreg->lock);
-       vreg->uV = uV;
        if (vreg->is_enabled)
-               ret = rpm_reg_write(vreg, req, vreg->uV);
+               ret = rpm_reg_write(vreg, req, uV);
+
+       if (!ret)
+               vreg->uV = uV;
        mutex_unlock(&vreg->lock);
 
        return ret;
@@ -674,6 +678,7 @@ static int rpm_reg_probe(struct platform_device *pdev)
        vreg->desc.owner = THIS_MODULE;
        vreg->desc.type = REGULATOR_VOLTAGE;
        vreg->desc.name = pdev->dev.of_node->name;
+       vreg->desc.supply_name = "vin";
 
        vreg->rpm = dev_get_drvdata(pdev->dev.parent);
        if (!vreg->rpm) {
@@ -768,7 +773,7 @@ static int rpm_reg_probe(struct platform_device *pdev)
                        break;
                }
 
-               if (force_mode < 0) {
+               if (force_mode == -1) {
                        dev_err(&pdev->dev, "invalid force mode\n");
                        return -EINVAL;
                }
index c94a3e0f3b91b4af039740a32a883c55d836a51f..1f93b752a81cdc36a824459ebf66354aea275af8 100644 (file)
@@ -97,7 +97,7 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
                                  RK808_RAMP_RATE_MASK, ramp_value);
 }
 
-int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
+static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
 {
        unsigned int reg;
        int sel = regulator_map_voltage_linear_range(rdev, uv, uv);
@@ -112,7 +112,7 @@ int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
                                  sel);
 }
 
-int rk808_set_suspend_enable(struct regulator_dev *rdev)
+static int rk808_set_suspend_enable(struct regulator_dev *rdev)
 {
        unsigned int reg;
 
@@ -123,7 +123,7 @@ int rk808_set_suspend_enable(struct regulator_dev *rdev)
                                  0);
 }
 
-int rk808_set_suspend_disable(struct regulator_dev *rdev)
+static int rk808_set_suspend_disable(struct regulator_dev *rdev)
 {
        unsigned int reg;
 
index 870cc49438dbe55d237dde1602010bb20105e104..96d2c18e051a071de50a490181e88151a310bed8 100644 (file)
@@ -36,6 +36,8 @@ static struct regulator_ops rt5033_buck_ops = {
 static const struct regulator_desc rt5033_supported_regulators[] = {
        [RT5033_BUCK] = {
                .name           = "BUCK",
+               .of_match       = of_match_ptr("BUCK"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = RT5033_BUCK,
                .ops            = &rt5033_buck_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -50,6 +52,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = {
        },
        [RT5033_LDO] = {
                .name           = "LDO",
+               .of_match       = of_match_ptr("LDO"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = RT5033_LDO,
                .ops            = &rt5033_buck_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -64,6 +68,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = {
        },
        [RT5033_SAFE_LDO] = {
                .name           = "SAFE_LDO",
+               .of_match       = of_match_ptr("SAFE_LDO"),
+               .regulators_node = of_match_ptr("regulators"),
                .id             = RT5033_SAFE_LDO,
                .ops            = &rt5033_safe_ldo_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -81,7 +87,7 @@ static int rt5033_regulator_probe(struct platform_device *pdev)
        int ret, i;
        struct regulator_config config = {};
 
-       config.dev = &pdev->dev;
+       config.dev = rt5033->dev;
        config.driver_data = rt5033;
 
        for (i = 0; i < ARRAY_SIZE(rt5033_supported_regulators); i++) {
index 7380af8bd50d4e8d699f7564c6ab4bb3e4edc84b..b941e564b3f3405a647b0d13794eed5d3dffa3fc 100644 (file)
@@ -173,7 +173,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
 }
 
 /* Operations permitted on VDCDCx */
-static struct regulator_ops tps65023_dcdc_ops = {
+static const struct regulator_ops tps65023_dcdc_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -184,7 +184,7 @@ static struct regulator_ops tps65023_dcdc_ops = {
 };
 
 /* Operations permitted on LDOx */
-static struct regulator_ops tps65023_ldo_ops = {
+static const struct regulator_ops tps65023_ldo_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -194,7 +194,7 @@ static struct regulator_ops tps65023_ldo_ops = {
        .map_voltage = regulator_map_voltage_ascend,
 };
 
-static struct regmap_config tps65023_regmap_config = {
+static const struct regmap_config tps65023_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 };
index 5479394fefcec75bce9a090093d9d5d6e81e5b5d..5dd65acc2a69e5188bb1f5d95ac1223c67fd36bc 100644 (file)
@@ -32,6 +32,8 @@ struct da9211_pdata {
         * 2 : 2 phase 2 buck
         */
        int num_buck;
+       int gpio_ren[DA9211_MAX_REGULATORS];
+       struct device_node *reg_node[DA9211_MAX_REGULATORS];
        struct regulator_init_data *init_data[DA9211_MAX_REGULATORS];
 };
 #endif
index 5f1e9ca47417febff0811df407abe43d99563786..d4ad5b5a02bb478a422b349406efba00997bab76 100644 (file)
@@ -21,6 +21,7 @@
 
 struct regmap;
 struct regulator_dev;
+struct regulator_config;
 struct regulator_init_data;
 struct regulator_enable_gpio;
 
@@ -205,6 +206,15 @@ enum regulator_type {
  * @supply_name: Identifying the regulator supply
  * @of_match: Name used to identify regulator in DT.
  * @regulators_node: Name of node containing regulator definitions in DT.
+ * @of_parse_cb: Optional callback called only if of_match is present.
+ *               Will be called for each regulator parsed from DT, during
+ *               init_data parsing.
+ *               The regulator_config passed as argument to the callback will
+ *               be a copy of config passed to regulator_register, valid only
+ *               for this particular call. Callback may freely change the
+ *               config but it cannot store it for later usage.
+ *               Callback should return 0 on success or negative ERRNO
+ *               indicating failure.
  * @id: Numerical identifier for the regulator.
  * @ops: Regulator operations table.
  * @irq: Interrupt number for the regulator.
@@ -251,6 +261,9 @@ struct regulator_desc {
        const char *supply_name;
        const char *of_match;
        const char *regulators_node;
+       int (*of_parse_cb)(struct device_node *,
+                           const struct regulator_desc *,
+                           struct regulator_config *);
        int id;
        bool continuous_voltage_range;
        unsigned n_voltages;
index 0b08d05d470b56cacec467d5368810517d4a1752..b07562e082c416a2b98fc08818f35111c8237288 100644 (file)
@@ -191,15 +191,22 @@ struct regulator_init_data {
        void *driver_data;      /* core does not touch this */
 };
 
-int regulator_suspend_prepare(suspend_state_t state);
-int regulator_suspend_finish(void);
-
 #ifdef CONFIG_REGULATOR
 void regulator_has_full_constraints(void);
+int regulator_suspend_prepare(suspend_state_t state);
+int regulator_suspend_finish(void);
 #else
 static inline void regulator_has_full_constraints(void)
 {
 }
+static inline int regulator_suspend_prepare(suspend_state_t state)
+{
+       return 0;
+}
+static inline int regulator_suspend_finish(void)
+{
+       return 0;
+}
 #endif
 
 #endif
diff --git a/include/linux/regulator/mt6397-regulator.h b/include/linux/regulator/mt6397-regulator.h
new file mode 100644 (file)
index 0000000..30cc596
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu <flora.fu@mediatek.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 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 __LINUX_REGULATOR_MT6397_H
+#define __LINUX_REGULATOR_MT6397_H
+
+enum {
+       MT6397_ID_VPCA15 = 0,
+       MT6397_ID_VPCA7,
+       MT6397_ID_VSRAMCA15,
+       MT6397_ID_VSRAMCA7,
+       MT6397_ID_VCORE,
+       MT6397_ID_VGPU,
+       MT6397_ID_VDRM,
+       MT6397_ID_VIO18 = 7,
+       MT6397_ID_VTCXO,
+       MT6397_ID_VA28,
+       MT6397_ID_VCAMA,
+       MT6397_ID_VIO28,
+       MT6397_ID_VUSB,
+       MT6397_ID_VMC,
+       MT6397_ID_VMCH,
+       MT6397_ID_VEMC3V3,
+       MT6397_ID_VGP1,
+       MT6397_ID_VGP2,
+       MT6397_ID_VGP3,
+       MT6397_ID_VGP4,
+       MT6397_ID_VGP5,
+       MT6397_ID_VGP6,
+       MT6397_ID_VIBR,
+       MT6397_ID_RG_MAX,
+};
+
+#define MT6397_MAX_REGULATOR   MT6397_ID_RG_MAX
+#define MT6397_REGULATOR_ID97  0x97
+#define MT6397_REGULATOR_ID91  0x91
+
+#endif /* __LINUX_REGULATOR_MT6397_H */
index 364f7a7c43db3db23e67805983e90b3dd0187837..70c6c66c5bcf16cc4be324a1aaf40b1981e56413 100644 (file)
 #define PFUZE200_VGEN5         11
 #define PFUZE200_VGEN6         12
 
+#define PFUZE3000_SW1A         0
+#define PFUZE3000_SW1B         1
+#define PFUZE3000_SW2          2
+#define PFUZE3000_SW3          3
+#define PFUZE3000_SWBST                4
+#define PFUZE3000_VSNVS                5
+#define PFUZE3000_VREFDDR      6
+#define PFUZE3000_VLDO1                7
+#define PFUZE3000_VLDO2                8
+#define PFUZE3000_VCCSD                9
+#define PFUZE3000_V33          10
+#define PFUZE3000_VLDO3                11
+#define PFUZE3000_VLDO4                12
+
 struct regulator_init_data;
 
 struct pfuze_regulator_platform_data {