1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Sunplus SoC UART driver |
4 | * |
5 | * Author: Hammer Hsieh <hammerh0314@gmail.com> |
6 | * |
7 | * Note1: This driver is 8250-like uart, but are not register compatible. |
8 | * |
9 | * Note2: On some buses, for preventing data incoherence, must do a read |
10 | * for ensure write made it to hardware. In this driver, function startup |
11 | * and shutdown did not do a read but only do a write directly. For what? |
12 | * In Sunplus bus communication between memory bus and peripheral bus with |
13 | * posted write, it will send a specific command after last write command |
14 | * to make sure write done. Then memory bus identify the specific command |
15 | * and send done signal back to master device. After master device received |
16 | * done signal, then proceed next write command. It is no need to do a read |
17 | * before write. |
18 | */ |
19 | #include <linux/clk.h> |
20 | #include <linux/console.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/io.h> |
23 | #include <linux/iopoll.h> |
24 | #include <linux/module.h> |
25 | #include <linux/of.h> |
26 | #include <linux/of_platform.h> |
27 | #include <linux/platform_device.h> |
28 | #include <linux/reset.h> |
29 | #include <linux/serial_core.h> |
30 | #include <linux/serial_reg.h> |
31 | #include <linux/sysrq.h> |
32 | #include <linux/tty.h> |
33 | #include <linux/tty_flip.h> |
34 | #include <asm/irq.h> |
35 | |
36 | /* Register offsets */ |
37 | #define SUP_UART_DATA 0x00 |
38 | #define SUP_UART_LSR 0x04 |
39 | #define SUP_UART_MSR 0x08 |
40 | #define SUP_UART_LCR 0x0C |
41 | #define SUP_UART_MCR 0x10 |
42 | #define SUP_UART_DIV_L 0x14 |
43 | #define SUP_UART_DIV_H 0x18 |
44 | #define SUP_UART_ISC 0x1C |
45 | #define SUP_UART_TX_RESIDUE 0x20 |
46 | #define SUP_UART_RX_RESIDUE 0x24 |
47 | |
48 | /* Line Status Register bits */ |
49 | #define SUP_UART_LSR_BC BIT(5) /* break condition status */ |
50 | #define SUP_UART_LSR_FE BIT(4) /* frame error status */ |
51 | #define SUP_UART_LSR_OE BIT(3) /* overrun error status */ |
52 | #define SUP_UART_LSR_PE BIT(2) /* parity error status */ |
53 | #define SUP_UART_LSR_RX BIT(1) /* 1: receive fifo not empty */ |
54 | #define SUP_UART_LSR_TX BIT(0) /* 1: transmit fifo is not full */ |
55 | #define SUP_UART_LSR_TX_NOT_FULL 1 |
56 | #define SUP_UART_LSR_BRK_ERROR_BITS GENMASK(5, 2) |
57 | |
58 | /* Line Control Register bits */ |
59 | #define SUP_UART_LCR_SBC BIT(5) /* select break condition */ |
60 | |
61 | /* Modem Control Register bits */ |
62 | #define SUP_UART_MCR_RI BIT(3) /* ring indicator */ |
63 | #define SUP_UART_MCR_DCD BIT(2) /* data carrier detect */ |
64 | |
65 | /* Interrupt Status/Control Register bits */ |
66 | #define SUP_UART_ISC_RXM BIT(5) /* RX interrupt enable */ |
67 | #define SUP_UART_ISC_TXM BIT(4) /* TX interrupt enable */ |
68 | #define SUP_UART_ISC_RX BIT(1) /* RX interrupt status */ |
69 | #define SUP_UART_ISC_TX BIT(0) /* TX interrupt status */ |
70 | |
71 | #define SUP_DUMMY_READ BIT(16) /* drop bytes received on a !CREAD port */ |
72 | #define SUP_UART_NR 5 |
73 | |
74 | struct sunplus_uart_port { |
75 | struct uart_port port; |
76 | struct clk *clk; |
77 | struct reset_control *rstc; |
78 | }; |
79 | |
80 | static void sp_uart_put_char(struct uart_port *port, unsigned int ch) |
81 | { |
82 | writel(val: ch, addr: port->membase + SUP_UART_DATA); |
83 | } |
84 | |
85 | static u32 sunplus_tx_buf_not_full(struct uart_port *port) |
86 | { |
87 | unsigned int lsr = readl(addr: port->membase + SUP_UART_LSR); |
88 | |
89 | return (lsr & SUP_UART_LSR_TX) ? SUP_UART_LSR_TX_NOT_FULL : 0; |
90 | } |
91 | |
92 | static unsigned int sunplus_tx_empty(struct uart_port *port) |
93 | { |
94 | unsigned int lsr = readl(addr: port->membase + SUP_UART_LSR); |
95 | |
96 | return (lsr & UART_LSR_TEMT) ? TIOCSER_TEMT : 0; |
97 | } |
98 | |
99 | static void sunplus_set_mctrl(struct uart_port *port, unsigned int mctrl) |
100 | { |
101 | unsigned int mcr = readl(addr: port->membase + SUP_UART_MCR); |
102 | |
103 | if (mctrl & TIOCM_DTR) |
104 | mcr |= UART_MCR_DTR; |
105 | else |
106 | mcr &= ~UART_MCR_DTR; |
107 | |
108 | if (mctrl & TIOCM_RTS) |
109 | mcr |= UART_MCR_RTS; |
110 | else |
111 | mcr &= ~UART_MCR_RTS; |
112 | |
113 | if (mctrl & TIOCM_CAR) |
114 | mcr |= SUP_UART_MCR_DCD; |
115 | else |
116 | mcr &= ~SUP_UART_MCR_DCD; |
117 | |
118 | if (mctrl & TIOCM_RI) |
119 | mcr |= SUP_UART_MCR_RI; |
120 | else |
121 | mcr &= ~SUP_UART_MCR_RI; |
122 | |
123 | if (mctrl & TIOCM_LOOP) |
124 | mcr |= UART_MCR_LOOP; |
125 | else |
126 | mcr &= ~UART_MCR_LOOP; |
127 | |
128 | writel(val: mcr, addr: port->membase + SUP_UART_MCR); |
129 | } |
130 | |
131 | static unsigned int sunplus_get_mctrl(struct uart_port *port) |
132 | { |
133 | unsigned int mcr, ret = 0; |
134 | |
135 | mcr = readl(addr: port->membase + SUP_UART_MCR); |
136 | |
137 | if (mcr & UART_MCR_DTR) |
138 | ret |= TIOCM_DTR; |
139 | |
140 | if (mcr & UART_MCR_RTS) |
141 | ret |= TIOCM_RTS; |
142 | |
143 | if (mcr & SUP_UART_MCR_DCD) |
144 | ret |= TIOCM_CAR; |
145 | |
146 | if (mcr & SUP_UART_MCR_RI) |
147 | ret |= TIOCM_RI; |
148 | |
149 | if (mcr & UART_MCR_LOOP) |
150 | ret |= TIOCM_LOOP; |
151 | |
152 | return ret; |
153 | } |
154 | |
155 | static void sunplus_stop_tx(struct uart_port *port) |
156 | { |
157 | unsigned int isc; |
158 | |
159 | isc = readl(addr: port->membase + SUP_UART_ISC); |
160 | isc &= ~SUP_UART_ISC_TXM; |
161 | writel(val: isc, addr: port->membase + SUP_UART_ISC); |
162 | } |
163 | |
164 | static void sunplus_start_tx(struct uart_port *port) |
165 | { |
166 | unsigned int isc; |
167 | |
168 | isc = readl(addr: port->membase + SUP_UART_ISC); |
169 | isc |= SUP_UART_ISC_TXM; |
170 | writel(val: isc, addr: port->membase + SUP_UART_ISC); |
171 | } |
172 | |
173 | static void sunplus_stop_rx(struct uart_port *port) |
174 | { |
175 | unsigned int isc; |
176 | |
177 | isc = readl(addr: port->membase + SUP_UART_ISC); |
178 | isc &= ~SUP_UART_ISC_RXM; |
179 | writel(val: isc, addr: port->membase + SUP_UART_ISC); |
180 | } |
181 | |
182 | static void sunplus_break_ctl(struct uart_port *port, int ctl) |
183 | { |
184 | unsigned long flags; |
185 | unsigned int lcr; |
186 | |
187 | uart_port_lock_irqsave(up: port, flags: &flags); |
188 | |
189 | lcr = readl(addr: port->membase + SUP_UART_LCR); |
190 | |
191 | if (ctl) |
192 | lcr |= SUP_UART_LCR_SBC; /* start break */ |
193 | else |
194 | lcr &= ~SUP_UART_LCR_SBC; /* stop break */ |
195 | |
196 | writel(val: lcr, addr: port->membase + SUP_UART_LCR); |
197 | |
198 | uart_port_unlock_irqrestore(up: port, flags); |
199 | } |
200 | |
201 | static void transmit_chars(struct uart_port *port) |
202 | { |
203 | struct circ_buf *xmit = &port->state->xmit; |
204 | |
205 | if (port->x_char) { |
206 | sp_uart_put_char(port, ch: port->x_char); |
207 | port->icount.tx++; |
208 | port->x_char = 0; |
209 | return; |
210 | } |
211 | |
212 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { |
213 | sunplus_stop_tx(port); |
214 | return; |
215 | } |
216 | |
217 | do { |
218 | sp_uart_put_char(port, ch: xmit->buf[xmit->tail]); |
219 | uart_xmit_advance(up: port, chars: 1); |
220 | if (uart_circ_empty(xmit)) |
221 | break; |
222 | } while (sunplus_tx_buf_not_full(port)); |
223 | |
224 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
225 | uart_write_wakeup(port); |
226 | |
227 | if (uart_circ_empty(xmit)) |
228 | sunplus_stop_tx(port); |
229 | } |
230 | |
231 | static void receive_chars(struct uart_port *port) |
232 | { |
233 | unsigned int lsr = readl(addr: port->membase + SUP_UART_LSR); |
234 | u8 ch, flag; |
235 | |
236 | do { |
237 | ch = readl(addr: port->membase + SUP_UART_DATA); |
238 | flag = TTY_NORMAL; |
239 | port->icount.rx++; |
240 | |
241 | if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) { |
242 | if (lsr & SUP_UART_LSR_BC) { |
243 | lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE); |
244 | port->icount.brk++; |
245 | flag = TTY_BREAK; |
246 | if (uart_handle_break(port)) |
247 | goto ignore_char; |
248 | } else if (lsr & SUP_UART_LSR_PE) { |
249 | port->icount.parity++; |
250 | flag = TTY_PARITY; |
251 | } else if (lsr & SUP_UART_LSR_FE) { |
252 | port->icount.frame++; |
253 | flag = TTY_FRAME; |
254 | } |
255 | |
256 | if (lsr & SUP_UART_LSR_OE) |
257 | port->icount.overrun++; |
258 | } |
259 | |
260 | if (port->ignore_status_mask & SUP_DUMMY_READ) |
261 | goto ignore_char; |
262 | |
263 | if (uart_prepare_sysrq_char(port, ch)) |
264 | goto ignore_char; |
265 | |
266 | uart_insert_char(port, status: lsr, SUP_UART_LSR_OE, ch, flag); |
267 | |
268 | ignore_char: |
269 | lsr = readl(addr: port->membase + SUP_UART_LSR); |
270 | } while (lsr & SUP_UART_LSR_RX); |
271 | |
272 | tty_flip_buffer_push(port: &port->state->port); |
273 | } |
274 | |
275 | static irqreturn_t sunplus_uart_irq(int irq, void *args) |
276 | { |
277 | struct uart_port *port = args; |
278 | unsigned int isc; |
279 | |
280 | uart_port_lock(up: port); |
281 | |
282 | isc = readl(addr: port->membase + SUP_UART_ISC); |
283 | |
284 | if (isc & SUP_UART_ISC_RX) |
285 | receive_chars(port); |
286 | |
287 | if (isc & SUP_UART_ISC_TX) |
288 | transmit_chars(port); |
289 | |
290 | uart_unlock_and_check_sysrq(port); |
291 | |
292 | return IRQ_HANDLED; |
293 | } |
294 | |
295 | static int sunplus_startup(struct uart_port *port) |
296 | { |
297 | unsigned long flags; |
298 | unsigned int isc = 0; |
299 | int ret; |
300 | |
301 | ret = request_irq(irq: port->irq, handler: sunplus_uart_irq, flags: 0, name: "sunplus_uart" , dev: port); |
302 | if (ret) |
303 | return ret; |
304 | |
305 | uart_port_lock_irqsave(up: port, flags: &flags); |
306 | /* isc define Bit[7:4] int setting, Bit[3:0] int status |
307 | * isc register will clean Bit[3:0] int status after read |
308 | * only do a write to Bit[7:4] int setting |
309 | */ |
310 | isc |= SUP_UART_ISC_RXM; |
311 | writel(val: isc, addr: port->membase + SUP_UART_ISC); |
312 | uart_port_unlock_irqrestore(up: port, flags); |
313 | |
314 | return 0; |
315 | } |
316 | |
317 | static void sunplus_shutdown(struct uart_port *port) |
318 | { |
319 | unsigned long flags; |
320 | |
321 | uart_port_lock_irqsave(up: port, flags: &flags); |
322 | /* isc define Bit[7:4] int setting, Bit[3:0] int status |
323 | * isc register will clean Bit[3:0] int status after read |
324 | * only do a write to Bit[7:4] int setting |
325 | */ |
326 | writel(val: 0, addr: port->membase + SUP_UART_ISC); /* disable all interrupt */ |
327 | uart_port_unlock_irqrestore(up: port, flags); |
328 | |
329 | free_irq(port->irq, port); |
330 | } |
331 | |
332 | static void sunplus_set_termios(struct uart_port *port, |
333 | struct ktermios *termios, |
334 | const struct ktermios *oldtermios) |
335 | { |
336 | u32 ext, div, div_l, div_h, baud, lcr; |
337 | u32 clk = port->uartclk; |
338 | unsigned long flags; |
339 | |
340 | baud = uart_get_baud_rate(port, termios, old: oldtermios, min: 0, max: port->uartclk / 16); |
341 | |
342 | /* baud rate = uartclk / ((16 * divisor + 1) + divisor_ext) */ |
343 | clk += baud >> 1; |
344 | div = clk / baud; |
345 | ext = div & 0x0F; |
346 | div = (div >> 4) - 1; |
347 | div_l = (div & 0xFF) | (ext << 12); |
348 | div_h = div >> 8; |
349 | |
350 | switch (termios->c_cflag & CSIZE) { |
351 | case CS5: |
352 | lcr = UART_LCR_WLEN5; |
353 | break; |
354 | case CS6: |
355 | lcr = UART_LCR_WLEN6; |
356 | break; |
357 | case CS7: |
358 | lcr = UART_LCR_WLEN7; |
359 | break; |
360 | default: |
361 | lcr = UART_LCR_WLEN8; |
362 | break; |
363 | } |
364 | |
365 | if (termios->c_cflag & CSTOPB) |
366 | lcr |= UART_LCR_STOP; |
367 | |
368 | if (termios->c_cflag & PARENB) { |
369 | lcr |= UART_LCR_PARITY; |
370 | |
371 | if (!(termios->c_cflag & PARODD)) |
372 | lcr |= UART_LCR_EPAR; |
373 | } |
374 | |
375 | uart_port_lock_irqsave(up: port, flags: &flags); |
376 | |
377 | uart_update_timeout(port, cflag: termios->c_cflag, baud); |
378 | |
379 | port->read_status_mask = 0; |
380 | if (termios->c_iflag & INPCK) |
381 | port->read_status_mask |= SUP_UART_LSR_PE | SUP_UART_LSR_FE; |
382 | |
383 | if (termios->c_iflag & (BRKINT | PARMRK)) |
384 | port->read_status_mask |= SUP_UART_LSR_BC; |
385 | |
386 | /* Characters to ignore */ |
387 | port->ignore_status_mask = 0; |
388 | if (termios->c_iflag & IGNPAR) |
389 | port->ignore_status_mask |= SUP_UART_LSR_FE | SUP_UART_LSR_PE; |
390 | |
391 | if (termios->c_iflag & IGNBRK) { |
392 | port->ignore_status_mask |= SUP_UART_LSR_BC; |
393 | |
394 | if (termios->c_iflag & IGNPAR) |
395 | port->ignore_status_mask |= SUP_UART_LSR_OE; |
396 | } |
397 | |
398 | /* Ignore all characters if CREAD is not set */ |
399 | if ((termios->c_cflag & CREAD) == 0) { |
400 | port->ignore_status_mask |= SUP_DUMMY_READ; |
401 | /* flush rx data FIFO */ |
402 | writel(val: 0, addr: port->membase + SUP_UART_RX_RESIDUE); |
403 | } |
404 | |
405 | /* Settings for baud rate divisor and lcr */ |
406 | writel(val: div_h, addr: port->membase + SUP_UART_DIV_H); |
407 | writel(val: div_l, addr: port->membase + SUP_UART_DIV_L); |
408 | writel(val: lcr, addr: port->membase + SUP_UART_LCR); |
409 | |
410 | uart_port_unlock_irqrestore(up: port, flags); |
411 | } |
412 | |
413 | static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios) |
414 | { |
415 | int new = termios->c_line; |
416 | |
417 | if (new == N_PPS) |
418 | port->flags |= UPF_HARDPPS_CD; |
419 | else |
420 | port->flags &= ~UPF_HARDPPS_CD; |
421 | } |
422 | |
423 | static const char *sunplus_type(struct uart_port *port) |
424 | { |
425 | return port->type == PORT_SUNPLUS ? "sunplus_uart" : NULL; |
426 | } |
427 | |
428 | static void sunplus_config_port(struct uart_port *port, int type) |
429 | { |
430 | if (type & UART_CONFIG_TYPE) |
431 | port->type = PORT_SUNPLUS; |
432 | } |
433 | |
434 | static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser) |
435 | { |
436 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_SUNPLUS) |
437 | return -EINVAL; |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | #if defined(CONFIG_SERIAL_SUNPLUS_CONSOLE) || defined(CONFIG_CONSOLE_POLL) |
443 | static void wait_for_xmitr(struct uart_port *port) |
444 | { |
445 | unsigned int val; |
446 | int ret; |
447 | |
448 | /* Wait while FIFO is full or timeout */ |
449 | ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, |
450 | (val & SUP_UART_LSR_TX), 1, 10000); |
451 | |
452 | if (ret == -ETIMEDOUT) { |
453 | dev_err(port->dev, "Timeout waiting while UART TX FULL\n" ); |
454 | return; |
455 | } |
456 | } |
457 | #endif |
458 | |
459 | #ifdef CONFIG_CONSOLE_POLL |
460 | static void sunplus_poll_put_char(struct uart_port *port, unsigned char data) |
461 | { |
462 | wait_for_xmitr(port); |
463 | sp_uart_put_char(port, ch: data); |
464 | } |
465 | |
466 | static int sunplus_poll_get_char(struct uart_port *port) |
467 | { |
468 | unsigned int lsr = readl(addr: port->membase + SUP_UART_LSR); |
469 | |
470 | if (!(lsr & SUP_UART_LSR_RX)) |
471 | return NO_POLL_CHAR; |
472 | |
473 | return readl(addr: port->membase + SUP_UART_DATA); |
474 | } |
475 | #endif |
476 | |
477 | static const struct uart_ops sunplus_uart_ops = { |
478 | .tx_empty = sunplus_tx_empty, |
479 | .set_mctrl = sunplus_set_mctrl, |
480 | .get_mctrl = sunplus_get_mctrl, |
481 | .stop_tx = sunplus_stop_tx, |
482 | .start_tx = sunplus_start_tx, |
483 | .stop_rx = sunplus_stop_rx, |
484 | .break_ctl = sunplus_break_ctl, |
485 | .startup = sunplus_startup, |
486 | .shutdown = sunplus_shutdown, |
487 | .set_termios = sunplus_set_termios, |
488 | .set_ldisc = sunplus_set_ldisc, |
489 | .type = sunplus_type, |
490 | .config_port = sunplus_config_port, |
491 | .verify_port = sunplus_verify_port, |
492 | #ifdef CONFIG_CONSOLE_POLL |
493 | .poll_put_char = sunplus_poll_put_char, |
494 | .poll_get_char = sunplus_poll_get_char, |
495 | #endif |
496 | }; |
497 | |
498 | #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE |
499 | static struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR]; |
500 | |
501 | static void sunplus_uart_console_putchar(struct uart_port *port, |
502 | unsigned char ch) |
503 | { |
504 | wait_for_xmitr(port); |
505 | sp_uart_put_char(port, ch); |
506 | } |
507 | |
508 | static void sunplus_console_write(struct console *co, |
509 | const char *s, |
510 | unsigned int count) |
511 | { |
512 | unsigned long flags; |
513 | int locked = 1; |
514 | |
515 | if (oops_in_progress) |
516 | locked = uart_port_trylock_irqsave(up: &sunplus_console_ports[co->index]->port, flags: &flags); |
517 | else |
518 | uart_port_lock_irqsave(up: &sunplus_console_ports[co->index]->port, flags: &flags); |
519 | |
520 | uart_console_write(port: &sunplus_console_ports[co->index]->port, s, count, |
521 | putchar: sunplus_uart_console_putchar); |
522 | |
523 | if (locked) |
524 | uart_port_unlock_irqrestore(up: &sunplus_console_ports[co->index]->port, flags); |
525 | } |
526 | |
527 | static int __init sunplus_console_setup(struct console *co, char *options) |
528 | { |
529 | struct sunplus_uart_port *sup; |
530 | int baud = 115200; |
531 | int bits = 8; |
532 | int parity = 'n'; |
533 | int flow = 'n'; |
534 | |
535 | if (co->index < 0 || co->index >= SUP_UART_NR) |
536 | return -EINVAL; |
537 | |
538 | sup = sunplus_console_ports[co->index]; |
539 | if (!sup) |
540 | return -ENODEV; |
541 | |
542 | if (options) |
543 | uart_parse_options(options, baud: &baud, parity: &parity, bits: &bits, flow: &flow); |
544 | |
545 | return uart_set_options(port: &sup->port, co, baud, parity, bits, flow); |
546 | } |
547 | |
548 | static struct uart_driver sunplus_uart_driver; |
549 | static struct console sunplus_uart_console = { |
550 | .name = "ttySUP" , |
551 | .write = sunplus_console_write, |
552 | .device = uart_console_device, |
553 | .setup = sunplus_console_setup, |
554 | .flags = CON_PRINTBUFFER, |
555 | .index = -1, |
556 | .data = &sunplus_uart_driver |
557 | }; |
558 | |
559 | #define SERIAL_SUNPLUS_CONSOLE (&sunplus_uart_console) |
560 | #else |
561 | #define SERIAL_SUNPLUS_CONSOLE NULL |
562 | #endif |
563 | |
564 | static struct uart_driver sunplus_uart_driver = { |
565 | .owner = THIS_MODULE, |
566 | .driver_name = "sunplus_uart" , |
567 | .dev_name = "ttySUP" , |
568 | .major = TTY_MAJOR, |
569 | .minor = 64, |
570 | .nr = SUP_UART_NR, |
571 | .cons = SERIAL_SUNPLUS_CONSOLE, |
572 | }; |
573 | |
574 | static void sunplus_uart_disable_unprepare(void *data) |
575 | { |
576 | clk_disable_unprepare(clk: data); |
577 | } |
578 | |
579 | static void sunplus_uart_reset_control_assert(void *data) |
580 | { |
581 | reset_control_assert(rstc: data); |
582 | } |
583 | |
584 | static int sunplus_uart_probe(struct platform_device *pdev) |
585 | { |
586 | struct sunplus_uart_port *sup; |
587 | struct uart_port *port; |
588 | struct resource *res; |
589 | int ret, irq; |
590 | |
591 | pdev->id = of_alias_get_id(np: pdev->dev.of_node, stem: "serial" ); |
592 | |
593 | if (pdev->id < 0 || pdev->id >= SUP_UART_NR) |
594 | return -EINVAL; |
595 | |
596 | sup = devm_kzalloc(dev: &pdev->dev, size: sizeof(*sup), GFP_KERNEL); |
597 | if (!sup) |
598 | return -ENOMEM; |
599 | |
600 | sup->clk = devm_clk_get_optional(dev: &pdev->dev, NULL); |
601 | if (IS_ERR(ptr: sup->clk)) |
602 | return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: sup->clk), fmt: "clk not found\n" ); |
603 | |
604 | ret = clk_prepare_enable(clk: sup->clk); |
605 | if (ret) |
606 | return ret; |
607 | |
608 | ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_disable_unprepare, sup->clk); |
609 | if (ret) |
610 | return ret; |
611 | |
612 | sup->rstc = devm_reset_control_get_exclusive(dev: &pdev->dev, NULL); |
613 | if (IS_ERR(ptr: sup->rstc)) |
614 | return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: sup->rstc), fmt: "rstc not found\n" ); |
615 | |
616 | port = &sup->port; |
617 | |
618 | port->membase = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
619 | if (IS_ERR(ptr: port->membase)) |
620 | return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: port->membase), fmt: "membase not found\n" ); |
621 | |
622 | irq = platform_get_irq(pdev, 0); |
623 | if (irq < 0) |
624 | return irq; |
625 | |
626 | port->mapbase = res->start; |
627 | port->uartclk = clk_get_rate(clk: sup->clk); |
628 | port->line = pdev->id; |
629 | port->irq = irq; |
630 | port->dev = &pdev->dev; |
631 | port->iotype = UPIO_MEM; |
632 | port->ops = &sunplus_uart_ops; |
633 | port->flags = UPF_BOOT_AUTOCONF; |
634 | port->fifosize = 128; |
635 | |
636 | ret = reset_control_deassert(rstc: sup->rstc); |
637 | if (ret) |
638 | return ret; |
639 | |
640 | ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_reset_control_assert, sup->rstc); |
641 | if (ret) |
642 | return ret; |
643 | |
644 | #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE |
645 | sunplus_console_ports[sup->port.line] = sup; |
646 | #endif |
647 | |
648 | platform_set_drvdata(pdev, data: &sup->port); |
649 | |
650 | ret = uart_add_one_port(reg: &sunplus_uart_driver, port: &sup->port); |
651 | #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE |
652 | if (ret) |
653 | sunplus_console_ports[sup->port.line] = NULL; |
654 | #endif |
655 | |
656 | return ret; |
657 | } |
658 | |
659 | static void sunplus_uart_remove(struct platform_device *pdev) |
660 | { |
661 | struct sunplus_uart_port *sup = platform_get_drvdata(pdev); |
662 | |
663 | uart_remove_one_port(reg: &sunplus_uart_driver, port: &sup->port); |
664 | } |
665 | |
666 | static int __maybe_unused sunplus_uart_suspend(struct device *dev) |
667 | { |
668 | struct sunplus_uart_port *sup = dev_get_drvdata(dev); |
669 | |
670 | if (!uart_console(&sup->port)) |
671 | uart_suspend_port(reg: &sunplus_uart_driver, port: &sup->port); |
672 | |
673 | return 0; |
674 | } |
675 | |
676 | static int __maybe_unused sunplus_uart_resume(struct device *dev) |
677 | { |
678 | struct sunplus_uart_port *sup = dev_get_drvdata(dev); |
679 | |
680 | if (!uart_console(&sup->port)) |
681 | uart_resume_port(reg: &sunplus_uart_driver, port: &sup->port); |
682 | |
683 | return 0; |
684 | } |
685 | |
686 | static const struct dev_pm_ops sunplus_uart_pm_ops = { |
687 | SET_SYSTEM_SLEEP_PM_OPS(sunplus_uart_suspend, sunplus_uart_resume) |
688 | }; |
689 | |
690 | static const struct of_device_id sp_uart_of_match[] = { |
691 | { .compatible = "sunplus,sp7021-uart" }, |
692 | {} |
693 | }; |
694 | MODULE_DEVICE_TABLE(of, sp_uart_of_match); |
695 | |
696 | static struct platform_driver sunplus_uart_platform_driver = { |
697 | .probe = sunplus_uart_probe, |
698 | .remove_new = sunplus_uart_remove, |
699 | .driver = { |
700 | .name = "sunplus_uart" , |
701 | .of_match_table = sp_uart_of_match, |
702 | .pm = &sunplus_uart_pm_ops, |
703 | } |
704 | }; |
705 | |
706 | static int __init sunplus_uart_init(void) |
707 | { |
708 | int ret; |
709 | |
710 | ret = uart_register_driver(uart: &sunplus_uart_driver); |
711 | if (ret) |
712 | return ret; |
713 | |
714 | ret = platform_driver_register(&sunplus_uart_platform_driver); |
715 | if (ret) |
716 | uart_unregister_driver(uart: &sunplus_uart_driver); |
717 | |
718 | return ret; |
719 | } |
720 | module_init(sunplus_uart_init); |
721 | |
722 | static void __exit sunplus_uart_exit(void) |
723 | { |
724 | platform_driver_unregister(&sunplus_uart_platform_driver); |
725 | uart_unregister_driver(uart: &sunplus_uart_driver); |
726 | } |
727 | module_exit(sunplus_uart_exit); |
728 | |
729 | #ifdef CONFIG_SERIAL_EARLYCON |
730 | static void sunplus_uart_putc(struct uart_port *port, unsigned char c) |
731 | { |
732 | unsigned int val; |
733 | int ret; |
734 | |
735 | ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, |
736 | (val & UART_LSR_TEMT), 1, 10000); |
737 | if (ret) |
738 | return; |
739 | |
740 | writel(val: c, addr: port->membase + SUP_UART_DATA); |
741 | } |
742 | |
743 | static void sunplus_uart_early_write(struct console *con, const char *s, unsigned int n) |
744 | { |
745 | struct earlycon_device *dev = con->data; |
746 | |
747 | uart_console_write(port: &dev->port, s, count: n, putchar: sunplus_uart_putc); |
748 | } |
749 | |
750 | static int __init |
751 | sunplus_uart_early_setup(struct earlycon_device *dev, const char *opt) |
752 | { |
753 | if (!(dev->port.membase || dev->port.iobase)) |
754 | return -ENODEV; |
755 | |
756 | dev->con->write = sunplus_uart_early_write; |
757 | |
758 | return 0; |
759 | } |
760 | OF_EARLYCON_DECLARE(sunplus_uart, "sunplus,sp7021-uart" , sunplus_uart_early_setup); |
761 | #endif |
762 | |
763 | MODULE_DESCRIPTION("Sunplus UART driver" ); |
764 | MODULE_AUTHOR("Hammer Hsieh <hammerh0314@gmail.com>" ); |
765 | MODULE_LICENSE("GPL v2" ); |
766 | |