Commit c26448c48448266480e1b6c371f897167060ceaf

Authored by Gary King
Committed by Samuel Ortiz
1 parent 39368eda96

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>

Showing 3 changed files with 233 additions and 2 deletions Side-by-side Diff

... ... @@ -563,8 +563,8 @@
563 563 This driver is necessary for jz4740-battery and jz4740-hwmon driver.
564 564  
565 565 config MFD_TPS6586X
566   - tristate "TPS6586x Power Management chips"
567   - depends on I2C && GPIOLIB
  566 + bool "TPS6586x Power Management chips"
  567 + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
568 568 select MFD_CORE
569 569 help
570 570 If you say yes here you get support for the TPS6586X series of
drivers/mfd/tps6586x.c
... ... @@ -15,6 +15,8 @@
15 15 * published by the Free Software Foundation.
16 16 */
17 17  
  18 +#include <linux/interrupt.h>
  19 +#include <linux/irq.h>
18 20 #include <linux/kernel.h>
19 21 #include <linux/module.h>
20 22 #include <linux/mutex.h>
21 23  
22 24  
... ... @@ -29,16 +31,76 @@
29 31 #define TPS6586X_GPIOSET1 0x5d
30 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 47 /* device id */
33 48 #define TPS6586X_VERSIONCRC 0xcd
34 49 #define TPS658621A_VERSIONCRC 0x15
35 50  
  51 +struct 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 +
  62 +static 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 +
36 92 struct tps6586x {
37 93 struct mutex lock;
38 94 struct device *dev;
39 95 struct i2c_client *client;
40 96  
41 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  
44 106 static inline int __tps6586x_read(struct i2c_client *client,
... ... @@ -262,6 +324,129 @@
262 324 return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
263 325 }
264 326  
  327 +static 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 +
  334 +static 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 +
  344 +static 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 +
  355 +static 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 +
  372 +static 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 +
  400 +static 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 +
265 450 static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
266 451 struct tps6586x_platform_data *pdata)
267 452 {
... ... @@ -327,6 +512,15 @@
327 512  
328 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 524 ret = tps6586x_add_subdevs(tps6586x, pdata);
331 525 if (ret) {
332 526 dev_err(&client->dev, "add devices failed: %d\n", ret);
... ... @@ -338,6 +532,9 @@
338 532 return 0;
339 533  
340 534 err_add_devs:
  535 + if (client->irq)
  536 + free_irq(client->irq, tps6586x);
  537 +err_irq_init:
341 538 kfree(tps6586x);
342 539 return ret;
343 540 }
... ... @@ -347,6 +544,9 @@
347 544 struct tps6586x *tps6586x = i2c_get_clientdata(client);
348 545 struct tps6586x_platform_data *pdata = client->dev.platform_data;
349 546 int ret;
  547 +
  548 + if (client->irq)
  549 + free_irq(client->irq, tps6586x);
350 550  
351 551 if (pdata->gpio_base) {
352 552 ret = gpiochip_remove(&tps6586x->gpio);
include/linux/mfd/tps6586x.h
... ... @@ -18,6 +18,36 @@
18 18 TPS6586X_ID_LDO_RTC,
19 19 };
20 20  
  21 +enum {
  22 + TPS6586X_INT_PLDO_0,
  23 + TPS6586X_INT_PLDO_1,
  24 + TPS6586X_INT_PLDO_2,
  25 + TPS6586X_INT_PLDO_3,
  26 + TPS6586X_INT_PLDO_4,
  27 + TPS6586X_INT_PLDO_5,
  28 + TPS6586X_INT_PLDO_6,
  29 + TPS6586X_INT_PLDO_7,
  30 + TPS6586X_INT_COMP_DET,
  31 + TPS6586X_INT_ADC,
  32 + TPS6586X_INT_PLDO_8,
  33 + TPS6586X_INT_PLDO_9,
  34 + TPS6586X_INT_PSM_0,
  35 + TPS6586X_INT_PSM_1,
  36 + TPS6586X_INT_PSM_2,
  37 + TPS6586X_INT_PSM_3,
  38 + TPS6586X_INT_RTC_ALM1,
  39 + TPS6586X_INT_ACUSB_OVP,
  40 + TPS6586X_INT_USB_DET,
  41 + TPS6586X_INT_AC_DET,
  42 + TPS6586X_INT_BAT_DET,
  43 + TPS6586X_INT_CHG_STAT,
  44 + TPS6586X_INT_CHG_TEMP,
  45 + TPS6586X_INT_PP,
  46 + TPS6586X_INT_RESUME,
  47 + TPS6586X_INT_LOW_SYS,
  48 + TPS6586X_INT_RTC_ALM2,
  49 +};
  50 +
21 51 struct tps6586x_subdev_info {
22 52 int id;
23 53 const char *name;
... ... @@ -29,6 +59,7 @@
29 59 struct tps6586x_subdev_info *subdevs;
30 60  
31 61 int gpio_base;
  62 + int irq_base;
32 63 };
33 64  
34 65 /*