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.5-rc7 245 lines 6.8 kB view raw
1/* 2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. 3 */ 4 5/* 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21#include <linux/slab.h> 22#include <linux/device.h> 23#include <linux/module.h> 24#include <linux/err.h> 25#include <linux/io.h> 26#include <linux/platform_device.h> 27#include <linux/of.h> 28#include <linux/of_address.h> 29#include <linux/mfd/anatop.h> 30#include <linux/regulator/driver.h> 31#include <linux/regulator/of_regulator.h> 32 33struct anatop_regulator { 34 const char *name; 35 u32 control_reg; 36 struct anatop *mfd; 37 int vol_bit_shift; 38 int vol_bit_width; 39 int min_bit_val; 40 int min_voltage; 41 int max_voltage; 42 struct regulator_desc rdesc; 43 struct regulator_init_data *initdata; 44}; 45 46static int anatop_set_voltage(struct regulator_dev *reg, int min_uV, 47 int max_uV, unsigned *selector) 48{ 49 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 50 u32 val, sel, mask; 51 int uv; 52 53 uv = min_uV; 54 dev_dbg(&reg->dev, "%s: uv %d, min %d, max %d\n", __func__, 55 uv, anatop_reg->min_voltage, 56 anatop_reg->max_voltage); 57 58 if (uv < anatop_reg->min_voltage) { 59 if (max_uV > anatop_reg->min_voltage) 60 uv = anatop_reg->min_voltage; 61 else 62 return -EINVAL; 63 } 64 65 if (!anatop_reg->control_reg) 66 return -ENOTSUPP; 67 68 sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000); 69 if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage) 70 return -EINVAL; 71 val = anatop_reg->min_bit_val + sel; 72 *selector = sel; 73 dev_dbg(&reg->dev, "%s: calculated val %d\n", __func__, val); 74 mask = ((1 << anatop_reg->vol_bit_width) - 1) << 75 anatop_reg->vol_bit_shift; 76 val <<= anatop_reg->vol_bit_shift; 77 anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask); 78 79 return 0; 80} 81 82static int anatop_get_voltage_sel(struct regulator_dev *reg) 83{ 84 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 85 u32 val; 86 87 if (!anatop_reg->control_reg) 88 return -ENOTSUPP; 89 90 val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg); 91 val = (val & ((1 << anatop_reg->vol_bit_width) - 1)) >> 92 anatop_reg->vol_bit_shift; 93 94 return val - anatop_reg->min_bit_val; 95} 96 97static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector) 98{ 99 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 100 int uv; 101 102 uv = anatop_reg->min_voltage + selector * 25000; 103 dev_dbg(&reg->dev, "vddio = %d, selector = %u\n", uv, selector); 104 105 return uv; 106} 107 108static struct regulator_ops anatop_rops = { 109 .set_voltage = anatop_set_voltage, 110 .get_voltage_sel = anatop_get_voltage_sel, 111 .list_voltage = anatop_list_voltage, 112}; 113 114static int __devinit anatop_regulator_probe(struct platform_device *pdev) 115{ 116 struct device *dev = &pdev->dev; 117 struct device_node *np = dev->of_node; 118 struct regulator_desc *rdesc; 119 struct regulator_dev *rdev; 120 struct anatop_regulator *sreg; 121 struct regulator_init_data *initdata; 122 struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent); 123 struct regulator_config config = { }; 124 int ret = 0; 125 126 initdata = of_get_regulator_init_data(dev, np); 127 sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); 128 if (!sreg) 129 return -ENOMEM; 130 sreg->initdata = initdata; 131 sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL), 132 GFP_KERNEL); 133 rdesc = &sreg->rdesc; 134 memset(rdesc, 0, sizeof(*rdesc)); 135 rdesc->name = sreg->name; 136 rdesc->ops = &anatop_rops; 137 rdesc->type = REGULATOR_VOLTAGE; 138 rdesc->owner = THIS_MODULE; 139 sreg->mfd = anatopmfd; 140 ret = of_property_read_u32(np, "anatop-reg-offset", 141 &sreg->control_reg); 142 if (ret) { 143 dev_err(dev, "no anatop-reg-offset property set\n"); 144 goto anatop_probe_end; 145 } 146 ret = of_property_read_u32(np, "anatop-vol-bit-width", 147 &sreg->vol_bit_width); 148 if (ret) { 149 dev_err(dev, "no anatop-vol-bit-width property set\n"); 150 goto anatop_probe_end; 151 } 152 ret = of_property_read_u32(np, "anatop-vol-bit-shift", 153 &sreg->vol_bit_shift); 154 if (ret) { 155 dev_err(dev, "no anatop-vol-bit-shift property set\n"); 156 goto anatop_probe_end; 157 } 158 ret = of_property_read_u32(np, "anatop-min-bit-val", 159 &sreg->min_bit_val); 160 if (ret) { 161 dev_err(dev, "no anatop-min-bit-val property set\n"); 162 goto anatop_probe_end; 163 } 164 ret = of_property_read_u32(np, "anatop-min-voltage", 165 &sreg->min_voltage); 166 if (ret) { 167 dev_err(dev, "no anatop-min-voltage property set\n"); 168 goto anatop_probe_end; 169 } 170 ret = of_property_read_u32(np, "anatop-max-voltage", 171 &sreg->max_voltage); 172 if (ret) { 173 dev_err(dev, "no anatop-max-voltage property set\n"); 174 goto anatop_probe_end; 175 } 176 177 rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) 178 / 25000 + 1; 179 180 config.dev = &pdev->dev; 181 config.init_data = initdata; 182 config.driver_data = sreg; 183 config.of_node = pdev->dev.of_node; 184 185 /* register regulator */ 186 rdev = regulator_register(rdesc, &config); 187 if (IS_ERR(rdev)) { 188 dev_err(dev, "failed to register %s\n", 189 rdesc->name); 190 ret = PTR_ERR(rdev); 191 goto anatop_probe_end; 192 } 193 194 platform_set_drvdata(pdev, rdev); 195 196anatop_probe_end: 197 if (ret) 198 kfree(sreg->name); 199 200 return ret; 201} 202 203static int __devexit anatop_regulator_remove(struct platform_device *pdev) 204{ 205 struct regulator_dev *rdev = platform_get_drvdata(pdev); 206 struct anatop_regulator *sreg = rdev_get_drvdata(rdev); 207 const char *name = sreg->name; 208 209 regulator_unregister(rdev); 210 kfree(name); 211 212 return 0; 213} 214 215static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = { 216 { .compatible = "fsl,anatop-regulator", }, 217 { /* end */ } 218}; 219 220static struct platform_driver anatop_regulator_driver = { 221 .driver = { 222 .name = "anatop_regulator", 223 .owner = THIS_MODULE, 224 .of_match_table = of_anatop_regulator_match_tbl, 225 }, 226 .probe = anatop_regulator_probe, 227 .remove = __devexit_p(anatop_regulator_remove), 228}; 229 230static int __init anatop_regulator_init(void) 231{ 232 return platform_driver_register(&anatop_regulator_driver); 233} 234postcore_initcall(anatop_regulator_init); 235 236static void __exit anatop_regulator_exit(void) 237{ 238 platform_driver_unregister(&anatop_regulator_driver); 239} 240module_exit(anatop_regulator_exit); 241 242MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " 243 "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); 244MODULE_DESCRIPTION("ANATOP Regulator driver"); 245MODULE_LICENSE("GPL v2");