blob: 6b1c92c1c27f5efd32518088ccb8b7d22458562a [file] [log] [blame]
Rong Wang161e7732011-11-17 23:17:04 +08001/*
2 * Driver for CSR SiRFprimaII onboard UARTs.
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/ioport.h>
11#include <linux/platform_device.h>
12#include <linux/init.h>
13#include <linux/sysrq.h>
14#include <linux/console.h>
15#include <linux/tty.h>
16#include <linux/tty_flip.h>
17#include <linux/serial_core.h>
18#include <linux/serial.h>
19#include <linux/clk.h>
20#include <linux/of.h>
21#include <linux/slab.h>
22#include <linux/io.h>
Qipan Li2eb56182013-08-15 06:52:15 +080023#include <linux/of_gpio.h>
Qipan Li8316d042013-08-19 11:47:53 +080024#include <linux/dmaengine.h>
25#include <linux/dma-direction.h>
26#include <linux/dma-mapping.h>
Rong Wang161e7732011-11-17 23:17:04 +080027#include <asm/irq.h>
28#include <asm/mach/irq.h>
Rong Wang161e7732011-11-17 23:17:04 +080029
30#include "sirfsoc_uart.h"
31
32static unsigned int
33sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count);
34static unsigned int
35sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
36static struct uart_driver sirfsoc_uart_drv;
37
Qipan Li8316d042013-08-19 11:47:53 +080038static void sirfsoc_uart_tx_dma_complete_callback(void *param);
39static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
40static void sirfsoc_uart_rx_dma_complete_callback(void *param);
Rong Wang161e7732011-11-17 23:17:04 +080041static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
42 {4000000, 2359296},
43 {3500000, 1310721},
44 {3000000, 1572865},
45 {2500000, 1245186},
46 {2000000, 1572866},
47 {1500000, 1245188},
48 {1152000, 1638404},
49 {1000000, 1572869},
50 {921600, 1114120},
51 {576000, 1245196},
52 {500000, 1245198},
53 {460800, 1572876},
54 {230400, 1310750},
55 {115200, 1310781},
56 {57600, 1310843},
57 {38400, 1114328},
58 {19200, 1114545},
59 {9600, 1114979},
60};
61
Qipan Lia6ffe892015-04-29 06:45:08 +000062static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR];
Rong Wang161e7732011-11-17 23:17:04 +080063
64static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
65{
66 return container_of(port, struct sirfsoc_uart_port, port);
67}
68
69static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
70{
71 unsigned long reg;
Qipan Li5df83112013-08-12 18:15:35 +080072 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
73 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
74 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
75 reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
Qipan Licb4595a2015-04-29 06:45:09 +000076 return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0;
Rong Wang161e7732011-11-17 23:17:04 +080077}
78
79static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
80{
81 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +080082 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Qipan Li2eb56182013-08-15 06:52:15 +080083 if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
Rong Wang161e7732011-11-17 23:17:04 +080084 goto cts_asserted;
Qipan Li2eb56182013-08-15 06:52:15 +080085 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Li5df83112013-08-12 18:15:35 +080086 if (!(rd_regl(port, ureg->sirfsoc_afc_ctrl) &
87 SIRFUART_AFC_CTS_STATUS))
Rong Wang161e7732011-11-17 23:17:04 +080088 goto cts_asserted;
89 else
90 goto cts_deasserted;
Qipan Li2eb56182013-08-15 06:52:15 +080091 } else {
92 if (!gpio_get_value(sirfport->cts_gpio))
93 goto cts_asserted;
94 else
95 goto cts_deasserted;
Rong Wang161e7732011-11-17 23:17:04 +080096 }
97cts_deasserted:
98 return TIOCM_CAR | TIOCM_DSR;
99cts_asserted:
100 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
101}
102
103static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
104{
105 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800106 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800107 unsigned int assert = mctrl & TIOCM_RTS;
108 unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
109 unsigned int current_val;
Qipan Li2eb56182013-08-15 06:52:15 +0800110
Qipan Li7f60f2f2015-05-14 06:45:25 +0000111 if (mctrl & TIOCM_LOOP) {
112 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
113 wr_regl(port, ureg->sirfsoc_line_ctrl,
114 rd_regl(port, ureg->sirfsoc_line_ctrl) |
115 SIRFUART_LOOP_BACK);
116 else
117 wr_regl(port, ureg->sirfsoc_mode1,
118 rd_regl(port, ureg->sirfsoc_mode1) |
119 SIRFSOC_USP_LOOP_BACK_CTRL);
120 } else {
121 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
122 wr_regl(port, ureg->sirfsoc_line_ctrl,
123 rd_regl(port, ureg->sirfsoc_line_ctrl) &
124 ~SIRFUART_LOOP_BACK);
125 else
126 wr_regl(port, ureg->sirfsoc_mode1,
127 rd_regl(port, ureg->sirfsoc_mode1) &
128 ~SIRFSOC_USP_LOOP_BACK_CTRL);
129 }
130
Qipan Li2eb56182013-08-15 06:52:15 +0800131 if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
132 return;
133 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Li5df83112013-08-12 18:15:35 +0800134 current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF;
Rong Wang161e7732011-11-17 23:17:04 +0800135 val |= current_val;
Qipan Li5df83112013-08-12 18:15:35 +0800136 wr_regl(port, ureg->sirfsoc_afc_ctrl, val);
Qipan Li2eb56182013-08-15 06:52:15 +0800137 } else {
138 if (!val)
139 gpio_set_value(sirfport->rts_gpio, 1);
140 else
141 gpio_set_value(sirfport->rts_gpio, 0);
Rong Wang161e7732011-11-17 23:17:04 +0800142 }
143}
144
145static void sirfsoc_uart_stop_tx(struct uart_port *port)
146{
Barry Song909102d2013-08-07 13:35:38 +0800147 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800148 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
149 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800150
Qipan Li9be16b32014-01-30 13:57:29 +0800151 if (sirfport->tx_dma_chan) {
Qipan Li8316d042013-08-19 11:47:53 +0800152 if (sirfport->tx_dma_state == TX_DMA_RUNNING) {
153 dmaengine_pause(sirfport->tx_dma_chan);
154 sirfport->tx_dma_state = TX_DMA_PAUSE;
155 } else {
Barry Song057badd2015-01-03 17:02:57 +0800156 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800157 wr_regl(port, ureg->sirfsoc_int_en_reg,
158 rd_regl(port, ureg->sirfsoc_int_en_reg) &
159 ~uint_en->sirfsoc_txfifo_empty_en);
160 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000161 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800162 uint_en->sirfsoc_txfifo_empty_en);
163 }
164 } else {
Qipan Lic1b7ac62015-05-14 06:45:21 +0000165 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
166 wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
167 ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN);
Barry Song057badd2015-01-03 17:02:57 +0800168 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800169 wr_regl(port, ureg->sirfsoc_int_en_reg,
170 rd_regl(port, ureg->sirfsoc_int_en_reg) &
171 ~uint_en->sirfsoc_txfifo_empty_en);
172 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000173 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800174 uint_en->sirfsoc_txfifo_empty_en);
175 }
176}
177
178static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
179{
180 struct uart_port *port = &sirfport->port;
181 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
182 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
183 struct circ_buf *xmit = &port->state->xmit;
184 unsigned long tran_size;
185 unsigned long tran_start;
186 unsigned long pio_tx_size;
187
188 tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
189 tran_start = (unsigned long)(xmit->buf + xmit->tail);
190 if (uart_circ_empty(xmit) || uart_tx_stopped(port) ||
191 !tran_size)
192 return;
193 if (sirfport->tx_dma_state == TX_DMA_PAUSE) {
194 dmaengine_resume(sirfport->tx_dma_chan);
195 return;
196 }
197 if (sirfport->tx_dma_state == TX_DMA_RUNNING)
198 return;
Barry Song057badd2015-01-03 17:02:57 +0800199 if (!sirfport->is_atlas7)
Qipan Li5df83112013-08-12 18:15:35 +0800200 wr_regl(port, ureg->sirfsoc_int_en_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800201 rd_regl(port, ureg->sirfsoc_int_en_reg)&
202 ~(uint_en->sirfsoc_txfifo_empty_en));
203 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000204 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li5df83112013-08-12 18:15:35 +0800205 uint_en->sirfsoc_txfifo_empty_en);
Qipan Li8316d042013-08-19 11:47:53 +0800206 /*
207 * DMA requires buffer address and buffer length are both aligned with
208 * 4 bytes, so we use PIO for
209 * 1. if address is not aligned with 4bytes, use PIO for the first 1~3
210 * bytes, and move to DMA for the left part aligned with 4bytes
211 * 2. if buffer length is not aligned with 4bytes, use DMA for aligned
212 * part first, move to PIO for the left 1~3 bytes
213 */
214 if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) {
215 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
216 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
217 rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)|
218 SIRFUART_IO_MODE);
219 if (BYTES_TO_ALIGN(tran_start)) {
220 pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport,
221 BYTES_TO_ALIGN(tran_start));
222 tran_size -= pio_tx_size;
223 }
224 if (tran_size < 4)
225 sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
Barry Song057badd2015-01-03 17:02:57 +0800226 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800227 wr_regl(port, ureg->sirfsoc_int_en_reg,
228 rd_regl(port, ureg->sirfsoc_int_en_reg)|
229 uint_en->sirfsoc_txfifo_empty_en);
230 else
231 wr_regl(port, ureg->sirfsoc_int_en_reg,
232 uint_en->sirfsoc_txfifo_empty_en);
233 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
234 } else {
235 /* tx transfer mode switch into dma mode */
236 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
237 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
238 rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)&
239 ~SIRFUART_IO_MODE);
240 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
241 tran_size &= ~(0x3);
Qipan Li5df83112013-08-12 18:15:35 +0800242
Qipan Li8316d042013-08-19 11:47:53 +0800243 sirfport->tx_dma_addr = dma_map_single(port->dev,
244 xmit->buf + xmit->tail,
245 tran_size, DMA_TO_DEVICE);
246 sirfport->tx_dma_desc = dmaengine_prep_slave_single(
247 sirfport->tx_dma_chan, sirfport->tx_dma_addr,
248 tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
249 if (!sirfport->tx_dma_desc) {
250 dev_err(port->dev, "DMA prep slave single fail\n");
251 return;
252 }
253 sirfport->tx_dma_desc->callback =
254 sirfsoc_uart_tx_dma_complete_callback;
255 sirfport->tx_dma_desc->callback_param = (void *)sirfport;
256 sirfport->transfer_size = tran_size;
257
258 dmaengine_submit(sirfport->tx_dma_desc);
259 dma_async_issue_pending(sirfport->tx_dma_chan);
260 sirfport->tx_dma_state = TX_DMA_RUNNING;
261 }
Rong Wang161e7732011-11-17 23:17:04 +0800262}
263
Jingoo Hanada1f442013-08-08 17:41:43 +0900264static void sirfsoc_uart_start_tx(struct uart_port *port)
Rong Wang161e7732011-11-17 23:17:04 +0800265{
266 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800267 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
268 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li9be16b32014-01-30 13:57:29 +0800269 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +0800270 sirfsoc_uart_tx_with_dma(sirfport);
271 else {
Qipan Lic1b7ac62015-05-14 06:45:21 +0000272 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
273 wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
274 ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN);
Qipan Li326707e2015-05-26 09:35:58 +0000275 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
Qipan Licb4595a2015-04-29 06:45:09 +0000276 sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize);
Qipan Li8316d042013-08-19 11:47:53 +0800277 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
Barry Song057badd2015-01-03 17:02:57 +0800278 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800279 wr_regl(port, ureg->sirfsoc_int_en_reg,
280 rd_regl(port, ureg->sirfsoc_int_en_reg)|
281 uint_en->sirfsoc_txfifo_empty_en);
282 else
283 wr_regl(port, ureg->sirfsoc_int_en_reg,
284 uint_en->sirfsoc_txfifo_empty_en);
285 }
Rong Wang161e7732011-11-17 23:17:04 +0800286}
287
288static void sirfsoc_uart_stop_rx(struct uart_port *port)
289{
Barry Song909102d2013-08-07 13:35:38 +0800290 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800291 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
292 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800293
Qipan Li5df83112013-08-12 18:15:35 +0800294 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
Qipan Li9be16b32014-01-30 13:57:29 +0800295 if (sirfport->rx_dma_chan) {
Barry Song057badd2015-01-03 17:02:57 +0800296 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800297 wr_regl(port, ureg->sirfsoc_int_en_reg,
298 rd_regl(port, ureg->sirfsoc_int_en_reg) &
Qipan Lic1b7ac62015-05-14 06:45:21 +0000299 ~(SIRFUART_RX_DMA_INT_EN(uint_en,
300 sirfport->uart_reg->uart_type) |
Qipan Li8316d042013-08-19 11:47:53 +0800301 uint_en->sirfsoc_rx_done_en));
302 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000303 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
304 SIRFUART_RX_DMA_INT_EN(uint_en,
305 sirfport->uart_reg->uart_type)|
306 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800307 dmaengine_terminate_all(sirfport->rx_dma_chan);
308 } else {
Barry Song057badd2015-01-03 17:02:57 +0800309 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800310 wr_regl(port, ureg->sirfsoc_int_en_reg,
311 rd_regl(port, ureg->sirfsoc_int_en_reg)&
Qipan Lic1b7ac62015-05-14 06:45:21 +0000312 ~(SIRFUART_RX_IO_INT_EN(uint_en,
313 sirfport->uart_reg->uart_type)));
Qipan Li8316d042013-08-19 11:47:53 +0800314 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000315 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
316 SIRFUART_RX_IO_INT_EN(uint_en,
317 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800318 }
Rong Wang161e7732011-11-17 23:17:04 +0800319}
320
321static void sirfsoc_uart_disable_ms(struct uart_port *port)
322{
323 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800324 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
325 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800326
Rong Wang161e7732011-11-17 23:17:04 +0800327 if (!sirfport->hw_flow_ctrl)
328 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800329 sirfport->ms_enabled = false;
330 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
331 wr_regl(port, ureg->sirfsoc_afc_ctrl,
332 rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
Barry Song057badd2015-01-03 17:02:57 +0800333 if (!sirfport->is_atlas7)
Qipan Li2eb56182013-08-15 06:52:15 +0800334 wr_regl(port, ureg->sirfsoc_int_en_reg,
335 rd_regl(port, ureg->sirfsoc_int_en_reg)&
336 ~uint_en->sirfsoc_cts_en);
337 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000338 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li2eb56182013-08-15 06:52:15 +0800339 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800340 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800341 disable_irq(gpio_to_irq(sirfport->cts_gpio));
342}
343
344static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
345{
346 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
347 struct uart_port *port = &sirfport->port;
Qipan Li07d410e2014-05-26 19:02:07 +0800348 spin_lock(&port->lock);
Qipan Li2eb56182013-08-15 06:52:15 +0800349 if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
350 uart_handle_cts_change(port,
351 !gpio_get_value(sirfport->cts_gpio));
Qipan Li07d410e2014-05-26 19:02:07 +0800352 spin_unlock(&port->lock);
Qipan Li2eb56182013-08-15 06:52:15 +0800353 return IRQ_HANDLED;
Rong Wang161e7732011-11-17 23:17:04 +0800354}
355
356static void sirfsoc_uart_enable_ms(struct uart_port *port)
357{
358 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800359 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
360 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800361
Rong Wang161e7732011-11-17 23:17:04 +0800362 if (!sirfport->hw_flow_ctrl)
363 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800364 sirfport->ms_enabled = true;
365 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
366 wr_regl(port, ureg->sirfsoc_afc_ctrl,
367 rd_regl(port, ureg->sirfsoc_afc_ctrl) |
Qipan Lieab192a2015-05-14 06:45:22 +0000368 SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN |
369 SIRFUART_AFC_CTRL_RX_THD);
Barry Song057badd2015-01-03 17:02:57 +0800370 if (!sirfport->is_atlas7)
Qipan Li2eb56182013-08-15 06:52:15 +0800371 wr_regl(port, ureg->sirfsoc_int_en_reg,
372 rd_regl(port, ureg->sirfsoc_int_en_reg)
373 | uint_en->sirfsoc_cts_en);
374 else
375 wr_regl(port, ureg->sirfsoc_int_en_reg,
376 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800377 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800378 enable_irq(gpio_to_irq(sirfport->cts_gpio));
Rong Wang161e7732011-11-17 23:17:04 +0800379}
380
381static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
382{
Qipan Li5df83112013-08-12 18:15:35 +0800383 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
384 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
385 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
386 unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
387 if (break_state)
388 ulcon |= SIRFUART_SET_BREAK;
389 else
390 ulcon &= ~SIRFUART_SET_BREAK;
391 wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
392 }
Rong Wang161e7732011-11-17 23:17:04 +0800393}
394
395static unsigned int
396sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
397{
Qipan Li5df83112013-08-12 18:15:35 +0800398 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
399 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
400 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800401 unsigned int ch, rx_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800402 struct tty_struct *tty;
403 tty = tty_port_tty_get(&port->state->port);
404 if (!tty)
405 return -ENODEV;
406 while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000407 ufifo_st->ff_empty(port))) {
Qipan Li5df83112013-08-12 18:15:35 +0800408 ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
409 SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800410 if (unlikely(uart_handle_sysrq_char(port, ch)))
411 continue;
412 uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
413 rx_count++;
414 if (rx_count >= max_rx_count)
415 break;
416 }
417
Qipan Li8316d042013-08-19 11:47:53 +0800418 sirfport->rx_io_count += rx_count;
Rong Wang161e7732011-11-17 23:17:04 +0800419 port->icount.rx += rx_count;
Viresh Kumar8b9ade92013-08-19 20:14:28 +0530420
Rong Wang161e7732011-11-17 23:17:04 +0800421 return rx_count;
422}
423
424static unsigned int
425sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
426{
427 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800428 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
429 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800430 struct circ_buf *xmit = &port->state->xmit;
431 unsigned int num_tx = 0;
432 while (!uart_circ_empty(xmit) &&
Qipan Li5df83112013-08-12 18:15:35 +0800433 !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000434 ufifo_st->ff_full(port)) &&
Rong Wang161e7732011-11-17 23:17:04 +0800435 count--) {
Qipan Li5df83112013-08-12 18:15:35 +0800436 wr_regl(port, ureg->sirfsoc_tx_fifo_data,
437 xmit->buf[xmit->tail]);
Rong Wang161e7732011-11-17 23:17:04 +0800438 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
439 port->icount.tx++;
440 num_tx++;
441 }
442 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
443 uart_write_wakeup(port);
444 return num_tx;
445}
446
Qipan Li8316d042013-08-19 11:47:53 +0800447static void sirfsoc_uart_tx_dma_complete_callback(void *param)
448{
449 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
450 struct uart_port *port = &sirfport->port;
451 struct circ_buf *xmit = &port->state->xmit;
452 unsigned long flags;
453
Qipan Li07d410e2014-05-26 19:02:07 +0800454 spin_lock_irqsave(&port->lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800455 xmit->tail = (xmit->tail + sirfport->transfer_size) &
456 (UART_XMIT_SIZE - 1);
457 port->icount.tx += sirfport->transfer_size;
458 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
459 uart_write_wakeup(port);
460 if (sirfport->tx_dma_addr)
461 dma_unmap_single(port->dev, sirfport->tx_dma_addr,
462 sirfport->transfer_size, DMA_TO_DEVICE);
Qipan Li8316d042013-08-19 11:47:53 +0800463 sirfport->tx_dma_state = TX_DMA_IDLE;
464 sirfsoc_uart_tx_with_dma(sirfport);
Qipan Li07d410e2014-05-26 19:02:07 +0800465 spin_unlock_irqrestore(&port->lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800466}
467
468static void sirfsoc_uart_insert_rx_buf_to_tty(
469 struct sirfsoc_uart_port *sirfport, int count)
470{
471 struct uart_port *port = &sirfport->port;
472 struct tty_port *tport = &port->state->port;
473 int inserted;
474
475 inserted = tty_insert_flip_string(tport,
476 sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
477 port->icount.rx += inserted;
Qipan Li8316d042013-08-19 11:47:53 +0800478}
479
480static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
481{
482 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
483
484 sirfport->rx_dma_items[index].xmit.tail =
485 sirfport->rx_dma_items[index].xmit.head = 0;
486 sirfport->rx_dma_items[index].desc =
487 dmaengine_prep_slave_single(sirfport->rx_dma_chan,
488 sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
489 DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000490 if (IS_ERR_OR_NULL(sirfport->rx_dma_items[index].desc)) {
Qipan Li8316d042013-08-19 11:47:53 +0800491 dev_err(port->dev, "DMA slave single fail\n");
492 return;
493 }
494 sirfport->rx_dma_items[index].desc->callback =
495 sirfsoc_uart_rx_dma_complete_callback;
496 sirfport->rx_dma_items[index].desc->callback_param = sirfport;
497 sirfport->rx_dma_items[index].cookie =
498 dmaengine_submit(sirfport->rx_dma_items[index].desc);
499 dma_async_issue_pending(sirfport->rx_dma_chan);
500}
501
502static void sirfsoc_rx_tmo_process_tl(unsigned long param)
503{
504 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
505 struct uart_port *port = &sirfport->port;
506 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
507 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
508 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
509 unsigned int count;
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800510 struct dma_tx_state tx_state;
Qipan Lic1b7ac62015-05-14 06:45:21 +0000511 unsigned long flags;
Qipan Li36c09912015-05-14 06:45:23 +0000512 int i = 0;
Qipan Li8316d042013-08-19 11:47:53 +0800513
Qipan Li07d410e2014-05-26 19:02:07 +0800514 spin_lock_irqsave(&port->lock, flags);
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800515 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000516 sirfport->rx_dma_items[sirfport->rx_completed].cookie,
517 &tx_state)) {
Qipan Li8316d042013-08-19 11:47:53 +0800518 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
519 SIRFSOC_RX_DMA_BUF_SIZE);
Qipan Li59f8a622013-09-21 09:02:10 +0800520 sirfport->rx_completed++;
Qipan Li8316d042013-08-19 11:47:53 +0800521 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li36c09912015-05-14 06:45:23 +0000522 i++;
523 if (i > SIRFSOC_RX_LOOP_BUF_CNT)
524 break;
Qipan Li8316d042013-08-19 11:47:53 +0800525 }
526 count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
527 sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
528 SIRFSOC_RX_DMA_BUF_SIZE);
529 if (count > 0)
530 sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
531 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
532 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
533 SIRFUART_IO_MODE);
Qipan Lifb78b812014-01-27 14:23:39 +0800534 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
Qipan Li8316d042013-08-19 11:47:53 +0800535 if (sirfport->rx_io_count == 4) {
Qipan Li8316d042013-08-19 11:47:53 +0800536 sirfport->rx_io_count = 0;
537 wr_regl(port, ureg->sirfsoc_int_st_reg,
538 uint_st->sirfsoc_rx_done);
Barry Song057badd2015-01-03 17:02:57 +0800539 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800540 wr_regl(port, ureg->sirfsoc_int_en_reg,
541 rd_regl(port, ureg->sirfsoc_int_en_reg) &
542 ~(uint_en->sirfsoc_rx_done_en));
543 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000544 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800545 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800546 sirfsoc_uart_start_next_rx_dma(port);
547 } else {
Qipan Li8316d042013-08-19 11:47:53 +0800548 wr_regl(port, ureg->sirfsoc_int_st_reg,
549 uint_st->sirfsoc_rx_done);
Barry Song057badd2015-01-03 17:02:57 +0800550 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800551 wr_regl(port, ureg->sirfsoc_int_en_reg,
552 rd_regl(port, ureg->sirfsoc_int_en_reg) |
553 (uint_en->sirfsoc_rx_done_en));
554 else
555 wr_regl(port, ureg->sirfsoc_int_en_reg,
556 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800557 }
Qipan Li07d410e2014-05-26 19:02:07 +0800558 spin_unlock_irqrestore(&port->lock, flags);
559 tty_flip_buffer_push(&port->state->port);
Qipan Li8316d042013-08-19 11:47:53 +0800560}
561
562static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
563{
564 struct uart_port *port = &sirfport->port;
565 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
566 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
567 struct dma_tx_state tx_state;
Qipan Li8316d042013-08-19 11:47:53 +0800568 dmaengine_tx_status(sirfport->rx_dma_chan,
569 sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
570 dmaengine_terminate_all(sirfport->rx_dma_chan);
571 sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
572 SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
Barry Song057badd2015-01-03 17:02:57 +0800573 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800574 wr_regl(port, ureg->sirfsoc_int_en_reg,
575 rd_regl(port, ureg->sirfsoc_int_en_reg) &
576 ~(uint_en->sirfsoc_rx_timeout_en));
577 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000578 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800579 uint_en->sirfsoc_rx_timeout_en);
Qipan Li8316d042013-08-19 11:47:53 +0800580 tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
581}
582
583static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
584{
585 struct uart_port *port = &sirfport->port;
586 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
587 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
588 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
589
590 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
591 if (sirfport->rx_io_count == 4) {
592 sirfport->rx_io_count = 0;
Barry Song057badd2015-01-03 17:02:57 +0800593 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800594 wr_regl(port, ureg->sirfsoc_int_en_reg,
595 rd_regl(port, ureg->sirfsoc_int_en_reg) &
596 ~(uint_en->sirfsoc_rx_done_en));
597 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000598 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800599 uint_en->sirfsoc_rx_done_en);
600 wr_regl(port, ureg->sirfsoc_int_st_reg,
601 uint_st->sirfsoc_rx_timeout);
602 sirfsoc_uart_start_next_rx_dma(port);
603 }
604}
605
Rong Wang161e7732011-11-17 23:17:04 +0800606static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
607{
608 unsigned long intr_status;
609 unsigned long cts_status;
610 unsigned long flag = TTY_NORMAL;
611 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
612 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800613 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
614 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
615 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
616 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800617 struct uart_state *state = port->state;
618 struct circ_buf *xmit = &port->state->xmit;
Barry Song5425e032012-12-25 17:32:04 +0800619 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800620 intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
621 wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
Qipan Li8316d042013-08-19 11:47:53 +0800622 intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000623 if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
624 sirfport->uart_reg->uart_type)))) {
Qipan Li5df83112013-08-12 18:15:35 +0800625 if (intr_status & uint_st->sirfsoc_rxd_brk) {
626 port->icount.brk++;
Rong Wang161e7732011-11-17 23:17:04 +0800627 if (uart_handle_break(port))
628 goto recv_char;
Rong Wang161e7732011-11-17 23:17:04 +0800629 }
Qipan Lid9e8e972015-05-14 06:45:24 +0000630 if (intr_status & uint_st->sirfsoc_rx_oflow) {
Rong Wang161e7732011-11-17 23:17:04 +0800631 port->icount.overrun++;
Qipan Lid9e8e972015-05-14 06:45:24 +0000632 flag = TTY_OVERRUN;
633 }
Qipan Li5df83112013-08-12 18:15:35 +0800634 if (intr_status & uint_st->sirfsoc_frm_err) {
Rong Wang161e7732011-11-17 23:17:04 +0800635 port->icount.frame++;
636 flag = TTY_FRAME;
637 }
Qipan Lid9e8e972015-05-14 06:45:24 +0000638 if (intr_status & uint_st->sirfsoc_parity_err) {
639 port->icount.parity++;
Rong Wang161e7732011-11-17 23:17:04 +0800640 flag = TTY_PARITY;
Qipan Lid9e8e972015-05-14 06:45:24 +0000641 }
Qipan Li5df83112013-08-12 18:15:35 +0800642 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
643 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
644 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800645 intr_status &= port->read_status_mask;
646 uart_insert_char(port, intr_status,
Qipan Li5df83112013-08-12 18:15:35 +0800647 uint_en->sirfsoc_rx_oflow_en, 0, flag);
Rong Wang161e7732011-11-17 23:17:04 +0800648 }
649recv_char:
Qipan Li5df83112013-08-12 18:15:35 +0800650 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
Qipan Li8316d042013-08-19 11:47:53 +0800651 (intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
652 !sirfport->tx_dma_state) {
Qipan Li5df83112013-08-12 18:15:35 +0800653 cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
654 SIRFUART_AFC_CTS_STATUS;
655 if (cts_status != 0)
656 cts_status = 0;
657 else
658 cts_status = 1;
659 uart_handle_cts_change(port, cts_status);
660 wake_up_interruptible(&state->port.delta_msr_wait);
Rong Wang161e7732011-11-17 23:17:04 +0800661 }
Qipan Li9be16b32014-01-30 13:57:29 +0800662 if (sirfport->rx_dma_chan) {
Qipan Li8316d042013-08-19 11:47:53 +0800663 if (intr_status & uint_st->sirfsoc_rx_timeout)
664 sirfsoc_uart_handle_rx_tmo(sirfport);
665 if (intr_status & uint_st->sirfsoc_rx_done)
666 sirfsoc_uart_handle_rx_done(sirfport);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000667 } else if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st)) {
668 /*
669 * chip will trigger continuous RX_TIMEOUT interrupt
670 * in RXFIFO empty and not trigger if RXFIFO recevice
671 * data in limit time, original method use RX_TIMEOUT
672 * will trigger lots of useless interrupt in RXFIFO
673 * empty.RXFIFO received one byte will trigger RX_DONE
674 * interrupt.use RX_DONE to wait for data received
675 * into RXFIFO, use RX_THD/RX_FULL for lots data receive
676 * and use RX_TIMEOUT for the last left data.
677 */
678 if (intr_status & uint_st->sirfsoc_rx_done) {
679 if (!sirfport->is_atlas7) {
680 wr_regl(port, ureg->sirfsoc_int_en_reg,
681 rd_regl(port, ureg->sirfsoc_int_en_reg)
682 & ~(uint_en->sirfsoc_rx_done_en));
683 wr_regl(port, ureg->sirfsoc_int_en_reg,
684 rd_regl(port, ureg->sirfsoc_int_en_reg)
685 | (uint_en->sirfsoc_rx_timeout_en));
686 } else {
687 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
688 uint_en->sirfsoc_rx_done_en);
689 wr_regl(port, ureg->sirfsoc_int_en_reg,
690 uint_en->sirfsoc_rx_timeout_en);
691 }
692 } else {
693 if (intr_status & uint_st->sirfsoc_rx_timeout) {
694 if (!sirfport->is_atlas7) {
695 wr_regl(port, ureg->sirfsoc_int_en_reg,
696 rd_regl(port, ureg->sirfsoc_int_en_reg)
697 & ~(uint_en->sirfsoc_rx_timeout_en));
698 wr_regl(port, ureg->sirfsoc_int_en_reg,
699 rd_regl(port, ureg->sirfsoc_int_en_reg)
700 | (uint_en->sirfsoc_rx_done_en));
701 } else {
702 wr_regl(port,
703 ureg->sirfsoc_int_en_clr_reg,
704 uint_en->sirfsoc_rx_timeout_en);
705 wr_regl(port, ureg->sirfsoc_int_en_reg,
706 uint_en->sirfsoc_rx_done_en);
707 }
708 }
Qipan Licb4595a2015-04-29 06:45:09 +0000709 sirfsoc_uart_pio_rx_chars(port, port->fifosize);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000710 }
Qipan Li8316d042013-08-19 11:47:53 +0800711 }
Qipan Li07d410e2014-05-26 19:02:07 +0800712 spin_unlock(&port->lock);
713 tty_flip_buffer_push(&state->port);
714 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800715 if (intr_status & uint_st->sirfsoc_txfifo_empty) {
Qipan Li9be16b32014-01-30 13:57:29 +0800716 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +0800717 sirfsoc_uart_tx_with_dma(sirfport);
718 else {
719 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
720 spin_unlock(&port->lock);
721 return IRQ_HANDLED;
722 } else {
723 sirfsoc_uart_pio_tx_chars(sirfport,
Qipan Licb4595a2015-04-29 06:45:09 +0000724 port->fifosize);
Qipan Li8316d042013-08-19 11:47:53 +0800725 if ((uart_circ_empty(xmit)) &&
Qipan Li5df83112013-08-12 18:15:35 +0800726 (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000727 ufifo_st->ff_empty(port)))
Qipan Li8316d042013-08-19 11:47:53 +0800728 sirfsoc_uart_stop_tx(port);
729 }
Rong Wang161e7732011-11-17 23:17:04 +0800730 }
731 }
Barry Song5425e032012-12-25 17:32:04 +0800732 spin_unlock(&port->lock);
Qipan Li07d410e2014-05-26 19:02:07 +0800733
Rong Wang161e7732011-11-17 23:17:04 +0800734 return IRQ_HANDLED;
735}
736
Qipan Li8316d042013-08-19 11:47:53 +0800737static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
738{
739 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
740 struct uart_port *port = &sirfport->port;
Qipan Li59f8a622013-09-21 09:02:10 +0800741 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
742 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800743 struct dma_tx_state tx_state;
Qipan Lic1b7ac62015-05-14 06:45:21 +0000744 unsigned long flags;
Qipan Li36c09912015-05-14 06:45:23 +0000745 int i = 0;
746
Daniel Thompson58eb97c2014-05-29 11:13:43 +0100747 spin_lock_irqsave(&port->lock, flags);
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800748 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000749 sirfport->rx_dma_items[sirfport->rx_completed].cookie,
750 &tx_state)) {
Qipan Li8316d042013-08-19 11:47:53 +0800751 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
752 SIRFSOC_RX_DMA_BUF_SIZE);
Qipan Li59f8a622013-09-21 09:02:10 +0800753 if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
754 uint_en->sirfsoc_rx_timeout_en)
755 sirfsoc_rx_submit_one_dma_desc(port,
756 sirfport->rx_completed++);
757 else
758 sirfport->rx_completed++;
Qipan Li8316d042013-08-19 11:47:53 +0800759 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li36c09912015-05-14 06:45:23 +0000760 i++;
761 if (i > SIRFSOC_RX_LOOP_BUF_CNT)
762 break;
Qipan Li8316d042013-08-19 11:47:53 +0800763 }
Qipan Li07d410e2014-05-26 19:02:07 +0800764 spin_unlock_irqrestore(&port->lock, flags);
765 tty_flip_buffer_push(&port->state->port);
Qipan Li8316d042013-08-19 11:47:53 +0800766}
767
768static void sirfsoc_uart_rx_dma_complete_callback(void *param)
769{
770 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
Qipan Li07d410e2014-05-26 19:02:07 +0800771 unsigned long flags;
772
773 spin_lock_irqsave(&sirfport->port.lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800774 sirfport->rx_issued++;
775 sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li8316d042013-08-19 11:47:53 +0800776 tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
Qipan Li07d410e2014-05-26 19:02:07 +0800777 spin_unlock_irqrestore(&sirfport->port.lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800778}
779
780/* submit rx dma task into dmaengine */
781static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
782{
783 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
784 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
785 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800786 int i;
Qipan Li8316d042013-08-19 11:47:53 +0800787 sirfport->rx_io_count = 0;
788 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
789 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
790 ~SIRFUART_IO_MODE);
Qipan Li8316d042013-08-19 11:47:53 +0800791 for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
792 sirfsoc_rx_submit_one_dma_desc(port, i);
793 sirfport->rx_completed = sirfport->rx_issued = 0;
Barry Song057badd2015-01-03 17:02:57 +0800794 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800795 wr_regl(port, ureg->sirfsoc_int_en_reg,
796 rd_regl(port, ureg->sirfsoc_int_en_reg) |
Qipan Lic1b7ac62015-05-14 06:45:21 +0000797 SIRFUART_RX_DMA_INT_EN(uint_en,
798 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800799 else
800 wr_regl(port, ureg->sirfsoc_int_en_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000801 SIRFUART_RX_DMA_INT_EN(uint_en,
802 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800803}
804
Rong Wang161e7732011-11-17 23:17:04 +0800805static void sirfsoc_uart_start_rx(struct uart_port *port)
806{
Barry Song909102d2013-08-07 13:35:38 +0800807 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800808 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
809 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800810
811 sirfport->rx_io_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800812 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
813 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
814 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Qipan Li9be16b32014-01-30 13:57:29 +0800815 if (sirfport->rx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +0800816 sirfsoc_uart_start_next_rx_dma(port);
817 else {
Barry Song057badd2015-01-03 17:02:57 +0800818 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800819 wr_regl(port, ureg->sirfsoc_int_en_reg,
820 rd_regl(port, ureg->sirfsoc_int_en_reg) |
Qipan Lic1b7ac62015-05-14 06:45:21 +0000821 SIRFUART_RX_IO_INT_EN(uint_en,
822 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800823 else
824 wr_regl(port, ureg->sirfsoc_int_en_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000825 SIRFUART_RX_IO_INT_EN(uint_en,
826 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800827 }
Rong Wang161e7732011-11-17 23:17:04 +0800828}
829
830static unsigned int
Qipan Li5df83112013-08-12 18:15:35 +0800831sirfsoc_usp_calc_sample_div(unsigned long set_rate,
832 unsigned long ioclk_rate, unsigned long *sample_reg)
833{
834 unsigned long min_delta = ~0UL;
835 unsigned short sample_div;
836 unsigned long ioclk_div = 0;
837 unsigned long temp_delta;
838
Qipan Licb4595a2015-04-29 06:45:09 +0000839 for (sample_div = SIRF_USP_MIN_SAMPLE_DIV;
Qipan Li5df83112013-08-12 18:15:35 +0800840 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
841 temp_delta = ioclk_rate -
842 (ioclk_rate + (set_rate * sample_div) / 2)
843 / (set_rate * sample_div) * set_rate * sample_div;
844
845 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
846 if (temp_delta < min_delta) {
847 ioclk_div = (2 * ioclk_rate /
848 (set_rate * sample_div) + 1) / 2 - 1;
849 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
850 continue;
851 min_delta = temp_delta;
852 *sample_reg = sample_div;
853 if (!temp_delta)
854 break;
855 }
856 }
857 return ioclk_div;
858}
859
860static unsigned int
861sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
862 unsigned long ioclk_rate, unsigned long *set_baud)
Rong Wang161e7732011-11-17 23:17:04 +0800863{
864 unsigned long min_delta = ~0UL;
865 unsigned short sample_div;
866 unsigned int regv = 0;
867 unsigned long ioclk_div;
868 unsigned long baud_tmp;
869 int temp_delta;
870
871 for (sample_div = SIRF_MIN_SAMPLE_DIV;
872 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
873 ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
874 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
875 continue;
876 baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
877 temp_delta = baud_tmp - baud_rate;
878 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
879 if (temp_delta < min_delta) {
880 regv = regv & (~SIRF_IOCLK_DIV_MASK);
881 regv = regv | ioclk_div;
882 regv = regv & (~SIRF_SAMPLE_DIV_MASK);
883 regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
884 min_delta = temp_delta;
Qipan Li5df83112013-08-12 18:15:35 +0800885 *set_baud = baud_tmp;
Rong Wang161e7732011-11-17 23:17:04 +0800886 }
887 }
888 return regv;
889}
890
891static void sirfsoc_uart_set_termios(struct uart_port *port,
892 struct ktermios *termios,
893 struct ktermios *old)
894{
895 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800896 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
897 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800898 unsigned long config_reg = 0;
899 unsigned long baud_rate;
Qipan Li5df83112013-08-12 18:15:35 +0800900 unsigned long set_baud;
Rong Wang161e7732011-11-17 23:17:04 +0800901 unsigned long flags;
902 unsigned long ic;
903 unsigned int clk_div_reg = 0;
Qipan Li8316d042013-08-19 11:47:53 +0800904 unsigned long txfifo_op_reg, ioclk_rate;
Rong Wang161e7732011-11-17 23:17:04 +0800905 unsigned long rx_time_out;
906 int threshold_div;
Qipan Li5df83112013-08-12 18:15:35 +0800907 u32 data_bit_len, stop_bit_len, len_val;
908 unsigned long sample_div_reg = 0xf;
909 ioclk_rate = port->uartclk;
Rong Wang161e7732011-11-17 23:17:04 +0800910
Rong Wang161e7732011-11-17 23:17:04 +0800911 switch (termios->c_cflag & CSIZE) {
912 default:
913 case CS8:
Qipan Li5df83112013-08-12 18:15:35 +0800914 data_bit_len = 8;
Rong Wang161e7732011-11-17 23:17:04 +0800915 config_reg |= SIRFUART_DATA_BIT_LEN_8;
916 break;
917 case CS7:
Qipan Li5df83112013-08-12 18:15:35 +0800918 data_bit_len = 7;
Rong Wang161e7732011-11-17 23:17:04 +0800919 config_reg |= SIRFUART_DATA_BIT_LEN_7;
920 break;
921 case CS6:
Qipan Li5df83112013-08-12 18:15:35 +0800922 data_bit_len = 6;
Rong Wang161e7732011-11-17 23:17:04 +0800923 config_reg |= SIRFUART_DATA_BIT_LEN_6;
924 break;
925 case CS5:
Qipan Li5df83112013-08-12 18:15:35 +0800926 data_bit_len = 5;
Rong Wang161e7732011-11-17 23:17:04 +0800927 config_reg |= SIRFUART_DATA_BIT_LEN_5;
928 break;
929 }
Qipan Li5df83112013-08-12 18:15:35 +0800930 if (termios->c_cflag & CSTOPB) {
Rong Wang161e7732011-11-17 23:17:04 +0800931 config_reg |= SIRFUART_STOP_BIT_LEN_2;
Qipan Li5df83112013-08-12 18:15:35 +0800932 stop_bit_len = 2;
933 } else
934 stop_bit_len = 1;
935
Rong Wang161e7732011-11-17 23:17:04 +0800936 spin_lock_irqsave(&port->lock, flags);
Qipan Li5df83112013-08-12 18:15:35 +0800937 port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
Rong Wang161e7732011-11-17 23:17:04 +0800938 port->ignore_status_mask = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800939 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
940 if (termios->c_iflag & INPCK)
941 port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
942 uint_en->sirfsoc_parity_err_en;
Qipan Li2eb56182013-08-15 06:52:15 +0800943 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800944 if (termios->c_iflag & INPCK)
945 port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
946 }
Peter Hurleyef8b9dd2014-06-16 08:10:41 -0400947 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
Qipan Li5df83112013-08-12 18:15:35 +0800948 port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
949 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
950 if (termios->c_iflag & IGNPAR)
951 port->ignore_status_mask |=
952 uint_en->sirfsoc_frm_err_en |
953 uint_en->sirfsoc_parity_err_en;
954 if (termios->c_cflag & PARENB) {
955 if (termios->c_cflag & CMSPAR) {
956 if (termios->c_cflag & PARODD)
957 config_reg |= SIRFUART_STICK_BIT_MARK;
958 else
959 config_reg |= SIRFUART_STICK_BIT_SPACE;
Qipan Li5df83112013-08-12 18:15:35 +0800960 } else {
Qipan Lid9e8e972015-05-14 06:45:24 +0000961 if (termios->c_cflag & PARODD)
962 config_reg |= SIRFUART_STICK_BIT_ODD;
963 else
964 config_reg |= SIRFUART_STICK_BIT_EVEN;
Qipan Li5df83112013-08-12 18:15:35 +0800965 }
Rong Wang161e7732011-11-17 23:17:04 +0800966 }
Qipan Li2eb56182013-08-15 06:52:15 +0800967 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800968 if (termios->c_iflag & IGNPAR)
969 port->ignore_status_mask |=
970 uint_en->sirfsoc_frm_err_en;
971 if (termios->c_cflag & PARENB)
972 dev_warn(port->dev,
973 "USP-UART not support parity err\n");
974 }
975 if (termios->c_iflag & IGNBRK) {
976 port->ignore_status_mask |=
977 uint_en->sirfsoc_rxd_brk_en;
978 if (termios->c_iflag & IGNPAR)
979 port->ignore_status_mask |=
980 uint_en->sirfsoc_rx_oflow_en;
981 }
982 if ((termios->c_cflag & CREAD) == 0)
983 port->ignore_status_mask |= SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800984 /* Hardware Flow Control Settings */
985 if (UART_ENABLE_MS(port, termios->c_cflag)) {
986 if (!sirfport->ms_enabled)
987 sirfsoc_uart_enable_ms(port);
988 } else {
989 if (sirfport->ms_enabled)
990 sirfsoc_uart_disable_ms(port);
991 }
Qipan Li5df83112013-08-12 18:15:35 +0800992 baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
993 if (ioclk_rate == 150000000) {
Barry Songac4ce712013-01-16 14:49:27 +0800994 for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
995 if (baud_rate == baudrate_to_regv[ic].baud_rate)
996 clk_div_reg = baudrate_to_regv[ic].reg_val;
997 }
Qipan Li5df83112013-08-12 18:15:35 +0800998 set_baud = baud_rate;
999 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
1000 if (unlikely(clk_div_reg == 0))
1001 clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
1002 ioclk_rate, &set_baud);
1003 wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
Qipan Li2eb56182013-08-15 06:52:15 +08001004 } else {
Qipan Li5df83112013-08-12 18:15:35 +08001005 clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
1006 ioclk_rate, &sample_div_reg);
1007 sample_div_reg--;
1008 set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
1009 (sample_div_reg + 1));
1010 /* setting usp mode 2 */
Qipan Li459f15c2013-08-25 20:18:40 +08001011 len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) |
1012 (1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET));
1013 len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK)
1014 << SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET);
1015 wr_regl(port, ureg->sirfsoc_mode2, len_val);
Qipan Li5df83112013-08-12 18:15:35 +08001016 }
Rong Wang161e7732011-11-17 23:17:04 +08001017 if (tty_termios_baud_rate(termios))
Qipan Li5df83112013-08-12 18:15:35 +08001018 tty_termios_encode_baud_rate(termios, set_baud, set_baud);
1019 /* set receive timeout && data bits len */
1020 rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
1021 rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
Qipan Li8316d042013-08-19 11:47:53 +08001022 txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
Qipan Li459f15c2013-08-25 20:18:40 +08001023 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP);
Qipan Li5df83112013-08-12 18:15:35 +08001024 wr_regl(port, ureg->sirfsoc_tx_fifo_op,
Qipan Li8316d042013-08-19 11:47:53 +08001025 (txfifo_op_reg & ~SIRFUART_FIFO_START));
Qipan Li5df83112013-08-12 18:15:35 +08001026 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Lic1b7ac62015-05-14 06:45:21 +00001027 config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out);
Qipan Li5df83112013-08-12 18:15:35 +08001028 wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
Qipan Li2eb56182013-08-15 06:52:15 +08001029 } else {
Qipan Li5df83112013-08-12 18:15:35 +08001030 /*tx frame ctrl*/
Qipan Li459f15c2013-08-25 20:18:40 +08001031 len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET;
1032 len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
1033 SIRFSOC_USP_TX_FRAME_LEN_OFFSET;
1034 len_val |= ((data_bit_len - 1) <<
1035 SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET);
1036 len_val |= (((clk_div_reg & 0xc00) >> 10) <<
1037 SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001038 wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
1039 /*rx frame ctrl*/
Qipan Li459f15c2013-08-25 20:18:40 +08001040 len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET;
1041 len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
1042 SIRFSOC_USP_RX_FRAME_LEN_OFFSET;
1043 len_val |= (data_bit_len - 1) <<
1044 SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET;
1045 len_val |= (((clk_div_reg & 0xf000) >> 12) <<
1046 SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001047 wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
1048 /*async param*/
1049 wr_regl(port, ureg->sirfsoc_async_param_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +00001050 (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) |
Qipan Li459f15c2013-08-25 20:18:40 +08001051 (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
1052 SIRFSOC_USP_ASYNC_DIV2_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001053 }
Qipan Li9be16b32014-01-30 13:57:29 +08001054 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001055 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
1056 else
1057 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
Qipan Li9be16b32014-01-30 13:57:29 +08001058 if (sirfport->rx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001059 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
1060 else
1061 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
Rong Wang161e7732011-11-17 23:17:04 +08001062 /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
Qipan Li5df83112013-08-12 18:15:35 +08001063 if (set_baud < 1000000)
Rong Wang161e7732011-11-17 23:17:04 +08001064 threshold_div = 1;
1065 else
1066 threshold_div = 2;
Qipan Li8316d042013-08-19 11:47:53 +08001067 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl,
1068 SIRFUART_FIFO_THD(port) / threshold_div);
1069 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl,
1070 SIRFUART_FIFO_THD(port) / threshold_div);
1071 txfifo_op_reg |= SIRFUART_FIFO_START;
1072 wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg);
Qipan Li5df83112013-08-12 18:15:35 +08001073 uart_update_timeout(port, termios->c_cflag, set_baud);
Rong Wang161e7732011-11-17 23:17:04 +08001074 sirfsoc_uart_start_rx(port);
Qipan Li5df83112013-08-12 18:15:35 +08001075 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
Rong Wang161e7732011-11-17 23:17:04 +08001076 spin_unlock_irqrestore(&port->lock, flags);
1077}
1078
Qipan Li388faf92014-01-03 15:44:07 +08001079static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
1080 unsigned int oldstate)
1081{
1082 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li4b8038d2015-04-20 08:10:22 +00001083 if (!state)
Qipan Li388faf92014-01-03 15:44:07 +08001084 clk_prepare_enable(sirfport->clk);
Qipan Li4b8038d2015-04-20 08:10:22 +00001085 else
Qipan Li388faf92014-01-03 15:44:07 +08001086 clk_disable_unprepare(sirfport->clk);
1087}
1088
Rong Wang161e7732011-11-17 23:17:04 +08001089static int sirfsoc_uart_startup(struct uart_port *port)
1090{
1091 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li15cdcb12013-08-19 11:47:52 +08001092 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +08001093 unsigned int index = port->line;
1094 int ret;
1095 set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
1096 ret = request_irq(port->irq,
1097 sirfsoc_uart_isr,
1098 0,
1099 SIRFUART_PORT_NAME,
1100 sirfport);
1101 if (ret != 0) {
1102 dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
1103 index, port->irq);
1104 goto irq_err;
1105 }
Qipan Li15cdcb12013-08-19 11:47:52 +08001106 /* initial hardware settings */
1107 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
1108 rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
1109 SIRFUART_IO_MODE);
1110 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
1111 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
1112 SIRFUART_IO_MODE);
1113 wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
1114 wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
1115 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
1116 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
1117 wr_regl(port, ureg->sirfsoc_mode1,
1118 SIRFSOC_USP_ENDIAN_CTRL_LSBF |
1119 SIRFSOC_USP_EN);
1120 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
Qipan Li15cdcb12013-08-19 11:47:52 +08001121 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
1122 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
1123 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
1124 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
Qipan Li9be16b32014-01-30 13:57:29 +08001125 if (sirfport->rx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001126 wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
Qipan Li9be16b32014-01-30 13:57:29 +08001127 SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
1128 SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
1129 SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
1130 if (sirfport->tx_dma_chan) {
Qipan Li8316d042013-08-19 11:47:53 +08001131 sirfport->tx_dma_state = TX_DMA_IDLE;
1132 wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
1133 SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
1134 SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) |
1135 SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4));
1136 }
Qipan Li2eb56182013-08-15 06:52:15 +08001137 sirfport->ms_enabled = false;
1138 if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
1139 sirfport->hw_flow_ctrl) {
1140 set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
1141 IRQF_VALID | IRQF_NOAUTOEN);
1142 ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
1143 sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
1144 IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
1145 if (ret != 0) {
1146 dev_err(port->dev, "UART-USP:request gpio irq fail\n");
1147 goto init_rx_err;
1148 }
1149 }
1150
Rong Wang161e7732011-11-17 23:17:04 +08001151 enable_irq(port->irq);
Qipan Li2eb56182013-08-15 06:52:15 +08001152
Qipan Li15cdcb12013-08-19 11:47:52 +08001153 return 0;
Qipan Li2eb56182013-08-15 06:52:15 +08001154init_rx_err:
1155 free_irq(port->irq, sirfport);
Rong Wang161e7732011-11-17 23:17:04 +08001156irq_err:
1157 return ret;
1158}
1159
1160static void sirfsoc_uart_shutdown(struct uart_port *port)
1161{
1162 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +08001163 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Barry Song057badd2015-01-03 17:02:57 +08001164 if (!sirfport->is_atlas7)
Qipan Li5df83112013-08-12 18:15:35 +08001165 wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
Barry Song909102d2013-08-07 13:35:38 +08001166 else
Qipan Lic1b7ac62015-05-14 06:45:21 +00001167 wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL);
Barry Song909102d2013-08-07 13:35:38 +08001168
Rong Wang161e7732011-11-17 23:17:04 +08001169 free_irq(port->irq, sirfport);
Qipan Li2eb56182013-08-15 06:52:15 +08001170 if (sirfport->ms_enabled)
Rong Wang161e7732011-11-17 23:17:04 +08001171 sirfsoc_uart_disable_ms(port);
Qipan Li2eb56182013-08-15 06:52:15 +08001172 if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
1173 sirfport->hw_flow_ctrl) {
1174 gpio_set_value(sirfport->rts_gpio, 1);
1175 free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
Rong Wang161e7732011-11-17 23:17:04 +08001176 }
Qipan Li9be16b32014-01-30 13:57:29 +08001177 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001178 sirfport->tx_dma_state = TX_DMA_IDLE;
Rong Wang161e7732011-11-17 23:17:04 +08001179}
1180
1181static const char *sirfsoc_uart_type(struct uart_port *port)
1182{
1183 return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
1184}
1185
1186static int sirfsoc_uart_request_port(struct uart_port *port)
1187{
Qipan Li5df83112013-08-12 18:15:35 +08001188 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
1189 struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param;
Rong Wang161e7732011-11-17 23:17:04 +08001190 void *ret;
1191 ret = request_mem_region(port->mapbase,
Qipan Li5df83112013-08-12 18:15:35 +08001192 SIRFUART_MAP_SIZE, uart_param->port_name);
Rong Wang161e7732011-11-17 23:17:04 +08001193 return ret ? 0 : -EBUSY;
1194}
1195
1196static void sirfsoc_uart_release_port(struct uart_port *port)
1197{
1198 release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
1199}
1200
1201static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
1202{
1203 if (flags & UART_CONFIG_TYPE) {
1204 port->type = SIRFSOC_PORT_TYPE;
1205 sirfsoc_uart_request_port(port);
1206 }
1207}
1208
1209static struct uart_ops sirfsoc_uart_ops = {
1210 .tx_empty = sirfsoc_uart_tx_empty,
1211 .get_mctrl = sirfsoc_uart_get_mctrl,
1212 .set_mctrl = sirfsoc_uart_set_mctrl,
1213 .stop_tx = sirfsoc_uart_stop_tx,
1214 .start_tx = sirfsoc_uart_start_tx,
1215 .stop_rx = sirfsoc_uart_stop_rx,
1216 .enable_ms = sirfsoc_uart_enable_ms,
1217 .break_ctl = sirfsoc_uart_break_ctl,
1218 .startup = sirfsoc_uart_startup,
1219 .shutdown = sirfsoc_uart_shutdown,
1220 .set_termios = sirfsoc_uart_set_termios,
Qipan Li388faf92014-01-03 15:44:07 +08001221 .pm = sirfsoc_uart_pm,
Rong Wang161e7732011-11-17 23:17:04 +08001222 .type = sirfsoc_uart_type,
1223 .release_port = sirfsoc_uart_release_port,
1224 .request_port = sirfsoc_uart_request_port,
1225 .config_port = sirfsoc_uart_config_port,
1226};
1227
1228#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
Qipan Li5df83112013-08-12 18:15:35 +08001229static int __init
1230sirfsoc_uart_console_setup(struct console *co, char *options)
Rong Wang161e7732011-11-17 23:17:04 +08001231{
1232 unsigned int baud = 115200;
1233 unsigned int bits = 8;
1234 unsigned int parity = 'n';
1235 unsigned int flow = 'n';
Qipan Lia6ffe892015-04-29 06:45:08 +00001236 struct sirfsoc_uart_port *sirfport;
1237 struct sirfsoc_register *ureg;
Rong Wang161e7732011-11-17 23:17:04 +08001238 if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
Qipan Lic35b49b2015-05-14 06:45:26 +00001239 co->index = 1;
Qipan Lia6ffe892015-04-29 06:45:08 +00001240 sirfport = sirf_ports[co->index];
1241 if (!sirfport)
1242 return -ENODEV;
1243 ureg = &sirfport->uart_reg->uart_reg;
1244 if (!sirfport->port.mapbase)
Rong Wang161e7732011-11-17 23:17:04 +08001245 return -ENODEV;
1246
Qipan Li5df83112013-08-12 18:15:35 +08001247 /* enable usp in mode1 register */
1248 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
Qipan Lia6ffe892015-04-29 06:45:08 +00001249 wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
Qipan Li5df83112013-08-12 18:15:35 +08001250 SIRFSOC_USP_ENDIAN_CTRL_LSBF);
Rong Wang161e7732011-11-17 23:17:04 +08001251 if (options)
1252 uart_parse_options(options, &baud, &parity, &bits, &flow);
Qipan Lia6ffe892015-04-29 06:45:08 +00001253 sirfport->port.cons = co;
Qipan Li5df83112013-08-12 18:15:35 +08001254
Qipan Li8316d042013-08-19 11:47:53 +08001255 /* default console tx/rx transfer using io mode */
Qipan Li9be16b32014-01-30 13:57:29 +08001256 sirfport->rx_dma_chan = NULL;
1257 sirfport->tx_dma_chan = NULL;
Qipan Lia6ffe892015-04-29 06:45:08 +00001258 return uart_set_options(&sirfport->port, co, baud, parity, bits, flow);
Rong Wang161e7732011-11-17 23:17:04 +08001259}
1260
1261static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
1262{
Qipan Li5df83112013-08-12 18:15:35 +08001263 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
1264 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
1265 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Qipan Licb4595a2015-04-29 06:45:09 +00001266 while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
1267 ufifo_st->ff_full(port))
Rong Wang161e7732011-11-17 23:17:04 +08001268 cpu_relax();
Barry Song205c3842014-05-05 08:05:51 +08001269 wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
Rong Wang161e7732011-11-17 23:17:04 +08001270}
1271
1272static void sirfsoc_uart_console_write(struct console *co, const char *s,
1273 unsigned int count)
1274{
Qipan Lia6ffe892015-04-29 06:45:08 +00001275 struct sirfsoc_uart_port *sirfport = sirf_ports[co->index];
1276
1277 uart_console_write(&sirfport->port, s, count,
1278 sirfsoc_uart_console_putchar);
Rong Wang161e7732011-11-17 23:17:04 +08001279}
1280
1281static struct console sirfsoc_uart_console = {
1282 .name = SIRFSOC_UART_NAME,
1283 .device = uart_console_device,
1284 .flags = CON_PRINTBUFFER,
1285 .index = -1,
1286 .write = sirfsoc_uart_console_write,
1287 .setup = sirfsoc_uart_console_setup,
1288 .data = &sirfsoc_uart_drv,
1289};
1290
1291static int __init sirfsoc_uart_console_init(void)
1292{
1293 register_console(&sirfsoc_uart_console);
1294 return 0;
1295}
1296console_initcall(sirfsoc_uart_console_init);
1297#endif
1298
1299static struct uart_driver sirfsoc_uart_drv = {
1300 .owner = THIS_MODULE,
1301 .driver_name = SIRFUART_PORT_NAME,
1302 .nr = SIRFSOC_UART_NR,
1303 .dev_name = SIRFSOC_UART_NAME,
1304 .major = SIRFSOC_UART_MAJOR,
1305 .minor = SIRFSOC_UART_MINOR,
1306#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
1307 .cons = &sirfsoc_uart_console,
1308#else
1309 .cons = NULL,
1310#endif
1311};
1312
Qipan Lic1b7ac62015-05-14 06:45:21 +00001313static struct of_device_id sirfsoc_uart_ids[] = {
Qipan Li5df83112013-08-12 18:15:35 +08001314 { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
Barry Song057badd2015-01-03 17:02:57 +08001315 { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
Qipan Li5df83112013-08-12 18:15:35 +08001316 { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
Qipan Lic1b7ac62015-05-14 06:45:21 +00001317 { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp},
Qipan Li5df83112013-08-12 18:15:35 +08001318 {}
1319};
1320MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
1321
Jingoo Hanada1f442013-08-08 17:41:43 +09001322static int sirfsoc_uart_probe(struct platform_device *pdev)
Rong Wang161e7732011-11-17 23:17:04 +08001323{
1324 struct sirfsoc_uart_port *sirfport;
1325 struct uart_port *port;
1326 struct resource *res;
1327 int ret;
Qipan Li9be16b32014-01-30 13:57:29 +08001328 int i, j;
1329 struct dma_slave_config slv_cfg = {
1330 .src_maxburst = 2,
1331 };
1332 struct dma_slave_config tx_slv_cfg = {
1333 .dst_maxburst = 2,
1334 };
Qipan Li5df83112013-08-12 18:15:35 +08001335 const struct of_device_id *match;
Rong Wang161e7732011-11-17 23:17:04 +08001336
Qipan Li5df83112013-08-12 18:15:35 +08001337 match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
Qipan Lia6ffe892015-04-29 06:45:08 +00001338 sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
1339 if (!sirfport) {
1340 ret = -ENOMEM;
Rong Wang161e7732011-11-17 23:17:04 +08001341 goto err;
1342 }
Qipan Lia6ffe892015-04-29 06:45:08 +00001343 sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
1344 sirf_ports[sirfport->port.line] = sirfport;
1345 sirfport->port.iotype = UPIO_MEM;
1346 sirfport->port.flags = UPF_BOOT_AUTOCONF;
Rong Wang161e7732011-11-17 23:17:04 +08001347 port = &sirfport->port;
1348 port->dev = &pdev->dev;
1349 port->private_data = sirfport;
Qipan Li5df83112013-08-12 18:15:35 +08001350 sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
Rong Wang161e7732011-11-17 23:17:04 +08001351
Qipan Li2eb56182013-08-15 06:52:15 +08001352 sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
1353 "sirf,uart-has-rtscts");
Qipan Lic1b7ac62015-05-14 06:45:21 +00001354 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") ||
1355 of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
Qipan Li5df83112013-08-12 18:15:35 +08001356 sirfport->uart_reg->uart_type = SIRF_REAL_UART;
Qipan Lic1b7ac62015-05-14 06:45:21 +00001357 if (of_device_is_compatible(pdev->dev.of_node,
1358 "sirf,prima2-usp-uart") || of_device_is_compatible(
1359 pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
Qipan Li5df83112013-08-12 18:15:35 +08001360 sirfport->uart_reg->uart_type = SIRF_USP_UART;
Qipan Li2eb56182013-08-15 06:52:15 +08001361 if (!sirfport->hw_flow_ctrl)
1362 goto usp_no_flow_control;
1363 if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
1364 sirfport->cts_gpio = of_get_named_gpio(
1365 pdev->dev.of_node, "cts-gpios", 0);
1366 else
1367 sirfport->cts_gpio = -1;
1368 if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
1369 sirfport->rts_gpio = of_get_named_gpio(
1370 pdev->dev.of_node, "rts-gpios", 0);
1371 else
1372 sirfport->rts_gpio = -1;
1373
1374 if ((!gpio_is_valid(sirfport->cts_gpio) ||
1375 !gpio_is_valid(sirfport->rts_gpio))) {
1376 ret = -EINVAL;
1377 dev_err(&pdev->dev,
Qipan Li67bc3062013-08-19 11:47:51 +08001378 "Usp flow control must have cts and rts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +08001379 goto err;
1380 }
1381 ret = devm_gpio_request(&pdev->dev, sirfport->cts_gpio,
Qipan Li67bc3062013-08-19 11:47:51 +08001382 "usp-cts-gpio");
Qipan Li2eb56182013-08-15 06:52:15 +08001383 if (ret) {
Qipan Li67bc3062013-08-19 11:47:51 +08001384 dev_err(&pdev->dev, "Unable request cts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +08001385 goto err;
1386 }
1387 gpio_direction_input(sirfport->cts_gpio);
1388 ret = devm_gpio_request(&pdev->dev, sirfport->rts_gpio,
Qipan Li67bc3062013-08-19 11:47:51 +08001389 "usp-rts-gpio");
Qipan Li2eb56182013-08-15 06:52:15 +08001390 if (ret) {
Qipan Li67bc3062013-08-19 11:47:51 +08001391 dev_err(&pdev->dev, "Unable request rts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +08001392 goto err;
1393 }
1394 gpio_direction_output(sirfport->rts_gpio, 1);
1395 }
1396usp_no_flow_control:
Qipan Lic1b7ac62015-05-14 06:45:21 +00001397 if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
1398 of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
Barry Song057badd2015-01-03 17:02:57 +08001399 sirfport->is_atlas7 = true;
Barry Song909102d2013-08-07 13:35:38 +08001400
Rong Wang161e7732011-11-17 23:17:04 +08001401 if (of_property_read_u32(pdev->dev.of_node,
1402 "fifosize",
1403 &port->fifosize)) {
1404 dev_err(&pdev->dev,
1405 "Unable to find fifosize in uart node.\n");
1406 ret = -EFAULT;
1407 goto err;
1408 }
1409
1410 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1411 if (res == NULL) {
1412 dev_err(&pdev->dev, "Insufficient resources.\n");
1413 ret = -EFAULT;
1414 goto err;
1415 }
Qipan Li8316d042013-08-19 11:47:53 +08001416 tasklet_init(&sirfport->rx_dma_complete_tasklet,
1417 sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
1418 tasklet_init(&sirfport->rx_tmo_process_tasklet,
1419 sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
Rong Wang161e7732011-11-17 23:17:04 +08001420 port->mapbase = res->start;
1421 port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1422 if (!port->membase) {
1423 dev_err(&pdev->dev, "Cannot remap resource.\n");
1424 ret = -ENOMEM;
1425 goto err;
1426 }
1427 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1428 if (res == NULL) {
1429 dev_err(&pdev->dev, "Insufficient resources.\n");
1430 ret = -EFAULT;
Julia Lawall9250dd52012-09-01 18:33:09 +02001431 goto err;
Rong Wang161e7732011-11-17 23:17:04 +08001432 }
1433 port->irq = res->start;
1434
Qipan Liadeede72015-04-20 08:10:23 +00001435 sirfport->clk = devm_clk_get(&pdev->dev, NULL);
Barry Songac4ce712013-01-16 14:49:27 +08001436 if (IS_ERR(sirfport->clk)) {
1437 ret = PTR_ERR(sirfport->clk);
Barry Songa3437562013-08-15 06:52:14 +08001438 goto err;
Barry Songac4ce712013-01-16 14:49:27 +08001439 }
Barry Songac4ce712013-01-16 14:49:27 +08001440 port->uartclk = clk_get_rate(sirfport->clk);
1441
Rong Wang161e7732011-11-17 23:17:04 +08001442 port->ops = &sirfsoc_uart_ops;
1443 spin_lock_init(&port->lock);
1444
1445 platform_set_drvdata(pdev, sirfport);
1446 ret = uart_add_one_port(&sirfsoc_uart_drv, port);
1447 if (ret != 0) {
1448 dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
Qipan Liadeede72015-04-20 08:10:23 +00001449 goto err;
Rong Wang161e7732011-11-17 23:17:04 +08001450 }
1451
Qipan Li9be16b32014-01-30 13:57:29 +08001452 sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
1453 for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
1454 sirfport->rx_dma_items[i].xmit.buf =
1455 dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
1456 &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
1457 if (!sirfport->rx_dma_items[i].xmit.buf) {
1458 dev_err(port->dev, "Uart alloc bufa failed\n");
1459 ret = -ENOMEM;
1460 goto alloc_coherent_err;
1461 }
1462 sirfport->rx_dma_items[i].xmit.head =
1463 sirfport->rx_dma_items[i].xmit.tail = 0;
1464 }
1465 if (sirfport->rx_dma_chan)
1466 dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
1467 sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx");
1468 if (sirfport->tx_dma_chan)
1469 dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
Rong Wang161e7732011-11-17 23:17:04 +08001470
Qipan Li9be16b32014-01-30 13:57:29 +08001471 return 0;
1472alloc_coherent_err:
1473 for (j = 0; j < i; j++)
1474 dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
1475 sirfport->rx_dma_items[j].xmit.buf,
1476 sirfport->rx_dma_items[j].dma_addr);
1477 dma_release_channel(sirfport->rx_dma_chan);
Rong Wang161e7732011-11-17 23:17:04 +08001478err:
1479 return ret;
1480}
1481
1482static int sirfsoc_uart_remove(struct platform_device *pdev)
1483{
1484 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
1485 struct uart_port *port = &sirfport->port;
Rong Wang161e7732011-11-17 23:17:04 +08001486 uart_remove_one_port(&sirfsoc_uart_drv, port);
Qipan Li9be16b32014-01-30 13:57:29 +08001487 if (sirfport->rx_dma_chan) {
1488 int i;
1489 dmaengine_terminate_all(sirfport->rx_dma_chan);
1490 dma_release_channel(sirfport->rx_dma_chan);
1491 for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
1492 dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
1493 sirfport->rx_dma_items[i].xmit.buf,
1494 sirfport->rx_dma_items[i].dma_addr);
1495 }
1496 if (sirfport->tx_dma_chan) {
1497 dmaengine_terminate_all(sirfport->tx_dma_chan);
1498 dma_release_channel(sirfport->tx_dma_chan);
1499 }
Rong Wang161e7732011-11-17 23:17:04 +08001500 return 0;
1501}
1502
Qipan Li99e626f2014-01-03 15:44:06 +08001503#ifdef CONFIG_PM_SLEEP
Rong Wang161e7732011-11-17 23:17:04 +08001504static int
Qipan Li99e626f2014-01-03 15:44:06 +08001505sirfsoc_uart_suspend(struct device *pdev)
Rong Wang161e7732011-11-17 23:17:04 +08001506{
Qipan Li99e626f2014-01-03 15:44:06 +08001507 struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
Rong Wang161e7732011-11-17 23:17:04 +08001508 struct uart_port *port = &sirfport->port;
1509 uart_suspend_port(&sirfsoc_uart_drv, port);
1510 return 0;
1511}
1512
Qipan Li99e626f2014-01-03 15:44:06 +08001513static int sirfsoc_uart_resume(struct device *pdev)
Rong Wang161e7732011-11-17 23:17:04 +08001514{
Qipan Li99e626f2014-01-03 15:44:06 +08001515 struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
Rong Wang161e7732011-11-17 23:17:04 +08001516 struct uart_port *port = &sirfport->port;
1517 uart_resume_port(&sirfsoc_uart_drv, port);
1518 return 0;
1519}
Qipan Li99e626f2014-01-03 15:44:06 +08001520#endif
1521
1522static const struct dev_pm_ops sirfsoc_uart_pm_ops = {
1523 SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume)
1524};
Rong Wang161e7732011-11-17 23:17:04 +08001525
Rong Wang161e7732011-11-17 23:17:04 +08001526static struct platform_driver sirfsoc_uart_driver = {
1527 .probe = sirfsoc_uart_probe,
Bill Pemberton2d47b712012-11-19 13:21:34 -05001528 .remove = sirfsoc_uart_remove,
Rong Wang161e7732011-11-17 23:17:04 +08001529 .driver = {
1530 .name = SIRFUART_PORT_NAME,
Rong Wang161e7732011-11-17 23:17:04 +08001531 .of_match_table = sirfsoc_uart_ids,
Qipan Li99e626f2014-01-03 15:44:06 +08001532 .pm = &sirfsoc_uart_pm_ops,
Rong Wang161e7732011-11-17 23:17:04 +08001533 },
1534};
1535
1536static int __init sirfsoc_uart_init(void)
1537{
1538 int ret = 0;
1539
1540 ret = uart_register_driver(&sirfsoc_uart_drv);
1541 if (ret)
1542 goto out;
1543
1544 ret = platform_driver_register(&sirfsoc_uart_driver);
1545 if (ret)
1546 uart_unregister_driver(&sirfsoc_uart_drv);
1547out:
1548 return ret;
1549}
1550module_init(sirfsoc_uart_init);
1551
1552static void __exit sirfsoc_uart_exit(void)
1553{
1554 platform_driver_unregister(&sirfsoc_uart_driver);
1555 uart_unregister_driver(&sirfsoc_uart_drv);
1556}
1557module_exit(sirfsoc_uart_exit);
1558
1559MODULE_LICENSE("GPL v2");
1560MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
1561MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");