xref: /linux/drivers/regulator/pwm-regulator.c (revision d9070fdbe40a04b61262bac0f7ff0c7c29a68015)
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 
4027bfa889SAlexandre Courbot 	/* Enable GPIO */
4127bfa889SAlexandre Courbot 	struct gpio_desc *enb_gpio;
42aa66cc66SChris Zhong };
43aa66cc66SChris Zhong 
44aa66cc66SChris Zhong struct pwm_voltages {
45aa66cc66SChris Zhong 	unsigned int uV;
46aa66cc66SChris Zhong 	unsigned int dutycycle;
47aa66cc66SChris Zhong };
48aa66cc66SChris Zhong 
494773be18SLee Jones /**
504773be18SLee Jones  * Voltage table call-backs
514773be18SLee Jones  */
5287248991SBoris Brezillon static void pwm_regulator_init_state(struct regulator_dev *rdev)
5387248991SBoris Brezillon {
5487248991SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
5587248991SBoris Brezillon 	struct pwm_state pwm_state;
5687248991SBoris Brezillon 	unsigned int dutycycle;
5787248991SBoris Brezillon 	int i;
5887248991SBoris Brezillon 
5987248991SBoris Brezillon 	pwm_get_state(drvdata->pwm, &pwm_state);
6087248991SBoris Brezillon 	dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);
6187248991SBoris Brezillon 
6287248991SBoris Brezillon 	for (i = 0; i < rdev->desc->n_voltages; i++) {
6387248991SBoris Brezillon 		if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {
6487248991SBoris Brezillon 			drvdata->state = i;
6587248991SBoris Brezillon 			return;
6687248991SBoris Brezillon 		}
6787248991SBoris Brezillon 	}
6887248991SBoris Brezillon }
6987248991SBoris Brezillon 
70ab101e35SLee Jones static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
71aa66cc66SChris Zhong {
72ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
73aa66cc66SChris Zhong 
7487248991SBoris Brezillon 	if (drvdata->state < 0)
7587248991SBoris Brezillon 		pwm_regulator_init_state(rdev);
7687248991SBoris Brezillon 
77aa66cc66SChris Zhong 	return drvdata->state;
78aa66cc66SChris Zhong }
79aa66cc66SChris Zhong 
80ab101e35SLee Jones static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
81aa66cc66SChris Zhong 					 unsigned selector)
82aa66cc66SChris Zhong {
83ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
843f4eb39bSBoris Brezillon 	struct pwm_state pstate;
85aa66cc66SChris Zhong 	int ret;
86aa66cc66SChris Zhong 
873f4eb39bSBoris Brezillon 	pwm_init_state(drvdata->pwm, &pstate);
883f4eb39bSBoris Brezillon 	pwm_set_relative_duty_cycle(&pstate,
893f4eb39bSBoris Brezillon 			drvdata->duty_cycle_table[selector].dutycycle, 100);
90aa66cc66SChris Zhong 
913f4eb39bSBoris Brezillon 	ret = pwm_apply_state(drvdata->pwm, &pstate);
92aa66cc66SChris Zhong 	if (ret) {
935bf59bd5SLaxman Dewangan 		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
94aa66cc66SChris Zhong 		return ret;
95aa66cc66SChris Zhong 	}
96aa66cc66SChris Zhong 
97aa66cc66SChris Zhong 	drvdata->state = selector;
98aa66cc66SChris Zhong 
99aa66cc66SChris Zhong 	return 0;
100aa66cc66SChris Zhong }
101aa66cc66SChris Zhong 
102ab101e35SLee Jones static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
103aa66cc66SChris Zhong 				      unsigned selector)
104aa66cc66SChris Zhong {
105ab101e35SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
106aa66cc66SChris Zhong 
107ab101e35SLee Jones 	if (selector >= rdev->desc->n_voltages)
108aa66cc66SChris Zhong 		return -EINVAL;
109aa66cc66SChris Zhong 
110aa66cc66SChris Zhong 	return drvdata->duty_cycle_table[selector].uV;
111aa66cc66SChris Zhong }
1124773be18SLee Jones 
1131de7d802SBoris Brezillon static int pwm_regulator_enable(struct regulator_dev *dev)
1141de7d802SBoris Brezillon {
1151de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1161de7d802SBoris Brezillon 
11727bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
11827bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
11927bfa889SAlexandre Courbot 
1201de7d802SBoris Brezillon 	return pwm_enable(drvdata->pwm);
1211de7d802SBoris Brezillon }
1221de7d802SBoris Brezillon 
1231de7d802SBoris Brezillon static int pwm_regulator_disable(struct regulator_dev *dev)
1241de7d802SBoris Brezillon {
1251de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1261de7d802SBoris Brezillon 
1271de7d802SBoris Brezillon 	pwm_disable(drvdata->pwm);
1281de7d802SBoris Brezillon 
12927bfa889SAlexandre Courbot 	if (drvdata->enb_gpio)
13027bfa889SAlexandre Courbot 		gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
13127bfa889SAlexandre Courbot 
1321de7d802SBoris Brezillon 	return 0;
1331de7d802SBoris Brezillon }
1341de7d802SBoris Brezillon 
1351de7d802SBoris Brezillon static int pwm_regulator_is_enabled(struct regulator_dev *dev)
1361de7d802SBoris Brezillon {
1371de7d802SBoris Brezillon 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
1381de7d802SBoris Brezillon 
13927bfa889SAlexandre Courbot 	if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
14027bfa889SAlexandre Courbot 		return false;
14127bfa889SAlexandre Courbot 
1421de7d802SBoris Brezillon 	return pwm_is_enabled(drvdata->pwm);
1431de7d802SBoris Brezillon }
1441de7d802SBoris Brezillon 
1454773be18SLee Jones static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
1464773be18SLee Jones {
1474773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
148*d9070fdbSBoris Brezillon 	int min_uV = rdev->constraints->min_uV;
149*d9070fdbSBoris Brezillon 	int diff = rdev->constraints->max_uV - min_uV;
150*d9070fdbSBoris Brezillon 	struct pwm_state pstate;
1514773be18SLee Jones 
152*d9070fdbSBoris Brezillon 	pwm_get_state(drvdata->pwm, &pstate);
153*d9070fdbSBoris Brezillon 
154*d9070fdbSBoris Brezillon 	return min_uV + pwm_get_relative_duty_cycle(&pstate, diff);
1554773be18SLee Jones }
1564773be18SLee Jones 
1574773be18SLee Jones static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
1584773be18SLee Jones 					int min_uV, int max_uV,
1594773be18SLee Jones 					unsigned *selector)
1604773be18SLee Jones {
1614773be18SLee Jones 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
1624773be18SLee Jones 	unsigned int ramp_delay = rdev->constraints->ramp_delay;
163fd786fb0SLaxman Dewangan 	unsigned int req_diff = min_uV - rdev->constraints->min_uV;
1643f4eb39bSBoris Brezillon 	struct pwm_state pstate;
165fd786fb0SLaxman Dewangan 	unsigned int diff;
166c2588393SDouglas Anderson 	int old_uV = pwm_regulator_get_voltage(rdev);
1674773be18SLee Jones 	int ret;
1684773be18SLee Jones 
1693f4eb39bSBoris Brezillon 	pwm_init_state(drvdata->pwm, &pstate);
170fd786fb0SLaxman Dewangan 	diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
1714773be18SLee Jones 
1723f4eb39bSBoris Brezillon 	/* We pass diff as the scale to get a uV precision. */
1733f4eb39bSBoris Brezillon 	pwm_set_relative_duty_cycle(&pstate, req_diff, diff);
174fd786fb0SLaxman Dewangan 
1753f4eb39bSBoris Brezillon 	ret = pwm_apply_state(drvdata->pwm, &pstate);
1764773be18SLee Jones 	if (ret) {
1775bf59bd5SLaxman Dewangan 		dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
1784773be18SLee Jones 		return ret;
1794773be18SLee Jones 	}
1804773be18SLee Jones 
181c2588393SDouglas Anderson 	if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev))
182c2588393SDouglas Anderson 		return 0;
183c2588393SDouglas Anderson 
184c2588393SDouglas Anderson 	/* Ramp delay is in uV/uS. Adjust to uS and delay */
185c2588393SDouglas Anderson 	ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay);
186c2588393SDouglas Anderson 	usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10));
1874773be18SLee Jones 
1884773be18SLee Jones 	return 0;
1894773be18SLee Jones }
1904773be18SLee Jones 
191f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = {
192aa66cc66SChris Zhong 	.set_voltage_sel = pwm_regulator_set_voltage_sel,
193aa66cc66SChris Zhong 	.get_voltage_sel = pwm_regulator_get_voltage_sel,
194aa66cc66SChris Zhong 	.list_voltage    = pwm_regulator_list_voltage,
195aa66cc66SChris Zhong 	.map_voltage     = regulator_map_voltage_iterate,
1961de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
1971de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
1981de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
199aa66cc66SChris Zhong };
200aa66cc66SChris Zhong 
2014773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
2024773be18SLee Jones 	.get_voltage = pwm_regulator_get_voltage,
2034773be18SLee Jones 	.set_voltage = pwm_regulator_set_voltage,
2041de7d802SBoris Brezillon 	.enable          = pwm_regulator_enable,
2051de7d802SBoris Brezillon 	.disable         = pwm_regulator_disable,
2061de7d802SBoris Brezillon 	.is_enabled      = pwm_regulator_is_enabled,
2074773be18SLee Jones };
2084773be18SLee Jones 
209b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = {
210aa66cc66SChris Zhong 	.name		= "pwm-regulator",
211aa66cc66SChris Zhong 	.type		= REGULATOR_VOLTAGE,
212aa66cc66SChris Zhong 	.owner		= THIS_MODULE,
213aa66cc66SChris Zhong 	.supply_name    = "pwm",
214aa66cc66SChris Zhong };
215aa66cc66SChris Zhong 
216f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev,
217f9178dadSLee Jones 				    struct pwm_regulator_data *drvdata)
218f9178dadSLee Jones {
219f9178dadSLee Jones 	struct device_node *np = pdev->dev.of_node;
220f9178dadSLee Jones 	struct pwm_voltages *duty_cycle_table;
22160cb65ebSLee Jones 	unsigned int length = 0;
222f9178dadSLee Jones 	int ret;
223f9178dadSLee Jones 
224f9178dadSLee Jones 	of_find_property(np, "voltage-table", &length);
225f9178dadSLee Jones 
226f9178dadSLee Jones 	if ((length < sizeof(*duty_cycle_table)) ||
227f9178dadSLee Jones 	    (length % sizeof(*duty_cycle_table))) {
2285bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
229f9178dadSLee Jones 			length);
230f9178dadSLee Jones 		return -EINVAL;
231f9178dadSLee Jones 	}
232f9178dadSLee Jones 
233f9178dadSLee Jones 	duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
234f9178dadSLee Jones 	if (!duty_cycle_table)
235f9178dadSLee Jones 		return -ENOMEM;
236f9178dadSLee Jones 
237f9178dadSLee Jones 	ret = of_property_read_u32_array(np, "voltage-table",
238f9178dadSLee Jones 					 (u32 *)duty_cycle_table,
239f9178dadSLee Jones 					 length / sizeof(u32));
240f9178dadSLee Jones 	if (ret) {
2415bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
242f9178dadSLee Jones 		return ret;
243f9178dadSLee Jones 	}
244f9178dadSLee Jones 
24587248991SBoris Brezillon 	drvdata->state			= -EINVAL;
246f9178dadSLee Jones 	drvdata->duty_cycle_table	= duty_cycle_table;
247f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
248f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
249f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
250f907a0a9SLaxman Dewangan 	drvdata->desc.n_voltages	= length / sizeof(*duty_cycle_table);
251f9178dadSLee Jones 
252f9178dadSLee Jones 	return 0;
253f9178dadSLee Jones }
254f9178dadSLee Jones 
2554773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev,
2564773be18SLee Jones 					 struct pwm_regulator_data *drvdata)
2574773be18SLee Jones {
258f907a0a9SLaxman Dewangan 	memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
259f907a0a9SLaxman Dewangan 	       sizeof(drvdata->ops));
260f907a0a9SLaxman Dewangan 	drvdata->desc.ops = &drvdata->ops;
261f907a0a9SLaxman Dewangan 	drvdata->desc.continuous_voltage_range = true;
2624773be18SLee Jones 
2634773be18SLee Jones 	return 0;
2644773be18SLee Jones }
2654773be18SLee Jones 
266aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev)
267aa66cc66SChris Zhong {
2685ad2cb14SLee Jones 	const struct regulator_init_data *init_data;
269aa66cc66SChris Zhong 	struct pwm_regulator_data *drvdata;
270aa66cc66SChris Zhong 	struct regulator_dev *regulator;
271aa66cc66SChris Zhong 	struct regulator_config config = { };
272aa66cc66SChris Zhong 	struct device_node *np = pdev->dev.of_node;
27327bfa889SAlexandre Courbot 	enum gpiod_flags gpio_flags;
274f9178dadSLee Jones 	int ret;
275aa66cc66SChris Zhong 
276aa66cc66SChris Zhong 	if (!np) {
277aa66cc66SChris Zhong 		dev_err(&pdev->dev, "Device Tree node missing\n");
278aa66cc66SChris Zhong 		return -EINVAL;
279aa66cc66SChris Zhong 	}
280aa66cc66SChris Zhong 
281aa66cc66SChris Zhong 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
282aa66cc66SChris Zhong 	if (!drvdata)
283aa66cc66SChris Zhong 		return -ENOMEM;
284aa66cc66SChris Zhong 
285f907a0a9SLaxman Dewangan 	memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));
286f907a0a9SLaxman Dewangan 
2874773be18SLee Jones 	if (of_find_property(np, "voltage-table", NULL))
288f9178dadSLee Jones 		ret = pwm_regulator_init_table(pdev, drvdata);
2894773be18SLee Jones 	else
2904773be18SLee Jones 		ret = pwm_regulator_init_continuous(pdev, drvdata);
291f9178dadSLee Jones 	if (ret)
292aa66cc66SChris Zhong 		return ret;
293aa66cc66SChris Zhong 
2945ad2cb14SLee Jones 	init_data = of_get_regulator_init_data(&pdev->dev, np,
295f907a0a9SLaxman Dewangan 					       &drvdata->desc);
2965ad2cb14SLee Jones 	if (!init_data)
297aa66cc66SChris Zhong 		return -ENOMEM;
298aa66cc66SChris Zhong 
299aa66cc66SChris Zhong 	config.of_node = np;
300aa66cc66SChris Zhong 	config.dev = &pdev->dev;
301aa66cc66SChris Zhong 	config.driver_data = drvdata;
3025ad2cb14SLee Jones 	config.init_data = init_data;
303aa66cc66SChris Zhong 
304aa66cc66SChris Zhong 	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
305aa66cc66SChris Zhong 	if (IS_ERR(drvdata->pwm)) {
3065bf59bd5SLaxman Dewangan 		ret = PTR_ERR(drvdata->pwm);
3075bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
3085bf59bd5SLaxman Dewangan 		return ret;
309aa66cc66SChris Zhong 	}
310aa66cc66SChris Zhong 
31127bfa889SAlexandre Courbot 	if (init_data->constraints.boot_on || init_data->constraints.always_on)
31227bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_HIGH;
31327bfa889SAlexandre Courbot 	else
31427bfa889SAlexandre Courbot 		gpio_flags = GPIOD_OUT_LOW;
31527bfa889SAlexandre Courbot 	drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
31627bfa889SAlexandre Courbot 						    gpio_flags);
31727bfa889SAlexandre Courbot 	if (IS_ERR(drvdata->enb_gpio)) {
31827bfa889SAlexandre Courbot 		ret = PTR_ERR(drvdata->enb_gpio);
31927bfa889SAlexandre Courbot 		dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
32027bfa889SAlexandre Courbot 		return ret;
32127bfa889SAlexandre Courbot 	}
32227bfa889SAlexandre Courbot 
323fd4f99c4SBoris Brezillon 	ret = pwm_adjust_config(drvdata->pwm);
324fd4f99c4SBoris Brezillon 	if (ret)
325fd4f99c4SBoris Brezillon 		return ret;
3268c12ad8eSBoris Brezillon 
327aa66cc66SChris Zhong 	regulator = devm_regulator_register(&pdev->dev,
328f907a0a9SLaxman Dewangan 					    &drvdata->desc, &config);
329aa66cc66SChris Zhong 	if (IS_ERR(regulator)) {
3305bf59bd5SLaxman Dewangan 		ret = PTR_ERR(regulator);
3315bf59bd5SLaxman Dewangan 		dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
3325bf59bd5SLaxman Dewangan 			drvdata->desc.name, ret);
3335bf59bd5SLaxman Dewangan 		return ret;
334aa66cc66SChris Zhong 	}
335aa66cc66SChris Zhong 
336aa66cc66SChris Zhong 	return 0;
337aa66cc66SChris Zhong }
338aa66cc66SChris Zhong 
339aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = {
340aa66cc66SChris Zhong 	{ .compatible = "pwm-regulator" },
341aa66cc66SChris Zhong 	{ },
342aa66cc66SChris Zhong };
343aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match);
344aa66cc66SChris Zhong 
345aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = {
346aa66cc66SChris Zhong 	.driver = {
347aa66cc66SChris Zhong 		.name		= "pwm-regulator",
348aa66cc66SChris Zhong 		.of_match_table = of_match_ptr(pwm_of_match),
349aa66cc66SChris Zhong 	},
350aa66cc66SChris Zhong 	.probe = pwm_regulator_probe,
351aa66cc66SChris Zhong };
352aa66cc66SChris Zhong 
353aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver);
354aa66cc66SChris Zhong 
355aa66cc66SChris Zhong MODULE_LICENSE("GPL");
356aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
357aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver");
358aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator");
359