Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/drivers/serial/v850e_uart.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 15693 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 15693 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | /* |
2 | * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB |
3 | * |
4 | * Copyright (C) 2001,02,03 NEC Electronics Corporation |
5 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> |
6 | * |
7 | * This file is subject to the terms and conditions of the GNU General |
8 | * Public License. See the file COPYING in the main directory of this |
9 | * archive for more details. |
10 | * |
11 | * Written by Miles Bader <miles@gnu.org> |
12 | */ |
13 | |
14 | /* This driver supports both the original V850E UART interface (called |
15 | merely `UART' in the docs) and the newer `UARTB' interface, which is |
16 | roughly a superset of the first one. The selection is made at |
17 | configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is |
18 | presumed, otherwise the old UART -- as these are on-CPU UARTS, a system |
19 | can never have both. |
20 | |
21 | The UARTB interface also has a 16-entry FIFO mode, which is not |
22 | yet supported by this driver. */ |
23 | |
24 | #include <linux/kernel.h> |
25 | #include <linux/init.h> |
26 | #include <linux/module.h> |
27 | #include <linux/console.h> |
28 | #include <linux/tty.h> |
29 | #include <linux/tty_flip.h> |
30 | #include <linux/serial.h> |
31 | #include <linux/serial_core.h> |
32 | |
33 | #include <asm/v850e_uart.h> |
34 | |
35 | /* Initial UART state. This may be overridden by machine-dependent headers. */ |
36 | #ifndef V850E_UART_INIT_BAUD |
37 | #define V850E_UART_INIT_BAUD 115200 |
38 | #endif |
39 | #ifndef V850E_UART_INIT_CFLAGS |
40 | #define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) |
41 | #endif |
42 | |
43 | /* A string used for prefixing printed descriptions; since the same UART |
44 | macro is actually used on other chips than the V850E. This must be a |
45 | constant string. */ |
46 | #ifndef V850E_UART_CHIP_NAME |
47 | #define V850E_UART_CHIP_NAME "V850E" |
48 | #endif |
49 | |
50 | #define V850E_UART_MINOR_BASE 64 /* First tty minor number */ |
51 | |
52 | |
53 | /* Low-level UART functions. */ |
54 | |
55 | /* Configure and turn on uart channel CHAN, using the termios `control |
56 | modes' bits in CFLAGS, and a baud-rate of BAUD. */ |
57 | void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) |
58 | { |
59 | int flags; |
60 | v850e_uart_speed_t old_speed; |
61 | v850e_uart_config_t old_config; |
62 | v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); |
63 | v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); |
64 | |
65 | /* Disable interrupts while we're twiddling the hardware. */ |
66 | local_irq_save (flags); |
67 | |
68 | #ifdef V850E_UART_PRE_CONFIGURE |
69 | V850E_UART_PRE_CONFIGURE (chan, cflags, baud); |
70 | #endif |
71 | |
72 | old_config = V850E_UART_CONFIG (chan); |
73 | old_speed = v850e_uart_speed (chan); |
74 | |
75 | if (! v850e_uart_speed_eq (old_speed, new_speed)) { |
76 | /* The baud rate has changed. First, disable the UART. */ |
77 | V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; |
78 | old_config = 0; /* Force the uart to be re-initialized. */ |
79 | |
80 | /* Reprogram the baud-rate generator. */ |
81 | v850e_uart_set_speed (chan, new_speed); |
82 | } |
83 | |
84 | if (! (old_config & V850E_UART_CONFIG_ENABLED)) { |
85 | /* If we are using the uart for the first time, start by |
86 | enabling it, which must be done before turning on any |
87 | other bits. */ |
88 | V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; |
89 | /* See the initial state. */ |
90 | old_config = V850E_UART_CONFIG (chan); |
91 | } |
92 | |
93 | if (new_config != old_config) { |
94 | /* Which of the TXE/RXE bits we'll temporarily turn off |
95 | before changing other control bits. */ |
96 | unsigned temp_disable = 0; |
97 | /* Which of the TXE/RXE bits will be enabled. */ |
98 | unsigned enable = 0; |
99 | unsigned changed_bits = new_config ^ old_config; |
100 | |
101 | /* Which of RX/TX will be enabled in the new configuration. */ |
102 | if (new_config & V850E_UART_CONFIG_RX_BITS) |
103 | enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); |
104 | if (new_config & V850E_UART_CONFIG_TX_BITS) |
105 | enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); |
106 | |
107 | /* Figure out which of RX/TX needs to be disabled; note |
108 | that this will only happen if they're not already |
109 | disabled. */ |
110 | if (changed_bits & V850E_UART_CONFIG_RX_BITS) |
111 | temp_disable |
112 | |= (old_config & V850E_UART_CONFIG_RX_ENABLE); |
113 | if (changed_bits & V850E_UART_CONFIG_TX_BITS) |
114 | temp_disable |
115 | |= (old_config & V850E_UART_CONFIG_TX_ENABLE); |
116 | |
117 | /* We have to turn off RX and/or TX mode before changing |
118 | any associated control bits. */ |
119 | if (temp_disable) |
120 | V850E_UART_CONFIG (chan) = old_config & ~temp_disable; |
121 | |
122 | /* Write the new control bits, while RX/TX are disabled. */ |
123 | if (changed_bits & ~enable) |
124 | V850E_UART_CONFIG (chan) = new_config & ~enable; |
125 | |
126 | v850e_uart_config_delay (new_config, new_speed); |
127 | |
128 | /* Write the final version, with enable bits turned on. */ |
129 | V850E_UART_CONFIG (chan) = new_config; |
130 | } |
131 | |
132 | local_irq_restore (flags); |
133 | } |
134 | |
135 | |
136 | /* Low-level console. */ |
137 | |
138 | #ifdef CONFIG_V850E_UART_CONSOLE |
139 | |
140 | static void v850e_uart_cons_write (struct console *co, |
141 | const char *s, unsigned count) |
142 | { |
143 | if (count > 0) { |
144 | unsigned chan = co->index; |
145 | unsigned irq = V850E_UART_TX_IRQ (chan); |
146 | int irq_was_enabled, irq_was_pending, flags; |
147 | |
148 | /* We don't want to get `transmission completed' |
149 | interrupts, since we're busy-waiting, so we disable them |
150 | while sending (we don't disable interrupts entirely |
151 | because sending over a serial line is really slow). We |
152 | save the status of the tx interrupt and restore it when |
153 | we're done so that using printk doesn't interfere with |
154 | normal serial transmission (other than interleaving the |
155 | output, of course!). This should work correctly even if |
156 | this function is interrupted and the interrupt printks |
157 | something. */ |
158 | |
159 | /* Disable interrupts while fiddling with tx interrupt. */ |
160 | local_irq_save (flags); |
161 | /* Get current tx interrupt status. */ |
162 | irq_was_enabled = v850e_intc_irq_enabled (irq); |
163 | irq_was_pending = v850e_intc_irq_pending (irq); |
164 | /* Disable tx interrupt if necessary. */ |
165 | if (irq_was_enabled) |
166 | v850e_intc_disable_irq (irq); |
167 | /* Turn interrupts back on. */ |
168 | local_irq_restore (flags); |
169 | |
170 | /* Send characters. */ |
171 | while (count > 0) { |
172 | int ch = *s++; |
173 | |
174 | if (ch == '\n') { |
175 | /* We don't have the benefit of a tty |
176 | driver, so translate NL into CR LF. */ |
177 | v850e_uart_wait_for_xmit_ok (chan); |
178 | v850e_uart_putc (chan, '\r'); |
179 | } |
180 | |
181 | v850e_uart_wait_for_xmit_ok (chan); |
182 | v850e_uart_putc (chan, ch); |
183 | |
184 | count--; |
185 | } |
186 | |
187 | /* Restore saved tx interrupt status. */ |
188 | if (irq_was_enabled) { |
189 | /* Wait for the last character we sent to be |
190 | completely transmitted (as we'll get an |
191 | interrupt interrupt at that point). */ |
192 | v850e_uart_wait_for_xmit_done (chan); |
193 | /* Clear pending interrupts received due |
194 | to our transmission, unless there was already |
195 | one pending, in which case we want the |
196 | handler to be called. */ |
197 | if (! irq_was_pending) |
198 | v850e_intc_clear_pending_irq (irq); |
199 | /* ... and then turn back on handling. */ |
200 | v850e_intc_enable_irq (irq); |
201 | } |
202 | } |
203 | } |
204 | |
205 | extern struct uart_driver v850e_uart_driver; |
206 | static struct console v850e_uart_cons = |
207 | { |
208 | .name = "ttyS", |
209 | .write = v850e_uart_cons_write, |
210 | .device = uart_console_device, |
211 | .flags = CON_PRINTBUFFER, |
212 | .cflag = V850E_UART_INIT_CFLAGS, |
213 | .index = -1, |
214 | .data = &v850e_uart_driver, |
215 | }; |
216 | |
217 | void v850e_uart_cons_init (unsigned chan) |
218 | { |
219 | v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, |
220 | V850E_UART_INIT_BAUD); |
221 | v850e_uart_cons.index = chan; |
222 | register_console (&v850e_uart_cons); |
223 | printk ("Console: %s on-chip UART channel %d\n", |
224 | V850E_UART_CHIP_NAME, chan); |
225 | } |
226 | |
227 | /* This is what the init code actually calls. */ |
228 | static int v850e_uart_console_init (void) |
229 | { |
230 | v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); |
231 | return 0; |
232 | } |
233 | console_initcall(v850e_uart_console_init); |
234 | |
235 | #define V850E_UART_CONSOLE &v850e_uart_cons |
236 | |
237 | #else /* !CONFIG_V850E_UART_CONSOLE */ |
238 | #define V850E_UART_CONSOLE 0 |
239 | #endif /* CONFIG_V850E_UART_CONSOLE */ |
240 | |
241 | /* TX/RX interrupt handlers. */ |
242 | |
243 | static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop); |
244 | |
245 | void v850e_uart_tx (struct uart_port *port) |
246 | { |
247 | struct circ_buf *xmit = &port->info->xmit; |
248 | int stopped = uart_tx_stopped (port); |
249 | |
250 | if (v850e_uart_xmit_ok (port->line)) { |
251 | int tx_ch; |
252 | |
253 | if (port->x_char) { |
254 | tx_ch = port->x_char; |
255 | port->x_char = 0; |
256 | } else if (!uart_circ_empty (xmit) && !stopped) { |
257 | tx_ch = xmit->buf[xmit->tail]; |
258 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
259 | } else |
260 | goto no_xmit; |
261 | |
262 | v850e_uart_putc (port->line, tx_ch); |
263 | port->icount.tx++; |
264 | |
265 | if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) |
266 | uart_write_wakeup (port); |
267 | } |
268 | |
269 | no_xmit: |
270 | if (uart_circ_empty (xmit) || stopped) |
271 | v850e_uart_stop_tx (port, stopped); |
272 | } |
273 | |
274 | static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs) |
275 | { |
276 | struct uart_port *port = data; |
277 | v850e_uart_tx (port); |
278 | return IRQ_HANDLED; |
279 | } |
280 | |
281 | static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs) |
282 | { |
283 | struct uart_port *port = data; |
284 | unsigned ch_stat = TTY_NORMAL; |
285 | unsigned ch = v850e_uart_getc (port->line); |
286 | unsigned err = v850e_uart_err (port->line); |
287 | |
288 | if (err) { |
289 | if (err & V850E_UART_ERR_OVERRUN) { |
290 | ch_stat = TTY_OVERRUN; |
291 | port->icount.overrun++; |
292 | } else if (err & V850E_UART_ERR_FRAME) { |
293 | ch_stat = TTY_FRAME; |
294 | port->icount.frame++; |
295 | } else if (err & V850E_UART_ERR_PARITY) { |
296 | ch_stat = TTY_PARITY; |
297 | port->icount.parity++; |
298 | } |
299 | } |
300 | |
301 | port->icount.rx++; |
302 | |
303 | tty_insert_flip_char (port->info->tty, ch, ch_stat); |
304 | tty_schedule_flip (port->info->tty); |
305 | |
306 | return IRQ_HANDLED; |
307 | } |
308 | |
309 | |
310 | /* Control functions for the serial framework. */ |
311 | |
312 | static void v850e_uart_nop (struct uart_port *port) { } |
313 | static int v850e_uart_success (struct uart_port *port) { return 0; } |
314 | |
315 | static unsigned v850e_uart_tx_empty (struct uart_port *port) |
316 | { |
317 | return TIOCSER_TEMT; /* Can't detect. */ |
318 | } |
319 | |
320 | static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) |
321 | { |
322 | #ifdef V850E_UART_SET_RTS |
323 | V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); |
324 | #endif |
325 | } |
326 | |
327 | static unsigned v850e_uart_get_mctrl (struct uart_port *port) |
328 | { |
329 | /* We don't support DCD or DSR, so consider them permanently active. */ |
330 | int mctrl = TIOCM_CAR | TIOCM_DSR; |
331 | |
332 | /* We may support CTS. */ |
333 | #ifdef V850E_UART_CTS |
334 | mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; |
335 | #else |
336 | mctrl |= TIOCM_CTS; |
337 | #endif |
338 | |
339 | return mctrl; |
340 | } |
341 | |
342 | static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start) |
343 | { |
344 | v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); |
345 | v850e_uart_tx (port); |
346 | v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); |
347 | } |
348 | |
349 | static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop) |
350 | { |
351 | v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); |
352 | } |
353 | |
354 | static void v850e_uart_start_rx (struct uart_port *port) |
355 | { |
356 | v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); |
357 | } |
358 | |
359 | static void v850e_uart_stop_rx (struct uart_port *port) |
360 | { |
361 | v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); |
362 | } |
363 | |
364 | static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) |
365 | { |
366 | /* Umm, do this later. */ |
367 | } |
368 | |
369 | static int v850e_uart_startup (struct uart_port *port) |
370 | { |
371 | int err; |
372 | |
373 | /* Alloc RX irq. */ |
374 | err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, |
375 | SA_INTERRUPT, "v850e_uart", port); |
376 | if (err) |
377 | return err; |
378 | |
379 | /* Alloc TX irq. */ |
380 | err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, |
381 | SA_INTERRUPT, "v850e_uart", port); |
382 | if (err) { |
383 | free_irq (V850E_UART_RX_IRQ (port->line), port); |
384 | return err; |
385 | } |
386 | |
387 | v850e_uart_start_rx (port); |
388 | |
389 | return 0; |
390 | } |
391 | |
392 | static void v850e_uart_shutdown (struct uart_port *port) |
393 | { |
394 | /* Disable port interrupts. */ |
395 | free_irq (V850E_UART_TX_IRQ (port->line), port); |
396 | free_irq (V850E_UART_RX_IRQ (port->line), port); |
397 | |
398 | /* Turn off xmit/recv enable bits. */ |
399 | V850E_UART_CONFIG (port->line) |
400 | &= ~(V850E_UART_CONFIG_TX_ENABLE |
401 | | V850E_UART_CONFIG_RX_ENABLE); |
402 | /* Then reset the channel. */ |
403 | V850E_UART_CONFIG (port->line) = 0; |
404 | } |
405 | |
406 | static void |
407 | v850e_uart_set_termios (struct uart_port *port, struct termios *termios, |
408 | struct termios *old) |
409 | { |
410 | unsigned cflags = termios->c_cflag; |
411 | |
412 | /* Restrict flags to legal values. */ |
413 | if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) |
414 | /* The new value of CSIZE is invalid, use the old value. */ |
415 | cflags = (cflags & ~CSIZE) |
416 | | (old ? (old->c_cflag & CSIZE) : CS8); |
417 | |
418 | termios->c_cflag = cflags; |
419 | |
420 | v850e_uart_configure (port->line, cflags, |
421 | uart_get_baud_rate (port, termios, old, |
422 | v850e_uart_min_baud(), |
423 | v850e_uart_max_baud())); |
424 | } |
425 | |
426 | static const char *v850e_uart_type (struct uart_port *port) |
427 | { |
428 | return port->type == PORT_V850E_UART ? "v850e_uart" : 0; |
429 | } |
430 | |
431 | static void v850e_uart_config_port (struct uart_port *port, int flags) |
432 | { |
433 | if (flags & UART_CONFIG_TYPE) |
434 | port->type = PORT_V850E_UART; |
435 | } |
436 | |
437 | static int |
438 | v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) |
439 | { |
440 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) |
441 | return -EINVAL; |
442 | if (ser->irq != V850E_UART_TX_IRQ (port->line)) |
443 | return -EINVAL; |
444 | return 0; |
445 | } |
446 | |
447 | static struct uart_ops v850e_uart_ops = { |
448 | .tx_empty = v850e_uart_tx_empty, |
449 | .get_mctrl = v850e_uart_get_mctrl, |
450 | .set_mctrl = v850e_uart_set_mctrl, |
451 | .start_tx = v850e_uart_start_tx, |
452 | .stop_tx = v850e_uart_stop_tx, |
453 | .stop_rx = v850e_uart_stop_rx, |
454 | .enable_ms = v850e_uart_nop, |
455 | .break_ctl = v850e_uart_break_ctl, |
456 | .startup = v850e_uart_startup, |
457 | .shutdown = v850e_uart_shutdown, |
458 | .set_termios = v850e_uart_set_termios, |
459 | .type = v850e_uart_type, |
460 | .release_port = v850e_uart_nop, |
461 | .request_port = v850e_uart_success, |
462 | .config_port = v850e_uart_config_port, |
463 | .verify_port = v850e_uart_verify_port, |
464 | }; |
465 | |
466 | /* Initialization and cleanup. */ |
467 | |
468 | static struct uart_driver v850e_uart_driver = { |
469 | .owner = THIS_MODULE, |
470 | .driver_name = "v850e_uart", |
471 | .devfs_name = "tts/", |
472 | .dev_name = "ttyS", |
473 | .major = TTY_MAJOR, |
474 | .minor = V850E_UART_MINOR_BASE, |
475 | .nr = V850E_UART_NUM_CHANNELS, |
476 | .cons = V850E_UART_CONSOLE, |
477 | }; |
478 | |
479 | |
480 | static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; |
481 | |
482 | static int __init v850e_uart_init (void) |
483 | { |
484 | int rval; |
485 | |
486 | printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); |
487 | |
488 | rval = uart_register_driver (&v850e_uart_driver); |
489 | if (rval == 0) { |
490 | unsigned chan; |
491 | |
492 | for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { |
493 | struct uart_port *port = &v850e_uart_ports[chan]; |
494 | |
495 | memset (port, 0, sizeof *port); |
496 | |
497 | port->ops = &v850e_uart_ops; |
498 | port->line = chan; |
499 | port->iotype = SERIAL_IO_MEM; |
500 | port->flags = UPF_BOOT_AUTOCONF; |
501 | |
502 | /* We actually use multiple IRQs, but the serial |
503 | framework seems to mainly use this for |
504 | informational purposes anyway. Here we use the TX |
505 | irq. */ |
506 | port->irq = V850E_UART_TX_IRQ (chan); |
507 | |
508 | /* The serial framework doesn't really use these |
509 | membase/mapbase fields for anything useful, but |
510 | it requires that they be something non-zero to |
511 | consider the port `valid', and also uses them |
512 | for informational purposes. */ |
513 | port->membase = (void *)V850E_UART_BASE_ADDR (chan); |
514 | port->mapbase = V850E_UART_BASE_ADDR (chan); |
515 | |
516 | /* The framework insists on knowing the uart's master |
517 | clock freq, though it doesn't seem to do anything |
518 | useful for us with it. We must make it at least |
519 | higher than (the maximum baud rate * 16), otherwise |
520 | the framework will puke during its internal |
521 | calculations, and force the baud rate to be 9600. |
522 | To be accurate though, just repeat the calculation |
523 | we use when actually setting the speed. */ |
524 | port->uartclk = v850e_uart_max_clock() * 16; |
525 | |
526 | uart_add_one_port (&v850e_uart_driver, port); |
527 | } |
528 | } |
529 | |
530 | return rval; |
531 | } |
532 | |
533 | static void __exit v850e_uart_exit (void) |
534 | { |
535 | unsigned chan; |
536 | |
537 | for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) |
538 | uart_remove_one_port (&v850e_uart_driver, |
539 | &v850e_uart_ports[chan]); |
540 | |
541 | uart_unregister_driver (&v850e_uart_driver); |
542 | } |
543 | |
544 | module_init (v850e_uart_init); |
545 | module_exit (v850e_uart_exit); |
546 | |
547 | MODULE_AUTHOR ("Miles Bader"); |
548 | MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); |
549 | MODULE_LICENSE ("GPL"); |