xref: /linux/drivers/regulator/pwm-regulator.c (revision 27bfa8893b15a3fa22a593c90a48c8bcb1f9c75b)
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>
23*27bfa889SAlexandre Courbot #include <linux/gpio/consumer.h>
24aa66cc66SChris Zhong 
25aa66cc66SChris Zhong struct pwm_regulator_data {
264773be18SLee Jones 	/*  Shared */
27aa66cc66SChris Zhong 	struct pwm_device *pwm;
284773be18SLee Jones 
294773be18SLee Jones 	/* Voltage table */
304773be18SLee Jones 	struct pwm_voltages *duty_cycle_table;
31f907a0a9SLaxman Dewangan 
32f907a0a9SLaxman Dewangan 	/* regulator descriptor */
33f907a0a9SLaxman Dewangan 	struct regulator_desc desc;
34f907a0a9SLaxman Dewangan 
35f907a0a9SLaxman Dewangan 	/* Regulator ops */
36f907a0a9SLaxman Dewangan 	struct regulator_ops ops;
37f907a0a9SLaxman Dewangan 
38aa66cc66SChris Zhong 	int state;
394773be18SLee Jones 
404773be18SLee Jones 	/* Continuous voltage */
414773be18SLee Jones 	int volt_uV;
42*27bfa889SAlexandre Courbot 
43*27bfa889SAlexandre Courbot 	/* Enable GPIO */
44*27bfa889SAlexandre Courbot 	struct gpio_desc *enb_gpio;
45aa66cc66SChris Zhong };
46aa66cc66SChris Zhong 
47aa66cc66SChris Zhong struct pwm_voltages {
48aa66cc66SChris Zhong 	unsigned int uV;
49aa66cc66SChris Zhong 	unsigned int dutycycle;
50aa66cc66SChris Zhong };
51aa66cc66SChris Zhong 
524773be18SLee Jones /**
534773be18SLee Jones  * Voltage table call-backs
544773be18SLee Jones  */
55ab101e35SLee Jones static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
56aa66cc66SChris Zhong {
57ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
58aa66cc66SChris Zhong 
59aa66cc66SChris Zhong 	return drvdata->state;
60aa66cc66SChris Zhong }
61aa66cc66SChris Zhong 
62ab101e35SLee Jones static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
63aa66cc66SChris Zhong 					 unsigned selector)
64aa66cc66SChris Zhong {
65ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
668c12ad8eSBoris Brezillon 	struct pwm_args pargs;
67aa66cc66SChris Zhong 	int dutycycle;
68aa66cc66SChris Zhong 	int ret;
69aa66cc66SChris Zhong 
708c12ad8eSBoris Brezillon 	pwm_get_args(drvdata->pwm, &pargs);
71aa66cc66SChris Zhong 
728c12ad8eSBoris Brezillon 	dutycycle = (pargs.period *
73aa66cc66SChris Zhong 		    drvdata->duty_cycle_table[selector].dutycycle) / 100;
74aa66cc66SChris Zhong 
758c12ad8eSBoris Brezillon 	ret = pwm_config(drvdata->pwm, dutycycle, pargs.period);
76aa66cc66SChris Zhong 	if (ret) {
775bf59bd5SLaxman Dewangan 		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
78aa66cc66SChris Zhong 		return ret;
79aa66cc66SChris Zhong 	}
80aa66cc66SChris Zhong 
81aa66cc66SChris Zhong 	drvdata->state = selector;
82aa66cc66SChris Zhong 
83aa66cc66SChris Zhong 	return 0;
84aa66cc66SChris Zhong }
85aa66cc66SChris Zhong 
86ab101e35SLee Jones static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
87aa66cc66SChris Zhong 				      unsigned selector)
88aa66cc66SChris Zhong {
89ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
90aa66cc66SChris Zhong 
91ab101e35SLee Jones 	if (selector >= rdev->desc->n_voltages)
92aa66cc66SChris Zhong 		return -EINVAL;
93aa66cc66SChris Zhong 
94aa66cc66SChris Zhong 	return drvdata->duty_cycle_table[selector].uV;
95aa66cc66SChris Zhong }
964773be18SLee Jones 
971de7d802SBoris Brezillon static int pwm_regulator_enable(struct regulator_dev *dev)
981de7d802SBoris Brezillon {
991de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1001de7d802SBoris Brezillon 
101*27bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
102*27bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
103*27bfa889SAlexandre Courbot 
1041de7d802SBoris Brezillon 	return pwm_enable(drvdata->pwm);
1051de7d802SBoris Brezillon }
1061de7d802SBoris Brezillon 
1071de7d802SBoris Brezillon static int pwm_regulator_disable(struct regulator_dev *dev)
1081de7d802SBoris Brezillon {
1091de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1101de7d802SBoris Brezillon 
1111de7d802SBoris Brezillon 	pwm_disable(drvdata->pwm);
1121de7d802SBoris Brezillon 
113*27bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
114*27bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
115*27bfa889SAlexandre Courbot 
1161de7d802SBoris Brezillon 	return 0;
1171de7d802SBoris Brezillon }
1181de7d802SBoris Brezillon 
1191de7d802SBoris Brezillon static int pwm_regulator_is_enabled(struct regulator_dev *dev)
1201de7d802SBoris Brezillon {
1211de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1221de7d802SBoris Brezillon 
123*27bfa889SAlexandre Courbot 	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
124*27bfa889SAlexandre Courbot 		return false;
125*27bfa889SAlexandre Courbot 
1261de7d802SBoris Brezillon 	return pwm_is_enabled(drvdata->pwm);
1271de7d802SBoris Brezillon }
1281de7d802SBoris Brezillon 
1294773be18SLee Jones static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
1304773be18SLee Jones {
1314773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1324773be18SLee Jones 
1334773be18SLee Jones 	return drvdata->volt_uV;
1344773be18SLee Jones }
1354773be18SLee Jones 
1364773be18SLee Jones static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
1374773be18SLee Jones 					int min_uV, int max_uV,
1384773be18SLee Jones 					unsigned *selector)
1394773be18SLee Jones {
1404773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1414773be18SLee Jones 	unsigned int ramp_delay = rdev->constraints->ramp_delay;
1428c12ad8eSBoris Brezillon 	struct pwm_args pargs;
143fd786fb0SLaxman Dewangan 	unsigned int req_diff = min_uV - rdev->constraints->min_uV;
144fd786fb0SLaxman Dewangan 	unsigned int diff;
145fd786fb0SLaxman Dewangan 	unsigned int duty_pulse;
146fd786fb0SLaxman Dewangan 	u64 req_period;
147fd786fb0SLaxman Dewangan 	u32 rem;
1484773be18SLee Jones 	int ret;
1494773be18SLee Jones 
1508c12ad8eSBoris Brezillon 	pwm_get_args(drvdata->pwm, &pargs);
151fd786fb0SLaxman Dewangan 	diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
1524773be18SLee Jones 
153fd786fb0SLaxman Dewangan 	/* First try to find out if we get the iduty cycle time which is
154fd786fb0SLaxman Dewangan 	 * factor of PWM period time. If (request_diff_to_min * pwm_period)
155fd786fb0SLaxman Dewangan 	 * is perfect divided by voltage_range_diff then it is possible to
156fd786fb0SLaxman Dewangan 	 * get duty cycle time which is factor of PWM period. This will help
157fd786fb0SLaxman Dewangan 	 * to get output voltage nearer to requested value as there is no
158fd786fb0SLaxman Dewangan 	 * calculation loss.
159fd786fb0SLaxman Dewangan 	 */
160bc0868c6SMark Brown 	req_period = req_diff * pargs.period;
161fd786fb0SLaxman Dewangan 	div_u64_rem(req_period, diff, &rem);
162fd786fb0SLaxman Dewangan 	if (!rem) {
163fd786fb0SLaxman Dewangan 		do_div(req_period, diff);
164fd786fb0SLaxman Dewangan 		duty_pulse = (unsigned int)req_period;
165fd786fb0SLaxman Dewangan 	} else {
166bc0868c6SMark Brown 		duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff);
167fd786fb0SLaxman Dewangan 	}
168fd786fb0SLaxman Dewangan 
169bc0868c6SMark Brown 	ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period);
1704773be18SLee Jones 	if (ret) {
1715bf59bd5SLaxman Dewangan 		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
1724773be18SLee Jones 		return ret;
1734773be18SLee Jones 	}
1744773be18SLee Jones 
1754773be18SLee Jones 	drvdata->volt_uV = min_uV;
1764773be18SLee Jones 
1774773be18SLee Jones 	/* Delay required by PWM regulator to settle to the new voltage */
1784773be18SLee Jones 	usleep_range(ramp_delay, ramp_delay + 1000);
1794773be18SLee Jones 
1804773be18SLee Jones 	return 0;
1814773be18SLee Jones }
1824773be18SLee Jones 
183f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = {
184aa66cc66SChris Zhong 	.set_voltage_sel = pwm_regulator_set_voltage_sel,
185aa66cc66SChris Zhong 	.get_voltage_sel = pwm_regulator_get_voltage_sel,
186aa66cc66SChris Zhong 	.list_voltage    = pwm_regulator_list_voltage,
187aa66cc66SChris Zhong 	.map_voltage     = regulator_map_voltage_iterate,
1881de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1891de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1901de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
191aa66cc66SChris Zhong };
192aa66cc66SChris Zhong 
1934773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
1944773be18SLee Jones 	.get_voltage = pwm_regulator_get_voltage,
1954773be18SLee Jones 	.set_voltage = pwm_regulator_set_voltage,
1961de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1971de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1981de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
1994773be18SLee Jones };
2004773be18SLee Jones 
201b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = {
202aa66cc66SChris Zhong 	.name		= "pwm-regulator",
203aa66cc66SChris Zhong 	.type		= REGULATOR_VOLTAGE,
204aa66cc66SChris Zhong 	.owner		= THIS_MODULE,
205aa66cc66SChris Zhong 	.supply_name    = "pwm",
206aa66cc66SChris Zhong };
207aa66cc66SChris Zhong 
208f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev,
209f9178dadSLee Jones 				    struct pwm_regulator_data *drvdata)
210f9178dadSLee Jones {
211f9178dadSLee Jones 	struct device_node *np = pdev->dev.of_node;
212f9178dadSLee Jones 	struct pwm_voltages *duty_cycle_table;
21360cb65ebSLee Jones 	unsigned int length = 0;
214f9178dadSLee Jones 	int ret;
215f9178dadSLee Jones 
216f9178dadSLee Jones 	of_find_property(np, "voltage-table", &length);
217f9178dadSLee Jones 
218f9178dadSLee Jones 	if ((length < sizeof(*duty_cycle_table)) ||
219f9178dadSLee Jones 	    (length % sizeof(*duty_cycle_table))) {
2205bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
221f9178dadSLee Jones 			length);
222f9178dadSLee Jones 		return -EINVAL;
223f9178dadSLee Jones 	}
224f9178dadSLee Jones 
225f9178dadSLee Jones 	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
226f9178dadSLee Jones 	if (!duty_cycle_table)
227f9178dadSLee Jones 		return -ENOMEM;
228f9178dadSLee Jones 
229f9178dadSLee Jones 	ret = of_property_read_u32_array(np, "voltage-table",
230f9178dadSLee Jones 					 (u32 *)duty_cycle_table,
231f9178dadSLee Jones 					 length / sizeof(u32));
232f9178dadSLee Jones 	if (ret) {
2335bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
234f9178dadSLee Jones 		return ret;
235f9178dadSLee Jones 	}
236f9178dadSLee Jones 
237f9178dadSLee Jones 	drvdata->duty_cycle_table	= duty_cycle_table;
238f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
239f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
240f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
241f907a0a9SLaxman Dewangan 	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
242f9178dadSLee Jones 
243f9178dadSLee Jones 	return 0;
244f9178dadSLee Jones }
245f9178dadSLee Jones 
2464773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev,
2474773be18SLee Jones 					 struct pwm_regulator_data *drvdata)
2484773be18SLee Jones {
249f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
250f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
251f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
252f907a0a9SLaxman Dewangan 	drvdata->desc.continuous_voltage_range = true;
2534773be18SLee Jones 
2544773be18SLee Jones 	return 0;
2554773be18SLee Jones }
2564773be18SLee Jones 
257aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev)
258aa66cc66SChris Zhong {
2595ad2cb14SLee Jones 	const struct regulator_init_data *init_data;
260aa66cc66SChris Zhong 	struct pwm_regulator_data *drvdata;
261aa66cc66SChris Zhong 	struct regulator_dev *regulator;
262aa66cc66SChris Zhong 	struct regulator_config config = { };
263aa66cc66SChris Zhong 	struct device_node *np = pdev->dev.of_node;
264*27bfa889SAlexandre Courbot 	enum gpiod_flags gpio_flags;
265f9178dadSLee Jones 	int ret;
266aa66cc66SChris Zhong 
267aa66cc66SChris Zhong 	if (!np) {
268aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Device Tree node missing\n");
269aa66cc66SChris Zhong 		return -EINVAL;
270aa66cc66SChris Zhong 	}
271aa66cc66SChris Zhong 
272aa66cc66SChris Zhong 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
273aa66cc66SChris Zhong 	if (!drvdata)
274aa66cc66SChris Zhong 		return -ENOMEM;
275aa66cc66SChris Zhong 
276f907a0a9SLaxman Dewangan 	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
277f907a0a9SLaxman Dewangan 
2784773be18SLee Jones 	if (of_find_property(np, "voltage-table", NULL))
279f9178dadSLee Jones 		ret = pwm_regulator_init_table(pdev, drvdata);
2804773be18SLee Jones 	else
2814773be18SLee Jones 		ret = pwm_regulator_init_continuous(pdev, drvdata);
282f9178dadSLee Jones 	if (ret)
283aa66cc66SChris Zhong 		return ret;
284aa66cc66SChris Zhong 
2855ad2cb14SLee Jones 	init_data = of_get_regulator_init_data(&pdev->dev, np,
286f907a0a9SLaxman Dewangan 					       &drvdata->desc);
2875ad2cb14SLee Jones 	if (!init_data)
288aa66cc66SChris Zhong 		return -ENOMEM;
289aa66cc66SChris Zhong 
290aa66cc66SChris Zhong 	config.of_node = np;
291aa66cc66SChris Zhong 	config.dev = &pdev->dev;
292aa66cc66SChris Zhong 	config.driver_data = drvdata;
2935ad2cb14SLee Jones 	config.init_data = init_data;
294aa66cc66SChris Zhong 
295aa66cc66SChris Zhong 	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
296aa66cc66SChris Zhong 	if (IS_ERR(drvdata->pwm)) {
2975bf59bd5SLaxman Dewangan 		ret = PTR_ERR(drvdata->pwm);
2985bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
2995bf59bd5SLaxman Dewangan 		return ret;
300aa66cc66SChris Zhong 	}
301aa66cc66SChris Zhong 
302*27bfa889SAlexandre Courbot 	if (init_data->constraints.boot_on || init_data->constraints.always_on)
303*27bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_HIGH;
304*27bfa889SAlexandre Courbot 	else
305*27bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_LOW;
306*27bfa889SAlexandre Courbot 	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
307*27bfa889SAlexandre Courbot 						    gpio_flags);
308*27bfa889SAlexandre Courbot 	if (IS_ERR(drvdata->enb_gpio)) {
309*27bfa889SAlexandre Courbot 		ret = PTR_ERR(drvdata->enb_gpio);
310*27bfa889SAlexandre Courbot 		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
311*27bfa889SAlexandre Courbot 		return ret;
312*27bfa889SAlexandre Courbot 	}
313*27bfa889SAlexandre Courbot 
3148c12ad8eSBoris Brezillon 	/*
3158c12ad8eSBoris Brezillon 	 * FIXME: pwm_apply_args() should be removed when switching to the
3168c12ad8eSBoris Brezillon 	 * atomic PWM API.
3178c12ad8eSBoris Brezillon 	 */
3188c12ad8eSBoris Brezillon 	pwm_apply_args(drvdata->pwm);
3198c12ad8eSBoris Brezillon 
320aa66cc66SChris Zhong 	regulator = devm_regulator_register(&pdev->dev,
321f907a0a9SLaxman Dewangan 					    &drvdata->desc, &config);
322aa66cc66SChris Zhong 	if (IS_ERR(regulator)) {
3235bf59bd5SLaxman Dewangan 		ret = PTR_ERR(regulator);
3245bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
3255bf59bd5SLaxman Dewangan 			drvdata->desc.name, ret);
3265bf59bd5SLaxman Dewangan 		return ret;
327aa66cc66SChris Zhong 	}
328aa66cc66SChris Zhong 
329aa66cc66SChris Zhong 	return 0;
330aa66cc66SChris Zhong }
331aa66cc66SChris Zhong 
332aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = {
333aa66cc66SChris Zhong 	{ .compatible = "pwm-regulator" },
334aa66cc66SChris Zhong 	{ },
335aa66cc66SChris Zhong };
336aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match);
337aa66cc66SChris Zhong 
338aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = {
339aa66cc66SChris Zhong 	.driver = {
340aa66cc66SChris Zhong 		.name		= "pwm-regulator",
341aa66cc66SChris Zhong 		.of_match_table = of_match_ptr(pwm_of_match),
342aa66cc66SChris Zhong 	},
343aa66cc66SChris Zhong 	.probe = pwm_regulator_probe,
344aa66cc66SChris Zhong };
345aa66cc66SChris Zhong 
346aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver);
347aa66cc66SChris Zhong 
348aa66cc66SChris Zhong MODULE_LICENSE("GPL");
349aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
350aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver");
351aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator");
352