diff options
Diffstat (limited to 'drivers/mfd/da903x.c')
-rw-r--r-- | drivers/mfd/da903x.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c new file mode 100644 index 000000000000..b57326ae464d --- /dev/null +++ b/drivers/mfd/da903x.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Base driver for Dialog Semiconductor DA9030/DA9034 | ||
3 | * | ||
4 | * Copyright (C) 2008 Compulab, Ltd. | ||
5 | * Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * Copyright (C) 2006-2008 Marvell International Ltd. | ||
8 | * Eric Miao <eric.miao@marvell.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/mfd/da903x.h> | ||
21 | |||
22 | #define DA9030_CHIP_ID 0x00 | ||
23 | #define DA9030_EVENT_A 0x01 | ||
24 | #define DA9030_EVENT_B 0x02 | ||
25 | #define DA9030_EVENT_C 0x03 | ||
26 | #define DA9030_STATUS 0x04 | ||
27 | #define DA9030_IRQ_MASK_A 0x05 | ||
28 | #define DA9030_IRQ_MASK_B 0x06 | ||
29 | #define DA9030_IRQ_MASK_C 0x07 | ||
30 | #define DA9030_SYS_CTRL_A 0x08 | ||
31 | #define DA9030_SYS_CTRL_B 0x09 | ||
32 | #define DA9030_FAULT_LOG 0x0a | ||
33 | |||
34 | #define DA9034_CHIP_ID 0x00 | ||
35 | #define DA9034_EVENT_A 0x01 | ||
36 | #define DA9034_EVENT_B 0x02 | ||
37 | #define DA9034_EVENT_C 0x03 | ||
38 | #define DA9034_EVENT_D 0x04 | ||
39 | #define DA9034_STATUS_A 0x05 | ||
40 | #define DA9034_STATUS_B 0x06 | ||
41 | #define DA9034_IRQ_MASK_A 0x07 | ||
42 | #define DA9034_IRQ_MASK_B 0x08 | ||
43 | #define DA9034_IRQ_MASK_C 0x09 | ||
44 | #define DA9034_IRQ_MASK_D 0x0a | ||
45 | #define DA9034_SYS_CTRL_A 0x0b | ||
46 | #define DA9034_SYS_CTRL_B 0x0c | ||
47 | #define DA9034_FAULT_LOG 0x0d | ||
48 | |||
49 | struct da903x_chip; | ||
50 | |||
51 | struct da903x_chip_ops { | ||
52 | int (*init_chip)(struct da903x_chip *); | ||
53 | int (*unmask_events)(struct da903x_chip *, unsigned int events); | ||
54 | int (*mask_events)(struct da903x_chip *, unsigned int events); | ||
55 | int (*read_events)(struct da903x_chip *, unsigned int *events); | ||
56 | int (*read_status)(struct da903x_chip *, unsigned int *status); | ||
57 | }; | ||
58 | |||
59 | struct da903x_chip { | ||
60 | struct i2c_client *client; | ||
61 | struct device *dev; | ||
62 | struct da903x_chip_ops *ops; | ||
63 | |||
64 | int type; | ||
65 | uint32_t events_mask; | ||
66 | |||
67 | struct mutex lock; | ||
68 | struct work_struct irq_work; | ||
69 | |||
70 | struct blocking_notifier_head notifier_list; | ||
71 | }; | ||
72 | |||
73 | static inline int __da903x_read(struct i2c_client *client, | ||
74 | int reg, uint8_t *val) | ||
75 | { | ||
76 | int ret; | ||
77 | |||
78 | ret = i2c_smbus_read_byte_data(client, reg); | ||
79 | if (ret < 0) { | ||
80 | dev_err(&client->dev, "failed reading at 0x%02x\n", reg); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | *val = (uint8_t)ret; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static inline int __da903x_reads(struct i2c_client *client, int reg, | ||
89 | int len, uint8_t *val) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); | ||
94 | if (ret < 0) { | ||
95 | dev_err(&client->dev, "failed reading from 0x%02x\n", reg); | ||
96 | return ret; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static inline int __da903x_write(struct i2c_client *client, | ||
102 | int reg, uint8_t val) | ||
103 | { | ||
104 | int ret; | ||
105 | |||
106 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
107 | if (ret < 0) { | ||
108 | dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", | ||
109 | val, reg); | ||
110 | return ret; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static inline int __da903x_writes(struct i2c_client *client, int reg, | ||
116 | int len, uint8_t *val) | ||
117 | { | ||
118 | int ret; | ||
119 | |||
120 | ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); | ||
121 | if (ret < 0) { | ||
122 | dev_err(&client->dev, "failed writings to 0x%02x\n", reg); | ||
123 | return ret; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | int da903x_register_notifier(struct device *dev, struct notifier_block *nb, | ||
129 | unsigned int events) | ||
130 | { | ||
131 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
132 | |||
133 | chip->ops->unmask_events(chip, events); | ||
134 | return blocking_notifier_chain_register(&chip->notifier_list, nb); | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(da903x_register_notifier); | ||
137 | |||
138 | int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb, | ||
139 | unsigned int events) | ||
140 | { | ||
141 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
142 | |||
143 | chip->ops->mask_events(chip, events); | ||
144 | return blocking_notifier_chain_unregister(&chip->notifier_list, nb); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(da903x_unregister_notifier); | ||
147 | |||
148 | int da903x_write(struct device *dev, int reg, uint8_t val) | ||
149 | { | ||
150 | return __da903x_write(to_i2c_client(dev), reg, val); | ||
151 | } | ||
152 | EXPORT_SYMBOL_GPL(da903x_write); | ||
153 | |||
154 | int da903x_read(struct device *dev, int reg, uint8_t *val) | ||
155 | { | ||
156 | return __da903x_read(to_i2c_client(dev), reg, val); | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(da903x_read); | ||
159 | |||
160 | int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
161 | { | ||
162 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
163 | uint8_t reg_val; | ||
164 | int ret = 0; | ||
165 | |||
166 | mutex_lock(&chip->lock); | ||
167 | |||
168 | ret = __da903x_read(chip->client, reg, ®_val); | ||
169 | if (ret) | ||
170 | goto out; | ||
171 | |||
172 | if ((reg_val & bit_mask) == 0) { | ||
173 | reg_val |= bit_mask; | ||
174 | ret = __da903x_write(chip->client, reg, reg_val); | ||
175 | } | ||
176 | out: | ||
177 | mutex_unlock(&chip->lock); | ||
178 | return ret; | ||
179 | } | ||
180 | EXPORT_SYMBOL_GPL(da903x_set_bits); | ||
181 | |||
182 | int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask) | ||
183 | { | ||
184 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
185 | uint8_t reg_val; | ||
186 | int ret = 0; | ||
187 | |||
188 | mutex_lock(&chip->lock); | ||
189 | |||
190 | ret = __da903x_read(chip->client, reg, ®_val); | ||
191 | if (ret) | ||
192 | goto out; | ||
193 | |||
194 | if (reg_val & bit_mask) { | ||
195 | reg_val &= ~bit_mask; | ||
196 | ret = __da903x_write(chip->client, reg, reg_val); | ||
197 | } | ||
198 | out: | ||
199 | mutex_unlock(&chip->lock); | ||
200 | return ret; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(da903x_clr_bits); | ||
203 | |||
204 | int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask) | ||
205 | { | ||
206 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
207 | uint8_t reg_val; | ||
208 | int ret = 0; | ||
209 | |||
210 | mutex_lock(&chip->lock); | ||
211 | |||
212 | ret = __da903x_read(chip->client, reg, ®_val); | ||
213 | if (ret) | ||
214 | goto out; | ||
215 | |||
216 | if ((reg_val & mask) != val) { | ||
217 | reg_val = (reg_val & ~mask) | val; | ||
218 | ret = __da903x_write(chip->client, reg, reg_val); | ||
219 | } | ||
220 | out: | ||
221 | mutex_unlock(&chip->lock); | ||
222 | return ret; | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(da903x_update); | ||
225 | |||
226 | int da903x_query_status(struct device *dev, unsigned int sbits) | ||
227 | { | ||
228 | struct da903x_chip *chip = dev_get_drvdata(dev); | ||
229 | unsigned int status = 0; | ||
230 | |||
231 | chip->ops->read_status(chip, &status); | ||
232 | return ((status & sbits) == sbits); | ||
233 | } | ||
234 | EXPORT_SYMBOL(da903x_query_status); | ||
235 | |||
236 | static int __devinit da9030_init_chip(struct da903x_chip *chip) | ||
237 | { | ||
238 | uint8_t chip_id; | ||
239 | int err; | ||
240 | |||
241 | err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id); | ||
242 | if (err) | ||
243 | return err; | ||
244 | |||
245 | err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8); | ||
246 | if (err) | ||
247 | return err; | ||
248 | |||
249 | dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events) | ||
254 | { | ||
255 | uint8_t v[3]; | ||
256 | |||
257 | chip->events_mask &= ~events; | ||
258 | |||
259 | v[0] = (chip->events_mask & 0xff); | ||
260 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
261 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
262 | |||
263 | return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); | ||
264 | } | ||
265 | |||
266 | static int da9030_mask_events(struct da903x_chip *chip, unsigned int events) | ||
267 | { | ||
268 | uint8_t v[3]; | ||
269 | |||
270 | chip->events_mask &= ~events; | ||
271 | |||
272 | v[0] = (chip->events_mask & 0xff); | ||
273 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
274 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
275 | |||
276 | return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); | ||
277 | } | ||
278 | |||
279 | static int da9030_read_events(struct da903x_chip *chip, unsigned int *events) | ||
280 | { | ||
281 | uint8_t v[3] = {0, 0, 0}; | ||
282 | int ret; | ||
283 | |||
284 | ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
288 | *events = (v[2] << 16) | (v[1] << 8) | v[0]; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int da9030_read_status(struct da903x_chip *chip, unsigned int *status) | ||
293 | { | ||
294 | return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status); | ||
295 | } | ||
296 | |||
297 | static int da9034_init_chip(struct da903x_chip *chip) | ||
298 | { | ||
299 | uint8_t chip_id; | ||
300 | int err; | ||
301 | |||
302 | err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id); | ||
303 | if (err) | ||
304 | return err; | ||
305 | |||
306 | err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8); | ||
307 | if (err) | ||
308 | return err; | ||
309 | |||
310 | /* avoid SRAM power off during sleep*/ | ||
311 | __da903x_write(chip->client, 0x10, 0x07); | ||
312 | __da903x_write(chip->client, 0x11, 0xff); | ||
313 | __da903x_write(chip->client, 0x12, 0xff); | ||
314 | |||
315 | /* Enable the ONKEY power down functionality */ | ||
316 | __da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20); | ||
317 | __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60); | ||
318 | |||
319 | /* workaround to make LEDs work */ | ||
320 | __da903x_write(chip->client, 0x90, 0x01); | ||
321 | __da903x_write(chip->client, 0xB0, 0x08); | ||
322 | |||
323 | /* make ADTV1 and SDTV1 effective */ | ||
324 | __da903x_write(chip->client, 0x20, 0x00); | ||
325 | |||
326 | dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events) | ||
331 | { | ||
332 | uint8_t v[4]; | ||
333 | |||
334 | chip->events_mask &= ~events; | ||
335 | |||
336 | v[0] = (chip->events_mask & 0xff); | ||
337 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
338 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
339 | v[3] = (chip->events_mask >> 24) & 0xff; | ||
340 | |||
341 | return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); | ||
342 | } | ||
343 | |||
344 | static int da9034_mask_events(struct da903x_chip *chip, unsigned int events) | ||
345 | { | ||
346 | uint8_t v[4]; | ||
347 | |||
348 | chip->events_mask |= events; | ||
349 | |||
350 | v[0] = (chip->events_mask & 0xff); | ||
351 | v[1] = (chip->events_mask >> 8) & 0xff; | ||
352 | v[2] = (chip->events_mask >> 16) & 0xff; | ||
353 | v[3] = (chip->events_mask >> 24) & 0xff; | ||
354 | |||
355 | return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); | ||
356 | } | ||
357 | |||
358 | static int da9034_read_events(struct da903x_chip *chip, unsigned int *events) | ||
359 | { | ||
360 | uint8_t v[4] = {0, 0, 0, 0}; | ||
361 | int ret; | ||
362 | |||
363 | ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | *events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int da9034_read_status(struct da903x_chip *chip, unsigned int *status) | ||
372 | { | ||
373 | uint8_t v[2] = {0, 0}; | ||
374 | int ret = 0; | ||
375 | |||
376 | ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v); | ||
377 | if (ret) | ||
378 | return ret; | ||
379 | |||
380 | *status = (v[1] << 8) | v[0]; | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static void da903x_irq_work(struct work_struct *work) | ||
385 | { | ||
386 | struct da903x_chip *chip = | ||
387 | container_of(work, struct da903x_chip, irq_work); | ||
388 | unsigned int events = 0; | ||
389 | |||
390 | while (1) { | ||
391 | if (chip->ops->read_events(chip, &events)) | ||
392 | break; | ||
393 | |||
394 | events &= ~chip->events_mask; | ||
395 | if (events == 0) | ||
396 | break; | ||
397 | |||
398 | blocking_notifier_call_chain( | ||
399 | &chip->notifier_list, events, NULL); | ||
400 | } | ||
401 | enable_irq(chip->client->irq); | ||
402 | } | ||
403 | |||
404 | static int da903x_irq_handler(int irq, void *data) | ||
405 | { | ||
406 | struct da903x_chip *chip = data; | ||
407 | |||
408 | disable_irq_nosync(irq); | ||
409 | (void)schedule_work(&chip->irq_work); | ||
410 | |||
411 | return IRQ_HANDLED; | ||
412 | } | ||
413 | |||
414 | static struct da903x_chip_ops da903x_ops[] = { | ||
415 | [0] = { | ||
416 | .init_chip = da9030_init_chip, | ||
417 | .unmask_events = da9030_unmask_events, | ||
418 | .mask_events = da9030_mask_events, | ||
419 | .read_events = da9030_read_events, | ||
420 | .read_status = da9030_read_status, | ||
421 | }, | ||
422 | [1] = { | ||
423 | .init_chip = da9034_init_chip, | ||
424 | .unmask_events = da9034_unmask_events, | ||
425 | .mask_events = da9034_mask_events, | ||
426 | .read_events = da9034_read_events, | ||
427 | .read_status = da9034_read_status, | ||
428 | } | ||
429 | }; | ||
430 | |||
431 | static const struct i2c_device_id da903x_id_table[] = { | ||
432 | { "da9030", 0 }, | ||
433 | { "da9034", 1 }, | ||
434 | { }, | ||
435 | }; | ||
436 | MODULE_DEVICE_TABLE(i2c, da903x_id_table); | ||
437 | |||
438 | static int __devexit __remove_subdev(struct device *dev, void *unused) | ||
439 | { | ||
440 | platform_device_unregister(to_platform_device(dev)); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int __devexit da903x_remove_subdevs(struct da903x_chip *chip) | ||
445 | { | ||
446 | return device_for_each_child(chip->dev, NULL, __remove_subdev); | ||
447 | } | ||
448 | |||
449 | static int __devinit da903x_add_subdevs(struct da903x_chip *chip, | ||
450 | struct da903x_platform_data *pdata) | ||
451 | { | ||
452 | struct da903x_subdev_info *subdev; | ||
453 | struct platform_device *pdev; | ||
454 | int i, ret = 0; | ||
455 | |||
456 | for (i = 0; i < pdata->num_subdevs; i++) { | ||
457 | subdev = &pdata->subdevs[i]; | ||
458 | |||
459 | pdev = platform_device_alloc(subdev->name, subdev->id); | ||
460 | |||
461 | pdev->dev.parent = chip->dev; | ||
462 | pdev->dev.platform_data = subdev->platform_data; | ||
463 | |||
464 | ret = platform_device_add(pdev); | ||
465 | if (ret) | ||
466 | goto failed; | ||
467 | } | ||
468 | return 0; | ||
469 | |||
470 | failed: | ||
471 | da903x_remove_subdevs(chip); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | static int __devinit da903x_probe(struct i2c_client *client, | ||
476 | const struct i2c_device_id *id) | ||
477 | { | ||
478 | struct da903x_platform_data *pdata = client->dev.platform_data; | ||
479 | struct da903x_chip *chip; | ||
480 | unsigned int tmp; | ||
481 | int ret; | ||
482 | |||
483 | chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); | ||
484 | if (chip == NULL) | ||
485 | return -ENOMEM; | ||
486 | |||
487 | chip->client = client; | ||
488 | chip->dev = &client->dev; | ||
489 | chip->ops = &da903x_ops[id->driver_data]; | ||
490 | |||
491 | mutex_init(&chip->lock); | ||
492 | INIT_WORK(&chip->irq_work, da903x_irq_work); | ||
493 | BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); | ||
494 | |||
495 | i2c_set_clientdata(client, chip); | ||
496 | |||
497 | ret = chip->ops->init_chip(chip); | ||
498 | if (ret) | ||
499 | goto out_free_chip; | ||
500 | |||
501 | /* mask and clear all IRQs */ | ||
502 | chip->events_mask = 0xffffffff; | ||
503 | chip->ops->mask_events(chip, chip->events_mask); | ||
504 | chip->ops->read_events(chip, &tmp); | ||
505 | |||
506 | ret = request_irq(client->irq, da903x_irq_handler, | ||
507 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
508 | "da903x", chip); | ||
509 | if (ret) { | ||
510 | dev_err(&client->dev, "failed to request irq %d\n", | ||
511 | client->irq); | ||
512 | goto out_free_chip; | ||
513 | } | ||
514 | |||
515 | ret = da903x_add_subdevs(chip, pdata); | ||
516 | if (ret) | ||
517 | goto out_free_irq; | ||
518 | |||
519 | return 0; | ||
520 | |||
521 | out_free_irq: | ||
522 | free_irq(client->irq, chip); | ||
523 | out_free_chip: | ||
524 | i2c_set_clientdata(client, NULL); | ||
525 | kfree(chip); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static int __devexit da903x_remove(struct i2c_client *client) | ||
530 | { | ||
531 | struct da903x_chip *chip = i2c_get_clientdata(client); | ||
532 | |||
533 | da903x_remove_subdevs(chip); | ||
534 | kfree(chip); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static struct i2c_driver da903x_driver = { | ||
539 | .driver = { | ||
540 | .name = "da903x", | ||
541 | .owner = THIS_MODULE, | ||
542 | }, | ||
543 | .probe = da903x_probe, | ||
544 | .remove = __devexit_p(da903x_remove), | ||
545 | .id_table = da903x_id_table, | ||
546 | }; | ||
547 | |||
548 | static int __init da903x_init(void) | ||
549 | { | ||
550 | return i2c_add_driver(&da903x_driver); | ||
551 | } | ||
552 | module_init(da903x_init); | ||
553 | |||
554 | static void __exit da903x_exit(void) | ||
555 | { | ||
556 | i2c_del_driver(&da903x_driver); | ||
557 | } | ||
558 | module_exit(da903x_exit); | ||
559 | |||
560 | MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034"); | ||
561 | MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" | ||
562 | "Mike Rapoport <mike@compulab.co.il>"); | ||
563 | MODULE_LICENSE("GPL"); | ||