aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-09-19 18:18:27 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2010-10-28 18:29:28 -0400
commitc26448c48448266480e1b6c371f897167060ceaf (patch)
treedaaaa3b64dfe31d1c429b63dba6b4a27e325d18f /drivers/mfd
parent39368eda96c0a54ea0b3c6066b08e46b37f7905f (diff)
mfd: Add basic tps6586x interrupt support
Add support for enabling and disabling tps6586x subdevice interrupts Signed-off-by: Gary King <gking@nvidia.com> Acked-by: Mike Rapoport <mike@compulab.co.il> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig4
-rw-r--r--drivers/mfd/tps6586x.c200
2 files changed, 202 insertions, 2 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 01c928bca099..66779bdc9627 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -563,8 +563,8 @@ config MFD_JZ4740_ADC
563 This driver is necessary for jz4740-battery and jz4740-hwmon driver. 563 This driver is necessary for jz4740-battery and jz4740-hwmon driver.
564 564
565config MFD_TPS6586X 565config MFD_TPS6586X
566 tristate "TPS6586x Power Management chips" 566 bool "TPS6586x Power Management chips"
567 depends on I2C && GPIOLIB 567 depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
568 select MFD_CORE 568 select MFD_CORE
569 help 569 help
570 If you say yes here you get support for the TPS6586X series of 570 If you say yes here you get support for the TPS6586X series of
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 2f9336c3710c..117eb7cafe77 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -15,6 +15,8 @@
15 * published by the Free Software Foundation. 15 * published by the Free Software Foundation.
16 */ 16 */
17 17
18#include <linux/interrupt.h>
19#include <linux/irq.h>
18#include <linux/kernel.h> 20#include <linux/kernel.h>
19#include <linux/module.h> 21#include <linux/module.h>
20#include <linux/mutex.h> 22#include <linux/mutex.h>
@@ -29,16 +31,76 @@
29#define TPS6586X_GPIOSET1 0x5d 31#define TPS6586X_GPIOSET1 0x5d
30#define TPS6586X_GPIOSET2 0x5e 32#define TPS6586X_GPIOSET2 0x5e
31 33
34/* interrupt control registers */
35#define TPS6586X_INT_ACK1 0xb5
36#define TPS6586X_INT_ACK2 0xb6
37#define TPS6586X_INT_ACK3 0xb7
38#define TPS6586X_INT_ACK4 0xb8
39
40/* interrupt mask registers */
41#define TPS6586X_INT_MASK1 0xb0
42#define TPS6586X_INT_MASK2 0xb1
43#define TPS6586X_INT_MASK3 0xb2
44#define TPS6586X_INT_MASK4 0xb3
45#define TPS6586X_INT_MASK5 0xb4
46
32/* device id */ 47/* device id */
33#define TPS6586X_VERSIONCRC 0xcd 48#define TPS6586X_VERSIONCRC 0xcd
34#define TPS658621A_VERSIONCRC 0x15 49#define TPS658621A_VERSIONCRC 0x15
35 50
51struct tps6586x_irq_data {
52 u8 mask_reg;
53 u8 mask_mask;
54};
55
56#define TPS6586X_IRQ(_reg, _mask) \
57 { \
58 .mask_reg = (_reg) - TPS6586X_INT_MASK1, \
59 .mask_mask = (_mask), \
60 }
61
62static const struct tps6586x_irq_data tps6586x_irqs[] = {
63 [TPS6586X_INT_PLDO_0] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0),
64 [TPS6586X_INT_PLDO_1] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1),
65 [TPS6586X_INT_PLDO_2] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2),
66 [TPS6586X_INT_PLDO_3] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3),
67 [TPS6586X_INT_PLDO_4] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4),
68 [TPS6586X_INT_PLDO_5] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5),
69 [TPS6586X_INT_PLDO_6] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6),
70 [TPS6586X_INT_PLDO_7] = TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7),
71 [TPS6586X_INT_COMP_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0),
72 [TPS6586X_INT_ADC] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1),
73 [TPS6586X_INT_PLDO_8] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2),
74 [TPS6586X_INT_PLDO_9] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3),
75 [TPS6586X_INT_PSM_0] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4),
76 [TPS6586X_INT_PSM_1] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5),
77 [TPS6586X_INT_PSM_2] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6),
78 [TPS6586X_INT_PSM_3] = TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7),
79 [TPS6586X_INT_RTC_ALM1] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4),
80 [TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03),
81 [TPS6586X_INT_USB_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2),
82 [TPS6586X_INT_AC_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3),
83 [TPS6586X_INT_BAT_DET] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0),
84 [TPS6586X_INT_CHG_STAT] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc),
85 [TPS6586X_INT_CHG_TEMP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06),
86 [TPS6586X_INT_PP] = TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0),
87 [TPS6586X_INT_RESUME] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5),
88 [TPS6586X_INT_LOW_SYS] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6),
89 [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1),
90};
91
36struct tps6586x { 92struct tps6586x {
37 struct mutex lock; 93 struct mutex lock;
38 struct device *dev; 94 struct device *dev;
39 struct i2c_client *client; 95 struct i2c_client *client;
40 96
41 struct gpio_chip gpio; 97 struct gpio_chip gpio;
98 struct irq_chip irq_chip;
99 struct mutex irq_lock;
100 int irq_base;
101 u32 irq_en;
102 u8 mask_cache[5];
103 u8 mask_reg[5];
42}; 104};
43 105
44static inline int __tps6586x_read(struct i2c_client *client, 106static inline int __tps6586x_read(struct i2c_client *client,
@@ -262,6 +324,129 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
262 return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); 324 return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
263} 325}
264 326
327static void tps6586x_irq_lock(unsigned int irq)
328{
329 struct tps6586x *tps6586x = get_irq_chip_data(irq);
330
331 mutex_lock(&tps6586x->irq_lock);
332}
333
334static void tps6586x_irq_enable(unsigned int irq)
335{
336 struct tps6586x *tps6586x = get_irq_chip_data(irq);
337 unsigned int __irq = irq - tps6586x->irq_base;
338 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
339
340 tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
341 tps6586x->irq_en |= (1 << __irq);
342}
343
344static void tps6586x_irq_disable(unsigned int irq)
345{
346 struct tps6586x *tps6586x = get_irq_chip_data(irq);
347
348 unsigned int __irq = irq - tps6586x->irq_base;
349 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
350
351 tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
352 tps6586x->irq_en &= ~(1 << __irq);
353}
354
355static void tps6586x_irq_sync_unlock(unsigned int irq)
356{
357 struct tps6586x *tps6586x = get_irq_chip_data(irq);
358 int i;
359
360 for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
361 if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) {
362 if (!WARN_ON(tps6586x_write(tps6586x->dev,
363 TPS6586X_INT_MASK1 + i,
364 tps6586x->mask_reg[i])))
365 tps6586x->mask_cache[i] = tps6586x->mask_reg[i];
366 }
367 }
368
369 mutex_unlock(&tps6586x->irq_lock);
370}
371
372static irqreturn_t tps6586x_irq(int irq, void *data)
373{
374 struct tps6586x *tps6586x = data;
375 u32 acks;
376 int ret = 0;
377
378 ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1,
379 sizeof(acks), (uint8_t *)&acks);
380
381 if (ret < 0) {
382 dev_err(tps6586x->dev, "failed to read interrupt status\n");
383 return IRQ_NONE;
384 }
385
386 acks = le32_to_cpu(acks);
387
388 while (acks) {
389 int i = __ffs(acks);
390
391 if (tps6586x->irq_en & (1 << i))
392 handle_nested_irq(tps6586x->irq_base + i);
393
394 acks &= ~(1 << i);
395 }
396
397 return IRQ_HANDLED;
398}
399
400static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
401 int irq_base)
402{
403 int i, ret;
404 u8 tmp[4];
405
406 if (!irq_base) {
407 dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n");
408 return -EINVAL;
409 }
410
411 mutex_init(&tps6586x->irq_lock);
412 for (i = 0; i < 5; i++) {
413 tps6586x->mask_cache[i] = 0xff;
414 tps6586x->mask_reg[i] = 0xff;
415 tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff);
416 }
417
418 tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp);
419
420 tps6586x->irq_base = irq_base;
421
422 tps6586x->irq_chip.name = "tps6586x";
423 tps6586x->irq_chip.enable = tps6586x_irq_enable;
424 tps6586x->irq_chip.disable = tps6586x_irq_disable;
425 tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
426 tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
427
428 for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
429 int __irq = i + tps6586x->irq_base;
430 set_irq_chip_data(__irq, tps6586x);
431 set_irq_chip_and_handler(__irq, &tps6586x->irq_chip,
432 handle_simple_irq);
433 set_irq_nested_thread(__irq, 1);
434#ifdef CONFIG_ARM
435 set_irq_flags(__irq, IRQF_VALID);
436#endif
437 }
438
439 ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT,
440 "tps6586x", tps6586x);
441
442 if (!ret) {
443 device_init_wakeup(tps6586x->dev, 1);
444 enable_irq_wake(irq);
445 }
446
447 return ret;
448}
449
265static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, 450static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
266 struct tps6586x_platform_data *pdata) 451 struct tps6586x_platform_data *pdata)
267{ 452{
@@ -327,6 +512,15 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
327 512
328 mutex_init(&tps6586x->lock); 513 mutex_init(&tps6586x->lock);
329 514
515 if (client->irq) {
516 ret = tps6586x_irq_init(tps6586x, client->irq,
517 pdata->irq_base);
518 if (ret) {
519 dev_err(&client->dev, "IRQ init failed: %d\n", ret);
520 goto err_irq_init;
521 }
522 }
523
330 ret = tps6586x_add_subdevs(tps6586x, pdata); 524 ret = tps6586x_add_subdevs(tps6586x, pdata);
331 if (ret) { 525 if (ret) {
332 dev_err(&client->dev, "add devices failed: %d\n", ret); 526 dev_err(&client->dev, "add devices failed: %d\n", ret);
@@ -338,6 +532,9 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
338 return 0; 532 return 0;
339 533
340err_add_devs: 534err_add_devs:
535 if (client->irq)
536 free_irq(client->irq, tps6586x);
537err_irq_init:
341 kfree(tps6586x); 538 kfree(tps6586x);
342 return ret; 539 return ret;
343} 540}
@@ -348,6 +545,9 @@ static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
348 struct tps6586x_platform_data *pdata = client->dev.platform_data; 545 struct tps6586x_platform_data *pdata = client->dev.platform_data;
349 int ret; 546 int ret;
350 547
548 if (client->irq)
549 free_irq(client->irq, tps6586x);
550
351 if (pdata->gpio_base) { 551 if (pdata->gpio_base) {
352 ret = gpiochip_remove(&tps6586x->gpio); 552 ret = gpiochip_remove(&tps6586x->gpio);
353 if (ret) 553 if (ret)