diff options
Diffstat (limited to 'drivers/serial')
32 files changed, 416 insertions, 2787 deletions
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 6558a403780..f31c6698419 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -19,7 +19,7 @@ #include <asm/irq.h> #include <asm/mach-types.h> #include <asm/hardware/dec21285.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #define BAUD_BASE (mem_fclk_21285/64) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a97f1ae11f7..d4104a3bbe8 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -44,6 +44,10 @@ #include "8250.h" +#ifdef CONFIG_SPARC +#include "suncore.h" +#endif + /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; +static struct uart_driver serial8250_reg; + +static int serial_index(struct uart_port *port) +{ + return (serial8250_reg.minor - 64) + port->line; +} + /* * Debugging. */ @@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) /* * FIFO support. */ -static inline void serial8250_clear_fifos(struct uart_8250_port *p) +static void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); @@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p) * capability" bit enabled. Note that on XR16C850s, we need to * reset LCR to write to IER. */ -static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) return; DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", - up->port.line, up->port.iobase, up->port.membase); + serial_index(&up->port), up->port.iobase, up->port.membase); /* * We really do need global IRQs disabled here - we're going to @@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) if (up->capabilities != uart_config[up->port.type].flags) { printk(KERN_WARNING "ttyS%d: detected caps %08x should be %08x\n", - up->port.line, up->capabilities, - uart_config[up->port.type].flags); + serial_index(&up->port), up->capabilities, + uart_config[up->port.type].flags); } up->port.fifosize = uart_config[up->port.type].fifo_size; @@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) /* * This handles the interrupt from one port. */ -static inline void -serial8250_handle_port(struct uart_8250_port *up) +static void serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; unsigned long flags; @@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) /* * Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) +static void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port) */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { - printk("ttyS%d: LSR safety check engaged!\n", up->port.line); + printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(&up->port)); return -ENODEV; } @@ -1885,7 +1896,7 @@ static int serial8250_startup(struct uart_port *port) * the interrupt is enabled. Delays are necessary to * allow register changes to become visible. */ - spin_lock(&up->port.lock); + spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_SHARE_IRQ) disable_irq_nosync(up->port.irq); @@ -1901,22 +1912,31 @@ static int serial8250_startup(struct uart_port *port) if (up->port.flags & UPF_SHARE_IRQ) enable_irq(up->port.irq); - spin_unlock(&up->port.lock); + spin_unlock_irqrestore(&up->port.lock, flags); /* * If the interrupt is not reasserted, setup a timer to * kick the UART on a regular basis. */ if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { - pr_debug("ttyS%d - using backup timer\n", port->line); - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ / 5); + up->bugs |= UART_BUG_THRE; + pr_debug("ttyS%d - using backup timer\n", + serial_index(port)); } } /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + poll_timeout(up->port.timeout) + HZ / 5); + } + + /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. @@ -1961,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port) if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; pr_debug("ttyS%d - enabling bad tx status workarounds\n", - port->line); + serial_index(port)); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2622,7 +2642,6 @@ static int serial8250_console_early_setup(void) return serial8250_find_port_for_earlycon(); } -static struct uart_driver serial8250_reg; static struct console serial8250_console = { .name = "ttyS", .write = serial8250_console_write, @@ -2669,7 +2688,6 @@ static struct uart_driver serial8250_reg = { .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, - .nr = UART_NR, .cons = SERIAL8250_CONSOLE, }; @@ -2951,10 +2969,12 @@ static int __init serial8250_init(void) "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); - for (i = 0; i < NR_IRQS; i++) - spin_lock_init(&irq_lists[i].lock); - +#ifdef CONFIG_SPARC + ret = sunserial_register_minors(&serial8250_reg, UART_NR); +#else + serial8250_reg.nr = UART_NR; ret = uart_register_driver(&serial8250_reg); +#endif if (ret) goto out; @@ -2979,7 +2999,11 @@ static int __init serial8250_init(void) put_dev: platform_device_put(serial8250_isa_devs); unreg_uart_drv: +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else uart_unregister_driver(&serial8250_reg); +#endif out: return ret; } @@ -2998,7 +3022,11 @@ static void __exit serial8250_exit(void) platform_driver_unregister(&serial8250_isa_driver); platform_device_unregister(isa_dev); +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else uart_unregister_driver(&serial8250_reg); +#endif } module_init(serial8250_init); diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index 78c00162b04..520260326f3 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -47,6 +47,7 @@ struct serial8250_config { #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ +#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index c2f23933155..c014ffb110e 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev) * The device may have been disabled. Re-enable it. */ err = pci_enable_device(dev); + /* FIXME: We cannot simply error out here */ if (err) - return err; - + printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3b4a14e355c..31786b3b0a6 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -9,7 +9,6 @@ menu "Serial drivers" # The new 8250/16550 serial drivers config SERIAL_8250 tristate "8250/16550 and compatible serial support" - depends on (BROKEN || !SPARC) select SERIAL_CORE ---help--- This selects whether you want to include the driver for the standard @@ -449,6 +448,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" depends on ARM && PLAT_S3C24XX + select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not @@ -993,24 +993,12 @@ config SERIAL_68328_RTS_CTS bool "Support RTS/CTS on 68328 serial port" depends on SERIAL_68328 -config SERIAL_COLDFIRE - bool "ColdFire serial support (DEPRECATED)" - depends on COLDFIRE - help - This driver supports the built-in serial ports of the Motorola ColdFire - family of CPUs. - This driver is deprecated because it supports only the old interface - for serial drivers and features like magic keys are not working. - Please switch to the new style driver because this driver will be - removed soon. - config SERIAL_MCF - bool "Coldfire serial support (new style driver)" + bool "Coldfire serial support" depends on COLDFIRE select SERIAL_CORE help - This new serial driver supports the Freescale Coldfire serial ports - using the new serial driver subsystem. + This serial driver supports the Freescale Coldfire serial ports. config SERIAL_MCF_BAUDRATE int "Default baudrate for Coldfire serial ports" diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3a0bbbe17aa..0c17c8ddb19 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -4,6 +4,16 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o + +# These Sparc drivers have to appear before others such as 8250 +# which share ttySx minor node space. Otherwise console device +# names change and other unplesantries. +obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o +obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o +obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o +obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o +obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o + obj-$(CONFIG_SERIAL_8250) += 8250.o obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o @@ -31,18 +41,11 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o -obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o -obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_DZ) += dz.o diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 1fee12c1f4f..61fb8b6d19a 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -42,11 +42,11 @@ #include <asm/io.h> #include <asm/mach/serial_at91.h> -#include <asm/arch/board.h> +#include <mach/board.h> #ifdef CONFIG_ARM -#include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> +#include <mach/cpu.h> +#include <mach/gpio.h> #endif #define PDC_BUFFER_SIZE 512 @@ -131,7 +131,8 @@ struct atmel_uart_char { struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ - unsigned short suspended; /* is port suspended? */ + int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ + u32 backup_imr; /* IMR saved during suspend */ int break_active; /* break being received */ short use_dma_rx; /* enable PDC receiver */ @@ -984,8 +985,15 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * This is called on uart_open() or a resume event. */ clk_enable(atmel_port->clk); + + /* re-enable interrupts if we disabled some on suspend */ + UART_PUT_IER(port, atmel_port->backup_imr); break; case 3: + /* Back up the interrupt mask and disable all interrupts */ + atmel_port->backup_imr = UART_GET_IMR(port); + UART_PUT_IDR(port, -1); + /* * Disable the peripheral clock for this serial port. * This is called on uart_close() or a suspend event. @@ -1475,13 +1483,12 @@ static int atmel_serial_suspend(struct platform_device *pdev, cpu_relax(); } - if (device_may_wakeup(&pdev->dev) - && !atmel_serial_clk_will_stop()) - enable_irq_wake(port->irq); - else { - uart_suspend_port(&atmel_uart, port); - atmel_port->suspended = 1; - } + /* we can not wake up if we're running on slow clock */ + atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); + if (atmel_serial_clk_will_stop()) + device_set_wakeup_enable(&pdev->dev, 0); + + uart_suspend_port(&atmel_uart, port); return 0; } @@ -1491,11 +1498,8 @@ static int atmel_serial_resume(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (atmel_port->suspended) { - uart_resume_port(&atmel_uart, port); - atmel_port->suspended = 0; - } else - disable_irq_wake(port->irq); + uart_resume_port(&atmel_uart, port); + device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); return 0; } @@ -1513,6 +1517,8 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE)); port = &atmel_ports[pdev->id]; + port->backup_imr = 0; + atmel_init_port(port, pdev); if (!atmel_use_dma_rx(&port->uart)) { diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 9d8543762a3..569f0e2476c 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2008 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -28,7 +28,7 @@ #endif #include <asm/gpio.h> -#include <asm/mach/bfin_serial_5xx.h> +#include <mach/bfin_serial_5xx.h> #ifdef CONFIG_SERIAL_BFIN_DMA #include <linux/dma-mapping.h> @@ -42,6 +42,9 @@ #define BFIN_SERIAL_MAJOR 204 #define BFIN_SERIAL_MINOR 64 +static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; +static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); + /* * Setup for console. Argument comes from the menuconfig */ @@ -126,13 +129,13 @@ static int kgdb_entry_state; void kgdb_put_debug_char(int chr) { struct bfin_serial_port *uart; - + if (CONFIG_KGDB_UART_PORT < 0 || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while (!(UART_GET_LSR(uart) & THRE)) { SSYNC(); } @@ -152,7 +155,7 @@ int kgdb_get_debug_char(void) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while(!(UART_GET_LSR(uart) & DR)) { SSYNC(); } @@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) bfin_serial_mctrl_check(uart); if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { - bfin_serial_stop_tx(&uart->port); +#ifdef CONFIG_BF54x + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); +#endif + UART_CLEAR_IER(uart, ETBEI); return; } @@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); - - if (uart_circ_empty(xmit)) - bfin_serial_stop_tx(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) @@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port) free_irq(uart->port.irq, uart); return -EBUSY; } + +# ifdef CONFIG_BF54x + { + unsigned uart_dma_ch_rx, uart_dma_ch_tx; + + switch (uart->port.irq) { + case IRQ_UART3_RX: + uart_dma_ch_rx = CH_UART3_RX; + uart_dma_ch_tx = CH_UART3_TX; + break; + case IRQ_UART2_RX: + uart_dma_ch_rx = CH_UART2_RX; + uart_dma_ch_tx = CH_UART2_TX; + break; + default: + uart_dma_ch_rx = uart_dma_ch_tx = 0; + break; + }; + + if (uart_dma_ch_rx && + request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE"Fail to attach UART interrupt\n"); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + if (uart_dma_ch_tx && + request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Fail to attach UART interrupt\n"); + free_dma(uart_dma_ch_rx); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + } +# endif #endif UART_SET_IER(uart, ERBFI); return 0; @@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port) del_timer(&(uart->rx_dma_timer)); dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); #else +#ifdef CONFIG_BF54x + switch (uart->port.irq) { + case IRQ_UART3_RX: + free_dma(CH_UART3_RX); + free_dma(CH_UART3_TX); + break; + case IRQ_UART2_RX: + free_dma(CH_UART2_RX); + free_dma(CH_UART2_TX); + break; + default: + break; + }; +#endif #ifdef CONFIG_KGDB_UART if (uart->port.line != CONFIG_KGDB_UART_PORT) #endif @@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, val |= UCEN; UART_PUT_GCTL(uart, val); + /* Port speed changed, update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&uart->port.lock, flags); } @@ -817,7 +874,7 @@ static void bfin_serial_set_ldisc(struct uart_port *port) if (line >= port->info->port.tty->driver->num) return; - switch (port->info->port.tty->ldisc.num) { + switch (port->info->port.tty->termios->c_line) { case N_IRDA: val = UART_GET_GCTL(&bfin_serial_ports[line]); val |= (IREN | RPOLC); @@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void) return; first = 0; - for (i = 0; i < nr_ports; i++) { + for (i = 0; i < nr_active_ports; i++) { bfin_serial_ports[i].port.uartclk = get_sclk(); + bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; bfin_serial_ports[i].port.ops = &bfin_serial_pops; bfin_serial_ports[i].port.line = i; bfin_serial_ports[i].port.iotype = UPIO_MEM; @@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= nr_ports) + if (co->index == -1 || co->index >= nr_active_ports) co->index = 0; uart = &bfin_serial_ports[co->index]; @@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s, } } -static struct __init console bfin_early_serial_console = { +static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, @@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, struct bfin_serial_port *uart; struct ktermios t; - if (port == -1 || port >= nr_ports) + if (port == -1 || port >= nr_active_ports) port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; @@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = { static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_suspend_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } static int bfin_serial_resume(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_resume_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } @@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev) break; if (i < dev->num_resources) { - for (i = 0; i < nr_ports; i++, res++) { + for (i = 0; i < nr_active_ports; i++, res++) { if (bfin_serial_ports[i].port.mapbase != res->start) continue; bfin_serial_ports[i].port.dev = &dev->dev; uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - platform_set_drvdata(dev, &bfin_serial_ports[i]); } } return 0; } -static int bfin_serial_remove(struct platform_device *pdev) +static int bfin_serial_remove(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - + int i; + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + bfin_serial_ports[i].port.dev = NULL; #ifdef CONFIG_SERIAL_BFIN_CTSRTS - gpio_free(uart->cts_pin); - gpio_free(uart->rts_pin); + gpio_free(bfin_serial_ports[i].cts_pin); + gpio_free(bfin_serial_ports[i].rts_pin); #endif - - platform_set_drvdata(pdev, NULL); - - if (uart) - uart_remove_one_port(&bfin_serial_reg, &uart->port); + } return 0; } diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index fc1fa9267c5..459f3420a42 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -39,7 +39,7 @@ #include <linux/serial_core.h> #include <linux/serial.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/hardware/clps7111.h> diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5c76e0ae058..7274b527a3c 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -50,6 +50,15 @@ #define SCC_WAIT_CLOSING 100 +#define GPIO_CTS 0 +#define GPIO_RTS 1 +#define GPIO_DCD 2 +#define GPIO_DSR 3 +#define GPIO_DTR 4 +#define GPIO_RI 5 + +#define NUM_GPIOS (GPIO_RI+1) + struct uart_cpm_port { struct uart_port port; u16 rx_nrfifos; @@ -68,6 +77,7 @@ struct uart_cpm_port { unsigned char *rx_buf; u32 flags; void (*set_lineif)(struct uart_cpm_port *); + struct clk *clk; u8 brg; uint dp_addr; void *mem_addr; @@ -82,6 +92,7 @@ struct uart_cpm_port { int wait_closing; /* value to combine with opcode to form cpm command */ u32 command; + int gpios[NUM_GPIOS]; }; extern int cpm_uart_nr; diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a4f86927a74..25efca5a7a1 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -43,6 +43,9 @@ #include <linux/dma-mapping.h> #include <linux/fs_uart_pd.h> #include <linux/of_platform.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/clk.h> #include <asm/io.h> #include <asm/irq.h> @@ -96,13 +99,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port) static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Whee. Do nothing. */ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + if (pinfo->gpios[GPIO_RTS] >= 0) + gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); + + if (pinfo->gpios[GPIO_DTR] >= 0) + gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); } static unsigned int cpm_uart_get_mctrl(struct uart_port *port) { - /* Whee. Do nothing. */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + if (pinfo->gpios[GPIO_CTS] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_CTS])) + mctrl &= ~TIOCM_CTS; + } + + if (pinfo->gpios[GPIO_DSR] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DSR])) + mctrl &= ~TIOCM_DSR; + } + + if (pinfo->gpios[GPIO_DCD] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DCD])) + mctrl &= ~TIOCM_CAR; + } + + if (pinfo->gpios[GPIO_RI] >= 0) { + if (!gpio_get_value(pinfo->gpios[GPIO_RI])) + mctrl |= TIOCM_RNG; + } + + return mctrl; } /* @@ -566,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port, out_be16(&sccp->scc_psmr, (sbits << 12) | scval); } - cpm_set_brg(pinfo->brg - 1, baud); + if (pinfo->clk) + clk_set_rate(pinfo->clk, baud); + else + cpm_set_brg(pinfo->brg - 1, baud); spin_unlock_irqrestore(&port->lock, flags); } @@ -991,14 +1025,23 @@ static int cpm_uart_init_port(struct device_node *np, void __iomem *mem, *pram; int len; int ret; + int i; - data = of_get_property(np, "fsl,cpm-brg", &len); - if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-brg property.\n", np->name); - return -EINVAL; + data = of_get_property(np, "clock", NULL); + if (data) { + struct clk *clk = clk_get(NULL, (const char*)data); + if (!IS_ERR(clk)) + pinfo->clk = clk; + } + if (!pinfo->clk) { + data = of_get_property(np, "fsl,cpm-brg", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-brg property.\n", np->name); + return -EINVAL; + } + pinfo->brg = *data; } - pinfo->brg = *data; data = of_get_property(np, "fsl,cpm-command", &len); if (!data || len != 4) { @@ -1050,6 +1093,9 @@ static int cpm_uart_init_port(struct device_node *np, goto out_pram; } + for (i = 0; i < NUM_GPIOS; i++) + pinfo->gpios[i] = of_get_gpio(np, i); + return cpm_uart_request_port(&pinfo->port); out_pram: diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 8249ac49055..211c21797ce 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -234,7 +234,7 @@ unsigned long r_alt_ser_baudrate_shadow = 0; static struct e100_serial rs_table[] = { { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL0_CTRL, + .ioport = (unsigned char *)R_SERIAL0_CTRL, .irq = 1U << 12, /* uses DMA 6 and 7 */ .oclrintradr = R_DMA_CH6_CLR_INTR, .ofirstadr = R_DMA_CH6_FIRST, @@ -288,7 +288,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS0 */ #ifndef CONFIG_SVINTO_SIM { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL1_CTRL, + .ioport = (unsigned char *)R_SERIAL1_CTRL, .irq = 1U << 16, /* uses DMA 8 and 9 */ .oclrintradr = R_DMA_CH8_CLR_INTR, .ofirstadr = R_DMA_CH8_FIRST, @@ -344,7 +344,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS1 */ { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL2_CTRL, + .ioport = (unsigned char *)R_SERIAL2_CTRL, .irq = 1U << 4, /* uses DMA 2 and 3 */ .oclrintradr = R_DMA_CH2_CLR_INTR, .ofirstadr = R_DMA_CH2_FIRST, @@ -398,7 +398,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS2 */ { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL3_CTRL, + .ioport = (unsigned char *)R_SERIAL3_CTRL, .irq = 1U << 8, /* uses DMA 4 and 5 */ .oclrintradr = R_DMA_CH4_CLR_INTR, .ofirstadr = R_DMA_CH4_FIRST, @@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) static struct ktermios *serial_termios[NR_PORTS]; -static struct ktermios *serial_termios_locked[NR_PORTS]; #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static struct fast_timer fast_timers[NR_PORTS]; #endif @@ -939,7 +938,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Output */ #define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) /* Input */ -#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK) +#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ /* Is an output */ @@ -1092,7 +1091,7 @@ e100_rts(struct e100_serial *info, int set) local_irq_save(flags); info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ - info->port[REG_REC_CTRL] = info->rx_ctrl; + info->ioport[REG_REC_CTRL] = info->rx_ctrl; local_irq_restore(flags); #ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set); @@ -1142,7 +1141,7 @@ e100_disable_rx(struct e100_serial *info) { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = + info->ioport[REG_REC_CTRL] = (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -1152,7 +1151,7 @@ e100_enable_rx(struct e100_serial *info) { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = + info->ioport[REG_REC_CTRL] = (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -1490,7 +1489,7 @@ rs_stop(struct tty_struct *tty) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); } } @@ -1513,7 +1512,7 @@ rs_start(struct tty_struct *tty) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; if (!info->uses_dma_out && info->xmit.head != info->xmit.tail && info->xmit.buf) e100_enable_serial_tx_ready_irq(info); @@ -1888,7 +1887,7 @@ static void receive_chars_dma(struct e100_serial *info) handle_all_descr_data(info); /* Read the status register to detect errors */ - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); } @@ -1897,7 +1896,7 @@ static void receive_chars_dma(struct e100_serial *info) /* If we got an error, we must reset it by reading the * data_in field */ - unsigned char data = info->port[REG_DATA]; + unsigned char data = info->ioport[REG_DATA]; PROCSTAT(ser_stat[info->line].errors_cnt++); DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", @@ -2077,7 +2076,7 @@ static int force_eop_if_needed(struct e100_serial *info) /* We check data_avail bit to determine if data has * arrived since last time */ - unsigned char rstat = info->port[REG_STATUS]; + unsigned char rstat = info->ioport[REG_STATUS]; /* error or datavail? */ if (rstat & SER_ERROR_MASK) { @@ -2096,7 +2095,7 @@ static int force_eop_if_needed(struct e100_serial *info) TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", rstat | (info->line << 8))); /* Read data to clear status flags */ - (void)info->port[REG_DATA]; + (void)info->ioport[REG_DATA]; info->forced_eop = 0; START_FLUSH_FAST_TIMER(info, "magic"); @@ -2296,7 +2295,7 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) } /* Read data and status at the same time */ - data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]); + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); more_data: if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); @@ -2391,7 +2390,7 @@ more_data: info->icount.rx++; - data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]); + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); goto more_data; @@ -2413,7 +2412,7 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) return handle_ser_rx_interrupt_no_dma(info); } /* DMA is used */ - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); } @@ -2426,7 +2425,7 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) /* If we got an error, we must reset it by reading the * data_in field */ - data = info->port[REG_DATA]; + data = info->ioport[REG_DATA]; DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); if (!data && (rstat & SER_FRAMING_ERR_MASK)) { @@ -2528,10 +2527,10 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) unsigned char rstat; DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); local_irq_save(flags); - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); - info->port[REG_TR_DATA] = info->x_char; + info->ioport[REG_TR_DATA] = info->x_char; info->icount.tx++; info->x_char = 0; /* We must enable since it is disabled in ser_interrupt */ @@ -2545,7 +2544,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) /* We only use normal tx interrupt when sending x_char */ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); local_irq_save(flags); - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); e100_disable_serial_tx_ready_irq(info); if (info->port.tty->stopped) @@ -2573,7 +2572,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); /* Send a byte, rs485 timing is critical so turn of ints */ local_irq_save(flags); - info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; + info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); info->icount.tx++; if (info->xmit.head == info->xmit.tail) { @@ -2848,7 +2847,7 @@ startup(struct e100_serial * info) /* dummy read to reset any serial errors */ - (void)info->port[REG_DATA]; + (void)info->ioport[REG_DATA]; /* enable the interrupts */ if (info->uses_dma_out) @@ -2897,7 +2896,7 @@ shutdown(struct e100_serial * info) /* shut down the transmitter and receiver */ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); e100_disable_rx(info); - info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); + info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); /* disable interrupts, reset dma channels */ if (info->uses_dma_in) { @@ -2968,7 +2967,7 @@ change_speed(struct e100_serial *info) if (!info->port.tty || !info->port.tty->termios) return; - if (!info->port) + if (!info->ioport) return; cflag = info->port.tty->termios->c_cflag; @@ -3037,7 +3036,7 @@ change_speed(struct e100_serial *info) info->baud = cflag_to_baud(cflag); #ifndef CONFIG_SVINTO_SIM - info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); + info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); #endif /* CONFIG_SVINTO_SIM */ } @@ -3097,8 +3096,8 @@ change_speed(struct e100_serial *info) /* actually write the control regs to the hardware */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - info->port[REG_REC_CTRL] = info->rx_ctrl; + info->ioport[REG_TR_CTRL] = info->tx_ctrl; + info->ioport[REG_REC_CTRL] = info->rx_ctrl; xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); if (info->port.tty->termios->c_iflag & IXON ) { @@ -3107,7 +3106,7 @@ change_speed(struct e100_serial *info) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); #endif /* !CONFIG_SVINTO_SIM */ @@ -3156,7 +3155,7 @@ static int rs_raw_write(struct tty_struct *tty, #ifdef SERIAL_DEBUG_DATA if (info->line == SERIAL_DEBUG_LINE) printk("rs_raw_write (%d), status %d\n", - count, info->port[REG_STATUS]); + count, info->ioport[REG_STATUS]); #endif #ifdef CONFIG_SVINTO_SIM @@ -3427,7 +3426,7 @@ get_serial_info(struct e100_serial * info, memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; - tmp.port = (int)info->port; + tmp.port = (int)info->ioport; tmp.irq = info->irq; tmp.flags = info->flags; tmp.baud_base = info->baud_base; @@ -3557,14 +3556,14 @@ char *get_control_state_str(int MLines, char *s) } #endif -static void +static int rs_break(struct tty_struct *tty, int break_state) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; unsigned long flags; - if (!info->port) - return; + if (!info->ioport) + return -EIO; local_irq_save(flags); if (break_state == -1) { @@ -3575,8 +3574,9 @@ rs_break(struct tty_struct *tty, int break_state) /* Set bit 7 (txd) and 6 (tr_enable) */ info->tx_ctrl |= (0x80 | 0x40); } - info->port[REG_TR_CTRL] = info->tx_ctrl; + info->ioport[REG_TR_CTRL] = info->tx_ctrl; local_irq_restore(flags); + return 0; } static int @@ -4231,9 +4231,9 @@ static int line_info(char *buf, struct e100_serial *info) unsigned long tmp; ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d", - info->line, (unsigned long)info->port, info->irq); + info->line, (unsigned long)info->ioport, info->irq); - if (!info->port || (info->type == PORT_UNKNOWN)) { + if (!info->ioport || (info->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); return ret; } @@ -4281,7 +4281,7 @@ static int line_info(char *buf, struct e100_serial *info) } { - unsigned char rstat = info->port[REG_STATUS]; + unsigned char rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) ret += sprintf(buf+ret, " xoff_detect:1"); } @@ -4418,6 +4418,7 @@ rs_init(void) rs485_pa_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); + put_tty_driver(driver); return -EBUSY; } #endif @@ -4426,6 +4427,7 @@ rs_init(void) rs485_port_g_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); + put_tty_driver(driver); return -EBUSY; } #endif @@ -4445,8 +4447,6 @@ rs_init(void) driver->init_termios.c_ispeed = 115200; driver->init_termios.c_ospeed = 115200; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - driver->termios = serial_termios; - driver->termios_locked = serial_termios_locked; tty_set_operations(driver, &rs_ops); serial_driver = driver; @@ -4502,7 +4502,7 @@ rs_init(void) if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", - serial_driver->name, info->line, (unsigned int)info->port); + serial_driver->name, info->line, (unsigned int)info->ioport); } } #ifdef CONFIG_ETRAX_FAST_TIMER diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h index ccd0f32b737..e3c5c8c3c09 100644 --- a/drivers/serial/crisv10.h +++ b/drivers/serial/crisv10.h @@ -36,8 +36,9 @@ struct etrax_recv_buffer { }; struct e100_serial { + struct tty_port port; int baud; - volatile u8 *port; /* R_SERIALx_CTRL */ + volatile u8 *ioport; /* R_SERIALx_CTRL */ u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ /* Output registers */ diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index e0da4dc7bbf..3f90f1bbbbc 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -44,8 +44,8 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/arch/imx-uart.h> +#include <mach/hardware.h> +#include <mach/imx-uart.h> /* Register definitions */ #define URXD0 0x0 /* Receiver Register */ @@ -127,8 +127,13 @@ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */ -#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */ +#ifdef CONFIG_ARCH_IMX +#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ +#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ +#endif +#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 +#define UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */ +#endif #define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ #define UCR3_BPEN (1<<0) /* Preset registers enable */ #define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ @@ -445,7 +450,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) imx_txint(irq, dev_id); - if (sts & USR1_RTSS) + if (sts & USR1_RTSD) imx_rtsint(irq, dev_id); return IRQ_HANDLED; @@ -598,6 +603,12 @@ static int imx_startup(struct uart_port *port) temp |= (UCR2_RXEN | UCR2_TXEN); writel(temp, sport->port.membase + UCR2); +#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 + temp = readl(sport->port.membase + UCR3); + temp |= UCR3_RXDMUXSEL; + writel(temp, sport->port.membase + UCR3); +#endif + /* * Enable modem status interrupts */ @@ -1133,13 +1144,19 @@ static int serial_imx_probe(struct platform_device *pdev) if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; - if (pdata->init) - pdata->init(pdev); + if (pdata->init) { + ret = pdata->init(pdev); + if (ret) + goto clkput; + } uart_add_one_port(&imx_reg, &sport->port); platform_set_drvdata(pdev, &sport->port); return 0; +clkput: + clk_put(sport->clk); + clk_disable(sport->clk); unmap: iounmap(sport->port.membase); free: diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c deleted file mode 100644 index fbe3835f6b7..00000000000 --- a/drivers/serial/mcfserial.c +++ /dev/null @@ -1,1965 +0,0 @@ -#warning This driver is deprecated. Check Kconfig for details. -/* - * mcfserial.c -- serial driver for ColdFire internal UARTS. - * - * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com> - * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> - * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> - * - * Based on code from 68332serial.c which was: - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 TSHG - * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> - * - * Changes: - * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> - * some cleanups in mcfrs_write. - * - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/wait.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/serial.h> -#include <linux/serialP.h> -#include <linux/console.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/delay.h> -#include <asm/coldfire.h> -#include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/nettel.h> -#include <asm/uaccess.h> -#include "mcfserial.h" - -struct timer_list mcfrs_timer_struct; - -/* - * Default console baud rate, we use this as the default - * for all ports so init can just open /dev/console and - * keep going. Perhaps one day the cflag settings for the - * console can be used instead. - */ -#if defined(CONFIG_HW_FEITH) -#define CONSOLE_BAUD_RATE 38400 -#define DEFAULT_CBAUD B38400 -#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ - defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) -#define CONSOLE_BAUD_RATE 115200 -#define DEFAULT_CBAUD B115200 -#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ - defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) -#define CONSOLE_BAUD_RATE 19200 -#define DEFAULT_CBAUD B19200 -#endif - -#ifndef CONSOLE_BAUD_RATE -#define CONSOLE_BAUD_RATE 9600 -#define DEFAULT_CBAUD B9600 -#endif - -int mcfrs_console_inited = 0; -int mcfrs_console_port = -1; -int mcfrs_console_baud = CONSOLE_BAUD_RATE; -int mcfrs_console_cbaud = DEFAULT_CBAUD; - -/* - * Driver data structures. - */ -static struct tty_driver *mcfrs_serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* Debugging... - */ -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW - -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) -#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) -#else -#define IRQBASE 73 -#endif - -/* - * Configuration table, UARTs to look for at startup. - */ -static struct mcf_serial mcfrs_table[] = { - { /* ttyS0 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1), - .irq = IRQBASE, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#ifdef MCFUART_BASE2 - { /* ttyS1 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), - .irq = IRQBASE+1, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -#ifdef MCFUART_BASE3 - { /* ttyS2 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), - .irq = IRQBASE+2, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -#ifdef MCFUART_BASE4 - { /* ttyS3 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), - .irq = IRQBASE+3, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -}; - - -#define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial)) - -/* - * This is used to figure out the divisor speeds and the timeouts. - */ -static int mcfrs_baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 -}; -#define MCFRS_BAUD_TABLE_SIZE \ - (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0])) - - -#ifdef CONFIG_MAGIC_SYSRQ -/* - * Magic system request keys. Used for debugging... - */ -extern int magic_sysrq_key(int ch); -#endif - - -/* - * Forware declarations... - */ -static void mcfrs_change_speed(struct mcf_serial *info); -static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout); - - -static inline int serial_paranoia_check(struct mcf_serial *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char badmagic[] = - "MCFRS(warning): bad magic number for serial struct %s in %s\n"; - static const char badinfo[] = - "MCFRS(warning): null mcf_serial for %s in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * Sets or clears DTR and RTS on the requested line. - */ -static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts) -{ - volatile unsigned char *uartp; - unsigned long flags; - -#if 0 - printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n", - __FILE__, __LINE__, info, dtr, rts); -#endif - - local_irq_save(flags); - if (dtr >= 0) { -#ifdef MCFPP_DTR0 - if (info->line) - mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1)); - else - mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0)); -#endif - } - if (rts >= 0) { - uartp = info->addr; - if (rts) { - info->sigs |= TIOCM_RTS; - uartp[MCFUART_UOP1] = MCFUART_UOP_RTS; - } else { - info->sigs &= ~TIOCM_RTS; - uartp[MCFUART_UOP0] = MCFUART_UOP_RTS; - } - } - local_irq_restore(flags); - return; -} - -/* - * Gets values of serial signals. - */ -static int mcfrs_getsignals(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - unsigned long flags; - int sigs; -#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) - unsigned short ppdata; -#endif - -#if 0 - printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__); -#endif - - local_irq_save(flags); - uartp = info->addr; - sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; - sigs |= (info->sigs & TIOCM_RTS); - -#ifdef MCFPP_DCD0 -{ - unsigned int ppdata; - ppdata = mcf_getppdata(); - if (info->line == 0) { - sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD; - sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR; - } else if (info->line == 1) { - sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD; - sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR; - } -} -#endif - - local_irq_restore(flags); - return(sigs); -} - -/* - * ------------------------------------------------------------ - * mcfrs_stop() and mcfrs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void mcfrs_stop(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_stop")) - return; - - local_irq_save(flags); - uartp = info->addr; - info->imr &= ~MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); -} - -static void mcfrs_start(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_start")) - return; - - local_irq_save(flags); - if (info->xmit_cnt && info->xmit_buf) { - uartp = info->addr; - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - } - local_irq_restore(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * mcfrs_interrupt(). They were separated out for readability's sake. - * - * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * mcfrs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -static inline void receive_chars(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - struct tty_struct *tty = info->port.tty; - unsigned char status, ch, flag; - - if (!tty) - return; - - uartp = info->addr; - - while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) { - ch = uartp[MCFUART_URB]; - info->stats.rx++; - -#ifdef CONFIG_MAGIC_SYSRQ - if (mcfrs_console_inited && (info->line == mcfrs_console_port)) { - if (magic_sysrq_key(ch)) - continue; - } -#endif - - flag = TTY_NORMAL; - if (status & MCFUART_USR_RXERR) { - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR; - if (status & MCFUART_USR_RXBREAK) { - info->stats.rxbreak++; - flag = TTY_BREAK; - } else if (status & MCFUART_USR_RXPARITY) { - info->stats.rxparity++; - flag = TTY_PARITY; - } else if (status & MCFUART_USR_RXOVERRUN) { - info->stats.rxoverrun++; - flag = TTY_OVERRUN; - } else if (status & MCFUART_USR_RXFRAMING) { - info->stats.rxframing++; - flag = TTY_FRAME; - } - } - tty_insert_flip_char(tty, ch, flag); - } - tty_schedule_flip(tty); - return; -} - -static inline void transmit_chars(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - - uartp = info->addr; - - if (info->x_char) { - /* Send special char - probably flow control */ - uartp[MCFUART_UTB] = info->x_char; - info->x_char = 0; - info->stats.tx++; - } - - if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { - info->imr &= ~MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - return; - } - - while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { - uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->stats.tx++; - if (--info->xmit_cnt <= 0) - break; - } - - if (info->xmit_cnt < WAKEUP_CHARS) - schedule_work(&info->tqueue); - return; -} - -/* - * This is the serial driver's generic interrupt routine - */ -irqreturn_t mcfrs_interrupt(int irq, void *dev_id) -{ - struct mcf_serial *info; - unsigned char isr; - - info = &mcfrs_table[(irq - IRQBASE)]; - isr = info->addr[MCFUART_UISR] & info->imr; - - if (isr & MCFUART_UIR_RXREADY) - receive_chars(info); - if (isr & MCFUART_UIR_TXREADY) - transmit_chars(info); - return IRQ_HANDLED; -} - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -static void mcfrs_offintr(struct work_struct *work) -{ - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); - struct tty_struct *tty = info->port.tty; - - if (tty) - tty_wakeup(tty); -} - - -/* - * Change of state on a DCD line. - */ -void mcfrs_modem_change(struct mcf_serial *info, int dcd) -{ - if (info->count == 0) - return; - - if (info->flags & ASYNC_CHECK_CD) { - if (dcd) - wake_up_interruptible(&info->open_wait); - else - schedule_work(&info->tqueue_hangup); - } -} - - -#ifdef MCFPP_DCD0 - -unsigned short mcfrs_ppstatus; - -/* - * This subroutine is called when the RS_TIMER goes off. It is used - * to monitor the state of the DCD lines - since they have no edge - * sensors and interrupt generators. - */ -static void mcfrs_timer(void) -{ - unsigned int ppstatus, dcdval, i; - - ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); - - if (ppstatus != mcfrs_ppstatus) { - for (i = 0; (i < 2); i++) { - dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0); - if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) { - mcfrs_modem_change(&mcfrs_table[i], - ((ppstatus & dcdval) ? 0 : 1)); - } - } - } - mcfrs_ppstatus = ppstatus; - - /* Re-arm timer */ - mcfrs_timer_struct.expires = jiffies + HZ/25; - add_timer(&mcfrs_timer_struct); -} - -#endif /* MCFPP_DCD0 */ - - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup() - * - */ -static void do_serial_hangup(struct work_struct *work) -{ - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); - struct tty_struct *tty = info->port.tty; - - if (tty) - tty_hangup(tty); -} - -static int startup(struct mcf_serial * info) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (info->flags & ASYNC_INITIALIZED) - return 0; - - if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); - if (!info->xmit_buf) - return -ENOMEM; - } - - local_irq_save(flags); - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); -#endif - - /* - * Reset UART, get it into known state... - */ - uartp = info->addr; - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - mcfrs_setsignals(info, 1, 1); - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * and set the speed of the serial port - */ - mcfrs_change_speed(info); - - /* - * Lastly enable the UART transmitter and receiver, and - * interrupt enables. - */ - info->imr = MCFUART_UIR_RXREADY; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - uartp[MCFUART_UIMR] = info->imr; - - info->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct mcf_serial * info) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....\n", info->line, - info->irq); -#endif - - local_irq_save(flags); - - uartp = info->addr; - uartp[MCFUART_UIMR] = 0; /* mask all interrupts */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) - mcfrs_setsignals(info, 0, 0); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void mcfrs_change_speed(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - unsigned int baudclk, cflag; - unsigned long flags; - unsigned char mr1, mr2; - int i; -#ifdef CONFIG_M5272 - unsigned int fraction; -#endif - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - if (info->addr == 0) - return; - -#if 0 - printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__); -#endif - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 4) - info->port.tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (i == 0) { - mcfrs_setsignals(info, 0, -1); - return; - } - - /* compute the baudrate clock */ -#ifdef CONFIG_M5272 - /* - * For the MCF5272, also compute the baudrate fraction. - */ - baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32; - fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]); - fraction *= 16; - fraction /= (32 * mcfrs_baud_table[i]); -#else - baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32; -#endif - - info->baud = mcfrs_baud_table[i]; - - mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; - mr2 = 0; - - switch (cflag & CSIZE) { - case CS5: mr1 |= MCFUART_MR1_CS5; break; - case CS6: mr1 |= MCFUART_MR1_CS6; break; - case CS7: mr1 |= MCFUART_MR1_CS7; break; - case CS8: - default: mr1 |= MCFUART_MR1_CS8; break; - } - - if (cflag & PARENB) { - if (cflag & CMSPAR) { - if (cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYMARK; - else - mr1 |= MCFUART_MR1_PARITYSPACE; - } else { - if (cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYODD; - else - mr1 |= MCFUART_MR1_PARITYEVEN; - } - } else { - mr1 |= MCFUART_MR1_PARITYNONE; - } - - if (cflag & CSTOPB) - mr2 |= MCFUART_MR2_STOP2; - else - mr2 |= MCFUART_MR2_STOP1; - - if (cflag & CRTSCTS) { - mr1 |= MCFUART_MR1_RXRTS; - mr2 |= MCFUART_MR2_TXCTS; - } - - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else - info->flags |= ASYNC_CHECK_CD; - - uartp = info->addr; - - local_irq_save(flags); -#if 0 - printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__, - mr1, mr2, baudclk); -#endif - /* - Note: pg 12-16 of MCF5206e User's Manual states that a - software reset should be performed prior to changing - UMR1,2, UCSR, UACR, bit 7 - */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ - uartp[MCFUART_UMR] = mr1; - uartp[MCFUART_UMR] = mr2; - uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */ - uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */ -#ifdef CONFIG_M5272 - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ -#endif - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - mcfrs_setsignals(info, 1, -1); - local_irq_restore(flags); - return; -} - -static void mcfrs_flush_chars(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars")) - return; - - uartp = (volatile unsigned char *) info->addr; - - /* - * re-enable receiver interrupt - */ - local_irq_save(flags); - if ((!(info->imr & MCFUART_UIR_RXREADY)) && - (info->flags & ASYNC_INITIALIZED) ) { - info->imr |= MCFUART_UIR_RXREADY; - uartp[MCFUART_UIMR] = info->imr; - } - local_irq_restore(flags); - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) - return; - - /* Enable transmitter */ - local_irq_save(flags); - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); -} - -static int mcfrs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - int c, total = 0; - -#if 0 - printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n", - __FILE__, __LINE__, (int)tty, (int)buf, count); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - local_save_flags(flags); - while (1) { - local_irq_disable(); - c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, - ((int)SERIAL_XMIT_SIZE) - info->xmit_head)); - local_irq_restore(flags); - - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - - local_irq_disable(); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - local_irq_restore(flags); - - buf += c; - count -= c; - total += c; - } - - local_irq_disable(); - uartp = info->addr; - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); - - return total; -} - -static int mcfrs_write_room(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "mcfrs_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int mcfrs_chars_in_buffer(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void mcfrs_flush_buffer(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer")) - return; - - local_irq_save(flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); - - tty_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * mcfrs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void mcfrs_throttle(struct tty_struct * tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) - return; - - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) */ -} - -static void mcfrs_unthrottle(struct tty_struct * tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - - /* Assert RTS line (do this atomic) */ -} - -/* - * ------------------------------------------------------------ - * mcfrs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct mcf_serial * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = (unsigned int) info->addr; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; -} - -static int set_serial_info(struct mcf_serial * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct mcf_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - -check_and_exit: - retval = startup(info); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct mcf_serial * info, unsigned int *value) -{ - volatile unsigned char *uartp; - unsigned long flags; - unsigned char status; - - local_irq_save(flags); - uartp = info->addr; - status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; - local_irq_restore(flags); - - return put_user(status,value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break( struct mcf_serial * info, int duration) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (!info->addr) - return; - set_current_state(TASK_INTERRUPTIBLE); - uartp = info->addr; - - local_irq_save(flags); - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART; - schedule_timeout(duration); - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP; - local_irq_restore(flags); -} - -static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - return mcfrs_getsignals(info); -} - -static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - int rts = -1, dtr = -1; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - if (set & TIOCM_RTS) - rts = 1; - if (set & TIOCM_DTR) - dtr = 1; - if (clear & TIOCM_RTS) - rts = 0; - if (clear & TIOCM_DTR) - dtr = 0; - - mcfrs_setsignals(info, dtr, rts); - - return 0; -} - -static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - int retval, error; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - return 0; - case TIOCGSERIAL: - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) - return get_serial_info(info, - (struct serial_struct *) arg); - return -EFAULT; - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) - return get_lsr_info(info, (unsigned int *) arg); - return -EFAULT; - case TIOCSERGSTRUCT: - error = copy_to_user((struct mcf_serial *) arg, - info, sizeof(struct mcf_serial)); - if (error) - return -EFAULT; - return 0; - -#ifdef TIOCSET422 - case TIOCSET422: { - unsigned int val; - get_user(val, (unsigned int *) arg); - mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); - break; - } - case TIOCGET422: { - unsigned int val; - val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; - put_user(val, (unsigned int *) arg); - break; - } -#endif - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - - mcfrs_change_speed(info); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - mcfrs_setsignals(info, -1, 1); -#if 0 - mcfrs_start(tty); -#endif - } -} - -/* - * ------------------------------------------------------------ - * mcfrs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * S structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void mcfrs_close(struct tty_struct *tty, struct file * filp) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close")) - return; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count); -#endif - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("MCFRS: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk("MCFRS: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->imr &= ~MCFUART_UIR_RXREADY; - uartp = info->addr; - uartp[MCFUART_UIMR] = info->imr; - -#if 0 - /* FIXME: do we need to keep this enabled for console?? */ - if (mcfrs_console_inited && (mcfrs_console_port == info->line)) { - /* Do not disable the UART */ ; - } else -#endif - shutdown(info); - mcfrs_flush_buffer(tty); - tty_ldisc_flush(tty); - - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; -#if 0 - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * mcfrs_wait_until_sent() --- wait until the transmitter is empty - */ -static void -mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) -{ -#ifdef CONFIG_M5272 -#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */ - - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - volatile unsigned char *uartp; - unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt; - - if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent")) - return; - - orig_jiffies = jiffies; - - /* - * Set the check interval to be 1/5 of the approximate time - * to send the entire fifo, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - lock_kernel(); - - fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud; - char_time = fifo_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - - /* - * Clamp the timeout period at 2 * the time to empty the - * fifo. Just to be safe, set the minimum at .5 seconds. - */ - fifo_time *= 2; - if (fifo_time < (HZ/2)) - fifo_time = HZ/2; - if (!timeout || timeout > fifo_time) - timeout = fifo_time; - - /* - * Account for the number of bytes in the UART - * transmitter FIFO plus any byte being shifted out. - */ - uartp = (volatile unsigned char *) info->addr; - for (;;) { - fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB); - if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY| - MCFUART_USR_TXEMPTY)) == - MCFUART_USR_TXREADY) - fifo_cnt++; - if (fifo_cnt == 0) - break; - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - unlock_kernel(); -#else - /* - * For the other coldfire models, assume all data has been sent - */ -#endif -} - -/* - * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void mcfrs_hangup(struct tty_struct *tty) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_hangup")) - return; - - mcfrs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * mcfrs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct mcf_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * mcfrs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%d, count = %d\n", - info->line, info->count); -#endif - info->count--; - info->blocked_open++; - while (1) { - local_irq_disable(); - mcfrs_setsignals(info, 1, 1); - local_irq_enable(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -int mcfrs_open(struct tty_struct *tty, struct file * filp) -{ - struct mcf_serial *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - info = mcfrs_table + line; - if (serial_paranoia_check(info, tty->name, "mcfrs_open")) - return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open %s, count = %d\n", tty->name, info->count); -#endif - info->count++; - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open %s successful...\n", tty->name); -#endif - return 0; -} - -/* - * Based on the line number set up the internal interrupt stuff. - */ -static void mcfrs_irqinit(struct mcf_serial *info) -{ -#if defined(CONFIG_M5272) - volatile unsigned long *icrp; - volatile unsigned long *portp; - volatile unsigned char *uartp; - - uartp = info->addr; - icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); - - switch (info->line) { - case 0: - *icrp = 0xe0000000; - break; - case 1: - *icrp = 0x0e000000; - break; - default: - printk("MCFRS: don't know how to handle UART %d interrupt?\n", - info->line); - return; - } - - /* Enable the output lines for the serial ports */ - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT); - *portp = (*portp & ~0x000000ff) | 0x00000055; - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); - *portp = (*portp & ~0x000003fc) | 0x000002a8; -#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) - volatile unsigned char *icrp, *uartp; - volatile unsigned long *imrp; - - uartp = info->addr; - - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_ICR0 + MCFINT_UART0 + info->line); - *icrp = 0x30 + info->line; /* level 6, line based priority */ - - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_IMRL); - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); -#if defined(CONFIG_M527x) - { - /* - * External Pin Mask Setting & Enable External Pin for Interface - * mrcbis@aliceposta.it - */ - u16 *serpin_enable_mask; - serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART); - if (info->line == 0) - *serpin_enable_mask |= UART0_ENABLE_MASK; - else if (info->line == 1) - *serpin_enable_mask |= UART1_ENABLE_MASK; - else if (info->line == 2) - *serpin_enable_mask |= UART2_ENABLE_MASK; - } -#endif -#if defined(CONFIG_M528x) - /* make sure PUAPAR is set for UART0 and UART1 */ - if (info->line < 2) { - volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); - *portp |= (0x03 << (info->line * 2)); - } -#endif -#elif defined(CONFIG_M520x) - volatile unsigned char *icrp, *uartp; - volatile unsigned long *imrp; - - uartp = info->addr; - - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_ICR0 + MCFINT_UART0 + info->line); - *icrp = 0x03; - - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_IMRL); - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); - if (info->line < 2) { - unsigned short *uart_par; - uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); - if (info->line == 0) - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 - | MCF_GPIO_PAR_UART_PAR_URXD0; - else if (info->line == 1) - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 - | MCF_GPIO_PAR_UART_PAR_URXD1; - } else if (info->line == 2) { - unsigned char *feci2c_par; - feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); - *feci2c_par &= ~0x0F; - *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 - | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; - } -#elif defined(CONFIG_M532x) - volatile unsigned char *uartp; - uartp = info->addr; - switch (info->line) { - case 0: - MCF_INTC0_ICR26 = 0x3; - MCF_INTC0_CIMR = 26; - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x000F; - break; - case 1: - MCF_INTC0_ICR27 = 0x3; - MCF_INTC0_CIMR = 27; - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x0FF0; - break; - case 2: - MCF_INTC0_ICR28 = 0x3; - MCF_INTC0_CIMR = 28; - /* GPIOs also must be initalized, depends on board */ - break; - } -#else - volatile unsigned char *icrp, *uartp; - - switch (info->line) { - case 0: - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR); - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | - MCFSIM_ICR_PRI1; - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); - break; - case 1: - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR); - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | - MCFSIM_ICR_PRI2; - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); - break; - default: - printk("MCFRS: don't know how to handle UART %d interrupt?\n", - info->line); - return; - } - - uartp = info->addr; - uartp[MCFUART_UIVR] = info->irq; -#endif - - /* Clear mask, so no surprise interrupts. */ - uartp[MCFUART_UIMR] = 0; - - if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, - "ColdFire UART", NULL)) { - printk("MCFRS: Unable to attach ColdFire UART %d interrupt " - "vector=%d\n", info->line, info->irq); - } - - return; -} - - -char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n"; - - -/* - * Serial stats reporting... - */ -int mcfrs_readproc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct mcf_serial *info; - char str[20]; - int len, sigs, i; - - len = sprintf(page, mcfrs_drivername); - for (i = 0; (i < NR_PORTS); i++) { - info = &mcfrs_table[i]; - len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", - i, (unsigned int) info->addr, info->irq, info->baud); - if (info->stats.rx || info->stats.tx) - len += sprintf((page + len), "tx:%d rx:%d ", - info->stats.tx, info->stats.rx); - if (info->stats.rxframing) - len += sprintf((page + len), "fe:%d ", - info->stats.rxframing); - if (info->stats.rxparity) - len += sprintf((page + len), "pe:%d ", - info->stats.rxparity); - if (info->stats.rxbreak) - len += sprintf((page + len), "brk:%d ", - info->stats.rxbreak); - if (info->stats.rxoverrun) - len += sprintf((page + len), "oe:%d ", - info->stats.rxoverrun); - - str[0] = str[1] = 0; - if ((sigs = mcfrs_getsignals(info))) { - if (sigs & TIOCM_RTS) - strcat(str, "|RTS"); - if (sigs & TIOCM_CTS) - strcat(str, "|CTS"); - if (sigs & TIOCM_DTR) - strcat(str, "|DTR"); - if (sigs & TIOCM_CD) - strcat(str, "|CD"); - } - - len += sprintf((page + len), "%s\n", &str[1]); - } - - return(len); -} - - -/* Finally, routines used to initialize the serial driver. */ - -static void show_serial_version(void) -{ - printk(mcfrs_drivername); -} - -static const struct tty_operations mcfrs_ops = { - .open = mcfrs_open, - .close = mcfrs_close, - .write = mcfrs_write, - .flush_chars = mcfrs_flush_chars, - .write_room = mcfrs_write_room, - .chars_in_buffer = mcfrs_chars_in_buffer, - .flush_buffer = mcfrs_flush_buffer, - .ioctl = mcfrs_ioctl, - .throttle = mcfrs_throttle, - .unthrottle = mcfrs_unthrottle, - .set_termios = mcfrs_set_termios, - .stop = mcfrs_stop, - .start = mcfrs_start, - .hangup = mcfrs_hangup, - .read_proc = mcfrs_readproc, - .wait_until_sent = mcfrs_wait_until_sent, - .tiocmget = mcfrs_tiocmget, - .tiocmset = mcfrs_tiocmset, -}; - -/* mcfrs_init inits the driver */ -static int __init -mcfrs_init(void) -{ - struct mcf_serial *info; - unsigned long flags; - int i; - - /* Setup base handler, and timer table. */ -#ifdef MCFPP_DCD0 - init_timer(&mcfrs_timer_struct); - mcfrs_timer_struct.function = mcfrs_timer; - mcfrs_timer_struct.data = 0; - mcfrs_timer_struct.expires = jiffies + HZ/25; - add_timer(&mcfrs_timer_struct); - mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); -#endif - mcfrs_serial_driver = alloc_tty_driver(NR_PORTS); - if (!mcfrs_serial_driver) - return -ENOMEM; - - show_serial_version(); - - /* Initialize the tty_driver structure */ - mcfrs_serial_driver->owner = THIS_MODULE; - mcfrs_serial_driver->name = "ttyS"; - mcfrs_serial_driver->driver_name = "mcfserial"; - mcfrs_serial_driver->major = TTY_MAJOR; - mcfrs_serial_driver->minor_start = 64; - mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL; - mcfrs_serial_driver->init_termios = tty_std_termios; - - mcfrs_serial_driver->init_termios.c_cflag = - mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; - mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW; - - tty_set_operations(mcfrs_serial_driver, &mcfrs_ops); - - if (tty_register_driver(mcfrs_serial_driver)) { - printk("MCFRS: Couldn't register serial driver\n"); - put_tty_driver(mcfrs_serial_driver); - return(-EBUSY); - } - - local_irq_save(flags); - - /* - * Configure all the attached serial ports. - */ - for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { - info->magic = SERIAL_MAGIC; - info->line = i; - info->port.tty = NULL; - info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - INIT_WORK(&info->tqueue, mcfrs_offintr); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - - info->imr = 0; - mcfrs_setsignals(info, 0, 0); - mcfrs_irqinit(info); - - printk("ttyS%d at 0x%04x (irq = %d)", info->line, - (unsigned int) info->addr, info->irq); - printk(" is a builtin ColdFire UART\n"); - } - - local_irq_restore(flags); - return 0; -} - -module_init(mcfrs_init); - -/****************************************************************************/ -/* Serial Console */ -/****************************************************************************/ - -/* - * Quick and dirty UART initialization, for console output. - */ - -void mcfrs_init_console(void) -{ - volatile unsigned char *uartp; - unsigned int clk; - - /* - * Reset UART, get it into known state... - */ - uartp = (volatile unsigned char *) (MCF_MBAR + - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); - - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ - - /* - * Set port for defined baud , 8 data bits, 1 stop bit, no parity. - */ - uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; - uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; - -#ifdef CONFIG_M5272 -{ - /* - * For the MCF5272, also compute the baudrate fraction. - */ - int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); - fraction *= 16; - fraction /= (32 * mcfrs_console_baud); - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ - clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; -} -#else - clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ -#endif - - uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ - uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - - mcfrs_console_inited++; - return; -} - - -/* - * Setup for console. Argument comes from the boot command line. - */ - -int mcfrs_console_setup(struct console *cp, char *arg) -{ - int i, n = CONSOLE_BAUD_RATE; - - if (!cp) - return(-1); - - if (!strncmp(cp->name, "ttyS", 4)) - mcfrs_console_port = cp->index; - else if (!strncmp(cp->name, "cua", 3)) - mcfrs_console_port = cp->index; - else - return(-1); - - if (arg) - n = simple_strtoul(arg,NULL,0); - for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++) - if (mcfrs_baud_table[i] == n) - break; - if (i < MCFRS_BAUD_TABLE_SIZE) { - mcfrs_console_baud = n; - mcfrs_console_cbaud = 0; - if (i > 15) { - mcfrs_console_cbaud |= CBAUDEX; - i -= 15; - } - mcfrs_console_cbaud |= i; - } - mcfrs_init_console(); /* make sure baud rate changes */ - return(0); -} - - -static struct tty_driver *mcfrs_console_device(struct console *c, int *index) -{ - *index = c->index; - return mcfrs_serial_driver; -} - - -/* - * Output a single character, using UART polled mode. - * This is used for console output. - */ - -int mcfrs_put_char(char ch) -{ - volatile unsigned char *uartp; - unsigned long flags; - int i; - - uartp = (volatile unsigned char *) (MCF_MBAR + - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); - - local_irq_save(flags); - for (i = 0; (i < 0x10000); i++) { - if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) - break; - } - if (i < 0x10000) { - uartp[MCFUART_UTB] = ch; - for (i = 0; (i < 0x10000); i++) - if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) - break; - } - if (i >= 0x10000) - mcfrs_init_console(); /* try and get it back */ - local_irq_restore(flags); - - return 1; -} - - -/* - * rs_console_write is registered for printk output. - */ - -void mcfrs_console_write(struct console *cp, const char *p, unsigned len) -{ - if (!mcfrs_console_inited) - mcfrs_init_console(); - while (len-- > 0) { - if (*p == '\n') - mcfrs_put_char('\r'); - mcfrs_put_char(*p++); - } -} - -/* - * declare our consoles - */ - -struct console mcfrs_console = { - .name = "ttyS", - .write = mcfrs_console_write, - .device = mcfrs_console_device, - .setup = mcfrs_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init mcfrs_console_init(void) -{ - register_console(&mcfrs_console); - return 0; -} - -console_initcall(mcfrs_console_init); - -/****************************************************************************/ diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h deleted file mode 100644 index 56420e2cb11..00000000000 --- a/drivers/serial/mcfserial.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * mcfserial.c -- serial driver for ColdFire internal UARTS. - * - * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com> - * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> - * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com> - * - * Based on code from 68332serial.c which was: - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 TSHG - * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> - */ -#ifndef _MCF_SERIAL_H -#define _MCF_SERIAL_H - -#include <linux/serial.h> - -#ifdef __KERNEL__ - -/* - * Define a local serial stats structure. - */ - -struct mcf_stats { - unsigned int rx; - unsigned int tx; - unsigned int rxbreak; - unsigned int rxframing; - unsigned int rxparity; - unsigned int rxoverrun; -}; - - -/* - * This is our internal structure for each serial port's state. - * Each serial port has one of these structures associated with it. - */ - -struct mcf_serial { - int magic; - volatile unsigned char *addr; /* UART memory address */ - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - unsigned char imr; /* Software imr register */ - unsigned int baud; - int sigs; - int custom_divisor; - int x_char; /* xon/xoff character */ - int baud_base; - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct mcf_stats stats; - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - -}; - -#endif /* __KERNEL__ */ - -#endif /* _MCF_SERIAL_H */ diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index 9f8ccb735c1..3f489329e8d 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -35,8 +35,8 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/arch/netx-regs.h> +#include <mach/hardware.h> +#include <mach/netx-regs.h> /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_NX_MAJOR 204 diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index b9a93f326fb..abc00be5543 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -45,9 +45,9 @@ #include <linux/clk.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/irq.h> -#include <asm/arch/pxa-regs.h> +#include <mach/pxa-regs.h> struct uart_pxa_port { @@ -534,6 +534,11 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_IER, up->ier); + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + else + up->mcr &= ~UART_MCR_AFE; + serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c index a1102053e55..c8b4266ac35 100644 --- a/drivers/serial/s3c2400.c +++ b/drivers/serial/s3c2400.c @@ -17,10 +17,10 @@ #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/plat-s3c/regs-serial.h> -#include <asm/arch/regs-gpio.h> +#include <mach/regs-gpio.h> #include "samsung.h" diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index c5f03f41686..40a2531b554 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -19,10 +19,10 @@ #include <linux/serial.h> #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/plat-s3c/regs-serial.h> -#include <asm/arch/regs-gpio.h> +#include <mach/regs-gpio.h> #include "samsung.h" diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c index ce0c220e3e9..d0170319c72 100644 --- a/drivers/serial/s3c2412.c +++ b/drivers/serial/s3c2412.c @@ -19,10 +19,10 @@ #include <linux/serial.h> #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/plat-s3c/regs-serial.h> -#include <asm/arch/regs-gpio.h> +#include <mach/regs-gpio.h> #include "samsung.h" diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c index 38f954bd39c..d4a2b17b249 100644 --- a/drivers/serial/s3c2440.c +++ b/drivers/serial/s3c2440.c @@ -19,10 +19,10 @@ #include <linux/serial.h> #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/plat-s3c/regs-serial.h> -#include <asm/arch/regs-gpio.h> +#include <mach/regs-gpio.h> #include "samsung.h" diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index a5e76cc1807..b24a25ea6bc 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -39,7 +39,7 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach/serial_sa1100.h> /* We've been assigned a range on the "Low-density serial ports" major */ diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index d852f83f890..5a88b3f9fe9 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -45,10 +45,10 @@ #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/plat-s3c/regs-serial.h> -#include <asm/arch/regs-gpio.h> +#include <mach/regs-gpio.h> #include "samsung.h" diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f977c98cfa9..6bdf3362e3b 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) "transmitter\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", - drv->dev_name, port->line); + drv->dev_name, + drv->tty_driver->name_base + port->line); ops->shutdown(port); } @@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) switch (port->iotype) { case UPIO_PORT: - snprintf(address, sizeof(address), - "I/O 0x%x", port->iobase); + snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); break; case UPIO_HUB6: snprintf(address, sizeof(address), - "I/O 0x%x offset 0x%x", port->iobase, port->hub6); + "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: case UPIO_MEM32: @@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", - drv->dev_name, port->line, address, port->irq, uart_type(port)); + drv->dev_name, + drv->tty_driver->name_base + port->line, + address, port->irq, uart_type(port)); } static void diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index 0edbc5dd378..998e89dc5aa 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -26,8 +26,8 @@ #include <asm/irq.h> #include <asm/mach/irq.h> -#include <asm/arch/regs-uart.h> -#include <asm/arch/regs-irq.h> +#include <mach/regs-uart.h> +#include <mach/regs-irq.h> #if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -63,8 +63,44 @@ #define UART_DUMMY_LSR_RX 0x100 #define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4) -#define tx_enabled(port) ((port)->unused[0]) -#define rx_enabled(port) ((port)->unused[1]) +static inline int tx_enabled(struct uart_port *port) +{ + return port->unused[0] & 1; +} + +static inline int rx_enabled(struct uart_port *port) +{ + return port->unused[0] & 2; +} + +static inline int ms_enabled(struct uart_port *port) +{ + return port->unused[0] & 4; +} + +static inline void ms_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 4; + else + port->unused[0] &= ~4; +} + +static inline void rx_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 2; + else + port->unused[0] &= ~2; +} + +static inline void tx_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 1; + else + port->unused[0] &= ~1; +} #ifdef SUPPORT_SYSRQ @@ -75,7 +111,7 @@ static void ks8695uart_stop_tx(struct uart_port *port) { if (tx_enabled(port)) { disable_irq(KS8695_IRQ_UART_TX); - tx_enabled(port) = 0; + tx_enable(port, 0); } } @@ -83,7 +119,7 @@ static void ks8695uart_start_tx(struct uart_port *port) { if (!tx_enabled(port)) { enable_irq(KS8695_IRQ_UART_TX); - tx_enabled(port) = 1; + tx_enable(port, 1); } } @@ -91,18 +127,24 @@ static void ks8695uart_stop_rx(struct uart_port *port) { if (rx_enabled(port)) { disable_irq(KS8695_IRQ_UART_RX); - rx_enabled(port) = 0; + rx_enable(port, 0); } } static void ks8695uart_enable_ms(struct uart_port *port) { - enable_irq(KS8695_IRQ_UART_MODEM_STATUS); + if (!ms_enabled(port)) { + enable_irq(KS8695_IRQ_UART_MODEM_STATUS); + ms_enable(port,1); + } } static void ks8695uart_disable_ms(struct uart_port *port) { - disable_irq(KS8695_IRQ_UART_MODEM_STATUS); + if (ms_enabled(port)) { + disable_irq(KS8695_IRQ_UART_MODEM_STATUS); + ms_enable(port,0); + } } static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) @@ -285,8 +327,9 @@ static int ks8695uart_startup(struct uart_port *port) int retval; set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN); - tx_enabled(port) = 0; - rx_enabled(port) = 1; + tx_enable(port, 0); + rx_enable(port, 1); + ms_enable(port, 1); /* * Allocate the IRQ diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index cd728df6a01..8a0749e34ca 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -451,19 +451,21 @@ SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) SCIF_FNS(SCLSR, 0, 0, 0x28, 16) -#if defined(CONFIG_CPU_SUBTYPE_SH7763) -/* SH7763 SCIF2 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) -SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) -#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ +SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) +SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) +SCIF_FNS(SCLSR, 0, 0, 0x28, 16) #else SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7722) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index aeeec5588af..a94a2ab4b57 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -17,11 +17,11 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/of_device.h> #include <asm/hypervisor.h> #include <asm/spitfire.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/irq.h> #if defined(CONFIG_MAGIC_SYSRQ) @@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev) return 0; } -static struct of_device_id hv_match[] = { +static const struct of_device_id hv_match[] = { { .name = "console", .compatible = "qcn", diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 15ee497e1c7..0355efe115d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -32,11 +32,11 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/of_device.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op) return 0; } -static struct of_device_id sab_match[] = { +static const struct of_device_id sab_match[] = { { .name = "se", }, diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index e24e6823508..a4dc79b1d7a 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -35,11 +35,11 @@ #include <linux/serial_reg.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/of_device.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op) return 0; } -static struct of_device_id su_match[] = { +static const struct of_device_id su_match[] = { { .name = "su", }, diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 0f3d69b86d6..45a299f3561 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -32,11 +32,11 @@ #include <linux/serio.h> #endif #include <linux/init.h> +#include <linux/of_device.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op) return 0; } -static struct of_device_id zs_match[] = { +static const struct of_device_id zs_match[] = { { .name = "zs", }, diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c deleted file mode 100644 index 5acf061b6cd..00000000000 --- a/drivers/serial/v850e_uart.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader <miles@gnu.org> - */ - -/* This driver supports both the original V850E UART interface (called - merely `UART' in the docs) and the newer `UARTB' interface, which is - roughly a superset of the first one. The selection is made at - configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is - presumed, otherwise the old UART -- as these are on-CPU UARTS, a system - can never have both. - - The UARTB interface also has a 16-entry FIFO mode, which is not - yet supported by this driver. */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/console.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/serial_core.h> - -#include <asm/v850e_uart.h> - -/* Initial UART state. This may be overridden by machine-dependent headers. */ -#ifndef V850E_UART_INIT_BAUD -#define V850E_UART_INIT_BAUD 115200 -#endif -#ifndef V850E_UART_INIT_CFLAGS -#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) -#endif - -/* A string used for prefixing printed descriptions; since the same UART - macro is actually used on other chips than the V850E. This must be a - constant string. */ -#ifndef V850E_UART_CHIP_NAME -#define V850E_UART_CHIP_NAME "V850E" -#endif - -#define V850E_UART_MINOR_BASE 64 /* First tty minor number */ - - -/* Low-level UART functions. */ - -/* Configure and turn on uart channel CHAN, using the termios `control - modes' bits in CFLAGS, and a baud-rate of BAUD. */ -void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) -{ - int flags; - v850e_uart_speed_t old_speed; - v850e_uart_config_t old_config; - v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); - v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); - - /* Disable interrupts while we're twiddling the hardware. */ - local_irq_save (flags); - -#ifdef V850E_UART_PRE_CONFIGURE - V850E_UART_PRE_CONFIGURE (chan, cflags, baud); -#endif - - old_config = V850E_UART_CONFIG (chan); - old_speed = v850e_uart_speed (chan); - - if (! v850e_uart_speed_eq (old_speed, new_speed)) { - /* The baud rate has changed. First, disable the UART. */ - V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; - old_config = 0; /* Force the uart to be re-initialized. */ - - /* Reprogram the baud-rate generator. */ - v850e_uart_set_speed (chan, new_speed); - } - - if (! (old_config & V850E_UART_CONFIG_ENABLED)) { - /* If we are using the uart for the first time, start by - enabling it, which must be done before turning on any - other bits. */ - V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; - /* See the initial state. */ - old_config = V850E_UART_CONFIG (chan); - } - - if (new_config != old_config) { - /* Which of the TXE/RXE bits we'll temporarily turn off - before changing other control bits. */ - unsigned temp_disable = 0; - /* Which of the TXE/RXE bits will be enabled. */ - unsigned enable = 0; - unsigned changed_bits = new_config ^ old_config; - - /* Which of RX/TX will be enabled in the new configuration. */ - if (new_config & V850E_UART_CONFIG_RX_BITS) - enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); - if (new_config & V850E_UART_CONFIG_TX_BITS) - enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); - - /* Figure out which of RX/TX needs to be disabled; note - that this will only happen if they're not already - disabled. */ - if (changed_bits & V850E_UART_CONFIG_RX_BITS) - temp_disable - |= (old_config & V850E_UART_CONFIG_RX_ENABLE); - if (changed_bits & V850E_UART_CONFIG_TX_BITS) - temp_disable - |= (old_config & V850E_UART_CONFIG_TX_ENABLE); - - /* We have to turn off RX and/or TX mode before changing - any associated control bits. */ - if (temp_disable) - V850E_UART_CONFIG (chan) = old_config & ~temp_disable; - - /* Write the new control bits, while RX/TX are disabled. */ - if (changed_bits & ~enable) - V850E_UART_CONFIG (chan) = new_config & ~enable; - - v850e_uart_config_delay (new_config, new_speed); - - /* Write the final version, with enable bits turned on. */ - V850E_UART_CONFIG (chan) = new_config; - } - - local_irq_restore (flags); -} - - -/* Low-level console. */ - -#ifdef CONFIG_V850E_UART_CONSOLE - -static void v850e_uart_cons_write (struct console *co, - const char *s, unsigned count) -{ - if (count > 0) { - unsigned chan = co->index; - unsigned irq = V850E_UART_TX_IRQ (chan); - int irq_was_enabled, irq_was_pending, flags; - - /* We don't want to get `transmission completed' - interrupts, since we're busy-waiting, so we disable them - while sending (we don't disable interrupts entirely - because sending over a serial line is really slow). We - save the status of the tx interrupt and restore it when - we're done so that using printk doesn't interfere with - normal serial transmission (other than interleaving the - output, of course!). This should work correctly even if - this function is interrupted and the interrupt printks - something. */ - - /* Disable interrupts while fiddling with tx interrupt. */ - local_irq_save (flags); - /* Get current tx interrupt status. */ - irq_was_enabled = v850e_intc_irq_enabled (irq); - irq_was_pending = v850e_intc_irq_pending (irq); - /* Disable tx interrupt if necessary. */ - if (irq_was_enabled) - v850e_intc_disable_irq (irq); - /* Turn interrupts back on. */ - local_irq_restore (flags); - - /* Send characters. */ - while (count > 0) { - int ch = *s++; - - if (ch == '\n') { - /* We don't have the benefit of a tty - driver, so translate NL into CR LF. */ - v850e_uart_wait_for_xmit_ok (chan); - v850e_uart_putc (chan, '\r'); - } - - v850e_uart_wait_for_xmit_ok (chan); - v850e_uart_putc (chan, ch); - - count--; - } - - /* Restore saved tx interrupt status. */ - if (irq_was_enabled) { - /* Wait for the last character we sent to be - completely transmitted (as we'll get an - interrupt interrupt at that point). */ - v850e_uart_wait_for_xmit_done (chan); - /* Clear pending interrupts received due - to our transmission, unless there was already - one pending, in which case we want the - handler to be called. */ - if (! irq_was_pending) - v850e_intc_clear_pending_irq (irq); - /* ... and then turn back on handling. */ - v850e_intc_enable_irq (irq); - } - } -} - -extern struct uart_driver v850e_uart_driver; -static struct console v850e_uart_cons = -{ - .name = "ttyS", - .write = v850e_uart_cons_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .cflag = V850E_UART_INIT_CFLAGS, - .index = -1, - .data = &v850e_uart_driver, -}; - -void v850e_uart_cons_init (unsigned chan) -{ - v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, - V850E_UART_INIT_BAUD); - v850e_uart_cons.index = chan; - register_console (&v850e_uart_cons); - printk ("Console: %s on-chip UART channel %d\n", - V850E_UART_CHIP_NAME, chan); -} - -/* This is what the init code actually calls. */ -static int v850e_uart_console_init (void) -{ - v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); - return 0; -} -console_initcall(v850e_uart_console_init); - -#define V850E_UART_CONSOLE &v850e_uart_cons - -#else /* !CONFIG_V850E_UART_CONSOLE */ -#define V850E_UART_CONSOLE 0 -#endif /* CONFIG_V850E_UART_CONSOLE */ - -/* TX/RX interrupt handlers. */ - -static void v850e_uart_stop_tx (struct uart_port *port); - -void v850e_uart_tx (struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - int stopped = uart_tx_stopped (port); - - if (v850e_uart_xmit_ok (port->line)) { - int tx_ch; - - if (port->x_char) { - tx_ch = port->x_char; - port->x_char = 0; - } else if (!uart_circ_empty (xmit) && !stopped) { - tx_ch = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - goto no_xmit; - - v850e_uart_putc (port->line, tx_ch); - port->icount.tx++; - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - } - - no_xmit: - if (uart_circ_empty (xmit) || stopped) - v850e_uart_stop_tx (port, stopped); -} - -static irqreturn_t v850e_uart_tx_irq(int irq, void *data) -{ - struct uart_port *port = data; - v850e_uart_tx (port); - return IRQ_HANDLED; -} - -static irqreturn_t v850e_uart_rx_irq(int irq, void *data) -{ - struct uart_port *port = data; - unsigned ch_stat = TTY_NORMAL; - unsigned ch = v850e_uart_getc (port->line); - unsigned err = v850e_uart_err (port->line); - - if (err) { - if (err & V850E_UART_ERR_OVERRUN) { - ch_stat = TTY_OVERRUN; - port->icount.overrun++; - } else if (err & V850E_UART_ERR_FRAME) { - ch_stat = TTY_FRAME; - port->icount.frame++; - } else if (err & V850E_UART_ERR_PARITY) { - ch_stat = TTY_PARITY; - port->icount.parity++; - } - } - - port->icount.rx++; - - tty_insert_flip_char (port->info->port.tty, ch, ch_stat); - tty_schedule_flip (port->info->port.tty); - - return IRQ_HANDLED; -} - - -/* Control functions for the serial framework. */ - -static void v850e_uart_nop (struct uart_port *port) { } -static int v850e_uart_success (struct uart_port *port) { return 0; } - -static unsigned v850e_uart_tx_empty (struct uart_port *port) -{ - return TIOCSER_TEMT; /* Can't detect. */ -} - -static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) -{ -#ifdef V850E_UART_SET_RTS - V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); -#endif -} - -static unsigned v850e_uart_get_mctrl (struct uart_port *port) -{ - /* We don't support DCD or DSR, so consider them permanently active. */ - int mctrl = TIOCM_CAR | TIOCM_DSR; - - /* We may support CTS. */ -#ifdef V850E_UART_CTS - mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; -#else - mctrl |= TIOCM_CTS; -#endif - - return mctrl; -} - -static void v850e_uart_start_tx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); - v850e_uart_tx (port); - v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); -} - -static void v850e_uart_stop_tx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); -} - -static void v850e_uart_start_rx (struct uart_port *port) -{ - v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); -} - -static void v850e_uart_stop_rx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); -} - -static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) -{ - /* Umm, do this later. */ -} - -static int v850e_uart_startup (struct uart_port *port) -{ - int err; - - /* Alloc RX irq. */ - err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, - IRQF_DISABLED, "v850e_uart", port); - if (err) - return err; - - /* Alloc TX irq. */ - err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, - IRQF_DISABLED, "v850e_uart", port); - if (err) { - free_irq (V850E_UART_RX_IRQ (port->line), port); - return err; - } - - v850e_uart_start_rx (port); - - return 0; -} - -static void v850e_uart_shutdown (struct uart_port *port) -{ - /* Disable port interrupts. */ - free_irq (V850E_UART_TX_IRQ (port->line), port); - free_irq (V850E_UART_RX_IRQ (port->line), port); - - /* Turn off xmit/recv enable bits. */ - V850E_UART_CONFIG (port->line) - &= ~(V850E_UART_CONFIG_TX_ENABLE - | V850E_UART_CONFIG_RX_ENABLE); - /* Then reset the channel. */ - V850E_UART_CONFIG (port->line) = 0; -} - -static void -v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned cflags = termios->c_cflag; - - /* Restrict flags to legal values. */ - if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) - /* The new value of CSIZE is invalid, use the old value. */ - cflags = (cflags & ~CSIZE) - | (old ? (old->c_cflag & CSIZE) : CS8); - - termios->c_cflag = cflags; - - v850e_uart_configure (port->line, cflags, - uart_get_baud_rate (port, termios, old, - v850e_uart_min_baud(), - v850e_uart_max_baud())); -} - -static const char *v850e_uart_type (struct uart_port *port) -{ - return port->type == PORT_V850E_UART ? "v850e_uart" : 0; -} - -static void v850e_uart_config_port (struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_V850E_UART; -} - -static int -v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) - return -EINVAL; - if (ser->irq != V850E_UART_TX_IRQ (port->line)) - return -EINVAL; - return 0; -} - -static struct uart_ops v850e_uart_ops = { - .tx_empty = v850e_uart_tx_empty, - .get_mctrl = v850e_uart_get_mctrl, - .set_mctrl = v850e_uart_set_mctrl, - .start_tx = v850e_uart_start_tx, - .stop_tx = v850e_uart_stop_tx, - .stop_rx = v850e_uart_stop_rx, - .enable_ms = v850e_uart_nop, - .break_ctl = v850e_uart_break_ctl, - .startup = v850e_uart_startup, - .shutdown = v850e_uart_shutdown, - .set_termios = v850e_uart_set_termios, - .type = v850e_uart_type, - .release_port = v850e_uart_nop, - .request_port = v850e_uart_success, - .config_port = v850e_uart_config_port, - .verify_port = v850e_uart_verify_port, -}; - -/* Initialization and cleanup. */ - -static struct uart_driver v850e_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "v850e_uart", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = V850E_UART_MINOR_BASE, - .nr = V850E_UART_NUM_CHANNELS, - .cons = V850E_UART_CONSOLE, -}; - - -static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; - -static int __init v850e_uart_init (void) -{ - int rval; - - printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); - - rval = uart_register_driver (&v850e_uart_driver); - if (rval == 0) { - unsigned chan; - - for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { - struct uart_port *port = &v850e_uart_ports[chan]; - - memset (port, 0, sizeof *port); - - port->ops = &v850e_uart_ops; - port->line = chan; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - - /* We actually use multiple IRQs, but the serial - framework seems to mainly use this for - informational purposes anyway. Here we use the TX - irq. */ - port->irq = V850E_UART_TX_IRQ (chan); - - /* The serial framework doesn't really use these - membase/mapbase fields for anything useful, but - it requires that they be something non-zero to - consider the port `valid', and also uses them - for informational purposes. */ - port->membase = (void *)V850E_UART_BASE_ADDR (chan); - port->mapbase = V850E_UART_BASE_ADDR (chan); - - /* The framework insists on knowing the uart's master - clock freq, though it doesn't seem to do anything - useful for us with it. We must make it at least - higher than (the maximum baud rate * 16), otherwise - the framework will puke during its internal - calculations, and force the baud rate to be 9600. - To be accurate though, just repeat the calculation - we use when actually setting the speed. */ - port->uartclk = v850e_uart_max_clock() * 16; - - uart_add_one_port (&v850e_uart_driver, port); - } - } - - return rval; -} - -static void __exit v850e_uart_exit (void) -{ - unsigned chan; - - for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) - uart_remove_one_port (&v850e_uart_driver, - &v850e_uart_ports[chan]); - - uart_unregister_driver (&v850e_uart_driver); -} - -module_init (v850e_uart_init); -module_exit (v850e_uart_exit); - -MODULE_AUTHOR ("Miles Bader"); -MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); -MODULE_LICENSE ("GPL"); |