blob: 8d759629ffb0238bbfd455b4ccc8235787623cc5 [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 Licb4595a2015-04-29 06:45:09 +0000275 sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize);
Qipan Li8316d042013-08-19 11:47:53 +0800276 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
Barry Song057badd2015-01-03 17:02:57 +0800277 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800278 wr_regl(port, ureg->sirfsoc_int_en_reg,
279 rd_regl(port, ureg->sirfsoc_int_en_reg)|
280 uint_en->sirfsoc_txfifo_empty_en);
281 else
282 wr_regl(port, ureg->sirfsoc_int_en_reg,
283 uint_en->sirfsoc_txfifo_empty_en);
284 }
Rong Wang161e7732011-11-17 23:17:04 +0800285}
286
287static void sirfsoc_uart_stop_rx(struct uart_port *port)
288{
Barry Song909102d2013-08-07 13:35:38 +0800289 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800290 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
291 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800292
Qipan Li5df83112013-08-12 18:15:35 +0800293 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
Qipan Li9be16b32014-01-30 13:57:29 +0800294 if (sirfport->rx_dma_chan) {
Barry Song057badd2015-01-03 17:02:57 +0800295 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800296 wr_regl(port, ureg->sirfsoc_int_en_reg,
297 rd_regl(port, ureg->sirfsoc_int_en_reg) &
Qipan Lic1b7ac62015-05-14 06:45:21 +0000298 ~(SIRFUART_RX_DMA_INT_EN(uint_en,
299 sirfport->uart_reg->uart_type) |
Qipan Li8316d042013-08-19 11:47:53 +0800300 uint_en->sirfsoc_rx_done_en));
301 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000302 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
303 SIRFUART_RX_DMA_INT_EN(uint_en,
304 sirfport->uart_reg->uart_type)|
305 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800306 dmaengine_terminate_all(sirfport->rx_dma_chan);
307 } else {
Barry Song057badd2015-01-03 17:02:57 +0800308 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800309 wr_regl(port, ureg->sirfsoc_int_en_reg,
310 rd_regl(port, ureg->sirfsoc_int_en_reg)&
Qipan Lic1b7ac62015-05-14 06:45:21 +0000311 ~(SIRFUART_RX_IO_INT_EN(uint_en,
312 sirfport->uart_reg->uart_type)));
Qipan Li8316d042013-08-19 11:47:53 +0800313 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000314 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
315 SIRFUART_RX_IO_INT_EN(uint_en,
316 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800317 }
Rong Wang161e7732011-11-17 23:17:04 +0800318}
319
320static void sirfsoc_uart_disable_ms(struct uart_port *port)
321{
322 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800323 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
324 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800325
Rong Wang161e7732011-11-17 23:17:04 +0800326 if (!sirfport->hw_flow_ctrl)
327 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800328 sirfport->ms_enabled = false;
329 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
330 wr_regl(port, ureg->sirfsoc_afc_ctrl,
331 rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
Barry Song057badd2015-01-03 17:02:57 +0800332 if (!sirfport->is_atlas7)
Qipan Li2eb56182013-08-15 06:52:15 +0800333 wr_regl(port, ureg->sirfsoc_int_en_reg,
334 rd_regl(port, ureg->sirfsoc_int_en_reg)&
335 ~uint_en->sirfsoc_cts_en);
336 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000337 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li2eb56182013-08-15 06:52:15 +0800338 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800339 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800340 disable_irq(gpio_to_irq(sirfport->cts_gpio));
341}
342
343static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
344{
345 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
346 struct uart_port *port = &sirfport->port;
Qipan Li07d410e2014-05-26 19:02:07 +0800347 spin_lock(&port->lock);
Qipan Li2eb56182013-08-15 06:52:15 +0800348 if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
349 uart_handle_cts_change(port,
350 !gpio_get_value(sirfport->cts_gpio));
Qipan Li07d410e2014-05-26 19:02:07 +0800351 spin_unlock(&port->lock);
Qipan Li2eb56182013-08-15 06:52:15 +0800352 return IRQ_HANDLED;
Rong Wang161e7732011-11-17 23:17:04 +0800353}
354
355static void sirfsoc_uart_enable_ms(struct uart_port *port)
356{
357 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800358 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
359 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800360
Rong Wang161e7732011-11-17 23:17:04 +0800361 if (!sirfport->hw_flow_ctrl)
362 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800363 sirfport->ms_enabled = true;
364 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
365 wr_regl(port, ureg->sirfsoc_afc_ctrl,
366 rd_regl(port, ureg->sirfsoc_afc_ctrl) |
Qipan Lieab192a2015-05-14 06:45:22 +0000367 SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN |
368 SIRFUART_AFC_CTRL_RX_THD);
Barry Song057badd2015-01-03 17:02:57 +0800369 if (!sirfport->is_atlas7)
Qipan Li2eb56182013-08-15 06:52:15 +0800370 wr_regl(port, ureg->sirfsoc_int_en_reg,
371 rd_regl(port, ureg->sirfsoc_int_en_reg)
372 | uint_en->sirfsoc_cts_en);
373 else
374 wr_regl(port, ureg->sirfsoc_int_en_reg,
375 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800376 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800377 enable_irq(gpio_to_irq(sirfport->cts_gpio));
Rong Wang161e7732011-11-17 23:17:04 +0800378}
379
380static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
381{
Qipan Li5df83112013-08-12 18:15:35 +0800382 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
383 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
384 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
385 unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
386 if (break_state)
387 ulcon |= SIRFUART_SET_BREAK;
388 else
389 ulcon &= ~SIRFUART_SET_BREAK;
390 wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
391 }
Rong Wang161e7732011-11-17 23:17:04 +0800392}
393
394static unsigned int
395sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
396{
Qipan Li5df83112013-08-12 18:15:35 +0800397 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
398 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
399 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800400 unsigned int ch, rx_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800401 struct tty_struct *tty;
402 tty = tty_port_tty_get(&port->state->port);
403 if (!tty)
404 return -ENODEV;
405 while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000406 ufifo_st->ff_empty(port))) {
Qipan Li5df83112013-08-12 18:15:35 +0800407 ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
408 SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800409 if (unlikely(uart_handle_sysrq_char(port, ch)))
410 continue;
411 uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
412 rx_count++;
413 if (rx_count >= max_rx_count)
414 break;
415 }
416
Qipan Li8316d042013-08-19 11:47:53 +0800417 sirfport->rx_io_count += rx_count;
Rong Wang161e7732011-11-17 23:17:04 +0800418 port->icount.rx += rx_count;
Viresh Kumar8b9ade92013-08-19 20:14:28 +0530419
Rong Wang161e7732011-11-17 23:17:04 +0800420 return rx_count;
421}
422
423static unsigned int
424sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
425{
426 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800427 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
428 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800429 struct circ_buf *xmit = &port->state->xmit;
430 unsigned int num_tx = 0;
431 while (!uart_circ_empty(xmit) &&
Qipan Li5df83112013-08-12 18:15:35 +0800432 !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000433 ufifo_st->ff_full(port)) &&
Rong Wang161e7732011-11-17 23:17:04 +0800434 count--) {
Qipan Li5df83112013-08-12 18:15:35 +0800435 wr_regl(port, ureg->sirfsoc_tx_fifo_data,
436 xmit->buf[xmit->tail]);
Rong Wang161e7732011-11-17 23:17:04 +0800437 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
438 port->icount.tx++;
439 num_tx++;
440 }
441 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
442 uart_write_wakeup(port);
443 return num_tx;
444}
445
Qipan Li8316d042013-08-19 11:47:53 +0800446static void sirfsoc_uart_tx_dma_complete_callback(void *param)
447{
448 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
449 struct uart_port *port = &sirfport->port;
450 struct circ_buf *xmit = &port->state->xmit;
451 unsigned long flags;
452
Qipan Li07d410e2014-05-26 19:02:07 +0800453 spin_lock_irqsave(&port->lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800454 xmit->tail = (xmit->tail + sirfport->transfer_size) &
455 (UART_XMIT_SIZE - 1);
456 port->icount.tx += sirfport->transfer_size;
457 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
458 uart_write_wakeup(port);
459 if (sirfport->tx_dma_addr)
460 dma_unmap_single(port->dev, sirfport->tx_dma_addr,
461 sirfport->transfer_size, DMA_TO_DEVICE);
Qipan Li8316d042013-08-19 11:47:53 +0800462 sirfport->tx_dma_state = TX_DMA_IDLE;
463 sirfsoc_uart_tx_with_dma(sirfport);
Qipan Li07d410e2014-05-26 19:02:07 +0800464 spin_unlock_irqrestore(&port->lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800465}
466
467static void sirfsoc_uart_insert_rx_buf_to_tty(
468 struct sirfsoc_uart_port *sirfport, int count)
469{
470 struct uart_port *port = &sirfport->port;
471 struct tty_port *tport = &port->state->port;
472 int inserted;
473
474 inserted = tty_insert_flip_string(tport,
475 sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
476 port->icount.rx += inserted;
Qipan Li8316d042013-08-19 11:47:53 +0800477}
478
479static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
480{
481 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
482
483 sirfport->rx_dma_items[index].xmit.tail =
484 sirfport->rx_dma_items[index].xmit.head = 0;
485 sirfport->rx_dma_items[index].desc =
486 dmaengine_prep_slave_single(sirfport->rx_dma_chan,
487 sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
488 DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000489 if (IS_ERR_OR_NULL(sirfport->rx_dma_items[index].desc)) {
Qipan Li8316d042013-08-19 11:47:53 +0800490 dev_err(port->dev, "DMA slave single fail\n");
491 return;
492 }
493 sirfport->rx_dma_items[index].desc->callback =
494 sirfsoc_uart_rx_dma_complete_callback;
495 sirfport->rx_dma_items[index].desc->callback_param = sirfport;
496 sirfport->rx_dma_items[index].cookie =
497 dmaengine_submit(sirfport->rx_dma_items[index].desc);
498 dma_async_issue_pending(sirfport->rx_dma_chan);
499}
500
501static void sirfsoc_rx_tmo_process_tl(unsigned long param)
502{
503 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
504 struct uart_port *port = &sirfport->port;
505 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
506 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
507 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
508 unsigned int count;
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800509 struct dma_tx_state tx_state;
Qipan Lic1b7ac62015-05-14 06:45:21 +0000510 unsigned long flags;
Qipan Li36c09912015-05-14 06:45:23 +0000511 int i = 0;
Qipan Li8316d042013-08-19 11:47:53 +0800512
Qipan Li07d410e2014-05-26 19:02:07 +0800513 spin_lock_irqsave(&port->lock, flags);
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800514 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000515 sirfport->rx_dma_items[sirfport->rx_completed].cookie,
516 &tx_state)) {
Qipan Li8316d042013-08-19 11:47:53 +0800517 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
518 SIRFSOC_RX_DMA_BUF_SIZE);
Qipan Li59f8a622013-09-21 09:02:10 +0800519 sirfport->rx_completed++;
Qipan Li8316d042013-08-19 11:47:53 +0800520 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li36c09912015-05-14 06:45:23 +0000521 i++;
522 if (i > SIRFSOC_RX_LOOP_BUF_CNT)
523 break;
Qipan Li8316d042013-08-19 11:47:53 +0800524 }
525 count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
526 sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
527 SIRFSOC_RX_DMA_BUF_SIZE);
528 if (count > 0)
529 sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
530 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
531 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
532 SIRFUART_IO_MODE);
Qipan Lifb78b812014-01-27 14:23:39 +0800533 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
Qipan Li8316d042013-08-19 11:47:53 +0800534 if (sirfport->rx_io_count == 4) {
Qipan Li8316d042013-08-19 11:47:53 +0800535 sirfport->rx_io_count = 0;
536 wr_regl(port, ureg->sirfsoc_int_st_reg,
537 uint_st->sirfsoc_rx_done);
Barry Song057badd2015-01-03 17:02:57 +0800538 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800539 wr_regl(port, ureg->sirfsoc_int_en_reg,
540 rd_regl(port, ureg->sirfsoc_int_en_reg) &
541 ~(uint_en->sirfsoc_rx_done_en));
542 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000543 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800544 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800545 sirfsoc_uart_start_next_rx_dma(port);
546 } else {
Qipan Li8316d042013-08-19 11:47:53 +0800547 wr_regl(port, ureg->sirfsoc_int_st_reg,
548 uint_st->sirfsoc_rx_done);
Barry Song057badd2015-01-03 17:02:57 +0800549 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800550 wr_regl(port, ureg->sirfsoc_int_en_reg,
551 rd_regl(port, ureg->sirfsoc_int_en_reg) |
552 (uint_en->sirfsoc_rx_done_en));
553 else
554 wr_regl(port, ureg->sirfsoc_int_en_reg,
555 uint_en->sirfsoc_rx_done_en);
Qipan Li8316d042013-08-19 11:47:53 +0800556 }
Qipan Li07d410e2014-05-26 19:02:07 +0800557 spin_unlock_irqrestore(&port->lock, flags);
558 tty_flip_buffer_push(&port->state->port);
Qipan Li8316d042013-08-19 11:47:53 +0800559}
560
561static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
562{
563 struct uart_port *port = &sirfport->port;
564 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
565 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
566 struct dma_tx_state tx_state;
Qipan Li8316d042013-08-19 11:47:53 +0800567 dmaengine_tx_status(sirfport->rx_dma_chan,
568 sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
569 dmaengine_terminate_all(sirfport->rx_dma_chan);
570 sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
571 SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
Barry Song057badd2015-01-03 17:02:57 +0800572 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800573 wr_regl(port, ureg->sirfsoc_int_en_reg,
574 rd_regl(port, ureg->sirfsoc_int_en_reg) &
575 ~(uint_en->sirfsoc_rx_timeout_en));
576 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000577 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800578 uint_en->sirfsoc_rx_timeout_en);
Qipan Li8316d042013-08-19 11:47:53 +0800579 tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
580}
581
582static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
583{
584 struct uart_port *port = &sirfport->port;
585 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
586 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
587 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
588
589 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
590 if (sirfport->rx_io_count == 4) {
591 sirfport->rx_io_count = 0;
Barry Song057badd2015-01-03 17:02:57 +0800592 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800593 wr_regl(port, ureg->sirfsoc_int_en_reg,
594 rd_regl(port, ureg->sirfsoc_int_en_reg) &
595 ~(uint_en->sirfsoc_rx_done_en));
596 else
Qipan Lic1b7ac62015-05-14 06:45:21 +0000597 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
Qipan Li8316d042013-08-19 11:47:53 +0800598 uint_en->sirfsoc_rx_done_en);
599 wr_regl(port, ureg->sirfsoc_int_st_reg,
600 uint_st->sirfsoc_rx_timeout);
601 sirfsoc_uart_start_next_rx_dma(port);
602 }
603}
604
Rong Wang161e7732011-11-17 23:17:04 +0800605static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
606{
607 unsigned long intr_status;
608 unsigned long cts_status;
609 unsigned long flag = TTY_NORMAL;
610 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
611 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800612 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
613 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
614 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
615 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800616 struct uart_state *state = port->state;
617 struct circ_buf *xmit = &port->state->xmit;
Barry Song5425e032012-12-25 17:32:04 +0800618 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800619 intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
620 wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
Qipan Li8316d042013-08-19 11:47:53 +0800621 intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000622 if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
623 sirfport->uart_reg->uart_type)))) {
Qipan Li5df83112013-08-12 18:15:35 +0800624 if (intr_status & uint_st->sirfsoc_rxd_brk) {
625 port->icount.brk++;
Rong Wang161e7732011-11-17 23:17:04 +0800626 if (uart_handle_break(port))
627 goto recv_char;
Rong Wang161e7732011-11-17 23:17:04 +0800628 }
Qipan Lid9e8e972015-05-14 06:45:24 +0000629 if (intr_status & uint_st->sirfsoc_rx_oflow) {
Rong Wang161e7732011-11-17 23:17:04 +0800630 port->icount.overrun++;
Qipan Lid9e8e972015-05-14 06:45:24 +0000631 flag = TTY_OVERRUN;
632 }
Qipan Li5df83112013-08-12 18:15:35 +0800633 if (intr_status & uint_st->sirfsoc_frm_err) {
Rong Wang161e7732011-11-17 23:17:04 +0800634 port->icount.frame++;
635 flag = TTY_FRAME;
636 }
Qipan Lid9e8e972015-05-14 06:45:24 +0000637 if (intr_status & uint_st->sirfsoc_parity_err) {
638 port->icount.parity++;
Rong Wang161e7732011-11-17 23:17:04 +0800639 flag = TTY_PARITY;
Qipan Lid9e8e972015-05-14 06:45:24 +0000640 }
Qipan Li5df83112013-08-12 18:15:35 +0800641 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
642 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
643 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800644 intr_status &= port->read_status_mask;
645 uart_insert_char(port, intr_status,
Qipan Li5df83112013-08-12 18:15:35 +0800646 uint_en->sirfsoc_rx_oflow_en, 0, flag);
Rong Wang161e7732011-11-17 23:17:04 +0800647 }
648recv_char:
Qipan Li5df83112013-08-12 18:15:35 +0800649 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
Qipan Li8316d042013-08-19 11:47:53 +0800650 (intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
651 !sirfport->tx_dma_state) {
Qipan Li5df83112013-08-12 18:15:35 +0800652 cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
653 SIRFUART_AFC_CTS_STATUS;
654 if (cts_status != 0)
655 cts_status = 0;
656 else
657 cts_status = 1;
658 uart_handle_cts_change(port, cts_status);
659 wake_up_interruptible(&state->port.delta_msr_wait);
Rong Wang161e7732011-11-17 23:17:04 +0800660 }
Qipan Li9be16b32014-01-30 13:57:29 +0800661 if (sirfport->rx_dma_chan) {
Qipan Li8316d042013-08-19 11:47:53 +0800662 if (intr_status & uint_st->sirfsoc_rx_timeout)
663 sirfsoc_uart_handle_rx_tmo(sirfport);
664 if (intr_status & uint_st->sirfsoc_rx_done)
665 sirfsoc_uart_handle_rx_done(sirfport);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000666 } else if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st)) {
667 /*
668 * chip will trigger continuous RX_TIMEOUT interrupt
669 * in RXFIFO empty and not trigger if RXFIFO recevice
670 * data in limit time, original method use RX_TIMEOUT
671 * will trigger lots of useless interrupt in RXFIFO
672 * empty.RXFIFO received one byte will trigger RX_DONE
673 * interrupt.use RX_DONE to wait for data received
674 * into RXFIFO, use RX_THD/RX_FULL for lots data receive
675 * and use RX_TIMEOUT for the last left data.
676 */
677 if (intr_status & uint_st->sirfsoc_rx_done) {
678 if (!sirfport->is_atlas7) {
679 wr_regl(port, ureg->sirfsoc_int_en_reg,
680 rd_regl(port, ureg->sirfsoc_int_en_reg)
681 & ~(uint_en->sirfsoc_rx_done_en));
682 wr_regl(port, ureg->sirfsoc_int_en_reg,
683 rd_regl(port, ureg->sirfsoc_int_en_reg)
684 | (uint_en->sirfsoc_rx_timeout_en));
685 } else {
686 wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
687 uint_en->sirfsoc_rx_done_en);
688 wr_regl(port, ureg->sirfsoc_int_en_reg,
689 uint_en->sirfsoc_rx_timeout_en);
690 }
691 } else {
692 if (intr_status & uint_st->sirfsoc_rx_timeout) {
693 if (!sirfport->is_atlas7) {
694 wr_regl(port, ureg->sirfsoc_int_en_reg,
695 rd_regl(port, ureg->sirfsoc_int_en_reg)
696 & ~(uint_en->sirfsoc_rx_timeout_en));
697 wr_regl(port, ureg->sirfsoc_int_en_reg,
698 rd_regl(port, ureg->sirfsoc_int_en_reg)
699 | (uint_en->sirfsoc_rx_done_en));
700 } else {
701 wr_regl(port,
702 ureg->sirfsoc_int_en_clr_reg,
703 uint_en->sirfsoc_rx_timeout_en);
704 wr_regl(port, ureg->sirfsoc_int_en_reg,
705 uint_en->sirfsoc_rx_done_en);
706 }
707 }
Qipan Licb4595a2015-04-29 06:45:09 +0000708 sirfsoc_uart_pio_rx_chars(port, port->fifosize);
Qipan Lic1b7ac62015-05-14 06:45:21 +0000709 }
Qipan Li8316d042013-08-19 11:47:53 +0800710 }
Qipan Li07d410e2014-05-26 19:02:07 +0800711 spin_unlock(&port->lock);
712 tty_flip_buffer_push(&state->port);
713 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800714 if (intr_status & uint_st->sirfsoc_txfifo_empty) {
Qipan Li9be16b32014-01-30 13:57:29 +0800715 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +0800716 sirfsoc_uart_tx_with_dma(sirfport);
717 else {
718 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
719 spin_unlock(&port->lock);
720 return IRQ_HANDLED;
721 } else {
722 sirfsoc_uart_pio_tx_chars(sirfport,
Qipan Licb4595a2015-04-29 06:45:09 +0000723 port->fifosize);
Qipan Li8316d042013-08-19 11:47:53 +0800724 if ((uart_circ_empty(xmit)) &&
Qipan Li5df83112013-08-12 18:15:35 +0800725 (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
Qipan Licb4595a2015-04-29 06:45:09 +0000726 ufifo_st->ff_empty(port)))
Qipan Li8316d042013-08-19 11:47:53 +0800727 sirfsoc_uart_stop_tx(port);
728 }
Rong Wang161e7732011-11-17 23:17:04 +0800729 }
730 }
Barry Song5425e032012-12-25 17:32:04 +0800731 spin_unlock(&port->lock);
Qipan Li07d410e2014-05-26 19:02:07 +0800732
Rong Wang161e7732011-11-17 23:17:04 +0800733 return IRQ_HANDLED;
734}
735
Qipan Li8316d042013-08-19 11:47:53 +0800736static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
737{
738 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
739 struct uart_port *port = &sirfport->port;
Qipan Li59f8a622013-09-21 09:02:10 +0800740 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
741 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800742 struct dma_tx_state tx_state;
Qipan Lic1b7ac62015-05-14 06:45:21 +0000743 unsigned long flags;
Qipan Li36c09912015-05-14 06:45:23 +0000744 int i = 0;
745
Daniel Thompson58eb97c2014-05-29 11:13:43 +0100746 spin_lock_irqsave(&port->lock, flags);
Qipan Lidf8d4aa2014-01-03 15:44:08 +0800747 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000748 sirfport->rx_dma_items[sirfport->rx_completed].cookie,
749 &tx_state)) {
Qipan Li8316d042013-08-19 11:47:53 +0800750 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
751 SIRFSOC_RX_DMA_BUF_SIZE);
Qipan Li59f8a622013-09-21 09:02:10 +0800752 if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
753 uint_en->sirfsoc_rx_timeout_en)
754 sirfsoc_rx_submit_one_dma_desc(port,
755 sirfport->rx_completed++);
756 else
757 sirfport->rx_completed++;
Qipan Li8316d042013-08-19 11:47:53 +0800758 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li36c09912015-05-14 06:45:23 +0000759 i++;
760 if (i > SIRFSOC_RX_LOOP_BUF_CNT)
761 break;
Qipan Li8316d042013-08-19 11:47:53 +0800762 }
Qipan Li07d410e2014-05-26 19:02:07 +0800763 spin_unlock_irqrestore(&port->lock, flags);
764 tty_flip_buffer_push(&port->state->port);
Qipan Li8316d042013-08-19 11:47:53 +0800765}
766
767static void sirfsoc_uart_rx_dma_complete_callback(void *param)
768{
769 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
Qipan Li07d410e2014-05-26 19:02:07 +0800770 unsigned long flags;
771
772 spin_lock_irqsave(&sirfport->port.lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800773 sirfport->rx_issued++;
774 sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
Qipan Li8316d042013-08-19 11:47:53 +0800775 tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
Qipan Li07d410e2014-05-26 19:02:07 +0800776 spin_unlock_irqrestore(&sirfport->port.lock, flags);
Qipan Li8316d042013-08-19 11:47:53 +0800777}
778
779/* submit rx dma task into dmaengine */
780static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
781{
782 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
783 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
784 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800785 int i;
Qipan Li8316d042013-08-19 11:47:53 +0800786 sirfport->rx_io_count = 0;
787 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
788 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
789 ~SIRFUART_IO_MODE);
Qipan Li8316d042013-08-19 11:47:53 +0800790 for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
791 sirfsoc_rx_submit_one_dma_desc(port, i);
792 sirfport->rx_completed = sirfport->rx_issued = 0;
Barry Song057badd2015-01-03 17:02:57 +0800793 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800794 wr_regl(port, ureg->sirfsoc_int_en_reg,
795 rd_regl(port, ureg->sirfsoc_int_en_reg) |
Qipan Lic1b7ac62015-05-14 06:45:21 +0000796 SIRFUART_RX_DMA_INT_EN(uint_en,
797 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800798 else
799 wr_regl(port, ureg->sirfsoc_int_en_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000800 SIRFUART_RX_DMA_INT_EN(uint_en,
801 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800802}
803
Rong Wang161e7732011-11-17 23:17:04 +0800804static void sirfsoc_uart_start_rx(struct uart_port *port)
805{
Barry Song909102d2013-08-07 13:35:38 +0800806 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800807 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
808 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Qipan Li8316d042013-08-19 11:47:53 +0800809
810 sirfport->rx_io_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800811 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
812 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
813 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Qipan Li9be16b32014-01-30 13:57:29 +0800814 if (sirfport->rx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +0800815 sirfsoc_uart_start_next_rx_dma(port);
816 else {
Barry Song057badd2015-01-03 17:02:57 +0800817 if (!sirfport->is_atlas7)
Qipan Li8316d042013-08-19 11:47:53 +0800818 wr_regl(port, ureg->sirfsoc_int_en_reg,
819 rd_regl(port, ureg->sirfsoc_int_en_reg) |
Qipan Lic1b7ac62015-05-14 06:45:21 +0000820 SIRFUART_RX_IO_INT_EN(uint_en,
821 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800822 else
823 wr_regl(port, ureg->sirfsoc_int_en_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +0000824 SIRFUART_RX_IO_INT_EN(uint_en,
825 sirfport->uart_reg->uart_type));
Qipan Li8316d042013-08-19 11:47:53 +0800826 }
Rong Wang161e7732011-11-17 23:17:04 +0800827}
828
829static unsigned int
Qipan Li5df83112013-08-12 18:15:35 +0800830sirfsoc_usp_calc_sample_div(unsigned long set_rate,
831 unsigned long ioclk_rate, unsigned long *sample_reg)
832{
833 unsigned long min_delta = ~0UL;
834 unsigned short sample_div;
835 unsigned long ioclk_div = 0;
836 unsigned long temp_delta;
837
Qipan Licb4595a2015-04-29 06:45:09 +0000838 for (sample_div = SIRF_USP_MIN_SAMPLE_DIV;
Qipan Li5df83112013-08-12 18:15:35 +0800839 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
840 temp_delta = ioclk_rate -
841 (ioclk_rate + (set_rate * sample_div) / 2)
842 / (set_rate * sample_div) * set_rate * sample_div;
843
844 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
845 if (temp_delta < min_delta) {
846 ioclk_div = (2 * ioclk_rate /
847 (set_rate * sample_div) + 1) / 2 - 1;
848 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
849 continue;
850 min_delta = temp_delta;
851 *sample_reg = sample_div;
852 if (!temp_delta)
853 break;
854 }
855 }
856 return ioclk_div;
857}
858
859static unsigned int
860sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
861 unsigned long ioclk_rate, unsigned long *set_baud)
Rong Wang161e7732011-11-17 23:17:04 +0800862{
863 unsigned long min_delta = ~0UL;
864 unsigned short sample_div;
865 unsigned int regv = 0;
866 unsigned long ioclk_div;
867 unsigned long baud_tmp;
868 int temp_delta;
869
870 for (sample_div = SIRF_MIN_SAMPLE_DIV;
871 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
872 ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
873 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
874 continue;
875 baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
876 temp_delta = baud_tmp - baud_rate;
877 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
878 if (temp_delta < min_delta) {
879 regv = regv & (~SIRF_IOCLK_DIV_MASK);
880 regv = regv | ioclk_div;
881 regv = regv & (~SIRF_SAMPLE_DIV_MASK);
882 regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
883 min_delta = temp_delta;
Qipan Li5df83112013-08-12 18:15:35 +0800884 *set_baud = baud_tmp;
Rong Wang161e7732011-11-17 23:17:04 +0800885 }
886 }
887 return regv;
888}
889
890static void sirfsoc_uart_set_termios(struct uart_port *port,
891 struct ktermios *termios,
892 struct ktermios *old)
893{
894 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800895 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
896 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800897 unsigned long config_reg = 0;
898 unsigned long baud_rate;
Qipan Li5df83112013-08-12 18:15:35 +0800899 unsigned long set_baud;
Rong Wang161e7732011-11-17 23:17:04 +0800900 unsigned long flags;
901 unsigned long ic;
902 unsigned int clk_div_reg = 0;
Qipan Li8316d042013-08-19 11:47:53 +0800903 unsigned long txfifo_op_reg, ioclk_rate;
Rong Wang161e7732011-11-17 23:17:04 +0800904 unsigned long rx_time_out;
905 int threshold_div;
Qipan Li5df83112013-08-12 18:15:35 +0800906 u32 data_bit_len, stop_bit_len, len_val;
907 unsigned long sample_div_reg = 0xf;
908 ioclk_rate = port->uartclk;
Rong Wang161e7732011-11-17 23:17:04 +0800909
Rong Wang161e7732011-11-17 23:17:04 +0800910 switch (termios->c_cflag & CSIZE) {
911 default:
912 case CS8:
Qipan Li5df83112013-08-12 18:15:35 +0800913 data_bit_len = 8;
Rong Wang161e7732011-11-17 23:17:04 +0800914 config_reg |= SIRFUART_DATA_BIT_LEN_8;
915 break;
916 case CS7:
Qipan Li5df83112013-08-12 18:15:35 +0800917 data_bit_len = 7;
Rong Wang161e7732011-11-17 23:17:04 +0800918 config_reg |= SIRFUART_DATA_BIT_LEN_7;
919 break;
920 case CS6:
Qipan Li5df83112013-08-12 18:15:35 +0800921 data_bit_len = 6;
Rong Wang161e7732011-11-17 23:17:04 +0800922 config_reg |= SIRFUART_DATA_BIT_LEN_6;
923 break;
924 case CS5:
Qipan Li5df83112013-08-12 18:15:35 +0800925 data_bit_len = 5;
Rong Wang161e7732011-11-17 23:17:04 +0800926 config_reg |= SIRFUART_DATA_BIT_LEN_5;
927 break;
928 }
Qipan Li5df83112013-08-12 18:15:35 +0800929 if (termios->c_cflag & CSTOPB) {
Rong Wang161e7732011-11-17 23:17:04 +0800930 config_reg |= SIRFUART_STOP_BIT_LEN_2;
Qipan Li5df83112013-08-12 18:15:35 +0800931 stop_bit_len = 2;
932 } else
933 stop_bit_len = 1;
934
Rong Wang161e7732011-11-17 23:17:04 +0800935 spin_lock_irqsave(&port->lock, flags);
Qipan Li5df83112013-08-12 18:15:35 +0800936 port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
Rong Wang161e7732011-11-17 23:17:04 +0800937 port->ignore_status_mask = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800938 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
939 if (termios->c_iflag & INPCK)
940 port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
941 uint_en->sirfsoc_parity_err_en;
Qipan Li2eb56182013-08-15 06:52:15 +0800942 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800943 if (termios->c_iflag & INPCK)
944 port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
945 }
Peter Hurleyef8b9dd2014-06-16 08:10:41 -0400946 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
Qipan Li5df83112013-08-12 18:15:35 +0800947 port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
948 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
949 if (termios->c_iflag & IGNPAR)
950 port->ignore_status_mask |=
951 uint_en->sirfsoc_frm_err_en |
952 uint_en->sirfsoc_parity_err_en;
953 if (termios->c_cflag & PARENB) {
954 if (termios->c_cflag & CMSPAR) {
955 if (termios->c_cflag & PARODD)
956 config_reg |= SIRFUART_STICK_BIT_MARK;
957 else
958 config_reg |= SIRFUART_STICK_BIT_SPACE;
Qipan Li5df83112013-08-12 18:15:35 +0800959 } else {
Qipan Lid9e8e972015-05-14 06:45:24 +0000960 if (termios->c_cflag & PARODD)
961 config_reg |= SIRFUART_STICK_BIT_ODD;
962 else
963 config_reg |= SIRFUART_STICK_BIT_EVEN;
Qipan Li5df83112013-08-12 18:15:35 +0800964 }
Rong Wang161e7732011-11-17 23:17:04 +0800965 }
Qipan Li2eb56182013-08-15 06:52:15 +0800966 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800967 if (termios->c_iflag & IGNPAR)
968 port->ignore_status_mask |=
969 uint_en->sirfsoc_frm_err_en;
970 if (termios->c_cflag & PARENB)
971 dev_warn(port->dev,
972 "USP-UART not support parity err\n");
973 }
974 if (termios->c_iflag & IGNBRK) {
975 port->ignore_status_mask |=
976 uint_en->sirfsoc_rxd_brk_en;
977 if (termios->c_iflag & IGNPAR)
978 port->ignore_status_mask |=
979 uint_en->sirfsoc_rx_oflow_en;
980 }
981 if ((termios->c_cflag & CREAD) == 0)
982 port->ignore_status_mask |= SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800983 /* Hardware Flow Control Settings */
984 if (UART_ENABLE_MS(port, termios->c_cflag)) {
985 if (!sirfport->ms_enabled)
986 sirfsoc_uart_enable_ms(port);
987 } else {
988 if (sirfport->ms_enabled)
989 sirfsoc_uart_disable_ms(port);
990 }
Qipan Li5df83112013-08-12 18:15:35 +0800991 baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
992 if (ioclk_rate == 150000000) {
Barry Songac4ce712013-01-16 14:49:27 +0800993 for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
994 if (baud_rate == baudrate_to_regv[ic].baud_rate)
995 clk_div_reg = baudrate_to_regv[ic].reg_val;
996 }
Qipan Li5df83112013-08-12 18:15:35 +0800997 set_baud = baud_rate;
998 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
999 if (unlikely(clk_div_reg == 0))
1000 clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
1001 ioclk_rate, &set_baud);
1002 wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
Qipan Li2eb56182013-08-15 06:52:15 +08001003 } else {
Qipan Li5df83112013-08-12 18:15:35 +08001004 clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
1005 ioclk_rate, &sample_div_reg);
1006 sample_div_reg--;
1007 set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
1008 (sample_div_reg + 1));
1009 /* setting usp mode 2 */
Qipan Li459f15c2013-08-25 20:18:40 +08001010 len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) |
1011 (1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET));
1012 len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK)
1013 << SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET);
1014 wr_regl(port, ureg->sirfsoc_mode2, len_val);
Qipan Li5df83112013-08-12 18:15:35 +08001015 }
Rong Wang161e7732011-11-17 23:17:04 +08001016 if (tty_termios_baud_rate(termios))
Qipan Li5df83112013-08-12 18:15:35 +08001017 tty_termios_encode_baud_rate(termios, set_baud, set_baud);
1018 /* set receive timeout && data bits len */
1019 rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
1020 rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
Qipan Li8316d042013-08-19 11:47:53 +08001021 txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
Qipan Li459f15c2013-08-25 20:18:40 +08001022 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP);
Qipan Li5df83112013-08-12 18:15:35 +08001023 wr_regl(port, ureg->sirfsoc_tx_fifo_op,
Qipan Li8316d042013-08-19 11:47:53 +08001024 (txfifo_op_reg & ~SIRFUART_FIFO_START));
Qipan Li5df83112013-08-12 18:15:35 +08001025 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Lic1b7ac62015-05-14 06:45:21 +00001026 config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out);
Qipan Li5df83112013-08-12 18:15:35 +08001027 wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
Qipan Li2eb56182013-08-15 06:52:15 +08001028 } else {
Qipan Li5df83112013-08-12 18:15:35 +08001029 /*tx frame ctrl*/
Qipan Li459f15c2013-08-25 20:18:40 +08001030 len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET;
1031 len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
1032 SIRFSOC_USP_TX_FRAME_LEN_OFFSET;
1033 len_val |= ((data_bit_len - 1) <<
1034 SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET);
1035 len_val |= (((clk_div_reg & 0xc00) >> 10) <<
1036 SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001037 wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
1038 /*rx frame ctrl*/
Qipan Li459f15c2013-08-25 20:18:40 +08001039 len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET;
1040 len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
1041 SIRFSOC_USP_RX_FRAME_LEN_OFFSET;
1042 len_val |= (data_bit_len - 1) <<
1043 SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET;
1044 len_val |= (((clk_div_reg & 0xf000) >> 12) <<
1045 SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001046 wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
1047 /*async param*/
1048 wr_regl(port, ureg->sirfsoc_async_param_reg,
Qipan Lic1b7ac62015-05-14 06:45:21 +00001049 (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) |
Qipan Li459f15c2013-08-25 20:18:40 +08001050 (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
1051 SIRFSOC_USP_ASYNC_DIV2_OFFSET);
Qipan Li5df83112013-08-12 18:15:35 +08001052 }
Qipan Li9be16b32014-01-30 13:57:29 +08001053 if (sirfport->tx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001054 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
1055 else
1056 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
Qipan Li9be16b32014-01-30 13:57:29 +08001057 if (sirfport->rx_dma_chan)
Qipan Li8316d042013-08-19 11:47:53 +08001058 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
1059 else
1060 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
Rong Wang161e7732011-11-17 23:17:04 +08001061 /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
Qipan Li5df83112013-08-12 18:15:35 +08001062 if (set_baud < 1000000)
Rong Wang161e7732011-11-17 23:17:04 +08001063 threshold_div = 1;
1064 else
1065 threshold_div = 2;
Qipan Li8316d042013-08-19 11:47:53 +08001066 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl,
1067 SIRFUART_FIFO_THD(port) / threshold_div);
1068 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl,
1069 SIRFUART_FIFO_THD(port) / threshold_div);
1070 txfifo_op_reg |= SIRFUART_FIFO_START;
1071 wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg);
Qipan Li5df83112013-08-12 18:15:35 +08001072 uart_update_timeout(port, termios->c_cflag, set_baud);
Rong Wang161e7732011-11-17 23:17:04 +08001073 sirfsoc_uart_start_rx(port);
Qipan Li5df83112013-08-12 18:15:35 +08001074 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
Rong Wang161e7732011-11-17 23:17:04 +08001075 spin_unlock_irqrestore(&port->lock, flags);
1076}
1077
Qipan Li388faf92014-01-03 15:44:07 +08001078static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
1079 unsigned int oldstate)
1080{
1081 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li4b8038d2015-04-20 08:10:22 +00001082 if (!state)
Qipan Li388faf92014-01-03 15:44:07 +08001083 clk_prepare_enable(sirfport->clk);
Qipan Li4b8038d2015-04-20 08:10:22 +00001084 else
Qipan Li388faf92014-01-03 15:44:07 +08001085 clk_disable_unprepare(sirfport->clk);
1086}
1087
Rong Wang161e7732011-11-17 23:17:04 +08001088static int sirfsoc_uart_startup(struct uart_port *port)
1089{
1090 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li15cdcb12013-08-19 11:47:52 +08001091 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +08001092 unsigned int index = port->line;
1093 int ret;
1094 set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
1095 ret = request_irq(port->irq,
1096 sirfsoc_uart_isr,
1097 0,
1098 SIRFUART_PORT_NAME,
1099 sirfport);
1100 if (ret != 0) {
1101 dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
1102 index, port->irq);
1103 goto irq_err;
1104 }
Qipan Li15cdcb12013-08-19 11:47:52 +08001105 /* initial hardware settings */
1106 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
1107 rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
1108 SIRFUART_IO_MODE);
1109 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
1110 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
1111 SIRFUART_IO_MODE);
1112 wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
1113 wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
1114 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
1115 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
1116 wr_regl(port, ureg->sirfsoc_mode1,
1117 SIRFSOC_USP_ENDIAN_CTRL_LSBF |
1118 SIRFSOC_USP_EN);
1119 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
1120 wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
1121 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");