aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/pwm-regulator.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-07 21:07:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-07 21:07:48 -0400
commit81e29b7d1be91ac78e561659171dd79af042aafd (patch)
tree469cf08ed4e744e1b7f76821af82d06c0d173b7b /drivers/regulator/pwm-regulator.c
parentc831dd7352c0eedb270b9b6430590da5991bb65c (diff)
parentad21edcdb2172c0d8f47f856867104e331525820 (diff)
Merge tag 'regulator-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown: "This time around most of the changes are a lot of new drivers along with the standard set of fixes and cleanups (thanks again largely to Axel Lin). We do have one nice new feature in the core which factors out the disappointingly tricky code around DT parsing, only a couple of drivers have been converted so far: - Factor out the code for parsing the standard bindings for a set of regulators out of DT, making the probe part of a lot of drivers simplier. - New drivers for Dialog DA9213, HiSilicon HI6420, Intersil ISL9305/H, Ricoh RN5T618, Rockchip RK808, Skyworks SKY81452, Silergy SYR82x, and Qualcomm RPM" * tag 'regulator-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (71 commits) regulator: da9211: Fix a bug in update of mask bit regulator: pwm-regulator: add devicetree bindings for pwm regulator regulator: pwm-regulator: get voltage and duty table from dts regulator: qcom_rpm: Fix FORCE_MODE_IS_2_BITS macro regulator: qcom_rpm: Don't explicitly initialise the first field of config regulator: ltc3589: fix broken voltage transitions regulator: qcom-rpm: Regulator driver for the Qualcomm RPM regulator: axp20x: Use parent device as regulator configuration device regulator: fan53555: Fix null pointer dereference regulator: fan53555: Fixup report wrong vendor message regulator: fan53555: fix wrong cast in probe regulator: fan53555: add support for Silergy SYR82x regulators regulator: fan53555: add devicetree support regulator: add devicetree bindings for Fairchild FAN53555 regulators regulator: rk808: Add function for ramp delay for buck1/buck2 regulator: fan53555: use set_ramp_delay to set the ramp up slew rate regulator: fan53555: enable vin supply regulator: rk808: Fix missing of_node_put regulator: rk808: Remove unused variables regulator: of: Add stub OF match function for !OF case ...
Diffstat (limited to 'drivers/regulator/pwm-regulator.c')
-rw-r--r--drivers/regulator/pwm-regulator.c197
1 files changed, 197 insertions, 0 deletions
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");