summaryrefslogtreecommitdiff
path: root/drivers/mfd/tps65912-irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/tps65912-irq.c')
-rw-r--r--drivers/mfd/tps65912-irq.c79
1 files changed, 61 insertions, 18 deletions
diff --git a/drivers/mfd/tps65912-irq.c b/drivers/mfd/tps65912-irq.c
index d360a83a273..766ed7dd8f5 100644
--- a/drivers/mfd/tps65912-irq.c
+++ b/drivers/mfd/tps65912-irq.c
@@ -22,6 +22,7 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/mfd/tps65912.h>
+#include <linux/input.h>
static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
int irq)
@@ -29,6 +30,34 @@ static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
return irq - tps65912->irq_base;
}
+/* this powerkey_handler runs in process contextt, not in interrupt context*/
+static irqreturn_t powerkey_handler(int irq, void *irq_data)
+{
+ struct tps65912 *tps65912 = irq_data;
+ u32 new_state;
+
+ if (irq - tps65912->irq_base == tps65912->powerkey_up_irq) {
+ new_state = PWRKEY_RELEASE;
+ } else if (irq - tps65912->irq_base == tps65912->powerkey_down_irq) {
+ new_state = PWRKEY_PRESS;
+ } else {
+ pr_info("incorrect interrupt %d for power key\n",
+ irq - tps65912->irq_base);
+ return IRQ_HANDLED;
+ }
+
+ mutex_lock(&tps65912->irq_lock);
+ if (new_state != tps65912->powerkey_state) {
+ tps65912_broadcast_key_event(tps65912,
+ tps65912->powerkey_code,
+ new_state);
+ tps65912->powerkey_state = new_state;
+ }
+ mutex_unlock(&tps65912->irq_lock);
+ pr_debug("tps65912 handle irq %d state = %s\n", irq,
+ new_state == PWRKEY_RELEASE ? "RELEASE" : "PRESS" );
+ return IRQ_HANDLED;
+}
/*
* This is a threaded IRQ handler so can access I2C/SPI. Since the
* IRQ handler explicitly clears the IRQ it handles the IRQ line
@@ -42,10 +71,11 @@ static irqreturn_t tps65912_irq(int irq, void *irq_data)
{
struct tps65912 *tps65912 = irq_data;
u32 irq_sts;
- u32 irq_mask;
u8 reg;
int i;
+ pr_debug("tps65912 handle irq %d\n", irq);
+ mutex_lock(&tps65912->pm_lock);
tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
irq_sts = reg;
@@ -56,20 +86,14 @@ static irqreturn_t tps65912_irq(int irq, void *irq_data)
tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
irq_sts |= reg << 24;
- tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
- irq_mask = reg;
- tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
- irq_mask |= reg << 8;
- tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
- irq_mask |= reg << 16;
- tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
- irq_mask |= reg << 24;
-
- irq_sts &= ~irq_mask;
- if (!irq_sts)
+ irq_sts &= ~tps65912->irq_mask;
+ if (!irq_sts) {
+ mutex_unlock(&tps65912->pm_lock);
+ pr_debug("tps65912 %d IRQ_NONE\n", irq);
return IRQ_NONE;
+ }
- for (i = 0; i < tps65912->irq_num; i++) {
+ for (i = tps65912->irq_num - 1; i >= 0; i--) {
if (!(irq_sts & (1 << i)))
continue;
@@ -93,6 +117,9 @@ static irqreturn_t tps65912_irq(int irq, void *irq_data)
if (reg)
tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
+ mutex_unlock(&tps65912->pm_lock);
+
+ pr_debug("tps65912 %d IRQ_HANDLED\n", irq);
return IRQ_HANDLED;
}
@@ -158,7 +185,6 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
struct tps65912_platform_data *pdata)
{
int ret, cur_irq;
- int flags = IRQF_ONESHOT;
u8 reg;
if (!irq) {
@@ -171,6 +197,8 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
return 0;
}
+ tps65912->powerkey_state = PWRKEY_RELEASE;
+
/* Clear unattended interrupts */
tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
@@ -207,13 +235,28 @@ int tps65912_irq_init(struct tps65912 *tps65912, int irq,
#endif
}
- ret = request_threaded_irq(irq, NULL, tps65912_irq, flags,
- "tps65912", tps65912);
-
- irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+ ret = request_threaded_irq(irq, NULL, tps65912_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "tps65912", tps65912);
if (ret != 0)
dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret);
+ ret = request_threaded_irq(tps65912->irq_base +
+ tps65912->powerkey_up_irq, NULL, powerkey_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "tps65912_key_rel",
+ tps65912);
+ if (ret != 0)
+ dev_err(tps65912->dev,
+ "Failed to request sub-IRQ for power key rel: %d\n", ret);
+
+ ret = request_threaded_irq(tps65912->irq_base +
+ tps65912->powerkey_down_irq, NULL, powerkey_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "tps65912_key_press",
+ tps65912);
+ if (ret != 0)
+ dev_err(tps65912->dev,
+ "Failed to request sub-IRQ for power key press: %d\n", ret);
+
return ret;
}