aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2014-09-28 07:14:26 -0400
committerMark Brown <broonie@kernel.org>2014-09-28 07:14:26 -0400
commitd1c3f7ca158e78fa78c9789d836d2a98d5fd25f3 (patch)
tree30f11b3581cdab9f344bd6718a73988e7fc6a59c
parent6a642509801116037720892efe72f0e84f02f317 (diff)
parentfbf7974427910a3f13fcb76a3493f9da0b141120 (diff)
Merge remote-tracking branch 'regulator/topic/pwm' into regulator-drivers
Conflicts: drivers/regulator/Kconfig
-rw-r--r--Documentation/devicetree/bindings/regulator/pwm-regulator.txt27
-rw-r--r--drivers/regulator/Kconfig13
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/pwm-regulator.c197
-rw-r--r--drivers/regulator/st-pwm.c190
5 files changed, 232 insertions, 197 deletions
diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt
new file mode 100644
index 000000000000..ce91f61feb12
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt
@@ -0,0 +1,27 @@
1pwm regulator bindings
2
3Required properties:
4- compatible: Should be "pwm-regulator"
5- pwms: OF device-tree PWM specification (see PWM binding pwm.txt)
6- voltage-table: voltage and duty table, include 2 members in each set of
7 brackets, first one is voltage(unit: uv), the next is duty(unit: percent)
8
9Any property defined as part of the core regulator binding defined in
10regulator.txt can also be used.
11
12Example:
13 pwm_regulator {
14 compatible = "pwm-regulator;
15 pwms = <&pwm1 0 8448 0>;
16
17 voltage-table = <1114000 0>,
18 <1095000 10>,
19 <1076000 20>,
20 <1056000 30>,
21 <1036000 40>,
22 <1016000 50>;
23
24 regulator-min-microvolt = <1016000>;
25 regulator-max-microvolt = <1114000>;
26 regulator-name = "vdd_logic";
27 };
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 0e59754d8df2..c3ca05cb5c87 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -449,6 +449,13 @@ config REGULATOR_PFUZE100
449 Say y here to support the regulators found on the Freescale 449 Say y here to support the regulators found on the Freescale
450 PFUZE100/PFUZE200 PMIC. 450 PFUZE100/PFUZE200 PMIC.
451 451
452config REGULATOR_PWM
453 tristate "PWM voltage regulator"
454 depends on PWM
455 help
456 This driver supports PWM controlled voltage regulators. PWM
457 duty cycle can increase or decrease the voltage.
458
452config REGULATOR_QCOM_RPM 459config REGULATOR_QCOM_RPM
453 tristate "Qualcomm RPM regulator driver" 460 tristate "Qualcomm RPM regulator driver"
454 depends on MFD_QCOM_RPM 461 depends on MFD_QCOM_RPM
@@ -495,12 +502,6 @@ config REGULATOR_S5M8767
495 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and 502 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
496 supports DVS mode with 8bits of output voltage control. 503 supports DVS mode with 8bits of output voltage control.
497 504
498config REGULATOR_ST_PWM
499 tristate "STMicroelectronics PWM voltage regulator"
500 depends on ARCH_STI
501 help
502 This driver supports ST's PWM controlled voltage regulators.
503
504config REGULATOR_TI_ABB 505config REGULATOR_TI_ABB
505 tristate "TI Adaptive Body Bias on-chip LDO" 506 tristate "TI Adaptive Body Bias on-chip LDO"
506 depends on ARCH_OMAP 507 depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 9c50dc61d927..2f49356e03a7 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
58obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o 58obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
59obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 59obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
60obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o 60obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
61obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
61obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o 62obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
62obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o 63obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
63obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o 64obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
@@ -66,7 +67,6 @@ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
66obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o 67obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
67obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o 68obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
68obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o 69obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
69obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
70obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o 70obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
71obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o 71obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
72obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o 72obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
new file mode 100644
index 000000000000..d3f55eaea058
--- /dev/null
+++ b/drivers/regulator/pwm-regulator.c
@@ -0,0 +1,197 @@
1/*
2 * Regulator driver for PWM Regulators
3 *
4 * Copyright (C) 2014 - STMicroelectronics Inc.
5 *
6 * Author: Lee Jones <lee.jones@linaro.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/regulator/driver.h>
17#include <linux/regulator/machine.h>
18#include <linux/regulator/of_regulator.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21#include <linux/pwm.h>
22
23struct pwm_regulator_data {
24 struct regulator_desc desc;
25 struct pwm_voltages *duty_cycle_table;
26 struct pwm_device *pwm;
27 bool enabled;
28 int state;
29};
30
31struct pwm_voltages {
32 unsigned int uV;
33 unsigned int dutycycle;
34};
35
36static int pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
37{
38 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
39
40 return drvdata->state;
41}
42
43static int pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
44 unsigned selector)
45{
46 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
47 unsigned int pwm_reg_period;
48 int dutycycle;
49 int ret;
50
51 pwm_reg_period = pwm_get_period(drvdata->pwm);
52
53 dutycycle = (pwm_reg_period *
54 drvdata->duty_cycle_table[selector].dutycycle) / 100;
55
56 ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
57 if (ret) {
58 dev_err(&dev->dev, "Failed to configure PWM\n");
59 return ret;
60 }
61
62 drvdata->state = selector;
63
64 if (!drvdata->enabled) {
65 ret = pwm_enable(drvdata->pwm);
66 if (ret) {
67 dev_err(&dev->dev, "Failed to enable PWM\n");
68 return ret;
69 }
70 drvdata->enabled = true;
71 }
72
73 return 0;
74}
75
76static int pwm_regulator_list_voltage(struct regulator_dev *dev,
77 unsigned selector)
78{
79 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
80
81 if (selector >= drvdata->desc.n_voltages)
82 return -EINVAL;
83
84 return drvdata->duty_cycle_table[selector].uV;
85}
86
87static struct regulator_ops pwm_regulator_voltage_ops = {
88 .set_voltage_sel = pwm_regulator_set_voltage_sel,
89 .get_voltage_sel = pwm_regulator_get_voltage_sel,
90 .list_voltage = pwm_regulator_list_voltage,
91 .map_voltage = regulator_map_voltage_iterate,
92};
93
94static const struct regulator_desc pwm_regulator_desc = {
95 .name = "pwm-regulator",
96 .ops = &pwm_regulator_voltage_ops,
97 .type = REGULATOR_VOLTAGE,
98 .owner = THIS_MODULE,
99 .supply_name = "pwm",
100};
101
102static int pwm_regulator_probe(struct platform_device *pdev)
103{
104 struct pwm_regulator_data *drvdata;
105 struct property *prop;
106 struct regulator_dev *regulator;
107 struct regulator_config config = { };
108 struct device_node *np = pdev->dev.of_node;
109 int length, ret;
110
111 if (!np) {
112 dev_err(&pdev->dev, "Device Tree node missing\n");
113 return -EINVAL;
114 }
115
116 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
117 if (!drvdata)
118 return -ENOMEM;
119
120 memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(pwm_regulator_desc));
121
122 /* determine the number of voltage-table */
123 prop = of_find_property(np, "voltage-table", &length);
124 if (!prop) {
125 dev_err(&pdev->dev, "No voltage-table\n");
126 return -EINVAL;
127 }
128
129 if ((length < sizeof(*drvdata->duty_cycle_table)) ||
130 (length % sizeof(*drvdata->duty_cycle_table))) {
131 dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
132 length);
133 return -EINVAL;
134 }
135
136 drvdata->desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table);
137
138 drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev,
139 length, GFP_KERNEL);
140 if (!drvdata->duty_cycle_table)
141 return -ENOMEM;
142
143 /* read voltage table from DT property */
144 ret = of_property_read_u32_array(np, "voltage-table",
145 (u32 *)drvdata->duty_cycle_table,
146 length / sizeof(u32));
147 if (ret < 0) {
148 dev_err(&pdev->dev, "read voltage-table failed\n");
149 return ret;
150 }
151
152 config.init_data = of_get_regulator_init_data(&pdev->dev, np);
153 if (!config.init_data)
154 return -ENOMEM;
155
156 config.of_node = np;
157 config.dev = &pdev->dev;
158 config.driver_data = drvdata;
159
160 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
161 if (IS_ERR(drvdata->pwm)) {
162 dev_err(&pdev->dev, "Failed to get PWM\n");
163 return PTR_ERR(drvdata->pwm);
164 }
165
166 regulator = devm_regulator_register(&pdev->dev,
167 &drvdata->desc, &config);
168 if (IS_ERR(regulator)) {
169 dev_err(&pdev->dev, "Failed to register regulator %s\n",
170 drvdata->desc.name);
171 return PTR_ERR(regulator);
172 }
173
174 return 0;
175}
176
177static const struct of_device_id pwm_of_match[] = {
178 { .compatible = "pwm-regulator" },
179 { },
180};
181MODULE_DEVICE_TABLE(of, pwm_of_match);
182
183static struct platform_driver pwm_regulator_driver = {
184 .driver = {
185 .name = "pwm-regulator",
186 .owner = THIS_MODULE,
187 .of_match_table = of_match_ptr(pwm_of_match),
188 },
189 .probe = pwm_regulator_probe,
190};
191
192module_platform_driver(pwm_regulator_driver);
193
194MODULE_LICENSE("GPL");
195MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
196MODULE_DESCRIPTION("PWM Regulator Driver");
197MODULE_ALIAS("platform:pwm-regulator");
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
deleted file mode 100644
index 5ea78df449f8..000000000000
--- a/drivers/regulator/st-pwm.c
+++ /dev/null
@@ -1,190 +0,0 @@
1/*
2 * Regulator driver for ST's PWM Regulators
3 *
4 * Copyright (C) 2014 - STMicroelectronics Inc.
5 *
6 * Author: Lee Jones <lee.jones@linaro.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/regulator/driver.h>
17#include <linux/regulator/machine.h>
18#include <linux/regulator/of_regulator.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21#include <linux/pwm.h>
22
23#define ST_PWM_REG_PERIOD 8448
24
25struct st_pwm_regulator_pdata {
26 const struct regulator_desc *desc;
27 struct st_pwm_voltages *duty_cycle_table;
28};
29
30struct st_pwm_regulator_data {
31 const struct st_pwm_regulator_pdata *pdata;
32 struct pwm_device *pwm;
33 bool enabled;
34 int state;
35};
36
37struct st_pwm_voltages {
38 unsigned int uV;
39 unsigned int dutycycle;
40};
41
42static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
43{
44 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
45
46 return drvdata->state;
47}
48
49static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
50 unsigned selector)
51{
52 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
53 int dutycycle;
54 int ret;
55
56 dutycycle = (ST_PWM_REG_PERIOD / 100) *
57 drvdata->pdata->duty_cycle_table[selector].dutycycle;
58
59 ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
60 if (ret) {
61 dev_err(&dev->dev, "Failed to configure PWM\n");
62 return ret;
63 }
64
65 drvdata->state = selector;
66
67 if (!drvdata->enabled) {
68 ret = pwm_enable(drvdata->pwm);
69 if (ret) {
70 dev_err(&dev->dev, "Failed to enable PWM\n");
71 return ret;
72 }
73 drvdata->enabled = true;
74 }
75
76 return 0;
77}
78
79static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
80 unsigned selector)
81{
82 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
83
84 if (selector >= dev->desc->n_voltages)
85 return -EINVAL;
86
87 return drvdata->pdata->duty_cycle_table[selector].uV;
88}
89
90static struct regulator_ops st_pwm_regulator_voltage_ops = {
91 .set_voltage_sel = st_pwm_regulator_set_voltage_sel,
92 .get_voltage_sel = st_pwm_regulator_get_voltage_sel,
93 .list_voltage = st_pwm_regulator_list_voltage,
94 .map_voltage = regulator_map_voltage_iterate,
95};
96
97static struct st_pwm_voltages b2105_duty_cycle_table[] = {
98 { .uV = 1114000, .dutycycle = 0, },
99 { .uV = 1095000, .dutycycle = 10, },
100 { .uV = 1076000, .dutycycle = 20, },
101 { .uV = 1056000, .dutycycle = 30, },
102 { .uV = 1036000, .dutycycle = 40, },
103 { .uV = 1016000, .dutycycle = 50, },
104 /* WARNING: Values above 50% duty-cycle cause boot failures. */
105};
106
107static const struct regulator_desc b2105_desc = {
108 .name = "b2105-pwm-regulator",
109 .ops = &st_pwm_regulator_voltage_ops,
110 .type = REGULATOR_VOLTAGE,
111 .owner = THIS_MODULE,
112 .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table),
113 .supply_name = "pwm",
114};
115
116static const struct st_pwm_regulator_pdata b2105_info = {
117 .desc = &b2105_desc,
118 .duty_cycle_table = b2105_duty_cycle_table,
119};
120
121static const struct of_device_id st_pwm_of_match[] = {
122 { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
123 { },
124};
125MODULE_DEVICE_TABLE(of, st_pwm_of_match);
126
127static int st_pwm_regulator_probe(struct platform_device *pdev)
128{
129 struct st_pwm_regulator_data *drvdata;
130 struct regulator_dev *regulator;
131 struct regulator_config config = { };
132 struct device_node *np = pdev->dev.of_node;
133 const struct of_device_id *of_match;
134
135 if (!np) {
136 dev_err(&pdev->dev, "Device Tree node missing\n");
137 return -EINVAL;
138 }
139
140 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
141 if (!drvdata)
142 return -ENOMEM;
143
144 of_match = of_match_device(st_pwm_of_match, &pdev->dev);
145 if (!of_match) {
146 dev_err(&pdev->dev, "failed to match of device\n");
147 return -ENODEV;
148 }
149 drvdata->pdata = of_match->data;
150
151 config.init_data = of_get_regulator_init_data(&pdev->dev, np);
152 if (!config.init_data)
153 return -ENOMEM;
154
155 config.of_node = np;
156 config.dev = &pdev->dev;
157 config.driver_data = drvdata;
158
159 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
160 if (IS_ERR(drvdata->pwm)) {
161 dev_err(&pdev->dev, "Failed to get PWM\n");
162 return PTR_ERR(drvdata->pwm);
163 }
164
165 regulator = devm_regulator_register(&pdev->dev,
166 drvdata->pdata->desc, &config);
167 if (IS_ERR(regulator)) {
168 dev_err(&pdev->dev, "Failed to register regulator %s\n",
169 drvdata->pdata->desc->name);
170 return PTR_ERR(regulator);
171 }
172
173 return 0;
174}
175
176static struct platform_driver st_pwm_regulator_driver = {
177 .driver = {
178 .name = "st-pwm-regulator",
179 .owner = THIS_MODULE,
180 .of_match_table = of_match_ptr(st_pwm_of_match),
181 },
182 .probe = st_pwm_regulator_probe,
183};
184
185module_platform_driver(st_pwm_regulator_driver);
186
187MODULE_LICENSE("GPL");
188MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
189MODULE_DESCRIPTION("ST PWM Regulator Driver");
190MODULE_ALIAS("platform:st_pwm-regulator");