diff mbox

[4/5] regulator: Add support for TI TWL6032

Message ID 20161126181326.14951-5-Nicolae_Rosia@mentor.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nicolae Rosia Nov. 26, 2016, 6:13 p.m. UTC
The TWL6032 PMIC is similar to TWL6030, has different
output names, and regulator control logic.
It is used on Barnes & Noble Nook HD and HD+.

Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
 .../bindings/regulator/twl6032-regulator.txt       | 109 ++++
 drivers/regulator/Kconfig                          |   7 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/twl6032-regulator.c              | 582 +++++++++++++++++++++
 4 files changed, 699 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
 create mode 100644 drivers/regulator/twl6032-regulator.c

Comments

kernel test robot Nov. 26, 2016, 6:55 p.m. UTC | #1
Hi Nicolae,

[auto build test ERROR on omap/for-next]
[also build test ERROR on v4.9-rc6]
[cannot apply to next-20161125]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Nicolae-Rosia/mfd-twl-improvements-and-new-regulator-driver/20161127-022201
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/regulator/twl6032-regulator.c:11:0:
>> drivers/regulator/twl6032-regulator.c:557:31: error: 'twl6032_regulator_driver_ids' undeclared here (not in a function)
    MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
                                  ^
   include/linux/module.h:213:21: note: in definition of macro 'MODULE_DEVICE_TABLE'
    extern const typeof(name) __mod_##type##__##name##_device_table  \
                        ^~~~
>> include/linux/module.h:213:27: error: '__mod_platform__twl6032_regulator_driver_ids_device_table' aliased to undefined symbol 'twl6032_regulator_driver_ids'
    extern const typeof(name) __mod_##type##__##name##_device_table  \
                              ^
>> drivers/regulator/twl6032-regulator.c:557:1: note: in expansion of macro 'MODULE_DEVICE_TABLE'
    MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
    ^~~~~~~~~~~~~~~~~~~

