rk_serial:in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends
authorhhb <hhb@rock-chips.com>
Sat, 19 Oct 2013 06:22:25 +0000 (14:22 +0800)
committerhhb <hhb@rock-chips.com>
Sat, 19 Oct 2013 06:22:25 +0000 (14:22 +0800)
drivers/tty/serial/Kconfig
drivers/tty/serial/rk_serial.c

index 53e023db36a4c4c886959d262a3fb209d46f9815..40dba2f27516182b455a3b6eeb75433d414d320c 100644 (file)
@@ -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
index 5272a00100af861ba104680391f4025857697a74..319b9d0bf7d6f6c70908cf7455f6d6998f6cfd3d 100644 (file)
                 UART_LSR_THRE doesn't. So, the macro BOTH_EMPTY should be replaced with UART_LSR_TEMT.\r
 *v1.4 : 2013-04-16\r
 *              1.fix bug dma buffer free error\r
+*v1.5 : 2013-10-17\r
+*              1.in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends \r
 */\r
-#define VERSION_AND_TIME  "rk_serial.c v1.4 2013-04-16"\r
+#define VERSION_AND_TIME  "rk_serial.c v1.5 2013-10-17"\r
 \r
 #define PORT_RK                90\r
 #define UART_USR       0x1F    /* UART Status Register */\r
 #define UART3_USE_DMA CLOSE_DMA\r
 #endif\r
 \r
+//serial wake up \r
+#ifdef CONFIG_UART0_WAKEUP_RK29 \r
+#define UART0_USE_WAKEUP CONFIG_UART0_WAKEUP_RK29\r
+#else\r
+#define UART0_USE_WAKEUP 0\r
+#endif\r
+#ifdef CONFIG_UART1_WAKEUP_RK29\r
+#define UART1_USE_WAKEUP CONFIG_UART1_WAKEUP_RK29\r
+#else\r
+#define UART1_USE_WAKEUP 0\r
+#endif\r
+#ifdef CONFIG_UART2_WAKEUP_RK29\r
+#define UART2_USE_WAKEUP CONFIG_UART2_WAKEUP_RK29\r
+#else\r
+#define UART2_USE_WAKEUP 0\r
+#endif\r
+#ifdef CONFIG_UART3_WAKEUP_RK29\r
+#define UART3_USE_WAKEUP CONFIG_UART3_WAKEUP_RK29\r
+#else\r
+#define UART3_USE_WAKEUP 0\r
+#endif\r
+\r
+\r
+\r
 #define USE_TIMER    1           // use timer for dma transport\r
 #define POWER_MANEGEMENT 1\r
 #define RX_TIMEOUT             (3000*3)  //uint ms\r
 \r
 \r
 #define USE_DMA (UART0_USE_DMA | UART1_USE_DMA | UART2_USE_DMA | UART3_USE_DMA)\r
+#define USE_WAKEUP (UART0_USE_WAKEUP | UART1_USE_WAKEUP | UART2_USE_WAKEUP | UART3_USE_WAKEUP)\r
+\r
 #if USE_DMA\r
 #ifdef CONFIG_ARCH_RK29\r
 #include <mach/dma-pl330.h>\r
 #endif\r
 #endif\r
 \r
+#if USE_WAKEUP\r
+#include <mach/iomux.h>\r
+#include <linux/wakelock.h>\r
+#endif\r
+\r
 \r
 \r
 static struct uart_driver serial_rk_reg;\r
@@ -214,6 +247,21 @@ struct rk_uart_dma {
 };\r
 #endif\r
 \r
