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> 23aa66cc66SChris Zhong 24aa66cc66SChris Zhong struct pwm_regulator_data { 254773be18SLee Jones /* Shared */ 26aa66cc66SChris Zhong struct pwm_device *pwm; 274773be18SLee Jones 284773be18SLee Jones /* Voltage table */ 294773be18SLee Jones struct pwm_voltages *duty_cycle_table; 30*f907a0a9SLaxman Dewangan 31*f907a0a9SLaxman Dewangan /* regulator descriptor */ 32*f907a0a9SLaxman Dewangan struct regulator_desc desc; 33*f907a0a9SLaxman Dewangan 34*f907a0a9SLaxman Dewangan /* Regulator ops */ 35*f907a0a9SLaxman Dewangan struct regulator_ops ops; 36*f907a0a9SLaxman Dewangan 37aa66cc66SChris Zhong int state; 384773be18SLee Jones 394773be18SLee Jones /* Continuous voltage */ 404773be18SLee Jones int volt_uV; 41aa66cc66SChris Zhong }; 42aa66cc66SChris Zhong 43aa66cc66SChris Zhong struct pwm_voltages { 44aa66cc66SChris Zhong unsigned int uV; 45aa66cc66SChris Zhong unsigned int dutycycle; 46aa66cc66SChris Zhong }; 47aa66cc66SChris Zhong 484773be18SLee Jones /** 494773be18SLee Jones * Voltage table call-backs 504773be18SLee Jones */ 51ab101e35SLee Jones static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) 52aa66cc66SChris Zhong { 53ab101e35SLee Jones struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 54aa66cc66SChris Zhong 55aa66cc66SChris Zhong return drvdata->state; 56aa66cc66SChris Zhong } 57aa66cc66SChris Zhong 58ab101e35SLee Jones static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, 59aa66cc66SChris Zhong unsigned selector) 60aa66cc66SChris Zhong { 61ab101e35SLee Jones struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 62aa66cc66SChris Zhong unsigned int pwm_reg_period; 63aa66cc66SChris Zhong int dutycycle; 64aa66cc66SChris Zhong int ret; 65aa66cc66SChris Zhong 66aa66cc66SChris Zhong pwm_reg_period = pwm_get_period(drvdata->pwm); 67aa66cc66SChris Zhong 68aa66cc66SChris Zhong dutycycle = (pwm_reg_period * 69aa66cc66SChris Zhong drvdata->duty_cycle_table[selector].dutycycle) / 100; 70aa66cc66SChris Zhong 71aa66cc66SChris Zhong ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period); 72aa66cc66SChris Zhong if (ret) { 73ab101e35SLee Jones dev_err(&rdev->dev, "Failed to configure PWM\n"); 74aa66cc66SChris Zhong return ret; 75aa66cc66SChris Zhong } 76aa66cc66SChris Zhong 77aa66cc66SChris Zhong drvdata->state = selector; 78aa66cc66SChris Zhong 79aa66cc66SChris Zhong return 0; 80aa66cc66SChris Zhong } 81aa66cc66SChris Zhong 82ab101e35SLee Jones static int pwm_regulator_list_voltage(struct regulator_dev *rdev, 83aa66cc66SChris Zhong unsigned selector) 84aa66cc66SChris Zhong { 85ab101e35SLee Jones struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 86aa66cc66SChris Zhong 87ab101e35SLee Jones if (selector >= rdev->desc->n_voltages) 88aa66cc66SChris Zhong return -EINVAL; 89aa66cc66SChris Zhong 90aa66cc66SChris Zhong return drvdata->duty_cycle_table[selector].uV; 91aa66cc66SChris Zhong } 924773be18SLee Jones 931de7d802SBoris Brezillon static int pwm_regulator_enable(struct regulator_dev *dev) 941de7d802SBoris Brezillon { 951de7d802SBoris Brezillon struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 961de7d802SBoris Brezillon 971de7d802SBoris Brezillon return pwm_enable(drvdata->pwm); 981de7d802SBoris Brezillon } 991de7d802SBoris Brezillon 1001de7d802SBoris Brezillon static int pwm_regulator_disable(struct regulator_dev *dev) 1011de7d802SBoris Brezillon { 1021de7d802SBoris Brezillon struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 1031de7d802SBoris Brezillon 1041de7d802SBoris Brezillon pwm_disable(drvdata->pwm); 1051de7d802SBoris Brezillon 1061de7d802SBoris Brezillon return 0; 1071de7d802SBoris Brezillon } 1081de7d802SBoris Brezillon 1091de7d802SBoris Brezillon static int pwm_regulator_is_enabled(struct regulator_dev *dev) 1101de7d802SBoris Brezillon { 1111de7d802SBoris Brezillon struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 1121de7d802SBoris Brezillon 1131de7d802SBoris Brezillon return pwm_is_enabled(drvdata->pwm); 1141de7d802SBoris Brezillon } 1151de7d802SBoris Brezillon 1164773be18SLee Jones /** 1174773be18SLee Jones * Continuous voltage call-backs 1184773be18SLee Jones */ 119f3f6439dSLee Jones static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) 1204773be18SLee Jones { 121cae897deSLee Jones int min_uV = rdev->constraints->min_uV; 122cae897deSLee Jones int max_uV = rdev->constraints->max_uV; 123cae897deSLee Jones int diff = max_uV - min_uV; 1244773be18SLee Jones 1251aaab348SLaxman Dewangan return ((req_uV * 100) - (min_uV * 100)) / diff; 1264773be18SLee Jones } 1274773be18SLee Jones 1284773be18SLee Jones static int pwm_regulator_get_voltage(struct regulator_dev *rdev) 1294773be18SLee Jones { 1304773be18SLee Jones struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 1314773be18SLee Jones 1324773be18SLee Jones return drvdata->volt_uV; 1334773be18SLee Jones } 1344773be18SLee Jones 1354773be18SLee Jones static int pwm_regulator_set_voltage(struct regulator_dev *rdev, 1364773be18SLee Jones int min_uV, int max_uV, 1374773be18SLee Jones unsigned *selector) 1384773be18SLee Jones { 1394773be18SLee Jones struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 1404773be18SLee Jones unsigned int ramp_delay = rdev->constraints->ramp_delay; 141f3f6439dSLee Jones unsigned int period = pwm_get_period(drvdata->pwm); 1424773be18SLee Jones int duty_cycle; 1434773be18SLee Jones int ret; 1444773be18SLee Jones 145f3f6439dSLee Jones duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); 1464773be18SLee Jones 147f3f6439dSLee Jones ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); 1484773be18SLee Jones if (ret) { 1494773be18SLee Jones dev_err(&rdev->dev, "Failed to configure PWM\n"); 1504773be18SLee Jones return ret; 1514773be18SLee Jones } 1524773be18SLee Jones 1534773be18SLee Jones ret = pwm_enable(drvdata->pwm); 1544773be18SLee Jones if (ret) { 1554773be18SLee Jones dev_err(&rdev->dev, "Failed to enable PWM\n"); 1564773be18SLee Jones return ret; 1574773be18SLee Jones } 1584773be18SLee Jones drvdata->volt_uV = min_uV; 1594773be18SLee Jones 1604773be18SLee Jones /* Delay required by PWM regulator to settle to the new voltage */ 1614773be18SLee Jones usleep_range(ramp_delay, ramp_delay + 1000); 1624773be18SLee Jones 1634773be18SLee Jones return 0; 1644773be18SLee Jones } 1654773be18SLee Jones 166f9178dadSLee Jones static struct regulator_ops pwm_regulator_voltage_table_ops = { 167aa66cc66SChris Zhong .set_voltage_sel = pwm_regulator_set_voltage_sel, 168aa66cc66SChris Zhong .get_voltage_sel = pwm_regulator_get_voltage_sel, 169aa66cc66SChris Zhong .list_voltage = pwm_regulator_list_voltage, 170aa66cc66SChris Zhong .map_voltage = regulator_map_voltage_iterate, 1711de7d802SBoris Brezillon .enable = pwm_regulator_enable, 1721de7d802SBoris Brezillon .disable = pwm_regulator_disable, 1731de7d802SBoris Brezillon .is_enabled = pwm_regulator_is_enabled, 174aa66cc66SChris Zhong }; 175aa66cc66SChris Zhong 1764773be18SLee Jones static struct regulator_ops pwm_regulator_voltage_continuous_ops = { 1774773be18SLee Jones .get_voltage = pwm_regulator_get_voltage, 1784773be18SLee Jones .set_voltage = pwm_regulator_set_voltage, 1791de7d802SBoris Brezillon .enable = pwm_regulator_enable, 1801de7d802SBoris Brezillon .disable = pwm_regulator_disable, 1811de7d802SBoris Brezillon .is_enabled = pwm_regulator_is_enabled, 1824773be18SLee Jones }; 1834773be18SLee Jones 184b6f55e74SLee Jones static struct regulator_desc pwm_regulator_desc = { 185aa66cc66SChris Zhong .name = "pwm-regulator", 186aa66cc66SChris Zhong .type = REGULATOR_VOLTAGE, 187aa66cc66SChris Zhong .owner = THIS_MODULE, 188aa66cc66SChris Zhong .supply_name = "pwm", 189aa66cc66SChris Zhong }; 190aa66cc66SChris Zhong 191f9178dadSLee Jones static int pwm_regulator_init_table(struct platform_device *pdev, 192f9178dadSLee Jones struct pwm_regulator_data *drvdata) 193f9178dadSLee Jones { 194f9178dadSLee Jones struct device_node *np = pdev->dev.of_node; 195f9178dadSLee Jones struct pwm_voltages *duty_cycle_table; 19660cb65ebSLee Jones unsigned int length = 0; 197f9178dadSLee Jones int ret; 198f9178dadSLee Jones 199f9178dadSLee Jones of_find_property(np, "voltage-table", &length); 200f9178dadSLee Jones 201f9178dadSLee Jones if ((length < sizeof(*duty_cycle_table)) || 202f9178dadSLee Jones (length % sizeof(*duty_cycle_table))) { 203f9178dadSLee Jones dev_err(&pdev->dev, 204f9178dadSLee Jones "voltage-table length(%d) is invalid\n", 205f9178dadSLee Jones length); 206f9178dadSLee Jones return -EINVAL; 207f9178dadSLee Jones } 208f9178dadSLee Jones 209f9178dadSLee Jones duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); 210f9178dadSLee Jones if (!duty_cycle_table) 211f9178dadSLee Jones return -ENOMEM; 212f9178dadSLee Jones 213f9178dadSLee Jones ret = of_property_read_u32_array(np, "voltage-table", 214f9178dadSLee Jones (u32 *)duty_cycle_table, 215f9178dadSLee Jones length / sizeof(u32)); 216f9178dadSLee Jones if (ret) { 217f9178dadSLee Jones dev_err(&pdev->dev, "Failed to read voltage-table\n"); 218f9178dadSLee Jones return ret; 219f9178dadSLee Jones } 220f9178dadSLee Jones 221f9178dadSLee Jones drvdata->duty_cycle_table = duty_cycle_table; 222*f907a0a9SLaxman Dewangan memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops, 223*f907a0a9SLaxman Dewangan sizeof(drvdata->ops)); 224*f907a0a9SLaxman Dewangan drvdata->desc.ops = &drvdata->ops; 225*f907a0a9SLaxman Dewangan drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table); 226f9178dadSLee Jones 227f9178dadSLee Jones return 0; 228f9178dadSLee Jones } 229f9178dadSLee Jones 2304773be18SLee Jones static int pwm_regulator_init_continuous(struct platform_device *pdev, 2314773be18SLee Jones struct pwm_regulator_data *drvdata) 2324773be18SLee Jones { 233*f907a0a9SLaxman Dewangan memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops, 234*f907a0a9SLaxman Dewangan sizeof(drvdata->ops)); 235*f907a0a9SLaxman Dewangan drvdata->desc.ops = &drvdata->ops; 236*f907a0a9SLaxman Dewangan drvdata->desc.continuous_voltage_range = true; 2374773be18SLee Jones 2384773be18SLee Jones return 0; 2394773be18SLee Jones } 2404773be18SLee Jones 241aa66cc66SChris Zhong static int pwm_regulator_probe(struct platform_device *pdev) 242aa66cc66SChris Zhong { 2435ad2cb14SLee Jones const struct regulator_init_data *init_data; 244aa66cc66SChris Zhong struct pwm_regulator_data *drvdata; 245aa66cc66SChris Zhong struct regulator_dev *regulator; 246aa66cc66SChris Zhong struct regulator_config config = { }; 247aa66cc66SChris Zhong struct device_node *np = pdev->dev.of_node; 248f9178dadSLee Jones int ret; 249aa66cc66SChris Zhong 250aa66cc66SChris Zhong if (!np) { 251aa66cc66SChris Zhong dev_err(&pdev->dev, "Device Tree node missing\n"); 252aa66cc66SChris Zhong return -EINVAL; 253aa66cc66SChris Zhong } 254aa66cc66SChris Zhong 255aa66cc66SChris Zhong drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 256aa66cc66SChris Zhong if (!drvdata) 257aa66cc66SChris Zhong return -ENOMEM; 258aa66cc66SChris Zhong 259*f907a0a9SLaxman Dewangan memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc)); 260*f907a0a9SLaxman Dewangan 2614773be18SLee Jones if (of_find_property(np, "voltage-table", NULL)) 262f9178dadSLee Jones ret = pwm_regulator_init_table(pdev, drvdata); 2634773be18SLee Jones else 2644773be18SLee Jones ret = pwm_regulator_init_continuous(pdev, drvdata); 265f9178dadSLee Jones if (ret) 266aa66cc66SChris Zhong return ret; 267aa66cc66SChris Zhong 2685ad2cb14SLee Jones init_data = of_get_regulator_init_data(&pdev->dev, np, 269*f907a0a9SLaxman Dewangan &drvdata->desc); 2705ad2cb14SLee Jones if (!init_data) 271aa66cc66SChris Zhong return -ENOMEM; 272aa66cc66SChris Zhong 273aa66cc66SChris Zhong config.of_node = np; 274aa66cc66SChris Zhong config.dev = &pdev->dev; 275aa66cc66SChris Zhong config.driver_data = drvdata; 2765ad2cb14SLee Jones config.init_data = init_data; 277aa66cc66SChris Zhong 278aa66cc66SChris Zhong drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 279aa66cc66SChris Zhong if (IS_ERR(drvdata->pwm)) { 280aa66cc66SChris Zhong dev_err(&pdev->dev, "Failed to get PWM\n"); 281aa66cc66SChris Zhong return PTR_ERR(drvdata->pwm); 282aa66cc66SChris Zhong } 283aa66cc66SChris Zhong 284aa66cc66SChris Zhong regulator = devm_regulator_register(&pdev->dev, 285*f907a0a9SLaxman Dewangan &drvdata->desc, &config); 286aa66cc66SChris Zhong if (IS_ERR(regulator)) { 287aa66cc66SChris Zhong dev_err(&pdev->dev, "Failed to register regulator %s\n", 288*f907a0a9SLaxman Dewangan drvdata->desc.name); 289aa66cc66SChris Zhong return PTR_ERR(regulator); 290aa66cc66SChris Zhong } 291aa66cc66SChris Zhong 292aa66cc66SChris Zhong return 0; 293aa66cc66SChris Zhong } 294aa66cc66SChris Zhong 295aa66cc66SChris Zhong static const struct of_device_id pwm_of_match[] = { 296aa66cc66SChris Zhong { .compatible = "pwm-regulator" }, 297aa66cc66SChris Zhong { }, 298aa66cc66SChris Zhong }; 299aa66cc66SChris Zhong MODULE_DEVICE_TABLE(of, pwm_of_match); 300aa66cc66SChris Zhong 301aa66cc66SChris Zhong static struct platform_driver pwm_regulator_driver = { 302aa66cc66SChris Zhong .driver = { 303aa66cc66SChris Zhong .name = "pwm-regulator", 304aa66cc66SChris Zhong .of_match_table = of_match_ptr(pwm_of_match), 305aa66cc66SChris Zhong }, 306aa66cc66SChris Zhong .probe = pwm_regulator_probe, 307aa66cc66SChris Zhong }; 308aa66cc66SChris Zhong 309aa66cc66SChris Zhong module_platform_driver(pwm_regulator_driver); 310aa66cc66SChris Zhong 311aa66cc66SChris Zhong MODULE_LICENSE("GPL"); 312aa66cc66SChris Zhong MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 313aa66cc66SChris Zhong MODULE_DESCRIPTION("PWM Regulator Driver"); 314aa66cc66SChris Zhong MODULE_ALIAS("platform:pwm-regulator"); 315