vim +/twl6032_regulator_driver_ids +557 drivers/regulator/twl6032-regulator.c

   551	
   552	static const struct of_device_id twl6032_dt_match[] = {
   553		{ .compatible = "ti,twl6032-regulator" },
   554		{ /* last entry */ }
   555	};
   556	
 > 557	MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
   558	
   559	static struct platform_driver twl6032_regulator_driver = {
   560		.driver = {

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Nicolae Rosia Nov. 26, 2016, 8:24 p.m. UTC | #2
SGksDQoNCk9uIFN1biwgMjAxNi0xMS0yNyBhdCAwMjo1NSArMDgwMCwga2J1aWxkIHRlc3Qgcm9i
b3Qgd3JvdGU6DQo+IEhpIE5pY29sYWUsDQo+IA0KPiBbYXV0byBidWlsZCB0ZXN0IEVSUk9SIG9u
IG9tYXAvZm9yLW5leHRdDQo+IFthbHNvIGJ1aWxkIHRlc3QgRVJST1Igb24gdjQuOS1yYzZdDQo+
IFtjYW5ub3QgYXBwbHkgdG8gbmV4dC0yMDE2MTEyNV0NCj4gW2lmIHlvdXIgcGF0Y2ggaXMgYXBw
bGllZCB0byB0aGUgd3JvbmcgZ2l0IHRyZWUsIHBsZWFzZSBkcm9wIHVzIGENCj4gbm90ZSB0byBo
ZWxwIGltcHJvdmUgdGhlIHN5c3RlbV0NCj4gDQo+IHVybDrCoMKgwqDCoGh0dHBzOi8vZ2l0aHVi
LmNvbS8wZGF5LWNpL2xpbnV4L2NvbW1pdHMvTmljb2xhZS1Sb3NpYS9tZmQtdHcNCj4gbC1pbXBy
b3ZlbWVudHMtYW5kLW5ldy1yZWd1bGF0b3ItZHJpdmVyLzIwMTYxMTI3LTAyMjIwMQ0KPiBiYXNl
OsKgwqDCoGh0dHBzOi8vZ2l0Lmtlcm5lbC5vcmcvcHViL3NjbS9saW51eC9rZXJuZWwvZ2l0L3Rt
bGluZC9saW51eC0NCj4gb21hcC5naXQgZm9yLW5leHQNCj4gY29uZmlnOiBpMzg2LWFsbG1vZGNv
bmZpZyAoYXR0YWNoZWQgYXMgLmNvbmZpZykNCj4gY29tcGlsZXI6IGdjYy02IChEZWJpYW4gNi4y
LjAtMykgNi4yLjAgMjAxNjA5MDENCj4gcmVwcm9kdWNlOg0KPiDCoMKgwqDCoMKgwqDCoMKgIyBz
YXZlIHRoZSBhdHRhY2hlZCAuY29uZmlnIHRvIGxpbnV4IGJ1aWxkIHRyZWUNCj4gwqDCoMKgwqDC
oMKgwqDCoG1ha2UgQVJDSD1pMzg2wqANCj4gDQo+IEFsbCBlcnJvci93YXJuaW5ncyAobmV3IG9u
ZXMgcHJlZml4ZWQgYnkgPj4pOg0KPiANCj4gwqDCoMKgSW4gZmlsZSBpbmNsdWRlZCBmcm9tIGRy
aXZlcnMvcmVndWxhdG9yL3R3bDYwMzItcmVndWxhdG9yLmM6MTE6MDoNCj4gPiA+IGRyaXZlcnMv
cmVndWxhdG9yL3R3bDYwMzItcmVndWxhdG9yLmM6NTU3OjMxOiBlcnJvcjoNCj4gPiA+ICd0d2w2
MDMyX3JlZ3VsYXRvcl9kcml2ZXJfaWRzJyB1bmRlY2xhcmVkIGhlcmUgKG5vdCBpbiBhDQo+ID4g
PiBmdW5jdGlvbikNCj4gDQo+IMKgwqDCoMKgTU9EVUxFX0RFVklDRV9UQUJMRShwbGF0Zm9ybSwg
dHdsNjAzMl9yZWd1bGF0b3JfZHJpdmVyX2lkcyk7DQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgXg0KPiDCoMKgwqBp
bmNsdWRlL2xpbnV4L21vZHVsZS5oOjIxMzoyMTogbm90ZTogaW4gZGVmaW5pdGlvbiBvZiBtYWNy
bw0KPiAnTU9EVUxFX0RFVklDRV9UQUJMRScNCj4gwqDCoMKgwqBleHRlcm4gY29uc3QgdHlwZW9m
KG5hbWUpDQo+IF9fbW9kXyMjdHlwZSMjX18jI25hbWUjI19kZXZpY2VfdGFibGXCoMKgXA0KPiDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBefn5+DQo+ID4g
PiBpbmNsdWRlL2xpbnV4L21vZHVsZS5oOjIxMzoyNzogZXJyb3I6DQo+ID4gPiAnX19tb2RfcGxh
dGZvcm1fX3R3bDYwMzJfcmVndWxhdG9yX2RyaXZlcl9pZHNfZGV2aWNlX3RhYmxlJw0KPiA+ID4g
YWxpYXNlZCB0byB1bmRlZmluZWQgc3ltYm9sICd0d2w2MDMyX3JlZ3VsYXRvcl9kcml2ZXJfaWRz
Jw0KPiANCj4gwqDCoMKgwqBleHRlcm4gY29uc3QgdHlwZW9mKG5hbWUpDQo+IF9fbW9kXyMjdHlw
ZSMjX18jI25hbWUjI19kZXZpY2VfdGFibGXCoMKgXA0KPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBeDQo+ID4gPiBkcml2ZXJzL3Jl
Z3VsYXRvci90d2w2MDMyLXJlZ3VsYXRvci5jOjU1NzoxOiBub3RlOiBpbiBleHBhbnNpb24NCj4g
PiA+IG9mIG1hY3JvICdNT0RVTEVfREVWSUNFX1RBQkxFJw0KPiANCj4gwqDCoMKgwqBNT0RVTEVf
REVWSUNFX1RBQkxFKHBsYXRmb3JtLCB0d2w2MDMyX3JlZ3VsYXRvcl9kcml2ZXJfaWRzKTsNCj4g
wqDCoMKgwqBefn5+fn5+fn5+fn5+fn5+fn5+DQo+IA0KPiB2aW0gKy90d2w2MDMyX3JlZ3VsYXRv
cl9kcml2ZXJfaWRzICs1NTcgZHJpdmVycy9yZWd1bGF0b3IvdHdsNjAzMi0NCj4gcmVndWxhdG9y
LmMNCj4gDQo+IMKgwqDCoDU1MQkNCj4gwqDCoMKgNTUyCXN0YXRpYyBjb25zdCBzdHJ1Y3Qgb2Zf
ZGV2aWNlX2lkIHR3bDYwMzJfZHRfbWF0Y2hbXSA9IHsNCj4gwqDCoMKgNTUzCQl7IC5jb21wYXRp
YmxlID0gInRpLHR3bDYwMzItcmVndWxhdG9yIiB9LA0KPiDCoMKgwqA1NTQJCXsgLyogbGFzdCBl
bnRyeSAqLyB9DQo+IMKgwqDCoDU1NQl9Ow0KPiDCoMKgwqA1NTYJDQo+IMKgPiA1NTcJTU9EVUxF
X0RFVklDRV9UQUJMRShwbGF0Zm9ybSwNCj4gdHdsNjAzMl9yZWd1bGF0b3JfZHJpdmVyX2lkcyk7
DQo+IMKgwqDCoDU1OAkNCj4gwqDCoMKgNTU5CXN0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVy
IHR3bDYwMzJfcmVndWxhdG9yX2RyaXZlcg0KPiA9IHsNCj4gwqDCoMKgNTYwCQkuZHJpdmVyID0g
ew0KDQpUaGFua3MsIEkgZGlkIG5vdCBub3RpY2UgdGhpcyBzaW5jZSBJIHdhcyBvbmx5IHRlc3Rp
bmcgdXNpbmcgYnVpbHQtaW4NCm1vZHVsZS4NCkkgd2lsbCB3YWl0IGZvciBjb21tZW50cyBiZWZv
cmUgc2VuZGluZyBWMiwgdW50aWxsIHRoZW4gaGVyZSdzIGFuDQppbmxpbmUgcGF0Y2ggd2l0aCB0
aGUgZml4Lg0KDQoNCkJlc3QgcmVnYXJkcywNCk5pY29sYWUNCg0K
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring (Arm) Dec. 1, 2016, 4:10 p.m. UTC | #3
On Sat, Nov 26, 2016 at 08:13:25PM +0200, Nicolae Rosia wrote:
> The TWL6032 PMIC is similar to TWL6030, has different
> output names, and regulator control logic.
> It is used on Barnes & Noble Nook HD and HD+.
> 
> Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
> ---
>  .../bindings/regulator/twl6032-regulator.txt       | 109 ++++
>  drivers/regulator/Kconfig                          |   7 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/twl6032-regulator.c              | 582 +++++++++++++++++++++
>  4 files changed, 699 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
>  create mode 100644 drivers/regulator/twl6032-regulator.c
> 
> diff --git a/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
> new file mode 100644
> index 0000000..323f5a9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
> @@ -0,0 +1,109 @@
> +TWL6032 PMIC Voltage Regulator Bindings
> +
> +The parent node must be MFD TWL Core, ti,twl6032.
> +
> +Required properties:
> +- compatible: "ti,twl6032"
> +
> +Optional properties:
> +- regulators node containing regulator childs.

s/childs/children/

regulators node is not a property.

> +
> +The child regulators  must be named after their hardware

extra space             ^

> +counterparts: LDO[1-6], LDOLN, LDOUSB and VANA.
> +
> +Each regulator is defined using the standard binding
> +for regulators as described in ./regulator.txt
> +
> +Example:
> +twl {
> +	compatible = "ti,twl6032";
> +
> +	[...]
> +
> +	pmic {
> +		compatible = "ti,twl6032-regulator";

Not documented.

> +
> +		regulators {

Do you really need pmic node and regulators node?

> +			ldo1: LDO1 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <2500000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo2: LDO2 {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo3: LDO3 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo4: LDO4 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo5: LDO5 {
> +				regulator-min-microvolt = <1200000>;
> +				regulator-max-microvolt = <3000000>;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo6: LDO6 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-always-on;
> +
> +				regulator-state-mem {
> +					regulator-off-in-suspend;
> +				};
> +			};
> +
> +			ldo7: LDO7 {
> +				regulator-min-microvolt = <1800000>;
> +				regulator-max-microvolt = <1800000>;
> +				regulator-boot-on;
> +				regulator-always-on;
> +			};
> +
> +			ldoln: LDOLN {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +			};
> +
> +			ldousb: LDOUSB {
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <3000000>;
> +			};
> +
> +			vana: VANA {
> +				regulator-min-microvolt = <2100000>;
> +				regulator-max-microvolt = <2100000>;
> +				regulator-always-on;
> +			};
> +		};
> +	};
> +
> +	[...]
> +};
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
new file mode 100644
index 0000000..323f5a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
@@ -0,0 +1,109 @@ 
+TWL6032 PMIC Voltage Regulator Bindings
+
+The parent node must be MFD TWL Core, ti,twl6032.
+
+Required properties:
+- compatible: "ti,twl6032"
+
+Optional properties:
+- regulators node containing regulator childs.
+
+The child regulators  must be named after their hardware
+counterparts: LDO[1-6], LDOLN, LDOUSB and VANA.
+
+Each regulator is defined using the standard binding
+for regulators as described in ./regulator.txt
+
+Example:
+twl {
+	compatible = "ti,twl6032";
+
+	[...]
+
+	pmic {
+		compatible = "ti,twl6032-regulator";
+
+		regulators {
+			ldo1: LDO1 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2500000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo2: LDO2 {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo3: LDO3 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo4: LDO4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo5: LDO5 {
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo6: LDO6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo7: LDO7 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldoln: LDOLN {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			ldousb: LDOUSB {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			vana: VANA {
+				regulator-min-microvolt = <2100000>;
+				regulator-max-microvolt = <2100000>;
+				regulator-always-on;
+			};
+		};
+	};
+
+	[...]
+};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 936f7cc..3168aba 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -843,6 +843,13 @@  config REGULATOR_TWL4030
 	  This driver supports the voltage regulators provided by
 	  this family of companion chips.
 
+config REGULATOR_TWL6032
+	tristate "TI TWL6032 PMIC"
+	depends on TWL4030_CORE
+	depends on OF || COMPILE_TEST
+	help
+	  This driver supports the Texas Instruments TWL6032 voltage regulator.
+
 config REGULATOR_VEXPRESS
 	tristate "Versatile Express regulators"
 	depends on VEXPRESS_CONFIG
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 2142a5d..185a979 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -105,6 +105,7 @@  obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_TWL6032) += twl6032-regulator.o
 obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
diff --git a/drivers/regulator/twl6032-regulator.c b/drivers/regulator/twl6032-regulator.c
new file mode 100644
index 0000000..70a0fdf
--- /dev/null
+++ b/drivers/regulator/twl6032-regulator.c
@@ -0,0 +1,582 @@ 
+/*
+ * TWL6032 regulator driver
+ * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.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/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/mfd/twl-core.h>
+
+/* TWL6032 register offsets */
+#define TWL6032_VREG_TRANS 1
+#define TWL6032_VREG_STATE 2
+#define TWL6032_VREG_VOLTAGE 3
+
+#define TWL6032_LDO_MIN_MV 1000
+#define TWL6032_LDO_MAX_MV 3300
+
+/* TWL6030 LDO register values for CFG_TRANS */
+#define TWL6032_CFG_TRANS_STATE_MASK 0x03
+#define TWL6032_CFG_TRANS_STATE_OFF 0x00
+#define TWL6032_CFG_TRANS_STATE_AUTO 0x01
+#define TWL6032_CFG_TRANS_SLEEP_SHIFT 2
+
+#define TWL6032_CFG_STATE_MASK 0x03
+#define TWL6032_CFG_STATE_OFF 0x00
+#define TWL6032_CFG_STATE_ON 0x01
+#define TWL6032_CFG_STATE_OFF2 0x02
+#define TWL6032_CFG_STATE_SLEEP 0x03
+
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+	if (rdev->constraints && rdev->constraints->name)
+		return rdev->constraints->name;
+	else if (rdev->desc->name)
+		return rdev->desc->name;
+	else
+		return "";
+}
+
+struct twl6032_regulator_info {
+	u8 base;
+	unsigned int min_mV;
+	struct regulator_desc desc;
+};
+
+struct twl6032_regulator {
+	struct twl6032_regulator_info *info;
+};
+
+static int twl6032_set_trans_state(struct regulator_dev *rdev, u8 shift, u8 val)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	unsigned int state;
+	u8 mask;
+	int ret;
+
+	/* Read CFG_TRANS register of TWL6030 */
+	ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_TRANS,
+			  &state);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	mask = TWL6032_CFG_TRANS_STATE_MASK << shift;
+	val = (val << shift) & mask;
+
+	/* If value is already set, no need to write to reg */
+	if (val == (state & mask))
+		return 0;
+
+	state &= ~mask;
+	state |= val;
+
+	return regmap_write(rdev->regmap, info->base + TWL6032_VREG_TRANS,
+			    state);
+}
+
+static int
+twl6032_ldo_list_voltage(struct regulator_dev *rdev, unsigned int sel)
+{
+	int ret;
+
+	switch (sel) {
+	case 0:
+		ret = 0;
+		break;
+	case 1 ... 24:
+		/* Linear mapping from 00000001 to 00011000:
+		 * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001)
+		 */
+		ret = (TWL6032_LDO_MIN_MV + 100 * (sel - 1)) * 1000;
+		break;
+	case 25 ... 30:
+		ret = -EINVAL;
+		break;
+	case 31:
+		ret = 2750000;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	dev_dbg(&rdev->dev, "%s %s: sel: %d, mV: %d\n", rdev_get_name(rdev),
+		__func__, sel, ret);
+
+	return ret;
+}
+
+static int
+twl6032_ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	int ret;
+
+	dev_dbg(&rdev->dev, "%s %s: sel: 0x%02X\n", rdev_get_name(rdev),
+		__func__, sel);
+
+	ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_VOLTAGE,
+			   sel);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int twl6032_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_VOLTAGE,
+			  &val);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	dev_dbg(&rdev->dev, "%s %s: vsel: 0x%02X\n", rdev_get_name(rdev),
+		__func__, val);
+
+	return val;
+}
+
+static int twl6032_ldo_enable(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	int ret;
+
+	dev_dbg(&rdev->dev, "%s %s\n", rdev_get_name(rdev), __func__);
+
+	ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE,
+			   TWL6032_CFG_STATE_ON);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	ret = twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+				      TWL6032_CFG_TRANS_STATE_AUTO);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: twl6032_set_trans_state: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int twl6032_ldo_disable(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	int ret;
+
+	dev_dbg(&rdev->dev, "%s %s\n", rdev_get_name(rdev), __func__);
+
+	ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE,
+			   TWL6032_CFG_STATE_OFF);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	ret = twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+				      TWL6032_CFG_TRANS_STATE_OFF);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: twl6032_set_trans_state: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int twl6032_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_STATE, &val);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s regmap_read: %d\n", __func__, ret);
+		return ret;
+	}
+
+	dev_dbg(&rdev->dev, "%s %s: val: 0x%02X, val-masked: 0x%02X, ret: %d\n",
+		rdev_get_name(rdev), __func__,
+		val, val & TWL6032_CFG_STATE_MASK,
+		(val & TWL6032_CFG_STATE_MASK) == TWL6032_CFG_STATE_ON);
+
+	val &= TWL6032_CFG_STATE_MASK;
+
+	return val == TWL6032_CFG_STATE_ON;
+}
+
+static int twl6032_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	unsigned int val = 0;
+	int ret;
+
+	dev_dbg(&rdev->dev, "%s %s: mode: 0x%02X\n", rdev_get_name(rdev),
+		__func__, mode);
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val |= TWL6032_CFG_STATE_ON;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val |= TWL6032_CFG_STATE_SLEEP;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_write(rdev->regmap, info->base + TWL6032_VREG_STATE, val);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_write: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int twl6032_ldo_get_status(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(rdev->regmap, info->base + TWL6032_VREG_STATE, &val);
+	if (ret < 0) {
+		dev_err(&rdev->dev, "%s %s: regmap_read: %d\n",
+			rdev_get_name(rdev), __func__, ret);
+		return ret;
+	}
+
+	dev_dbg(&rdev->dev, "%s %s: val: 0x%02X, val-with-mask: 0x%02X\n",
+		rdev_get_name(rdev), __func__,
+		val, val & TWL6032_CFG_STATE_MASK);
+
+	val &= TWL6032_CFG_STATE_MASK;
+
+	switch (val) {
+	case TWL6032_CFG_STATE_ON:
+		return REGULATOR_STATUS_NORMAL;
+
+	case TWL6032_CFG_STATE_SLEEP:
+		return REGULATOR_STATUS_STANDBY;
+
+	case TWL6032_CFG_STATE_OFF:
+	case TWL6032_CFG_STATE_OFF2:
+	default:
+		break;
+	}
+
+	return REGULATOR_STATUS_OFF;
+}
+
+static int twl6032_ldo_suspend_enable(struct regulator_dev *rdev)
+{
+	return twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+				       TWL6032_CFG_TRANS_STATE_AUTO);
+}
+
+static int twl6032_ldo_suspend_disable(struct regulator_dev *rdev)
+{
+	return twl6032_set_trans_state(rdev, TWL6032_CFG_TRANS_SLEEP_SHIFT,
+				       TWL6032_CFG_TRANS_STATE_OFF);
+}
+
+static int
+twl6032_fixed_list_voltage(struct regulator_dev *rdev, unsigned int sel)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+
+	return info->min_mV * 1000; /* mV to V */
+}
+
+static int twl6032_fixed_get_voltage(struct regulator_dev *rdev)
+{
+	struct twl6032_regulator *twl6032_reg = rdev_get_drvdata(rdev);
+	struct twl6032_regulator_info *info = twl6032_reg->info;
+
+	return info->min_mV * 1000; /* mV to V */
+}
+
+static const struct regulator_ops twl6032_ldo_ops = {
+	.list_voltage = twl6032_ldo_list_voltage,
+	.set_voltage_sel = twl6032_ldo_set_voltage_sel,
+	.get_voltage_sel = twl6032_ldo_get_voltage_sel,
+	.enable = twl6032_ldo_enable,
+	.disable = twl6032_ldo_disable,
+	.is_enabled = twl6032_ldo_is_enabled,
+	.set_mode = twl6032_ldo_set_mode,
+	.get_status = twl6032_ldo_get_status,
+	.set_suspend_enable = twl6032_ldo_suspend_enable,
+	.set_suspend_disable =  twl6032_ldo_suspend_disable,
+};
+
+static const struct regulator_ops twl6032_fixed_ops = {
+	.list_voltage = twl6032_fixed_list_voltage,
+	.get_voltage = twl6032_fixed_get_voltage,
+	.enable = twl6032_ldo_enable,
+	.disable = twl6032_ldo_disable,
+	.is_enabled = twl6032_ldo_is_enabled,
+	.set_mode = twl6032_ldo_set_mode,
+	.get_status = twl6032_ldo_get_status,
+	.set_suspend_enable = twl6032_ldo_suspend_enable,
+	.set_suspend_disable =  twl6032_ldo_suspend_disable,
+};
+
+#define TWL6032_LDO_REG_VOLTAGES \
+	((TWL6032_LDO_MAX_MV - TWL6032_LDO_MIN_MV) / 100 + 1)
+#define TWL6032_LDO_REG(_id, _reg) \
+{ \
+	.base = _reg, \
+	.desc = { \
+		.name = "twl6032-reg-" # _id, \
+		.n_voltages = TWL6032_LDO_REG_VOLTAGES, \
+		.ops = &twl6032_ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+	}, \
+}
+
+#define TWL6032_FIXED_REG(_id, _reg, _min_mV) \
+{ \
+	.base = _reg, \
+	.min_mV = _min_mV, \
+	.desc = { \
+		.name = "twl6032-reg-" # _id, \
+		.n_voltages = 1, \
+		.ops = &twl6032_fixed_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+	}, \
+}
+
+#define TWL6032_RESOURCE_REG(_id, _reg) \
+{ \
+	.base = _reg, \
+	.desc = { \
+		.name = "twl6032-reg-" # _id, \
+		.ops = &twl6032_ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+	}, \
+}
+
+static struct twl6032_regulator_info twl6032_ldo_reg_info[] = {
+	TWL6032_LDO_REG(LDO1, 0x9C),
+	TWL6032_LDO_REG(LDO2, 0x84),
+	TWL6032_LDO_REG(LDO3, 0x8C),
+	TWL6032_LDO_REG(LDO4, 0x88),
+	TWL6032_LDO_REG(LDO5, 0x98),
+	TWL6032_LDO_REG(LDO6, 0x90),
+	TWL6032_LDO_REG(LDO7, 0xA4),
+	TWL6032_LDO_REG(LDOLN, 0x94),
+	TWL6032_LDO_REG(LDOUSB, 0xA0),
+};
+
+static struct twl6032_regulator_info twl6032_fixed_reg_info[] = {
+	TWL6032_FIXED_REG(VANA, 0x80, 2100),
+};
+
+static struct of_regulator_match
+twl6032_ldo_reg_matches[] = {
+	{ .name = "LDO1", },
+	{ .name = "LDO2", },
+	{ .name = "LDO3", },
+	{ .name = "LDO4", },
+	{ .name = "LDO5", },
+	{ .name = "LDO6", },
+	{ .name = "LDO7", },
+	{ .name = "LDOLN" },
+	{ .name = "LDOUSB" }
+};
+
+static struct of_regulator_match
+twl6032_fixed_reg_matches[] = {
+	{ .name = "VANA", },
+};
+
+#define TWL6032_LDO_REG_NUM ARRAY_SIZE(twl6032_ldo_reg_matches)
+#define TWL6032_FIXED_REG_NUM ARRAY_SIZE(twl6032_fixed_reg_matches)
+
+struct twl6032_regulator_priv {
+	struct twl6032_regulator ldo_regulators[TWL6032_LDO_REG_NUM];
+	struct twl6032_regulator fixed_regulators[TWL6032_FIXED_REG_NUM];
+};
+
+static int twl6032_regulator_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *regulators;
+	struct of_regulator_match *match;
+	struct twlcore *twl = dev_get_drvdata(pdev->dev.parent);
+	struct twl6032_regulator_priv *priv;
+	struct regulator_config config = {
+		.dev = &pdev->dev,
+	};
+	struct regulator_dev *rdev;
+	int ret, i;
+
+	if (!dev->of_node) {
+		dev_err(&pdev->dev, "no DT info\n");
+		return -EINVAL;
+	}
+
+	regulators = of_get_child_by_name(dev->of_node, "regulators");
+	if (!regulators) {
+		dev_err(dev, "regulator node not found\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	/* LDO regulators parsing */
+	ret = of_regulator_match(dev, regulators, twl6032_ldo_reg_matches,
+				 TWL6032_LDO_REG_NUM);
+	of_node_put(regulators);
+	if (ret < 0) {
+		dev_err(dev, "error parsing LDO reg init data: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < TWL6032_LDO_REG_NUM; i++) {
+		struct twl6032_regulator *twl6032_reg;
+
+		match = &twl6032_ldo_reg_matches[i];
+		if (!match->of_node)
+			continue;
+
+		twl6032_reg = &priv->ldo_regulators[i];
+		twl6032_reg->info = &twl6032_ldo_reg_info[i];
+
+		config.init_data = match->init_data;
+		config.driver_data = &priv->ldo_regulators[i];
+		config.regmap = twl->twl_modules[0].regmap;
+		config.of_node = match->of_node;
+
+		rdev = devm_regulator_register(dev, &twl6032_reg->info->desc,
+					       &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(dev, "failed to register regulator %s: %d\n",
+				twl6032_reg->info->desc.name, ret);
+			return ret;
+		}
+	}
+
+	/* Fixed regulators parsing */
+	ret = of_regulator_match(dev, regulators, twl6032_fixed_reg_matches,
+				 TWL6032_FIXED_REG_NUM);
+	of_node_put(regulators);
+	if (ret < 0) {
+		dev_err(dev, "error parsing fixed reg init data: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < TWL6032_FIXED_REG_NUM; i++) {
+		struct twl6032_regulator *twl6032_reg;
+
+		match = &twl6032_fixed_reg_matches[i];
+		if (!match->of_node)
+			continue;
+
+		twl6032_reg = &priv->fixed_regulators[i];
+		twl6032_reg->info = &twl6032_fixed_reg_info[i];
+
+		config.init_data = match->init_data;
+		config.driver_data = &priv->fixed_regulators[i];
+		config.regmap = twl->twl_modules[0].regmap;
+		config.of_node = match->of_node;
+
+		rdev = devm_regulator_register(dev, &twl6032_reg->info->desc,
+					       &config);
+		if (IS_ERR(rdev)) {
+			ret = PTR_ERR(rdev);
+			dev_err(dev, "failed to register regulator %s: %d\n",
+				twl6032_reg->info->desc.name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int twl6032_regulator_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id twl6032_dt_match[] = {
+	{ .compatible = "ti,twl6032-regulator" },
+	{ /* last entry */ }
+};
+
+MODULE_DEVICE_TABLE(platform, twl6032_regulator_driver_ids);
+
+static struct platform_driver twl6032_regulator_driver = {
+	.driver = {
+		.name = "twl6032-regulator",
+		.of_match_table = twl6032_dt_match,
+	},
+	.probe = twl6032_regulator_probe,
+	.remove = twl6032_regulator_remove,
+};
+
+static int __init twl6032_regulator_init(void)
+{
+	return platform_driver_register(&twl6032_regulator_driver);
+}
+subsys_initcall(twl6032_regulator_init);
+
+static void __exit twl6032_regulator_exit(void)
+{
+	platform_driver_unregister(&twl6032_regulator_driver);
+}
+module_exit(twl6032_regulator_exit);
+
+MODULE_AUTHOR("Nicolae Rosia <nicolae.rosia@gmail.com>");
+MODULE_DESCRIPTION("TI TWL6032 Regulator Driver");
+MODULE_LICENSE("GPL v2");