Root/
1 | /* |
2 | * Voltage and current regulation for AD5398 and AD5821 |
3 | * |
4 | * Copyright 2010 Analog Devices Inc. |
5 | * |
6 | * Enter bugs at http://blackfin.uclinux.org/ |
7 | * |
8 | * Licensed under the GPL-2 or later. |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/err.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/regulator/driver.h> |
17 | #include <linux/regulator/machine.h> |
18 | |
19 | #define AD5398_CURRENT_EN_MASK 0x8000 |
20 | |
21 | struct ad5398_chip_info { |
22 | struct i2c_client *client; |
23 | int min_uA; |
24 | int max_uA; |
25 | unsigned int current_level; |
26 | unsigned int current_mask; |
27 | unsigned int current_offset; |
28 | struct regulator_dev *rdev; |
29 | }; |
30 | |
31 | static int ad5398_calc_current(struct ad5398_chip_info *chip, |
32 | unsigned selector) |
33 | { |
34 | unsigned range_uA = chip->max_uA - chip->min_uA; |
35 | |
36 | return chip->min_uA + (selector * range_uA / chip->current_level); |
37 | } |
38 | |
39 | static int ad5398_read_reg(struct i2c_client *client, unsigned short *data) |
40 | { |
41 | unsigned short val; |
42 | int ret; |
43 | |
44 | ret = i2c_master_recv(client, (char *)&val, 2); |
45 | if (ret < 0) { |
46 | dev_err(&client->dev, "I2C read error\n"); |
47 | return ret; |
48 | } |
49 | *data = be16_to_cpu(val); |
50 | |
51 | return ret; |
52 | } |
53 | |
54 | static int ad5398_write_reg(struct i2c_client *client, const unsigned short data) |
55 | { |
56 | unsigned short val; |
57 | int ret; |
58 | |
59 | val = cpu_to_be16(data); |
60 | ret = i2c_master_send(client, (char *)&val, 2); |
61 | if (ret < 0) |
62 | dev_err(&client->dev, "I2C write error\n"); |
63 | |
64 | return ret; |
65 | } |
66 | |
67 | static int ad5398_get_current_limit(struct regulator_dev *rdev) |
68 | { |
69 | struct ad5398_chip_info *chip = rdev_get_drvdata(rdev); |
70 | struct i2c_client *client = chip->client; |
71 | unsigned short data; |
72 | int ret; |
73 | |
74 | ret = ad5398_read_reg(client, &data); |
75 | if (ret < 0) |
76 | return ret; |
77 | |
78 | ret = (data & chip->current_mask) >> chip->current_offset; |
79 | |
80 | return ad5398_calc_current(chip, ret); |
81 | } |
82 | |
83 | static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) |
84 | { |
85 | struct ad5398_chip_info *chip = rdev_get_drvdata(rdev); |
86 | struct i2c_client *client = chip->client; |
87 | unsigned range_uA = chip->max_uA - chip->min_uA; |
88 | unsigned selector; |
89 | unsigned short data; |
90 | int ret; |
91 | |
92 | if (min_uA < chip->min_uA) |
93 | min_uA = chip->min_uA; |
94 | if (max_uA > chip->max_uA) |
95 | max_uA = chip->max_uA; |
96 | |
97 | if (min_uA > chip->max_uA || max_uA < chip->min_uA) |
98 | return -EINVAL; |
99 | |
100 | selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level, |
101 | range_uA); |
102 | if (ad5398_calc_current(chip, selector) > max_uA) |
103 | return -EINVAL; |
104 | |
105 | dev_dbg(&client->dev, "changing current %duA\n", |
106 | ad5398_calc_current(chip, selector)); |
107 | |
108 | /* read chip enable bit */ |
109 | ret = ad5398_read_reg(client, &data); |
110 | if (ret < 0) |
111 | return ret; |
112 | |
113 | /* prepare register data */ |
114 | selector = (selector << chip->current_offset) & chip->current_mask; |
115 | data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK); |
116 | |
117 | /* write the new current value back as well as enable bit */ |
118 | ret = ad5398_write_reg(client, data); |
119 | |
120 | return ret; |
121 | } |
122 | |
123 | static int ad5398_is_enabled(struct regulator_dev *rdev) |
124 | { |
125 | struct ad5398_chip_info *chip = rdev_get_drvdata(rdev); |
126 | struct i2c_client *client = chip->client; |
127 | unsigned short data; |
128 | int ret; |
129 | |
130 | ret = ad5398_read_reg(client, &data); |
131 | if (ret < 0) |
132 | return ret; |
133 | |
134 | if (data & AD5398_CURRENT_EN_MASK) |
135 | return 1; |
136 | else |
137 | return 0; |
138 | } |
139 | |
140 | static int ad5398_enable(struct regulator_dev *rdev) |
141 | { |
142 | struct ad5398_chip_info *chip = rdev_get_drvdata(rdev); |
143 | struct i2c_client *client = chip->client; |
144 | unsigned short data; |
145 | int ret; |
146 | |
147 | ret = ad5398_read_reg(client, &data); |
148 | if (ret < 0) |
149 | return ret; |
150 | |
151 | if (data & AD5398_CURRENT_EN_MASK) |
152 | return 0; |
153 | |
154 | data |= AD5398_CURRENT_EN_MASK; |
155 | |
156 | ret = ad5398_write_reg(client, data); |
157 | |
158 | return ret; |
159 | } |
160 | |
161 | static int ad5398_disable(struct regulator_dev *rdev) |
162 | { |
163 | struct ad5398_chip_info *chip = rdev_get_drvdata(rdev); |
164 | struct i2c_client *client = chip->client; |
165 | unsigned short data; |
166 | int ret; |
167 | |
168 | ret = ad5398_read_reg(client, &data); |
169 | if (ret < 0) |
170 | return ret; |
171 | |
172 | if (!(data & AD5398_CURRENT_EN_MASK)) |
173 | return 0; |
174 | |
175 | data &= ~AD5398_CURRENT_EN_MASK; |
176 | |
177 | ret = ad5398_write_reg(client, data); |
178 | |
179 | return ret; |
180 | } |
181 | |
182 | static struct regulator_ops ad5398_ops = { |
183 | .get_current_limit = ad5398_get_current_limit, |
184 | .set_current_limit = ad5398_set_current_limit, |
185 | .enable = ad5398_enable, |
186 | .disable = ad5398_disable, |
187 | .is_enabled = ad5398_is_enabled, |
188 | }; |
189 | |
190 | static const struct regulator_desc ad5398_reg = { |
191 | .name = "isink", |
192 | .id = 0, |
193 | .ops = &ad5398_ops, |
194 | .type = REGULATOR_CURRENT, |
195 | .owner = THIS_MODULE, |
196 | }; |
197 | |
198 | struct ad5398_current_data_format { |
199 | int current_bits; |
200 | int current_offset; |
201 | int min_uA; |
202 | int max_uA; |
203 | }; |
204 | |
205 | static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000}; |
206 | |
207 | static const struct i2c_device_id ad5398_id[] = { |
208 | { "ad5398", (kernel_ulong_t)&df_10_4_120 }, |
209 | { "ad5821", (kernel_ulong_t)&df_10_4_120 }, |
210 | { } |
211 | }; |
212 | MODULE_DEVICE_TABLE(i2c, ad5398_id); |
213 | |
214 | static int __devinit ad5398_probe(struct i2c_client *client, |
215 | const struct i2c_device_id *id) |
216 | { |
217 | struct regulator_init_data *init_data = client->dev.platform_data; |
218 | struct regulator_config config = { }; |
219 | struct ad5398_chip_info *chip; |
220 | const struct ad5398_current_data_format *df = |
221 | (struct ad5398_current_data_format *)id->driver_data; |
222 | int ret; |
223 | |
224 | if (!init_data) |
225 | return -EINVAL; |
226 | |
227 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); |
228 | if (!chip) |
229 | return -ENOMEM; |
230 | |
231 | config.dev = &client->dev; |
232 | config.init_data = init_data; |
233 | config.driver_data = chip; |
234 | |
235 | chip->client = client; |
236 | |
237 | chip->min_uA = df->min_uA; |
238 | chip->max_uA = df->max_uA; |
239 | chip->current_level = 1 << df->current_bits; |
240 | chip->current_offset = df->current_offset; |
241 | chip->current_mask = (chip->current_level - 1) << chip->current_offset; |
242 | |
243 | chip->rdev = regulator_register(&ad5398_reg, &config); |
244 | if (IS_ERR(chip->rdev)) { |
245 | ret = PTR_ERR(chip->rdev); |
246 | dev_err(&client->dev, "failed to register %s %s\n", |
247 | id->name, ad5398_reg.name); |
248 | goto err; |
249 | } |
250 | |
251 | i2c_set_clientdata(client, chip); |
252 | dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name); |
253 | return 0; |
254 | |
255 | err: |
256 | return ret; |
257 | } |
258 | |
259 | static int __devexit ad5398_remove(struct i2c_client *client) |
260 | { |
261 | struct ad5398_chip_info *chip = i2c_get_clientdata(client); |
262 | |
263 | regulator_unregister(chip->rdev); |
264 | return 0; |
265 | } |
266 | |
267 | static struct i2c_driver ad5398_driver = { |
268 | .probe = ad5398_probe, |
269 | .remove = __devexit_p(ad5398_remove), |
270 | .driver = { |
271 | .name = "ad5398", |
272 | }, |
273 | .id_table = ad5398_id, |
274 | }; |
275 | |
276 | static int __init ad5398_init(void) |
277 | { |
278 | return i2c_add_driver(&ad5398_driver); |
279 | } |
280 | subsys_initcall(ad5398_init); |
281 | |
282 | static void __exit ad5398_exit(void) |
283 | { |
284 | i2c_del_driver(&ad5398_driver); |
285 | } |
286 | module_exit(ad5398_exit); |
287 | |
288 | MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver"); |
289 | MODULE_AUTHOR("Sonic Zhang"); |
290 | MODULE_LICENSE("GPL"); |
291 | MODULE_ALIAS("i2c:ad5398-regulator"); |
292 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9