diff options
author | Jin Park <jinyoungp@nvidia.com> | 2011-07-04 04:43:42 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-07-31 17:28:26 -0400 |
commit | f7eb6c5e8e5e1e96c36763778e9a78b9da6fcd31 (patch) | |
tree | 2a1981407f4d09556fdf7ed16f5cb4007c43ce0a /drivers/regulator/aat2870-regulator.c | |
parent | 4b0d711be39f927200e4aaee51176091f9ba22e2 (diff) |
regulator: aat2870: Add AAT2870 regulator driver
Add regulator driver for AnalogicTech AAT2870.
Signed-off-by: Jin Park <jinyoungp@nvidia.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/regulator/aat2870-regulator.c')
-rw-r--r-- | drivers/regulator/aat2870-regulator.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c new file mode 100644 index 000000000000..cd4104542f0d --- /dev/null +++ b/drivers/regulator/aat2870-regulator.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * linux/drivers/regulator/aat2870-regulator.c | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * Author: Jin Park <jinyoungp@nvidia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/regulator/driver.h> | ||
29 | #include <linux/regulator/machine.h> | ||
30 | #include <linux/mfd/aat2870.h> | ||
31 | |||
32 | struct aat2870_regulator { | ||
33 | struct platform_device *pdev; | ||
34 | struct regulator_desc desc; | ||
35 | |||
36 | const int *voltages; /* uV */ | ||
37 | |||
38 | int min_uV; | ||
39 | int max_uV; | ||
40 | |||
41 | u8 enable_addr; | ||
42 | u8 enable_shift; | ||
43 | u8 enable_mask; | ||
44 | |||
45 | u8 voltage_addr; | ||
46 | u8 voltage_shift; | ||
47 | u8 voltage_mask; | ||
48 | }; | ||
49 | |||
50 | static int aat2870_ldo_list_voltage(struct regulator_dev *rdev, | ||
51 | unsigned selector) | ||
52 | { | ||
53 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
54 | |||
55 | return ri->voltages[selector]; | ||
56 | } | ||
57 | |||
58 | static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, | ||
59 | unsigned selector) | ||
60 | { | ||
61 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
62 | struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); | ||
63 | |||
64 | return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask, | ||
65 | (selector << ri->voltage_shift) & ri->voltage_mask); | ||
66 | } | ||
67 | |||
68 | static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) | ||
69 | { | ||
70 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
71 | struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); | ||
72 | u8 val; | ||
73 | int ret; | ||
74 | |||
75 | ret = aat2870->read(aat2870, ri->voltage_addr, &val); | ||
76 | if (ret) | ||
77 | return ret; | ||
78 | |||
79 | return (val & ri->voltage_mask) >> ri->voltage_shift; | ||
80 | } | ||
81 | |||
82 | static int aat2870_ldo_enable(struct regulator_dev *rdev) | ||
83 | { | ||
84 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
85 | struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); | ||
86 | |||
87 | return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, | ||
88 | ri->enable_mask); | ||
89 | } | ||
90 | |||
91 | static int aat2870_ldo_disable(struct regulator_dev *rdev) | ||
92 | { | ||
93 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
94 | struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); | ||
95 | |||
96 | return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0); | ||
97 | } | ||
98 | |||
99 | static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) | ||
100 | { | ||
101 | struct aat2870_regulator *ri = rdev_get_drvdata(rdev); | ||
102 | struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); | ||
103 | u8 val; | ||
104 | int ret; | ||
105 | |||
106 | ret = aat2870->read(aat2870, ri->enable_addr, &val); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | return val & ri->enable_mask ? 1 : 0; | ||
111 | } | ||
112 | |||
113 | static struct regulator_ops aat2870_ldo_ops = { | ||
114 | .list_voltage = aat2870_ldo_list_voltage, | ||
115 | .set_voltage_sel = aat2870_ldo_set_voltage_sel, | ||
116 | .get_voltage_sel = aat2870_ldo_get_voltage_sel, | ||
117 | .enable = aat2870_ldo_enable, | ||
118 | .disable = aat2870_ldo_disable, | ||
119 | .is_enabled = aat2870_ldo_is_enabled, | ||
120 | }; | ||
121 | |||
122 | static const int aat2870_ldo_voltages[] = { | ||
123 | 1200000, 1300000, 1500000, 1600000, | ||
124 | 1800000, 2000000, 2200000, 2500000, | ||
125 | 2600000, 2700000, 2800000, 2900000, | ||
126 | 3000000, 3100000, 3200000, 3300000, | ||
127 | }; | ||
128 | |||
129 | #define AAT2870_LDO(ids) \ | ||
130 | { \ | ||
131 | .desc = { \ | ||
132 | .name = #ids, \ | ||
133 | .id = AAT2870_ID_##ids, \ | ||
134 | .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ | ||
135 | .ops = &aat2870_ldo_ops, \ | ||
136 | .type = REGULATOR_VOLTAGE, \ | ||
137 | .owner = THIS_MODULE, \ | ||
138 | }, \ | ||
139 | .voltages = aat2870_ldo_voltages, \ | ||
140 | .min_uV = 1200000, \ | ||
141 | .max_uV = 3300000, \ | ||
142 | } | ||
143 | |||
144 | static struct aat2870_regulator aat2870_regulators[] = { | ||
145 | AAT2870_LDO(LDOA), | ||
146 | AAT2870_LDO(LDOB), | ||
147 | AAT2870_LDO(LDOC), | ||
148 | AAT2870_LDO(LDOD), | ||
149 | }; | ||
150 | |||
151 | static struct aat2870_regulator *aat2870_get_regulator(int id) | ||
152 | { | ||
153 | struct aat2870_regulator *ri = NULL; | ||
154 | int i; | ||
155 | |||
156 | for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) { | ||
157 | ri = &aat2870_regulators[i]; | ||
158 | if (ri->desc.id == id) | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | if (!ri) | ||
163 | return NULL; | ||
164 | |||
165 | ri->enable_addr = AAT2870_LDO_EN; | ||
166 | ri->enable_shift = id - AAT2870_ID_LDOA; | ||
167 | ri->enable_mask = 0x1 << ri->enable_shift; | ||
168 | |||
169 | ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ? | ||
170 | AAT2870_LDO_CD : AAT2870_LDO_AB; | ||
171 | ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4; | ||
172 | ri->voltage_mask = 0xF << ri->voltage_shift; | ||
173 | |||
174 | return ri; | ||
175 | } | ||
176 | |||
177 | static int aat2870_regulator_probe(struct platform_device *pdev) | ||
178 | { | ||
179 | struct aat2870_regulator *ri; | ||
180 | struct regulator_dev *rdev; | ||
181 | |||
182 | ri = aat2870_get_regulator(pdev->id); | ||
183 | if (!ri) { | ||
184 | dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id); | ||
185 | return -EINVAL; | ||
186 | } | ||
187 | ri->pdev = pdev; | ||
188 | |||
189 | rdev = regulator_register(&ri->desc, &pdev->dev, | ||
190 | pdev->dev.platform_data, ri); | ||
191 | if (IS_ERR(rdev)) { | ||
192 | dev_err(&pdev->dev, "Failed to register regulator %s\n", | ||
193 | ri->desc.name); | ||
194 | return PTR_ERR(rdev); | ||
195 | } | ||
196 | platform_set_drvdata(pdev, rdev); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int __devexit aat2870_regulator_remove(struct platform_device *pdev) | ||
202 | { | ||
203 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | ||
204 | |||
205 | regulator_unregister(rdev); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static struct platform_driver aat2870_regulator_driver = { | ||
210 | .driver = { | ||
211 | .name = "aat2870-regulator", | ||
212 | .owner = THIS_MODULE, | ||
213 | }, | ||
214 | .probe = aat2870_regulator_probe, | ||
215 | .remove = __devexit_p(aat2870_regulator_remove), | ||
216 | }; | ||
217 | |||
218 | static int __init aat2870_regulator_init(void) | ||
219 | { | ||
220 | return platform_driver_register(&aat2870_regulator_driver); | ||
221 | } | ||
222 | subsys_initcall(aat2870_regulator_init); | ||
223 | |||
224 | static void __exit aat2870_regulator_exit(void) | ||
225 | { | ||
226 | platform_driver_unregister(&aat2870_regulator_driver); | ||
227 | } | ||
228 | module_exit(aat2870_regulator_exit); | ||
229 | |||
230 | MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator"); | ||
231 | MODULE_LICENSE("GPL"); | ||
232 | MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>"); | ||