+#if USE_WAKEUP \r
+struct uart_wake_up {\r
+       unsigned int enable;\r
+       unsigned int rx_mode;\r
+       unsigned int tx_mode;\r
+       unsigned int rx_pin;\r
+       char rx_pin_name[32];\r
+       unsigned int tx_pin;\r
+       unsigned int rx_irq;\r
+       char rx_irq_name[32];\r
+       struct wake_lock wakelock;\r
+       char wakelock_name[32];\r
+};\r
+#endif\r
+\r
 struct uart_rk_port {\r
        struct uart_port        port;\r
        struct platform_device  *pdev;\r
@@ -237,7 +285,7 @@ struct uart_rk_port {
        unsigned char           msr_saved_flags;\r
 #endif\r
 \r
-       char                    name[12];\r
+       char                    name[16];\r
        char                    fifo[64];\r
        char                    fifo_size;\r
        unsigned long           port_activity;\r
@@ -247,6 +295,9 @@ struct uart_rk_port {
 #if USE_DMA\r
        struct rk_uart_dma *dma;\r
 #endif\r
+#if USE_WAKEUP\r
+       struct uart_wake_up *wakeup;\r
+#endif\r
 };\r
 \r
 #if USE_DMA\r
@@ -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)\r
 {\r
        offset = offset << 2;\r
+\r
        return __raw_readb(up->port.membase + offset);\r
 }\r
 \r
@@ -464,6 +516,14 @@ static void serial_rk_enable_ms(struct uart_port *port)
 #endif\r
 }\r
 \r
