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/module.h> 14 #include <linux/init.h> 15 #include <linux/err.h> 16 #include <linux/regulator/driver.h> 17 #include <linux/regulator/machine.h> 18 #include <linux/regulator/of_regulator.h> 19 #include <linux/of.h> 20 #include <linux/of_device.h> 21 #include <linux/pwm.h> 22 23 struct pwm_regulator_data { 24 struct pwm_voltages *duty_cycle_table; 25 struct pwm_device *pwm; 26 int state; 27 }; 28 29 struct pwm_voltages { 30 unsigned int uV; 31 unsigned int dutycycle; 32 }; 33 34 static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) 35 { 36 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 37 38 return drvdata->state; 39 } 40 41 static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev, 42 unsigned selector) 43 { 44 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 45 unsigned int pwm_reg_period; 46 int dutycycle; 47 int ret; 48 49 pwm_reg_period = pwm_get_period(drvdata->pwm); 50 51 dutycycle = (pwm_reg_period * 52 drvdata->duty_cycle_table[selector].dutycycle) / 100; 53 54 ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period); 55 if (ret) { 56 dev_err(&rdev->dev, "Failed to configure PWM\n"); 57 return ret; 58 } 59 60 drvdata->state = selector; 61 62 ret = pwm_enable(drvdata->pwm); 63 if (ret) { 64 dev_err(&rdev->dev, "Failed to enable PWM\n"); 65 return ret; 66 } 67 68 return 0; 69 } 70 71 static int pwm_regulator_list_voltage(struct regulator_dev *rdev, 72 unsigned selector) 73 { 74 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); 75 76 if (selector >= rdev->desc->n_voltages) 77 return -EINVAL; 78 79 return drvdata->duty_cycle_table[selector].uV; 80 } 81 82 static struct regulator_ops pwm_regulator_voltage_ops = { 83 .set_voltage_sel = pwm_regulator_set_voltage_sel, 84 .get_voltage_sel = pwm_regulator_get_voltage_sel, 85 .list_voltage = pwm_regulator_list_voltage, 86 .map_voltage = regulator_map_voltage_iterate, 87 }; 88 89 static struct regulator_desc pwm_regulator_desc = { 90 .name = "pwm-regulator", 91 .ops = &pwm_regulator_voltage_ops, 92 .type = REGULATOR_VOLTAGE, 93 .owner = THIS_MODULE, 94 .supply_name = "pwm", 95 }; 96 97 static int pwm_regulator_probe(struct platform_device *pdev) 98 { 99 struct pwm_regulator_data *drvdata; 100 struct property *prop; 101 struct regulator_dev *regulator; 102 struct regulator_config config = { }; 103 struct device_node *np = pdev->dev.of_node; 104 int length, ret; 105 106 if (!np) { 107 dev_err(&pdev->dev, "Device Tree node missing\n"); 108 return -EINVAL; 109 } 110 111 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 112 if (!drvdata) 113 return -ENOMEM; 114 115 /* determine the number of voltage-table */ 116 prop = of_find_property(np, "voltage-table", &length); 117 if (!prop) { 118 dev_err(&pdev->dev, "No voltage-table\n"); 119 return -EINVAL; 120 } 121 122 if ((length < sizeof(*drvdata->duty_cycle_table)) || 123 (length % sizeof(*drvdata->duty_cycle_table))) { 124 dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", 125 length); 126 return -EINVAL; 127 } 128 129 pwm_regulator_desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table); 130 131 drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev, 132 length, GFP_KERNEL); 133 if (!drvdata->duty_cycle_table) 134 return -ENOMEM; 135 136 /* read voltage table from DT property */ 137 ret = of_property_read_u32_array(np, "voltage-table", 138 (u32 *)drvdata->duty_cycle_table, 139 length / sizeof(u32)); 140 if (ret < 0) { 141 dev_err(&pdev->dev, "read voltage-table failed\n"); 142 return ret; 143 } 144 145 config.init_data = of_get_regulator_init_data(&pdev->dev, np, 146 &pwm_regulator_desc); 147 if (!config.init_data) 148 return -ENOMEM; 149 150 config.of_node = np; 151 config.dev = &pdev->dev; 152 config.driver_data = drvdata; 153 154 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 155 if (IS_ERR(drvdata->pwm)) { 156 dev_err(&pdev->dev, "Failed to get PWM\n"); 157 return PTR_ERR(drvdata->pwm); 158 } 159 160 regulator = devm_regulator_register(&pdev->dev, 161 &pwm_regulator_desc, &config); 162 if (IS_ERR(regulator)) { 163 dev_err(&pdev->dev, "Failed to register regulator %s\n", 164 pwm_regulator_desc.name); 165 return PTR_ERR(regulator); 166 } 167 168 return 0; 169 } 170 171 static const struct of_device_id pwm_of_match[] = { 172 { .compatible = "pwm-regulator" }, 173 { }, 174 }; 175 MODULE_DEVICE_TABLE(of, pwm_of_match); 176 177 static struct platform_driver pwm_regulator_driver = { 178 .driver = { 179 .name = "pwm-regulator", 180 .of_match_table = of_match_ptr(pwm_of_match), 181 }, 182 .probe = pwm_regulator_probe, 183 }; 184 185 module_platform_driver(pwm_regulator_driver); 186 187 MODULE_LICENSE("GPL"); 188 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 189 MODULE_DESCRIPTION("PWM Regulator Driver"); 190 MODULE_ALIAS("platform:pwm-regulator"); 191