summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2013-11-21 15:34:07 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-11-26 19:35:27 +0000
commit009dd17588c8b1f0160e1e7c2acf3a4a4bb9dd80 (patch)
tree4511831edd2bd11d22b9f503b2e140995ec7bded
parent0892ff6418e615b6f52a4010cf94a6f28b675511 (diff)
downloadchrome-ec-009dd17588c8b1f0160e1e7c2acf3a4a4bb9dd80.tar.gz
mec1322: Add GPIO interrupt support
With this, we can now define and trigger interrupt on GPIO status. BUG=chrome-os-partner:24107 TEST=Test GPIO036 with following cases: - Pulled up and rising edge trigger. Pull down externally and then release. - Pulled up and falling edge trigger. Pull down externally. - Pulled up and both edge trigger. Pull down and then release. - Pulled up and low level trigger. Pull down externally. BRANCH=None Change-Id: Id9bfd2ba9dd8a75bcf2c5691ffe2aa6518076925 Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/177560 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/mec1322/gpio.c119
1 files changed, 116 insertions, 3 deletions
diff --git a/chip/mec1322/gpio.c b/chip/mec1322/gpio.c
index 065b4383ec..6569985c67 100644
--- a/chip/mec1322/gpio.c
+++ b/chip/mec1322/gpio.c
@@ -7,10 +7,27 @@
#include "common.h"
#include "gpio.h"
+#include "hooks.h"
#include "registers.h"
+#include "task.h"
#include "timer.h"
#include "util.h"
+struct gpio_int_mapping {
+ int8_t girq_id;
+ int8_t port_offset;
+};
+
+/* Mapping from GPIO port to GIRQ info */
+static const struct gpio_int_mapping int_map[22] = {
+ {11, 0}, {11, 0}, {11, 0}, {11, 0},
+ {10, 4}, {10, 4}, {10, 4}, {-1, -1},
+ {-1, -1}, {-1, -1}, {9, 10}, {9, 10},
+ {9, 10}, {9, 10}, {8, 14}, {8, 14},
+ {8, 14}, {-1, -1}, {-1, -1}, {-1, -1},
+ {20, 20}, {20, 20}
+};
+
void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
{
int i;
@@ -82,7 +99,24 @@ void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
else
val &= ~0x3;
- /* TODO(crosbug.com/p/24107): Set up interrupt */
+ /* Set up interrupt */
+ if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING))
+ val |= (1 << 7);
+ else
+ val &= ~(1 << 7);
+
+ val &= ~(0x7 << 4);
+
+ if ((flags & GPIO_INT_F_RISING) && (flags & GPIO_INT_F_FALLING))
+ val |= 0x7 << 4;
+ else if (flags & GPIO_INT_F_RISING)
+ val |= 0x5 << 4;
+ else if (flags & GPIO_INT_F_FALLING)
+ val |= 0x6 << 4;
+ else if (flags & GPIO_INT_F_HIGH)
+ val |= 0x1 << 4;
+ else if (!(flags & GPIO_INT_F_LOW)) /* No interrupt flag set */
+ val |= 0x4 << 4;
/* Use as GPIO */
val &= ~((1 << 12) | (1 << 13));
@@ -98,12 +132,27 @@ void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
int gpio_enable_interrupt(enum gpio_signal signal)
{
- return EC_ERROR_UNIMPLEMENTED;
+ int i = 31 - __builtin_clz(gpio_list[signal].mask);
+ int port = gpio_list[signal].port;
+ int girq_id = int_map[port].girq_id;
+ int bit_id = (port - int_map[port].port_offset) * 8 + i;
+
+ MEC1322_INT_ENABLE(girq_id) |= (1 << bit_id);
+ MEC1322_INT_BLK_EN |= (1 << girq_id);
+
+ return EC_SUCCESS;
}
int gpio_disable_interrupt(enum gpio_signal signal)
{
- return EC_ERROR_UNIMPLEMENTED;
+ int i = 31 - __builtin_clz(gpio_list[signal].mask);
+ int port = gpio_list[signal].port;
+ int girq_id = int_map[port].girq_id;
+ int bit_id = (port - int_map[port].port_offset) * 8 + i;
+
+ MEC1322_INT_DISABLE(girq_id) |= (1 << bit_id);
+
+ return EC_SUCCESS;
}
void gpio_pre_init(void)
@@ -114,3 +163,67 @@ void gpio_pre_init(void)
for (i = 0; i < GPIO_COUNT; i++, g++)
gpio_set_flags_by_mask(g->port, g->mask, g->flags);
}
+
+static void gpio_init(void)
+{
+ task_enable_irq(MEC1322_IRQ_GIRQ8);
+ task_enable_irq(MEC1322_IRQ_GIRQ9);
+ task_enable_irq(MEC1322_IRQ_GIRQ10);
+ task_enable_irq(MEC1322_IRQ_GIRQ11);
+ task_enable_irq(MEC1322_IRQ_GIRQ20);
+}
+DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);
+
+/*****************************************************************************/
+/* Interrupt handlers */
+
+
+/**
+ * Handler for each GIRQ interrupt. This reads and clears the interrupt bits for
+ * the GIRQ interrupt, then finds and calls the corresponding GPIO interrupt
+ * handlers.
+ *
+ * @param girq GIRQ index
+ * @param port_offset GPIO port offset for the given GIRQ
+ */
+static void gpio_interrupt(int girq, int port_offset)
+{
+ int i, bit;
+ const struct gpio_info *g = gpio_list;
+ uint32_t sts = MEC1322_INT_RESULT(girq);
+
+ MEC1322_INT_SOURCE(girq) |= sts;
+
+ for (i = 0; i < GPIO_COUNT && sts; ++i, ++g) {
+ if (!g->irq_handler)
+ continue;
+ bit = (g->port - port_offset) * 8 + __builtin_ffs(g->mask) - 1;
+ if (sts & (1 << bit))
+ g->irq_handler(i);
+ sts &= ~(1 << bit);
+ }
+}
+
+#define GPIO_IRQ_FUNC(irqfunc, girq, port_offset) \
+ static void irqfunc(void) \
+ { \
+ gpio_interrupt(girq, port_offset); \
+ }
+
+GPIO_IRQ_FUNC(__girq_8_interrupt, 8, 14);
+GPIO_IRQ_FUNC(__girq_9_interrupt, 9, 10);
+GPIO_IRQ_FUNC(__girq_10_interrupt, 10, 4);
+GPIO_IRQ_FUNC(__girq_11_interrupt, 11, 0);
+GPIO_IRQ_FUNC(__girq_20_interrupt, 20, 20);
+
+#undef GPIO_IRQ_FUNC
+
+/*
+ * Declare IRQs. Nesting this macro inside the GPIO_IRQ_FUNC macro works
+ * poorly because DECLARE_IRQ() stringizes its inputs.
+ */
+DECLARE_IRQ(MEC1322_IRQ_GIRQ8, __girq_8_interrupt, 1);
+DECLARE_IRQ(MEC1322_IRQ_GIRQ9, __girq_9_interrupt, 1);
+DECLARE_IRQ(MEC1322_IRQ_GIRQ10, __girq_10_interrupt, 1);
+DECLARE_IRQ(MEC1322_IRQ_GIRQ11, __girq_11_interrupt, 1);
+DECLARE_IRQ(MEC1322_IRQ_GIRQ20, __girq_20_interrupt, 1);