Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15-rc8 190 lines 4.9 kB view raw
1/* 2 * Regulator driver for ST's 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#define ST_PWM_REG_PERIOD 8448 24 25struct st_pwm_regulator_pdata { 26 const struct regulator_desc *desc; 27 struct st_pwm_voltages *duty_cycle_table; 28}; 29 30struct st_pwm_regulator_data { 31 const struct st_pwm_regulator_pdata *pdata; 32 struct pwm_device *pwm; 33 bool enabled; 34 int state; 35}; 36 37struct st_pwm_voltages { 38 unsigned int uV; 39 unsigned int dutycycle; 40}; 41 42static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev) 43{ 44 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 45 46 return drvdata->state; 47} 48 49static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev, 50 unsigned selector) 51{ 52 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 53 int dutycycle; 54 int ret; 55 56 dutycycle = (ST_PWM_REG_PERIOD / 100) * 57 drvdata->pdata->duty_cycle_table[selector].dutycycle; 58 59 ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD); 60 if (ret) { 61 dev_err(&dev->dev, "Failed to configure PWM\n"); 62 return ret; 63 } 64 65 drvdata->state = selector; 66 67 if (!drvdata->enabled) { 68 ret = pwm_enable(drvdata->pwm); 69 if (ret) { 70 dev_err(&dev->dev, "Failed to enable PWM\n"); 71 return ret; 72 } 73 drvdata->enabled = true; 74 } 75 76 return 0; 77} 78 79static int st_pwm_regulator_list_voltage(struct regulator_dev *dev, 80 unsigned selector) 81{ 82 struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); 83 84 if (selector >= dev->desc->n_voltages) 85 return -EINVAL; 86 87 return drvdata->pdata->duty_cycle_table[selector].uV; 88} 89 90static struct regulator_ops st_pwm_regulator_voltage_ops = { 91 .set_voltage_sel = st_pwm_regulator_set_voltage_sel, 92 .get_voltage_sel = st_pwm_regulator_get_voltage_sel, 93 .list_voltage = st_pwm_regulator_list_voltage, 94 .map_voltage = regulator_map_voltage_iterate, 95}; 96 97static struct st_pwm_voltages b2105_duty_cycle_table[] = { 98 { .uV = 1114000, .dutycycle = 0, }, 99 { .uV = 1095000, .dutycycle = 10, }, 100 { .uV = 1076000, .dutycycle = 20, }, 101 { .uV = 1056000, .dutycycle = 30, }, 102 { .uV = 1036000, .dutycycle = 40, }, 103 { .uV = 1016000, .dutycycle = 50, }, 104 /* WARNING: Values above 50% duty-cycle cause boot failures. */ 105}; 106 107static const struct regulator_desc b2105_desc = { 108 .name = "b2105-pwm-regulator", 109 .ops = &st_pwm_regulator_voltage_ops, 110 .type = REGULATOR_VOLTAGE, 111 .owner = THIS_MODULE, 112 .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table), 113 .supply_name = "pwm", 114}; 115 116static const struct st_pwm_regulator_pdata b2105_info = { 117 .desc = &b2105_desc, 118 .duty_cycle_table = b2105_duty_cycle_table, 119}; 120 121static struct of_device_id st_pwm_of_match[] = { 122 { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, 123 { }, 124}; 125MODULE_DEVICE_TABLE(of, st_pwm_of_match); 126 127static int st_pwm_regulator_probe(struct platform_device *pdev) 128{ 129 struct st_pwm_regulator_data *drvdata; 130 struct regulator_dev *regulator; 131 struct regulator_config config = { }; 132 struct device_node *np = pdev->dev.of_node; 133 const struct of_device_id *of_match; 134 135 if (!np) { 136 dev_err(&pdev->dev, "Device Tree node missing\n"); 137 return -EINVAL; 138 } 139 140 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 141 if (!drvdata) 142 return -ENOMEM; 143 144 of_match = of_match_device(st_pwm_of_match, &pdev->dev); 145 if (!of_match) { 146 dev_err(&pdev->dev, "failed to match of device\n"); 147 return -ENODEV; 148 } 149 drvdata->pdata = of_match->data; 150 151 config.init_data = of_get_regulator_init_data(&pdev->dev, np); 152 if (!config.init_data) 153 return -ENOMEM; 154 155 config.of_node = np; 156 config.dev = &pdev->dev; 157 config.driver_data = drvdata; 158 159 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); 160 if (IS_ERR(drvdata->pwm)) { 161 dev_err(&pdev->dev, "Failed to get PWM\n"); 162 return PTR_ERR(drvdata->pwm); 163 } 164 165 regulator = devm_regulator_register(&pdev->dev, 166 drvdata->pdata->desc, &config); 167 if (IS_ERR(regulator)) { 168 dev_err(&pdev->dev, "Failed to register regulator %s\n", 169 drvdata->pdata->desc->name); 170 return PTR_ERR(regulator); 171 } 172 173 return 0; 174} 175 176static struct platform_driver st_pwm_regulator_driver = { 177 .driver = { 178 .name = "st-pwm-regulator", 179 .owner = THIS_MODULE, 180 .of_match_table = of_match_ptr(st_pwm_of_match), 181 }, 182 .probe = st_pwm_regulator_probe, 183}; 184 185module_platform_driver(st_pwm_regulator_driver); 186 187MODULE_LICENSE("GPL"); 188MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); 189MODULE_DESCRIPTION("ST PWM Regulator Driver"); 190MODULE_ALIAS("platform:st_pwm-regulator");