#include <asm/io.h>\r
#include <asm/irq.h>\r
\r
+#include <linux/dmaengine.h>\r
+\r
#ifdef CONFIG_OF\r
#include <linux/of.h>\r
#endif\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
*v1.6 : 2013-11-29\r
- migrate to kernel3.10,and fit device tree \r
+ migrate to kernel3.10,and fit device tree\r
+*v1.7 : 2014-03-03\r
+ DMA use new interfaces, and use some interfaces with devm_ prefix \r
+*v1.8 : 2014-03-04\r
+* 1.clear receive time out interrupt request in irq handler \r
*/\r
-#define VERSION_AND_TIME "rk_serial.c v1.5 2013-11-29"\r
+#define VERSION_AND_TIME "rk_serial.c v1.8 2014-03-04"\r
\r
#define PORT_RK 90\r
#define UART_USR 0x1F /* UART Status Register */\r
\r
\r
//#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)\r
-\r
#define UART_NR 5 //uart port number\r
\r
\r
\r
#define TX_DMA (1)\r
#define RX_DMA (2)\r
-\r
-#ifdef CONFIG_UART0_DMA_RK29 \r
-#define UART0_USE_DMA CONFIG_UART0_DMA_RK29\r
-#else\r
-#define UART0_USE_DMA CLOSE_DMA\r
-#endif\r
-#ifdef CONFIG_UART1_DMA_RK29\r
-#define UART1_USE_DMA CONFIG_UART1_DMA_RK29\r
-#else\r
-#define UART1_USE_DMA CLOSE_DMA\r
-#endif\r
-#ifdef CONFIG_UART2_DMA_RK29\r
-#define UART2_USE_DMA CONFIG_UART2_DMA_RK29\r
-#else\r
-#define UART2_USE_DMA CLOSE_DMA\r
-#endif\r
-#ifdef CONFIG_UART3_DMA_RK29\r
-#define UART3_USE_DMA CONFIG_UART3_DMA_RK29\r
-#else\r
-#define UART3_USE_DMA CLOSE_DMA\r
-#endif\r
-\r
+#define DMA_SERIAL_BUFFER_SIZE (UART_XMIT_SIZE*2)\r
+#define CONFIG_CLOCK_CTRL 1\r
//serial wake up \r
#ifdef CONFIG_UART0_WAKEUP_RK29 \r
#define UART0_USE_WAKEUP CONFIG_UART0_WAKEUP_RK29\r
#define DMA_TX_TRRIGE_LEVEL 128\r
#define SERIAL_CIRC_CNT_TO_END(xmit) CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)\r
\r
-#ifdef CONFIG_OF\r
-#define USE_DMA 0\r
-#else\r
-#define USE_DMA (UART0_USE_DMA | UART1_USE_DMA | UART2_USE_DMA | UART3_USE_DMA)\r
-#endif\r
+#define USE_DMA OPEN_DMA\r
\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
-#else\r
-#include <plat/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
-//#define CONFIG_CLOCK_CTRL\r
-\r
#if USE_DMA\r
/* added by hhb@rock-chips.com for uart dma transfer */\r
\r
struct rk_uart_dma {\r
u32 use_dma; //1:used\r
- enum dma_ch rx_dmach;\r
- enum dma_ch tx_dmach;\r
+ //enum dma_ch rx_dmach;\r
+ //enum dma_ch tx_dmach;\r
\r
//receive and transfer buffer\r
char * rx_buffer; //visual memory\r
char use_timer;\r
int rx_timeout;\r
struct timer_list rx_timer;\r
+\r
+ struct dma_chan *dma_chan_rx, *dma_chan_tx;\r
+ struct scatterlist rx_sgl, tx_sgl;\r
+ unsigned int rx_bytes, tx_bytes;\r
};\r
#endif\r
\r
struct work_struct uart_work;\r
struct work_struct uart_work_rx;\r
struct workqueue_struct *uart_wq;\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 void serial_rk_release_dma_tx(struct uart_port *port);\r
-static int serial_rk_start_tx_dma(struct uart_port *port);\r
+static void serial_rk_release_dma_tx(struct uart_rk_port *up);\r
+static int serial_rk_start_dma_tx(struct uart_rk_port *up);\r
//static void serial_rk_rx_timeout(unsigned long uart);\r
-static void serial_rk_release_dma_rx(struct uart_port *port);\r
-static int serial_rk_start_rx_dma(struct uart_port *port);\r
+static void serial_rk_release_dma_rx(struct uart_rk_port *up);\r
+static int serial_rk_start_dma_rx(struct uart_rk_port *up);\r
+static void serial_rk_stop_dma_tx(struct uart_rk_port *up);\r
+static void serial_rk_stop_dma_rx(struct uart_rk_port *up);\r
+\r
#else\r
static inline int serial_rk_start_tx_dma(struct uart_port *port) { return 0; }\r
#endif\r
#if USE_DMA\r
struct rk_uart_dma *uart_dma = up->dma;\r
if(uart_dma->use_dma & TX_DMA){\r
- serial_rk_release_dma_tx(port);\r
+ serial_rk_stop_dma_tx(up);\r
}\r
#endif\r
__stop_tx(up);\r
-\r
}\r
\r
\r
#if USE_DMA\r
struct rk_uart_dma *uart_dma = up->dma;\r
if(uart_dma->use_dma & RX_DMA){\r
- serial_rk_release_dma_rx(port);\r
+ serial_rk_stop_dma_rx(up);\r
}\r
#endif\r
up->ier &= ~UART_IER_RLSI;\r
#endif\r
\r
#if USE_DMA\r
-/*\r
- * Start transmitting by dma.\r
- */\r
-#define DMA_SERIAL_BUFFER_SIZE UART_XMIT_SIZE\r
-\r
-/* added by hhb@rock-chips.com for uart dma transfer*/\r
-static struct rk_uart_dma rk29_uart_ports_dma[] = {\r
- {UART0_USE_DMA, DMACH_UART0_RX, DMACH_UART0_TX},\r
- {UART1_USE_DMA, DMACH_UART1_RX, DMACH_UART1_TX},\r
- {UART2_USE_DMA, DMACH_UART2_RX, DMACH_UART2_TX},\r
- {UART3_USE_DMA, DMACH_UART3_RX, DMACH_UART3_TX},\r
-};\r
-\r
-\r
/* DMAC PL330 add by hhb@rock-chips.com */\r
-static struct rk29_dma_client rk29_uart_dma_client = {\r
- .name = "rk-uart-dma",\r
-};\r
\r
-/*TX*/\r
-\r
-static void serial_rk_release_dma_tx(struct uart_port *port)\r
+static void serial_rk_stop_dma_tx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
struct rk_uart_dma *uart_dma = up->dma;\r
- if(!port){\r
- return;\r
+ \r
+ if(uart_dma && uart_dma->tx_dma_used) {\r
+ dmaengine_terminate_all(uart_dma->dma_chan_tx);\r
+ uart_dma->tx_dma_used = 0;\r
}\r
+}\r
+\r
+static void serial_rk_release_dma_tx(struct uart_rk_port *up)\r
+{\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+\r
if(uart_dma && uart_dma->tx_dma_inited) {\r
- rk29_dma_free(uart_dma->tx_dmach, &rk29_uart_dma_client);\r
+ serial_rk_stop_dma_tx(up);\r
+ dma_release_channel(uart_dma->dma_chan_tx);\r
+ uart_dma->dma_chan_tx = NULL;\r
uart_dma->tx_dma_inited = 0;\r
- uart_dma->tx_dma_used = 0;\r
}\r
}\r
\r
-/*this function will be called every time after rk29_dma_enqueue() be invoked*/\r
-static void serial_rk_dma_txcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
- struct uart_port *port = buf;\r
+static void dma_tx_callback(void *data)\r
+{\r
+ struct uart_port *port = data;\r
struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
struct circ_buf *xmit = &port->state->xmit;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ struct scatterlist *sgl = &uart_dma->tx_sgl;\r
\r
- if(result != RK29_RES_OK){\r
- printk(">>>>%s:%d result:%d\n", __func__, __LINE__, result);\r
- up->dma->tx_dma_used = 0;\r
- return;\r
- }\r
+ dma_unmap_sg(up->port.dev, sgl, 1, DMA_TO_DEVICE);\r
\r
- //spin_lock(&(up->dma->rx_lock));\r
- xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);\r
- port->icount.tx += size;\r
+ xmit->tail = (xmit->tail + uart_dma->tx_bytes) & (UART_XMIT_SIZE - 1);\r
+ port->icount.tx += uart_dma->tx_bytes;\r
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
- uart_write_wakeup(&up->port);\r
+ uart_write_wakeup(port);\r
\r
//spin_lock(&(up->dma->tx_lock));\r
- up->dma->tx_dma_used = 0;\r
+ uart_dma->tx_dma_used = 0;\r
//spin_unlock(&(up->dma->tx_lock));\r
serial_rk_enable_ier_thri(up);\r
up->port_activity = jiffies;\r
// dev_info(up->port.dev, "s:%d\n", size);\r
-}\r
\r
-static int serial_rk_init_dma_tx(struct uart_port *port) {\r
+}\r
+static int serial_rk_init_dma_tx(struct uart_rk_port *up) {\r
\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
+ struct dma_slave_config slave_config;\r
+ struct uart_port *port = &up->port;\r
struct rk_uart_dma *uart_dma = up->dma;\r
+ int ret;\r
\r
- if(!port || !uart_dma){\r
+ if(!uart_dma){\r
dev_info(up->port.dev, "serial_rk_init_dma_tx fail\n");\r
return -1;\r
}\r
return 0;\r
}\r
\r
- if (rk29_dma_request(uart_dma->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request tx fail\n");\r
- return -1;\r
+ uart_dma->dma_chan_tx = dma_request_slave_channel(port->dev, "tx");\r
+ if (!uart_dma->dma_chan_tx) {\r
+ dev_err(port->dev, "cannot get the TX DMA channel!\n");\r
+ ret = -EINVAL;\r
}\r
\r
- if (rk29_dma_set_buffdone_fn(uart_dma->tx_dmach, serial_rk_dma_txcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn tx fail\n");\r
- return -1;\r
- }\r
- \r
- if (rk29_dma_devconfig(uart_dma->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig tx fail\n");\r
- return -1;\r
- }\r
- \r
- if (rk29_dma_config(uart_dma->tx_dmach, 1, 16)) {\r
- dev_info(up->port.dev, "rk29_dma_config tx fail\n");\r
- return -1;\r
+ slave_config.direction = DMA_MEM_TO_DEV; \r
+ slave_config.dst_addr = port->mapbase + UART_TX; \r
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; \r
+ slave_config.dst_maxburst = 16;\r
+ ret = dmaengine_slave_config(uart_dma->dma_chan_tx, &slave_config); \r
+ if (ret) {\r
+ dev_err(port->dev, "error in TX dma configuration."); \r
+ return ret;\r
}\r
\r
uart_dma->tx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_tx sucess\n");\r
+ dev_info(port->dev, "serial_rk_init_dma_tx sucess\n");\r
return 0;\r
-\r
}\r
\r
-static int serial_rk_start_tx_dma(struct uart_port *port)\r
+static int serial_rk_start_dma_tx(struct uart_rk_port *up)\r
{\r
int count = 0;\r
+ struct uart_port *port = &up->port;\r
struct circ_buf *xmit = &port->state->xmit;\r
- struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
struct rk_uart_dma *uart_dma = up->dma;\r
+ struct scatterlist *sgl = &uart_dma->tx_sgl;\r
+ struct dma_async_tx_descriptor *desc;\r
+ int ret;\r
\r
if(!uart_dma->use_dma)\r
goto err_out;\r
\r
- if(-1 == serial_rk_init_dma_tx(port))\r
+ if(-1 == serial_rk_init_dma_tx(up))\r
goto err_out;\r
\r
if (1 == uart_dma->tx_dma_used)\r
count = SERIAL_CIRC_CNT_TO_END(xmit);\r
count -= count%16;\r
if(count >= DMA_TX_TRRIGE_LEVEL) {\r
- if (rk29_dma_enqueue(uart_dma->tx_dmach, port, uart_dma->tx_phy_addr + xmit->tail , count)) {\r
- goto err_out;\r
- }\r
- rk29_dma_ctrl(uart_dma->tx_dmach, RK29_DMAOP_START);\r
- up->dma->tx_dma_used = 1;\r
+ uart_dma->tx_bytes = count;\r
+ sg_init_one(sgl, uart_dma->tx_buffer + xmit->tail, count);\r
+ ret = dma_map_sg(port->dev, sgl, 1, DMA_TO_DEVICE);\r
+ \r
+ if (ret == 0) {\r
+ dev_err(port->dev, "DMA mapping error for TX.\n"); \r
+ return -1;\r
+ } \r
+ desc = dmaengine_prep_slave_sg(uart_dma->dma_chan_tx, sgl, 1,\r
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); \r
+\r
+ if (!desc) {\r
+ dev_err(port->dev, "We cannot prepare for the TX slave dma!\n"); \r
+ return -1; \r
+ } \r
+ desc->callback = dma_tx_callback; \r
+ desc->callback_param = port; \r
+ dmaengine_submit(desc);\r
+ dma_async_issue_pending(uart_dma->dma_chan_tx);\r
+ uart_dma->tx_dma_used = 1;\r
}\r
// spin_unlock(&(uart_dma->tx_lock));\r
return 1;\r
err_out:\r
- dev_info(up->port.dev, "-serial_rk_start_tx_dma-error-\n");\r
+ dev_info(up->port.dev, "-serial_rk_start_dma_tx-error-\n");\r
return -1;\r
}\r
\r
\r
\r
/*RX*/\r
+#if 0\r
static void serial_rk_dma_rxcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
\r
//printk(">>%s:%d\n", __func__, result);\r
}\r
+#endif\r
\r
-static void serial_rk_release_dma_rx(struct uart_port *port)\r
+static void serial_rk_stop_dma_rx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
struct rk_uart_dma *uart_dma = up->dma;\r
\r
- if(!port){\r
- return;\r
- }\r
- \r
- if(uart_dma && uart_dma->rx_dma_inited) {\r
+ if(uart_dma && uart_dma->rx_dma_used) {\r
del_timer(&uart_dma->rx_timer);\r
- rk29_dma_free(uart_dma->rx_dmach, &rk29_uart_dma_client);\r
+ dmaengine_terminate_all(uart_dma->dma_chan_rx); \r
uart_dma->rb_tail = 0;\r
- uart_dma->rx_dma_inited = 0;\r
uart_dma->rx_dma_used = 0;\r
}\r
}\r
\r
\r
-static int serial_rk_init_dma_rx(struct uart_port *port) {\r
+static void serial_rk_release_dma_rx(struct uart_rk_port *up)\r
+{\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ \r
+ if(uart_dma && uart_dma->rx_dma_inited) {\r
+ serial_rk_stop_dma_rx(up);\r
+ dma_release_channel(uart_dma->dma_chan_rx);\r
+ uart_dma->dma_chan_rx = NULL; \r
+ uart_dma->rx_dma_inited = 0;\r
+ }\r
+}\r
\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
+\r
+static int serial_rk_init_dma_rx(struct uart_rk_port *up) \r
+{\r
+ int ret;\r
+ struct uart_port *port = &up->port;\r
+ struct dma_slave_config slave_config;\r
struct rk_uart_dma *uart_dma = up->dma;\r
\r
- if(!port || !uart_dma){\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx: port fail\n");\r
+ if(!uart_dma) {\r
+ dev_info(port->dev, "serial_rk_init_dma_rx: port fail\n");\r
return -1;\r
}\r
\r
return 0;\r
}\r
\r
- if (rk29_dma_request(uart_dma->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request fail rx \n");\r
+ uart_dma->dma_chan_rx = dma_request_slave_channel(port->dev, "rx");\r
+ if (!uart_dma->dma_chan_rx) {\r
+ dev_err(port->dev, "cannot get the DMA channel.\n");\r
return -1;\r
}\r
\r
- if (rk29_dma_set_buffdone_fn(uart_dma->rx_dmach, serial_rk_dma_rxcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn rx fail\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_devconfig(uart_dma->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig rx fail\n");\r
- return -1;\r
- }\r
-\r
- if (rk29_dma_config(uart_dma->rx_dmach, 1, 1)) {\r
- dev_info(up->port.dev, "rk29_dma_config rx fail 1 1 \n");\r
- return -1;\r
+ slave_config.direction = DMA_DEV_TO_MEM; \r
+ slave_config.src_addr = port->mapbase + UART_RX; \r
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; \r
+ slave_config.src_maxburst = 1;\r
+ ret = dmaengine_slave_config(uart_dma->dma_chan_rx, &slave_config); \r
+ if (ret) {\r
+ dev_err(port->dev, "error in RX dma configuration.\n"); \r
+ return ret; \r
}\r
\r
- //rk29_dma_setflags(uart_dma->rx_dmach, RK29_DMAF_CIRCULAR);\r
-\r
uart_dma->rx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx sucess\n");\r
+ dev_info(port->dev, "serial_rk_init_dma_rx sucess\n");\r
return 0;\r
-\r
}\r
\r
-static int serial_rk_start_rx_dma(struct uart_port *port)\r
+static int serial_rk_start_dma_rx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk_uart_dma *uart_dma = up->dma;\r
+ struct uart_port *port = &up->port;\r
+ struct rk_uart_dma *uart_dma = up->dma; \r
+ struct dma_async_tx_descriptor *desc; \r
+ \r
if(!uart_dma->use_dma)\r
return 0;\r
\r
if(uart_dma->rx_dma_used == 1)\r
return 0;\r
\r
- if(-1 == serial_rk_init_dma_rx(port)){\r
+ if(-1 == serial_rk_init_dma_rx(up)){\r
dev_info(up->port.dev, "*******serial_rk_init_dma_rx*******error*******\n");\r
return -1;\r
}\r
- \r
-#if 0 \r
- if (rk29_dma_enqueue(uart_dma->rx_dmach, (void *)up, uart_dma->rx_phy_addr,\r
- uart_dma->rb_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
- }\r
+ desc = dmaengine_prep_dma_cyclic(uart_dma->dma_chan_rx, uart_dma->rx_phy_addr, uart_dma->rb_size, uart_dma->rb_size/2,DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); \r
\r
- if (rk29_dma_enqueue(uart_dma->rx_dmach, (void *)up,\r
- uart_dma->rx_phy_addr+uart_dma->rb_size/2, uart_dma->rb_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
- }\r
+ if (!desc) {\r
+ dev_err(port->dev, "We cannot prepare for the RX slave dma!\n"); \r
+ return -EINVAL; \r
+ }\r
+\r
+ //desc->callback = dma_rx_callback; \r
+ //desc->callback_param = port; \r
+ dev_dbg(port->dev, "RX: prepare for the DMA.\n");\r
+ dmaengine_submit(desc); \r
+ dma_async_issue_pending(uart_dma->dma_chan_rx);\r
\r
-#else\r
- rk29_dma_enqueue_ring(uart_dma->rx_dmach, (void *)up, uart_dma->rx_phy_addr, uart_dma->rb_size/4, 4, false);\r
-#endif\r
- rk29_dma_ctrl(uart_dma->rx_dmach, RK29_DMAOP_START);\r
uart_dma->rx_dma_used = 1;\r
if(uart_dma->use_timer == 1){\r
mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout));\r
return 1;\r
}\r
\r
-static void serial_rk_update_rb_addr(struct uart_rk_port *up){\r
- dma_addr_t current_pos = 0;\r
- dma_addr_t rx_current_pos = 0;\r
+static void serial_rk_update_rb_addr(struct uart_rk_port *up)\r
+{\r
struct rk_uart_dma *uart_dma = up->dma;\r
+ struct dma_tx_state state; \r
//spin_lock(&(up->dma->rx_lock));\r
uart_dma->rx_size = 0;\r
- if(uart_dma->rx_dma_used == 1){\r
- rk29_dma_getposition(uart_dma->rx_dmach, ¤t_pos, &rx_current_pos);\r
- uart_dma->rb_head = (rx_current_pos - uart_dma->rx_phy_addr);\r
+ if(uart_dma->rx_dma_used == 1) {\r
+ dmaengine_tx_status(uart_dma->dma_chan_rx, (dma_cookie_t)0, &state);\r
+ uart_dma->rb_head = (state.residue - uart_dma->rx_phy_addr);\r
uart_dma->rx_size = CIRC_CNT(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size);\r
}\r
//spin_unlock(&(up->dma->rx_lock));\r
{\r
int count, flip = 0;\r
struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
+ struct uart_port *port = &up->port;\r
struct rk_uart_dma *uart_dma = up->dma;\r
\r
- if(!uart_dma->rx_dma_used || !up->port.state->port.tty)\r
+ if(!uart_dma->rx_dma_used || !port->state->port.tty)\r
return;\r
\r
serial_rk_update_rb_addr(up);\r
-\r
+ //if (uart_dma->rx_size > 0)\r
+ // printk("rx_size:%d ADDR:%x\n", uart_dma->rx_size, uart_dma->rb_head);\r
while(1) {\r
count = CIRC_CNT_TO_END(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size);\r
if(count <= 0)\r
break;\r
- up->port.icount.rx += count;\r
- flip = tty_insert_flip_string(up->port.state->port.tty, uart_dma->rx_buffer\r
- + uart_dma->rb_tail, count);\r
- tty_flip_buffer_push(&up->port.state->port);\r
+ port->icount.rx += count;\r
+ flip = tty_insert_flip_string(&port->state->port, uart_dma->rx_buffer\r
+ + uart_dma->rb_tail, count);\r
+ tty_flip_buffer_push(&port->state->port);\r
uart_dma->rb_tail = (uart_dma->rb_tail + count) & (uart_dma->rb_size - 1);\r
up->port_activity = jiffies;\r
}\r
\r
- //if (uart_dma->rx_size > 0)\r
- // printk("rx_size:%d ADDR:%x\n", uart_dma->rx_size, uart_dma->rb_head);\r
-\r
- if(uart_dma->use_timer == 1){\r
+ if(uart_dma->use_timer == 1)\r
mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout));\r
- }\r
-\r
-}\r
-#if 0\r
-static void serial_rk_rx_timeout(unsigned long uart)\r
-{\r
- struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
-\r
- serial_rk_report_dma_rx(up);\r
- //queue_work(up->uart_wq, &up->uart_work);\r
-}\r
-\r
-static void serial_rk_report_revdata_workfunc(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work);\r
-\r
- serial_rk_report_dma_rx((unsigned long)up);\r
-\r
- //spin_lock(&(up->dma->rx_lock));\r
-\r
- if(up->port.state->port.tty && up->dma->use_timer != 1 && up->fifo_size > 0){\r
-\r
- tty_insert_flip_string(up->port.state->port.tty, up->fifo, up->fifo_size);\r
- tty_flip_buffer_push(&up->port.state->port);\r
- up->port.icount.rx += up->fifo_size;\r
- up->ier |= UART_IER_RDI;\r
- serial_out(up, UART_IER, up->ier);\r
- }\r
-\r
- //spin_unlock(&(up->dma->rx_lock));\r
-\r
-}\r
-\r
-\r
-static void serial_rk_start_dma_rx(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work_rx);\r
-\r
- //mod_timer(&up->dma->rx_timer, jiffies + msecs_to_jiffies(up->dma->rx_timeout));\r
- //rk29_dma_ctrl(up->dma->rx_dmach, RK29_DMAOP_START);\r
- //serial_rk_start_rx_dma(&up->port);\r
-\r
}\r
-#endif\r
-\r
#endif /* USE_DMA */\r
\r
\r
//hhb\r
if(up->dma->use_dma & TX_DMA){\r
if(SERIAL_CIRC_CNT_TO_END(xmit) >= DMA_TX_TRRIGE_LEVEL){\r
- serial_rk_start_tx_dma(&up->port);\r
+ serial_rk_start_dma_tx(up);\r
return;\r
}\r
}\r
if(!(up->dma->use_dma & RX_DMA)) {\r
if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
receive_chars(up, &status);\r
- }\r
+ } else if ((up->iir & 0x0f) == 0x0c) {\r
+ serial_in(up, UART_RX);\r
+ }\r
}\r
\r
if ((up->iir & 0x0f) == 0x02) {\r
\r
if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
receive_chars(up, &status);\r
- }\r
+ } else if ((up->iir & 0x0f) == 0x0c) {\r
+ serial_in(up, UART_RX);\r
+ }\r
check_modem_status(up);\r
//hhb@rock-chips.com when FIFO and THRE mode both are enabled,and FIFO TX empty trigger is set to larger than 1,\r
//,we need to add ((up->iir & 0x0f) == 0x02) to transmit_chars,because when entering interrupt,the FIFO and THR\r
\r
up->mcr = 0;\r
#ifdef CONFIG_CLOCK_CTRL\r
- clk_enable(up->pclk);\r
- clk_enable(up->clk); // enable the config uart clock\r
+ clk_prepare_enable(up->clk);\r
+ clk_prepare_enable(up->pclk); // enable the config uart clock\r
#endif\r
/*\r
* Clear the FIFO buffers and disable them.\r
#endif\r
free_irq(up->port.irq, up);\r
#ifdef CONFIG_CLOCK_CTRL\r
- clk_disable(up->clk);\r
- clk_disable(up->pclk);\r
+ clk_disable_unprepare(up->clk);\r
+ clk_disable_unprepare(up->pclk); \r
#endif\r
}\r
\r
unsigned char cval = 0, fcr = 0, mcr = 0;\r
unsigned long flags;\r
unsigned int baud, quot;\r
+\r
dev_dbg(port->dev, "+%s\n", __func__);\r
\r
+#if USE_DMA\r
+ //stop dma tx, which might make the uart be busy while some registers are set\r
+ if(up->dma->tx_dma_used) {\r
+ serial_rk_stop_dma_tx(up);\r
+ }\r
+#endif\r
+\r
switch (termios->c_cflag & CSIZE) {\r
case CS5:\r
cval = UART_LCR_WLEN5;\r
up->ier |= UART_IER_RLSI;\r
up->ier |= UART_IER_PTIME; //Programmable THRE Interrupt Mode Enable\r
if (up->dma->use_dma & RX_DMA)\r
- serial_rk_start_rx_dma(&up->port);\r
+ serial_rk_start_dma_rx(up);\r
else\r
up->ier |= UART_IER_RDI;\r
} else\r
dev_dbg(port->dev, "%s: %s\n", __func__, state ? "disable" : "enable");\r
if (state) {\r
#ifdef CONFIG_CLOCK_CTRL\r
- clk_disable(up->clk);\r
- clk_disable(up->pclk);\r
+ clk_disable_unprepare(up->clk);\r
+ clk_disable_unprepare(up->pclk); \r
#endif\r
} else {\r
#ifdef CONFIG_CLOCK_CTRL\r
- clk_enable(up->pclk);\r
- clk_enable(up->clk);\r
+ clk_prepare_enable(up->clk);\r
+ clk_prepare_enable(up->pclk); \r
#endif\r
}\r
}\r
#endif\r
\r
#ifdef CONFIG_OF\r
-static int of_rk_serial_parse_dt(struct device_node *np, struct of_rk_serial *rks) {\r
+static int of_rk_serial_parse_dt(struct device_node *np, struct of_rk_serial *rks) \r
+{\r
unsigned int val = 0;\r
+ const char *s = NULL;\r
+ int ret, i = 0;\r
rks->id = of_alias_get_id(np, "serial");\r
if(!of_property_read_u32(np, "clock-frequency", &val))\r
rks->uartclk = val;\r
+\r
#if USE_DMA\r
- rks->use_dma = 0; \r
- if(of_find_property(np, "use-dma-rx", &val))\r
- rks->use_dma |= RX_DMA;\r
- if(of_find_property(np, "use-dma-tx", &val))\r
- rks->use_dma |= TX_DMA;\r
+ rks->use_dma = 0;\r
+ for(i = 0; i < 2; i++) {\r
+ ret = of_property_read_string_index(np, "dma-names", i, &s);\r
+ if(!ret) {\r
+ if(!strcmp(s, "tx"))\r
+ rks->use_dma |= TX_DMA;\r
+ else if (!strcmp(s, "rx"))\r
+ rks->use_dma |= RX_DMA;\r
+ }\r
+ }\r
#endif\r
return 0;\r
}\r
#endif\r
\r
-\r
static int serial_rk_probe(struct platform_device *pdev)\r
{\r
struct uart_rk_port *up;\r
struct resource *mem;\r
int irq;\r
int ret = -ENOSPC;\r
- struct of_rk_serial rks; \r
+ struct of_rk_serial rks;\r
+\r
+ up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);\r
+ if (!up)\r
+ return -ENOMEM;\r
\r
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- if (!mem) {\r
- dev_err(&pdev->dev, "no mem resource?\n");\r
- return -ENODEV;\r
- }\r
+ up->port.membase = devm_request_and_ioremap(&pdev->dev, mem);\r
+ if (!up->port.membase)\r
+ return -ENOMEM;\r
\r
irq = platform_get_irq(pdev, 0);\r
if (irq < 0) {\r
of_rk_serial_parse_dt(pdev->dev.of_node, &rks);\r
pdev->id = rks.id;\r
#endif\r
- if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,\r
- pdev->dev.driver->name)) {\r
- dev_err(&pdev->dev, "memory region already claimed\n");\r
- return -EBUSY;\r
- }\r
- \r
- up = kzalloc(sizeof(*up), GFP_KERNEL);\r
- if (up == NULL) {\r
- ret = -ENOMEM;\r
- goto do_release_region;\r
- }\r
- \r
+\r
sprintf(up->name, "rk29_serial.%d", pdev->id);\r
up->pdev = pdev;\r
#ifdef CONFIG_CLOCK_CTRL\r
- up->pclk = clk_get(&pdev->dev, "pclk_uart");\r
- up->clk = clk_get(&pdev->dev, "uart");\r
- if (unlikely(IS_ERR(up->clk))) {\r
- ret = PTR_ERR(up->clk);\r
- printk("%s:%d\n", __func__, __LINE__);\r
- goto do_free;\r
- \r
+ up->pclk = devm_clk_get(&pdev->dev, "pclk_uart");\r
+ up->clk = devm_clk_get(&pdev->dev, "sclk_uart");\r
+ if (unlikely(IS_ERR(up->clk)) || unlikely(IS_ERR(up->pclk))) {\r
+ dev_err(&pdev->dev, "get clock fail\n");\r
+ return -EINVAL;\r
}\r
#endif\r
up->tx_loadsz = 30;\r
#if USE_DMA\r
- up->dma = &rk29_uart_ports_dma[pdev->id];\r
+ up->dma = devm_kzalloc(&pdev->dev, sizeof(struct rk_uart_dma), GFP_KERNEL);\r
+ if (!up->dma) {\r
+ dev_err(&pdev->dev, "unable to allocate mem\n");\r
+ return -ENOMEM;\r
+ }\r
up->dma->use_dma = rks.use_dma;\r
#endif\r
#if USE_WAKEUP\r
up->port.ops = &serial_rk_pops;\r
up->port.line = pdev->id;\r
up->port.iobase = mem->start;\r
- up->port.membase = ioremap_nocache(mem->start, mem->end - mem->start + 1);\r
- if (!up->port.membase) {\r
- ret = -ENOMEM;\r
- goto do_put_clk;\r
- }\r
up->port.mapbase = mem->start;\r
up->port.irqflags = IRQF_DISABLED;\r
#if defined(CONFIG_CLOCK_CTRL)\r
#else\r
up->port.uartclk = 24000000;\r
#endif\r
+\r
#if USE_DMA\r
/* set dma config */\r
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);\r
init_timer(&up->dma->rx_timer);\r
\r
//rx buffer\r
- up->dma->rb_size = UART_XMIT_SIZE*2;\r
+ up->dma->rb_size = DMA_SERIAL_BUFFER_SIZE;\r
up->dma->rx_buffer = dmam_alloc_coherent(up->port.dev, up->dma->rb_size,\r
&up->dma->rx_phy_addr, DMA_MEMORY_MAP);\r
up->dma->rb_tail = 0;\r
+ up->dma->rx_dma_inited = 0;\r
+ up->dma->rx_dma_used = 0;\r
\r
if(!up->dma->rx_buffer){\r
dev_info(up->port.dev, "dmam_alloc_coherent dma_rx_buffer fail\n");\r
//INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc);\r
//INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx);\r
//up->uart_wq = create_singlethread_workqueue("uart_workqueue");\r
- up->dma->rx_dma_used = 0;\r
spin_lock_init(&(up->dma->rx_lock));\r
- serial_rk_init_dma_rx(&up->port);\r
+ serial_rk_init_dma_rx(up);\r
}\r
\r
if(up->dma->use_dma & TX_DMA){\r
dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->dma->tx_phy_addr);\r
}\r
spin_lock_init(&(up->dma->tx_lock));\r
- serial_rk_init_dma_tx(&up->port);\r
+ serial_rk_init_dma_tx(up);\r
}\r
\r
+ \r
#endif\r
serial_rk_add_console_port(up);\r
ret = uart_add_one_port(&serial_rk_reg, &up->port);\r
if (ret != 0)\r
- goto do_iounmap;\r
+ return ret;\r
platform_set_drvdata(pdev, up);\r
dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase);\r
#if USE_WAKEUP\r
serial_rk_setup_wakeup_irq(up); \r
#endif\r
return 0;\r
-\r
-do_iounmap:\r
- iounmap(up->port.membase);\r
- up->port.membase = NULL;\r
-do_put_clk:\r
-#ifdef CONFIG_CLOCK_CTRL\r
- clk_put(up->clk);\r
- clk_put(up->pclk);\r
-do_free:\r
-#endif\r
- kfree(up);\r
-do_release_region:\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
- return ret;\r
}\r
\r
static int serial_rk_remove(struct platform_device *pdev)\r
\r
platform_set_drvdata(pdev, NULL);\r
if (up) {\r
- struct resource *mem;\r
- destroy_workqueue(up->uart_wq);\r
- uart_remove_one_port(&serial_rk_reg, &up->port);\r
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- iounmap(up->port.membase);\r
- up->port.membase = NULL;\r
-#ifdef CONFIG_CLOCK_CTRL\r
- clk_put(up->clk);\r
- clk_put(up->pclk);\r
+#if USE_DMA\r
+ serial_rk_release_dma_tx(up);\r
+ serial_rk_release_dma_rx(up);\r
#endif\r
- kfree(up);\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
- }\r
#if USE_WAKEUP\r
- serial_rk_remove_wakeup_irq(up);\r
+ serial_rk_remove_wakeup_irq(up);\r
#endif\r
+ //destroy_workqueue(up->uart_wq);\r
+ uart_remove_one_port(&serial_rk_reg, &up->port);\r
+ up->port.membase = NULL;\r
+ }\r
+\r
return 0;\r
}\r
\r
module_exit(serial_rk_exit);\r
\r
MODULE_LICENSE("GPL");\r
-MODULE_DESCRIPTION("RK UART driver");\r
-\r
+MODULE_DESCRIPTION("RK UART driver");
\ No newline at end of file