diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/serial/v850e_uart.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/serial/v850e_uart.c')
-rw-r--r-- | drivers/serial/v850e_uart.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c new file mode 100644 index 000000000000..bb482780a41d --- /dev/null +++ b/drivers/serial/v850e_uart.c | |||
@@ -0,0 +1,549 @@ | |||
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"); | ||