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