mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 08:31:52 +00:00
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>
This commit is contained in:
committed by
chrome-internal-fetch
parent
0892ff6418
commit
009dd17588
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user