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