xref: /linux/drivers/regulator/pwm-regulator.c (revision cae897dec26a9d81dcb5182b13b08450f38d6bde)
1aa66cc66SChris Zhong /*
2aa66cc66SChris Zhong  * Regulator driver for PWM Regulators
3aa66cc66SChris Zhong  *
4aa66cc66SChris Zhong  * Copyright (C) 2014 - STMicroelectronics Inc.
5aa66cc66SChris Zhong  *
6aa66cc66SChris Zhong  * Author: Lee Jones <lee.jones@linaro.org>
7aa66cc66SChris Zhong  *
8aa66cc66SChris Zhong  * This program is free software; you can redistribute it and/or modify
9aa66cc66SChris Zhong  * it under the terms of the GNU General Public License version 2 as
10aa66cc66SChris Zhong  * published by the Free Software Foundation.
11aa66cc66SChris Zhong  */
12aa66cc66SChris Zhong 
134773be18SLee Jones #include <linux/delay.h>
14aa66cc66SChris Zhong #include <linux/module.h>
15aa66cc66SChris Zhong #include <linux/init.h>
16aa66cc66SChris Zhong #include <linux/err.h>
17aa66cc66SChris Zhong #include <linux/regulator/driver.h>
18aa66cc66SChris Zhong #include <linux/regulator/machine.h>
19aa66cc66SChris Zhong #include <linux/regulator/of_regulator.h>
20aa66cc66SChris Zhong #include <linux/of.h>
21aa66cc66SChris Zhong #include <linux/of_device.h>
22aa66cc66SChris Zhong #include <linux/pwm.h>
23aa66cc66SChris Zhong 
24aa66cc66SChris Zhong struct pwm_regulator_data {
254773be18SLee Jones 	/*  Shared */
26aa66cc66SChris Zhong 	struct pwm_device *pwm;
274773be18SLee Jones 
284773be18SLee Jones 	/* Voltage table */
294773be18SLee Jones 	struct pwm_voltages *duty_cycle_table;
30aa66cc66SChris Zhong 	int state;
314773be18SLee Jones 
324773be18SLee Jones 	/* Continuous voltage */
334773be18SLee Jones 	u32 max_duty_cycle;
344773be18SLee Jones 	int volt_uV;
35aa66cc66SChris Zhong };
36aa66cc66SChris Zhong 
37aa66cc66SChris Zhong struct pwm_voltages {
38aa66cc66SChris Zhong 	unsigned int uV;
39aa66cc66SChris Zhong 	unsigned int dutycycle;
40aa66cc66SChris Zhong };
41aa66cc66SChris Zhong 
424773be18SLee Jones /**
434773be18SLee Jones  * Voltage table call-backs
444773be18SLee Jones  */
45ab101e35SLee Jones static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
46aa66cc66SChris Zhong {
47ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
48aa66cc66SChris Zhong 
49aa66cc66SChris Zhong 	return drvdata->state;
50aa66cc66SChris Zhong }
51aa66cc66SChris Zhong 
52ab101e35SLee Jones static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
53aa66cc66SChris Zhong 					 unsigned selector)
54aa66cc66SChris Zhong {
55ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
56aa66cc66SChris Zhong 	unsigned int pwm_reg_period;
57aa66cc66SChris Zhong 	int dutycycle;
58aa66cc66SChris Zhong 	int ret;
59aa66cc66SChris Zhong 
60aa66cc66SChris Zhong 	pwm_reg_period = pwm_get_period(drvdata->pwm);
61aa66cc66SChris Zhong 
62aa66cc66SChris Zhong 	dutycycle = (pwm_reg_period *
63aa66cc66SChris Zhong 		    drvdata->duty_cycle_table[selector].dutycycle) / 100;
64aa66cc66SChris Zhong 
65aa66cc66SChris Zhong 	ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
66aa66cc66SChris Zhong 	if (ret) {
67ab101e35SLee Jones 		dev_err(&rdev->dev, "Failed to configure PWM\n");
68aa66cc66SChris Zhong 		return ret;
69aa66cc66SChris Zhong 	}
70aa66cc66SChris Zhong 
71aa66cc66SChris Zhong 	drvdata->state = selector;
72aa66cc66SChris Zhong 
73aa66cc66SChris Zhong 	ret = pwm_enable(drvdata->pwm);
74aa66cc66SChris Zhong 	if (ret) {
75ab101e35SLee Jones 		dev_err(&rdev->dev, "Failed to enable PWM\n");
76aa66cc66SChris Zhong 		return ret;
77aa66cc66SChris Zhong 	}
78aa66cc66SChris Zhong 
79aa66cc66SChris Zhong 	return 0;
80aa66cc66SChris Zhong }
81aa66cc66SChris Zhong 
82ab101e35SLee Jones static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
83aa66cc66SChris Zhong 				      unsigned selector)
84aa66cc66SChris Zhong {
85ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
86aa66cc66SChris Zhong 
87ab101e35SLee Jones 	if (selector >= rdev->desc->n_voltages)
88aa66cc66SChris Zhong 		return -EINVAL;
89aa66cc66SChris Zhong 
90aa66cc66SChris Zhong 	return drvdata->duty_cycle_table[selector].uV;
91aa66cc66SChris Zhong }
924773be18SLee Jones 
934773be18SLee Jones /**
944773be18SLee Jones  * Continuous voltage call-backs
954773be18SLee Jones  */
96*cae897deSLee Jones static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, int req_uV)
974773be18SLee Jones {
98*cae897deSLee Jones 	int min_uV = rdev->constraints->min_uV;
99*cae897deSLee Jones 	int max_uV = rdev->constraints->max_uV;
100*cae897deSLee Jones 	int diff = max_uV - min_uV;
1014773be18SLee Jones 
102*cae897deSLee Jones 	return 100 - ((((req_uV * 100) - (min_uV * 100)) / diff));
1034773be18SLee Jones }
1044773be18SLee Jones 
1054773be18SLee Jones static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
1064773be18SLee Jones {
1074773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1084773be18SLee Jones 
1094773be18SLee Jones 	return drvdata->volt_uV;
1104773be18SLee Jones }
1114773be18SLee Jones 
1124773be18SLee Jones static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
1134773be18SLee Jones 					int min_uV, int max_uV,
1144773be18SLee Jones 					unsigned *selector)
1154773be18SLee Jones {
1164773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1174773be18SLee Jones 	unsigned int ramp_delay = rdev->constraints->ramp_delay;
1184773be18SLee Jones 	int duty_cycle;
1194773be18SLee Jones 	int ret;
1204773be18SLee Jones 
121*cae897deSLee Jones 	duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV);
1224773be18SLee Jones 
1234773be18SLee Jones 	ret = pwm_config(drvdata->pwm,
1244773be18SLee Jones 			 (drvdata->pwm->period / 100) * duty_cycle,
1254773be18SLee Jones 			 drvdata->pwm->period);
1264773be18SLee Jones 	if (ret) {
1274773be18SLee Jones 		dev_err(&rdev->dev, "Failed to configure PWM\n");
1284773be18SLee Jones 		return ret;
1294773be18SLee Jones 	}
1304773be18SLee Jones 
1314773be18SLee Jones 	ret = pwm_enable(drvdata->pwm);
1324773be18SLee Jones 	if (ret) {
1334773be18SLee Jones 		dev_err(&rdev->dev, "Failed to enable PWM\n");
1344773be18SLee Jones 		return ret;
1354773be18SLee Jones 	}
1364773be18SLee Jones 	drvdata->volt_uV = min_uV;
1374773be18SLee Jones 
1384773be18SLee Jones 	/* Delay required by PWM regulator to settle to the new voltage */
1394773be18SLee Jones 	usleep_range(ramp_delay, ramp_delay + 1000);
1404773be18SLee Jones 
1414773be18SLee Jones 	return 0;
1424773be18SLee Jones }
1434773be18SLee Jones 
144f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = {
145aa66cc66SChris Zhong 	.set_voltage_sel = pwm_regulator_set_voltage_sel,
146aa66cc66SChris Zhong 	.get_voltage_sel = pwm_regulator_get_voltage_sel,
147aa66cc66SChris Zhong 	.list_voltage    = pwm_regulator_list_voltage,
148aa66cc66SChris Zhong 	.map_voltage     = regulator_map_voltage_iterate,
149aa66cc66SChris Zhong };
150aa66cc66SChris Zhong 
1514773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
1524773be18SLee Jones 	.get_voltage = pwm_regulator_get_voltage,
1534773be18SLee Jones 	.set_voltage = pwm_regulator_set_voltage,
1544773be18SLee Jones };
1554773be18SLee Jones 
156b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = {
157aa66cc66SChris Zhong 	.name		= "pwm-regulator",
158aa66cc66SChris Zhong 	.type		= REGULATOR_VOLTAGE,
159aa66cc66SChris Zhong 	.owner		= THIS_MODULE,
160aa66cc66SChris Zhong 	.supply_name    = "pwm",
161aa66cc66SChris Zhong };
162aa66cc66SChris Zhong 
163f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev,
164f9178dadSLee Jones 				    struct pwm_regulator_data *drvdata)
165f9178dadSLee Jones {
166f9178dadSLee Jones 	struct device_node *np = pdev->dev.of_node;
167f9178dadSLee Jones 	struct pwm_voltages *duty_cycle_table;
168f9178dadSLee Jones 	int length;
169f9178dadSLee Jones 	int ret;
170f9178dadSLee Jones 
171f9178dadSLee Jones 	of_find_property(np, "voltage-table", &length);
172f9178dadSLee Jones 
173f9178dadSLee Jones 	if ((length < sizeof(*duty_cycle_table)) ||
174f9178dadSLee Jones 	    (length % sizeof(*duty_cycle_table))) {
175f9178dadSLee Jones 		dev_err(&pdev->dev,
176f9178dadSLee Jones 			"voltage-table length(%d) is invalid\n",
177f9178dadSLee Jones 			length);
178f9178dadSLee Jones 		return -EINVAL;
179f9178dadSLee Jones 	}
180f9178dadSLee Jones 
181f9178dadSLee Jones 	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
182f9178dadSLee Jones 	if (!duty_cycle_table)
183f9178dadSLee Jones 		return -ENOMEM;
184f9178dadSLee Jones 
185f9178dadSLee Jones 	ret = of_property_read_u32_array(np, "voltage-table",
186f9178dadSLee Jones 					 (u32 *)duty_cycle_table,
187f9178dadSLee Jones 					 length / sizeof(u32));
188f9178dadSLee Jones 	if (ret) {
189f9178dadSLee Jones 		dev_err(&pdev->dev, "Failed to read voltage-table\n");
190f9178dadSLee Jones 		return ret;
191f9178dadSLee Jones 	}
192f9178dadSLee Jones 
193f9178dadSLee Jones 	drvdata->duty_cycle_table	= duty_cycle_table;
194f9178dadSLee Jones 	pwm_regulator_desc.ops		= &pwm_regulator_voltage_table_ops;
195f9178dadSLee Jones 	pwm_regulator_desc.n_voltages	= length / sizeof(*duty_cycle_table);
196f9178dadSLee Jones 
197f9178dadSLee Jones 	return 0;
198f9178dadSLee Jones }
199f9178dadSLee Jones 
2004773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev,
2014773be18SLee Jones 					 struct pwm_regulator_data *drvdata)
2024773be18SLee Jones {
2034773be18SLee Jones 	struct device_node *np = pdev->dev.of_node;
2044773be18SLee Jones 	int ret;
2054773be18SLee Jones 
2064773be18SLee Jones 	ret = of_property_read_u32(np, "max-duty-cycle",
2074773be18SLee Jones 				   &drvdata->max_duty_cycle);
2084773be18SLee Jones 	if (ret) {
2094773be18SLee Jones 		dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n");
2104773be18SLee Jones 		return ret;
2114773be18SLee Jones 	}
2124773be18SLee Jones 
2134773be18SLee Jones 	pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops;
2144773be18SLee Jones 	pwm_regulator_desc.continuous_voltage_range = true;
2154773be18SLee Jones 
2164773be18SLee Jones 	return 0;
2174773be18SLee Jones }
2184773be18SLee Jones 
219aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev)
220aa66cc66SChris Zhong {
221aa66cc66SChris Zhong 	struct pwm_regulator_data *drvdata;
222aa66cc66SChris Zhong 	struct regulator_dev *regulator;
223aa66cc66SChris Zhong 	struct regulator_config config = { };
224aa66cc66SChris Zhong 	struct device_node *np = pdev->dev.of_node;
225f9178dadSLee Jones 	int ret;
226aa66cc66SChris Zhong 
227aa66cc66SChris Zhong 	if (!np) {
228aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Device Tree node missing\n");
229aa66cc66SChris Zhong 		return -EINVAL;
230aa66cc66SChris Zhong 	}
231aa66cc66SChris Zhong 
232aa66cc66SChris Zhong 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
233aa66cc66SChris Zhong 	if (!drvdata)
234aa66cc66SChris Zhong 		return -ENOMEM;
235aa66cc66SChris Zhong 
2364773be18SLee Jones 	if (of_find_property(np, "voltage-table", NULL))
237f9178dadSLee Jones 		ret = pwm_regulator_init_table(pdev, drvdata);
2384773be18SLee Jones 	else
2394773be18SLee Jones 		ret = pwm_regulator_init_continuous(pdev, drvdata);
240f9178dadSLee Jones 	if (ret)
241aa66cc66SChris Zhong 		return ret;
242aa66cc66SChris Zhong 
243072e78b1SJavier Martinez Canillas 	config.init_data = of_get_regulator_init_data(&pdev->dev, np,
244b6f55e74SLee Jones 						      &pwm_regulator_desc);
245aa66cc66SChris Zhong 	if (!config.init_data)
246aa66cc66SChris Zhong 		return -ENOMEM;
247aa66cc66SChris Zhong 
248aa66cc66SChris Zhong 	config.of_node = np;
249aa66cc66SChris Zhong 	config.dev = &pdev->dev;
250aa66cc66SChris Zhong 	config.driver_data = drvdata;
251aa66cc66SChris Zhong 
252aa66cc66SChris Zhong 	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
253aa66cc66SChris Zhong 	if (IS_ERR(drvdata->pwm)) {
254aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Failed to get PWM\n");
255aa66cc66SChris Zhong 		return PTR_ERR(drvdata->pwm);
256aa66cc66SChris Zhong 	}
257aa66cc66SChris Zhong 
258aa66cc66SChris Zhong 	regulator = devm_regulator_register(&pdev->dev,
259b6f55e74SLee Jones 					    &pwm_regulator_desc, &config);
260aa66cc66SChris Zhong 	if (IS_ERR(regulator)) {
261aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Failed to register regulator %s\n",
262b6f55e74SLee Jones 			pwm_regulator_desc.name);
263aa66cc66SChris Zhong 		return PTR_ERR(regulator);
264aa66cc66SChris Zhong 	}
265aa66cc66SChris Zhong 
266aa66cc66SChris Zhong 	return 0;
267aa66cc66SChris Zhong }
268aa66cc66SChris Zhong 
269aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = {
270aa66cc66SChris Zhong 	{ .compatible = "pwm-regulator" },
271aa66cc66SChris Zhong 	{ },
272aa66cc66SChris Zhong };
273aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match);
274aa66cc66SChris Zhong 
275aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = {
276aa66cc66SChris Zhong 	.driver = {
277aa66cc66SChris Zhong 		.name		= "pwm-regulator",
278aa66cc66SChris Zhong 		.of_match_table = of_match_ptr(pwm_of_match),
279aa66cc66SChris Zhong 	},
280aa66cc66SChris Zhong 	.probe = pwm_regulator_probe,
281aa66cc66SChris Zhong };
282aa66cc66SChris Zhong 
283aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver);
284aa66cc66SChris Zhong 
285aa66cc66SChris Zhong MODULE_LICENSE("GPL");
286aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
287aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver");
288aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator");
289