diff options
| author | Pritesh Raithatha <praithatha@nvidia.com> | 2011-06-04 19:45:23 +0530 |
|---|---|---|
| committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:43:02 -0800 |
| commit | a034d7416371d44bdac75a80c155b205ca9850e5 (patch) | |
| tree | 5a5f82c010cd0ff34040eb4a4b1a34bbd69a857f /drivers/mfd/tps6591x.c | |
| parent | d0b8998e043bb114a891a0c1ab536e88e2b6cc27 (diff) | |
mfd: tps6591x: add interrupt support
Original-Change-Id: I2d30f3ce900896805b99288e69a22e734d6c3911
Reviewed-on: http://git-master/r/32717
Reviewed-by: Pritesh Raithatha <praithatha@nvidia.com>
Tested-by: Pritesh Raithatha <praithatha@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Rebase-Id: R4e34356ab5a8bb6a80421b705453bbe5c7725548
Diffstat (limited to 'drivers/mfd/tps6591x.c')
| -rw-r--r-- | drivers/mfd/tps6591x.c | 147 |
1 files changed, 102 insertions, 45 deletions
diff --git a/drivers/mfd/tps6591x.c b/drivers/mfd/tps6591x.c index d194265d315f..f63a01a2166a 100644 --- a/drivers/mfd/tps6591x.c +++ b/drivers/mfd/tps6591x.c @@ -67,42 +67,43 @@ #define TPS6591X_GPIO_PDEN 3 #define TPS6591X_GPIO_DIR 2 +enum irq_type { + EVENT, + GPIO, +}; + struct tps6591x_irq_data { - u8 mask_reg; - u8 mask_mask; + u8 mask_reg; + u8 mask_pos; + enum irq_type type; }; -#define TPS6591X_IRQ(_reg, _mask) \ - { \ - .mask_reg = (_reg) - TPS6591X_INT_MSK, \ - .mask_mask = (_mask), \ +#define TPS6591X_IRQ(_reg, _mask_pos, _type) \ + { \ + .mask_reg = (_reg), \ + .mask_pos = (_mask_pos), \ + .type = (_type), \ } static const struct tps6591x_irq_data tps6591x_irqs[] = { - [TPS6591X_INT_PWRHOLD_F] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 0), - [TPS6591X_INT_VMBHI] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 1), - [TPS6591X_INT_PWRON] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 2), - [TPS6591X_INT_PWRON_LP] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 3), - [TPS6591X_INT_PWRHOLD_R] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 4), - [TPS6591X_INT_HOTDIE] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 5), - [TPS6591X_INT_RTC_ALARM] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 6), - [TPS6591X_INT_RTC_PERIOD] = TPS6591X_IRQ(TPS6591X_INT_MSK, 1 << 7), - [TPS6591X_INT_GPIO0_R] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 0), - [TPS6591X_INT_GPIO0_F] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 1), - [TPS6591X_INT_GPIO1_R] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 2), - [TPS6591X_INT_GPIO1_F] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 3), - [TPS6591X_INT_GPIO2_R] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 4), - [TPS6591X_INT_GPIO2_F] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 5), - [TPS6591X_INT_GPIO3_R] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 6), - [TPS6591X_INT_GPIO3_F] = TPS6591X_IRQ(TPS6591X_INT_MSK2, 1 << 7), - [TPS6591X_INT_GPIO4_R] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 0), - [TPS6591X_INT_GPIO4_F] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 1), - [TPS6591X_INT_GPIO5_R] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 2), - [TPS6591X_INT_GPIO5_F] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 3), - [TPS6591X_INT_WTCHDG] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 4), - [TPS6591X_INT_VMBCH2_H] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 5), - [TPS6591X_INT_VMBCH2_L] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 6), - [TPS6591X_INT_PWRDN] = TPS6591X_IRQ(TPS6591X_INT_MSK3, 1 << 7), + [TPS6591X_INT_PWRHOLD_F] = TPS6591X_IRQ(0, 0, EVENT), + [TPS6591X_INT_VMBHI] = TPS6591X_IRQ(0, 1, EVENT), + [TPS6591X_INT_PWRON] = TPS6591X_IRQ(0, 2, EVENT), + [TPS6591X_INT_PWRON_LP] = TPS6591X_IRQ(0, 3, EVENT), + [TPS6591X_INT_PWRHOLD_R] = TPS6591X_IRQ(0, 4, EVENT), + [TPS6591X_INT_HOTDIE] = TPS6591X_IRQ(0, 5, EVENT), + [TPS6591X_INT_RTC_ALARM] = TPS6591X_IRQ(0, 6, EVENT), + [TPS6591X_INT_RTC_PERIOD] = TPS6591X_IRQ(0, 7, EVENT), + [TPS6591X_INT_GPIO0] = TPS6591X_IRQ(1, 0, GPIO), + [TPS6591X_INT_GPIO1] = TPS6591X_IRQ(1, 2, GPIO), + [TPS6591X_INT_GPIO2] = TPS6591X_IRQ(1, 4, GPIO), + [TPS6591X_INT_GPIO3] = TPS6591X_IRQ(1, 6, GPIO), + [TPS6591X_INT_GPIO4] = TPS6591X_IRQ(2, 0, GPIO), + [TPS6591X_INT_GPIO5] = TPS6591X_IRQ(2, 2, GPIO), + [TPS6591X_INT_WTCHDG] = TPS6591X_IRQ(2, 4, EVENT), + [TPS6591X_INT_VMBCH2_H] = TPS6591X_IRQ(2, 5, EVENT), + [TPS6591X_INT_VMBCH2_L] = TPS6591X_IRQ(2, 6, EVENT), + [TPS6591X_INT_PWRDN] = TPS6591X_IRQ(2, 7, EVENT), }; struct tps6591x { @@ -364,6 +365,17 @@ static int tps6591x_gpio_output(struct gpio_chip *gc, unsigned offset, offset, reg_val); } +static int tps6591x_gpio_to_irq(struct gpio_chip *gc, unsigned off) +{ + struct tps6591x *tps6591x; + tps6591x = container_of(gc, struct tps6591x, gpio); + + if ((off >= 0) && (off <= TPS6591X_INT_GPIO5 - TPS6591X_INT_GPIO0)) + return tps6591x->irq_base + TPS6591X_INT_GPIO0 + off; + + return -EIO; +} + static void tps6591x_gpio_init(struct tps6591x *tps6591x, struct tps6591x_platform_data *pdata) { @@ -405,6 +417,7 @@ static void tps6591x_gpio_init(struct tps6591x *tps6591x, tps6591x->gpio.direction_output = tps6591x_gpio_output; tps6591x->gpio.set = tps6591x_gpio_set; tps6591x->gpio.get = tps6591x_gpio_get; + tps6591x->gpio.to_irq = tps6591x_gpio_to_irq; ret = gpiochip_add(&tps6591x->gpio); if (ret) @@ -429,25 +442,31 @@ static void tps6591x_irq_lock(unsigned int irq) mutex_lock(&tps6591x->irq_lock); } -static void tps6591x_irq_enable(unsigned int irq) +static void tps6591x_irq_mask(unsigned int irq) { struct tps6591x *tps6591x = get_irq_chip_data(irq); unsigned int __irq = irq - tps6591x->irq_base; const struct tps6591x_irq_data *data = &tps6591x_irqs[__irq]; - tps6591x->mask_reg[data->mask_reg] &= ~data->mask_mask; - tps6591x->irq_en |= (1 << __irq); + if (data->type == EVENT) + tps6591x->mask_reg[data->mask_reg] |= (1 << data->mask_pos); + else + tps6591x->mask_reg[data->mask_reg] |= (3 << data->mask_pos); + + tps6591x->irq_en &= ~(1 << __irq); } -static void tps6591x_irq_disable(unsigned int irq) +static void tps6591x_irq_unmask(unsigned int irq) { struct tps6591x *tps6591x = get_irq_chip_data(irq); unsigned int __irq = irq - tps6591x->irq_base; const struct tps6591x_irq_data *data = &tps6591x_irqs[__irq]; - tps6591x->mask_reg[data->mask_reg] |= data->mask_mask; - tps6591x->irq_en &= ~(1 << __irq); + if (data->type == EVENT) { + tps6591x->mask_reg[data->mask_reg] &= ~(1 << data->mask_pos); + tps6591x->irq_en |= (1 << __irq); + } } static void tps6591x_irq_sync_unlock(unsigned int irq) @@ -467,36 +486,73 @@ static void tps6591x_irq_sync_unlock(unsigned int irq) mutex_unlock(&tps6591x->irq_lock); } +static int tps6591x_irq_set_type(unsigned int irq, unsigned int type) +{ + struct tps6591x *tps6591x = get_irq_chip_data(irq); + + unsigned int __irq = irq - tps6591x->irq_base; + const struct tps6591x_irq_data *data = &tps6591x_irqs[__irq]; + + if (data->type == GPIO) { + if (type & IRQ_TYPE_EDGE_FALLING) + tps6591x->mask_reg[data->mask_reg] + &= ~(1 << data->mask_pos); + else + tps6591x->mask_reg[data->mask_reg] + |= (1 << data->mask_pos); + + if (type & IRQ_TYPE_EDGE_RISING) + tps6591x->mask_reg[data->mask_reg] + &= ~(2 << data->mask_pos); + else + tps6591x->mask_reg[data->mask_reg] + |= (2 << data->mask_pos); + + tps6591x->irq_en |= (1 << __irq); + } + + return 0; +} + static irqreturn_t tps6591x_irq(int irq, void *data) { struct tps6591x *tps6591x = data; int ret = 0; u8 tmp[3]; - u32 acks; + u32 acks, mask = 0; int i; for (i = 0; i < 3; i++) { ret = tps6591x_read(tps6591x->dev, TPS6591X_INT_STS + 2*i, &tmp[i]); if (ret < 0) { - dev_err(tps6591x->dev, "failed to read interrupt status\n"); + dev_err(tps6591x->dev, + "failed to read interrupt status\n"); return IRQ_NONE; } if (tmp[i]) { ret = tps6591x_write(tps6591x->dev, TPS6591X_INT_STS + 2*i, tmp[i]); if (ret < 0) { - dev_err(tps6591x->dev, "failed to write interrupt status\n"); + dev_err(tps6591x->dev, + "failed to write interrupt status\n"); return IRQ_NONE; } } } + acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]; - while (acks) { - i = __ffs(acks); - if (tps6591x->irq_en & (1 << i)) + + for (i = 0; i < ARRAY_SIZE(tps6591x_irqs); i++) { + if (tps6591x_irqs[i].type == GPIO) + mask = (3 << (tps6591x_irqs[i].mask_pos + + tps6591x_irqs[i].mask_reg*8)); + else if (tps6591x_irqs[i].type == EVENT) + mask = (1 << (tps6591x_irqs[i].mask_pos + + tps6591x_irqs[i].mask_reg*8)); + + if ((acks & mask) && (tps6591x->irq_en & (1 << i))) handle_nested_irq(tps6591x->irq_base + i); - acks &= ~(1 << i); } return IRQ_HANDLED; } @@ -528,10 +584,11 @@ static int __devinit tps6591x_irq_init(struct tps6591x *tps6591x, int irq, tps6591x->irq_base = irq_base; tps6591x->irq_chip.name = "tps6591x"; - tps6591x->irq_chip.enable = tps6591x_irq_enable; - tps6591x->irq_chip.disable = tps6591x_irq_disable; + tps6591x->irq_chip.mask = tps6591x_irq_mask; + tps6591x->irq_chip.unmask = tps6591x_irq_unmask; tps6591x->irq_chip.bus_lock = tps6591x_irq_lock; tps6591x->irq_chip.bus_sync_unlock = tps6591x_irq_sync_unlock; + tps6591x->irq_chip.set_type = tps6591x_irq_set_type; for (i = 0; i < ARRAY_SIZE(tps6591x_irqs); i++) { int __irq = i + tps6591x->irq_base; |