+#if USE_WAKEUP\r
+static struct uart_wake_up rk29_uart_ports_wakeup[] = {\r
+               {UART0_USE_WAKEUP, UART0_SIN, UART0_SOUT},\r
+               {UART1_USE_WAKEUP, UART1_SIN, UART1_SOUT},\r
+               {UART2_USE_WAKEUP, UART2_SIN, UART2_SOUT},\r
+               {UART3_USE_WAKEUP, UART3_SIN, UART3_SOUT},\r
+};\r
+#endif\r
 \r
 #if USE_DMA\r
 /*\r
@@ -1790,6 +1850,81 @@ static struct uart_driver serial_rk_reg = {
        .cons                   = SERIAL_CONSOLE,\r
        .nr                     = UART_NR,\r
 };\r
+#if USE_WAKEUP\r
+static irqreturn_t serial_rk_wakeup_handler(int irq, void *dev) {\r
+       struct uart_rk_port *up = dev;\r
+       struct uart_wake_up *wakeup = up->wakeup;\r
+       if(wakeup->enable == 1) {\r
+               iomux_set(wakeup->rx_mode);\r
+               wake_lock_timeout(&wakeup->wakelock, 3 * HZ);\r
+       }    \r
+       return 0;\r
+}\r
+\r
+static int serial_rk_setup_wakeup_irq(struct uart_rk_port *up)\r
+{\r
+       int ret = 0;\r
+       struct uart_wake_up *wakeup = up->wakeup;\r
+\r
+       if(wakeup->enable == 1) {\r
+               memset(wakeup->wakelock_name, 0, 32);\r
+               sprintf(wakeup->wakelock_name, "serial.%d_wakelock", up->port.line);\r
+               wake_lock_init(&wakeup->wakelock, WAKE_LOCK_SUSPEND, wakeup->wakelock_name);\r
+               memset(wakeup->rx_pin_name, 0, 32);             \r
+               sprintf(wakeup->rx_pin_name, "UART%d_SIN", up->port.line);\r
+               wakeup->rx_pin = iomux_mode_to_gpio(wakeup->rx_mode);\r
+               ret = gpio_request(wakeup->rx_pin, wakeup->rx_pin_name);\r
+               if (ret) {\r
+                       printk("request %s fail ! \n", wakeup->rx_pin_name);\r
+                   return ret;\r
+               }\r
+               gpio_direction_input(wakeup->rx_pin);\r
+               wakeup->rx_irq = gpio_to_irq(wakeup->rx_pin);\r
+               memset(wakeup->rx_irq_name, 0, 32);\r
+               sprintf(wakeup->rx_irq_name, "serial.%d_wake_up_irq", up->port.line);\r
+               ret = request_irq(wakeup->rx_irq, serial_rk_wakeup_handler, IRQF_TRIGGER_FALLING, wakeup->rx_irq_name, up);\r
+               if(ret < 0) {\r
+                       printk("%s request fail\n", wakeup->rx_irq_name);\r
+                   return ret;\r
+               }\r
+               disable_irq_nosync(wakeup->rx_irq);\r
+               enable_irq_wake(wakeup->rx_irq);\r
+               iomux_set(wakeup->rx_mode);\r
+       }\r
+       return ret;\r
+}\r
+\r
+static int serial_rk_enable_wakeup_irq(struct uart_rk_port *up) {\r
+       struct uart_wake_up *wakeup = up->wakeup;\r
+       if(wakeup->enable == 1) {\r
+               iomux_set(wakeup->rx_mode & 0xfff0);\r
+               enable_irq(wakeup->rx_irq);\r
+       }\r
+    return 0;\r
+}\r
+\r
+static int serial_rk_disable_wakeup_irq(struct uart_rk_port *up) {\r
+       struct uart_wake_up *wakeup = up->wakeup;\r
+       if(wakeup->enable == 1) {\r
+               disable_irq_nosync(wakeup->rx_irq);\r
+               iomux_set(wakeup->rx_mode);\r
+       }\r
+    return 0;\r
+}\r
+\r
+static int serial_rk_remove_wakeup_irq(struct uart_rk_port *up) {\r
+       struct uart_wake_up *wakeup = up->wakeup;\r
+       if(wakeup->enable == 1) {\r
+               //disable_irq_nosync(wakeup->rx_irq);\r
+               free_irq(wakeup->rx_irq, NULL);\r
+               gpio_free(wakeup->rx_pin);\r
+               wake_lock_destroy(&wakeup->wakelock);\r
+       }\r
+    return 0;\r
+}\r
+#endif\r
+\r
+\r
 \r
 static int __devinit serial_rk_probe(struct platform_device *pdev)\r
 {\r
@@ -1833,6 +1968,9 @@ static int __devinit serial_rk_probe(struct platform_device *pdev)
        up->tx_loadsz = 30;\r
 #if USE_DMA\r
        up->dma = &rk29_uart_ports_dma[pdev->id];\r
+#endif\r
+#if USE_WAKEUP\r
+       up->wakeup = &rk29_uart_ports_wakeup[pdev->id];\r
 #endif\r
        up->port.dev = &pdev->dev;\r
        up->port.type = PORT_RK;\r
@@ -1913,7 +2051,9 @@ static int __devinit serial_rk_probe(struct platform_device *pdev)
 \r
        platform_set_drvdata(pdev, up);\r
        dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase);\r
-\r
+#if USE_WAKEUP\r
+       serial_rk_setup_wakeup_irq(up); \r
+#endif\r
        return 0;\r
 \r
 do_iounmap:\r
@@ -1946,7 +2086,9 @@ static int __devexit serial_rk_remove(struct platform_device *pdev)
                kfree(up);\r
                release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
        }\r
-\r
+#if USE_WAKEUP\r
+    serial_rk_remove_wakeup_irq(up);\r
+#endif\r
        return 0;\r
 }\r
 \r
@@ -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){\r
                serial_rk_pm(&up->port, 1, 0);\r
        }\r
-\r
+#if USE_WAKEUP\r
+    serial_rk_enable_wakeup_irq(up);\r
+#endif\r
        return 0;\r
 }\r
 \r
 static int serial_rk_resume(struct platform_device *dev)\r
 {\r
        struct uart_rk_port *up = platform_get_drvdata(dev);\r
-\r
+#if USE_WAKEUP\r
+    serial_rk_disable_wakeup_irq(up);\r
+#endif\r
        if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
                uart_resume_port(&serial_rk_reg, &up->port);\r
        }\r