206 lines
6.0 KiB
C
206 lines
6.0 KiB
C
#include "asm/includes.h"
|
||
#include "device/gpio.h"
|
||
#include "system/includes.h"
|
||
|
||
|
||
struct port_wakeup_work {
|
||
u8 event;
|
||
/* u8 wkup_edge; */
|
||
void (*handler)(void);
|
||
/* void *priv; */
|
||
/* unsigned int gpio; */
|
||
} port_wakeup_work;
|
||
|
||
#define CLEAR_PORT_PEND() JL_WAKEUP->CON2 = 0xffff
|
||
#define READ_PORT_PEND() JL_WAKEUP->CON3
|
||
#define WKUP_ENABLE(x) JL_WAKEUP->CON0 |= BIT(x)
|
||
#define WKUP_DISABLE(x) JL_WAKEUP->CON0 &= (~BIT(x))
|
||
#define WKUP_EDGE(x,edg) JL_WAKEUP->CON1 = ((JL_WAKEUP->CON1 & (~BIT(x))) | (edg? BIT(x): 0))
|
||
#define WKUP_CLEAR_PEND(x) (JL_WAKEUP->CON2 |= BIT(x))
|
||
|
||
#define PORT_WAKED_ID_BASE 0X2A
|
||
#define PORT_WAKED_ID_GIVE(i) (PORT_WAKED_ID_BASE + i)
|
||
#define PORT_WAKED_ID_GET(hdl) (hdl - PORT_WAKED_ID_BASE)
|
||
#define PORT_WAKED_ID_NUM (3) //最多16个事件
|
||
|
||
static struct port_wakeup_work g_wakeup_work[PORT_WAKED_ID_NUM];
|
||
static DEFINE_SPINLOCK(lock);
|
||
|
||
|
||
static const s32 port_table[64] = {
|
||
IO_PORTA_00, IO_PORTA_01, IO_PORTA_02, IO_PORTA_03, IO_PORTA_04, IO_PORTA_05, IO_PORTA_06, IO_PORTA_07, IO_PORTA_08, IO_PORTA_09, IO_PORTA_10,
|
||
IO_PORTB_00, IO_PORTB_01, IO_PORTB_02, IO_PORTB_03, IO_PORTB_04, IO_PORTB_05, IO_PORTB_06, IO_PORTB_07, IO_PORTB_08,
|
||
IO_PORTC_00, IO_PORTC_01, IO_PORTC_02, IO_PORTC_03, IO_PORTC_04, IO_PORTC_05, IO_PORTC_06, IO_PORTC_07, IO_PORTC_08, IO_PORTC_09, IO_PORTC_10,
|
||
IO_PORTE_00, IO_PORTE_01, IO_PORTE_02, IO_PORTE_03, IO_PORTE_04, IO_PORTE_05, IO_PORTE_06, IO_PORTE_07, IO_PORTE_08, IO_PORTE_09,
|
||
IO_PORTH_00, IO_PORTH_01, IO_PORTH_02, IO_PORTH_03, IO_PORTH_04, IO_PORTH_05, IO_PORTH_06, IO_PORTH_07, IO_PORTH_08, IO_PORTH_09,
|
||
IO_PORTG_08, IO_PORTG_09, IO_PORTG_10, IO_PORTG_11, IO_PORTG_12, IO_PORTG_13, IO_PORTG_14, IO_PORTG_15,
|
||
-1, /* TMR5_PWM_OUT,\ */
|
||
IO_PORT_USB_DPA, IO_PORT_USB_DMA,
|
||
IO_PORT_USB_DPB, IO_PORT_USB_DMB
|
||
};
|
||
|
||
|
||
___interrupt
|
||
static void port_wakeup_isr(void)
|
||
{
|
||
int i;
|
||
u16 wkup_pend;
|
||
|
||
//spin_lock(&lock);
|
||
wkup_pend = READ_PORT_PEND();
|
||
for (i = 0; i < sizeof(g_wakeup_work) / sizeof(struct port_wakeup_work); i++) {
|
||
if (wkup_pend & BIT(g_wakeup_work[i].event)) {
|
||
if (g_wakeup_work[i].handler) {
|
||
g_wakeup_work[i].handler();
|
||
}
|
||
WKUP_CLEAR_PEND(g_wakeup_work[i].event);
|
||
}
|
||
}
|
||
//spin_unlock(&lock);
|
||
}
|
||
|
||
|
||
static s32 get_remap_gpio(u32 gpio)
|
||
{
|
||
for (u32 idx = 0; idx < ARRAY_SIZE(port_table); idx++) {
|
||
if (port_table[idx] == gpio) {
|
||
return idx;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
static u8 gpio_2_port_bit(unsigned int gpio)
|
||
{
|
||
u8 port_bit;
|
||
u8 port_h;
|
||
u8 port_l;
|
||
port_h = gpio / IO_GROUP_NUM;
|
||
port_l = gpio % IO_GROUP_NUM;
|
||
if (port_h == 4) {
|
||
//PORTE
|
||
port_h = 6;
|
||
} else if (port_h == 6) {
|
||
//PORTG
|
||
port_h = 4;
|
||
} else if (port_h == 7) {
|
||
//PORTH
|
||
port_h = 5;
|
||
}
|
||
port_bit = (port_h << 4) | port_l;
|
||
return port_bit;
|
||
}
|
||
|
||
//event: event参数为EVENT_IO_0或EVENT_IO_1时,gpio为任意IO都可以唤醒
|
||
void *port_wakeup_reg(PORT_EVENT_E event, unsigned int gpio, PORT_EDGE_E edge, void (*handler)(void))
|
||
{
|
||
int i = 0;
|
||
s32 idx = -1;
|
||
|
||
if (!handler) {
|
||
return NULL;
|
||
}
|
||
|
||
//if (event > EVENT_PH7) {
|
||
// return NULL;
|
||
//}
|
||
|
||
if (gpio > IO_PORT_USB_DMB) {
|
||
return NULL;
|
||
}
|
||
static char port_wakeup_init_flag;
|
||
if (!port_wakeup_init_flag) {
|
||
port_wakeup_init_flag = 1;
|
||
JL_WAKEUP->CON0 = 0;
|
||
JL_WAKEUP->CON2 = 0xffffffff;
|
||
request_irq(IRQ_PORT_IDX, 3, port_wakeup_isr, 0x1);
|
||
}
|
||
|
||
spin_lock(&lock);
|
||
|
||
while (i < sizeof(g_wakeup_work) / sizeof(struct port_wakeup_work)) {
|
||
if (g_wakeup_work[i].handler == NULL) {
|
||
break;
|
||
}
|
||
++i;
|
||
}
|
||
|
||
if (i == sizeof(g_wakeup_work) / sizeof(struct port_wakeup_work)) {
|
||
spin_unlock(&lock);
|
||
printf("[error]>PORT_WAKED_ID_NUM to less = %d", PORT_WAKED_ID_NUM);
|
||
return NULL;
|
||
}
|
||
|
||
/* u8 port_io = gpio_2_port_bit(gpio); */
|
||
|
||
/* if (event == EVENT_IO_0) { */
|
||
/* JL_IOMAP->CON2 &= ~(0xff); */
|
||
/* JL_IOMAP->CON2 |= gpio; */
|
||
/* } else if (event == EVENT_IO_1) { */
|
||
/* JL_IOMAP->CON2 &= ~(0xff << 8); */
|
||
/* JL_IOMAP->CON2 |= (gpio << 8); */
|
||
/* } */
|
||
|
||
if ((event == EVENT_IO_0) || (event == EVENT_IO_1)) {
|
||
idx = get_remap_gpio(gpio);
|
||
if (idx != -1) {
|
||
if (event == EVENT_IO_0) {
|
||
JL_IOMAP->CON2 &= ~(0xff);
|
||
JL_IOMAP->CON2 |= idx;
|
||
} else if (event == EVENT_IO_1) {
|
||
JL_IOMAP->CON2 &= ~(0xff << 8);
|
||
JL_IOMAP->CON2 |= (idx << 8);
|
||
}
|
||
} else {
|
||
spin_unlock(&lock);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
if (event < EVENT_SDC0_DAT1 && (event < EVENT_UT0_RX || event > EVENT_UT2_RX)) {
|
||
gpio_direction_input(gpio);
|
||
gpio_set_die(gpio, 1);
|
||
if (edge == EDGE_POSITIVE) {
|
||
gpio_set_pull_down(gpio, 1);
|
||
gpio_set_pull_up(gpio, 0);
|
||
} else if (edge == EDGE_NEGATIVE) {
|
||
gpio_set_pull_down(gpio, 0);
|
||
gpio_set_pull_up(gpio, 1);
|
||
}
|
||
}
|
||
|
||
g_wakeup_work[i].event = event;
|
||
/* g_wakeup_work[i].wkup_edge = edge; */
|
||
/* g_wakeup_work[i].gpio = gpio; */
|
||
g_wakeup_work[i].handler = handler;
|
||
/* g_wakeup_work[i].priv = priv; */
|
||
|
||
WKUP_EDGE(event, edge);
|
||
WKUP_CLEAR_PEND(event);
|
||
WKUP_ENABLE(event);
|
||
|
||
spin_unlock(&lock);
|
||
|
||
log_i("ENABLE REG = 0x%x.\n", JL_WAKEUP->CON0);
|
||
log_i("EDGE REG = 0x%x.\n", JL_WAKEUP->CON1);
|
||
log_i("PEND REG = 0x%x.\n", JL_WAKEUP->CON3);
|
||
log_i("JL_IOMAP->CON2=0x%x\n", JL_IOMAP->CON2);
|
||
|
||
return (void *)PORT_WAKED_ID_GIVE(i);
|
||
}
|
||
|
||
void port_wakeup_unreg(void *hdl)
|
||
{
|
||
if (!hdl || (int)hdl < PORT_WAKED_ID_BASE || (int)hdl >= (PORT_WAKED_ID_BASE + PORT_WAKED_ID_NUM)) {
|
||
log_i("hdl err = 0x%x \r\n", hdl);
|
||
return;
|
||
}
|
||
int i = PORT_WAKED_ID_GET((int)hdl);
|
||
spin_lock(&lock);
|
||
WKUP_DISABLE(g_wakeup_work[i].event);
|
||
WKUP_CLEAR_PEND(g_wakeup_work[i].event);
|
||
memset(&g_wakeup_work[i], 0, sizeof(struct port_wakeup_work));
|
||
spin_unlock(&lock);
|
||
}
|