Commit | Line | Data |
---|---|---|
c4b05856 SK |
1 | /* |
2 | * st-asc.c: ST Asynchronous serial controller (ASC) driver | |
3 | * | |
4 | * Copyright (C) 2003-2013 STMicroelectronics (R&D) Limited | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | */ | |
12 | ||
13 | #if defined(CONFIG_SERIAL_ST_ASC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | |
14 | #define SUPPORT_SYSRQ | |
15 | #endif | |
16 | ||
17 | #include <linux/module.h> | |
18 | #include <linux/serial.h> | |
19 | #include <linux/console.h> | |
20 | #include <linux/sysrq.h> | |
21 | #include <linux/platform_device.h> | |
22 | #include <linux/io.h> | |
23 | #include <linux/irq.h> | |
24 | #include <linux/tty.h> | |
25 | #include <linux/tty_flip.h> | |
26 | #include <linux/delay.h> | |
27 | #include <linux/spinlock.h> | |
28 | #include <linux/pm_runtime.h> | |
29 | #include <linux/of.h> | |
30 | #include <linux/of_platform.h> | |
31 | #include <linux/serial_core.h> | |
32 | #include <linux/clk.h> | |
33 | ||
34 | #define DRIVER_NAME "st-asc" | |
35 | #define ASC_SERIAL_NAME "ttyAS" | |
36 | #define ASC_FIFO_SIZE 16 | |
37 | #define ASC_MAX_PORTS 8 | |
38 | ||
39 | struct asc_port { | |
40 | struct uart_port port; | |
41 | struct clk *clk; | |
42 | unsigned int hw_flow_control:1; | |
43 | unsigned int force_m1:1; | |
44 | }; | |
45 | ||
46 | static struct asc_port asc_ports[ASC_MAX_PORTS]; | |
47 | static struct uart_driver asc_uart_driver; | |
48 | ||
49 | /*---- UART Register definitions ------------------------------*/ | |
50 | ||
51 | /* Register offsets */ | |
52 | ||
53 | #define ASC_BAUDRATE 0x00 | |
54 | #define ASC_TXBUF 0x04 | |
55 | #define ASC_RXBUF 0x08 | |
56 | #define ASC_CTL 0x0C | |
57 | #define ASC_INTEN 0x10 | |
58 | #define ASC_STA 0x14 | |
59 | #define ASC_GUARDTIME 0x18 | |
60 | #define ASC_TIMEOUT 0x1C | |
61 | #define ASC_TXRESET 0x20 | |
62 | #define ASC_RXRESET 0x24 | |
63 | #define ASC_RETRIES 0x28 | |
64 | ||
65 | /* ASC_RXBUF */ | |
66 | #define ASC_RXBUF_PE 0x100 | |
67 | #define ASC_RXBUF_FE 0x200 | |
68 | /** | |
69 | * Some of status comes from higher bits of the character and some come from | |
70 | * the status register. Combining both of them in to single status using dummy | |
71 | * bits. | |
72 | */ | |
73 | #define ASC_RXBUF_DUMMY_RX 0x10000 | |
74 | #define ASC_RXBUF_DUMMY_BE 0x20000 | |
75 | #define ASC_RXBUF_DUMMY_OE 0x40000 | |
76 | ||
77 | /* ASC_CTL */ | |
78 | ||
79 | #define ASC_CTL_MODE_MSK 0x0007 | |
80 | #define ASC_CTL_MODE_8BIT 0x0001 | |
81 | #define ASC_CTL_MODE_7BIT_PAR 0x0003 | |
82 | #define ASC_CTL_MODE_9BIT 0x0004 | |
83 | #define ASC_CTL_MODE_8BIT_WKUP 0x0005 | |
84 | #define ASC_CTL_MODE_8BIT_PAR 0x0007 | |
85 | #define ASC_CTL_STOP_MSK 0x0018 | |
86 | #define ASC_CTL_STOP_HALFBIT 0x0000 | |
87 | #define ASC_CTL_STOP_1BIT 0x0008 | |
88 | #define ASC_CTL_STOP_1_HALFBIT 0x0010 | |
89 | #define ASC_CTL_STOP_2BIT 0x0018 | |
90 | #define ASC_CTL_PARITYODD 0x0020 | |
91 | #define ASC_CTL_LOOPBACK 0x0040 | |
92 | #define ASC_CTL_RUN 0x0080 | |
93 | #define ASC_CTL_RXENABLE 0x0100 | |
94 | #define ASC_CTL_SCENABLE 0x0200 | |
95 | #define ASC_CTL_FIFOENABLE 0x0400 | |
96 | #define ASC_CTL_CTSENABLE 0x0800 | |
97 | #define ASC_CTL_BAUDMODE 0x1000 | |
98 | ||
99 | /* ASC_GUARDTIME */ | |
100 | ||
101 | #define ASC_GUARDTIME_MSK 0x00FF | |
102 | ||
103 | /* ASC_INTEN */ | |
104 | ||
105 | #define ASC_INTEN_RBE 0x0001 | |
106 | #define ASC_INTEN_TE 0x0002 | |
107 | #define ASC_INTEN_THE 0x0004 | |
108 | #define ASC_INTEN_PE 0x0008 | |
109 | #define ASC_INTEN_FE 0x0010 | |
110 | #define ASC_INTEN_OE 0x0020 | |
111 | #define ASC_INTEN_TNE 0x0040 | |
112 | #define ASC_INTEN_TOI 0x0080 | |
113 | #define ASC_INTEN_RHF 0x0100 | |
114 | ||
115 | /* ASC_RETRIES */ | |
116 | ||
117 | #define ASC_RETRIES_MSK 0x00FF | |
118 | ||
119 | /* ASC_RXBUF */ | |
120 | ||
121 | #define ASC_RXBUF_MSK 0x03FF | |
122 | ||
123 | /* ASC_STA */ | |
124 | ||
125 | #define ASC_STA_RBF 0x0001 | |
126 | #define ASC_STA_TE 0x0002 | |
127 | #define ASC_STA_THE 0x0004 | |
128 | #define ASC_STA_PE 0x0008 | |
129 | #define ASC_STA_FE 0x0010 | |
130 | #define ASC_STA_OE 0x0020 | |
131 | #define ASC_STA_TNE 0x0040 | |
132 | #define ASC_STA_TOI 0x0080 | |
133 | #define ASC_STA_RHF 0x0100 | |
134 | #define ASC_STA_TF 0x0200 | |
135 | #define ASC_STA_NKD 0x0400 | |
136 | ||
137 | /* ASC_TIMEOUT */ | |
138 | ||
139 | #define ASC_TIMEOUT_MSK 0x00FF | |
140 | ||
141 | /* ASC_TXBUF */ | |
142 | ||
143 | #define ASC_TXBUF_MSK 0x01FF | |
144 | ||
145 | /*---- Inline function definitions ---------------------------*/ | |
146 | ||
147 | static inline struct asc_port *to_asc_port(struct uart_port *port) | |
148 | { | |
149 | return container_of(port, struct asc_port, port); | |
150 | } | |
151 | ||
152 | static inline u32 asc_in(struct uart_port *port, u32 offset) | |
153 | { | |
daea65a7 | 154 | #ifdef readl_relaxed |
08177ece | 155 | return readl_relaxed(port->membase + offset); |
daea65a7 DT |
156 | #else |
157 | return readl(port->membase + offset); | |
158 | #endif | |
c4b05856 SK |
159 | } |
160 | ||
161 | static inline void asc_out(struct uart_port *port, u32 offset, u32 value) | |
162 | { | |
08177ece DT |
163 | #ifdef writel_relaxed |
164 | writel_relaxed(value, port->membase + offset); | |
165 | #else | |
c4b05856 | 166 | writel(value, port->membase + offset); |
08177ece | 167 | #endif |
c4b05856 SK |
168 | } |
169 | ||
170 | /* | |
171 | * Some simple utility functions to enable and disable interrupts. | |
172 | * Note that these need to be called with interrupts disabled. | |
173 | */ | |
174 | static inline void asc_disable_tx_interrupts(struct uart_port *port) | |
175 | { | |
176 | u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_THE; | |
177 | asc_out(port, ASC_INTEN, intenable); | |
178 | (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */ | |
179 | } | |
180 | ||
181 | static inline void asc_enable_tx_interrupts(struct uart_port *port) | |
182 | { | |
183 | u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_THE; | |
184 | asc_out(port, ASC_INTEN, intenable); | |
185 | } | |
186 | ||
187 | static inline void asc_disable_rx_interrupts(struct uart_port *port) | |
188 | { | |
189 | u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_RBE; | |
190 | asc_out(port, ASC_INTEN, intenable); | |
191 | (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */ | |
192 | } | |
193 | ||
194 | static inline void asc_enable_rx_interrupts(struct uart_port *port) | |
195 | { | |
196 | u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_RBE; | |
197 | asc_out(port, ASC_INTEN, intenable); | |
198 | } | |
199 | ||
200 | static inline u32 asc_txfifo_is_empty(struct uart_port *port) | |
201 | { | |
202 | return asc_in(port, ASC_STA) & ASC_STA_TE; | |
203 | } | |
204 | ||
1ffcd67d | 205 | static inline u32 asc_txfifo_is_half_empty(struct uart_port *port) |
c4b05856 | 206 | { |
1ffcd67d | 207 | return asc_in(port, ASC_STA) & ASC_STA_THE; |
c4b05856 SK |
208 | } |
209 | ||
210 | static inline const char *asc_port_name(struct uart_port *port) | |
211 | { | |
212 | return to_platform_device(port->dev)->name; | |
213 | } | |
214 | ||
215 | /*----------------------------------------------------------------------*/ | |
216 | ||
217 | /* | |
218 | * This section contains code to support the use of the ASC as a | |
219 | * generic serial port. | |
220 | */ | |
221 | ||
222 | static inline unsigned asc_hw_txroom(struct uart_port *port) | |
223 | { | |
224 | u32 status = asc_in(port, ASC_STA); | |
225 | ||
226 | if (status & ASC_STA_THE) | |
227 | return port->fifosize / 2; | |
228 | else if (!(status & ASC_STA_TF)) | |
229 | return 1; | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | /* | |
235 | * Start transmitting chars. | |
236 | * This is called from both interrupt and task level. | |
237 | * Either way interrupts are disabled. | |
238 | */ | |
239 | static void asc_transmit_chars(struct uart_port *port) | |
240 | { | |
241 | struct circ_buf *xmit = &port->state->xmit; | |
242 | int txroom; | |
243 | unsigned char c; | |
244 | ||
245 | txroom = asc_hw_txroom(port); | |
246 | ||
247 | if ((txroom != 0) && port->x_char) { | |
248 | c = port->x_char; | |
249 | port->x_char = 0; | |
250 | asc_out(port, ASC_TXBUF, c); | |
251 | port->icount.tx++; | |
252 | txroom = asc_hw_txroom(port); | |
253 | } | |
254 | ||
255 | if (uart_tx_stopped(port)) { | |
256 | /* | |
257 | * We should try and stop the hardware here, but I | |
258 | * don't think the ASC has any way to do that. | |
259 | */ | |
260 | asc_disable_tx_interrupts(port); | |
261 | return; | |
262 | } | |
263 | ||
264 | if (uart_circ_empty(xmit)) { | |
265 | asc_disable_tx_interrupts(port); | |
266 | return; | |
267 | } | |
268 | ||
269 | if (txroom == 0) | |
270 | return; | |
271 | ||
272 | do { | |
273 | c = xmit->buf[xmit->tail]; | |
274 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | |
275 | asc_out(port, ASC_TXBUF, c); | |
276 | port->icount.tx++; | |
277 | txroom--; | |
278 | } while ((txroom > 0) && (!uart_circ_empty(xmit))); | |
279 | ||
280 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | |
281 | uart_write_wakeup(port); | |
282 | ||
283 | if (uart_circ_empty(xmit)) | |
284 | asc_disable_tx_interrupts(port); | |
285 | } | |
286 | ||
287 | static void asc_receive_chars(struct uart_port *port) | |
288 | { | |
289 | struct tty_port *tport = &port->state->port; | |
290 | unsigned long status; | |
291 | unsigned long c = 0; | |
292 | char flag; | |
293 | ||
294 | if (port->irq_wake) | |
295 | pm_wakeup_event(tport->tty->dev, 0); | |
296 | ||
297 | while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) { | |
298 | c = asc_in(port, ASC_RXBUF) | ASC_RXBUF_DUMMY_RX; | |
299 | flag = TTY_NORMAL; | |
300 | port->icount.rx++; | |
301 | ||
302 | if ((c & (ASC_RXBUF_FE | ASC_RXBUF_PE)) || | |
303 | status & ASC_STA_OE) { | |
304 | ||
305 | if (c & ASC_RXBUF_FE) { | |
c3c00b6f | 306 | if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) { |
c4b05856 SK |
307 | port->icount.brk++; |
308 | if (uart_handle_break(port)) | |
309 | continue; | |
310 | c |= ASC_RXBUF_DUMMY_BE; | |
311 | } else { | |
312 | port->icount.frame++; | |
313 | } | |
314 | } else if (c & ASC_RXBUF_PE) { | |
315 | port->icount.parity++; | |
316 | } | |
317 | /* | |
318 | * Reading any data from the RX FIFO clears the | |
319 | * overflow error condition. | |
320 | */ | |
321 | if (status & ASC_STA_OE) { | |
322 | port->icount.overrun++; | |
323 | c |= ASC_RXBUF_DUMMY_OE; | |
324 | } | |
325 | ||
326 | c &= port->read_status_mask; | |
327 | ||
328 | if (c & ASC_RXBUF_DUMMY_BE) | |
329 | flag = TTY_BREAK; | |
330 | else if (c & ASC_RXBUF_PE) | |
331 | flag = TTY_PARITY; | |
332 | else if (c & ASC_RXBUF_FE) | |
333 | flag = TTY_FRAME; | |
334 | } | |
335 | ||
c3c00b6f | 336 | if (uart_handle_sysrq_char(port, c & 0xff)) |
c4b05856 SK |
337 | continue; |
338 | ||
339 | uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag); | |
340 | } | |
341 | ||
342 | /* Tell the rest of the system the news. New characters! */ | |
343 | tty_flip_buffer_push(tport); | |
344 | } | |
345 | ||
346 | static irqreturn_t asc_interrupt(int irq, void *ptr) | |
347 | { | |
348 | struct uart_port *port = ptr; | |
349 | u32 status; | |
350 | ||
351 | spin_lock(&port->lock); | |
352 | ||
353 | status = asc_in(port, ASC_STA); | |
354 | ||
355 | if (status & ASC_STA_RBF) { | |
356 | /* Receive FIFO not empty */ | |
357 | asc_receive_chars(port); | |
358 | } | |
359 | ||
360 | if ((status & ASC_STA_THE) && | |
361 | (asc_in(port, ASC_INTEN) & ASC_INTEN_THE)) { | |
362 | /* Transmitter FIFO at least half empty */ | |
363 | asc_transmit_chars(port); | |
364 | } | |
365 | ||
366 | spin_unlock(&port->lock); | |
367 | ||
368 | return IRQ_HANDLED; | |
369 | } | |
370 | ||
371 | /*----------------------------------------------------------------------*/ | |
372 | ||
373 | /* | |
374 | * UART Functions | |
375 | */ | |
376 | ||
377 | static unsigned int asc_tx_empty(struct uart_port *port) | |
378 | { | |
379 | return asc_txfifo_is_empty(port) ? TIOCSER_TEMT : 0; | |
380 | } | |
381 | ||
382 | static void asc_set_mctrl(struct uart_port *port, unsigned int mctrl) | |
383 | { | |
384 | /* | |
385 | * This routine is used for seting signals of: DTR, DCD, CTS/RTS | |
386 | * We use ASC's hardware for CTS/RTS, so don't need any for that. | |
387 | * Some boards have DTR and DCD implemented using PIO pins, | |
388 | * code to do this should be hooked in here. | |
389 | */ | |
390 | } | |
391 | ||
392 | static unsigned int asc_get_mctrl(struct uart_port *port) | |
393 | { | |
394 | /* | |
395 | * This routine is used for geting signals of: DTR, DCD, DSR, RI, | |
396 | * and CTS/RTS | |
397 | */ | |
398 | return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; | |
399 | } | |
400 | ||
401 | /* There are probably characters waiting to be transmitted. */ | |
402 | static void asc_start_tx(struct uart_port *port) | |
403 | { | |
404 | struct circ_buf *xmit = &port->state->xmit; | |
405 | ||
406 | if (!uart_circ_empty(xmit)) | |
407 | asc_enable_tx_interrupts(port); | |
408 | } | |
409 | ||
410 | /* Transmit stop */ | |
411 | static void asc_stop_tx(struct uart_port *port) | |
412 | { | |
413 | asc_disable_tx_interrupts(port); | |
414 | } | |
415 | ||
416 | /* Receive stop */ | |
417 | static void asc_stop_rx(struct uart_port *port) | |
418 | { | |
419 | asc_disable_rx_interrupts(port); | |
420 | } | |
421 | ||
c4b05856 SK |
422 | /* Handle breaks - ignored by us */ |
423 | static void asc_break_ctl(struct uart_port *port, int break_state) | |
424 | { | |
425 | /* Nothing here yet .. */ | |
426 | } | |
427 | ||
428 | /* | |
429 | * Enable port for reception. | |
430 | */ | |
431 | static int asc_startup(struct uart_port *port) | |
432 | { | |
616ea8d2 | 433 | if (request_irq(port->irq, asc_interrupt, 0, |
c4b05856 SK |
434 | asc_port_name(port), port)) { |
435 | dev_err(port->dev, "cannot allocate irq.\n"); | |
436 | return -ENODEV; | |
437 | } | |
438 | ||
439 | asc_transmit_chars(port); | |
440 | asc_enable_rx_interrupts(port); | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | static void asc_shutdown(struct uart_port *port) | |
446 | { | |
447 | asc_disable_tx_interrupts(port); | |
448 | asc_disable_rx_interrupts(port); | |
449 | free_irq(port->irq, port); | |
450 | } | |
451 | ||
452 | static void asc_pm(struct uart_port *port, unsigned int state, | |
453 | unsigned int oldstate) | |
454 | { | |
455 | struct asc_port *ascport = to_asc_port(port); | |
456 | unsigned long flags = 0; | |
457 | u32 ctl; | |
458 | ||
459 | switch (state) { | |
460 | case UART_PM_STATE_ON: | |
461 | clk_prepare_enable(ascport->clk); | |
462 | break; | |
463 | case UART_PM_STATE_OFF: | |
464 | /* | |
465 | * Disable the ASC baud rate generator, which is as close as | |
466 | * we can come to turning it off. Note this is not called with | |
467 | * the port spinlock held. | |
468 | */ | |
469 | spin_lock_irqsave(&port->lock, flags); | |
470 | ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN; | |
471 | asc_out(port, ASC_CTL, ctl); | |
472 | spin_unlock_irqrestore(&port->lock, flags); | |
473 | clk_disable_unprepare(ascport->clk); | |
474 | break; | |
475 | } | |
476 | } | |
477 | ||
478 | static void asc_set_termios(struct uart_port *port, struct ktermios *termios, | |
479 | struct ktermios *old) | |
480 | { | |
481 | struct asc_port *ascport = to_asc_port(port); | |
482 | unsigned int baud; | |
483 | u32 ctrl_val; | |
484 | tcflag_t cflag; | |
485 | unsigned long flags; | |
486 | ||
487 | /* Update termios to reflect hardware capabilities */ | |
488 | termios->c_cflag &= ~(CMSPAR | | |
489 | (ascport->hw_flow_control ? 0 : CRTSCTS)); | |
490 | ||
491 | port->uartclk = clk_get_rate(ascport->clk); | |
492 | ||
493 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | |
494 | cflag = termios->c_cflag; | |
495 | ||
496 | spin_lock_irqsave(&port->lock, flags); | |
497 | ||
498 | /* read control register */ | |
499 | ctrl_val = asc_in(port, ASC_CTL); | |
500 | ||
501 | /* stop serial port and reset value */ | |
502 | asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN)); | |
503 | ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE; | |
504 | ||
505 | /* reset fifo rx & tx */ | |
506 | asc_out(port, ASC_TXRESET, 1); | |
507 | asc_out(port, ASC_RXRESET, 1); | |
508 | ||
509 | /* set character length */ | |
510 | if ((cflag & CSIZE) == CS7) { | |
511 | ctrl_val |= ASC_CTL_MODE_7BIT_PAR; | |
512 | } else { | |
513 | ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR : | |
514 | ASC_CTL_MODE_8BIT; | |
515 | } | |
516 | ||
517 | /* set stop bit */ | |
518 | ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT; | |
519 | ||
520 | /* odd parity */ | |
521 | if (cflag & PARODD) | |
522 | ctrl_val |= ASC_CTL_PARITYODD; | |
523 | ||
524 | /* hardware flow control */ | |
525 | if ((cflag & CRTSCTS)) | |
526 | ctrl_val |= ASC_CTL_CTSENABLE; | |
527 | ||
528 | if ((baud < 19200) && !ascport->force_m1) { | |
529 | asc_out(port, ASC_BAUDRATE, (port->uartclk / (16 * baud))); | |
530 | } else { | |
531 | /* | |
532 | * MODE 1: recommended for high bit rates (above 19.2K) | |
533 | * | |
534 | * baudrate * 16 * 2^16 | |
535 | * ASCBaudRate = ------------------------ | |
536 | * inputclock | |
537 | * | |
1d6ba284 | 538 | * To keep maths inside 64bits, we divide inputclock by 16. |
c4b05856 | 539 | */ |
1d6ba284 MC |
540 | u64 dividend = (u64)baud * (1 << 16); |
541 | ||
542 | do_div(dividend, port->uartclk / 16); | |
543 | asc_out(port, ASC_BAUDRATE, dividend); | |
c4b05856 SK |
544 | ctrl_val |= ASC_CTL_BAUDMODE; |
545 | } | |
546 | ||
547 | uart_update_timeout(port, cflag, baud); | |
548 | ||
549 | ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE; | |
550 | if (termios->c_iflag & INPCK) | |
551 | ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; | |
ef8b9ddc | 552 | if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) |
c4b05856 SK |
553 | ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE; |
554 | ||
555 | /* | |
556 | * Characters to ignore | |
557 | */ | |
558 | ascport->port.ignore_status_mask = 0; | |
559 | if (termios->c_iflag & IGNPAR) | |
560 | ascport->port.ignore_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; | |
561 | if (termios->c_iflag & IGNBRK) { | |
562 | ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_BE; | |
563 | /* | |
564 | * If we're ignoring parity and break indicators, | |
565 | * ignore overruns too (for real raw support). | |
566 | */ | |
567 | if (termios->c_iflag & IGNPAR) | |
568 | ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_OE; | |
569 | } | |
570 | ||
571 | /* | |
572 | * Ignore all characters if CREAD is not set. | |
573 | */ | |
574 | if (!(termios->c_cflag & CREAD)) | |
575 | ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_RX; | |
576 | ||
577 | /* Set the timeout */ | |
578 | asc_out(port, ASC_TIMEOUT, 20); | |
579 | ||
580 | /* write final value and enable port */ | |
581 | asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN)); | |
582 | ||
583 | spin_unlock_irqrestore(&port->lock, flags); | |
584 | } | |
585 | ||
586 | static const char *asc_type(struct uart_port *port) | |
587 | { | |
588 | return (port->type == PORT_ASC) ? DRIVER_NAME : NULL; | |
589 | } | |
590 | ||
591 | static void asc_release_port(struct uart_port *port) | |
592 | { | |
593 | } | |
594 | ||
595 | static int asc_request_port(struct uart_port *port) | |
596 | { | |
597 | return 0; | |
598 | } | |
599 | ||
600 | /* | |
601 | * Called when the port is opened, and UPF_BOOT_AUTOCONF flag is set | |
602 | * Set type field if successful | |
603 | */ | |
604 | static void asc_config_port(struct uart_port *port, int flags) | |
605 | { | |
606 | if ((flags & UART_CONFIG_TYPE)) | |
607 | port->type = PORT_ASC; | |
608 | } | |
609 | ||
610 | static int | |
611 | asc_verify_port(struct uart_port *port, struct serial_struct *ser) | |
612 | { | |
613 | /* No user changeable parameters */ | |
614 | return -EINVAL; | |
615 | } | |
616 | ||
617 | #ifdef CONFIG_CONSOLE_POLL | |
618 | /* | |
619 | * Console polling routines for writing and reading from the uart while | |
620 | * in an interrupt or debug context (i.e. kgdb). | |
621 | */ | |
622 | ||
623 | static int asc_get_poll_char(struct uart_port *port) | |
624 | { | |
625 | if (!(asc_in(port, ASC_STA) & ASC_STA_RBF)) | |
626 | return NO_POLL_CHAR; | |
627 | ||
628 | return asc_in(port, ASC_RXBUF); | |
629 | } | |
630 | ||
631 | static void asc_put_poll_char(struct uart_port *port, unsigned char c) | |
632 | { | |
1ffcd67d | 633 | while (!asc_txfifo_is_half_empty(port)) |
c4b05856 SK |
634 | cpu_relax(); |
635 | asc_out(port, ASC_TXBUF, c); | |
636 | } | |
637 | ||
638 | #endif /* CONFIG_CONSOLE_POLL */ | |
639 | ||
640 | /*---------------------------------------------------------------------*/ | |
641 | ||
642 | static struct uart_ops asc_uart_ops = { | |
643 | .tx_empty = asc_tx_empty, | |
644 | .set_mctrl = asc_set_mctrl, | |
645 | .get_mctrl = asc_get_mctrl, | |
646 | .start_tx = asc_start_tx, | |
647 | .stop_tx = asc_stop_tx, | |
648 | .stop_rx = asc_stop_rx, | |
c4b05856 SK |
649 | .break_ctl = asc_break_ctl, |
650 | .startup = asc_startup, | |
651 | .shutdown = asc_shutdown, | |
652 | .set_termios = asc_set_termios, | |
653 | .type = asc_type, | |
654 | .release_port = asc_release_port, | |
655 | .request_port = asc_request_port, | |
656 | .config_port = asc_config_port, | |
657 | .verify_port = asc_verify_port, | |
658 | .pm = asc_pm, | |
659 | #ifdef CONFIG_CONSOLE_POLL | |
660 | .poll_get_char = asc_get_poll_char, | |
661 | .poll_put_char = asc_put_poll_char, | |
662 | #endif /* CONFIG_CONSOLE_POLL */ | |
663 | }; | |
664 | ||
665 | static int asc_init_port(struct asc_port *ascport, | |
666 | struct platform_device *pdev) | |
667 | { | |
668 | struct uart_port *port = &ascport->port; | |
3abeff77 | 669 | struct resource *res; |
c4b05856 SK |
670 | |
671 | port->iotype = UPIO_MEM; | |
672 | port->flags = UPF_BOOT_AUTOCONF; | |
673 | port->ops = &asc_uart_ops; | |
674 | port->fifosize = ASC_FIFO_SIZE; | |
675 | port->dev = &pdev->dev; | |
c4b05856 SK |
676 | port->irq = platform_get_irq(pdev, 0); |
677 | ||
3abeff77 JL |
678 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
679 | port->membase = devm_ioremap_resource(&pdev->dev, res); | |
680 | if (IS_ERR(port->membase)) | |
681 | return PTR_ERR(port->membase); | |
682 | port->mapbase = res->start; | |
c4b05856 SK |
683 | |
684 | spin_lock_init(&port->lock); | |
685 | ||
686 | ascport->clk = devm_clk_get(&pdev->dev, NULL); | |
687 | ||
688 | if (WARN_ON(IS_ERR(ascport->clk))) | |
689 | return -EINVAL; | |
690 | /* ensure that clk rate is correct by enabling the clk */ | |
691 | clk_prepare_enable(ascport->clk); | |
692 | ascport->port.uartclk = clk_get_rate(ascport->clk); | |
693 | WARN_ON(ascport->port.uartclk == 0); | |
694 | clk_disable_unprepare(ascport->clk); | |
695 | ||
696 | return 0; | |
697 | } | |
698 | ||
699 | static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev) | |
700 | { | |
701 | struct device_node *np = pdev->dev.of_node; | |
702 | int id; | |
703 | ||
704 | if (!np) | |
705 | return NULL; | |
706 | ||
707 | id = of_alias_get_id(np, ASC_SERIAL_NAME); | |
708 | ||
709 | if (id < 0) | |
710 | id = 0; | |
711 | ||
712 | if (WARN_ON(id >= ASC_MAX_PORTS)) | |
713 | return NULL; | |
714 | ||
715 | asc_ports[id].hw_flow_control = of_property_read_bool(np, | |
716 | "st,hw-flow-control"); | |
717 | asc_ports[id].force_m1 = of_property_read_bool(np, "st,force_m1"); | |
718 | asc_ports[id].port.line = id; | |
719 | return &asc_ports[id]; | |
720 | } | |
721 | ||
a4f2dc9e | 722 | #ifdef CONFIG_OF |
ed0bb232 | 723 | static const struct of_device_id asc_match[] = { |
c4b05856 SK |
724 | { .compatible = "st,asc", }, |
725 | {}, | |
726 | }; | |
727 | ||
728 | MODULE_DEVICE_TABLE(of, asc_match); | |
a4f2dc9e | 729 | #endif |
c4b05856 SK |
730 | |
731 | static int asc_serial_probe(struct platform_device *pdev) | |
732 | { | |
733 | int ret; | |
734 | struct asc_port *ascport; | |
735 | ||
736 | ascport = asc_of_get_asc_port(pdev); | |
737 | if (!ascport) | |
738 | return -ENODEV; | |
739 | ||
740 | ret = asc_init_port(ascport, pdev); | |
741 | if (ret) | |
742 | return ret; | |
743 | ||
744 | ret = uart_add_one_port(&asc_uart_driver, &ascport->port); | |
745 | if (ret) | |
746 | return ret; | |
747 | ||
748 | platform_set_drvdata(pdev, &ascport->port); | |
749 | ||
750 | return 0; | |
751 | } | |
752 | ||
753 | static int asc_serial_remove(struct platform_device *pdev) | |
754 | { | |
755 | struct uart_port *port = platform_get_drvdata(pdev); | |
756 | ||
c4b05856 SK |
757 | return uart_remove_one_port(&asc_uart_driver, port); |
758 | } | |
759 | ||
760 | #ifdef CONFIG_PM_SLEEP | |
761 | static int asc_serial_suspend(struct device *dev) | |
762 | { | |
763 | struct platform_device *pdev = to_platform_device(dev); | |
764 | struct uart_port *port = platform_get_drvdata(pdev); | |
765 | ||
766 | return uart_suspend_port(&asc_uart_driver, port); | |
767 | } | |
768 | ||
769 | static int asc_serial_resume(struct device *dev) | |
770 | { | |
771 | struct platform_device *pdev = to_platform_device(dev); | |
772 | struct uart_port *port = platform_get_drvdata(pdev); | |
773 | ||
774 | return uart_resume_port(&asc_uart_driver, port); | |
775 | } | |
776 | ||
777 | #endif /* CONFIG_PM_SLEEP */ | |
778 | ||
779 | /*----------------------------------------------------------------------*/ | |
780 | ||
781 | #ifdef CONFIG_SERIAL_ST_ASC_CONSOLE | |
782 | static void asc_console_putchar(struct uart_port *port, int ch) | |
783 | { | |
784 | unsigned int timeout = 1000000; | |
785 | ||
786 | /* Wait for upto 1 second in case flow control is stopping us. */ | |
1ffcd67d | 787 | while (--timeout && !asc_txfifo_is_half_empty(port)) |
c4b05856 SK |
788 | udelay(1); |
789 | ||
790 | asc_out(port, ASC_TXBUF, ch); | |
791 | } | |
792 | ||
793 | /* | |
794 | * Print a string to the serial port trying not to disturb | |
795 | * any possible real use of the port... | |
796 | */ | |
797 | ||
798 | static void asc_console_write(struct console *co, const char *s, unsigned count) | |
799 | { | |
800 | struct uart_port *port = &asc_ports[co->index].port; | |
801 | unsigned long flags; | |
802 | unsigned long timeout = 1000000; | |
803 | int locked = 1; | |
804 | u32 intenable; | |
805 | ||
806 | local_irq_save(flags); | |
807 | if (port->sysrq) | |
808 | locked = 0; /* asc_interrupt has already claimed the lock */ | |
809 | else if (oops_in_progress) | |
810 | locked = spin_trylock(&port->lock); | |
811 | else | |
812 | spin_lock(&port->lock); | |
813 | ||
814 | /* | |
815 | * Disable interrupts so we don't get the IRQ line bouncing | |
816 | * up and down while interrupts are disabled. | |
817 | */ | |
818 | intenable = asc_in(port, ASC_INTEN); | |
819 | asc_out(port, ASC_INTEN, 0); | |
820 | (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */ | |
821 | ||
822 | uart_console_write(port, s, count, asc_console_putchar); | |
823 | ||
824 | while (--timeout && !asc_txfifo_is_empty(port)) | |
825 | udelay(1); | |
826 | ||
827 | asc_out(port, ASC_INTEN, intenable); | |
828 | ||
829 | if (locked) | |
830 | spin_unlock(&port->lock); | |
831 | local_irq_restore(flags); | |
832 | } | |
833 | ||
834 | static int asc_console_setup(struct console *co, char *options) | |
835 | { | |
836 | struct asc_port *ascport; | |
837 | int baud = 9600; | |
838 | int bits = 8; | |
839 | int parity = 'n'; | |
840 | int flow = 'n'; | |
841 | ||
842 | if (co->index >= ASC_MAX_PORTS) | |
843 | return -ENODEV; | |
844 | ||
845 | ascport = &asc_ports[co->index]; | |
846 | ||
847 | /* | |
848 | * This driver does not support early console initialization | |
849 | * (use ARM early printk support instead), so we only expect | |
850 | * this to be called during the uart port registration when the | |
851 | * driver gets probed and the port should be mapped at that point. | |
852 | */ | |
5b4e79ae MC |
853 | if (ascport->port.mapbase == 0 || ascport->port.membase == NULL) |
854 | return -ENXIO; | |
c4b05856 SK |
855 | |
856 | if (options) | |
857 | uart_parse_options(options, &baud, &parity, &bits, &flow); | |
858 | ||
859 | return uart_set_options(&ascport->port, co, baud, parity, bits, flow); | |
860 | } | |
861 | ||
862 | static struct console asc_console = { | |
863 | .name = ASC_SERIAL_NAME, | |
864 | .device = uart_console_device, | |
865 | .write = asc_console_write, | |
866 | .setup = asc_console_setup, | |
867 | .flags = CON_PRINTBUFFER, | |
868 | .index = -1, | |
869 | .data = &asc_uart_driver, | |
870 | }; | |
871 | ||
872 | #define ASC_SERIAL_CONSOLE (&asc_console) | |
873 | ||
874 | #else | |
875 | #define ASC_SERIAL_CONSOLE NULL | |
876 | #endif /* CONFIG_SERIAL_ST_ASC_CONSOLE */ | |
877 | ||
878 | static struct uart_driver asc_uart_driver = { | |
879 | .owner = THIS_MODULE, | |
880 | .driver_name = DRIVER_NAME, | |
881 | .dev_name = ASC_SERIAL_NAME, | |
882 | .major = 0, | |
883 | .minor = 0, | |
884 | .nr = ASC_MAX_PORTS, | |
885 | .cons = ASC_SERIAL_CONSOLE, | |
886 | }; | |
887 | ||
888 | static const struct dev_pm_ops asc_serial_pm_ops = { | |
889 | SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume) | |
890 | }; | |
891 | ||
892 | static struct platform_driver asc_serial_driver = { | |
893 | .probe = asc_serial_probe, | |
894 | .remove = asc_serial_remove, | |
895 | .driver = { | |
896 | .name = DRIVER_NAME, | |
897 | .pm = &asc_serial_pm_ops, | |
c4b05856 SK |
898 | .of_match_table = of_match_ptr(asc_match), |
899 | }, | |
900 | }; | |
901 | ||
902 | static int __init asc_init(void) | |
903 | { | |
904 | int ret; | |
905 | static char banner[] __initdata = | |
906 | KERN_INFO "STMicroelectronics ASC driver initialized\n"; | |
907 | ||
908 | printk(banner); | |
909 | ||
910 | ret = uart_register_driver(&asc_uart_driver); | |
911 | if (ret) | |
912 | return ret; | |
913 | ||
914 | ret = platform_driver_register(&asc_serial_driver); | |
915 | if (ret) | |
916 | uart_unregister_driver(&asc_uart_driver); | |
917 | ||
918 | return ret; | |
919 | } | |
920 | ||
921 | static void __exit asc_exit(void) | |
922 | { | |
923 | platform_driver_unregister(&asc_serial_driver); | |
924 | uart_unregister_driver(&asc_uart_driver); | |
925 | } | |
926 | ||
927 | module_init(asc_init); | |
928 | module_exit(asc_exit); | |
929 | ||
930 | MODULE_ALIAS("platform:" DRIVER_NAME); | |
931 | MODULE_AUTHOR("STMicroelectronics (R&D) Limited"); | |
932 | MODULE_DESCRIPTION("STMicroelectronics ASC serial port driver"); | |
933 | MODULE_LICENSE("GPL"); |