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
};\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
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
#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
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
#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
.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
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
\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
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
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