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 ret = pwm_enable(drvdata->pwm); 73 if (ret) { 74 dev_err(&rdev->dev, "Failed to enable PWM\n"); 75 return ret; 76 } 77 78 return 0; 79 } 80 81 static int pwm_regulator_list_voltage(struct regulator_dev *rdev, 82 unsigned selector) 83 { 84 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 85 86 if (selector >= rdev->desc->n_voltages) 87 return -EINVAL; 88 89 return drvdata->duty_cycle_table[selector].uV; 90 } 91 92 /** 93 * Continuous voltage call-backs 94 */ 95 static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) 96 { 97 int min_uV = rdev->constraints->min_uV; 98 int max_uV = rdev->constraints->max_uV; 99 int diff = max_uV - min_uV; 100 101 return 100 - (((req_uV * 100) - (min_uV * 100)) / diff); 102 } 103 104 static int pwm_regulator_get_voltage(struct regulator_dev *rdev) 105 { 106 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 107 108 return drvdata->volt_uV; 109 } 110 111 static int pwm_regulator_set_voltage(struct regulator_dev *rdev, 112 int min_uV, int max_uV, 113 unsigned *selector) 114 { 115 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 116 unsigned int ramp_delay = rdev->constraints->ramp_delay; 117 unsigned int period = pwm_get_period(drvdata->pwm); 118 int duty_cycle; 119 int ret; 120 121 duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); 122 123 ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); 124 if (ret) { 125 dev_err(&rdev->dev, "Failed to configure PWM\n"); 126 return ret; 127 } 128 129 ret = pwm_enable(drvdata->pwm); 130 if (ret) { 131 dev_err(&rdev->dev, "Failed to enable PWM\n"); 132 return ret; 133 } 134 drvdata->volt_uV = min_uV; 135 136 /* Delay required by PWM regulator to settle to the new voltage */ 137 usleep_range(ramp_delay, ramp_delay + 1000); 138 139 return 0; 140 } 141 142 static struct regulator_ops pwm_regulator_voltage_table_ops = { 143 .set_voltage_sel = pwm_regulator_set_voltage_sel, 144 .get_voltage_sel = pwm_regulator_get_voltage_sel, 145 .list_voltage = pwm_regulator_list_voltage, 146 .map_voltage = regulator_map_voltage_iterate, 147 }; 148 149 static struct regulator_ops pwm_regulator_voltage_continuous_ops = { 150 .get_voltage = pwm_regulator_get_voltage, 151 .set_voltage = pwm_regulator_set_voltage, 152 }; 153 154 static struct regulator_desc pwm_regulator_desc = { 155 .name = "pwm-regulator", 156 .type = REGULATOR_VOLTAGE, 157 .owner = THIS_MODULE, 158 .supply_name = "pwm", 159 }; 160 161 static int pwm_regulator_init_table(struct platform_device *pdev, 162 struct pwm_regulator_data *drvdata) 163 { 164 struct device_node *np = pdev->dev.of_node; 165 struct pwm_voltages *duty_cycle_table; 166 unsigned int length = 0; 167 int ret; 168 169 of_find_property(np, "voltage-table", &length); 170 171 if ((length < sizeof(*duty_cycle_table)) || 172 (length % sizeof(*duty_cycle_table))) { 173 dev_err(&pdev->dev, 174 "voltage-table length(%d) is invalid\n", 175 length); 176 return -EINVAL; 177 } 178 179 duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); 180 if (!duty_cycle_table) 181 return -ENOMEM; 182 183 ret = of_property_read_u32_array(np, "voltage-table", 184 (u32 *)duty_cycle_table, 185 length / sizeof(u32)); 186 if (ret) { 187 dev_err(&pdev->dev, "Failed to read voltage-table\n"); 188 return ret; 189 } 190 191 drvdata->duty_cycle_table = duty_cycle_table; 192 pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops; 193 pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table); 194 195 return 0; 196 } 197 198 static int pwm_regulator_init_continuous(struct platform_device *pdev, 199 struct pwm_regulator_data *drvdata) 200 { 201 pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; 202 pwm_regulator_desc.continuous_voltage_range = true; 203 204 return 0; 205 } 206 207 static int pwm_regulator_probe(struct platform_device *pdev) 208 { 209 const struct regulator_init_data *init_data; 210 struct pwm_regulator_data *drvdata; 211 struct regulator_dev *regulator; 212 struct regulator_config config = { }; 213 struct device_node *np = pdev->dev.of_node; 214 int ret; 215 216 if (!np) { 217 dev_err(&pdev->dev, "Device Tree node missing\n"); 218 return -EINVAL; 219 } 220 221 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 222 if (!drvdata) 223 return -ENOMEM; 224 225 if (of_find_property(np, "voltage-table", NULL)) 226 ret = pwm_regulator_init_table(pdev, drvdata); 227 else 228 ret = pwm_regulator_init_continuous(pdev, drvdata); 229 if (ret) 230 return ret; 231 232 init_data = of_get_regulator_init_data(&pdev->dev, np, 233 &pwm_regulator_desc); 234 if (!init_data) 235 return -ENOMEM; 236 237 config.of_node = np; 238 config.dev = &pdev->dev; 239 config.driver_data = drvdata; 240 config.init_data = init_data; 241 242 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 243 if (IS_ERR(drvdata->pwm)) { 244 dev_err(&pdev->dev, "Failed to get PWM\n"); 245 return PTR_ERR(drvdata->pwm); 246 } 247 248 regulator = devm_regulator_register(&pdev->dev, 249 &pwm_regulator_desc, &config); 250 if (IS_ERR(regulator)) { 251 dev_err(&pdev->dev, "Failed to register regulator %s\n", 252 pwm_regulator_desc.name); 253 return PTR_ERR(regulator); 254 } 255 256 return 0; 257 } 258 259 static const struct of_device_id pwm_of_match[] = { 260 { .compatible = "pwm-regulator" }, 261 { }, 262 }; 263 MODULE_DEVICE_TABLE(of, pwm_of_match); 264 265 static struct platform_driver pwm_regulator_driver = { 266 .driver = { 267 .name = "pwm-regulator", 268 .of_match_table = of_match_ptr(pwm_of_match), 269 }, 270 .probe = pwm_regulator_probe, 271 }; 272 273 module_platform_driver(pwm_regulator_driver); 274 275 MODULE_LICENSE("GPL"); 276 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 277 MODULE_DESCRIPTION("PWM Regulator Driver"); 278 MODULE_ALIAS("platform:pwm-regulator"); 279