diff options
author | Chris Zhong <zyw@rock-chips.com> | 2014-09-27 22:28:53 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2014-09-28 06:35:53 -0400 |
commit | aa66cc6630a4088e84b64992aa5f137711ae45fa (patch) | |
tree | ce2c2439297c720528c8e3aeeca6c6673f483aa0 /drivers | |
parent | 7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff) |
regulator: pwm-regulator: get voltage and duty table from dts
rename st-pwm to pwm-regulator. And support getting voltage & duty table from
device tree, other platforms can also use this driver without any modify.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/Kconfig | 13 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 2 | ||||
-rw-r--r-- | drivers/regulator/pwm-regulator.c | 197 | ||||
-rw-r--r-- | drivers/regulator/st-pwm.c | 190 |
4 files changed, 205 insertions, 197 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2dc8289e5dba..b0ff94a6e45d 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 | ||
452 | config 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 | |||
452 | config REGULATOR_RC5T583 | 459 | config REGULATOR_RC5T583 |
453 | tristate "RICOH RC5T583 Power regulators" | 460 | tristate "RICOH RC5T583 Power regulators" |
454 | depends on MFD_RC5T583 | 461 | depends on MFD_RC5T583 |
@@ -483,12 +490,6 @@ config REGULATOR_S5M8767 | |||
483 | via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and | 490 | via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and |
484 | supports DVS mode with 8bits of output voltage control. | 491 | supports DVS mode with 8bits of output voltage control. |
485 | 492 | ||
486 | config REGULATOR_ST_PWM | ||
487 | tristate "STMicroelectronics PWM voltage regulator" | ||
488 | depends on ARCH_STI | ||
489 | help | ||
490 | This driver supports ST's PWM controlled voltage regulators. | ||
491 | |||
492 | config REGULATOR_TI_ABB | 493 | config REGULATOR_TI_ABB |
493 | tristate "TI Adaptive Body Bias on-chip LDO" | 494 | tristate "TI Adaptive Body Bias on-chip LDO" |
494 | depends on ARCH_OMAP | 495 | depends on ARCH_OMAP |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index aa4a6aa7b558..516c36b67c59 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -57,6 +57,7 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o | |||
57 | obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o | 57 | obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o |
58 | obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o | 58 | obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o |
59 | obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o | 59 | obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o |
60 | obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o | ||
60 | obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o | 61 | obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o |
61 | obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o | 62 | obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o |
62 | obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o | 63 | obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o |
@@ -65,7 +66,6 @@ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o | |||
65 | obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o | 66 | obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o |
66 | obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o | 67 | obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o |
67 | obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o | 68 | obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o |
68 | obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o | ||
69 | obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o | 69 | obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o |
70 | obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o | 70 | obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o |
71 | obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o | 71 | obj-$(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 | |||
23 | struct 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 | |||
31 | struct pwm_voltages { | ||
32 | unsigned int uV; | ||
33 | unsigned int dutycycle; | ||
34 | }; | ||
35 | |||
36 | static 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 | |||
43 | static 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 | |||
76 | static 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 | |||
87 | static 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 | |||
94 | static 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 | |||
102 | static 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 | |||
177 | static const struct of_device_id pwm_of_match[] = { | ||
178 | { .compatible = "pwm-regulator" }, | ||
179 | { }, | ||
180 | }; | ||
181 | MODULE_DEVICE_TABLE(of, pwm_of_match); | ||
182 | |||
183 | static 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 | |||
192 | module_platform_driver(pwm_regulator_driver); | ||
193 | |||
194 | MODULE_LICENSE("GPL"); | ||
195 | MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); | ||
196 | MODULE_DESCRIPTION("PWM Regulator Driver"); | ||
197 | MODULE_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 | |||
25 | struct st_pwm_regulator_pdata { | ||
26 | const struct regulator_desc *desc; | ||
27 | struct st_pwm_voltages *duty_cycle_table; | ||
28 | }; | ||
29 | |||
30 | struct 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 | |||
37 | struct st_pwm_voltages { | ||
38 | unsigned int uV; | ||
39 | unsigned int dutycycle; | ||
40 | }; | ||
41 | |||
42 | static 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 | |||
49 | static 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 | |||
79 | static 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 | |||
90 | static 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 | |||
97 | static 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 | |||
107 | static 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 | |||
116 | static const struct st_pwm_regulator_pdata b2105_info = { | ||
117 | .desc = &b2105_desc, | ||
118 | .duty_cycle_table = b2105_duty_cycle_table, | ||
119 | }; | ||
120 | |||
121 | static const struct of_device_id st_pwm_of_match[] = { | ||
122 | { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, | ||
123 | { }, | ||
124 | }; | ||
125 | MODULE_DEVICE_TABLE(of, st_pwm_of_match); | ||
126 | |||
127 | static 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 | |||
176 | static 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 | |||
185 | module_platform_driver(st_pwm_regulator_driver); | ||
186 | |||
187 | MODULE_LICENSE("GPL"); | ||
188 | MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); | ||
189 | MODULE_DESCRIPTION("ST PWM Regulator Driver"); | ||
190 | MODULE_ALIAS("platform:st_pwm-regulator"); | ||