Files
OpenCellular/chip/it83xx/gpio.c
Dino Li 8a11eae6df it83xx: Add GPIO group K and L
The 144-pins package IC(IT8320) supports these two GPIO groups.

Signed-off-by: Dino Li <dino.li@ite.com.tw>

BRANCH=none
BUG=none
TEST=1. Declare GPIO groups K/L in gpio.inc and using console commands
        'gpioget'/'gpioset' to read/set GPIOs.
     2. Choose four GPIO pins(GPIOK.0/1 and GPIOL.0/1)
        and test interrupt functionally.

Change-Id: Ia618c314eeca1d061ffe172da762865f5df9b5c6
Reviewed-on: https://chromium-review.googlesource.com/345776
Commit-Ready: Dino Li <Dino.Li@ite.com.tw>
Tested-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@google.com>
2016-05-24 10:19:00 -07:00

523 lines
17 KiB
C

/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* GPIO module for Chrome EC */
#include "clock.h"
#include "common.h"
#include "gpio.h"
#include "hooks.h"
#include "intc.h"
#include "kmsc_chip.h"
#include "registers.h"
#include "switch.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
/*
* Converts port (ie GPIO A) to base address offset of the control register
* (GPCRx0) for that port.
*/
#define CTRL_BASE(port) ((port)*8 + ((port) < GPIO_K ? 8 : 56))
/**
* Convert wake-up controller (WUC) group to the corresponding wake-up edge
* sense register (WUESR). Return pointer to the register.
*
* @param grp WUC group.
*
* @return Pointer to corresponding WUESR register.
*/
static volatile uint8_t *wuesr(uint8_t grp)
{
/*
* From WUESR1-WUESR4, the address increases by ones. From WUESR5 on
* the address increases by fours.
*/
return (grp <= 4) ?
(volatile uint8_t *)(IT83XX_WUC_WUESR1 + grp-1) :
(volatile uint8_t *)(IT83XX_WUC_WUESR5 + 4*(grp-5));
}
/**
* Convert wake-up controller (WUC) group to the corresponding wake-up edge
* mode register (WUEMR). Return pointer to the register.
*
* @param grp WUC group.
*
* @return Pointer to corresponding WUEMR register.
*/
static volatile uint8_t *wuemr(uint8_t grp)
{
/*
* From WUEMR1-WUEMR4, the address increases by ones. From WUEMR5 on
* the address increases by fours.
*/
return (grp <= 4) ?
(volatile uint8_t *)(IT83XX_WUC_WUEMR1 + grp-1) :
(volatile uint8_t *)(IT83XX_WUC_WUEMR5 + 4*(grp-5));
}
/*
* Array to store the corresponding GPIO port and mask, and WUC group and mask
* for each WKO interrupt. This allows GPIO interrupts coming in through WKO
* to easily identify which pin caused the interrupt.
* Note: Using designated initializers here in addition to using the array size
* assert because many rows are purposely skipped. Not all IRQs are WKO IRQs,
* so the IRQ index skips around. But, we still want the entire array to take
* up the size of the total number of IRQs because the index to the array could
* be any IRQ number.
*/
static const struct {
uint8_t gpio_port;
uint8_t gpio_mask;
uint8_t wuc_group;
uint8_t wuc_mask;
} gpio_irqs[] = {
/* irq gpio_port,gpio_mask,wuc_group,wuc_mask */
[IT83XX_IRQ_WKO20] = {GPIO_D, (1<<0), 2, (1<<0)},
[IT83XX_IRQ_WKO21] = {GPIO_D, (1<<1), 2, (1<<1)},
[IT83XX_IRQ_WKO22] = {GPIO_C, (1<<4), 2, (1<<2)},
[IT83XX_IRQ_WKO23] = {GPIO_C, (1<<6), 2, (1<<3)},
[IT83XX_IRQ_WKO24] = {GPIO_D, (1<<2), 2, (1<<4)},
[IT83XX_IRQ_WKO50] = {GPIO_K, (1<<0), 5, (1<<0)},
[IT83XX_IRQ_WKO51] = {GPIO_K, (1<<1), 5, (1<<1)},
[IT83XX_IRQ_WKO52] = {GPIO_K, (1<<2), 5, (1<<2)},
[IT83XX_IRQ_WKO53] = {GPIO_K, (1<<3), 5, (1<<3)},
[IT83XX_IRQ_WKO54] = {GPIO_K, (1<<4), 5, (1<<4)},
[IT83XX_IRQ_WKO55] = {GPIO_K, (1<<5), 5, (1<<5)},
[IT83XX_IRQ_WKO56] = {GPIO_K, (1<<6), 5, (1<<6)},
[IT83XX_IRQ_WKO57] = {GPIO_K, (1<<7), 5, (1<<7)},
[IT83XX_IRQ_WKO60] = {GPIO_H, (1<<0), 6, (1<<0)},
[IT83XX_IRQ_WKO61] = {GPIO_H, (1<<1), 6, (1<<1)},
[IT83XX_IRQ_WKO62] = {GPIO_H, (1<<2), 6, (1<<2)},
[IT83XX_IRQ_WKO63] = {GPIO_H, (1<<3), 6, (1<<3)},
[IT83XX_IRQ_WKO64] = {GPIO_F, (1<<4), 6, (1<<4)},
[IT83XX_IRQ_WKO65] = {GPIO_F, (1<<5), 6, (1<<5)},
[IT83XX_IRQ_WKO65] = {GPIO_F, (1<<6), 6, (1<<6)},
[IT83XX_IRQ_WKO67] = {GPIO_F, (1<<7), 6, (1<<7)},
[IT83XX_IRQ_WKO70] = {GPIO_E, (1<<0), 7, (1<<0)},
[IT83XX_IRQ_WKO71] = {GPIO_E, (1<<1), 7, (1<<1)},
[IT83XX_IRQ_WKO72] = {GPIO_E, (1<<2), 7, (1<<2)},
[IT83XX_IRQ_WKO73] = {GPIO_E, (1<<3), 7, (1<<3)},
[IT83XX_IRQ_WKO74] = {GPIO_I, (1<<4), 7, (1<<4)},
[IT83XX_IRQ_WKO75] = {GPIO_I, (1<<5), 7, (1<<5)},
[IT83XX_IRQ_WKO76] = {GPIO_I, (1<<6), 7, (1<<6)},
[IT83XX_IRQ_WKO77] = {GPIO_I, (1<<7), 7, (1<<7)},
[IT83XX_IRQ_WKO80] = {GPIO_A, (1<<3), 8, (1<<0)},
[IT83XX_IRQ_WKO81] = {GPIO_A, (1<<4), 8, (1<<1)},
[IT83XX_IRQ_WKO82] = {GPIO_A, (1<<5), 8, (1<<2)},
[IT83XX_IRQ_WKO83] = {GPIO_A, (1<<6), 8, (1<<3)},
[IT83XX_IRQ_WKO84] = {GPIO_B, (1<<2), 8, (1<<4)},
[IT83XX_IRQ_WKO85] = {GPIO_C, (1<<0), 8, (1<<5)},
[IT83XX_IRQ_WKO86] = {GPIO_C, (1<<7), 8, (1<<6)},
[IT83XX_IRQ_WKO87] = {GPIO_D, (1<<7), 8, (1<<7)},
[IT83XX_IRQ_WKO88] = {GPIO_H, (1<<4), 9, (1<<0)},
[IT83XX_IRQ_WKO89] = {GPIO_H, (1<<5), 9, (1<<1)},
[IT83XX_IRQ_WKO90] = {GPIO_H, (1<<6), 9, (1<<2)},
[IT83XX_IRQ_WKO91] = {GPIO_A, (1<<0), 9, (1<<3)},
[IT83XX_IRQ_WKO92] = {GPIO_A, (1<<1), 9, (1<<4)},
[IT83XX_IRQ_WKO93] = {GPIO_A, (1<<2), 9, (1<<5)},
[IT83XX_IRQ_WKO94] = {GPIO_B, (1<<4), 9, (1<<6)},
[IT83XX_IRQ_WKO95] = {GPIO_C, (1<<2), 9, (1<<7)},
[IT83XX_IRQ_WKO96] = {GPIO_F, (1<<0), 10, (1<<0)},
[IT83XX_IRQ_WKO97] = {GPIO_F, (1<<1), 10, (1<<1)},
[IT83XX_IRQ_WKO98] = {GPIO_F, (1<<2), 10, (1<<2)},
[IT83XX_IRQ_WKO99] = {GPIO_F, (1<<3), 10, (1<<3)},
[IT83XX_IRQ_WKO100] = {GPIO_A, (1<<7), 10, (1<<4)},
[IT83XX_IRQ_WKO101] = {GPIO_B, (1<<0), 10, (1<<5)},
[IT83XX_IRQ_WKO102] = {GPIO_B, (1<<1), 10, (1<<6)},
[IT83XX_IRQ_WKO103] = {GPIO_B, (1<<3), 10, (1<<7)},
[IT83XX_IRQ_WKO104] = {GPIO_B, (1<<5), 11, (1<<0)},
[IT83XX_IRQ_WKO105] = {GPIO_B, (1<<6), 11, (1<<1)},
[IT83XX_IRQ_WKO106] = {GPIO_B, (1<<7), 11, (1<<2)},
[IT83XX_IRQ_WKO107] = {GPIO_C, (1<<1), 11, (1<<3)},
[IT83XX_IRQ_WKO108] = {GPIO_C, (1<<3), 11, (1<<4)},
[IT83XX_IRQ_WKO109] = {GPIO_C, (1<<5), 11, (1<<5)},
[IT83XX_IRQ_WKO110] = {GPIO_D, (1<<3), 11, (1<<6)},
[IT83XX_IRQ_WKO111] = {GPIO_D, (1<<4), 11, (1<<7)},
[IT83XX_IRQ_WKO112] = {GPIO_D, (1<<5), 12, (1<<0)},
[IT83XX_IRQ_WKO113] = {GPIO_D, (1<<6), 12, (1<<1)},
[IT83XX_IRQ_WKO114] = {GPIO_E, (1<<4), 12, (1<<2)},
[IT83XX_IRQ_WKO115] = {GPIO_G, (1<<0), 12, (1<<3)},
[IT83XX_IRQ_WKO116] = {GPIO_G, (1<<1), 12, (1<<4)},
[IT83XX_IRQ_WKO117] = {GPIO_G, (1<<2), 12, (1<<5)},
[IT83XX_IRQ_WKO118] = {GPIO_G, (1<<6), 12, (1<<6)},
[IT83XX_IRQ_WKO119] = {GPIO_I, (1<<0), 12, (1<<7)},
[IT83XX_IRQ_WKO120] = {GPIO_I, (1<<1), 13, (1<<0)},
[IT83XX_IRQ_WKO121] = {GPIO_I, (1<<2), 13, (1<<1)},
[IT83XX_IRQ_WKO122] = {GPIO_I, (1<<3), 13, (1<<2)},
[IT83XX_IRQ_WKO128] = {GPIO_J, (1<<0), 14, (1<<0)},
[IT83XX_IRQ_WKO129] = {GPIO_J, (1<<1), 14, (1<<1)},
[IT83XX_IRQ_WKO130] = {GPIO_J, (1<<2), 14, (1<<2)},
[IT83XX_IRQ_WKO131] = {GPIO_J, (1<<3), 14, (1<<3)},
[IT83XX_IRQ_WKO132] = {GPIO_J, (1<<4), 14, (1<<4)},
[IT83XX_IRQ_WKO133] = {GPIO_J, (1<<5), 14, (1<<5)},
[IT83XX_IRQ_WKO136] = {GPIO_L, (1<<0), 15, (1<<0)},
[IT83XX_IRQ_WKO137] = {GPIO_L, (1<<1), 15, (1<<1)},
[IT83XX_IRQ_WKO138] = {GPIO_L, (1<<2), 15, (1<<2)},
[IT83XX_IRQ_WKO139] = {GPIO_L, (1<<3), 15, (1<<3)},
[IT83XX_IRQ_WKO140] = {GPIO_L, (1<<4), 15, (1<<4)},
[IT83XX_IRQ_WKO141] = {GPIO_L, (1<<5), 15, (1<<5)},
[IT83XX_IRQ_WKO142] = {GPIO_L, (1<<6), 15, (1<<6)},
[IT83XX_IRQ_WKO143] = {GPIO_L, (1<<7), 15, (1<<7)},
[IT83XX_IRQ_COUNT-1] = {0, 0, 0, 0},
};
BUILD_ASSERT(ARRAY_SIZE(gpio_irqs) == IT83XX_IRQ_COUNT);
/**
* Given a GPIO port and mask, find the corresponding WKO interrupt number.
*
* @param port GPIO port
* @param mask GPIO mask
*
* @return IRQ for the WKO interrupt on the corresponding input pin.
*/
static int gpio_to_irq(uint8_t port, uint8_t mask)
{
int i;
for (i = 0; i < IT83XX_IRQ_COUNT; i++) {
if (gpio_irqs[i].gpio_port == port &&
gpio_irqs[i].gpio_mask == mask)
return i;
}
return -1;
}
struct gpio_1p8v_t {
uint8_t gpio_port;
uint8_t gpio_mask;
volatile uint8_t *ctrl_reg;
uint8_t ctrl_mask;
};
const struct gpio_1p8v_t gpio_1p8v_ctrl[] = {
{GPIO_A, (1 << 4), &IT83XX_GPIO_GRC24, (1 << 0)},
{GPIO_A, (1 << 5), &IT83XX_GPIO_GRC24, (1 << 1)},
{GPIO_B, (1 << 3), &IT83XX_GPIO_GRC22, (1 << 1)},
{GPIO_B, (1 << 4), &IT83XX_GPIO_GRC22, (1 << 0)},
{GPIO_B, (1 << 5), &IT83XX_GPIO_GRC19, (1 << 7)},
{GPIO_B, (1 << 6), &IT83XX_GPIO_GRC19, (1 << 6)},
{GPIO_C, (1 << 1), &IT83XX_GPIO_GRC19, (1 << 5)},
{GPIO_C, (1 << 2), &IT83XX_GPIO_GRC19, (1 << 4)},
{GPIO_C, (1 << 7), &IT83XX_GPIO_GRC19, (1 << 3)},
{GPIO_D, (1 << 0), &IT83XX_GPIO_GRC19, (1 << 2)},
{GPIO_D, (1 << 1), &IT83XX_GPIO_GRC19, (1 << 1)},
{GPIO_D, (1 << 2), &IT83XX_GPIO_GRC19, (1 << 0)},
{GPIO_D, (1 << 3), &IT83XX_GPIO_GRC20, (1 << 7)},
{GPIO_D, (1 << 4), &IT83XX_GPIO_GRC20, (1 << 6)},
{GPIO_E, (1 << 0), &IT83XX_GPIO_GRC20, (1 << 5)},
{GPIO_E, (1 << 6), &IT83XX_GPIO_GRC20, (1 << 4)},
{GPIO_E, (1 << 7), &IT83XX_GPIO_GRC20, (1 << 3)},
{GPIO_F, (1 << 2), &IT83XX_GPIO_GRC20, (1 << 2)},
{GPIO_F, (1 << 3), &IT83XX_GPIO_GRC20, (1 << 1)},
{GPIO_F, (1 << 4), &IT83XX_GPIO_GRC20, (1 << 0)},
{GPIO_F, (1 << 5), &IT83XX_GPIO_GRC21, (1 << 7)},
{GPIO_F, (1 << 6), &IT83XX_GPIO_GRC21, (1 << 6)},
{GPIO_F, (1 << 7), &IT83XX_GPIO_GRC21, (1 << 5)},
{GPIO_H, (1 << 0), &IT83XX_GPIO_GRC21, (1 << 2)},
{GPIO_H, (1 << 1), &IT83XX_GPIO_GRC21, (1 << 1)},
{GPIO_H, (1 << 2), &IT83XX_GPIO_GRC21, (1 << 0)},
{GPIO_I, (1 << 1), &IT83XX_GPIO_GRC23, (1 << 4)},
{GPIO_I, (1 << 2), &IT83XX_GPIO_GRC23, (1 << 5)},
{GPIO_I, (1 << 3), &IT83XX_GPIO_GRC23, (1 << 6)},
{GPIO_I, (1 << 4), &IT83XX_GPIO_GRC23, (1 << 7)},
{GPIO_J, (1 << 0), &IT83XX_GPIO_GRC23, (1 << 0)},
{GPIO_J, (1 << 1), &IT83XX_GPIO_GRC23, (1 << 1)},
{GPIO_J, (1 << 2), &IT83XX_GPIO_GRC23, (1 << 2)},
{GPIO_J, (1 << 3), &IT83XX_GPIO_GRC23, (1 << 3)},
};
static void gpio_1p8v_3p3v_sel(uint8_t port, uint8_t mask, uint32_t flags)
{
int i;
for (i = 0; i < ARRAY_SIZE(gpio_1p8v_ctrl); i++) {
if (gpio_1p8v_ctrl[i].gpio_port == port &&
gpio_1p8v_ctrl[i].gpio_mask == mask) {
if (flags & GPIO_SEL_1P8V)
*gpio_1p8v_ctrl[i].ctrl_reg |=
gpio_1p8v_ctrl[i].ctrl_mask;
else
*gpio_1p8v_ctrl[i].ctrl_reg &=
~gpio_1p8v_ctrl[i].ctrl_mask;
break;
}
}
}
void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
{
uint32_t pin = 0;
/* For each bit high in the mask, set that pin to use alt. func. */
while (mask > 0) {
/*
* If func is non-negative, set for alternate function.
* Otherwise, turn the pin into an input as it's default.
*/
if ((mask & 1) && func >= 0)
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) &= ~0xc0;
else if ((mask & 1) && func < 0)
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) =
(IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) | 0x80) & ~0x40;
pin++;
mask >>= 1;
}
}
test_mockable int gpio_get_level(enum gpio_signal signal)
{
return (IT83XX_GPIO_DATA(gpio_list[signal].port) &
gpio_list[signal].mask) ? 1 : 0;
}
void gpio_set_level(enum gpio_signal signal, int value)
{
uint32_t int_mask = get_int_mask();
/* critical section with interrupts off */
interrupt_disable();
if (value)
IT83XX_GPIO_DATA(gpio_list[signal].port) |=
gpio_list[signal].mask;
else
IT83XX_GPIO_DATA(gpio_list[signal].port) &=
~gpio_list[signal].mask;
/* restore interrupts */
set_int_mask(int_mask);
}
void gpio_kbs_pin_gpio_mode(uint32_t port, uint32_t mask, uint32_t flags)
{
if (port == GPIO_KSO_H)
IT83XX_KBS_KSOHGCTRL |= mask;
else if (port == GPIO_KSO_L)
IT83XX_KBS_KSOLGCTRL |= mask;
else if (port == GPIO_KSI)
IT83XX_KBS_KSIGCTRL |= mask;
}
void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
{
uint32_t pin = 0;
uint32_t mask_copy = mask;
int irq;
/*
* Select open drain first, so that we don't glitch the signal
* when changing the line to an output.
*/
if (flags & GPIO_OPEN_DRAIN)
IT83XX_GPIO_GPOT(port) |= mask;
else
IT83XX_GPIO_GPOT(port) &= ~mask;
/* To select 1.8v or 3.3v support. */
gpio_1p8v_3p3v_sel(port, mask, flags);
/* If output, set level before changing type to an output. */
if (flags & GPIO_OUTPUT) {
if (flags & GPIO_HIGH)
IT83XX_GPIO_DATA(port) |= mask;
else if (flags & GPIO_LOW)
IT83XX_GPIO_DATA(port) &= ~mask;
}
/* For each bit high in the mask, set input/output and pullup/down. */
while (mask_copy > 0) {
if (mask_copy & 1) {
/* Set input or output. */
if (flags & GPIO_OUTPUT)
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) =
(IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) | 0x40)
& ~0x80;
else
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) =
(IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) | 0x80)
& ~0x40;
/* Handle pullup / pulldown */
if (flags & GPIO_PULL_UP) {
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) =
(IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) | 0x04)
& ~0x02;
} else if (flags & GPIO_PULL_DOWN) {
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) =
(IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) | 0x02)
& ~0x04;
} else {
/* No pull up/down */
IT83XX_GPIO_CTRL(CTRL_BASE(port), pin) &= ~0x06;
}
}
pin++;
mask_copy >>= 1;
}
/* Set rising edge interrupt. */
if (flags & GPIO_INT_F_RISING) {
irq = gpio_to_irq(port, mask);
*(wuemr(gpio_irqs[irq].wuc_group)) &= ~gpio_irqs[irq].wuc_mask;
}
/*
* Set falling edge or both edges interrupt. Note that pins in WUC
* groups 7, 10, and 12 can only declare a falling edge trigger. All
* other pins can only declare both edges as the trigger.
*
* TODO: use an assert to catch if a developer tries to declare one
* type of interrupt on a pin that doesn't support that type.
*/
if (flags & GPIO_INT_F_FALLING) {
irq = gpio_to_irq(port, mask);
*(wuemr(gpio_irqs[irq].wuc_group)) |= gpio_irqs[irq].wuc_mask;
}
}
int gpio_enable_interrupt(enum gpio_signal signal)
{
int irq = gpio_to_irq(gpio_list[signal].port, gpio_list[signal].mask);
if (irq == -1)
return EC_ERROR_UNKNOWN;
else
task_enable_irq(irq);
return EC_SUCCESS;
}
int gpio_disable_interrupt(enum gpio_signal signal)
{
int irq = gpio_to_irq(gpio_list[signal].port, gpio_list[signal].mask);
if (irq == -1)
return EC_ERROR_UNKNOWN;
else
task_disable_irq(irq);
return EC_SUCCESS;
}
int gpio_clear_pending_interrupt(enum gpio_signal signal)
{
int irq = gpio_to_irq(gpio_list[signal].port, gpio_list[signal].mask);
if (irq == -1)
return EC_ERROR_UNKNOWN;
*(wuesr(gpio_irqs[irq].wuc_group)) = gpio_irqs[irq].wuc_mask;
task_clear_pending_irq(irq);
return EC_SUCCESS;
}
void gpio_pre_init(void)
{
const struct gpio_info *g = gpio_list;
int is_warm = system_is_reboot_warm();
int flags;
int i;
IT83XX_GPIO_GCR = 0x06;
#ifndef CONFIG_USB_PD_TCPM_ITE83XX
/* To prevent cc pins leakage if we don't use pd module */
for (i = 0; i < USBPD_PORT_COUNT; i++) {
IT83XX_USBPD_CCGCR(i) = 0x1f;
IT83XX_USBPD_CCPSR(i) = 0x66;
}
#endif
for (i = 0; i < GPIO_COUNT; i++, g++) {
flags = g->flags;
if (flags & GPIO_DEFAULT)
continue;
/*
* If this is a warm reboot, don't set the output levels or
* we'll shut off the AP.
*/
if (is_warm)
flags &= ~(GPIO_LOW | GPIO_HIGH);
if (g->port > GPIO_KBS_OFF)
/* KSO/KSI pins to GPIO mode (input only). */
gpio_kbs_pin_gpio_mode(g->port, g->mask, flags);
else
/* Set up GPIO based on flags */
gpio_set_flags_by_mask(g->port, g->mask, flags);
}
}
/**
* Handle a GPIO interrupt by calling the pins corresponding handler if
* one exists.
*
* @param port GPIO port (GPIO_*)
* @param mask GPIO mask
*/
static void gpio_interrupt(int port, uint8_t mask)
{
int i = 0;
const struct gpio_info *g = gpio_list;
for (i = 0; i < GPIO_IH_COUNT; i++, g++) {
if (port == g->port && (mask & g->mask)) {
gpio_irq_handlers[i](i);
return;
}
}
}
/**
* Define one IRQ function to handle all GPIO interrupts. The IRQ determines
* the interrupt number which was triggered, calls the master handler above,
* and clears status registers.
*/
static void __gpio_irq(void)
{
/* Determine interrupt number. */
int irq = intc_get_ec_int();
#ifdef HAS_TASK_KEYSCAN
if (irq == IT83XX_IRQ_WKINTC) {
keyboard_raw_interrupt();
return;
}
#endif
#ifdef CONFIG_LPC
if (irq == IT83XX_IRQ_WKINTAD)
return;
#endif
/*
* Clear the WUC status register. Note the external pin first goes
* to the WUC module and is always edge triggered.
*/
*(wuesr(gpio_irqs[irq].wuc_group)) = gpio_irqs[irq].wuc_mask;
/*
* Clear the interrupt controller status register. Note the interrupt
* controller is level triggered from the WUC status.
*/
task_clear_pending_irq(irq);
/* Run the GPIO master handler above with corresponding port/mask. */
gpio_interrupt(gpio_irqs[irq].gpio_port, gpio_irqs[irq].gpio_mask);
}
/* Route all WKO interrupts coming from INT#2 into __gpio_irq. */
DECLARE_IRQ(CPU_INT_2_ALL_GPIOS, __gpio_irq, 1);