1 /* 2 * Regulator driver for PWM Regulators 3 * 4 * Copyright (C) 2014 - STMicroelectronics Inc. 5 * 6 * Author: Lee Jones <lee.jones@linaro.org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/err.h> 17 #include <linux/regulator/driver.h> 18 #include <linux/regulator/machine.h> 19 #include <linux/regulator/of_regulator.h> 20 #include <linux/of.h> 21 #include <linux/of_device.h> 22 #include <linux/pwm.h> 23 24 struct pwm_regulator_data { 25 /* Shared */ 26 struct pwm_device *pwm; 27 28 /* Voltage table */ 29 struct pwm_voltages *duty_cycle_table; 30 int state; 31 32 /* Continuous voltage */ 33 int volt_uV; 34 }; 35 36 struct pwm_voltages { 37 unsigned int uV; 38 unsigned int dutycycle; 39 }; 40 41 /** 42 * Voltage table call-backs 43 */ 44 static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) 45 { 46 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 47 48 return drvdata->state; 49 } 50 51 static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, 52 unsigned selector) 53 { 54 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 55 unsigned int pwm_reg_period; 56 int dutycycle; 57 int ret; 58 59 pwm_reg_period = pwm_get_period(drvdata->pwm); 60 61 dutycycle = (pwm_reg_period * 62 drvdata->duty_cycle_table[selector].dutycycle) / 100; 63 64 ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period); 65 if (ret) { 66 dev_err(&rdev->dev, "Failed to configure PWM\n"); 67 return ret; 68 } 69 70 drvdata->state = selector; 71 72 return 0; 73 } 74 75 static int pwm_regulator_list_voltage(struct regulator_dev *rdev, 76 unsigned selector) 77 { 78 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 79 80 if (selector >= rdev->desc->n_voltages) 81 return -EINVAL; 82 83 return drvdata->duty_cycle_table[selector].uV; 84 } 85 86 static int pwm_regulator_enable(struct regulator_dev *dev) 87 { 88 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 89 90 return pwm_enable(drvdata->pwm); 91 } 92 93 static int pwm_regulator_disable(struct regulator_dev *dev) 94 { 95 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 96 97 pwm_disable(drvdata->pwm); 98 99 return 0; 100 } 101 102 static int pwm_regulator_is_enabled(struct regulator_dev *dev) 103 { 104 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 105 106 return pwm_is_enabled(drvdata->pwm); 107 } 108 109 /** 110 * Continuous voltage call-backs 111 */ 112 static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) 113 { 114 int min_uV = rdev->constraints->min_uV; 115 int max_uV = rdev->constraints->max_uV; 116 int diff = max_uV - min_uV; 117 118 return 100 - (((req_uV * 100) - (min_uV * 100)) / diff); 119 } 120 121 static int pwm_regulator_get_voltage(struct regulator_dev *rdev) 122 { 123 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 124 125 return drvdata->volt_uV; 126 } 127 128 static int pwm_regulator_set_voltage(struct regulator_dev *rdev, 129 int min_uV, int max_uV, 130 unsigned *selector) 131 { 132 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 133 unsigned int ramp_delay = rdev->constraints->ramp_delay; 134 unsigned int period = pwm_get_period(drvdata->pwm); 135 int duty_cycle; 136 int ret; 137 138 duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); 139 140 ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); 141 if (ret) { 142 dev_err(&rdev->dev, "Failed to configure PWM\n"); 143 return ret; 144 } 145 146 ret = pwm_enable(drvdata->pwm); 147 if (ret) { 148 dev_err(&rdev->dev, "Failed to enable PWM\n"); 149 return ret; 150 } 151 drvdata->volt_uV = min_uV; 152 153 /* Delay required by PWM regulator to settle to the new voltage */ 154 usleep_range(ramp_delay, ramp_delay + 1000); 155 156 return 0; 157 } 158 159 static struct regulator_ops pwm_regulator_voltage_table_ops = { 160 .set_voltage_sel = pwm_regulator_set_voltage_sel, 161 .get_voltage_sel = pwm_regulator_get_voltage_sel, 162 .list_voltage = pwm_regulator_list_voltage, 163 .map_voltage = regulator_map_voltage_iterate, 164 .enable = pwm_regulator_enable, 165 .disable = pwm_regulator_disable, 166 .is_enabled = pwm_regulator_is_enabled, 167 }; 168 169 static struct regulator_ops pwm_regulator_voltage_continuous_ops = { 170 .get_voltage = pwm_regulator_get_voltage, 171 .set_voltage = pwm_regulator_set_voltage, 172 .enable = pwm_regulator_enable, 173 .disable = pwm_regulator_disable, 174 .is_enabled = pwm_regulator_is_enabled, 175 }; 176 177 static struct regulator_desc pwm_regulator_desc = { 178 .name = "pwm-regulator", 179 .type = REGULATOR_VOLTAGE, 180 .owner = THIS_MODULE, 181 .supply_name = "pwm", 182 }; 183 184 static int pwm_regulator_init_table(struct platform_device *pdev, 185 struct pwm_regulator_data *drvdata) 186 { 187 struct device_node *np = pdev->dev.of_node; 188 struct pwm_voltages *duty_cycle_table; 189 unsigned int length = 0; 190 int ret; 191 192 of_find_property(np, "voltage-table", &length); 193 194 if ((length < sizeof(*duty_cycle_table)) || 195 (length % sizeof(*duty_cycle_table))) { 196 dev_err(&pdev->dev, 197 "voltage-table length(%d) is invalid\n", 198 length); 199 return -EINVAL; 200 } 201 202 duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); 203 if (!duty_cycle_table) 204 return -ENOMEM; 205 206 ret = of_property_read_u32_array(np, "voltage-table", 207 (u32 *)duty_cycle_table, 208 length / sizeof(u32)); 209 if (ret) { 210 dev_err(&pdev->dev, "Failed to read voltage-table\n"); 211 return ret; 212 } 213 214 drvdata->duty_cycle_table = duty_cycle_table; 215 pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops; 216 pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table); 217 218 return 0; 219 } 220 221 static int pwm_regulator_init_continuous(struct platform_device *pdev, 222 struct pwm_regulator_data *drvdata) 223 { 224 pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; 225 pwm_regulator_desc.continuous_voltage_range = true; 226 227 return 0; 228 } 229 230 static int pwm_regulator_probe(struct platform_device *pdev) 231 { 232 const struct regulator_init_data *init_data; 233 struct pwm_regulator_data *drvdata; 234 struct regulator_dev *regulator; 235 struct regulator_config config = { }; 236 struct device_node *np = pdev->dev.of_node; 237 int ret; 238 239 if (!np) { 240 dev_err(&pdev->dev, "Device Tree node missing\n"); 241 return -EINVAL; 242 } 243 244 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 245 if (!drvdata) 246 return -ENOMEM; 247 248 if (of_find_property(np, "voltage-table", NULL)) 249 ret = pwm_regulator_init_table(pdev, drvdata); 250 else 251 ret = pwm_regulator_init_continuous(pdev, drvdata); 252 if (ret) 253 return ret; 254 255 init_data = of_get_regulator_init_data(&pdev->dev, np, 256 &pwm_regulator_desc); 257 if (!init_data) 258 return -ENOMEM; 259 260 config.of_node = np; 261 config.dev = &pdev->dev; 262 config.driver_data = drvdata; 263 config.init_data = init_data; 264 265 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 266 if (IS_ERR(drvdata->pwm)) { 267 dev_err(&pdev->dev, "Failed to get PWM\n"); 268 return PTR_ERR(drvdata->pwm); 269 } 270 271 regulator = devm_regulator_register(&pdev->dev, 272 &pwm_regulator_desc, &config); 273 if (IS_ERR(regulator)) { 274 dev_err(&pdev->dev, "Failed to register regulator %s\n", 275 pwm_regulator_desc.name); 276 return PTR_ERR(regulator); 277 } 278 279 return 0; 280 } 281 282 static const struct of_device_id pwm_of_match[] = { 283 { .compatible = "pwm-regulator" }, 284 { }, 285 }; 286 MODULE_DEVICE_TABLE(of, pwm_of_match); 287 288 static struct platform_driver pwm_regulator_driver = { 289 .driver = { 290 .name = "pwm-regulator", 291 .of_match_table = of_match_ptr(pwm_of_match), 292 }, 293 .probe = pwm_regulator_probe, 294 }; 295 296 module_platform_driver(pwm_regulator_driver); 297 298 MODULE_LICENSE("GPL"); 299 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 300 MODULE_DESCRIPTION("PWM Regulator Driver"); 301 MODULE_ALIAS("platform:pwm-regulator"); 302