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