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 33 struct 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 46 static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) 47 { 48 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 49 u32 val, mask; 50 51 if (!anatop_reg->control_reg) 52 return -ENOTSUPP; 53 54 val = anatop_reg->min_bit_val + selector; 55 dev_dbg(®->dev, "%s: calculated val %d\n", __func__, val); 56 mask = ((1 << anatop_reg->vol_bit_width) - 1) << 57 anatop_reg->vol_bit_shift; 58 val <<= anatop_reg->vol_bit_shift; 59 anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask); 60 61 return 0; 62 } 63 64 static int anatop_get_voltage_sel(struct regulator_dev *reg) 65 { 66 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 67 u32 val, mask; 68 69 if (!anatop_reg->control_reg) 70 return -ENOTSUPP; 71 72 val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg); 73 mask = ((1 << anatop_reg->vol_bit_width) - 1) << 74 anatop_reg->vol_bit_shift; 75 val = (val & mask) >> anatop_reg->vol_bit_shift; 76 77 return val - anatop_reg->min_bit_val; 78 } 79 80 static struct regulator_ops anatop_rops = { 81 .set_voltage_sel = anatop_set_voltage_sel, 82 .get_voltage_sel = anatop_get_voltage_sel, 83 .list_voltage = regulator_list_voltage_linear, 84 .map_voltage = regulator_map_voltage_linear, 85 }; 86 87 static int __devinit anatop_regulator_probe(struct platform_device *pdev) 88 { 89 struct device *dev = &pdev->dev; 90 struct device_node *np = dev->of_node; 91 struct regulator_desc *rdesc; 92 struct regulator_dev *rdev; 93 struct anatop_regulator *sreg; 94 struct regulator_init_data *initdata; 95 struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent); 96 struct regulator_config config = { }; 97 int ret = 0; 98 99 initdata = of_get_regulator_init_data(dev, np); 100 sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); 101 if (!sreg) 102 return -ENOMEM; 103 sreg->initdata = initdata; 104 sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL), 105 GFP_KERNEL); 106 rdesc = &sreg->rdesc; 107 memset(rdesc, 0, sizeof(*rdesc)); 108 rdesc->name = sreg->name; 109 rdesc->ops = &anatop_rops; 110 rdesc->type = REGULATOR_VOLTAGE; 111 rdesc->owner = THIS_MODULE; 112 sreg->mfd = anatopmfd; 113 ret = of_property_read_u32(np, "anatop-reg-offset", 114 &sreg->control_reg); 115 if (ret) { 116 dev_err(dev, "no anatop-reg-offset property set\n"); 117 goto anatop_probe_end; 118 } 119 ret = of_property_read_u32(np, "anatop-vol-bit-width", 120 &sreg->vol_bit_width); 121 if (ret) { 122 dev_err(dev, "no anatop-vol-bit-width property set\n"); 123 goto anatop_probe_end; 124 } 125 ret = of_property_read_u32(np, "anatop-vol-bit-shift", 126 &sreg->vol_bit_shift); 127 if (ret) { 128 dev_err(dev, "no anatop-vol-bit-shift property set\n"); 129 goto anatop_probe_end; 130 } 131 ret = of_property_read_u32(np, "anatop-min-bit-val", 132 &sreg->min_bit_val); 133 if (ret) { 134 dev_err(dev, "no anatop-min-bit-val property set\n"); 135 goto anatop_probe_end; 136 } 137 ret = of_property_read_u32(np, "anatop-min-voltage", 138 &sreg->min_voltage); 139 if (ret) { 140 dev_err(dev, "no anatop-min-voltage property set\n"); 141 goto anatop_probe_end; 142 } 143 ret = of_property_read_u32(np, "anatop-max-voltage", 144 &sreg->max_voltage); 145 if (ret) { 146 dev_err(dev, "no anatop-max-voltage property set\n"); 147 goto anatop_probe_end; 148 } 149 150 rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) 151 / 25000 + 1; 152 rdesc->min_uV = sreg->min_voltage; 153 rdesc->uV_step = 25000; 154 155 config.dev = &pdev->dev; 156 config.init_data = initdata; 157 config.driver_data = sreg; 158 config.of_node = pdev->dev.of_node; 159 160 /* register regulator */ 161 rdev = regulator_register(rdesc, &config); 162 if (IS_ERR(rdev)) { 163 dev_err(dev, "failed to register %s\n", 164 rdesc->name); 165 ret = PTR_ERR(rdev); 166 goto anatop_probe_end; 167 } 168 169 platform_set_drvdata(pdev, rdev); 170 171 anatop_probe_end: 172 if (ret) 173 kfree(sreg->name); 174 175 return ret; 176 } 177 178 static int __devexit anatop_regulator_remove(struct platform_device *pdev) 179 { 180 struct regulator_dev *rdev = platform_get_drvdata(pdev); 181 struct anatop_regulator *sreg = rdev_get_drvdata(rdev); 182 const char *name = sreg->name; 183 184 regulator_unregister(rdev); 185 kfree(name); 186 187 return 0; 188 } 189 190 static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = { 191 { .compatible = "fsl,anatop-regulator", }, 192 { /* end */ } 193 }; 194 195 static struct platform_driver anatop_regulator_driver = { 196 .driver = { 197 .name = "anatop_regulator", 198 .owner = THIS_MODULE, 199 .of_match_table = of_anatop_regulator_match_tbl, 200 }, 201 .probe = anatop_regulator_probe, 202 .remove = __devexit_p(anatop_regulator_remove), 203 }; 204 205 static int __init anatop_regulator_init(void) 206 { 207 return platform_driver_register(&anatop_regulator_driver); 208 } 209 postcore_initcall(anatop_regulator_init); 210 211 static void __exit anatop_regulator_exit(void) 212 { 213 platform_driver_unregister(&anatop_regulator_driver); 214 } 215 module_exit(anatop_regulator_exit); 216 217 MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " 218 "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); 219 MODULE_DESCRIPTION("ANATOP Regulator driver"); 220 MODULE_LICENSE("GPL v2"); 221