xref: /linux/drivers/regulator/pwm-regulator.c (revision f907a0a9498db29fb7c91b798d7af70add7dd86e)
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;
30*f907a0a9SLaxman Dewangan 
31*f907a0a9SLaxman Dewangan 	/* regulator descriptor */
32*f907a0a9SLaxman Dewangan 	struct regulator_desc desc;
33*f907a0a9SLaxman Dewangan 
34*f907a0a9SLaxman Dewangan 	/* Regulator ops */
35*f907a0a9SLaxman Dewangan 	struct regulator_ops ops;
36*f907a0a9SLaxman Dewangan 
37aa66cc66SChris Zhong 	int state;
384773be18SLee Jones 
394773be18SLee Jones 	/* Continuous voltage */
404773be18SLee Jones 	int volt_uV;
41aa66cc66SChris Zhong };
42aa66cc66SChris Zhong 
43aa66cc66SChris Zhong struct pwm_voltages {
44aa66cc66SChris Zhong 	unsigned int uV;
45aa66cc66SChris Zhong 	unsigned int dutycycle;
46aa66cc66SChris Zhong };
47aa66cc66SChris Zhong 
484773be18SLee Jones /**
494773be18SLee Jones  * Voltage table call-backs
504773be18SLee Jones  */
51ab101e35SLee Jones static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
52aa66cc66SChris Zhong {
53ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
54aa66cc66SChris Zhong 
55aa66cc66SChris Zhong 	return drvdata->state;
56aa66cc66SChris Zhong }
57aa66cc66SChris Zhong 
58ab101e35SLee Jones static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
59aa66cc66SChris Zhong 					 unsigned selector)
60aa66cc66SChris Zhong {
61ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
62aa66cc66SChris Zhong 	unsigned int pwm_reg_period;
63aa66cc66SChris Zhong 	int dutycycle;
64aa66cc66SChris Zhong 	int ret;
65aa66cc66SChris Zhong 
66aa66cc66SChris Zhong 	pwm_reg_period = pwm_get_period(drvdata->pwm);
67aa66cc66SChris Zhong 
68aa66cc66SChris Zhong 	dutycycle = (pwm_reg_period *
69aa66cc66SChris Zhong 		    drvdata->duty_cycle_table[selector].dutycycle) / 100;
70aa66cc66SChris Zhong 
71aa66cc66SChris Zhong 	ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
72aa66cc66SChris Zhong 	if (ret) {
73ab101e35SLee Jones 		dev_err(&rdev->dev, "Failed to configure PWM\n");
74aa66cc66SChris Zhong 		return ret;
75aa66cc66SChris Zhong 	}
76aa66cc66SChris Zhong 
77aa66cc66SChris Zhong 	drvdata->state = selector;
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 
931de7d802SBoris Brezillon static int pwm_regulator_enable(struct regulator_dev *dev)
941de7d802SBoris Brezillon {
951de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
961de7d802SBoris Brezillon 
971de7d802SBoris Brezillon 	return pwm_enable(drvdata->pwm);
981de7d802SBoris Brezillon }
991de7d802SBoris Brezillon 
1001de7d802SBoris Brezillon static int pwm_regulator_disable(struct regulator_dev *dev)
1011de7d802SBoris Brezillon {
1021de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1031de7d802SBoris Brezillon 
1041de7d802SBoris Brezillon 	pwm_disable(drvdata->pwm);
1051de7d802SBoris Brezillon 
1061de7d802SBoris Brezillon 	return 0;
1071de7d802SBoris Brezillon }
1081de7d802SBoris Brezillon 
1091de7d802SBoris Brezillon static int pwm_regulator_is_enabled(struct regulator_dev *dev)
1101de7d802SBoris Brezillon {
1111de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1121de7d802SBoris Brezillon 
1131de7d802SBoris Brezillon 	return pwm_is_enabled(drvdata->pwm);
1141de7d802SBoris Brezillon }
1151de7d802SBoris Brezillon 
1164773be18SLee Jones /**
1174773be18SLee Jones  * Continuous voltage call-backs
1184773be18SLee Jones  */
119f3f6439dSLee Jones static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV)
1204773be18SLee Jones {
121cae897deSLee Jones 	int min_uV = rdev->constraints->min_uV;
122cae897deSLee Jones 	int max_uV = rdev->constraints->max_uV;
123cae897deSLee Jones 	int diff = max_uV - min_uV;
1244773be18SLee Jones 
1251aaab348SLaxman Dewangan 	return ((req_uV * 100) - (min_uV * 100)) / diff;
1264773be18SLee Jones }
1274773be18SLee Jones 
1284773be18SLee Jones static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
1294773be18SLee Jones {
1304773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1314773be18SLee Jones 
1324773be18SLee Jones 	return drvdata->volt_uV;
1334773be18SLee Jones }
1344773be18SLee Jones 
1354773be18SLee Jones static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
1364773be18SLee Jones 					int min_uV, int max_uV,
1374773be18SLee Jones 					unsigned *selector)
1384773be18SLee Jones {
1394773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1404773be18SLee Jones 	unsigned int ramp_delay = rdev->constraints->ramp_delay;
141f3f6439dSLee Jones 	unsigned int period = pwm_get_period(drvdata->pwm);
1424773be18SLee Jones 	int duty_cycle;
1434773be18SLee Jones 	int ret;
1444773be18SLee Jones 
145f3f6439dSLee Jones 	duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV);
1464773be18SLee Jones 
147f3f6439dSLee Jones 	ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period);
1484773be18SLee Jones 	if (ret) {
1494773be18SLee Jones 		dev_err(&rdev->dev, "Failed to configure PWM\n");
1504773be18SLee Jones 		return ret;
1514773be18SLee Jones 	}
1524773be18SLee Jones 
1534773be18SLee Jones 	ret = pwm_enable(drvdata->pwm);
1544773be18SLee Jones 	if (ret) {
1554773be18SLee Jones 		dev_err(&rdev->dev, "Failed to enable PWM\n");
1564773be18SLee Jones 		return ret;
1574773be18SLee Jones 	}
1584773be18SLee Jones 	drvdata->volt_uV = min_uV;
1594773be18SLee Jones 
1604773be18SLee Jones 	/* Delay required by PWM regulator to settle to the new voltage */
1614773be18SLee Jones 	usleep_range(ramp_delay, ramp_delay + 1000);
1624773be18SLee Jones 
1634773be18SLee Jones 	return 0;
1644773be18SLee Jones }
1654773be18SLee Jones 
166f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = {
167aa66cc66SChris Zhong 	.set_voltage_sel = pwm_regulator_set_voltage_sel,
168aa66cc66SChris Zhong 	.get_voltage_sel = pwm_regulator_get_voltage_sel,
169aa66cc66SChris Zhong 	.list_voltage    = pwm_regulator_list_voltage,
170aa66cc66SChris Zhong 	.map_voltage     = regulator_map_voltage_iterate,
1711de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1721de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1731de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
174aa66cc66SChris Zhong };
175aa66cc66SChris Zhong 
1764773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
1774773be18SLee Jones 	.get_voltage = pwm_regulator_get_voltage,
1784773be18SLee Jones 	.set_voltage = pwm_regulator_set_voltage,
1791de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1801de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1811de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
1824773be18SLee Jones };
1834773be18SLee Jones 
184b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = {
185aa66cc66SChris Zhong 	.name		= "pwm-regulator",
186aa66cc66SChris Zhong 	.type		= REGULATOR_VOLTAGE,
187aa66cc66SChris Zhong 	.owner		= THIS_MODULE,
188aa66cc66SChris Zhong 	.supply_name    = "pwm",
189aa66cc66SChris Zhong };
190aa66cc66SChris Zhong 
191f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev,
192f9178dadSLee Jones 				    struct pwm_regulator_data *drvdata)
193f9178dadSLee Jones {
194f9178dadSLee Jones 	struct device_node *np = pdev->dev.of_node;
195f9178dadSLee Jones 	struct pwm_voltages *duty_cycle_table;
19660cb65ebSLee Jones 	unsigned int length = 0;
197f9178dadSLee Jones 	int ret;
198f9178dadSLee Jones 
199f9178dadSLee Jones 	of_find_property(np, "voltage-table", &length);
200f9178dadSLee Jones 
201f9178dadSLee Jones 	if ((length < sizeof(*duty_cycle_table)) ||
202f9178dadSLee Jones 	    (length % sizeof(*duty_cycle_table))) {
203f9178dadSLee Jones 		dev_err(&pdev->dev,
204f9178dadSLee Jones 			"voltage-table length(%d) is invalid\n",
205f9178dadSLee Jones 			length);
206f9178dadSLee Jones 		return -EINVAL;
207f9178dadSLee Jones 	}
208f9178dadSLee Jones 
209f9178dadSLee Jones 	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
210f9178dadSLee Jones 	if (!duty_cycle_table)
211f9178dadSLee Jones 		return -ENOMEM;
212f9178dadSLee Jones 
213f9178dadSLee Jones 	ret = of_property_read_u32_array(np, "voltage-table",
214f9178dadSLee Jones 					 (u32 *)duty_cycle_table,
215f9178dadSLee Jones 					 length / sizeof(u32));
216f9178dadSLee Jones 	if (ret) {
217f9178dadSLee Jones 		dev_err(&pdev->dev, "Failed to read voltage-table\n");
218f9178dadSLee Jones 		return ret;
219f9178dadSLee Jones 	}
220f9178dadSLee Jones 
221f9178dadSLee Jones 	drvdata->duty_cycle_table	= duty_cycle_table;
222*f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
223*f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
224*f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
225*f907a0a9SLaxman Dewangan 	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
226f9178dadSLee Jones 
227f9178dadSLee Jones 	return 0;
228f9178dadSLee Jones }
229f9178dadSLee Jones 
2304773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev,
2314773be18SLee Jones 					 struct pwm_regulator_data *drvdata)
2324773be18SLee Jones {
233*f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
234*f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
235*f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
236*f907a0a9SLaxman Dewangan 	drvdata->desc.continuous_voltage_range = true;
2374773be18SLee Jones 
2384773be18SLee Jones 	return 0;
2394773be18SLee Jones }
2404773be18SLee Jones 
241aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev)
242aa66cc66SChris Zhong {
2435ad2cb14SLee Jones 	const struct regulator_init_data *init_data;
244aa66cc66SChris Zhong 	struct pwm_regulator_data *drvdata;
245aa66cc66SChris Zhong 	struct regulator_dev *regulator;
246aa66cc66SChris Zhong 	struct regulator_config config = { };
247aa66cc66SChris Zhong 	struct device_node *np = pdev->dev.of_node;
248f9178dadSLee Jones 	int ret;
249aa66cc66SChris Zhong 
250aa66cc66SChris Zhong 	if (!np) {
251aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Device Tree node missing\n");
252aa66cc66SChris Zhong 		return -EINVAL;
253aa66cc66SChris Zhong 	}
254aa66cc66SChris Zhong 
255aa66cc66SChris Zhong 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
256aa66cc66SChris Zhong 	if (!drvdata)
257aa66cc66SChris Zhong 		return -ENOMEM;
258aa66cc66SChris Zhong 
259*f907a0a9SLaxman Dewangan 	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
260*f907a0a9SLaxman Dewangan 
2614773be18SLee Jones 	if (of_find_property(np, "voltage-table", NULL))
262f9178dadSLee Jones 		ret = pwm_regulator_init_table(pdev, drvdata);
2634773be18SLee Jones 	else
2644773be18SLee Jones 		ret = pwm_regulator_init_continuous(pdev, drvdata);
265f9178dadSLee Jones 	if (ret)
266aa66cc66SChris Zhong 		return ret;
267aa66cc66SChris Zhong 
2685ad2cb14SLee Jones 	init_data = of_get_regulator_init_data(&pdev->dev, np,
269*f907a0a9SLaxman Dewangan 					       &drvdata->desc);
2705ad2cb14SLee Jones 	if (!init_data)
271aa66cc66SChris Zhong 		return -ENOMEM;
272aa66cc66SChris Zhong 
273aa66cc66SChris Zhong 	config.of_node = np;
274aa66cc66SChris Zhong 	config.dev = &pdev->dev;
275aa66cc66SChris Zhong 	config.driver_data = drvdata;
2765ad2cb14SLee Jones 	config.init_data = init_data;
277aa66cc66SChris Zhong 
278aa66cc66SChris Zhong 	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
279aa66cc66SChris Zhong 	if (IS_ERR(drvdata->pwm)) {
280aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Failed to get PWM\n");
281aa66cc66SChris Zhong 		return PTR_ERR(drvdata->pwm);
282aa66cc66SChris Zhong 	}
283aa66cc66SChris Zhong 
284aa66cc66SChris Zhong 	regulator = devm_regulator_register(&pdev->dev,
285*f907a0a9SLaxman Dewangan 					    &drvdata->desc, &config);
286aa66cc66SChris Zhong 	if (IS_ERR(regulator)) {
287aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Failed to register regulator %s\n",
288*f907a0a9SLaxman Dewangan 			drvdata->desc.name);
289aa66cc66SChris Zhong 		return PTR_ERR(regulator);
290aa66cc66SChris Zhong 	}
291aa66cc66SChris Zhong 
292aa66cc66SChris Zhong 	return 0;
293aa66cc66SChris Zhong }
294aa66cc66SChris Zhong 
295aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = {
296aa66cc66SChris Zhong 	{ .compatible = "pwm-regulator" },
297aa66cc66SChris Zhong 	{ },
298aa66cc66SChris Zhong };
299aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match);
300aa66cc66SChris Zhong 
301aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = {
302aa66cc66SChris Zhong 	.driver = {
303aa66cc66SChris Zhong 		.name		= "pwm-regulator",
304aa66cc66SChris Zhong 		.of_match_table = of_match_ptr(pwm_of_match),
305aa66cc66SChris Zhong 	},
306aa66cc66SChris Zhong 	.probe = pwm_regulator_probe,
307aa66cc66SChris Zhong };
308aa66cc66SChris Zhong 
309aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver);
310aa66cc66SChris Zhong 
311aa66cc66SChris Zhong MODULE_LICENSE("GPL");
312aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
313aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver");
314aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator");
315