blob: d37609dfcf765e18c42dd5bc0271815b8755476c [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>
Rong Wang161e7732011-11-17 23:17:04 +080024#include <asm/irq.h>
25#include <asm/mach/irq.h>
Rong Wang161e7732011-11-17 23:17:04 +080026
27#include "sirfsoc_uart.h"
28
29static unsigned int
30sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count);
31static unsigned int
32sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
33static struct uart_driver sirfsoc_uart_drv;
34
35static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
36 {4000000, 2359296},
37 {3500000, 1310721},
38 {3000000, 1572865},
39 {2500000, 1245186},
40 {2000000, 1572866},
41 {1500000, 1245188},
42 {1152000, 1638404},
43 {1000000, 1572869},
44 {921600, 1114120},
45 {576000, 1245196},
46 {500000, 1245198},
47 {460800, 1572876},
48 {230400, 1310750},
49 {115200, 1310781},
50 {57600, 1310843},
51 {38400, 1114328},
52 {19200, 1114545},
53 {9600, 1114979},
54};
55
56static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
57 [0] = {
58 .port = {
59 .iotype = UPIO_MEM,
60 .flags = UPF_BOOT_AUTOCONF,
61 .line = 0,
62 },
63 },
64 [1] = {
65 .port = {
66 .iotype = UPIO_MEM,
67 .flags = UPF_BOOT_AUTOCONF,
68 .line = 1,
69 },
70 },
71 [2] = {
72 .port = {
73 .iotype = UPIO_MEM,
74 .flags = UPF_BOOT_AUTOCONF,
75 .line = 2,
76 },
77 },
Barry Song5425e032012-12-25 17:32:04 +080078 [3] = {
79 .port = {
80 .iotype = UPIO_MEM,
81 .flags = UPF_BOOT_AUTOCONF,
82 .line = 3,
83 },
84 },
85 [4] = {
86 .port = {
87 .iotype = UPIO_MEM,
88 .flags = UPF_BOOT_AUTOCONF,
89 .line = 4,
90 },
91 },
Rong Wang161e7732011-11-17 23:17:04 +080092};
93
94static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
95{
96 return container_of(port, struct sirfsoc_uart_port, port);
97}
98
99static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
100{
101 unsigned long reg;
Qipan Li5df83112013-08-12 18:15:35 +0800102 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
103 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
104 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
105 reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
106
107 return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
Rong Wang161e7732011-11-17 23:17:04 +0800108}
109
110static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
111{
112 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800113 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Qipan Li2eb56182013-08-15 06:52:15 +0800114 if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
Rong Wang161e7732011-11-17 23:17:04 +0800115 goto cts_asserted;
Qipan Li2eb56182013-08-15 06:52:15 +0800116 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Li5df83112013-08-12 18:15:35 +0800117 if (!(rd_regl(port, ureg->sirfsoc_afc_ctrl) &
118 SIRFUART_AFC_CTS_STATUS))
Rong Wang161e7732011-11-17 23:17:04 +0800119 goto cts_asserted;
120 else
121 goto cts_deasserted;
Qipan Li2eb56182013-08-15 06:52:15 +0800122 } else {
123 if (!gpio_get_value(sirfport->cts_gpio))
124 goto cts_asserted;
125 else
126 goto cts_deasserted;
Rong Wang161e7732011-11-17 23:17:04 +0800127 }
128cts_deasserted:
129 return TIOCM_CAR | TIOCM_DSR;
130cts_asserted:
131 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
132}
133
134static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
135{
136 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800137 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800138 unsigned int assert = mctrl & TIOCM_RTS;
139 unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
140 unsigned int current_val;
Qipan Li2eb56182013-08-15 06:52:15 +0800141
142 if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
143 return;
144 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
Qipan Li5df83112013-08-12 18:15:35 +0800145 current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF;
Rong Wang161e7732011-11-17 23:17:04 +0800146 val |= current_val;
Qipan Li5df83112013-08-12 18:15:35 +0800147 wr_regl(port, ureg->sirfsoc_afc_ctrl, val);
Qipan Li2eb56182013-08-15 06:52:15 +0800148 } else {
149 if (!val)
150 gpio_set_value(sirfport->rts_gpio, 1);
151 else
152 gpio_set_value(sirfport->rts_gpio, 0);
Rong Wang161e7732011-11-17 23:17:04 +0800153 }
154}
155
156static void sirfsoc_uart_stop_tx(struct uart_port *port)
157{
Barry Song909102d2013-08-07 13:35:38 +0800158 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800159 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
160 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800161 unsigned int regv;
Barry Song909102d2013-08-07 13:35:38 +0800162
163 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800164 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
165 wr_regl(port, ureg->sirfsoc_int_en_reg,
166 regv & ~uint_en->sirfsoc_txfifo_empty_en);
167 } else
168 wr_regl(port, SIRFUART_INT_EN_CLR,
169 uint_en->sirfsoc_txfifo_empty_en);
170
Rong Wang161e7732011-11-17 23:17:04 +0800171}
172
Jingoo Hanada1f442013-08-08 17:41:43 +0900173static void sirfsoc_uart_start_tx(struct uart_port *port)
Rong Wang161e7732011-11-17 23:17:04 +0800174{
175 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800176 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
177 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800178 unsigned long regv;
Barry Song909102d2013-08-07 13:35:38 +0800179
Rong Wang161e7732011-11-17 23:17:04 +0800180 sirfsoc_uart_pio_tx_chars(sirfport, 1);
Qipan Li5df83112013-08-12 18:15:35 +0800181 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
Barry Song909102d2013-08-07 13:35:38 +0800182 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800183 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
184 wr_regl(port, ureg->sirfsoc_int_en_reg, regv |
185 uint_en->sirfsoc_txfifo_empty_en);
186 } else
187 wr_regl(port, ureg->sirfsoc_int_en_reg,
188 uint_en->sirfsoc_txfifo_empty_en);
Rong Wang161e7732011-11-17 23:17:04 +0800189}
190
191static void sirfsoc_uart_stop_rx(struct uart_port *port)
192{
Barry Song909102d2013-08-07 13:35:38 +0800193 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800194 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
195 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
196 unsigned long reg;
197 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
Barry Song909102d2013-08-07 13:35:38 +0800198 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800199 reg = rd_regl(port, ureg->sirfsoc_int_en_reg);
200 wr_regl(port, ureg->sirfsoc_int_en_reg,
201 reg & ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
202 } else
203 wr_regl(port, SIRFUART_INT_EN_CLR,
204 SIRFUART_RX_IO_INT_EN(port, uint_en));
Rong Wang161e7732011-11-17 23:17:04 +0800205}
206
207static void sirfsoc_uart_disable_ms(struct uart_port *port)
208{
209 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800210 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
211 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800212
Rong Wang161e7732011-11-17 23:17:04 +0800213 if (!sirfport->hw_flow_ctrl)
214 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800215 sirfport->ms_enabled = false;
216 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
217 wr_regl(port, ureg->sirfsoc_afc_ctrl,
218 rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
219 if (!sirfport->is_marco)
220 wr_regl(port, ureg->sirfsoc_int_en_reg,
221 rd_regl(port, ureg->sirfsoc_int_en_reg)&
222 ~uint_en->sirfsoc_cts_en);
223 else
224 wr_regl(port, SIRFUART_INT_EN_CLR,
225 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800226 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800227 disable_irq(gpio_to_irq(sirfport->cts_gpio));
228}
229
230static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
231{
232 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
233 struct uart_port *port = &sirfport->port;
234 if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
235 uart_handle_cts_change(port,
236 !gpio_get_value(sirfport->cts_gpio));
237 return IRQ_HANDLED;
Rong Wang161e7732011-11-17 23:17:04 +0800238}
239
240static void sirfsoc_uart_enable_ms(struct uart_port *port)
241{
242 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800243 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
244 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Barry Song909102d2013-08-07 13:35:38 +0800245
Rong Wang161e7732011-11-17 23:17:04 +0800246 if (!sirfport->hw_flow_ctrl)
247 return;
Qipan Li2eb56182013-08-15 06:52:15 +0800248 sirfport->ms_enabled = true;
249 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
250 wr_regl(port, ureg->sirfsoc_afc_ctrl,
251 rd_regl(port, ureg->sirfsoc_afc_ctrl) |
252 SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
253 if (!sirfport->is_marco)
254 wr_regl(port, ureg->sirfsoc_int_en_reg,
255 rd_regl(port, ureg->sirfsoc_int_en_reg)
256 | uint_en->sirfsoc_cts_en);
257 else
258 wr_regl(port, ureg->sirfsoc_int_en_reg,
259 uint_en->sirfsoc_cts_en);
Qipan Li5df83112013-08-12 18:15:35 +0800260 } else
Qipan Li2eb56182013-08-15 06:52:15 +0800261 enable_irq(gpio_to_irq(sirfport->cts_gpio));
Rong Wang161e7732011-11-17 23:17:04 +0800262}
263
264static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
265{
Qipan Li5df83112013-08-12 18:15:35 +0800266 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
267 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
268 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
269 unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
270 if (break_state)
271 ulcon |= SIRFUART_SET_BREAK;
272 else
273 ulcon &= ~SIRFUART_SET_BREAK;
274 wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
275 }
Rong Wang161e7732011-11-17 23:17:04 +0800276}
277
278static unsigned int
279sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
280{
Qipan Li5df83112013-08-12 18:15:35 +0800281 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
282 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
283 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800284 unsigned int ch, rx_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800285 struct tty_struct *tty;
286 tty = tty_port_tty_get(&port->state->port);
287 if (!tty)
288 return -ENODEV;
289 while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
290 ufifo_st->ff_empty(port->line))) {
291 ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
292 SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800293 if (unlikely(uart_handle_sysrq_char(port, ch)))
294 continue;
295 uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
296 rx_count++;
297 if (rx_count >= max_rx_count)
298 break;
299 }
300
301 port->icount.rx += rx_count;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100302 tty_flip_buffer_push(&port->state->port);
Rong Wang161e7732011-11-17 23:17:04 +0800303
304 return rx_count;
305}
306
307static unsigned int
308sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
309{
310 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800311 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
312 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800313 struct circ_buf *xmit = &port->state->xmit;
314 unsigned int num_tx = 0;
315 while (!uart_circ_empty(xmit) &&
Qipan Li5df83112013-08-12 18:15:35 +0800316 !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
317 ufifo_st->ff_full(port->line)) &&
Rong Wang161e7732011-11-17 23:17:04 +0800318 count--) {
Qipan Li5df83112013-08-12 18:15:35 +0800319 wr_regl(port, ureg->sirfsoc_tx_fifo_data,
320 xmit->buf[xmit->tail]);
Rong Wang161e7732011-11-17 23:17:04 +0800321 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
322 port->icount.tx++;
323 num_tx++;
324 }
325 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
326 uart_write_wakeup(port);
327 return num_tx;
328}
329
330static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
331{
332 unsigned long intr_status;
333 unsigned long cts_status;
334 unsigned long flag = TTY_NORMAL;
335 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
336 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800337 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
338 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
339 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
340 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800341 struct uart_state *state = port->state;
342 struct circ_buf *xmit = &port->state->xmit;
Barry Song5425e032012-12-25 17:32:04 +0800343 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800344 intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
345 wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
346 if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
347 if (intr_status & uint_st->sirfsoc_rxd_brk) {
348 port->icount.brk++;
Rong Wang161e7732011-11-17 23:17:04 +0800349 if (uart_handle_break(port))
350 goto recv_char;
Rong Wang161e7732011-11-17 23:17:04 +0800351 }
Qipan Li5df83112013-08-12 18:15:35 +0800352 if (intr_status & uint_st->sirfsoc_rx_oflow)
Rong Wang161e7732011-11-17 23:17:04 +0800353 port->icount.overrun++;
Qipan Li5df83112013-08-12 18:15:35 +0800354 if (intr_status & uint_st->sirfsoc_frm_err) {
Rong Wang161e7732011-11-17 23:17:04 +0800355 port->icount.frame++;
356 flag = TTY_FRAME;
357 }
Qipan Li5df83112013-08-12 18:15:35 +0800358 if (intr_status & uint_st->sirfsoc_parity_err)
Rong Wang161e7732011-11-17 23:17:04 +0800359 flag = TTY_PARITY;
Qipan Li5df83112013-08-12 18:15:35 +0800360 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
361 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
362 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800363 intr_status &= port->read_status_mask;
364 uart_insert_char(port, intr_status,
Qipan Li5df83112013-08-12 18:15:35 +0800365 uint_en->sirfsoc_rx_oflow_en, 0, flag);
366 tty_flip_buffer_push(&state->port);
Rong Wang161e7732011-11-17 23:17:04 +0800367 }
368recv_char:
Qipan Li5df83112013-08-12 18:15:35 +0800369 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
370 (intr_status & SIRFUART_CTS_INT_ST(uint_st))) {
371 cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
372 SIRFUART_AFC_CTS_STATUS;
373 if (cts_status != 0)
374 cts_status = 0;
375 else
376 cts_status = 1;
377 uart_handle_cts_change(port, cts_status);
378 wake_up_interruptible(&state->port.delta_msr_wait);
Rong Wang161e7732011-11-17 23:17:04 +0800379 }
Qipan Li5df83112013-08-12 18:15:35 +0800380 if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
Rong Wang161e7732011-11-17 23:17:04 +0800381 sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
Qipan Li5df83112013-08-12 18:15:35 +0800382 if (intr_status & uint_st->sirfsoc_txfifo_empty) {
Rong Wang161e7732011-11-17 23:17:04 +0800383 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
Barry Song5425e032012-12-25 17:32:04 +0800384 spin_unlock(&port->lock);
Rong Wang161e7732011-11-17 23:17:04 +0800385 return IRQ_HANDLED;
386 } else {
387 sirfsoc_uart_pio_tx_chars(sirfport,
388 SIRFSOC_UART_IO_TX_REASONABLE_CNT);
389 if ((uart_circ_empty(xmit)) &&
Qipan Li5df83112013-08-12 18:15:35 +0800390 (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
391 ufifo_st->ff_empty(port->line)))
Rong Wang161e7732011-11-17 23:17:04 +0800392 sirfsoc_uart_stop_tx(port);
393 }
394 }
Barry Song5425e032012-12-25 17:32:04 +0800395 spin_unlock(&port->lock);
Rong Wang161e7732011-11-17 23:17:04 +0800396 return IRQ_HANDLED;
397}
398
399static void sirfsoc_uart_start_rx(struct uart_port *port)
400{
Barry Song909102d2013-08-07 13:35:38 +0800401 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800402 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
403 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
404 unsigned long regv;
Barry Song909102d2013-08-07 13:35:38 +0800405 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800406 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
407 wr_regl(port, ureg->sirfsoc_int_en_reg, regv |
408 SIRFUART_RX_IO_INT_EN(port, uint_en));
409 } else
410 wr_regl(port, ureg->sirfsoc_int_en_reg,
411 SIRFUART_RX_IO_INT_EN(port, uint_en));
412 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
413 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
414 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800415}
416
417static unsigned int
Qipan Li5df83112013-08-12 18:15:35 +0800418sirfsoc_usp_calc_sample_div(unsigned long set_rate,
419 unsigned long ioclk_rate, unsigned long *sample_reg)
420{
421 unsigned long min_delta = ~0UL;
422 unsigned short sample_div;
423 unsigned long ioclk_div = 0;
424 unsigned long temp_delta;
425
426 for (sample_div = SIRF_MIN_SAMPLE_DIV;
427 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
428 temp_delta = ioclk_rate -
429 (ioclk_rate + (set_rate * sample_div) / 2)
430 / (set_rate * sample_div) * set_rate * sample_div;
431
432 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
433 if (temp_delta < min_delta) {
434 ioclk_div = (2 * ioclk_rate /
435 (set_rate * sample_div) + 1) / 2 - 1;
436 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
437 continue;
438 min_delta = temp_delta;
439 *sample_reg = sample_div;
440 if (!temp_delta)
441 break;
442 }
443 }
444 return ioclk_div;
445}
446
447static unsigned int
448sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
449 unsigned long ioclk_rate, unsigned long *set_baud)
Rong Wang161e7732011-11-17 23:17:04 +0800450{
451 unsigned long min_delta = ~0UL;
452 unsigned short sample_div;
453 unsigned int regv = 0;
454 unsigned long ioclk_div;
455 unsigned long baud_tmp;
456 int temp_delta;
457
458 for (sample_div = SIRF_MIN_SAMPLE_DIV;
459 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
460 ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
461 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
462 continue;
463 baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
464 temp_delta = baud_tmp - baud_rate;
465 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
466 if (temp_delta < min_delta) {
467 regv = regv & (~SIRF_IOCLK_DIV_MASK);
468 regv = regv | ioclk_div;
469 regv = regv & (~SIRF_SAMPLE_DIV_MASK);
470 regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
471 min_delta = temp_delta;
Qipan Li5df83112013-08-12 18:15:35 +0800472 *set_baud = baud_tmp;
Rong Wang161e7732011-11-17 23:17:04 +0800473 }
474 }
475 return regv;
476}
477
478static void sirfsoc_uart_set_termios(struct uart_port *port,
479 struct ktermios *termios,
480 struct ktermios *old)
481{
482 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800483 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
484 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800485 unsigned long config_reg = 0;
486 unsigned long baud_rate;
Qipan Li5df83112013-08-12 18:15:35 +0800487 unsigned long set_baud;
Rong Wang161e7732011-11-17 23:17:04 +0800488 unsigned long flags;
489 unsigned long ic;
490 unsigned int clk_div_reg = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800491 unsigned long temp_reg_val, ioclk_rate;
Rong Wang161e7732011-11-17 23:17:04 +0800492 unsigned long rx_time_out;
493 int threshold_div;
494 int temp;
Qipan Li5df83112013-08-12 18:15:35 +0800495 u32 data_bit_len, stop_bit_len, len_val;
496 unsigned long sample_div_reg = 0xf;
497 ioclk_rate = port->uartclk;
Rong Wang161e7732011-11-17 23:17:04 +0800498
Rong Wang161e7732011-11-17 23:17:04 +0800499 switch (termios->c_cflag & CSIZE) {
500 default:
501 case CS8:
Qipan Li5df83112013-08-12 18:15:35 +0800502 data_bit_len = 8;
Rong Wang161e7732011-11-17 23:17:04 +0800503 config_reg |= SIRFUART_DATA_BIT_LEN_8;
504 break;
505 case CS7:
Qipan Li5df83112013-08-12 18:15:35 +0800506 data_bit_len = 7;
Rong Wang161e7732011-11-17 23:17:04 +0800507 config_reg |= SIRFUART_DATA_BIT_LEN_7;
508 break;
509 case CS6:
Qipan Li5df83112013-08-12 18:15:35 +0800510 data_bit_len = 6;
Rong Wang161e7732011-11-17 23:17:04 +0800511 config_reg |= SIRFUART_DATA_BIT_LEN_6;
512 break;
513 case CS5:
Qipan Li5df83112013-08-12 18:15:35 +0800514 data_bit_len = 5;
Rong Wang161e7732011-11-17 23:17:04 +0800515 config_reg |= SIRFUART_DATA_BIT_LEN_5;
516 break;
517 }
Qipan Li5df83112013-08-12 18:15:35 +0800518 if (termios->c_cflag & CSTOPB) {
Rong Wang161e7732011-11-17 23:17:04 +0800519 config_reg |= SIRFUART_STOP_BIT_LEN_2;
Qipan Li5df83112013-08-12 18:15:35 +0800520 stop_bit_len = 2;
521 } else
522 stop_bit_len = 1;
523
Rong Wang161e7732011-11-17 23:17:04 +0800524 spin_lock_irqsave(&port->lock, flags);
Qipan Li5df83112013-08-12 18:15:35 +0800525 port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
Rong Wang161e7732011-11-17 23:17:04 +0800526 port->ignore_status_mask = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800527 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
528 if (termios->c_iflag & INPCK)
529 port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
530 uint_en->sirfsoc_parity_err_en;
Qipan Li2eb56182013-08-15 06:52:15 +0800531 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800532 if (termios->c_iflag & INPCK)
533 port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
534 }
Rong Wang161e7732011-11-17 23:17:04 +0800535 if (termios->c_iflag & (BRKINT | PARMRK))
Qipan Li5df83112013-08-12 18:15:35 +0800536 port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
537 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
538 if (termios->c_iflag & IGNPAR)
539 port->ignore_status_mask |=
540 uint_en->sirfsoc_frm_err_en |
541 uint_en->sirfsoc_parity_err_en;
542 if (termios->c_cflag & PARENB) {
543 if (termios->c_cflag & CMSPAR) {
544 if (termios->c_cflag & PARODD)
545 config_reg |= SIRFUART_STICK_BIT_MARK;
546 else
547 config_reg |= SIRFUART_STICK_BIT_SPACE;
548 } else if (termios->c_cflag & PARODD) {
549 config_reg |= SIRFUART_STICK_BIT_ODD;
550 } else {
551 config_reg |= SIRFUART_STICK_BIT_EVEN;
552 }
Rong Wang161e7732011-11-17 23:17:04 +0800553 }
Qipan Li2eb56182013-08-15 06:52:15 +0800554 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800555 if (termios->c_iflag & IGNPAR)
556 port->ignore_status_mask |=
557 uint_en->sirfsoc_frm_err_en;
558 if (termios->c_cflag & PARENB)
559 dev_warn(port->dev,
560 "USP-UART not support parity err\n");
561 }
562 if (termios->c_iflag & IGNBRK) {
563 port->ignore_status_mask |=
564 uint_en->sirfsoc_rxd_brk_en;
565 if (termios->c_iflag & IGNPAR)
566 port->ignore_status_mask |=
567 uint_en->sirfsoc_rx_oflow_en;
568 }
569 if ((termios->c_cflag & CREAD) == 0)
570 port->ignore_status_mask |= SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800571 /* Hardware Flow Control Settings */
572 if (UART_ENABLE_MS(port, termios->c_cflag)) {
573 if (!sirfport->ms_enabled)
574 sirfsoc_uart_enable_ms(port);
575 } else {
576 if (sirfport->ms_enabled)
577 sirfsoc_uart_disable_ms(port);
578 }
Qipan Li5df83112013-08-12 18:15:35 +0800579 baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
580 if (ioclk_rate == 150000000) {
Barry Songac4ce712013-01-16 14:49:27 +0800581 for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
582 if (baud_rate == baudrate_to_regv[ic].baud_rate)
583 clk_div_reg = baudrate_to_regv[ic].reg_val;
584 }
Qipan Li5df83112013-08-12 18:15:35 +0800585 set_baud = baud_rate;
586 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
587 if (unlikely(clk_div_reg == 0))
588 clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
589 ioclk_rate, &set_baud);
590 wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
Qipan Li2eb56182013-08-15 06:52:15 +0800591 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800592 clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
593 ioclk_rate, &sample_div_reg);
594 sample_div_reg--;
595 set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
596 (sample_div_reg + 1));
597 /* setting usp mode 2 */
598 len_val = ((1 << 0) | (1 << 8));
599 len_val |= ((clk_div_reg & 0x3ff) << 21);
600 wr_regl(port, ureg->sirfsoc_mode2,
601 len_val);
Barry Songac4ce712013-01-16 14:49:27 +0800602
Qipan Li5df83112013-08-12 18:15:35 +0800603 }
Rong Wang161e7732011-11-17 23:17:04 +0800604 if (tty_termios_baud_rate(termios))
Qipan Li5df83112013-08-12 18:15:35 +0800605 tty_termios_encode_baud_rate(termios, set_baud, set_baud);
606 /* set receive timeout && data bits len */
607 rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
608 rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
609 temp_reg_val = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
610 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
611 wr_regl(port, ureg->sirfsoc_tx_fifo_op,
612 (temp_reg_val & ~SIRFUART_FIFO_START));
613 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
614 config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
615 wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
Qipan Li2eb56182013-08-15 06:52:15 +0800616 } else {
Qipan Li5df83112013-08-12 18:15:35 +0800617 /*tx frame ctrl*/
618 len_val = (data_bit_len - 1) << 0;
619 len_val |= (data_bit_len + 1 + stop_bit_len - 1) << 16;
620 len_val |= ((data_bit_len - 1) << 24);
621 len_val |= (((clk_div_reg & 0xc00) >> 10) << 30);
622 wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
623 /*rx frame ctrl*/
624 len_val = (data_bit_len - 1) << 0;
625 len_val |= (data_bit_len + 1 + stop_bit_len - 1) << 8;
626 len_val |= (data_bit_len - 1) << 16;
627 len_val |= (((clk_div_reg & 0xf000) >> 12) << 24);
628 wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
629 /*async param*/
630 wr_regl(port, ureg->sirfsoc_async_param_reg,
631 (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
632 (sample_div_reg & 0x3f) << 16);
633 }
634 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
635 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
Rong Wang161e7732011-11-17 23:17:04 +0800636 /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
Qipan Li5df83112013-08-12 18:15:35 +0800637 if (set_baud < 1000000)
Rong Wang161e7732011-11-17 23:17:04 +0800638 threshold_div = 1;
639 else
640 threshold_div = 2;
Qipan Li5df83112013-08-12 18:15:35 +0800641 temp = SIRFUART_FIFO_THD(port);
642 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, temp / threshold_div);
643 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, temp / threshold_div);
644 temp_reg_val |= SIRFUART_FIFO_START;
645 wr_regl(port, ureg->sirfsoc_tx_fifo_op, temp_reg_val);
646 uart_update_timeout(port, termios->c_cflag, set_baud);
Rong Wang161e7732011-11-17 23:17:04 +0800647 sirfsoc_uart_start_rx(port);
Qipan Li5df83112013-08-12 18:15:35 +0800648 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
Rong Wang161e7732011-11-17 23:17:04 +0800649 spin_unlock_irqrestore(&port->lock, flags);
650}
651
Rong Wang161e7732011-11-17 23:17:04 +0800652static int sirfsoc_uart_startup(struct uart_port *port)
653{
654 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li15cdcb12013-08-19 11:47:52 +0800655 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800656 unsigned int index = port->line;
657 int ret;
658 set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
659 ret = request_irq(port->irq,
660 sirfsoc_uart_isr,
661 0,
662 SIRFUART_PORT_NAME,
663 sirfport);
664 if (ret != 0) {
665 dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
666 index, port->irq);
667 goto irq_err;
668 }
Qipan Li15cdcb12013-08-19 11:47:52 +0800669
670 /* initial hardware settings */
671 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
672 rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
673 SIRFUART_IO_MODE);
674 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
675 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
676 SIRFUART_IO_MODE);
677 wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
678 wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
679 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
680 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
681 wr_regl(port, ureg->sirfsoc_mode1,
682 SIRFSOC_USP_ENDIAN_CTRL_LSBF |
683 SIRFSOC_USP_EN);
684 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
685 wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
686 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
687 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
688 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
689 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
Qipan Li2eb56182013-08-15 06:52:15 +0800690
691 sirfport->ms_enabled = false;
692 if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
693 sirfport->hw_flow_ctrl) {
694 set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
695 IRQF_VALID | IRQF_NOAUTOEN);
696 ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
697 sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
698 IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
699 if (ret != 0) {
700 dev_err(port->dev, "UART-USP:request gpio irq fail\n");
701 goto init_rx_err;
702 }
703 }
704
Rong Wang161e7732011-11-17 23:17:04 +0800705 enable_irq(port->irq);
Qipan Li2eb56182013-08-15 06:52:15 +0800706
Qipan Li15cdcb12013-08-19 11:47:52 +0800707 return 0;
Qipan Li2eb56182013-08-15 06:52:15 +0800708init_rx_err:
709 free_irq(port->irq, sirfport);
Rong Wang161e7732011-11-17 23:17:04 +0800710irq_err:
711 return ret;
712}
713
714static void sirfsoc_uart_shutdown(struct uart_port *port)
715{
716 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800717 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Barry Song909102d2013-08-07 13:35:38 +0800718 if (!sirfport->is_marco)
Qipan Li5df83112013-08-12 18:15:35 +0800719 wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
Barry Song909102d2013-08-07 13:35:38 +0800720 else
721 wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
722
Rong Wang161e7732011-11-17 23:17:04 +0800723 free_irq(port->irq, sirfport);
Qipan Li2eb56182013-08-15 06:52:15 +0800724 if (sirfport->ms_enabled)
Rong Wang161e7732011-11-17 23:17:04 +0800725 sirfsoc_uart_disable_ms(port);
Qipan Li2eb56182013-08-15 06:52:15 +0800726 if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
727 sirfport->hw_flow_ctrl) {
728 gpio_set_value(sirfport->rts_gpio, 1);
729 free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
Rong Wang161e7732011-11-17 23:17:04 +0800730 }
731}
732
733static const char *sirfsoc_uart_type(struct uart_port *port)
734{
735 return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
736}
737
738static int sirfsoc_uart_request_port(struct uart_port *port)
739{
Qipan Li5df83112013-08-12 18:15:35 +0800740 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
741 struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param;
Rong Wang161e7732011-11-17 23:17:04 +0800742 void *ret;
743 ret = request_mem_region(port->mapbase,
Qipan Li5df83112013-08-12 18:15:35 +0800744 SIRFUART_MAP_SIZE, uart_param->port_name);
Rong Wang161e7732011-11-17 23:17:04 +0800745 return ret ? 0 : -EBUSY;
746}
747
748static void sirfsoc_uart_release_port(struct uart_port *port)
749{
750 release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
751}
752
753static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
754{
755 if (flags & UART_CONFIG_TYPE) {
756 port->type = SIRFSOC_PORT_TYPE;
757 sirfsoc_uart_request_port(port);
758 }
759}
760
761static struct uart_ops sirfsoc_uart_ops = {
762 .tx_empty = sirfsoc_uart_tx_empty,
763 .get_mctrl = sirfsoc_uart_get_mctrl,
764 .set_mctrl = sirfsoc_uart_set_mctrl,
765 .stop_tx = sirfsoc_uart_stop_tx,
766 .start_tx = sirfsoc_uart_start_tx,
767 .stop_rx = sirfsoc_uart_stop_rx,
768 .enable_ms = sirfsoc_uart_enable_ms,
769 .break_ctl = sirfsoc_uart_break_ctl,
770 .startup = sirfsoc_uart_startup,
771 .shutdown = sirfsoc_uart_shutdown,
772 .set_termios = sirfsoc_uart_set_termios,
773 .type = sirfsoc_uart_type,
774 .release_port = sirfsoc_uart_release_port,
775 .request_port = sirfsoc_uart_request_port,
776 .config_port = sirfsoc_uart_config_port,
777};
778
779#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
Qipan Li5df83112013-08-12 18:15:35 +0800780static int __init
781sirfsoc_uart_console_setup(struct console *co, char *options)
Rong Wang161e7732011-11-17 23:17:04 +0800782{
783 unsigned int baud = 115200;
784 unsigned int bits = 8;
785 unsigned int parity = 'n';
786 unsigned int flow = 'n';
787 struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
Qipan Li5df83112013-08-12 18:15:35 +0800788 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
789 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800790 if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
791 return -EINVAL;
792
793 if (!port->mapbase)
794 return -ENODEV;
795
Qipan Li5df83112013-08-12 18:15:35 +0800796 /* enable usp in mode1 register */
797 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
798 wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
799 SIRFSOC_USP_ENDIAN_CTRL_LSBF);
Rong Wang161e7732011-11-17 23:17:04 +0800800 if (options)
801 uart_parse_options(options, &baud, &parity, &bits, &flow);
802 port->cons = co;
Qipan Li5df83112013-08-12 18:15:35 +0800803
Rong Wang161e7732011-11-17 23:17:04 +0800804 return uart_set_options(port, co, baud, parity, bits, flow);
805}
806
807static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
808{
Qipan Li5df83112013-08-12 18:15:35 +0800809 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
810 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
811 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800812 while (rd_regl(port,
Qipan Li5df83112013-08-12 18:15:35 +0800813 ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
Rong Wang161e7732011-11-17 23:17:04 +0800814 cpu_relax();
Qipan Li5df83112013-08-12 18:15:35 +0800815 wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
Rong Wang161e7732011-11-17 23:17:04 +0800816}
817
818static void sirfsoc_uart_console_write(struct console *co, const char *s,
819 unsigned int count)
820{
821 struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
822 uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
823}
824
825static struct console sirfsoc_uart_console = {
826 .name = SIRFSOC_UART_NAME,
827 .device = uart_console_device,
828 .flags = CON_PRINTBUFFER,
829 .index = -1,
830 .write = sirfsoc_uart_console_write,
831 .setup = sirfsoc_uart_console_setup,
832 .data = &sirfsoc_uart_drv,
833};
834
835static int __init sirfsoc_uart_console_init(void)
836{
837 register_console(&sirfsoc_uart_console);
838 return 0;
839}
840console_initcall(sirfsoc_uart_console_init);
841#endif
842
843static struct uart_driver sirfsoc_uart_drv = {
844 .owner = THIS_MODULE,
845 .driver_name = SIRFUART_PORT_NAME,
846 .nr = SIRFSOC_UART_NR,
847 .dev_name = SIRFSOC_UART_NAME,
848 .major = SIRFSOC_UART_MAJOR,
849 .minor = SIRFSOC_UART_MINOR,
850#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
851 .cons = &sirfsoc_uart_console,
852#else
853 .cons = NULL,
854#endif
855};
856
Qipan Li5df83112013-08-12 18:15:35 +0800857static struct of_device_id sirfsoc_uart_ids[] = {
858 { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
859 { .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
860 { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
861 {}
862};
863MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
864
Jingoo Hanada1f442013-08-08 17:41:43 +0900865static int sirfsoc_uart_probe(struct platform_device *pdev)
Rong Wang161e7732011-11-17 23:17:04 +0800866{
867 struct sirfsoc_uart_port *sirfport;
868 struct uart_port *port;
869 struct resource *res;
870 int ret;
Qipan Li5df83112013-08-12 18:15:35 +0800871 const struct of_device_id *match;
Rong Wang161e7732011-11-17 23:17:04 +0800872
Qipan Li5df83112013-08-12 18:15:35 +0800873 match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
Rong Wang161e7732011-11-17 23:17:04 +0800874 if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
875 dev_err(&pdev->dev,
876 "Unable to find cell-index in uart node.\n");
877 ret = -EFAULT;
878 goto err;
879 }
Qipan Li5df83112013-08-12 18:15:35 +0800880 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
881 pdev->id += ((struct sirfsoc_uart_register *)
882 match->data)->uart_param.register_uart_nr;
Rong Wang161e7732011-11-17 23:17:04 +0800883 sirfport = &sirfsoc_uart_ports[pdev->id];
884 port = &sirfport->port;
885 port->dev = &pdev->dev;
886 port->private_data = sirfport;
Qipan Li5df83112013-08-12 18:15:35 +0800887 sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
Rong Wang161e7732011-11-17 23:17:04 +0800888
Qipan Li2eb56182013-08-15 06:52:15 +0800889 sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
890 "sirf,uart-has-rtscts");
Qipan Li5df83112013-08-12 18:15:35 +0800891 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
892 sirfport->uart_reg->uart_type = SIRF_REAL_UART;
Qipan Li2eb56182013-08-15 06:52:15 +0800893 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
Qipan Li5df83112013-08-12 18:15:35 +0800894 sirfport->uart_reg->uart_type = SIRF_USP_UART;
Qipan Li2eb56182013-08-15 06:52:15 +0800895 if (!sirfport->hw_flow_ctrl)
896 goto usp_no_flow_control;
897 if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
898 sirfport->cts_gpio = of_get_named_gpio(
899 pdev->dev.of_node, "cts-gpios", 0);
900 else
901 sirfport->cts_gpio = -1;
902 if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
903 sirfport->rts_gpio = of_get_named_gpio(
904 pdev->dev.of_node, "rts-gpios", 0);
905 else
906 sirfport->rts_gpio = -1;
907
908 if ((!gpio_is_valid(sirfport->cts_gpio) ||
909 !gpio_is_valid(sirfport->rts_gpio))) {
910 ret = -EINVAL;
911 dev_err(&pdev->dev,
Qipan Li67bc3062013-08-19 11:47:51 +0800912 "Usp flow control must have cts and rts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +0800913 goto err;
914 }
915 ret = devm_gpio_request(&pdev->dev, sirfport->cts_gpio,
Qipan Li67bc3062013-08-19 11:47:51 +0800916 "usp-cts-gpio");
Qipan Li2eb56182013-08-15 06:52:15 +0800917 if (ret) {
Qipan Li67bc3062013-08-19 11:47:51 +0800918 dev_err(&pdev->dev, "Unable request cts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +0800919 goto err;
920 }
921 gpio_direction_input(sirfport->cts_gpio);
922 ret = devm_gpio_request(&pdev->dev, sirfport->rts_gpio,
Qipan Li67bc3062013-08-19 11:47:51 +0800923 "usp-rts-gpio");
Qipan Li2eb56182013-08-15 06:52:15 +0800924 if (ret) {
Qipan Li67bc3062013-08-19 11:47:51 +0800925 dev_err(&pdev->dev, "Unable request rts gpio");
Qipan Li2eb56182013-08-15 06:52:15 +0800926 goto err;
927 }
928 gpio_direction_output(sirfport->rts_gpio, 1);
929 }
930usp_no_flow_control:
Barry Song909102d2013-08-07 13:35:38 +0800931 if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
932 sirfport->is_marco = true;
933
Rong Wang161e7732011-11-17 23:17:04 +0800934 if (of_property_read_u32(pdev->dev.of_node,
935 "fifosize",
936 &port->fifosize)) {
937 dev_err(&pdev->dev,
938 "Unable to find fifosize in uart node.\n");
939 ret = -EFAULT;
940 goto err;
941 }
942
943 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
944 if (res == NULL) {
945 dev_err(&pdev->dev, "Insufficient resources.\n");
946 ret = -EFAULT;
947 goto err;
948 }
949 port->mapbase = res->start;
950 port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
951 if (!port->membase) {
952 dev_err(&pdev->dev, "Cannot remap resource.\n");
953 ret = -ENOMEM;
954 goto err;
955 }
956 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
957 if (res == NULL) {
958 dev_err(&pdev->dev, "Insufficient resources.\n");
959 ret = -EFAULT;
Julia Lawall9250dd52012-09-01 18:33:09 +0200960 goto err;
Rong Wang161e7732011-11-17 23:17:04 +0800961 }
962 port->irq = res->start;
963
Barry Songac4ce712013-01-16 14:49:27 +0800964 sirfport->clk = clk_get(&pdev->dev, NULL);
965 if (IS_ERR(sirfport->clk)) {
966 ret = PTR_ERR(sirfport->clk);
Barry Songa3437562013-08-15 06:52:14 +0800967 goto err;
Barry Songac4ce712013-01-16 14:49:27 +0800968 }
969 clk_prepare_enable(sirfport->clk);
970 port->uartclk = clk_get_rate(sirfport->clk);
971
Rong Wang161e7732011-11-17 23:17:04 +0800972 port->ops = &sirfsoc_uart_ops;
973 spin_lock_init(&port->lock);
974
975 platform_set_drvdata(pdev, sirfport);
976 ret = uart_add_one_port(&sirfsoc_uart_drv, port);
977 if (ret != 0) {
978 dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
979 goto port_err;
980 }
981
982 return 0;
983
984port_err:
Barry Songac4ce712013-01-16 14:49:27 +0800985 clk_disable_unprepare(sirfport->clk);
986 clk_put(sirfport->clk);
Rong Wang161e7732011-11-17 23:17:04 +0800987err:
988 return ret;
989}
990
991static int sirfsoc_uart_remove(struct platform_device *pdev)
992{
993 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
994 struct uart_port *port = &sirfport->port;
Barry Songac4ce712013-01-16 14:49:27 +0800995 clk_disable_unprepare(sirfport->clk);
996 clk_put(sirfport->clk);
Rong Wang161e7732011-11-17 23:17:04 +0800997 uart_remove_one_port(&sirfsoc_uart_drv, port);
998 return 0;
999}
1000
1001static int
1002sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
1003{
1004 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
1005 struct uart_port *port = &sirfport->port;
1006 uart_suspend_port(&sirfsoc_uart_drv, port);
1007 return 0;
1008}
1009
1010static int sirfsoc_uart_resume(struct platform_device *pdev)
1011{
1012 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
1013 struct uart_port *port = &sirfport->port;
1014 uart_resume_port(&sirfsoc_uart_drv, port);
1015 return 0;
1016}
1017
Rong Wang161e7732011-11-17 23:17:04 +08001018static struct platform_driver sirfsoc_uart_driver = {
1019 .probe = sirfsoc_uart_probe,
Bill Pemberton2d47b712012-11-19 13:21:34 -05001020 .remove = sirfsoc_uart_remove,
Rong Wang161e7732011-11-17 23:17:04 +08001021 .suspend = sirfsoc_uart_suspend,
1022 .resume = sirfsoc_uart_resume,
1023 .driver = {
1024 .name = SIRFUART_PORT_NAME,
1025 .owner = THIS_MODULE,
1026 .of_match_table = sirfsoc_uart_ids,
1027 },
1028};
1029
1030static int __init sirfsoc_uart_init(void)
1031{
1032 int ret = 0;
1033
1034 ret = uart_register_driver(&sirfsoc_uart_drv);
1035 if (ret)
1036 goto out;
1037
1038 ret = platform_driver_register(&sirfsoc_uart_driver);
1039 if (ret)
1040 uart_unregister_driver(&sirfsoc_uart_drv);
1041out:
1042 return ret;
1043}
1044module_init(sirfsoc_uart_init);
1045
1046static void __exit sirfsoc_uart_exit(void)
1047{
1048 platform_driver_unregister(&sirfsoc_uart_driver);
1049 uart_unregister_driver(&sirfsoc_uart_drv);
1050}
1051module_exit(sirfsoc_uart_exit);
1052
1053MODULE_LICENSE("GPL v2");
1054MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
1055MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");