diff options
Diffstat (limited to 'drivers/tty/serial/uartlite.c')
| -rw-r--r-- | drivers/tty/serial/uartlite.c | 253 |
1 files changed, 131 insertions, 122 deletions
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index d2fce865b73..dce27f34937 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -15,26 +15,16 @@ #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <asm/io.h> -#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) +#include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> -/* Match table for of_platform binding */ -static struct of_device_id ulite_of_match[] __devinitdata = { - { .compatible = "xlnx,opb-uartlite-1.00.b", }, - { .compatible = "xlnx,xps-uartlite-1.00.a", }, - {} -}; -MODULE_DEVICE_TABLE(of, ulite_of_match); - -#endif - #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 #define ULITE_MINOR 187 @@ -44,7 +34,7 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); * Register definitions * * For register details see datasheet: - * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf + * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf */ #define ULITE_RX 0x00 @@ -67,6 +57,54 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +struct uartlite_reg_ops { + u32 (*in)(void __iomem *addr); + void (*out)(u32 val, void __iomem *addr); +}; + +static u32 uartlite_inbe32(void __iomem *addr) +{ + return ioread32be(addr); +} + +static void uartlite_outbe32(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +static struct uartlite_reg_ops uartlite_be = { + .in = uartlite_inbe32, + .out = uartlite_outbe32, +}; + +static u32 uartlite_inle32(void __iomem *addr) +{ + return ioread32(addr); +} + +static void uartlite_outle32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +static struct uartlite_reg_ops uartlite_le = { + .in = uartlite_inle32, + .out = uartlite_outle32, +}; + +static inline u32 uart_in32(u32 offset, struct uart_port *port) +{ + struct uartlite_reg_ops *reg_ops = port->private_data; + + return reg_ops->in(port->membase + offset); +} + +static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) +{ + struct uartlite_reg_ops *reg_ops = port->private_data; + + reg_ops->out(val, port->membase + offset); +} static struct uart_port ulite_ports[ULITE_NR_UARTS]; @@ -76,7 +114,7 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { - struct tty_struct *tty = port->state->port.tty; + struct tty_port *tport = &port->state->port; unsigned char ch = 0; char flag = TTY_NORMAL; @@ -87,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = ioread32be(port->membase + ULITE_RX); + ch = uart_in32(ULITE_RX, port); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -113,13 +151,13 @@ static int ulite_receive(struct uart_port *port, int stat) stat &= ~port->ignore_status_mask; if (stat & ULITE_STATUS_RXVALID) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(tport, ch, flag); if (stat & ULITE_STATUS_FRAME) - tty_insert_flip_char(tty, 0, TTY_FRAME); + tty_insert_flip_char(tport, 0, TTY_FRAME); if (stat & ULITE_STATUS_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(tport, 0, TTY_OVERRUN); return 1; } @@ -132,7 +170,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - iowrite32be(port->x_char, port->membase + ULITE_TX); + uart_out32(port->x_char, ULITE_TX, port); port->x_char = 0; port->icount.tx++; return 1; @@ -141,7 +179,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX); + uart_out32(xmit->buf[xmit->tail], ULITE_TX, port); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -158,7 +196,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy, n = 0; do { - int stat = ioread32be(port->membase + ULITE_STATUS); + int stat = uart_in32(ULITE_STATUS, port); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); n++; @@ -166,7 +204,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) /* work done? */ if (n > 1) { - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(&port->state->port); return IRQ_HANDLED; } else { return IRQ_NONE; @@ -179,7 +217,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = ioread32be(port->membase + ULITE_STATUS); + ret = uart_in32(ULITE_STATUS, port); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -202,7 +240,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS)); + ulite_transmit(port, uart_in32(ULITE_STATUS, port)); } static void ulite_stop_rx(struct uart_port *port) @@ -226,22 +264,21 @@ static int ulite_startup(struct uart_port *port) { int ret; - ret = request_irq(port->irq, ulite_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port); + ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port); if (ret) return ret; - iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, - port->membase + ULITE_CONTROL); - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + uart_out32(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + ULITE_CONTROL, port); + uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); return 0; } static void ulite_shutdown(struct uart_port *port) { - iowrite32be(0, port->membase + ULITE_CONTROL); - ioread32be(port->membase + ULITE_CONTROL); /* dummy */ + uart_out32(0, ULITE_CONTROL, port); + uart_in32(ULITE_CONTROL, port); /* dummy */ free_irq(port->irq, port); } @@ -292,6 +329,8 @@ static void ulite_release_port(struct uart_port *port) static int ulite_request_port(struct uart_port *port) { + int ret; + pr_debug("ulite console: port=%p; port->mapbase=%llx\n", port, (unsigned long long) port->mapbase); @@ -307,6 +346,14 @@ static int ulite_request_port(struct uart_port *port) return -EBUSY; } + port->private_data = &uartlite_be; + ret = uart_in32(ULITE_CONTROL, port); + uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port); + ret = uart_in32(ULITE_STATUS, port); + /* Endianess detection */ + if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY) + port->private_data = &uartlite_le; + return 0; } @@ -325,20 +372,19 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) #ifdef CONFIG_CONSOLE_POLL static int ulite_get_poll_char(struct uart_port *port) { - if (!(ioread32be(port->membase + ULITE_STATUS) - & ULITE_STATUS_RXVALID)) + if (!(uart_in32(ULITE_STATUS, port) & ULITE_STATUS_RXVALID)) return NO_POLL_CHAR; - return ioread32be(port->membase + ULITE_RX); + return uart_in32(ULITE_RX, port); } static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) { - while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL) + while (uart_in32(ULITE_STATUS, port) & ULITE_STATUS_TXFULL) cpu_relax(); /* write char to device */ - iowrite32be(ch, port->membase + ULITE_TX); + uart_out32(ch, ULITE_TX, port); } #endif @@ -372,14 +418,23 @@ static struct uart_ops ulite_ops = { #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE static void ulite_console_wait_tx(struct uart_port *port) { - int i; u8 val; - - /* Spin waiting for TX fifo to have space available */ - for (i = 0; i < 100000; i++) { - val = ioread32be(port->membase + ULITE_STATUS); + unsigned long timeout; + + /* + * Spin waiting for TX fifo to have space available. + * When using the Microblaze Debug Module this can take up to 1s + */ + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + val = uart_in32(ULITE_STATUS, port); if ((val & ULITE_STATUS_TXFULL) == 0) break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for TX buffer empty\n"); + break; + } cpu_relax(); } } @@ -387,7 +442,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - iowrite32be(ch, port->membase + ULITE_TX); + uart_out32(ch, ULITE_TX, port); } static void ulite_console_write(struct console *co, const char *s, @@ -404,8 +459,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - iowrite32be(0, port->membase + ULITE_CONTROL); + ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE; + uart_out32(0, ULITE_CONTROL, port); uart_console_write(port, s, count, ulite_console_putchar); @@ -413,13 +468,13 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); if (locked) spin_unlock_irqrestore(&port->lock, flags); } -static int __devinit ulite_console_setup(struct console *co, char *options) +static int ulite_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; @@ -497,7 +552,7 @@ static struct uart_driver ulite_uart_driver = { * * Returns: 0 on success, <0 otherwise */ -static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) +static int ulite_assign(struct device *dev, int id, u32 base, int irq) { struct uart_port *port; int rc; @@ -553,7 +608,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) * * @dev: pointer to device structure */ -static int __devexit ulite_release(struct device *dev) +static int ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); int rc = 0; @@ -571,9 +626,27 @@ static int __devexit ulite_release(struct device *dev) * Platform bus binding */ -static int __devinit ulite_probe(struct platform_device *pdev) +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static struct of_device_id ulite_of_match[] = { + { .compatible = "xlnx,opb-uartlite-1.00.b", }, + { .compatible = "xlnx,xps-uartlite-1.00.a", }, + {} +}; +MODULE_DEVICE_TABLE(of, ulite_of_match); +#endif /* CONFIG_OF */ + +static int ulite_probe(struct platform_device *pdev) { struct resource *res, *res2; + int id = pdev->id; +#ifdef CONFIG_OF + const __be32 *prop; + + prop = of_get_property(pdev->dev.of_node, "port-number", NULL); + if (prop) + id = be32_to_cpup(prop); +#endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -583,10 +656,10 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); + return ulite_assign(&pdev->dev, id, res->start, res2->start); } -static int __devexit ulite_remove(struct platform_device *pdev) +static int ulite_remove(struct platform_device *pdev) { return ulite_release(&pdev->dev); } @@ -595,77 +668,20 @@ static int __devexit ulite_remove(struct platform_device *pdev) MODULE_ALIAS("platform:uartlite"); static struct platform_driver ulite_platform_driver = { - .probe = ulite_probe, - .remove = __devexit_p(ulite_remove), - .driver = { - .owner = THIS_MODULE, - .name = "uartlite", - }, -}; - -/* --------------------------------------------------------------------- - * OF bus bindings - */ -#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) -static int __devinit -ulite_of_probe(struct platform_device *op, const struct of_device_id *match) -{ - struct resource res; - const unsigned int *id; - int irq, rc; - - dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match); - - rc = of_address_to_resource(op->dev.of_node, 0, &res); - if (rc) { - dev_err(&op->dev, "invalid address\n"); - return rc; - } - - irq = irq_of_parse_and_map(op->dev.of_node, 0); - - id = of_get_property(op->dev.of_node, "port-number", NULL); - - return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); -} - -static int __devexit ulite_of_remove(struct platform_device *op) -{ - return ulite_release(&op->dev); -} - -static struct of_platform_driver ulite_of_driver = { - .probe = ulite_of_probe, - .remove = __devexit_p(ulite_of_remove), + .probe = ulite_probe, + .remove = ulite_remove, .driver = { - .name = "uartlite", .owner = THIS_MODULE, - .of_match_table = ulite_of_match, + .name = "uartlite", + .of_match_table = of_match_ptr(ulite_of_match), }, }; -/* Registration helpers to keep the number of #ifdefs to a minimum */ -static inline int __init ulite_of_register(void) -{ - pr_debug("uartlite: calling of_register_platform_driver()\n"); - return of_register_platform_driver(&ulite_of_driver); -} - -static inline void __exit ulite_of_unregister(void) -{ - of_unregister_platform_driver(&ulite_of_driver); -} -#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ -/* Appropriate config not enabled; do nothing helpers */ -static inline int __init ulite_of_register(void) { return 0; } -static inline void __exit ulite_of_unregister(void) { } -#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ - /* --------------------------------------------------------------------- * Module setup/teardown */ -int __init ulite_init(void) +static int __init ulite_init(void) { int ret; @@ -674,10 +690,6 @@ int __init ulite_init(void) if (ret) goto err_uart; - ret = ulite_of_register(); - if (ret) - goto err_of; - pr_debug("uartlite: calling platform_driver_register()\n"); ret = platform_driver_register(&ulite_platform_driver); if (ret) @@ -686,18 +698,15 @@ int __init ulite_init(void) return 0; err_plat: - ulite_of_unregister(); -err_of: uart_unregister_driver(&ulite_uart_driver); err_uart: - printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); + pr_err("registering uartlite driver failed: err=%i", ret); return ret; } -void __exit ulite_exit(void) +static void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); - ulite_of_unregister(); uart_unregister_driver(&ulite_uart_driver); } |
