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 31 /* regulator descriptor */ 32 struct regulator_desc desc; 33 34 /* Regulator ops */ 35 struct regulator_ops ops; 36 37 int state; 38 39 /* Continuous voltage */ 40 int volt_uV; 41 }; 42 43 struct pwm_voltages { 44 unsigned int uV; 45 unsigned int dutycycle; 46 }; 47 48 /** 49 * Voltage table call-backs 50 */ 51 static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) 52 { 53 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 54 55 return drvdata->state; 56 } 57 58 static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, 59 unsigned selector) 60 { 61 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 62 struct pwm_args pargs; 63 int dutycycle; 64 int ret; 65 66 pwm_get_args(drvdata->pwm, &pargs); 67 68 dutycycle = (pargs.period * 69 drvdata->duty_cycle_table[selector].dutycycle) / 100; 70 71 ret = pwm_config(drvdata->pwm, dutycycle, pargs.period); 72 if (ret) { 73 dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); 74 return ret; 75 } 76 77 drvdata->state = selector; 78 79 return 0; 80 } 81 82 static int pwm_regulator_list_voltage(struct regulator_dev *rdev, 83 unsigned selector) 84 { 85 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 86 87 if (selector >= rdev->desc->n_voltages) 88 return -EINVAL; 89 90 return drvdata->duty_cycle_table[selector].uV; 91 } 92 93 static int pwm_regulator_enable(struct regulator_dev *dev) 94 { 95 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 96 97 return pwm_enable(drvdata->pwm); 98 } 99 100 static int pwm_regulator_disable(struct regulator_dev *dev) 101 { 102 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 103 104 pwm_disable(drvdata->pwm); 105 106 return 0; 107 } 108 109 static int pwm_regulator_is_enabled(struct regulator_dev *dev) 110 { 111 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 112 113 return pwm_is_enabled(drvdata->pwm); 114 } 115 116 static int pwm_regulator_get_voltage(struct regulator_dev *rdev) 117 { 118 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 119 120 return drvdata->volt_uV; 121 } 122 123 static int pwm_regulator_set_voltage(struct regulator_dev *rdev, 124 int min_uV, int max_uV, 125 unsigned *selector) 126 { 127 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 128 unsigned int ramp_delay = rdev->constraints->ramp_delay; 129 struct pwm_args pargs; 130 unsigned int req_diff = min_uV - rdev->constraints->min_uV; 131 unsigned int diff; 132 unsigned int duty_pulse; 133 u64 req_period; 134 u32 rem; 135 int ret; 136 137 pwm_get_args(drvdata->pwm, &pargs); 138 diff = rdev->constraints->max_uV - rdev->constraints->min_uV; 139 140 /* First try to find out if we get the iduty cycle time which is 141 * factor of PWM period time. If (request_diff_to_min * pwm_period) 142 * is perfect divided by voltage_range_diff then it is possible to 143 * get duty cycle time which is factor of PWM period. This will help 144 * to get output voltage nearer to requested value as there is no 145 * calculation loss. 146 */ 147 req_period = req_diff * pargs.period; 148 div_u64_rem(req_period, diff, &rem); 149 if (!rem) { 150 do_div(req_period, diff); 151 duty_pulse = (unsigned int)req_period; 152 } else { 153 duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff); 154 } 155 156 ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period); 157 if (ret) { 158 dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret); 159 return ret; 160 } 161 162 ret = pwm_enable(drvdata->pwm); 163 if (ret) { 164 dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret); 165 return ret; 166 } 167 drvdata->volt_uV = min_uV; 168 169 /* Delay required by PWM regulator to settle to the new voltage */ 170 usleep_range(ramp_delay, ramp_delay + 1000); 171 172 return 0; 173 } 174 175 static struct regulator_ops pwm_regulator_voltage_table_ops = { 176 .set_voltage_sel = pwm_regulator_set_voltage_sel, 177 .get_voltage_sel = pwm_regulator_get_voltage_sel, 178 .list_voltage = pwm_regulator_list_voltage, 179 .map_voltage = regulator_map_voltage_iterate, 180 .enable = pwm_regulator_enable, 181 .disable = pwm_regulator_disable, 182 .is_enabled = pwm_regulator_is_enabled, 183 }; 184 185 static struct regulator_ops pwm_regulator_voltage_continuous_ops = { 186 .get_voltage = pwm_regulator_get_voltage, 187 .set_voltage = pwm_regulator_set_voltage, 188 .enable = pwm_regulator_enable, 189 .disable = pwm_regulator_disable, 190 .is_enabled = pwm_regulator_is_enabled, 191 }; 192 193 static struct regulator_desc pwm_regulator_desc = { 194 .name = "pwm-regulator", 195 .type = REGULATOR_VOLTAGE, 196 .owner = THIS_MODULE, 197 .supply_name = "pwm", 198 }; 199 200 static int pwm_regulator_init_table(struct platform_device *pdev, 201 struct pwm_regulator_data *drvdata) 202 { 203 struct device_node *np = pdev->dev.of_node; 204 struct pwm_voltages *duty_cycle_table; 205 unsigned int length = 0; 206 int ret; 207 208 of_find_property(np, "voltage-table", &length); 209 210 if ((length < sizeof(*duty_cycle_table)) || 211 (length % sizeof(*duty_cycle_table))) { 212 dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", 213 length); 214 return -EINVAL; 215 } 216 217 duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); 218 if (!duty_cycle_table) 219 return -ENOMEM; 220 221 ret = of_property_read_u32_array(np, "voltage-table", 222 (u32 *)duty_cycle_table, 223 length / sizeof(u32)); 224 if (ret) { 225 dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret); 226 return ret; 227 } 228 229 drvdata->duty_cycle_table = duty_cycle_table; 230 memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops, 231 sizeof(drvdata->ops)); 232 drvdata->desc.ops = &drvdata->ops; 233 drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table); 234 235 return 0; 236 } 237 238 static int pwm_regulator_init_continuous(struct platform_device *pdev, 239 struct pwm_regulator_data *drvdata) 240 { 241 memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops, 242 sizeof(drvdata->ops)); 243 drvdata->desc.ops = &drvdata->ops; 244 drvdata->desc.continuous_voltage_range = true; 245 246 return 0; 247 } 248 249 static int pwm_regulator_probe(struct platform_device *pdev) 250 { 251 const struct regulator_init_data *init_data; 252 struct pwm_regulator_data *drvdata; 253 struct regulator_dev *regulator; 254 struct regulator_config config = { }; 255 struct device_node *np = pdev->dev.of_node; 256 int ret; 257 258 if (!np) { 259 dev_err(&pdev->dev, "Device Tree node missing\n"); 260 return -EINVAL; 261 } 262 263 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 264 if (!drvdata) 265 return -ENOMEM; 266 267 memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc)); 268 269 if (of_find_property(np, "voltage-table", NULL)) 270 ret = pwm_regulator_init_table(pdev, drvdata); 271 else 272 ret = pwm_regulator_init_continuous(pdev, drvdata); 273 if (ret) 274 return ret; 275 276 init_data = of_get_regulator_init_data(&pdev->dev, np, 277 &drvdata->desc); 278 if (!init_data) 279 return -ENOMEM; 280 281 config.of_node = np; 282 config.dev = &pdev->dev; 283 config.driver_data = drvdata; 284 config.init_data = init_data; 285 286 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 287 if (IS_ERR(drvdata->pwm)) { 288 ret = PTR_ERR(drvdata->pwm); 289 dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret); 290 return ret; 291 } 292 293 /* 294 * FIXME: pwm_apply_args() should be removed when switching to the 295 * atomic PWM API. 296 */ 297 pwm_apply_args(drvdata->pwm); 298 299 regulator = devm_regulator_register(&pdev->dev, 300 &drvdata->desc, &config); 301 if (IS_ERR(regulator)) { 302 ret = PTR_ERR(regulator); 303 dev_err(&pdev->dev, "Failed to register regulator %s: %d\n", 304 drvdata->desc.name, ret); 305 return ret; 306 } 307 308 return 0; 309 } 310 311 static const struct of_device_id pwm_of_match[] = { 312 { .compatible = "pwm-regulator" }, 313 { }, 314 }; 315 MODULE_DEVICE_TABLE(of, pwm_of_match); 316 317 static struct platform_driver pwm_regulator_driver = { 318 .driver = { 319 .name = "pwm-regulator", 320 .of_match_table = of_match_ptr(pwm_of_match), 321 }, 322 .probe = pwm_regulator_probe, 323 }; 324 325 module_platform_driver(pwm_regulator_driver); 326 327 MODULE_LICENSE("GPL"); 328 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 329 MODULE_DESCRIPTION("PWM Regulator Driver"); 330 MODULE_ALIAS("platform:pwm-regulator"); 331