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