xref: /linux/drivers/regulator/pwm-regulator.c (revision c2588393e6315ab68207323d37d2a73713d6bc81)
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>
2327bfa889SAlexandre 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;
4227bfa889SAlexandre Courbot 
4327bfa889SAlexandre Courbot 	/* Enable GPIO */
4427bfa889SAlexandre 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 
10127bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
10227bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
10327bfa889SAlexandre 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 
11327bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
11427bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
11527bfa889SAlexandre 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 
12327bfa889SAlexandre Courbot 	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
12427bfa889SAlexandre Courbot 		return false;
12527bfa889SAlexandre 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;
148*c2588393SDouglas Anderson 	int old_uV = pwm_regulator_get_voltage(rdev);
1494773be18SLee Jones 	int ret;
1504773be18SLee Jones 
1518c12ad8eSBoris Brezillon 	pwm_get_args(drvdata->pwm, &pargs);
152fd786fb0SLaxman Dewangan 	diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
1534773be18SLee Jones 
154fd786fb0SLaxman Dewangan 	/* First try to find out if we get the iduty cycle time which is
155fd786fb0SLaxman Dewangan 	 * factor of PWM period time. If (request_diff_to_min * pwm_period)
156fd786fb0SLaxman Dewangan 	 * is perfect divided by voltage_range_diff then it is possible to
157fd786fb0SLaxman Dewangan 	 * get duty cycle time which is factor of PWM period. This will help
158fd786fb0SLaxman Dewangan 	 * to get output voltage nearer to requested value as there is no
159fd786fb0SLaxman Dewangan 	 * calculation loss.
160fd786fb0SLaxman Dewangan 	 */
161bc0868c6SMark Brown 	req_period = req_diff * pargs.period;
162fd786fb0SLaxman Dewangan 	div_u64_rem(req_period, diff, &rem);
163fd786fb0SLaxman Dewangan 	if (!rem) {
164fd786fb0SLaxman Dewangan 		do_div(req_period, diff);
165fd786fb0SLaxman Dewangan 		duty_pulse = (unsigned int)req_period;
166fd786fb0SLaxman Dewangan 	} else {
167bc0868c6SMark Brown 		duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff);
168fd786fb0SLaxman Dewangan 	}
169fd786fb0SLaxman Dewangan 
170bc0868c6SMark Brown 	ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period);
1714773be18SLee Jones 	if (ret) {
1725bf59bd5SLaxman Dewangan 		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
1734773be18SLee Jones 		return ret;
1744773be18SLee Jones 	}
1754773be18SLee Jones 
1764773be18SLee Jones 	drvdata->volt_uV = min_uV;
1774773be18SLee Jones 
178*c2588393SDouglas Anderson 	if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev))
179*c2588393SDouglas Anderson 		return 0;
180*c2588393SDouglas Anderson 
181*c2588393SDouglas Anderson 	/* Ramp delay is in uV/uS. Adjust to uS and delay */
182*c2588393SDouglas Anderson 	ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay);
183*c2588393SDouglas Anderson 	usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10));
1844773be18SLee Jones 
1854773be18SLee Jones 	return 0;
1864773be18SLee Jones }
1874773be18SLee Jones 
188f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = {
189aa66cc66SChris Zhong 	.set_voltage_sel = pwm_regulator_set_voltage_sel,
190aa66cc66SChris Zhong 	.get_voltage_sel = pwm_regulator_get_voltage_sel,
191aa66cc66SChris Zhong 	.list_voltage    = pwm_regulator_list_voltage,
192aa66cc66SChris Zhong 	.map_voltage     = regulator_map_voltage_iterate,
1931de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1941de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1951de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
196aa66cc66SChris Zhong };
197aa66cc66SChris Zhong 
1984773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
1994773be18SLee Jones 	.get_voltage = pwm_regulator_get_voltage,
2004773be18SLee Jones 	.set_voltage = pwm_regulator_set_voltage,
2011de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
2021de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
2031de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
2044773be18SLee Jones };
2054773be18SLee Jones 
206b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = {
207aa66cc66SChris Zhong 	.name		= "pwm-regulator",
208aa66cc66SChris Zhong 	.type		= REGULATOR_VOLTAGE,
209aa66cc66SChris Zhong 	.owner		= THIS_MODULE,
210aa66cc66SChris Zhong 	.supply_name    = "pwm",
211aa66cc66SChris Zhong };
212aa66cc66SChris Zhong 
213f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev,
214f9178dadSLee Jones 				    struct pwm_regulator_data *drvdata)
215f9178dadSLee Jones {
216f9178dadSLee Jones 	struct device_node *np = pdev->dev.of_node;
217f9178dadSLee Jones 	struct pwm_voltages *duty_cycle_table;
21860cb65ebSLee Jones 	unsigned int length = 0;
219f9178dadSLee Jones 	int ret;
220f9178dadSLee Jones 
221f9178dadSLee Jones 	of_find_property(np, "voltage-table", &length);
222f9178dadSLee Jones 
223f9178dadSLee Jones 	if ((length < sizeof(*duty_cycle_table)) ||
224f9178dadSLee Jones 	    (length % sizeof(*duty_cycle_table))) {
2255bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
226f9178dadSLee Jones 			length);
227f9178dadSLee Jones 		return -EINVAL;
228f9178dadSLee Jones 	}
229f9178dadSLee Jones 
230f9178dadSLee Jones 	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
231f9178dadSLee Jones 	if (!duty_cycle_table)
232f9178dadSLee Jones 		return -ENOMEM;
233f9178dadSLee Jones 
234f9178dadSLee Jones 	ret = of_property_read_u32_array(np, "voltage-table",
235f9178dadSLee Jones 					 (u32 *)duty_cycle_table,
236f9178dadSLee Jones 					 length / sizeof(u32));
237f9178dadSLee Jones 	if (ret) {
2385bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
239f9178dadSLee Jones 		return ret;
240f9178dadSLee Jones 	}
241f9178dadSLee Jones 
242f9178dadSLee Jones 	drvdata->duty_cycle_table	= duty_cycle_table;
243f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
244f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
245f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
246f907a0a9SLaxman Dewangan 	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
247f9178dadSLee Jones 
248f9178dadSLee Jones 	return 0;
249f9178dadSLee Jones }
250f9178dadSLee Jones 
2514773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev,
2524773be18SLee Jones 					 struct pwm_regulator_data *drvdata)
2534773be18SLee Jones {
254f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
255f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
256f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
257f907a0a9SLaxman Dewangan 	drvdata->desc.continuous_voltage_range = true;
2584773be18SLee Jones 
2594773be18SLee Jones 	return 0;
2604773be18SLee Jones }
2614773be18SLee Jones 
262aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev)
263aa66cc66SChris Zhong {
2645ad2cb14SLee Jones 	const struct regulator_init_data *init_data;
265aa66cc66SChris Zhong 	struct pwm_regulator_data *drvdata;
266aa66cc66SChris Zhong 	struct regulator_dev *regulator;
267aa66cc66SChris Zhong 	struct regulator_config config = { };
268aa66cc66SChris Zhong 	struct device_node *np = pdev->dev.of_node;
26927bfa889SAlexandre Courbot 	enum gpiod_flags gpio_flags;
270f9178dadSLee Jones 	int ret;
271aa66cc66SChris Zhong 
272aa66cc66SChris Zhong 	if (!np) {
273aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Device Tree node missing\n");
274aa66cc66SChris Zhong 		return -EINVAL;
275aa66cc66SChris Zhong 	}
276aa66cc66SChris Zhong 
277aa66cc66SChris Zhong 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
278aa66cc66SChris Zhong 	if (!drvdata)
279aa66cc66SChris Zhong 		return -ENOMEM;
280aa66cc66SChris Zhong 
281f907a0a9SLaxman Dewangan 	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
282f907a0a9SLaxman Dewangan 
2834773be18SLee Jones 	if (of_find_property(np, "voltage-table", NULL))
284f9178dadSLee Jones 		ret = pwm_regulator_init_table(pdev, drvdata);
2854773be18SLee Jones 	else
2864773be18SLee Jones 		ret = pwm_regulator_init_continuous(pdev, drvdata);
287f9178dadSLee Jones 	if (ret)
288aa66cc66SChris Zhong 		return ret;
289aa66cc66SChris Zhong 
2905ad2cb14SLee Jones 	init_data = of_get_regulator_init_data(&pdev->dev, np,
291f907a0a9SLaxman Dewangan 					       &drvdata->desc);
2925ad2cb14SLee Jones 	if (!init_data)
293aa66cc66SChris Zhong 		return -ENOMEM;
294aa66cc66SChris Zhong 
295aa66cc66SChris Zhong 	config.of_node = np;
296aa66cc66SChris Zhong 	config.dev = &pdev->dev;
297aa66cc66SChris Zhong 	config.driver_data = drvdata;
2985ad2cb14SLee Jones 	config.init_data = init_data;
299aa66cc66SChris Zhong 
300aa66cc66SChris Zhong 	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
301aa66cc66SChris Zhong 	if (IS_ERR(drvdata->pwm)) {
3025bf59bd5SLaxman Dewangan 		ret = PTR_ERR(drvdata->pwm);
3035bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
3045bf59bd5SLaxman Dewangan 		return ret;
305aa66cc66SChris Zhong 	}
306aa66cc66SChris Zhong 
30727bfa889SAlexandre Courbot 	if (init_data->constraints.boot_on || init_data->constraints.always_on)
30827bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_HIGH;
30927bfa889SAlexandre Courbot 	else
31027bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_LOW;
31127bfa889SAlexandre Courbot 	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
31227bfa889SAlexandre Courbot 						    gpio_flags);
31327bfa889SAlexandre Courbot 	if (IS_ERR(drvdata->enb_gpio)) {
31427bfa889SAlexandre Courbot 		ret = PTR_ERR(drvdata->enb_gpio);
31527bfa889SAlexandre Courbot 		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
31627bfa889SAlexandre Courbot 		return ret;
31727bfa889SAlexandre Courbot 	}
31827bfa889SAlexandre Courbot 
3198c12ad8eSBoris Brezillon 	/*
3208c12ad8eSBoris Brezillon 	 * FIXME: pwm_apply_args() should be removed when switching to the
3218c12ad8eSBoris Brezillon 	 * atomic PWM API.
3228c12ad8eSBoris Brezillon 	 */
3238c12ad8eSBoris Brezillon 	pwm_apply_args(drvdata->pwm);
3248c12ad8eSBoris Brezillon 
325aa66cc66SChris Zhong 	regulator = devm_regulator_register(&pdev->dev,
326f907a0a9SLaxman Dewangan 					    &drvdata->desc, &config);
327aa66cc66SChris Zhong 	if (IS_ERR(regulator)) {
3285bf59bd5SLaxman Dewangan 		ret = PTR_ERR(regulator);
3295bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
3305bf59bd5SLaxman Dewangan 			drvdata->desc.name, ret);
3315bf59bd5SLaxman Dewangan 		return ret;
332aa66cc66SChris Zhong 	}
333aa66cc66SChris Zhong 
334aa66cc66SChris Zhong 	return 0;
335aa66cc66SChris Zhong }
336aa66cc66SChris Zhong 
337aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = {
338aa66cc66SChris Zhong 	{ .compatible = "pwm-regulator" },
339aa66cc66SChris Zhong 	{ },
340aa66cc66SChris Zhong };
341aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match);
342aa66cc66SChris Zhong 
343aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = {
344aa66cc66SChris Zhong 	.driver = {
345aa66cc66SChris Zhong 		.name		= "pwm-regulator",
346aa66cc66SChris Zhong 		.of_match_table = of_match_ptr(pwm_of_match),
347aa66cc66SChris Zhong 	},
348aa66cc66SChris Zhong 	.probe = pwm_regulator_probe,
349aa66cc66SChris Zhong };
350aa66cc66SChris Zhong 
351aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver);
352aa66cc66SChris Zhong 
353aa66cc66SChris Zhong MODULE_LICENSE("GPL");
354aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
355aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver");
356aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator");
357