blob: f8a4d34ce3821d3e926a53f5a996f166c3e733f4 [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>
23#include <asm/irq.h>
24#include <asm/mach/irq.h>
Linus Walleij5c9bdc32012-02-16 19:36:21 +010025#include <linux/pinctrl/consumer.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;
Rong Wang161e7732011-11-17 23:17:04 +0800114 if (!(sirfport->ms_enabled)) {
115 goto cts_asserted;
116 } else if (sirfport->hw_flow_ctrl) {
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;
122 }
123cts_deasserted:
124 return TIOCM_CAR | TIOCM_DSR;
125cts_asserted:
126 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
127}
128
129static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
130{
131 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800132 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800133 unsigned int assert = mctrl & TIOCM_RTS;
134 unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
135 unsigned int current_val;
136 if (sirfport->hw_flow_ctrl) {
Qipan Li5df83112013-08-12 18:15:35 +0800137 current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF;
Rong Wang161e7732011-11-17 23:17:04 +0800138 val |= current_val;
Qipan Li5df83112013-08-12 18:15:35 +0800139 wr_regl(port, ureg->sirfsoc_afc_ctrl, val);
Rong Wang161e7732011-11-17 23:17:04 +0800140 }
141}
142
143static void sirfsoc_uart_stop_tx(struct uart_port *port)
144{
Barry Song909102d2013-08-07 13:35:38 +0800145 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800146 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
147 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800148 unsigned int regv;
Barry Song909102d2013-08-07 13:35:38 +0800149
150 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800151 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
152 wr_regl(port, ureg->sirfsoc_int_en_reg,
153 regv & ~uint_en->sirfsoc_txfifo_empty_en);
154 } else
155 wr_regl(port, SIRFUART_INT_EN_CLR,
156 uint_en->sirfsoc_txfifo_empty_en);
157
Rong Wang161e7732011-11-17 23:17:04 +0800158}
159
160void sirfsoc_uart_start_tx(struct uart_port *port)
161{
162 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800163 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
164 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800165 unsigned long regv;
Barry Song909102d2013-08-07 13:35:38 +0800166
Rong Wang161e7732011-11-17 23:17:04 +0800167 sirfsoc_uart_pio_tx_chars(sirfport, 1);
Qipan Li5df83112013-08-12 18:15:35 +0800168 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
Barry Song909102d2013-08-07 13:35:38 +0800169 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800170 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
171 wr_regl(port, ureg->sirfsoc_int_en_reg, regv |
172 uint_en->sirfsoc_txfifo_empty_en);
173 } else
174 wr_regl(port, ureg->sirfsoc_int_en_reg,
175 uint_en->sirfsoc_txfifo_empty_en);
Rong Wang161e7732011-11-17 23:17:04 +0800176}
177
178static void sirfsoc_uart_stop_rx(struct uart_port *port)
179{
Barry Song909102d2013-08-07 13:35:38 +0800180 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800181 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
182 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
183 unsigned long reg;
184 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
Barry Song909102d2013-08-07 13:35:38 +0800185 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800186 reg = rd_regl(port, ureg->sirfsoc_int_en_reg);
187 wr_regl(port, ureg->sirfsoc_int_en_reg,
188 reg & ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
189 } else
190 wr_regl(port, SIRFUART_INT_EN_CLR,
191 SIRFUART_RX_IO_INT_EN(port, uint_en));
Rong Wang161e7732011-11-17 23:17:04 +0800192}
193
194static void sirfsoc_uart_disable_ms(struct uart_port *port)
195{
196 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800197 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
198 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800199 unsigned long reg;
Barry Song909102d2013-08-07 13:35:38 +0800200
Rong Wang161e7732011-11-17 23:17:04 +0800201 sirfport->ms_enabled = 0;
202 if (!sirfport->hw_flow_ctrl)
203 return;
Barry Song909102d2013-08-07 13:35:38 +0800204
Qipan Li5df83112013-08-12 18:15:35 +0800205 reg = rd_regl(port, ureg->sirfsoc_afc_ctrl);
206 wr_regl(port, ureg->sirfsoc_afc_ctrl, reg & ~0x3FF);
Barry Song909102d2013-08-07 13:35:38 +0800207 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800208 reg = rd_regl(port, ureg->sirfsoc_int_en_reg);
209 wr_regl(port, ureg->sirfsoc_int_en_reg,
210 reg & ~uint_en->sirfsoc_cts_en);
211 } else
212 wr_regl(port, SIRFUART_INT_EN_CLR,
213 uint_en->sirfsoc_cts_en);
Rong Wang161e7732011-11-17 23:17:04 +0800214}
215
216static void sirfsoc_uart_enable_ms(struct uart_port *port)
217{
218 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800219 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
220 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800221 unsigned long reg;
222 unsigned long flg;
Barry Song909102d2013-08-07 13:35:38 +0800223
Rong Wang161e7732011-11-17 23:17:04 +0800224 if (!sirfport->hw_flow_ctrl)
225 return;
Qipan Li5df83112013-08-12 18:15:35 +0800226 flg = SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN;
227 reg = rd_regl(port, ureg->sirfsoc_afc_ctrl);
228 wr_regl(port, ureg->sirfsoc_afc_ctrl, reg | flg);
Barry Song909102d2013-08-07 13:35:38 +0800229 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800230 reg = rd_regl(port, ureg->sirfsoc_int_en_reg);
231 wr_regl(port, ureg->sirfsoc_int_en_reg,
232 reg | uint_en->sirfsoc_cts_en);
233 } else
234 wr_regl(port, ureg->sirfsoc_int_en_reg,
235 uint_en->sirfsoc_cts_en);
Rong Wang161e7732011-11-17 23:17:04 +0800236 uart_handle_cts_change(port,
Qipan Li5df83112013-08-12 18:15:35 +0800237 !(rd_regl(port, ureg->sirfsoc_afc_ctrl) &
238 SIRFUART_AFC_CTS_STATUS));
Rong Wang161e7732011-11-17 23:17:04 +0800239 sirfport->ms_enabled = 1;
240}
241
242static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
243{
Qipan Li5df83112013-08-12 18:15:35 +0800244 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
245 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
246 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
247 unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
248 if (break_state)
249 ulcon |= SIRFUART_SET_BREAK;
250 else
251 ulcon &= ~SIRFUART_SET_BREAK;
252 wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
253 }
Rong Wang161e7732011-11-17 23:17:04 +0800254}
255
256static unsigned int
257sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
258{
Qipan Li5df83112013-08-12 18:15:35 +0800259 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
260 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
261 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800262 unsigned int ch, rx_count = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800263 struct tty_struct *tty;
264 tty = tty_port_tty_get(&port->state->port);
265 if (!tty)
266 return -ENODEV;
267 while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
268 ufifo_st->ff_empty(port->line))) {
269 ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
270 SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800271 if (unlikely(uart_handle_sysrq_char(port, ch)))
272 continue;
273 uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
274 rx_count++;
275 if (rx_count >= max_rx_count)
276 break;
277 }
278
279 port->icount.rx += rx_count;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100280 tty_flip_buffer_push(&port->state->port);
Rong Wang161e7732011-11-17 23:17:04 +0800281
282 return rx_count;
283}
284
285static unsigned int
286sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
287{
288 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800289 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
290 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800291 struct circ_buf *xmit = &port->state->xmit;
292 unsigned int num_tx = 0;
293 while (!uart_circ_empty(xmit) &&
Qipan Li5df83112013-08-12 18:15:35 +0800294 !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
295 ufifo_st->ff_full(port->line)) &&
Rong Wang161e7732011-11-17 23:17:04 +0800296 count--) {
Qipan Li5df83112013-08-12 18:15:35 +0800297 wr_regl(port, ureg->sirfsoc_tx_fifo_data,
298 xmit->buf[xmit->tail]);
Rong Wang161e7732011-11-17 23:17:04 +0800299 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
300 port->icount.tx++;
301 num_tx++;
302 }
303 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
304 uart_write_wakeup(port);
305 return num_tx;
306}
307
308static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
309{
310 unsigned long intr_status;
311 unsigned long cts_status;
312 unsigned long flag = TTY_NORMAL;
313 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
314 struct uart_port *port = &sirfport->port;
Qipan Li5df83112013-08-12 18:15:35 +0800315 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
316 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
317 struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
318 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800319 struct uart_state *state = port->state;
320 struct circ_buf *xmit = &port->state->xmit;
Barry Song5425e032012-12-25 17:32:04 +0800321 spin_lock(&port->lock);
Qipan Li5df83112013-08-12 18:15:35 +0800322 intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
323 wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
324 if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
325 if (intr_status & uint_st->sirfsoc_rxd_brk) {
326 port->icount.brk++;
Rong Wang161e7732011-11-17 23:17:04 +0800327 if (uart_handle_break(port))
328 goto recv_char;
Rong Wang161e7732011-11-17 23:17:04 +0800329 }
Qipan Li5df83112013-08-12 18:15:35 +0800330 if (intr_status & uint_st->sirfsoc_rx_oflow)
Rong Wang161e7732011-11-17 23:17:04 +0800331 port->icount.overrun++;
Qipan Li5df83112013-08-12 18:15:35 +0800332 if (intr_status & uint_st->sirfsoc_frm_err) {
Rong Wang161e7732011-11-17 23:17:04 +0800333 port->icount.frame++;
334 flag = TTY_FRAME;
335 }
Qipan Li5df83112013-08-12 18:15:35 +0800336 if (intr_status & uint_st->sirfsoc_parity_err)
Rong Wang161e7732011-11-17 23:17:04 +0800337 flag = TTY_PARITY;
Qipan Li5df83112013-08-12 18:15:35 +0800338 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
339 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
340 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800341 intr_status &= port->read_status_mask;
342 uart_insert_char(port, intr_status,
Qipan Li5df83112013-08-12 18:15:35 +0800343 uint_en->sirfsoc_rx_oflow_en, 0, flag);
344 tty_flip_buffer_push(&state->port);
Rong Wang161e7732011-11-17 23:17:04 +0800345 }
346recv_char:
Qipan Li5df83112013-08-12 18:15:35 +0800347 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
348 (intr_status & SIRFUART_CTS_INT_ST(uint_st))) {
349 cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
350 SIRFUART_AFC_CTS_STATUS;
351 if (cts_status != 0)
352 cts_status = 0;
353 else
354 cts_status = 1;
355 uart_handle_cts_change(port, cts_status);
356 wake_up_interruptible(&state->port.delta_msr_wait);
Rong Wang161e7732011-11-17 23:17:04 +0800357 }
Qipan Li5df83112013-08-12 18:15:35 +0800358 if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
Rong Wang161e7732011-11-17 23:17:04 +0800359 sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
Qipan Li5df83112013-08-12 18:15:35 +0800360 if (intr_status & uint_st->sirfsoc_txfifo_empty) {
Rong Wang161e7732011-11-17 23:17:04 +0800361 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
Barry Song5425e032012-12-25 17:32:04 +0800362 spin_unlock(&port->lock);
Rong Wang161e7732011-11-17 23:17:04 +0800363 return IRQ_HANDLED;
364 } else {
365 sirfsoc_uart_pio_tx_chars(sirfport,
366 SIRFSOC_UART_IO_TX_REASONABLE_CNT);
367 if ((uart_circ_empty(xmit)) &&
Qipan Li5df83112013-08-12 18:15:35 +0800368 (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
369 ufifo_st->ff_empty(port->line)))
Rong Wang161e7732011-11-17 23:17:04 +0800370 sirfsoc_uart_stop_tx(port);
371 }
372 }
Barry Song5425e032012-12-25 17:32:04 +0800373 spin_unlock(&port->lock);
Rong Wang161e7732011-11-17 23:17:04 +0800374 return IRQ_HANDLED;
375}
376
377static void sirfsoc_uart_start_rx(struct uart_port *port)
378{
Barry Song909102d2013-08-07 13:35:38 +0800379 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800380 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
381 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
382 unsigned long regv;
Barry Song909102d2013-08-07 13:35:38 +0800383 if (!sirfport->is_marco) {
Qipan Li5df83112013-08-12 18:15:35 +0800384 regv = rd_regl(port, ureg->sirfsoc_int_en_reg);
385 wr_regl(port, ureg->sirfsoc_int_en_reg, regv |
386 SIRFUART_RX_IO_INT_EN(port, uint_en));
387 } else
388 wr_regl(port, ureg->sirfsoc_int_en_reg,
389 SIRFUART_RX_IO_INT_EN(port, uint_en));
390 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
391 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
392 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
Rong Wang161e7732011-11-17 23:17:04 +0800393}
394
395static unsigned int
Qipan Li5df83112013-08-12 18:15:35 +0800396sirfsoc_usp_calc_sample_div(unsigned long set_rate,
397 unsigned long ioclk_rate, unsigned long *sample_reg)
398{
399 unsigned long min_delta = ~0UL;
400 unsigned short sample_div;
401 unsigned long ioclk_div = 0;
402 unsigned long temp_delta;
403
404 for (sample_div = SIRF_MIN_SAMPLE_DIV;
405 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
406 temp_delta = ioclk_rate -
407 (ioclk_rate + (set_rate * sample_div) / 2)
408 / (set_rate * sample_div) * set_rate * sample_div;
409
410 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
411 if (temp_delta < min_delta) {
412 ioclk_div = (2 * ioclk_rate /
413 (set_rate * sample_div) + 1) / 2 - 1;
414 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
415 continue;
416 min_delta = temp_delta;
417 *sample_reg = sample_div;
418 if (!temp_delta)
419 break;
420 }
421 }
422 return ioclk_div;
423}
424
425static unsigned int
426sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
427 unsigned long ioclk_rate, unsigned long *set_baud)
Rong Wang161e7732011-11-17 23:17:04 +0800428{
429 unsigned long min_delta = ~0UL;
430 unsigned short sample_div;
431 unsigned int regv = 0;
432 unsigned long ioclk_div;
433 unsigned long baud_tmp;
434 int temp_delta;
435
436 for (sample_div = SIRF_MIN_SAMPLE_DIV;
437 sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
438 ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
439 if (ioclk_div > SIRF_IOCLK_DIV_MAX)
440 continue;
441 baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
442 temp_delta = baud_tmp - baud_rate;
443 temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
444 if (temp_delta < min_delta) {
445 regv = regv & (~SIRF_IOCLK_DIV_MASK);
446 regv = regv | ioclk_div;
447 regv = regv & (~SIRF_SAMPLE_DIV_MASK);
448 regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
449 min_delta = temp_delta;
Qipan Li5df83112013-08-12 18:15:35 +0800450 *set_baud = baud_tmp;
Rong Wang161e7732011-11-17 23:17:04 +0800451 }
452 }
453 return regv;
454}
455
456static void sirfsoc_uart_set_termios(struct uart_port *port,
457 struct ktermios *termios,
458 struct ktermios *old)
459{
460 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800461 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
462 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
Rong Wang161e7732011-11-17 23:17:04 +0800463 unsigned long config_reg = 0;
464 unsigned long baud_rate;
Qipan Li5df83112013-08-12 18:15:35 +0800465 unsigned long set_baud;
Rong Wang161e7732011-11-17 23:17:04 +0800466 unsigned long flags;
467 unsigned long ic;
468 unsigned int clk_div_reg = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800469 unsigned long temp_reg_val, ioclk_rate;
Rong Wang161e7732011-11-17 23:17:04 +0800470 unsigned long rx_time_out;
471 int threshold_div;
472 int temp;
Qipan Li5df83112013-08-12 18:15:35 +0800473 u32 data_bit_len, stop_bit_len, len_val;
474 unsigned long sample_div_reg = 0xf;
475 ioclk_rate = port->uartclk;
Rong Wang161e7732011-11-17 23:17:04 +0800476
Rong Wang161e7732011-11-17 23:17:04 +0800477 switch (termios->c_cflag & CSIZE) {
478 default:
479 case CS8:
Qipan Li5df83112013-08-12 18:15:35 +0800480 data_bit_len = 8;
Rong Wang161e7732011-11-17 23:17:04 +0800481 config_reg |= SIRFUART_DATA_BIT_LEN_8;
482 break;
483 case CS7:
Qipan Li5df83112013-08-12 18:15:35 +0800484 data_bit_len = 7;
Rong Wang161e7732011-11-17 23:17:04 +0800485 config_reg |= SIRFUART_DATA_BIT_LEN_7;
486 break;
487 case CS6:
Qipan Li5df83112013-08-12 18:15:35 +0800488 data_bit_len = 6;
Rong Wang161e7732011-11-17 23:17:04 +0800489 config_reg |= SIRFUART_DATA_BIT_LEN_6;
490 break;
491 case CS5:
Qipan Li5df83112013-08-12 18:15:35 +0800492 data_bit_len = 5;
Rong Wang161e7732011-11-17 23:17:04 +0800493 config_reg |= SIRFUART_DATA_BIT_LEN_5;
494 break;
495 }
Qipan Li5df83112013-08-12 18:15:35 +0800496 if (termios->c_cflag & CSTOPB) {
Rong Wang161e7732011-11-17 23:17:04 +0800497 config_reg |= SIRFUART_STOP_BIT_LEN_2;
Qipan Li5df83112013-08-12 18:15:35 +0800498 stop_bit_len = 2;
499 } else
500 stop_bit_len = 1;
501
Rong Wang161e7732011-11-17 23:17:04 +0800502 spin_lock_irqsave(&port->lock, flags);
Qipan Li5df83112013-08-12 18:15:35 +0800503 port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
Rong Wang161e7732011-11-17 23:17:04 +0800504 port->ignore_status_mask = 0;
Qipan Li5df83112013-08-12 18:15:35 +0800505 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
506 if (termios->c_iflag & INPCK)
507 port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
508 uint_en->sirfsoc_parity_err_en;
509 }
510 if (sirfport->uart_reg->uart_type == SIRF_USP_UART) {
511 if (termios->c_iflag & INPCK)
512 port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
513 }
Rong Wang161e7732011-11-17 23:17:04 +0800514 if (termios->c_iflag & (BRKINT | PARMRK))
Qipan Li5df83112013-08-12 18:15:35 +0800515 port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
516 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
517 if (termios->c_iflag & IGNPAR)
518 port->ignore_status_mask |=
519 uint_en->sirfsoc_frm_err_en |
520 uint_en->sirfsoc_parity_err_en;
521 if (termios->c_cflag & PARENB) {
522 if (termios->c_cflag & CMSPAR) {
523 if (termios->c_cflag & PARODD)
524 config_reg |= SIRFUART_STICK_BIT_MARK;
525 else
526 config_reg |= SIRFUART_STICK_BIT_SPACE;
527 } else if (termios->c_cflag & PARODD) {
528 config_reg |= SIRFUART_STICK_BIT_ODD;
529 } else {
530 config_reg |= SIRFUART_STICK_BIT_EVEN;
531 }
Rong Wang161e7732011-11-17 23:17:04 +0800532 }
533 }
Qipan Li5df83112013-08-12 18:15:35 +0800534 if (sirfport->uart_reg->uart_type == SIRF_USP_UART) {
535 if (termios->c_iflag & IGNPAR)
536 port->ignore_status_mask |=
537 uint_en->sirfsoc_frm_err_en;
538 if (termios->c_cflag & PARENB)
539 dev_warn(port->dev,
540 "USP-UART not support parity err\n");
541 }
542 if (termios->c_iflag & IGNBRK) {
543 port->ignore_status_mask |=
544 uint_en->sirfsoc_rxd_brk_en;
545 if (termios->c_iflag & IGNPAR)
546 port->ignore_status_mask |=
547 uint_en->sirfsoc_rx_oflow_en;
548 }
549 if ((termios->c_cflag & CREAD) == 0)
550 port->ignore_status_mask |= SIRFUART_DUMMY_READ;
Rong Wang161e7732011-11-17 23:17:04 +0800551 /* Hardware Flow Control Settings */
552 if (UART_ENABLE_MS(port, termios->c_cflag)) {
553 if (!sirfport->ms_enabled)
554 sirfsoc_uart_enable_ms(port);
555 } else {
556 if (sirfport->ms_enabled)
557 sirfsoc_uart_disable_ms(port);
558 }
Qipan Li5df83112013-08-12 18:15:35 +0800559 baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
560 if (ioclk_rate == 150000000) {
Barry Songac4ce712013-01-16 14:49:27 +0800561 for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
562 if (baud_rate == baudrate_to_regv[ic].baud_rate)
563 clk_div_reg = baudrate_to_regv[ic].reg_val;
564 }
Qipan Li5df83112013-08-12 18:15:35 +0800565 set_baud = baud_rate;
566 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
567 if (unlikely(clk_div_reg == 0))
568 clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
569 ioclk_rate, &set_baud);
570 wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
571 }
572 if (sirfport->uart_reg->uart_type == SIRF_USP_UART) {
573 clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
574 ioclk_rate, &sample_div_reg);
575 sample_div_reg--;
576 set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
577 (sample_div_reg + 1));
578 /* setting usp mode 2 */
579 len_val = ((1 << 0) | (1 << 8));
580 len_val |= ((clk_div_reg & 0x3ff) << 21);
581 wr_regl(port, ureg->sirfsoc_mode2,
582 len_val);
Barry Songac4ce712013-01-16 14:49:27 +0800583
Qipan Li5df83112013-08-12 18:15:35 +0800584 }
Rong Wang161e7732011-11-17 23:17:04 +0800585 if (tty_termios_baud_rate(termios))
Qipan Li5df83112013-08-12 18:15:35 +0800586 tty_termios_encode_baud_rate(termios, set_baud, set_baud);
587 /* set receive timeout && data bits len */
588 rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
589 rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
590 temp_reg_val = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
591 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
592 wr_regl(port, ureg->sirfsoc_tx_fifo_op,
593 (temp_reg_val & ~SIRFUART_FIFO_START));
594 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
595 config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
596 wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
597 }
598 if (sirfport->uart_reg->uart_type == SIRF_USP_UART) {
599 /*tx frame ctrl*/
600 len_val = (data_bit_len - 1) << 0;
601 len_val |= (data_bit_len + 1 + stop_bit_len - 1) << 16;
602 len_val |= ((data_bit_len - 1) << 24);
603 len_val |= (((clk_div_reg & 0xc00) >> 10) << 30);
604 wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
605 /*rx frame ctrl*/
606 len_val = (data_bit_len - 1) << 0;
607 len_val |= (data_bit_len + 1 + stop_bit_len - 1) << 8;
608 len_val |= (data_bit_len - 1) << 16;
609 len_val |= (((clk_div_reg & 0xf000) >> 12) << 24);
610 wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
611 /*async param*/
612 wr_regl(port, ureg->sirfsoc_async_param_reg,
613 (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
614 (sample_div_reg & 0x3f) << 16);
615 }
616 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
617 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
Rong Wang161e7732011-11-17 23:17:04 +0800618 /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
Qipan Li5df83112013-08-12 18:15:35 +0800619 if (set_baud < 1000000)
Rong Wang161e7732011-11-17 23:17:04 +0800620 threshold_div = 1;
621 else
622 threshold_div = 2;
Qipan Li5df83112013-08-12 18:15:35 +0800623 temp = SIRFUART_FIFO_THD(port);
624 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, temp / threshold_div);
625 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, temp / threshold_div);
626 temp_reg_val |= SIRFUART_FIFO_START;
627 wr_regl(port, ureg->sirfsoc_tx_fifo_op, temp_reg_val);
628 uart_update_timeout(port, termios->c_cflag, set_baud);
Rong Wang161e7732011-11-17 23:17:04 +0800629 sirfsoc_uart_start_rx(port);
Qipan Li5df83112013-08-12 18:15:35 +0800630 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
Rong Wang161e7732011-11-17 23:17:04 +0800631 spin_unlock_irqrestore(&port->lock, flags);
632}
633
634static void startup_uart_controller(struct uart_port *port)
635{
Qipan Li5df83112013-08-12 18:15:35 +0800636 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
637 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800638 unsigned long temp_regv;
639 int temp;
Qipan Li5df83112013-08-12 18:15:35 +0800640 temp_regv = rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl);
641 wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, temp_regv |
642 SIRFUART_IO_MODE);
643 temp_regv = rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl);
644 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, temp_regv |
645 SIRFUART_IO_MODE);
646 wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
647 wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
648 wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
649 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
650 wr_regl(port, ureg->sirfsoc_mode1,
651 SIRFSOC_USP_ENDIAN_CTRL_LSBF |
652 SIRFSOC_USP_EN);
653 wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
654 wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
655 wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
656 wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
657 temp = SIRFUART_FIFO_THD(port);
658 wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, temp);
659 wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, temp);
Rong Wang161e7732011-11-17 23:17:04 +0800660}
661
662static int sirfsoc_uart_startup(struct uart_port *port)
663{
664 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
665 unsigned int index = port->line;
666 int ret;
667 set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
668 ret = request_irq(port->irq,
669 sirfsoc_uart_isr,
670 0,
671 SIRFUART_PORT_NAME,
672 sirfport);
673 if (ret != 0) {
674 dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
675 index, port->irq);
676 goto irq_err;
677 }
678 startup_uart_controller(port);
679 enable_irq(port->irq);
680irq_err:
681 return ret;
682}
683
684static void sirfsoc_uart_shutdown(struct uart_port *port)
685{
686 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
Qipan Li5df83112013-08-12 18:15:35 +0800687 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Barry Song909102d2013-08-07 13:35:38 +0800688 if (!sirfport->is_marco)
Qipan Li5df83112013-08-12 18:15:35 +0800689 wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
Barry Song909102d2013-08-07 13:35:38 +0800690 else
691 wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
692
Rong Wang161e7732011-11-17 23:17:04 +0800693 free_irq(port->irq, sirfport);
694 if (sirfport->ms_enabled) {
695 sirfsoc_uart_disable_ms(port);
696 sirfport->ms_enabled = 0;
697 }
698}
699
700static const char *sirfsoc_uart_type(struct uart_port *port)
701{
702 return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
703}
704
705static int sirfsoc_uart_request_port(struct uart_port *port)
706{
Qipan Li5df83112013-08-12 18:15:35 +0800707 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
708 struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param;
Rong Wang161e7732011-11-17 23:17:04 +0800709 void *ret;
710 ret = request_mem_region(port->mapbase,
Qipan Li5df83112013-08-12 18:15:35 +0800711 SIRFUART_MAP_SIZE, uart_param->port_name);
Rong Wang161e7732011-11-17 23:17:04 +0800712 return ret ? 0 : -EBUSY;
713}
714
715static void sirfsoc_uart_release_port(struct uart_port *port)
716{
717 release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
718}
719
720static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
721{
722 if (flags & UART_CONFIG_TYPE) {
723 port->type = SIRFSOC_PORT_TYPE;
724 sirfsoc_uart_request_port(port);
725 }
726}
727
728static struct uart_ops sirfsoc_uart_ops = {
729 .tx_empty = sirfsoc_uart_tx_empty,
730 .get_mctrl = sirfsoc_uart_get_mctrl,
731 .set_mctrl = sirfsoc_uart_set_mctrl,
732 .stop_tx = sirfsoc_uart_stop_tx,
733 .start_tx = sirfsoc_uart_start_tx,
734 .stop_rx = sirfsoc_uart_stop_rx,
735 .enable_ms = sirfsoc_uart_enable_ms,
736 .break_ctl = sirfsoc_uart_break_ctl,
737 .startup = sirfsoc_uart_startup,
738 .shutdown = sirfsoc_uart_shutdown,
739 .set_termios = sirfsoc_uart_set_termios,
740 .type = sirfsoc_uart_type,
741 .release_port = sirfsoc_uart_release_port,
742 .request_port = sirfsoc_uart_request_port,
743 .config_port = sirfsoc_uart_config_port,
744};
745
746#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
Qipan Li5df83112013-08-12 18:15:35 +0800747static int __init
748sirfsoc_uart_console_setup(struct console *co, char *options)
Rong Wang161e7732011-11-17 23:17:04 +0800749{
750 unsigned int baud = 115200;
751 unsigned int bits = 8;
752 unsigned int parity = 'n';
753 unsigned int flow = 'n';
754 struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
Qipan Li5df83112013-08-12 18:15:35 +0800755 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
756 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
Rong Wang161e7732011-11-17 23:17:04 +0800757 if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
758 return -EINVAL;
759
760 if (!port->mapbase)
761 return -ENODEV;
762
Qipan Li5df83112013-08-12 18:15:35 +0800763 /* enable usp in mode1 register */
764 if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
765 wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
766 SIRFSOC_USP_ENDIAN_CTRL_LSBF);
Rong Wang161e7732011-11-17 23:17:04 +0800767 if (options)
768 uart_parse_options(options, &baud, &parity, &bits, &flow);
769 port->cons = co;
Qipan Li5df83112013-08-12 18:15:35 +0800770
Rong Wang161e7732011-11-17 23:17:04 +0800771 return uart_set_options(port, co, baud, parity, bits, flow);
772}
773
774static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
775{
Qipan Li5df83112013-08-12 18:15:35 +0800776 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
777 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
778 struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
Rong Wang161e7732011-11-17 23:17:04 +0800779 while (rd_regl(port,
Qipan Li5df83112013-08-12 18:15:35 +0800780 ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
Rong Wang161e7732011-11-17 23:17:04 +0800781 cpu_relax();
Qipan Li5df83112013-08-12 18:15:35 +0800782 wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
Rong Wang161e7732011-11-17 23:17:04 +0800783}
784
785static void sirfsoc_uart_console_write(struct console *co, const char *s,
786 unsigned int count)
787{
788 struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
789 uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
790}
791
792static struct console sirfsoc_uart_console = {
793 .name = SIRFSOC_UART_NAME,
794 .device = uart_console_device,
795 .flags = CON_PRINTBUFFER,
796 .index = -1,
797 .write = sirfsoc_uart_console_write,
798 .setup = sirfsoc_uart_console_setup,
799 .data = &sirfsoc_uart_drv,
800};
801
802static int __init sirfsoc_uart_console_init(void)
803{
804 register_console(&sirfsoc_uart_console);
805 return 0;
806}
807console_initcall(sirfsoc_uart_console_init);
808#endif
809
810static struct uart_driver sirfsoc_uart_drv = {
811 .owner = THIS_MODULE,
812 .driver_name = SIRFUART_PORT_NAME,
813 .nr = SIRFSOC_UART_NR,
814 .dev_name = SIRFSOC_UART_NAME,
815 .major = SIRFSOC_UART_MAJOR,
816 .minor = SIRFSOC_UART_MINOR,
817#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
818 .cons = &sirfsoc_uart_console,
819#else
820 .cons = NULL,
821#endif
822};
823
Qipan Li5df83112013-08-12 18:15:35 +0800824static struct of_device_id sirfsoc_uart_ids[] = {
825 { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
826 { .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
827 { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
828 {}
829};
830MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
831
Rong Wang161e7732011-11-17 23:17:04 +0800832int sirfsoc_uart_probe(struct platform_device *pdev)
833{
834 struct sirfsoc_uart_port *sirfport;
835 struct uart_port *port;
836 struct resource *res;
837 int ret;
Qipan Li5df83112013-08-12 18:15:35 +0800838 const struct of_device_id *match;
Rong Wang161e7732011-11-17 23:17:04 +0800839
Qipan Li5df83112013-08-12 18:15:35 +0800840 match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
Rong Wang161e7732011-11-17 23:17:04 +0800841 if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
842 dev_err(&pdev->dev,
843 "Unable to find cell-index in uart node.\n");
844 ret = -EFAULT;
845 goto err;
846 }
Qipan Li5df83112013-08-12 18:15:35 +0800847 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
848 pdev->id += ((struct sirfsoc_uart_register *)
849 match->data)->uart_param.register_uart_nr;
Rong Wang161e7732011-11-17 23:17:04 +0800850 sirfport = &sirfsoc_uart_ports[pdev->id];
851 port = &sirfport->port;
852 port->dev = &pdev->dev;
853 port->private_data = sirfport;
Qipan Li5df83112013-08-12 18:15:35 +0800854 sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
Rong Wang161e7732011-11-17 23:17:04 +0800855
Qipan Li5df83112013-08-12 18:15:35 +0800856 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
857 sirfport->uart_reg->uart_type = SIRF_REAL_UART;
858 if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
859 sirfport->uart_reg->uart_type = SIRF_USP_UART;
Barry Song909102d2013-08-07 13:35:38 +0800860 if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
861 sirfport->is_marco = true;
862
Rong Wang161e7732011-11-17 23:17:04 +0800863 if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
864 sirfport->hw_flow_ctrl = 1;
865
866 if (of_property_read_u32(pdev->dev.of_node,
867 "fifosize",
868 &port->fifosize)) {
869 dev_err(&pdev->dev,
870 "Unable to find fifosize in uart node.\n");
871 ret = -EFAULT;
872 goto err;
873 }
874
875 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
876 if (res == NULL) {
877 dev_err(&pdev->dev, "Insufficient resources.\n");
878 ret = -EFAULT;
879 goto err;
880 }
881 port->mapbase = res->start;
882 port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
883 if (!port->membase) {
884 dev_err(&pdev->dev, "Cannot remap resource.\n");
885 ret = -ENOMEM;
886 goto err;
887 }
888 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
889 if (res == NULL) {
890 dev_err(&pdev->dev, "Insufficient resources.\n");
891 ret = -EFAULT;
Julia Lawall9250dd52012-09-01 18:33:09 +0200892 goto err;
Rong Wang161e7732011-11-17 23:17:04 +0800893 }
894 port->irq = res->start;
895
896 if (sirfport->hw_flow_ctrl) {
Stephen Warren6e5e9592012-03-02 13:05:47 -0700897 sirfport->p = pinctrl_get_select_default(&pdev->dev);
Qipan Li5df83112013-08-12 18:15:35 +0800898 ret = IS_ERR(sirfport->p);
899 if (ret)
Julia Lawall9250dd52012-09-01 18:33:09 +0200900 goto err;
Rong Wang161e7732011-11-17 23:17:04 +0800901 }
902
Barry Songac4ce712013-01-16 14:49:27 +0800903 sirfport->clk = clk_get(&pdev->dev, NULL);
904 if (IS_ERR(sirfport->clk)) {
905 ret = PTR_ERR(sirfport->clk);
906 goto clk_err;
907 }
908 clk_prepare_enable(sirfport->clk);
909 port->uartclk = clk_get_rate(sirfport->clk);
910
Rong Wang161e7732011-11-17 23:17:04 +0800911 port->ops = &sirfsoc_uart_ops;
912 spin_lock_init(&port->lock);
913
914 platform_set_drvdata(pdev, sirfport);
915 ret = uart_add_one_port(&sirfsoc_uart_drv, port);
916 if (ret != 0) {
917 dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
918 goto port_err;
919 }
920
921 return 0;
922
923port_err:
Barry Songac4ce712013-01-16 14:49:27 +0800924 clk_disable_unprepare(sirfport->clk);
925 clk_put(sirfport->clk);
926clk_err:
Stephen Warren6e5e9592012-03-02 13:05:47 -0700927 if (sirfport->hw_flow_ctrl)
Linus Walleij5c9bdc32012-02-16 19:36:21 +0100928 pinctrl_put(sirfport->p);
Rong Wang161e7732011-11-17 23:17:04 +0800929err:
930 return ret;
931}
932
933static int sirfsoc_uart_remove(struct platform_device *pdev)
934{
935 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
936 struct uart_port *port = &sirfport->port;
Jingoo Han43b829b2013-06-25 10:08:49 +0900937
Stephen Warren6e5e9592012-03-02 13:05:47 -0700938 if (sirfport->hw_flow_ctrl)
Linus Walleij5c9bdc32012-02-16 19:36:21 +0100939 pinctrl_put(sirfport->p);
Barry Songac4ce712013-01-16 14:49:27 +0800940 clk_disable_unprepare(sirfport->clk);
941 clk_put(sirfport->clk);
Rong Wang161e7732011-11-17 23:17:04 +0800942 uart_remove_one_port(&sirfsoc_uart_drv, port);
943 return 0;
944}
945
946static int
947sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
948{
949 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
950 struct uart_port *port = &sirfport->port;
951 uart_suspend_port(&sirfsoc_uart_drv, port);
952 return 0;
953}
954
955static int sirfsoc_uart_resume(struct platform_device *pdev)
956{
957 struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
958 struct uart_port *port = &sirfport->port;
959 uart_resume_port(&sirfsoc_uart_drv, port);
960 return 0;
961}
962
Rong Wang161e7732011-11-17 23:17:04 +0800963static struct platform_driver sirfsoc_uart_driver = {
964 .probe = sirfsoc_uart_probe,
Bill Pemberton2d47b712012-11-19 13:21:34 -0500965 .remove = sirfsoc_uart_remove,
Rong Wang161e7732011-11-17 23:17:04 +0800966 .suspend = sirfsoc_uart_suspend,
967 .resume = sirfsoc_uart_resume,
968 .driver = {
969 .name = SIRFUART_PORT_NAME,
970 .owner = THIS_MODULE,
971 .of_match_table = sirfsoc_uart_ids,
972 },
973};
974
975static int __init sirfsoc_uart_init(void)
976{
977 int ret = 0;
978
979 ret = uart_register_driver(&sirfsoc_uart_drv);
980 if (ret)
981 goto out;
982
983 ret = platform_driver_register(&sirfsoc_uart_driver);
984 if (ret)
985 uart_unregister_driver(&sirfsoc_uart_drv);
986out:
987 return ret;
988}
989module_init(sirfsoc_uart_init);
990
991static void __exit sirfsoc_uart_exit(void)
992{
993 platform_driver_unregister(&sirfsoc_uart_driver);
994 uart_unregister_driver(&sirfsoc_uart_drv);
995}
996module_exit(sirfsoc_uart_exit);
997
998MODULE_LICENSE("GPL v2");
999MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
1000MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");