aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2010-05-05 04:35:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-21 12:34:30 -0400
commit6b7d8f8b5c43f7bedda750d8a9dab0658da1d2ba (patch)
tree5af3b8bf06f8406fe537c5cbaa4e5c84b088ff1e /drivers/serial
parent5bcd601049c6b2ad52733d4cd2794bfbaf1b9314 (diff)
serial: Add driver for the Altera UART
Add an UART driver for the UART component available as a SOPC (System on Programmable Chip) component for Altera FPGAs. Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig31
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/altera_uart.c570
3 files changed, 602 insertions, 0 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index f4050e678460..8b23165bc5dc 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1544,4 +1544,35 @@ config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
1544 Bypass console output and keep going even if there is no 1544 Bypass console output and keep going even if there is no
1545 JTAG terminal connection with the host. 1545 JTAG terminal connection with the host.
1546 1546
1547config SERIAL_ALTERA_UART
1548 tristate "Altera UART support"
1549 select SERIAL_CORE
1550 help
1551 This driver supports the Altera softcore UART port.
1552
1553config SERIAL_ALTERA_UART_MAXPORTS
1554 int "Maximum number of Altera UART ports"
1555 depends on SERIAL_ALTERA_UART
1556 default 4
1557 help
1558 This setting lets you define the maximum number of the Altera
1559 UART ports. The usual default varies from board to board, and
1560 this setting is a way of catering for that.
1561
1562config SERIAL_ALTERA_UART_BAUDRATE
1563 int "Default baudrate for Altera UART ports"
1564 depends on SERIAL_ALTERA_UART
1565 default 115200
1566 help
1567 This setting lets you define what the default baudrate is for the
1568 Altera UART ports. The usual default varies from board to board,
1569 and this setting is a way of catering for that.
1570
1571config SERIAL_ALTERA_UART_CONSOLE
1572 bool "Altera UART console support"
1573 depends on SERIAL_ALTERA_UART=y
1574 select SERIAL_CORE_CONSOLE
1575 help
1576 Enable a Altera UART port to be the system console.
1577
1547endmenu 1578endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7f9d225d0430..208a85572c32 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
83obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o 83obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
84obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o 84obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
85obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o 85obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
86obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
new file mode 100644
index 000000000000..bcee156d2f2e
--- /dev/null
+++ b/drivers/serial/altera_uart.c
@@ -0,0 +1,570 @@
1/*
2 * altera_uart.c -- Altera UART driver
3 *
4 * Based on mcf.c -- Freescale ColdFire UART driver
5 *
6 * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
7 * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
8 * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
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/kernel.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/module.h>
20#include <linux/console.h>
21#include <linux/tty.h>
22#include <linux/tty_flip.h>
23#include <linux/serial.h>
24#include <linux/serial_core.h>
25#include <linux/platform_device.h>
26#include <linux/io.h>
27#include <linux/altera_uart.h>
28
29#define DRV_NAME "altera_uart"
30
31/*
32 * Altera UART register definitions according to the Nios UART datasheet:
33 * http://www.altera.com/literature/ds/ds_nios_uart.pdf
34 */
35
36#define ALTERA_UART_SIZE 32
37
38#define ALTERA_UART_RXDATA_REG 0
39#define ALTERA_UART_TXDATA_REG 4
40#define ALTERA_UART_STATUS_REG 8
41#define ALTERA_UART_CONTROL_REG 12
42#define ALTERA_UART_DIVISOR_REG 16
43#define ALTERA_UART_EOP_REG 20
44
45#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */
46#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */
47#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */
48#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */
49#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */
50#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */
51#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */
52#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */
53#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */
54#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */
55#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */
56#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */
57
58 /* Enable interrupt on... */
59#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */
60#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */
61#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */
62#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */
63#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */
64#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */
65#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */
66#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */
67#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/
68
69#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */
70#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */
71#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */
72#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */
73
74/*
75 * Local per-uart structure.
76 */
77struct altera_uart {
78 struct uart_port port;
79 unsigned int sigs; /* Local copy of line sigs */
80 unsigned short imr; /* Local IMR mirror */
81};
82
83static unsigned int altera_uart_tx_empty(struct uart_port *port)
84{
85 return (readl(port->membase + ALTERA_UART_STATUS_REG) &
86 ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
87}
88
89static unsigned int altera_uart_get_mctrl(struct uart_port *port)
90{
91 struct altera_uart *pp = container_of(port, struct altera_uart, port);
92 unsigned long flags;
93 unsigned int sigs;
94
95 spin_lock_irqsave(&port->lock, flags);
96 sigs =
97 (readl(port->membase + ALTERA_UART_STATUS_REG) &
98 ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
99 sigs |= (pp->sigs & TIOCM_RTS);
100 spin_unlock_irqrestore(&port->lock, flags);
101
102 return sigs;
103}
104
105static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
106{
107 struct altera_uart *pp = container_of(port, struct altera_uart, port);
108 unsigned long flags;
109
110 spin_lock_irqsave(&port->lock, flags);
111 pp->sigs = sigs;
112 if (sigs & TIOCM_RTS)
113 pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
114 else
115 pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
116 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
117 spin_unlock_irqrestore(&port->lock, flags);
118}
119
120static void altera_uart_start_tx(struct uart_port *port)
121{
122 struct altera_uart *pp = container_of(port, struct altera_uart, port);
123 unsigned long flags;
124
125 spin_lock_irqsave(&port->lock, flags);
126 pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
127 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
128 spin_unlock_irqrestore(&port->lock, flags);
129}
130
131static void altera_uart_stop_tx(struct uart_port *port)
132{
133 struct altera_uart *pp = container_of(port, struct altera_uart, port);
134 unsigned long flags;
135
136 spin_lock_irqsave(&port->lock, flags);
137 pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
138 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
139 spin_unlock_irqrestore(&port->lock, flags);
140}
141
142static void altera_uart_stop_rx(struct uart_port *port)
143{
144 struct altera_uart *pp = container_of(port, struct altera_uart, port);
145 unsigned long flags;
146
147 spin_lock_irqsave(&port->lock, flags);
148 pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
149 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
150 spin_unlock_irqrestore(&port->lock, flags);
151}
152
153static void altera_uart_break_ctl(struct uart_port *port, int break_state)
154{
155 struct altera_uart *pp = container_of(port, struct altera_uart, port);
156 unsigned long flags;
157
158 spin_lock_irqsave(&port->lock, flags);
159 if (break_state == -1)
160 pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
161 else
162 pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
163 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
164 spin_unlock_irqrestore(&port->lock, flags);
165}
166
167static void altera_uart_enable_ms(struct uart_port *port)
168{
169}
170
171static void altera_uart_set_termios(struct uart_port *port,
172 struct ktermios *termios,
173 struct ktermios *old)
174{
175 unsigned long flags;
176 unsigned int baud, baudclk;
177
178 baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
179 baudclk = port->uartclk / baud;
180
181 if (old)
182 tty_termios_copy_hw(termios, old);
183 tty_termios_encode_baud_rate(termios, baud, baud);
184
185 spin_lock_irqsave(&port->lock, flags);
186 writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
187 spin_unlock_irqrestore(&port->lock, flags);
188}
189
190static void altera_uart_rx_chars(struct altera_uart *pp)
191{
192 struct uart_port *port = &pp->port;
193 unsigned char ch, flag;
194 unsigned short status;
195
196 while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) &
197 ALTERA_UART_STATUS_RRDY_MSK) {
198 ch = readl(port->membase + ALTERA_UART_RXDATA_REG);
199 flag = TTY_NORMAL;
200 port->icount.rx++;
201
202 if (status & ALTERA_UART_STATUS_E_MSK) {
203 writel(status, port->membase + ALTERA_UART_STATUS_REG);
204
205 if (status & ALTERA_UART_STATUS_BRK_MSK) {
206 port->icount.brk++;
207 if (uart_handle_break(port))
208 continue;
209 } else if (status & ALTERA_UART_STATUS_PE_MSK) {
210 port->icount.parity++;
211 } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
212 port->icount.overrun++;
213 } else if (status & ALTERA_UART_STATUS_FE_MSK) {
214 port->icount.frame++;
215 }
216
217 status &= port->read_status_mask;
218
219 if (status & ALTERA_UART_STATUS_BRK_MSK)
220 flag = TTY_BREAK;
221 else if (status & ALTERA_UART_STATUS_PE_MSK)
222 flag = TTY_PARITY;
223 else if (status & ALTERA_UART_STATUS_FE_MSK)
224 flag = TTY_FRAME;
225 }
226
227 if (uart_handle_sysrq_char(port, ch))
228 continue;
229 uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
230 flag);
231 }
232
233 tty_flip_buffer_push(port->state->port.tty);
234}
235
236static void altera_uart_tx_chars(struct altera_uart *pp)
237{
238 struct uart_port *port = &pp->port;
239 struct circ_buf *xmit = &port->state->xmit;
240
241 if (port->x_char) {
242 /* Send special char - probably flow control */
243 writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG);
244 port->x_char = 0;
245 port->icount.tx++;
246 return;
247 }
248
249 while (readl(port->membase + ALTERA_UART_STATUS_REG) &
250 ALTERA_UART_STATUS_TRDY_MSK) {
251 if (xmit->head == xmit->tail)
252 break;
253 writel(xmit->buf[xmit->tail],
254 port->membase + ALTERA_UART_TXDATA_REG);
255 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
256 port->icount.tx++;
257 }
258
259 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
260 uart_write_wakeup(port);
261
262 if (xmit->head == xmit->tail) {
263 pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
264 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
265 }
266}
267
268static irqreturn_t altera_uart_interrupt(int irq, void *data)
269{
270 struct uart_port *port = data;
271 struct altera_uart *pp = container_of(port, struct altera_uart, port);
272 unsigned int isr;
273
274 isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
275 if (isr & ALTERA_UART_STATUS_RRDY_MSK)
276 altera_uart_rx_chars(pp);
277 if (isr & ALTERA_UART_STATUS_TRDY_MSK)
278 altera_uart_tx_chars(pp);
279 return IRQ_RETVAL(isr);
280}
281
282static void altera_uart_config_port(struct uart_port *port, int flags)
283{
284 port->type = PORT_ALTERA_UART;
285
286 /* Clear mask, so no surprise interrupts. */
287 writel(0, port->membase + ALTERA_UART_CONTROL_REG);
288 /* Clear status register */
289 writel(0, port->membase + ALTERA_UART_STATUS_REG);
290}
291
292static int altera_uart_startup(struct uart_port *port)
293{
294 struct altera_uart *pp = container_of(port, struct altera_uart, port);
295 unsigned long flags;
296 int ret;
297
298 ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
299 DRV_NAME, port);
300 if (ret) {
301 pr_err(DRV_NAME ": unable to attach Altera UART %d "
302 "interrupt vector=%d\n", port->line, port->irq);
303 return ret;
304 }
305
306 spin_lock_irqsave(&port->lock, flags);
307
308 /* Enable RX interrupts now */
309 pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
310 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
311
312 spin_unlock_irqrestore(&port->lock, flags);
313
314 return 0;
315}
316
317static void altera_uart_shutdown(struct uart_port *port)
318{
319 struct altera_uart *pp = container_of(port, struct altera_uart, port);
320 unsigned long flags;
321
322 spin_lock_irqsave(&port->lock, flags);
323
324 /* Disable all interrupts now */
325 pp->imr = 0;
326 writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
327
328 spin_unlock_irqrestore(&port->lock, flags);
329
330 free_irq(port->irq, port);
331}
332
333static const char *altera_uart_type(struct uart_port *port)
334{
335 return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
336}
337
338static int altera_uart_request_port(struct uart_port *port)
339{
340 /* UARTs always present */
341 return 0;
342}
343
344static void altera_uart_release_port(struct uart_port *port)
345{
346 /* Nothing to release... */
347}
348
349static int altera_uart_verify_port(struct uart_port *port,
350 struct serial_struct *ser)
351{
352 if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
353 return -EINVAL;
354 return 0;
355}
356
357/*
358 * Define the basic serial functions we support.
359 */
360static struct uart_ops altera_uart_ops = {
361 .tx_empty = altera_uart_tx_empty,
362 .get_mctrl = altera_uart_get_mctrl,
363 .set_mctrl = altera_uart_set_mctrl,
364 .start_tx = altera_uart_start_tx,
365 .stop_tx = altera_uart_stop_tx,
366 .stop_rx = altera_uart_stop_rx,
367 .enable_ms = altera_uart_enable_ms,
368 .break_ctl = altera_uart_break_ctl,
369 .startup = altera_uart_startup,
370 .shutdown = altera_uart_shutdown,
371 .set_termios = altera_uart_set_termios,
372 .type = altera_uart_type,
373 .request_port = altera_uart_request_port,
374 .release_port = altera_uart_release_port,
375 .config_port = altera_uart_config_port,
376 .verify_port = altera_uart_verify_port,
377};
378
379static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
380
381#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
382
383int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
384{
385 struct uart_port *port;
386 int i;
387
388 for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
389 port = &altera_uart_ports[i].port;
390
391 port->line = i;
392 port->type = PORT_ALTERA_UART;
393 port->mapbase = platp[i].mapbase;
394 port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
395 port->iotype = SERIAL_IO_MEM;
396 port->irq = platp[i].irq;
397 port->uartclk = platp[i].uartclk;
398 port->flags = ASYNC_BOOT_AUTOCONF;
399 port->ops = &altera_uart_ops;
400 }
401
402 return 0;
403}
404
405static void altera_uart_console_putc(struct console *co, const char c)
406{
407 struct uart_port *port = &(altera_uart_ports + co->index)->port;
408 int i;
409
410 for (i = 0; i < 0x10000; i++) {
411 if (readl(port->membase + ALTERA_UART_STATUS_REG) &
412 ALTERA_UART_STATUS_TRDY_MSK)
413 break;
414 }
415 writel(c, port->membase + ALTERA_UART_TXDATA_REG);
416 for (i = 0; i < 0x10000; i++) {
417 if (readl(port->membase + ALTERA_UART_STATUS_REG) &
418 ALTERA_UART_STATUS_TRDY_MSK)
419 break;
420 }
421}
422
423static void altera_uart_console_write(struct console *co, const char *s,
424 unsigned int count)
425{
426 for (; count; count--, s++) {
427 altera_uart_console_putc(co, *s);
428 if (*s == '\n')
429 altera_uart_console_putc(co, '\r');
430 }
431}
432
433static int __init altera_uart_console_setup(struct console *co, char *options)
434{
435 struct uart_port *port;
436 int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
437 int bits = 8;
438 int parity = 'n';
439 int flow = 'n';
440
441 if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
442 return -EINVAL;
443 port = &altera_uart_ports[co->index].port;
444 if (port->membase == 0)
445 return -ENODEV;
446
447 if (options)
448 uart_parse_options(options, &baud, &parity, &bits, &flow);
449
450 return uart_set_options(port, co, baud, parity, bits, flow);
451}
452
453static struct uart_driver altera_uart_driver;
454
455static struct console altera_uart_console = {
456 .name = "ttyS",
457 .write = altera_uart_console_write,
458 .device = uart_console_device,
459 .setup = altera_uart_console_setup,
460 .flags = CON_PRINTBUFFER,
461 .index = -1,
462 .data = &altera_uart_driver,
463};
464
465static int __init altera_uart_console_init(void)
466{
467 register_console(&altera_uart_console);
468 return 0;
469}
470
471console_initcall(altera_uart_console_init);
472
473#define ALTERA_UART_CONSOLE (&altera_uart_console)
474
475#else
476
477#define ALTERA_UART_CONSOLE NULL
478
479#endif /* CONFIG_ALTERA_UART_CONSOLE */
480
481/*
482 * Define the altera_uart UART driver structure.
483 */
484static struct uart_driver altera_uart_driver = {
485 .owner = THIS_MODULE,
486 .driver_name = DRV_NAME,
487 .dev_name = "ttyS",
488 .major = TTY_MAJOR,
489 .minor = 64,
490 .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
491 .cons = ALTERA_UART_CONSOLE,
492};
493
494static int __devinit altera_uart_probe(struct platform_device *pdev)
495{
496 struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
497 struct uart_port *port;
498 int i;
499
500 for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
501 port = &altera_uart_ports[i].port;
502
503 port->line = i;
504 port->type = PORT_ALTERA_UART;
505 port->mapbase = platp[i].mapbase;
506 port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
507 port->iotype = SERIAL_IO_MEM;
508 port->irq = platp[i].irq;
509 port->uartclk = platp[i].uartclk;
510 port->ops = &altera_uart_ops;
511 port->flags = ASYNC_BOOT_AUTOCONF;
512
513 uart_add_one_port(&altera_uart_driver, port);
514 }
515
516 return 0;
517}
518
519static int altera_uart_remove(struct platform_device *pdev)
520{
521 struct uart_port *port;
522 int i;
523
524 for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++) {
525 port = &altera_uart_ports[i].port;
526 if (port)
527 uart_remove_one_port(&altera_uart_driver, port);
528 }
529
530 return 0;
531}
532
533static struct platform_driver altera_uart_platform_driver = {
534 .probe = altera_uart_probe,
535 .remove = __devexit_p(altera_uart_remove),
536 .driver = {
537 .name = DRV_NAME,
538 .owner = THIS_MODULE,
539 .pm = NULL,
540 },
541};
542
543static int __init altera_uart_init(void)
544{
545 int rc;
546
547 rc = uart_register_driver(&altera_uart_driver);
548 if (rc)
549 return rc;
550 rc = platform_driver_register(&altera_uart_platform_driver);
551 if (rc) {
552 uart_unregister_driver(&altera_uart_driver);
553 return rc;
554 }
555 return 0;
556}
557
558static void __exit altera_uart_exit(void)
559{
560 platform_driver_unregister(&altera_uart_platform_driver);
561 uart_unregister_driver(&altera_uart_driver);
562}
563
564module_init(altera_uart_init);
565module_exit(altera_uart_exit);
566
567MODULE_DESCRIPTION("Altera UART driver");
568MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
569MODULE_LICENSE("GPL");
570MODULE_ALIAS("platform:" DRV_NAME);