aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndrew Victor <andrew@sanpeople.com>2007-05-11 16:37:25 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-05-11 17:02:52 -0400
commit2c7ee6ab7cb7261aacea91d41da8df1874772f3f (patch)
tree63e24f302030571fc367fa4ae76308d660ac12ec /drivers
parentc53c9cf60e49119e97d38390849cac5b2f0a0981 (diff)
[ARM] 4332/2: KS8695: Serial driver
A driver for the KS8695 internal UART. Based on the 2.6.9 driver from Micrel. Signed-off-by: Andrew Victor <andrew@sanpeople.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/Kconfig17
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_ks8695.c657
3 files changed, 675 insertions, 0 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a6f5bfbb777b..315ea9916456 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -359,6 +359,23 @@ config SERIAL_ATMEL_TTYAT
359 359
360 Say Y if you have an external 8250/16C550 UART. If unsure, say N. 360 Say Y if you have an external 8250/16C550 UART. If unsure, say N.
361 361
362config SERIAL_KS8695
363 bool "Micrel KS8695 (Centaur) serial port support"
364 depends on ARCH_KS8695
365 select SERIAL_CORE
366 help
367 This selects the Micrel Centaur KS8695 UART. Say Y here.
368
369config SERIAL_KS8695_CONSOLE
370 bool "Support for console on KS8695 (Centaur) serial port"
371 depends on SERIAL_KS8695=y
372 select SERIAL_CORE_CONSOLE
373 help
374 Say Y here if you wish to use a KS8695 (Centaur) UART as the
375 system console (the system console is the device which
376 receives all kernel messages and warnings and which allows
377 logins in single user mode).
378
362config SERIAL_CLPS711X 379config SERIAL_CLPS711X
363 tristate "CLPS711X serial port support" 380 tristate "CLPS711X serial port support"
364 depends on ARM && ARCH_CLPS711X 381 depends on ARM && ARCH_CLPS711X
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 4959bcb8d1ef..08ad0d978183 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
61obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o 61obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
62obj-$(CONFIG_SERIAL_NETX) += netx-serial.o 62obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
63obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o 63obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
64obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
new file mode 100644
index 000000000000..c5346d677315
--- /dev/null
+++ b/drivers/serial/serial_ks8695.c
@@ -0,0 +1,657 @@
1/*
2 * drivers/serial/serial_ks8695.c
3 *
4 * Driver for KS8695 serial ports
5 *
6 * Based on drivers/serial/serial_amba.c, by Kam Lee.
7 *
8 * Copyright 2002-2005 Micrel Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 */
16#include <linux/module.h>
17#include <linux/tty.h>
18#include <linux/ioport.h>
19#include <linux/init.h>
20#include <linux/serial.h>
21#include <linux/console.h>
22#include <linux/sysrq.h>
23#include <linux/device.h>
24
25#include <asm/io.h>
26#include <asm/irq.h>
27#include <asm/mach/irq.h>
28
29#include <asm/arch/regs-uart.h>
30#include <asm/arch/regs-irq.h>
31
32#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33#define SUPPORT_SYSRQ
34#endif
35
36#include <linux/serial_core.h>
37
38
39#define SERIAL_KS8695_MAJOR 204
40#define SERIAL_KS8695_MINOR 16
41#define SERIAL_KS8695_DEVNAME "ttyAM"
42
43#define SERIAL_KS8695_NR 1
44
45/*
46 * Access macros for the KS8695 UART
47 */
48#define UART_GET_CHAR(p) (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
49#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + KS8695_URTH)
50#define UART_GET_FCR(p) __raw_readl((p)->membase + KS8695_URFC)
51#define UART_PUT_FCR(p, c) __raw_writel((c), (p)->membase + KS8695_URFC)
52#define UART_GET_MSR(p) __raw_readl((p)->membase + KS8695_URMS)
53#define UART_GET_LSR(p) __raw_readl((p)->membase + KS8695_URLS)
54#define UART_GET_LCR(p) __raw_readl((p)->membase + KS8695_URLC)
55#define UART_PUT_LCR(p, c) __raw_writel((c), (p)->membase + KS8695_URLC)
56#define UART_GET_MCR(p) __raw_readl((p)->membase + KS8695_URMC)
57#define UART_PUT_MCR(p, c) __raw_writel((c), (p)->membase + KS8695_URMC)
58#define UART_GET_BRDR(p) __raw_readl((p)->membase + KS8695_URBD)
59#define UART_PUT_BRDR(p, c) __raw_writel((c), (p)->membase + KS8695_URBD)
60
61#define KS8695_CLR_TX_INT() __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
62
63#define UART_DUMMY_LSR_RX 0x100
64#define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4)
65
66#define tx_enabled(port) ((port)->unused[0])
67#define rx_enabled(port) ((port)->unused[1])
68
69
70#ifdef SUPPORT_SYSRQ
71static struct console ks8695_console;
72#endif
73
74static void ks8695uart_stop_tx(struct uart_port *port)
75{
76 if (tx_enabled(port)) {
77 disable_irq(KS8695_IRQ_UART_TX);
78 tx_enabled(port) = 0;
79 }
80}
81
82static void ks8695uart_start_tx(struct uart_port *port)
83{
84 if (!tx_enabled(port)) {
85 enable_irq(KS8695_IRQ_UART_TX);
86 tx_enabled(port) = 1;
87 }
88}
89
90static void ks8695uart_stop_rx(struct uart_port *port)
91{
92 if (rx_enabled(port)) {
93 disable_irq(KS8695_IRQ_UART_RX);
94 rx_enabled(port) = 0;
95 }
96}
97
98static void ks8695uart_enable_ms(struct uart_port *port)
99{
100 enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
101}
102
103static void ks8695uart_disable_ms(struct uart_port *port)
104{
105 disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
106}
107
108static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
109{
110 struct uart_port *port = dev_id;
111 struct tty_struct *tty = port->info->tty;
112 unsigned int status, ch, lsr, flg, max_count = 256;
113
114 status = UART_GET_LSR(port); /* clears pending LSR interrupts */
115 while ((status & URLS_URDR) && max_count--) {
116 ch = UART_GET_CHAR(port);
117 flg = TTY_NORMAL;
118
119 port->icount.rx++;
120
121 /*
122 * Note that the error handling code is
123 * out of the main execution path
124 */
125 lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
126 if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
127 if (lsr & URLS_URBI) {
128 lsr &= ~(URLS_URFE | URLS_URPE);
129 port->icount.brk++;
130 if (uart_handle_break(port))
131 goto ignore_char;
132 }
133 if (lsr & URLS_URPE)
134 port->icount.parity++;
135 if (lsr & URLS_URFE)
136 port->icount.frame++;
137 if (lsr & URLS_URROE)
138 port->icount.overrun++;
139
140 lsr &= port->read_status_mask;
141
142 if (lsr & URLS_URBI)
143 flg = TTY_BREAK;
144 else if (lsr & URLS_URPE)
145 flg = TTY_PARITY;
146 else if (lsr & URLS_URFE)
147 flg = TTY_FRAME;
148 }
149
150 if (uart_handle_sysrq_char(port, ch))
151 goto ignore_char;
152
153 uart_insert_char(port, lsr, URLS_URROE, ch, flg);
154
155ignore_char:
156 status = UART_GET_LSR(port);
157 }
158 tty_flip_buffer_push(tty);
159
160 return IRQ_HANDLED;
161}
162
163
164static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
165{
166 struct uart_port *port = dev_id;
167 struct circ_buf *xmit = &port->info->xmit;
168 unsigned int count;
169
170 if (port->x_char) {
171 KS8695_CLR_TX_INT();
172 UART_PUT_CHAR(port, port->x_char);
173 port->icount.tx++;
174 port->x_char = 0;
175 return IRQ_HANDLED;
176 }
177
178 if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
179 ks8695uart_stop_tx(port);
180 return IRQ_HANDLED;
181 }
182
183 count = 16; /* fifo size */
184 while (!uart_circ_empty(xmit) && (count-- > 0)) {
185 KS8695_CLR_TX_INT();
186 UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
187
188 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
189 port->icount.tx++;
190 }
191
192 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
193 uart_write_wakeup(port);
194
195 if (uart_circ_empty(xmit))
196 ks8695uart_stop_tx(port);
197
198 return IRQ_HANDLED;
199}
200
201static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
202{
203 struct uart_port *port = dev_id;
204 unsigned int status;
205
206 /*
207 * clear modem interrupt by reading MSR
208 */
209 status = UART_GET_MSR(port);
210
211 if (status & URMS_URDDCD)
212 uart_handle_dcd_change(port, status & URMS_URDDCD);
213
214 if (status & URMS_URDDST)
215 port->icount.dsr++;
216
217 if (status & URMS_URDCTS)
218 uart_handle_cts_change(port, status & URMS_URDCTS);
219
220 if (status & URMS_URTERI)
221 port->icount.rng++;
222
223 wake_up_interruptible(&port->info->delta_msr_wait);
224
225 return IRQ_HANDLED;
226}
227
228static unsigned int ks8695uart_tx_empty(struct uart_port *port)
229{
230 return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
231}
232
233static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
234{
235 unsigned int result = 0;
236 unsigned int status;
237
238 status = UART_GET_MSR(port);
239 if (status & URMS_URDCD)
240 result |= TIOCM_CAR;
241 if (status & URMS_URDSR)
242 result |= TIOCM_DSR;
243 if (status & URMS_URCTS)
244 result |= TIOCM_CTS;
245 if (status & URMS_URRI)
246 result |= TIOCM_RI;
247
248 return result;
249}
250
251static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
252{
253 unsigned int mcr;
254
255 mcr = UART_GET_MCR(port);
256 if (mctrl & TIOCM_RTS)
257 mcr |= URMC_URRTS;
258 else
259 mcr &= ~URMC_URRTS;
260
261 if (mctrl & TIOCM_DTR)
262 mcr |= URMC_URDTR;
263 else
264 mcr &= ~URMC_URDTR;
265
266 UART_PUT_MCR(port, mcr);
267}
268
269static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
270{
271 unsigned int lcr;
272
273 lcr = UART_GET_LCR(port);
274
275 if (break_state == -1)
276 lcr |= URLC_URSBC;
277 else
278 lcr &= ~URLC_URSBC;
279
280 UART_PUT_LCR(port, lcr);
281}
282
283static int ks8695uart_startup(struct uart_port *port)
284{
285 int retval;
286
287 set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
288 tx_enabled(port) = 0;
289 rx_enabled(port) = 1;
290
291 /*
292 * Allocate the IRQ
293 */
294 retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
295 if (retval)
296 goto err_tx;
297
298 retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
299 if (retval)
300 goto err_rx;
301
302 retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
303 if (retval)
304 return err_ls;
305
306 retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
307 if (retval)
308 return err_ms;
309
310 return 0;
311
312err_ms:
313 free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
314err_ls:
315 free_irq(KS8695_IRQ_UART_RX, port);
316err_rx:
317 free_irq(KS8695_IRQ_UART_TX, port);
318err_tx:
319 return retval;
320}
321
322static void ks8695uart_shutdown(struct uart_port *port)
323{
324 /*
325 * Free the interrupt
326 */
327 free_irq(KS8695_IRQ_UART_RX, port);
328 free_irq(KS8695_IRQ_UART_TX, port);
329 free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
330 free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
331
332 /* disable break condition and fifos */
333 UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
334 UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
335}
336
337static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
338{
339 unsigned int lcr, fcr = 0;
340 unsigned long flags;
341 unsigned int baud, quot;
342
343 /*
344 * Ask the core to calculate the divisor for us.
345 */
346 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
347 quot = uart_get_divisor(port, baud);
348
349 switch (termios->c_cflag & CSIZE) {
350 case CS5:
351 lcr = URCL_5;
352 break;
353 case CS6:
354 lcr = URCL_6;
355 break;
356 case CS7:
357 lcr = URCL_7;
358 break;
359 default:
360 lcr = URCL_8;
361 break;
362 }
363
364 /* stop bits */
365 if (termios->c_cflag & CSTOPB)
366 lcr |= URLC_URSB;
367
368 /* parity */
369 if (termios->c_cflag & PARENB) {
370 if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
371 if (termios->c_cflag & PARODD)
372 lcr |= URPE_MARK;
373 else
374 lcr |= URPE_SPACE;
375 }
376 else if (termios->c_cflag & PARODD)
377 lcr |= URPE_ODD;
378 else
379 lcr |= URPE_EVEN;
380 }
381
382 if (port->fifosize > 1)
383 fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
384
385 spin_lock_irqsave(&port->lock, flags);
386
387 /*
388 * Update the per-port timeout.
389 */
390 uart_update_timeout(port, termios->c_cflag, baud);
391
392 port->read_status_mask = URLS_URROE;
393 if (termios->c_iflag & INPCK)
394 port->read_status_mask |= (URLS_URFE | URLS_URPE);
395 if (termios->c_iflag & (BRKINT | PARMRK))
396 port->read_status_mask |= URLS_URBI;
397
398 /*
399 * Characters to ignore
400 */
401 port->ignore_status_mask = 0;
402 if (termios->c_iflag & IGNPAR)
403 port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
404 if (termios->c_iflag & IGNBRK) {
405 port->ignore_status_mask |= URLS_URBI;
406 /*
407 * If we're ignoring parity and break indicators,
408 * ignore overruns too (for real raw support).
409 */
410 if (termios->c_iflag & IGNPAR)
411 port->ignore_status_mask |= URLS_URROE;
412 }
413
414 /*
415 * Ignore all characters if CREAD is not set.
416 */
417 if ((termios->c_cflag & CREAD) == 0)
418 port->ignore_status_mask |= UART_DUMMY_LSR_RX;
419
420 /* first, disable everything */
421 if (UART_ENABLE_MS(port, termios->c_cflag))
422 ks8695uart_enable_ms(port);
423 else
424 ks8695uart_disable_ms(port);
425
426 /* Set baud rate */
427 UART_PUT_BRDR(port, quot);
428
429 UART_PUT_LCR(port, lcr);
430 UART_PUT_FCR(port, fcr);
431
432 spin_unlock_irqrestore(&port->lock, flags);
433}
434
435static const char *ks8695uart_type(struct uart_port *port)
436{
437 return port->type == PORT_KS8695 ? "KS8695" : NULL;
438}
439
440/*
441 * Release the memory region(s) being used by 'port'
442 */
443static void ks8695uart_release_port(struct uart_port *port)
444{
445 release_mem_region(port->mapbase, UART_PORT_SIZE);
446}
447
448/*
449 * Request the memory region(s) being used by 'port'
450 */
451static int ks8695uart_request_port(struct uart_port *port)
452{
453 return request_mem_region(port->mapbase, UART_PORT_SIZE,
454 "serial_ks8695") != NULL ? 0 : -EBUSY;
455}
456
457/*
458 * Configure/autoconfigure the port.
459 */
460static void ks8695uart_config_port(struct uart_port *port, int flags)
461{
462 if (flags & UART_CONFIG_TYPE) {
463 port->type = PORT_KS8695;
464 ks8695uart_request_port(port);
465 }
466}
467
468/*
469 * verify the new serial_struct (for TIOCSSERIAL).
470 */
471static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
472{
473 int ret = 0;
474
475 if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
476 ret = -EINVAL;
477 if (ser->irq != port->irq)
478 ret = -EINVAL;
479 if (ser->baud_base < 9600)
480 ret = -EINVAL;
481 return ret;
482}
483
484static struct uart_ops ks8695uart_pops = {
485 .tx_empty = ks8695uart_tx_empty,
486 .set_mctrl = ks8695uart_set_mctrl,
487 .get_mctrl = ks8695uart_get_mctrl,
488 .stop_tx = ks8695uart_stop_tx,
489 .start_tx = ks8695uart_start_tx,
490 .stop_rx = ks8695uart_stop_rx,
491 .enable_ms = ks8695uart_enable_ms,
492 .break_ctl = ks8695uart_break_ctl,
493 .startup = ks8695uart_startup,
494 .shutdown = ks8695uart_shutdown,
495 .set_termios = ks8695uart_set_termios,
496 .type = ks8695uart_type,
497 .release_port = ks8695uart_release_port,
498 .request_port = ks8695uart_request_port,
499 .config_port = ks8695uart_config_port,
500 .verify_port = ks8695uart_verify_port,
501};
502
503static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
504 {
505 .membase = (void *) KS8695_UART_VA,
506 .mapbase = KS8695_UART_VA,
507 .iotype = SERIAL_IO_MEM,
508 .irq = KS8695_IRQ_UART_TX,
509 .uartclk = CLOCK_TICK_RATE * 16,
510 .fifosize = 16,
511 .ops = &ks8695uart_pops,
512 .flags = ASYNC_BOOT_AUTOCONF,
513 .line = 0,
514 }
515};
516
517#ifdef CONFIG_SERIAL_KS8695_CONSOLE
518static void ks8695_console_putchar(struct uart_port *port, int ch)
519{
520 while (!(UART_GET_LSR(port) & URLS_URTHRE))
521 barrier();
522
523 UART_PUT_CHAR(port, ch);
524}
525
526static void ks8695_console_write(struct console *co, const char *s, u_int count)
527{
528 struct uart_port *port = ks8695uart_ports + co->index;
529
530 uart_console_write(port, s, count, ks8695_console_putchar);
531}
532
533static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
534{
535 unsigned int lcr;
536
537 lcr = UART_GET_LCR(port);
538
539 switch (lcr & URLC_PARITY) {
540 case URPE_ODD:
541 *parity = 'o';
542 break;
543 case URPE_EVEN:
544 *parity = 'e';
545 break;
546 default:
547 *parity = 'n';
548 }
549
550 switch (lcr & URLC_URCL) {
551 case URCL_5:
552 *bits = 5;
553 break;
554 case URCL_6:
555 *bits = 6;
556 break;
557 case URCL_7:
558 *bits = 7;
559 break;
560 default:
561 *bits = 8;
562 }
563
564 *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
565 *baud /= 16;
566 *baud &= 0xFFFFFFF0;
567}
568
569static int __init ks8695_console_setup(struct console *co, char *options)
570{
571 struct uart_port *port;
572 int baud = 115200;
573 int bits = 8;
574 int parity = 'n';
575 int flow = 'n';
576
577 /*
578 * Check whether an invalid uart number has been specified, and
579 * if so, search for the first available port that does have
580 * console support.
581 */
582 port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co);
583
584 if (options)
585 uart_parse_options(options, &baud, &parity, &bits, &flow);
586 else
587 ks8695_console_get_options(port, &baud, &parity, &bits);
588
589 return uart_set_options(port, co, baud, parity, bits, flow);
590}
591
592extern struct uart_driver ks8695_reg;
593
594static struct console ks8695_console = {
595 .name = SERIAL_KS8695_DEVNAME,
596 .write = ks8695_console_write,
597 .device = uart_console_device,
598 .setup = ks8695_console_setup,
599 .flags = CON_PRINTBUFFER,
600 .index = -1,
601 .data = &ks8695_reg,
602};
603
604static int __init ks8695_console_init(void)
605{
606 register_console(&ks8695_console);
607 return 0;
608}
609
610console_initcall(ks8695_console_init);
611
612#define KS8695_CONSOLE &ks8695_console
613#else
614#define KS8695_CONSOLE NULL
615#endif
616
617static struct uart_driver ks8695_reg = {
618 .owner = THIS_MODULE,
619 .driver_name = "serial_ks8695",
620 .dev_name = SERIAL_KS8695_DEVNAME,
621 .major = SERIAL_KS8695_MAJOR,
622 .minor = SERIAL_KS8695_MINOR,
623 .nr = SERIAL_KS8695_NR,
624 .cons = KS8695_CONSOLE,
625};
626
627static int __init ks8695uart_init(void)
628{
629 int i, ret;
630
631 printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
632
633 ret = uart_register_driver(&ks8695_reg);
634 if (ret)
635 return ret;
636
637 for (i = 0; i < SERIAL_KS8695_NR; i++)
638 uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
639
640 return 0;
641}
642
643static void __exit ks8695uart_exit(void)
644{
645 int i;
646
647 for (i = 0; i < SERIAL_KS8695_NR; i++)
648 uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
649 uart_unregister_driver(&ks8695_reg);
650}
651
652module_init(ks8695uart_init);
653module_exit(ks8695uart_exit);
654
655MODULE_DESCRIPTION("KS8695 serial port driver");
656MODULE_AUTHOR("Micrel Inc.");
657MODULE_LICENSE("GPL");