From: hhb Date: Sat, 19 Oct 2013 06:22:25 +0000 (+0800) Subject: rk_serial:in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends X-Git-Tag: firefly_0821_release~6554 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cfc366f69603190180e3e2fbdf0eed172cc3e2d5;p=firefly-linux-kernel-4.4.55.git rk_serial:in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends --- diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 53e023db36a4..40dba2f27516 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1533,6 +1533,11 @@ config UART0_DMA_RK29 1:enable dma tx 2:enable dma rx 3:both enable dma tx and rx +config UART0_WAKEUP_RK29 + bool "Serial port 0 WAKEUP support (EXPERIMENTAL)" + depends on UART0_RK29 + default 0 + config UART1_RK29 bool "Serial port 1 support" depends on SERIAL_RK29 @@ -1549,6 +1554,11 @@ config UART1_DMA_RK29 1:enable dma tx 2:enable dma rx 3:both enable dma tx and rx +config UART1_WAKEUP_RK29 + bool "Serial port 1 WAKEUP support (EXPERIMENTAL)" + depends on UART1_RK29 + default 0 + config UART2_RK29 bool "Serial port 2 support" depends on SERIAL_RK29 @@ -1565,6 +1575,11 @@ config UART2_DMA_RK29 1:enable dma tx 2:enable dma rx 3:both enable dma tx and rx +config UART2_WAKEUP_RK29 + bool "Serial port 2 WAKEUP support (EXPERIMENTAL)" + depends on UART2_RK29 + default 0 + config UART3_RK29 bool "Serial port 3 support" depends on SERIAL_RK29 && !ARCH_RK2928 && !ARCH_RK3026 @@ -1580,7 +1595,12 @@ config UART3_DMA_RK29 help 1:enable dma tx 2:enable dma rx - 3:both enable dma tx and rx + 3:both enable dma tx and rx +config UART3_WAKEUP_RK29 + bool "Serial port 3 WAKEUP support (EXPERIMENTAL)" + depends on UART3_RK29 + default 0 + config SERIAL_RK29_CONSOLE bool "Serial console support" depends on SERIAL_RK29=y diff --git a/drivers/tty/serial/rk_serial.c b/drivers/tty/serial/rk_serial.c index 5272a00100af..319b9d0bf7d6 100644 --- a/drivers/tty/serial/rk_serial.c +++ b/drivers/tty/serial/rk_serial.c @@ -66,8 +66,10 @@ UART_LSR_THRE doesn't. So, the macro BOTH_EMPTY should be replaced with UART_LSR_TEMT. *v1.4 : 2013-04-16 * 1.fix bug dma buffer free error +*v1.5 : 2013-10-17 +* 1.in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends */ -#define VERSION_AND_TIME "rk_serial.c v1.4 2013-04-16" +#define VERSION_AND_TIME "rk_serial.c v1.5 2013-10-17" #define PORT_RK 90 #define UART_USR 0x1F /* UART Status Register */ @@ -111,6 +113,30 @@ #define UART3_USE_DMA CLOSE_DMA #endif +//serial wake up +#ifdef CONFIG_UART0_WAKEUP_RK29 +#define UART0_USE_WAKEUP CONFIG_UART0_WAKEUP_RK29 +#else +#define UART0_USE_WAKEUP 0 +#endif +#ifdef CONFIG_UART1_WAKEUP_RK29 +#define UART1_USE_WAKEUP CONFIG_UART1_WAKEUP_RK29 +#else +#define UART1_USE_WAKEUP 0 +#endif +#ifdef CONFIG_UART2_WAKEUP_RK29 +#define UART2_USE_WAKEUP CONFIG_UART2_WAKEUP_RK29 +#else +#define UART2_USE_WAKEUP 0 +#endif +#ifdef CONFIG_UART3_WAKEUP_RK29 +#define UART3_USE_WAKEUP CONFIG_UART3_WAKEUP_RK29 +#else +#define UART3_USE_WAKEUP 0 +#endif + + + #define USE_TIMER 1 // use timer for dma transport #define POWER_MANEGEMENT 1 #define RX_TIMEOUT (3000*3) //uint ms @@ -119,6 +145,8 @@ #define USE_DMA (UART0_USE_DMA | UART1_USE_DMA | UART2_USE_DMA | UART3_USE_DMA) +#define USE_WAKEUP (UART0_USE_WAKEUP | UART1_USE_WAKEUP | UART2_USE_WAKEUP | UART3_USE_WAKEUP) + #if USE_DMA #ifdef CONFIG_ARCH_RK29 #include @@ -127,6 +155,11 @@ #endif #endif +#if USE_WAKEUP +#include +#include +#endif + static struct uart_driver serial_rk_reg; @@ -214,6 +247,21 @@ struct rk_uart_dma { }; #endif +#if USE_WAKEUP +struct uart_wake_up { + unsigned int enable; + unsigned int rx_mode; + unsigned int tx_mode; + unsigned int rx_pin; + char rx_pin_name[32]; + unsigned int tx_pin; + unsigned int rx_irq; + char rx_irq_name[32]; + struct wake_lock wakelock; + char wakelock_name[32]; +}; +#endif + struct uart_rk_port { struct uart_port port; struct platform_device *pdev; @@ -237,7 +285,7 @@ struct uart_rk_port { unsigned char msr_saved_flags; #endif - char name[12]; + char name[16]; char fifo[64]; char fifo_size; unsigned long port_activity; @@ -247,6 +295,9 @@ struct uart_rk_port { #if USE_DMA struct rk_uart_dma *dma; #endif +#if USE_WAKEUP + struct uart_wake_up *wakeup; +#endif }; #if USE_DMA @@ -263,6 +314,7 @@ static int serial_rk_startup(struct uart_port *port); static inline unsigned int serial_in(struct uart_rk_port *up, int offset) { offset = offset << 2; + return __raw_readb(up->port.membase + offset); } @@ -464,6 +516,14 @@ static void serial_rk_enable_ms(struct uart_port *port) #endif } +#if USE_WAKEUP +static struct uart_wake_up rk29_uart_ports_wakeup[] = { + {UART0_USE_WAKEUP, UART0_SIN, UART0_SOUT}, + {UART1_USE_WAKEUP, UART1_SIN, UART1_SOUT}, + {UART2_USE_WAKEUP, UART2_SIN, UART2_SOUT}, + {UART3_USE_WAKEUP, UART3_SIN, UART3_SOUT}, +}; +#endif #if USE_DMA /* @@ -1790,6 +1850,81 @@ static struct uart_driver serial_rk_reg = { .cons = SERIAL_CONSOLE, .nr = UART_NR, }; +#if USE_WAKEUP +static irqreturn_t serial_rk_wakeup_handler(int irq, void *dev) { + struct uart_rk_port *up = dev; + struct uart_wake_up *wakeup = up->wakeup; + if(wakeup->enable == 1) { + iomux_set(wakeup->rx_mode); + wake_lock_timeout(&wakeup->wakelock, 3 * HZ); + } + return 0; +} + +static int serial_rk_setup_wakeup_irq(struct uart_rk_port *up) +{ + int ret = 0; + struct uart_wake_up *wakeup = up->wakeup; + + if(wakeup->enable == 1) { + memset(wakeup->wakelock_name, 0, 32); + sprintf(wakeup->wakelock_name, "serial.%d_wakelock", up->port.line); + wake_lock_init(&wakeup->wakelock, WAKE_LOCK_SUSPEND, wakeup->wakelock_name); + memset(wakeup->rx_pin_name, 0, 32); + sprintf(wakeup->rx_pin_name, "UART%d_SIN", up->port.line); + wakeup->rx_pin = iomux_mode_to_gpio(wakeup->rx_mode); + ret = gpio_request(wakeup->rx_pin, wakeup->rx_pin_name); + if (ret) { + printk("request %s fail ! \n", wakeup->rx_pin_name); + return ret; + } + gpio_direction_input(wakeup->rx_pin); + wakeup->rx_irq = gpio_to_irq(wakeup->rx_pin); + memset(wakeup->rx_irq_name, 0, 32); + sprintf(wakeup->rx_irq_name, "serial.%d_wake_up_irq", up->port.line); + ret = request_irq(wakeup->rx_irq, serial_rk_wakeup_handler, IRQF_TRIGGER_FALLING, wakeup->rx_irq_name, up); + if(ret < 0) { + printk("%s request fail\n", wakeup->rx_irq_name); + return ret; + } + disable_irq_nosync(wakeup->rx_irq); + enable_irq_wake(wakeup->rx_irq); + iomux_set(wakeup->rx_mode); + } + return ret; +} + +static int serial_rk_enable_wakeup_irq(struct uart_rk_port *up) { + struct uart_wake_up *wakeup = up->wakeup; + if(wakeup->enable == 1) { + iomux_set(wakeup->rx_mode & 0xfff0); + enable_irq(wakeup->rx_irq); + } + return 0; +} + +static int serial_rk_disable_wakeup_irq(struct uart_rk_port *up) { + struct uart_wake_up *wakeup = up->wakeup; + if(wakeup->enable == 1) { + disable_irq_nosync(wakeup->rx_irq); + iomux_set(wakeup->rx_mode); + } + return 0; +} + +static int serial_rk_remove_wakeup_irq(struct uart_rk_port *up) { + struct uart_wake_up *wakeup = up->wakeup; + if(wakeup->enable == 1) { + //disable_irq_nosync(wakeup->rx_irq); + free_irq(wakeup->rx_irq, NULL); + gpio_free(wakeup->rx_pin); + wake_lock_destroy(&wakeup->wakelock); + } + return 0; +} +#endif + + static int __devinit serial_rk_probe(struct platform_device *pdev) { @@ -1833,6 +1968,9 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) up->tx_loadsz = 30; #if USE_DMA up->dma = &rk29_uart_ports_dma[pdev->id]; +#endif +#if USE_WAKEUP + up->wakeup = &rk29_uart_ports_wakeup[pdev->id]; #endif up->port.dev = &pdev->dev; up->port.type = PORT_RK; @@ -1913,7 +2051,9 @@ static int __devinit serial_rk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, up); dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase); - +#if USE_WAKEUP + serial_rk_setup_wakeup_irq(up); +#endif return 0; do_iounmap: @@ -1946,7 +2086,9 @@ static int __devexit serial_rk_remove(struct platform_device *pdev) kfree(up); release_mem_region(mem->start, (mem->end - mem->start) + 1); } - +#if USE_WAKEUP + serial_rk_remove_wakeup_irq(up); +#endif return 0; } @@ -1960,14 +2102,18 @@ static int serial_rk_suspend(struct platform_device *dev, pm_message_t state) if(up->port.line == DBG_PORT && POWER_MANEGEMENT){ serial_rk_pm(&up->port, 1, 0); } - +#if USE_WAKEUP + serial_rk_enable_wakeup_irq(up); +#endif return 0; } static int serial_rk_resume(struct platform_device *dev) { struct uart_rk_port *up = platform_get_drvdata(dev); - +#if USE_WAKEUP + serial_rk_disable_wakeup_irq(up); +#endif if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){ uart_resume_port(&serial_rk_reg, &up->port); }