diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/68328serial.h | 5 | ||||
-rw-r--r-- | drivers/serial/68360serial.c | 51 | ||||
-rw-r--r-- | drivers/serial/8250.c | 71 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 34 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/altera_uart.c | 156 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.c | 9 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.h | 2 | ||||
-rw-r--r-- | drivers/serial/imx.c | 5 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_driver.c | 4 | ||||
-rw-r--r-- | drivers/serial/kgdboc.c | 2 | ||||
-rw-r--r-- | drivers/serial/max3107.c | 34 | ||||
-rw-r--r-- | drivers/serial/mfd.c | 49 | ||||
-rw-r--r-- | drivers/serial/mrst_max3110.c | 358 | ||||
-rw-r--r-- | drivers/serial/mrst_max3110.h | 1 | ||||
-rw-r--r-- | drivers/serial/of_serial.c | 12 | ||||
-rw-r--r-- | drivers/serial/omap-serial.c | 1333 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 49 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 17 | ||||
-rw-r--r-- | drivers/serial/uartlite.c | 28 |
20 files changed, 1902 insertions, 319 deletions
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h index 58aa2154655..664ceb0a158 100644 --- a/drivers/serial/68328serial.h +++ b/drivers/serial/68328serial.h @@ -181,13 +181,8 @@ struct m68k_serial { /* * Define the number of ports supported and their irqs. */ -#ifndef CONFIG_68328_SERIAL_UART2 #define NR_PORTS 1 #define UART_IRQ_DEFNS {UART_IRQ_NUM} -#else -#define NR_PORTS 2 -#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM} -#endif #endif /* __KERNEL__ */ #endif /* !(_MC683XX_SERIAL_H) */ diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 0dff3bbddc8..88b13356ec1 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -1381,6 +1381,30 @@ static void send_break(ser_info_t *info, unsigned int duration) } +/* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ +static int rs_360_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + struct async_icount cnow; + + local_irq_disable(); + cnow = info->state->icount; + local_irq_enable(); + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + + return 0; +} + static int rs_360_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { @@ -1394,7 +1418,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (cmd != TIOCMIWAIT) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } @@ -1477,31 +1501,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, return 0; #endif - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - local_irq_disable(); - cnow = info->state->icount; - local_irq_enable(); - p_cuser = (struct serial_icounter_struct *) arg; -/* error = put_user(cnow.cts, &p_cuser->cts); */ -/* if (error) return error; */ -/* error = put_user(cnow.dsr, &p_cuser->dsr); */ -/* if (error) return error; */ -/* error = put_user(cnow.rng, &p_cuser->rng); */ -/* if (error) return error; */ -/* error = put_user(cnow.dcd, &p_cuser->dcd); */ -/* if (error) return error; */ - - put_user(cnow.cts, &p_cuser->cts); - put_user(cnow.dsr, &p_cuser->dsr); - put_user(cnow.rng, &p_cuser->rng); - put_user(cnow.dcd, &p_cuser->dcd); - return 0; default: return -ENOIOCTLCMD; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 24110f6f61e..4d8e14b7aa9 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/tty.h> +#include <linux/ratelimit.h> #include <linux/tty_flip.h> #include <linux/serial_reg.h> #include <linux/serial_core.h> @@ -154,12 +155,6 @@ struct uart_8250_port { unsigned char lsr_saved_flags; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; - - /* - * We provide a per-port pm hook. - */ - void (*pm)(struct uart_port *port, - unsigned int state, unsigned int old); }; struct irq_info { @@ -924,7 +919,7 @@ static int broken_efr(struct uart_8250_port *up) /* * Exar ST16C2550 "A2" devices incorrectly detect as * having an EFR, and report an ID of 0x0201. See - * http://www.exar.com/info.php?pdf=dan180_oct2004.pdf + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html */ if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) return 1; @@ -1606,8 +1601,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) if (l == i->head && pass_counter++ > PASS_LIMIT) { /* If we hit this, we're dead. */ - printk(KERN_ERR "serial8250: too much work for " - "irq%d\n", irq); + printk_ratelimited(KERN_ERR + "serial8250: too much work for irq%d\n", irq); break; } } while (l != end); @@ -1722,12 +1717,6 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) mutex_unlock(&hash_mutex); } -/* Base timer interval for polling */ -static inline int poll_timeout(int timeout) -{ - return timeout > 6 ? (timeout / 2 - 2) : 1; -} - /* * This function is used to handle ports that do not have an * interrupt. This doesn't work very well for 16450's, but gives @@ -1742,7 +1731,7 @@ static void serial8250_timeout(unsigned long data) iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) serial8250_handle_port(up); - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); } static void serial8250_backup_timeout(unsigned long data) @@ -1787,7 +1776,7 @@ static void serial8250_backup_timeout(unsigned long data) /* Standard timer interval plus 0.2s to keep the port running */ mod_timer(&up->timer, - jiffies + poll_timeout(up->port.timeout) + HZ / 5); + jiffies + uart_poll_timeout(&up->port) + HZ / 5); } static unsigned int serial8250_tx_empty(struct uart_port *port) @@ -1867,15 +1856,17 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) unsigned int status, tmout = 10000; /* Wait up to 10ms for the character(s) to be sent. */ - do { + for (;;) { status = serial_in(up, UART_LSR); up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + if ((status & bits) == bits) + break; if (--tmout == 0) break; udelay(1); - } while ((status & bits) != bits); + } /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -2069,7 +2060,7 @@ static int serial8250_startup(struct uart_port *port) up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ / 5); + uart_poll_timeout(port) + HZ / 5); } /* @@ -2079,7 +2070,7 @@ static int serial8250_startup(struct uart_port *port) */ if (!is_real_interrupt(up->port.irq)) { up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); } else { retval = serial_link_irq_chain(up); if (retval) @@ -2440,16 +2431,24 @@ serial8250_set_ldisc(struct uart_port *port, int new) port->flags &= ~UPF_HARDPPS_CD; } -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { struct uart_8250_port *p = (struct uart_8250_port *)port; serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); - if (p->pm) - p->pm(port, state, oldstate); +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); } static unsigned int serial8250_port_size(struct uart_8250_port *pt) @@ -2674,6 +2673,16 @@ static struct uart_ops serial8250_pops = { static struct uart_8250_port serial8250_ports[UART_NR]; +static void (*serial8250_isa_config)(int port, struct uart_port *up, + unsigned short *capabilities); + +void serial8250_set_isa_configurator( + void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) +{ + serial8250_isa_config = v; +} +EXPORT_SYMBOL(serial8250_set_isa_configurator); + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -2719,6 +2728,9 @@ static void __init serial8250_isa_init_ports(void) up->port.regshift = old_serial_port[i].iomem_reg_shift; set_io_from_upio(&up->port); up->port.irqflags |= irqflag; + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + } } @@ -3010,6 +3022,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_in = p->serial_in; port.serial_out = p->serial_out; port.set_termios = p->set_termios; + port.pm = p->pm; port.dev = &dev->dev; port.irqflags |= irqflag; ret = serial8250_register_port(&port); @@ -3176,6 +3189,12 @@ int serial8250_register_port(struct uart_port *port) /* Possibly override set_termios call */ if (port->set_termios) uart->port.set_termios = port->set_termios; + if (port->pm) + uart->port.pm = port->pm; + + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); ret = uart_add_one_port(&serial8250_reg, &uart->port); if (ret == 0) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3198c5335f0..aff9dcd051c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -718,13 +718,6 @@ config SERIAL_MRST_MAX3110 the Intel Moorestown platform. On other systems use the max3100 driver. -config MRST_MAX3110_IRQ - boolean "Enable GPIO IRQ for Max3110 over Moorestown" - default n - depends on SERIAL_MRST_MAX3110 && GPIO_LANGWELL - help - This has to be enabled after Moorestown GPIO driver is loaded - config SERIAL_MFD_HSU tristate "Medfield High Speed UART support" depends on PCI @@ -1417,6 +1410,33 @@ config SERIAL_OF_PLATFORM Currently, only 8250 compatible ports are supported, but others can easily be added. +config SERIAL_OMAP + tristate "OMAP serial port support" + depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 + select SERIAL_CORE + help + If you have a machine based on an Texas Instruments OMAP CPU you + can enable its onboard serial ports by enabling this option. + + By enabling this option you take advantage of dma feature available + with the omap-serial driver. DMA support can be enabled from platform + data. + +config SERIAL_OMAP_CONSOLE + bool "Console on OMAP serial port" + depends on SERIAL_OMAP + select SERIAL_CORE_CONSOLE + help + Select this option if you would like to use omap serial port as + console. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyOx". (Try "man bootparam" or see the documentation of + your boot loader about how to pass options to the kernel at + boot time.) + config SERIAL_OF_PLATFORM_NWPSERIAL tristate "NWP serial port driver" depends on PPC_OF && PPC_DCR diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 1ca4fd599ff..c5705765454 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o +obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index f8d8a00554d..721216292a5 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/timer.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/console.h> @@ -27,6 +28,8 @@ #include <linux/altera_uart.h> #define DRV_NAME "altera_uart" +#define SERIAL_ALTERA_MAJOR 204 +#define SERIAL_ALTERA_MINOR 213 /* * Altera UART register definitions according to the Nios UART datasheet: @@ -76,13 +79,28 @@ */ struct altera_uart { struct uart_port port; + struct timer_list tmr; unsigned int sigs; /* Local copy of line sigs */ unsigned short imr; /* Local IMR mirror */ }; +static u32 altera_uart_readl(struct uart_port *port, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + return readl(port->membase + (reg << platp->bus_shift)); +} + +static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + writel(dat, port->membase + (reg << platp->bus_shift)); +} + static unsigned int altera_uart_tx_empty(struct uart_port *port) { - return (readl(port->membase + ALTERA_UART_STATUS_REG) & + return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0; } @@ -91,8 +109,7 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned int sigs; - sigs = - (readl(port->membase + ALTERA_UART_STATUS_REG) & + sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; sigs |= (pp->sigs & TIOCM_RTS); @@ -108,7 +125,7 @@ static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_start_tx(struct uart_port *port) @@ -116,7 +133,7 @@ static void altera_uart_start_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_stop_tx(struct uart_port *port) @@ -124,7 +141,7 @@ static void altera_uart_stop_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_stop_rx(struct uart_port *port) @@ -132,7 +149,7 @@ static void altera_uart_stop_rx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_break_ctl(struct uart_port *port, int break_state) @@ -145,7 +162,7 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); } @@ -168,7 +185,8 @@ static void altera_uart_set_termios(struct uart_port *port, tty_termios_encode_baud_rate(termios, baud, baud); spin_lock_irqsave(&port->lock, flags); - writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG); + uart_update_timeout(port, termios->c_cflag, baud); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); spin_unlock_irqrestore(&port->lock, flags); } @@ -178,14 +196,15 @@ static void altera_uart_rx_chars(struct altera_uart *pp) unsigned char ch, flag; unsigned short status; - while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) & + while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) & ALTERA_UART_STATUS_RRDY_MSK) { - ch = readl(port->membase + ALTERA_UART_RXDATA_REG); + ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG); flag = TTY_NORMAL; port->icount.rx++; if (status & ALTERA_UART_STATUS_E_MSK) { - writel(status, port->membase + ALTERA_UART_STATUS_REG); + altera_uart_writel(port, status, + ALTERA_UART_STATUS_REG); if (status & ALTERA_UART_STATUS_BRK_MSK) { port->icount.brk++; @@ -225,18 +244,18 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (port->x_char) { /* Send special char - probably flow control */ - writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG); port->x_char = 0; port->icount.tx++; return; } - while (readl(port->membase + ALTERA_UART_STATUS_REG) & + while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK) { if (xmit->head == xmit->tail) break; - writel(xmit->buf[xmit->tail], - port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, xmit->buf[xmit->tail], + ALTERA_UART_TXDATA_REG); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } @@ -246,7 +265,7 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (xmit->head == xmit->tail) { pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } } @@ -256,7 +275,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned int isr; - isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr; + isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; spin_lock(&port->lock); if (isr & ALTERA_UART_STATUS_RRDY_MSK) @@ -268,14 +287,23 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) return IRQ_RETVAL(isr); } +static void altera_uart_timer(unsigned long data) +{ + struct uart_port *port = (void *)data; + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + altera_uart_interrupt(0, port); + mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); +} + static void altera_uart_config_port(struct uart_port *port, int flags) { port->type = PORT_ALTERA_UART; /* Clear mask, so no surprise interrupts. */ - writel(0, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG); /* Clear status register */ - writel(0, port->membase + ALTERA_UART_STATUS_REG); + altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG); } static int altera_uart_startup(struct uart_port *port) @@ -284,6 +312,12 @@ static int altera_uart_startup(struct uart_port *port) unsigned long flags; int ret; + if (!port->irq) { + setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port); + mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); + return 0; + } + ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED, DRV_NAME, port); if (ret) { @@ -316,7 +350,10 @@ static void altera_uart_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); - free_irq(port->irq, port); + if (port->irq) + free_irq(port->irq, port); + else + del_timer_sync(&pp->tmr); } static const char *altera_uart_type(struct uart_port *port) @@ -384,8 +421,9 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) port->iotype = SERIAL_IO_MEM; port->irq = platp[i].irq; port->uartclk = platp[i].uartclk; - port->flags = ASYNC_BOOT_AUTOCONF; + port->flags = UPF_BOOT_AUTOCONF; port->ops = &altera_uart_ops; + port->private_data = platp; } return 0; @@ -393,7 +431,7 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) static void altera_uart_console_putc(struct uart_port *port, const char c) { - while (!(readl(port->membase + ALTERA_UART_STATUS_REG) & + while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK)) cpu_relax(); @@ -423,7 +461,7 @@ static int __init altera_uart_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) return -EINVAL; port = &altera_uart_ports[co->index].port; - if (port->membase == 0) + if (!port->membase) return -ENODEV; if (options) @@ -435,7 +473,7 @@ static int __init altera_uart_console_setup(struct console *co, char *options) static struct uart_driver altera_uart_driver; static struct console altera_uart_console = { - .name = "ttyS", + .name = "ttyAL", .write = altera_uart_console_write, .device = uart_console_device, .setup = altera_uart_console_setup, @@ -466,9 +504,9 @@ console_initcall(altera_uart_console_init); static struct uart_driver altera_uart_driver = { .owner = THIS_MODULE, .driver_name = DRV_NAME, - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, + .dev_name = "ttyAL", + .major = SERIAL_ALTERA_MAJOR, + .minor = SERIAL_ALTERA_MINOR, .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS, .cons = ALTERA_UART_CONSOLE, }; @@ -477,38 +515,55 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) { struct altera_uart_platform_uart *platp = pdev->dev.platform_data; struct uart_port *port; - int i; + struct resource *res_mem; + struct resource *res_irq; + int i = pdev->id; - for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) { - port = &altera_uart_ports[i].port; + /* -1 emphasizes that the platform must have one port, no .N suffix */ + if (i == -1) + i = 0; - port->line = i; - port->type = PORT_ALTERA_UART; - port->mapbase = platp[i].mapbase; - port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = platp[i].uartclk; - port->ops = &altera_uart_ops; - port->flags = ASYNC_BOOT_AUTOCONF; + if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) + return -EINVAL; - uart_add_one_port(&altera_uart_driver, port); - } + port = &altera_uart_ports[i].port; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem) + port->mapbase = res_mem->start; + else if (platp->mapbase) + port->mapbase = platp->mapbase; + else + return -EINVAL; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res_irq) + port->irq = res_irq->start; + else if (platp->irq) + port->irq = platp->irq; + + port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); + if (!port->membase) + return -ENOMEM; + + port->line = i; + port->type = PORT_ALTERA_UART; + port->iotype = SERIAL_IO_MEM; + port->uartclk = platp->uartclk; + port->ops = &altera_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->private_data = platp; + + uart_add_one_port(&altera_uart_driver, port); return 0; } static int __devexit altera_uart_remove(struct platform_device *pdev) { - struct uart_port *port; - int i; - - for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++) { - port = &altera_uart_ports[i].port; - if (port) - uart_remove_one_port(&altera_uart_driver, port); - } + struct uart_port *port = &altera_uart_ports[pdev->id].port; + uart_remove_one_port(&altera_uart_driver, port); return 0; } @@ -550,3 +605,4 @@ MODULE_DESCRIPTION("Altera UART driver"); MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR); diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 5318dd3774a..e95c524d9d1 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -10,7 +10,7 @@ /* * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf + * http://www.analog.com/static/imported-files/application_notes/EE191.pdf * This application note describe how to implement a UART on a Sharc DSP, * but this driver is implemented on Blackfin Processor. * Transmit Frame Sync is not used by this driver to transfer data out. @@ -131,7 +131,12 @@ static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); tclkdiv = sclk / (2 * baud_rate) - 1; - rclkdiv = sclk / (2 * baud_rate * 2) - 1; + /* The actual uart baud rate of devices vary between +/-2%. The sport + * RX sample rate should be faster than the double of the worst case, + * otherwise, wrong data are received. So, set sport RX clock to be + * 3% faster. + */ + rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1; SPORT_PUT_TCLKDIV(up, tclkdiv); SPORT_PUT_RCLKDIV(up, rclkdiv); SSYNC(); diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h index 9ce253e381d..6d06ce1d567 100644 --- a/drivers/serial/bfin_sport_uart.h +++ b/drivers/serial/bfin_sport_uart.h @@ -10,7 +10,7 @@ /* * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf + * http://www.analog.com/static/imported-files/application_notes/EE191.pdf * This application note describe how to implement a UART on a Sharc DSP, * but this driver is implemented on Blackfin Processor. * Transmit Frame Sync is not used by this driver to transfer data out. diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 66ecc7ab6da..dfcf4b1878a 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -327,14 +327,13 @@ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; - while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) { + while (!uart_circ_empty(xmit) && + !(readl(sport->port.membase + UTS) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index eaf54501411..18f548449c6 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c @@ -172,13 +172,15 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device jsm_uart_port_init here! */ dev_err(&pdev->dev, "memory allocation for flipbuf failed\n"); rc = -ENOMEM; - goto out_free_irq; + goto out_free_uart; } pci_set_drvdata(pdev, brd); pci_save_state(pdev); return 0; + out_free_uart: + jsm_remove_uart_port(brd); out_free_irq: jsm_remove_uart_port(brd); free_irq(brd->irq, brd); diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index 39f9a1adaa7..d4b711c9a41 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -243,7 +243,7 @@ static struct kgdb_io kgdboc_io_ops = { #ifdef CONFIG_KGDB_SERIAL_CONSOLE /* This is only available if kgdboc is a built in for early debugging */ -int __init kgdboc_early_init(char *opt) +static int __init kgdboc_early_init(char *opt) { /* save the first character of the config string because the * init routine can destroy it. diff --git a/drivers/serial/max3107.c b/drivers/serial/max3107.c index 67283c1a57f..910870edf70 100644 --- a/drivers/serial/max3107.c +++ b/drivers/serial/max3107.c @@ -986,12 +986,14 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL); if (!s->rxbuf) { pr_err("Allocating RX buffer failed\n"); - return -ENOMEM; + retval = -ENOMEM; + goto err_free4; } s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL); if (!s->rxstr) { pr_err("Allocating RX buffer failed\n"); - return -ENOMEM; + retval = -ENOMEM; + goto err_free3; } /* SPI Tx buffer * SPI transfer buffer @@ -1002,7 +1004,8 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL); if (!s->txbuf) { pr_err("Allocating TX buffer failed\n"); - return -ENOMEM; + retval = -ENOMEM; + goto err_free2; } /* Initialize shared data lock */ spin_lock_init(&s->data_lock); @@ -1021,13 +1024,15 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) buf[0] = MAX3107_REVID_REG; if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n"); - return -EIO; + retval = -EIO; + goto err_free1; } if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 && (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) { dev_err(&s->spi->dev, "REVID %x does not match\n", (buf[0] & MAX3107_SPI_RX_DATA_MASK)); - return -ENODEV; + retval = -ENODEV; + goto err_free1; } /* Disable all interrupts */ @@ -1047,7 +1052,8 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) /* Perform SPI transfer */ if (max3107_rw(s, (u8 *)buf, NULL, 4)) { dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - return -EIO; + retval = -EIO; + goto err_free1; } /* Register UART driver */ @@ -1055,7 +1061,7 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) retval = uart_register_driver(&max3107_uart_driver); if (retval) { dev_err(&s->spi->dev, "Registering UART driver failed\n"); - return retval; + goto err_free1; } driver_registered = 1; } @@ -1074,13 +1080,13 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) retval = uart_add_one_port(&max3107_uart_driver, &s->port); if (retval < 0) { dev_err(&s->spi->dev, "Adding UART port failed\n"); - return retval; + goto err_free1; } if (pdata->configure) { retval = pdata->configure(s); if (retval < 0) - return retval; + goto err_free1; } /* Go to suspend mode */ @@ -1088,6 +1094,16 @@ int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) pdata->hw_suspend(s, 1); return 0; + +err_free1: + kfree(s->txbuf); +err_free2: + kfree(s->rxstr); +err_free3: + kfree(s->rxbuf); +err_free4: + kfree(s); + return retval; } EXPORT_SYMBOL_GPL(max3107_probe); diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c index 5dff45c76d3..5fc699e929d 100644 --- a/drivers/serial/mfd.c +++ b/drivers/serial/mfd.c @@ -172,6 +172,9 @@ static ssize_t port_show_regs(struct file *file, char __user *user_buf, len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); + if (len > HSU_REGS_BUFSIZE) + len = HSU_REGS_BUFSIZE; + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; @@ -219,6 +222,9 @@ static ssize_t dma_show_regs(struct file *file, char __user *user_buf, len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); + if (len > HSU_REGS_BUFSIZE) + len = HSU_REGS_BUFSIZE; + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; @@ -228,12 +234,14 @@ static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, .open = hsu_show_regs_open, .read = port_show_regs, + .llseek = default_llseek, }; static const struct file_operations dma_regs_ops = { .owner = THIS_MODULE, .open = hsu_show_regs_open, .read = dma_show_regs, + .llseek = default_llseek, }; static int hsu_debugfs_init(struct hsu_port *hsu) @@ -923,39 +931,52 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, cval |= UART_LCR_EPAR; /* + * The base clk is 50Mhz, and the baud rate come from: + * baud = 50M * MUL / (DIV * PS * DLAB) + * * For those basic low baud rate we can get the direct - * scalar from 2746800, like 115200 = 2746800/24, for those - * higher baud rate, we have to handle them case by case, - * but DIV reg is never touched as its default value 0x3d09 + * scalar from 2746800, like 115200 = 2746800/24. For those + * higher baud rate, we handle them case by case, mainly by + * adjusting the MUL/PS registers, and DIV register is kept + * as default value 0x3d09 to make things simple */ baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - quot = uart_get_divisor(port, baud); + quot = 1; switch (baud) { case 3500000: mul = 0x3345; ps = 0xC; - quot = 1; + break; + case 3000000: + mul = 0x2EE0; break; case 2500000: mul = 0x2710; - ps = 0x10; - quot = 1; break; - case 18432000: + case 2000000: + mul = 0x1F40; + break; + case 1843200: mul = 0x2400; - ps = 0x10; - quot = 1; break; case 1500000: - mul = 0x1D4C; - ps = 0xc; - quot = 1; + mul = 0x1770; + break; + case 1000000: + mul = 0xFA0; + break; + case 500000: + mul = 0x7D0; break; default: - ; + /* Use uart_get_divisor to get quot for other baud rates */ + quot = 0; } + if (!quot) + quot = uart_get_divisor(port, baud); + if ((up->port.uartclk / quot) < (2400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; else if ((up->port.uartclk / quot) < (230400 * 16)) diff --git a/drivers/serial/mrst_max3110.c b/drivers/serial/mrst_max3110.c index 51c15f58e01..b62857bf2fd 100644 --- a/drivers/serial/mrst_max3110.c +++ b/drivers/serial/mrst_max3110.c @@ -1,7 +1,7 @@ /* - * max3110.c - spi uart protocol driver for Maxim 3110 on Moorestown + * mrst_max3110.c - spi uart protocol driver for Maxim 3110 * - * Copyright (C) Intel 2008 Feng Tang <feng.tang@intel.com> + * Copyright (c) 2008-2010, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -32,18 +32,13 @@ #include <linux/irq.h> #include <linux/init.h> #include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/platform_device.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/kthread.h> -#include <linux/delay.h> -#include <asm/atomic.h> #include <linux/spi/spi.h> -#include <linux/spi/dw_spi.h> #include "mrst_max3110.h" @@ -56,7 +51,7 @@ struct uart_max3110 { struct uart_port port; struct spi_device *spi; - char *name; + char name[24]; wait_queue_head_t wq; struct task_struct *main_thread; @@ -67,35 +62,30 @@ struct uart_max3110 { u16 cur_conf; u8 clock; u8 parity, word_7bits; + u16 irq; unsigned long uart_flags; /* console related */ struct circ_buf con_xmit; - - /* irq related */ - u16 irq; }; /* global data structure, may need be removed */ -struct uart_max3110 *pmax; -static inline void receive_char(struct uart_max3110 *max, u8 ch); +static struct uart_max3110 *pmax; + static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len); -static int max3110_read_multi(struct uart_max3110 *max, int len, u8 *buf); -static void max3110_console_receive(struct uart_max3110 *max); +static int max3110_read_multi(struct uart_max3110 *max, u8 *buf); +static void max3110_con_receive(struct uart_max3110 *max); -int max3110_write_then_read(struct uart_max3110 *max, - const u8 *txbuf, u8 *rxbuf, unsigned len, int always_fast) +static int max3110_write_then_read(struct uart_max3110 *max, + const void *txbuf, void *rxbuf, unsigned len, int always_fast) { struct spi_device *spi = max->spi; struct spi_message message; struct spi_transfer x; int ret; - if (!txbuf || !rxbuf) - return -EINVAL; - spi_message_init(&message); memset(&x, 0, sizeof x); x.len = len; @@ -104,7 +94,7 @@ int max3110_write_then_read(struct uart_max3110 *max, spi_message_add_tail(&x, &message); if (always_fast) - x.speed_hz = 3125000; + x.speed_hz = spi->max_speed_hz; else if (max->baud) x.speed_hz = max->baud; @@ -113,58 +103,80 @@ int max3110_write_then_read(struct uart_max3110 *max, return ret; } -/* Write a u16 to the device, and return one u16 read back */ -int max3110_out(struct uart_max3110 *max, const u16 out) +/* Write a 16b word to the device */ +static int max3110_out(struct uart_max3110 *max, const u16 out) { - u16 tmp; + void *buf; + u16 *obuf, *ibuf; + u8 ch; int ret; - ret = max3110_write_then_read(max, (u8 *)&out, (u8 *)&tmp, 2, 1); - if (ret) - return ret; + buf = kzalloc(8, GFP_KERNEL | GFP_DMA); + if (!buf) + return -ENOMEM; + + obuf = buf; + ibuf = buf + 4; + *obuf = out; + ret = max3110_write_then_read(max, obuf, ibuf, 2, 1); + if (ret) { + pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n", + __func__, ret, out); + goto exit; + } /* If some valid data is read back */ - if (tmp & MAX3110_READ_DATA_AVAILABLE) - receive_char(max, (tmp & 0xff)); + if (*ibuf & MAX3110_READ_DATA_AVAILABLE) { + ch = *ibuf & 0xff; + receive_chars(max, &ch, 1); + } +exit: + kfree(buf); return ret; } -#define MAX_READ_LEN 20 /* * This is usually used to read data from SPIC RX FIFO, which doesn't - * need any delay like flushing character out. It returns how many - * valide bytes are read back + * need any delay like flushing character out. + * + * Return how many valide bytes are read back */ -static int max3110_read_multi(struct uart_max3110 *max, int len, u8 *buf) +static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf) { - u16 out[MAX_READ_LEN], in[MAX_READ_LEN]; - u8 *pbuf, valid_str[MAX_READ_LEN]; - int i, j, bytelen; + void *buf; + u16 *obuf, *ibuf; + u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH]; + int i, j, blen; - if (len > MAX_READ_LEN) { - pr_err(PR_FMT "read len %d is too large\n", len); + blen = M3110_RX_FIFO_DEPTH * sizeof(u16); + buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA); + if (!buf) { + pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__); return 0; } - bytelen = len * 2; - memset(out, 0, bytelen); - memset(in, 0, bytelen); + /* tx/rx always have the same length */ + obuf = buf; + ibuf = buf + blen; - if (max3110_write_then_read(max, (u8 *)out, (u8 *)in, bytelen, 1)) + if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) { + kfree(buf); return 0; + } - /* If caller don't provide a buffer, then handle received char */ - pbuf = buf ? buf : valid_str; + /* If caller doesn't provide a buffer, then handle received char */ + pbuf = rxbuf ? rxbuf : valid_str; - for (i = 0, j = 0; i < len; i++) { - if (in[i] & MAX3110_READ_DATA_AVAILABLE) - pbuf[j++] = (u8)(in[i] & 0xff); + for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) { + if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) + pbuf[j++] = ibuf[i] & 0xff; } if (j && (pbuf == valid_str)) receive_chars(max, valid_str, j); + kfree(buf); return j; } @@ -178,10 +190,6 @@ static void serial_m3110_con_putchar(struct uart_port *port, int ch) xmit->buf[xmit->head] = (char)ch; xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1); } - - - if (!test_and_set_bit(CON_TX_NEEDED, &max->uart_flags)) - wake_up_process(max->main_thread); } /* @@ -197,6 +205,9 @@ static void serial_m3110_con_write(struct console *co, return; uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar); + + if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags)) + wake_up_process(pmax->main_thread); } static int __init @@ -210,6 +221,9 @@ serial_m3110_con_setup(struct console *co, char *options) pr_info(PR_FMT "setting up console\n"); + if (co->index == -1) + co->index = 0; + if (!max) { pr_err(PR_FMT "pmax is NULL, return"); return -ENODEV; @@ -240,8 +254,6 @@ static struct console serial_m3110_console = { .data = &serial_m3110_reg, }; -#define MRST_CONSOLE (&serial_m3110_console) - static unsigned int serial_m3110_tx_empty(struct uart_port *port) { return 1; @@ -259,32 +271,44 @@ static void serial_m3110_stop_rx(struct uart_port *port) } #define WORDS_PER_XFER 128 -static inline void send_circ_buf(struct uart_max3110 *max, +static void send_circ_buf(struct uart_max3110 *max, struct circ_buf *xmit) { - int len, left = 0; - u16 obuf[WORDS_PER_XFER], ibuf[WORDS_PER_XFER]; + void *buf; + u16 *obuf, *ibuf; u8 valid_str[WORDS_PER_XFER]; - int i, j; + int i, j, len, blen, dma_size, left, ret = 0; + + + dma_size = WORDS_PER_XFER * sizeof(u16) * 2; + buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA); + if (!buf) + return; + obuf = buf; + ibuf = buf + dma_size/2; while (!uart_circ_empty(xmit)) { left = uart_circ_chars_pending(xmit); while (left) { - len = (left >= WORDS_PER_XFER) ? WORDS_PER_XFER : left; + len = min(left, WORDS_PER_XFER); + blen = len * sizeof(u16); + memset(ibuf, 0, blen); - memset(obuf, 0, len * 2); - memset(ibuf, 0, len * 2); for (i = 0; i < len; i++) { obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); } - max3110_write_then_read(max, (u8 *)obuf, - (u8 *)ibuf, len * 2, 0); + + /* Fail to send msg to console is not very critical */ + ret = max3110_write_then_read(max, obuf, ibuf, blen, 0); + if (ret) + pr_warning(PR_FMT "%s(): get err msg %d\n", + __func__, ret); for (i = 0, j = 0; i < len; i++) { if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) - valid_str[j++] = (u8)(ibuf[i] & 0xff); + valid_str[j++] = ibuf[i] & 0xff; } if (j) @@ -294,6 +318,8 @@ static inline void send_circ_buf(struct uart_max3110 *max, left -= len; } } + + kfree(buf); } static void transmit_char(struct uart_max3110 *max) @@ -313,8 +339,10 @@ static void transmit_char(struct uart_max3110 *max) serial_m3110_stop_tx(port); } -/* This will be called by uart_write() and tty_write, can't - * go to sleep */ +/* + * This will be called by uart_write() and tty_write, can't + * go to sleep + */ static void serial_m3110_start_tx(struct uart_port *port) { struct uart_max3110 *max = @@ -336,7 +364,7 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) tty = port->state->port.tty; if (!tty) - return; /* receive some char before the tty is opened */ + return; while (len) { usable = tty_buffer_request_room(tty, len); @@ -344,32 +372,37 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) tty_insert_flip_string(tty, str, usable); str += usable; port->icount.rx += usable; - tty_flip_buffer_push(tty); } len -= usable; } + tty_flip_buffer_push(tty); } -static inline void receive_char(struct uart_max3110 *max, u8 ch) -{ - receive_chars(max, &ch, 1); -} - -static void max3110_console_receive(struct uart_max3110 *max) +/* + * This routine will be used in read_thread or RX IRQ handling, + * it will first do one round buffer read(8 words), if there is some + * valid RX data, will try to read 5 more rounds till all data + * is read out. + * + * Use stack space as data buffer to save some system load, and chose + * 504 Btyes as a threadhold to do a bulk push to upper tty layer when + * receiving bulk data, a much bigger buffer may cause stack overflow + */ +static void max3110_con_receive(struct uart_max3110 *max) { int loop = 1, num, total = 0; u8 recv_buf[512], *pbuf; pbuf = recv_buf; do { - num = max3110_read_multi(max, 8, pbuf); + num = max3110_read_multi(max, pbuf); if (num) { - loop = 10; + loop = 5; pbuf += num; total += num; - if (total >= 500) { + if (total >= 504) { receive_chars(max, recv_buf, total); pbuf = recv_buf; total = 0; @@ -397,7 +430,7 @@ static int max3110_main_thread(void *_max) mutex_lock(&max->thread_mutex); if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags)) - max3110_console_receive(max); + max3110_con_receive(max); /* first handle console output */ if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags)) @@ -414,7 +447,6 @@ static int max3110_main_thread(void *_max) return ret; } -#ifdef CONFIG_MRST_MAX3110_IRQ static irqreturn_t serial_m3110_irq(int irq, void *dev_id) { struct uart_max3110 *max = dev_id; @@ -426,7 +458,7 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id) return IRQ_HANDLED; } -#else + /* if don't use RX IRQ, then need a thread to polling read */ static int max3110_read_thread(void *_max) { @@ -434,9 +466,14 @@ static int max3110_read_thread(void *_max) pr_info(PR_FMT "start read thread\n"); do { - mutex_lock(&max->thread_mutex); - max3110_console_receive(max); - mutex_unlock(&max->thread_mutex); + /* + * If can't acquire the mutex, it means the main thread + * is running which will also perform the rx job + */ + if (mutex_trylock(&max->thread_mutex)) { + max3110_con_receive(max); + mutex_unlock(&max->thread_mutex); + } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 20); @@ -444,7 +481,6 @@ static int max3110_read_thread(void *_max) return 0; } -#endif static int serial_m3110_startup(struct uart_port *port) { @@ -453,33 +489,54 @@ static int serial_m3110_startup(struct uart_port *port) u16 config = 0; int ret = 0; - if (port->line != 0) + if (port->line != 0) { pr_err(PR_FMT "uart port startup failed\n"); + return -1; + } - /* firstly disable all IRQ and config it to 115200, 8n1 */ + /* Disable all IRQ and config it to 115200, 8n1 */ config = WC_TAG | WC_FIFO_ENABLE | WC_1_STOPBITS | WC_8BIT_WORD | WC_BAUD_DR2; - ret = max3110_out(max, config); /* as we use thread to handle tx/rx, need set low latency */ port->state->port.tty->low_latency = 1; -#ifdef CONFIG_MRST_MAX3110_IRQ - ret = request_irq(max->irq, serial_m3110_irq, + if (max->irq) { + max->read_thread = NULL; + ret = request_irq(max->irq, serial_m3110_irq, IRQ_TYPE_EDGE_FALLING, "max3110", max); - if (ret) - return ret; + if (ret) { + max->irq = 0; + pr_err(PR_FMT "unable to allocate IRQ, polling\n"); + } else { + /* Enable RX IRQ only */ + config |= WC_RXA_IRQ_ENABLE; + } + } - /* enable RX IRQ only */ - config |= WC_RXA_IRQ_ENABLE; - max3110_out(max, config); -#else - /* if IRQ is disabled, start a read thread for input data */ - max->read_thread = - kthread_run(max3110_read_thread, max, "max3110_read"); -#endif + if (max->irq == 0) { + /* If IRQ is disabled, start a read thread for input data */ + max->read_thread = + kthread_run(max3110_read_thread, max, "max3110_read"); + if (IS_ERR(max->read_thread)) { + ret = PTR_ERR(max->read_thread); + max->read_thread = NULL; + pr_err(PR_FMT "Can't create read thread!\n"); + return ret; + } + } + + ret = max3110_out(max, config); + if (ret) { + if (max->irq) + free_irq(max->irq, max); + if (max->read_thread) + kthread_stop(max->read_thread); + max->read_thread = NULL; + return ret; + } max->cur_conf = config; return 0; @@ -496,9 +553,8 @@ static void serial_m3110_shutdown(struct uart_port *port) max->read_thread = NULL; } -#ifdef CONFIG_MRST_MAX3110_IRQ - free_irq(max->irq, max); -#endif + if (max->irq) + free_irq(max->irq, max); /* Disable interrupts from this port */ config = WC_TAG | WC_SW_SHDI; @@ -516,8 +572,7 @@ static int serial_m3110_request_port(struct uart_port *port) static void serial_m3110_config_port(struct uart_port *port, int flags) { - /* give it fake type */ - port->type = PORT_PXA; + port->type = PORT_MAX3100; } static int @@ -552,6 +607,9 @@ serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, new_conf |= WC_7BIT_WORD; break; default: + /* We only support CS7 & CS8 */ + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; case CS8: cval = UART_LCR_WLEN8; new_conf |= WC_8BIT_WORD; @@ -560,7 +618,7 @@ serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, 230400); - /* first calc the div for 1.8MHZ clock case */ + /* First calc the div for 1.8MHZ clock case */ switch (baud) { case 300: clk_div = WC_BAUD_DR384; @@ -596,7 +654,7 @@ serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, if (max->clock & MAX3110_HIGH_CLK) break; default: - /* pick the previous baud rate */ + /* Pick the previous baud rate */ baud = max->baud; clk_div = max->cur_conf & WC_BAUD_DIV_MASK; tty_termios_encode_baud_rate(termios, baud, baud); @@ -604,15 +662,21 @@ serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, if (max->clock & MAX3110_HIGH_CLK) { clk_div += 1; - /* high clk version max3110 doesn't support B300 */ - if (baud == 300) + /* High clk version max3110 doesn't support B300 */ + if (baud == 300) { baud = 600; + clk_div = WC_BAUD_DR384; + } if (baud == 230400) clk_div = WC_BAUD_DR1; tty_termios_encode_baud_rate(termios, baud, baud); } new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div; + + if (unlikely(termios->c_cflag & CMSPAR)) + termios->c_cflag &= ~CMSPAR; + if (termios->c_cflag & CSTOPB) new_conf |= WC_2_STOPBITS; else @@ -632,13 +696,14 @@ serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, new_conf |= WC_TAG; if (new_conf != max->cur_conf) { - max3110_out(max, new_conf); - max->cur_conf = new_conf; - max->baud = baud; + if (!max3110_out(max, new_conf)) { + max->cur_conf = new_conf; + max->baud = baud; + } } } -/* don't handle hw handshaking */ +/* Don't handle hw handshaking */ static unsigned int serial_m3110_get_mctrl(struct uart_port *port) { return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR; @@ -672,7 +737,7 @@ struct uart_ops serial_m3110_ops = { .break_ctl = serial_m3110_break_ctl, .startup = serial_m3110_startup, .shutdown = serial_m3110_shutdown, - .set_termios = serial_m3110_set_termios, /* must have */ + .set_termios = serial_m3110_set_termios, .pm = serial_m3110_pm, .type = serial_m3110_type, .release_port = serial_m3110_release_port, @@ -688,52 +753,60 @@ static struct uart_driver serial_m3110_reg = { .major = TTY_MAJOR, .minor = 64, .nr = 1, - .cons = MRST_CONSOLE, + .cons = &serial_m3110_console, }; +#ifdef CONFIG_PM static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state) { + struct uart_max3110 *max = spi_get_drvdata(spi); + + disable_irq(max->irq); + uart_suspend_port(&serial_m3110_reg, &max->port); + max3110_out(max, max->cur_conf | WC_SW_SHDI); return 0; } static int serial_m3110_resume(struct spi_device *spi) { + struct uart_max3110 *max = spi_get_drvdata(spi); + + max3110_out(max, max->cur_conf); + uart_resume_port(&serial_m3110_reg, &max->port); + enable_irq(max->irq); return 0; } +#else +#define serial_m3110_suspend NULL +#define serial_m3110_resume NULL +#endif -static struct dw_spi_chip spi0_uart = { - .poll_mode = 1, - .enable_dma = 0, - .type = SPI_FRF_SPI, -}; - -static int serial_m3110_probe(struct spi_device *spi) +static int __devinit serial_m3110_probe(struct spi_device *spi) { struct uart_max3110 *max; - int ret; - unsigned char *buffer; + void *buffer; u16 res; + int ret = 0; + max = kzalloc(sizeof(*max), GFP_KERNEL); if (!max) return -ENOMEM; - /* set spi info */ - spi->mode = SPI_MODE_0; + /* Set spi info */ spi->bits_per_word = 16; max->clock = MAX3110_HIGH_CLK; - spi->controller_data = &spi0_uart; spi_setup(spi); - max->port.type = PORT_PXA; /* need apply for a max3110 type */ - max->port.fifosize = 2; /* only have 16b buffer */ + max->port.type = PORT_MAX3100; + max->port.fifosize = 2; /* Only have 16b buffer */ max->port.ops = &serial_m3110_ops; max->port.line = 0; max->port.dev = &spi->dev; max->port.uartclk = 115200; max->spi = spi; - max->name = spi->modalias; /* use spi name as the name */ + strcpy(max->name, spi->modalias); max->irq = (u16)spi->irq; mutex_init(&max->thread_mutex); @@ -755,13 +828,15 @@ static int serial_m3110_probe(struct spi_device *spi) ret = -ENODEV; goto err_get_page; } - buffer = (unsigned char *)__get_free_page(GFP_KERNEL); + + buffer = (void *)__get_free_page(GFP_KERNEL); if (!buffer) { ret = -ENOMEM; goto err_get_page; } - max->con_xmit.buf = (unsigned char *)buffer; - max->con_xmit.head = max->con_xmit.tail = 0; + max->con_xmit.buf = buffer; + max->con_xmit.head = 0; + max->con_xmit.tail = 0; max->main_thread = kthread_run(max3110_main_thread, max, "max3110_main"); @@ -770,8 +845,10 @@ static int serial_m3110_probe(struct spi_device *spi) goto err_kthread; } + spi_set_drvdata(spi, max); pmax = max; - /* give membase a psudo value to pass serial_core's check */ + + /* Give membase a psudo value to pass serial_core's check */ max->port.membase = (void *)0xff110000; uart_add_one_port(&serial_m3110_reg, &max->port); @@ -780,19 +857,17 @@ static int serial_m3110_probe(struct spi_device *spi) err_kthread: free_page((unsigned long)buffer); err_get_page: - pmax = NULL; kfree(max); return ret; } -static int max3110_remove(struct spi_device *dev) +static int __devexit serial_m3110_remove(struct spi_device *dev) { - struct uart_max3110 *max = pmax; + struct uart_max3110 *max = spi_get_drvdata(dev); - if (!pmax) + if (!max) return 0; - pmax = NULL; uart_remove_one_port(&serial_m3110_reg, &max->port); free_page((unsigned long)max->con_xmit.buf); @@ -811,13 +886,12 @@ static struct spi_driver uart_max3110_driver = { .owner = THIS_MODULE, }, .probe = serial_m3110_probe, - .remove = __devexit_p(max3110_remove), + .remove = __devexit_p(serial_m3110_remove), .suspend = serial_m3110_suspend, .resume = serial_m3110_resume, }; - -int __init serial_m3110_init(void) +static int __init serial_m3110_init(void) { int ret = 0; @@ -832,7 +906,7 @@ int __init serial_m3110_init(void) return ret; } -void __exit serial_m3110_exit(void) +static void __exit serial_m3110_exit(void) { spi_unregister_driver(&uart_max3110_driver); uart_unregister_driver(&serial_m3110_reg); @@ -841,5 +915,5 @@ void __exit serial_m3110_exit(void) module_init(serial_m3110_init); module_exit(serial_m3110_exit); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("max3110-uart"); diff --git a/drivers/serial/mrst_max3110.h b/drivers/serial/mrst_max3110.h index 363478acb2c..d1ef43af397 100644 --- a/drivers/serial/mrst_max3110.h +++ b/drivers/serial/mrst_max3110.h @@ -56,4 +56,5 @@ #define WC_BAUD_DR192 (0xE) #define WC_BAUD_DR384 (0xF) +#define M3110_RX_FIFO_DEPTH 8 #endif diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 2af8fd11312..17849dcb9ad 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -31,8 +31,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, { struct resource resource; struct device_node *np = ofdev->dev.of_node; - const unsigned int *clk, *spd; - const u32 *prop; + const __be32 *clk, *spd; + const __be32 *prop; int ret, prop_size; memset(port, 0, sizeof *port); @@ -55,23 +55,23 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, /* Check for shifted address mapping */ prop = of_get_property(np, "reg-offset", &prop_size); if (prop && (prop_size == sizeof(u32))) - port->mapbase += *prop; + port->mapbase += be32_to_cpup(prop); /* Check for registers offset within the devices address range */ prop = of_get_property(np, "reg-shift", &prop_size); if (prop && (prop_size == sizeof(u32))) - port->regshift = *prop; + port->regshift = be32_to_cpup(prop); port->irq = irq_of_parse_and_map(np, 0); port->iotype = UPIO_MEM; port->type = type; - port->uartclk = *clk; + port->uartclk = be32_to_cpup(clk); port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; /* If current-speed was set, then try not to change it. */ if (spd) - port->custom_divisor = *clk / (16 * (*spd)); + port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd))); return 0; } diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c new file mode 100644 index 00000000000..14365f72b66 --- /dev/null +++ b/drivers/serial/omap-serial.c @@ -0,0 +1,1333 @@ +/* + * Driver for OMAP-UART controller. + * Based on drivers/serial/8250.c + * + * Copyright (C) 2010 Texas Instruments. + * + * Authors: + * Govindraj R <govindraj.raja@ti.com> + * Thara Gopinath <thara@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Note: This driver is made seperate from 8250 driver as we cannot + * over load 8250 driver with omap platform specific configuration for + * features like DMA, it makes easier to implement features like DMA and + * hardware flow control and software flow control configuration with + * this driver as required for the omap-platform. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/serial_reg.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/clk.h> +#include <linux/serial_core.h> +#include <linux/irq.h> + +#include <plat/dma.h> +#include <plat/dmtimer.h> +#include <plat/omap-serial.h> + +static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; + +/* Forward declaration of functions */ +static void uart_tx_dma_callback(int lch, u16 ch_status, void *data); +static void serial_omap_rx_timeout(unsigned long uart_no); +static int serial_omap_start_rxdma(struct uart_omap_port *up); + +static inline unsigned int serial_in(struct uart_omap_port *up, int offset) +{ + offset <<= up->port.regshift; + return readw(up->port.membase + offset); +} + +static inline void serial_out(struct uart_omap_port *up, int offset, int value) +{ + offset <<= up->port.regshift; + writew(value, up->port.membase + offset); +} + +static inline void serial_omap_clear_fifos(struct uart_omap_port *up) +{ + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); +} + +/* + * serial_omap_get_divisor - calculate divisor value + * @port: uart port info + * @baud: baudrate for which divisor needs to be calculated. + * + * We have written our own function to get the divisor so as to support + * 13x mode. 3Mbps Baudrate as an different divisor. + * Reference OMAP TRM Chapter 17: + * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates + * referring to oversampling - divisor value + * baudrate 460,800 to 3,686,400 all have divisor 13 + * except 3,000,000 which has divisor value 16 + */ +static unsigned int +serial_omap_get_divisor(struct uart_port *port, unsigned int baud) +{ + unsigned int divisor; + + if (baud > OMAP_MODE13X_SPEED && baud != 3000000) + divisor = 13; + else + divisor = 16; + return port->uartclk/(baud * divisor); +} + +static void serial_omap_stop_rxdma(struct uart_omap_port *up) +{ + if (up->uart_dma.rx_dma_used) { + del_timer(&up->uart_dma.rx_timer); + omap_stop_dma(up->uart_dma.rx_dma_channel); + omap_free_dma(up->uart_dma.rx_dma_channel); + up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; + up->uart_dma.rx_dma_used = false; + } +} + +static void serial_omap_enable_ms(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id); + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +static void serial_omap_stop_tx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + if (up->use_dma && + up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { + /* + * Check if dma is still active. If yes do nothing, + * return. Else stop dma + */ + if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel)) + return; + omap_stop_dma(up->uart_dma.tx_dma_channel); + omap_free_dma(up->uart_dma.tx_dma_channel); + up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; + } + + if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_omap_stop_rx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + if (up->use_dma) + serial_omap_stop_rxdma(up); + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +} + +static inline void receive_chars(struct uart_omap_port *up, int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned int flag; + unsigned char ch, lsr = *status; + int max_count = 256; + + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + /* + * For statistics only + */ + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) { + up->port.icount.parity++; + } else if (lsr & UART_LSR_FE) { + up->port.icount.frame++; + } + + if (lsr & UART_LSR_OE) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + lsr &= up->port.read_status_mask; + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + lsr |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } +#endif + if (lsr & UART_LSR_BI) + flag = TTY_BREAK; + else if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); +ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); + spin_unlock(&up->port.lock); + tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); +} + +static void transmit_chars(struct uart_omap_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + serial_out(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + serial_omap_stop_tx(&up->port); + return; + } + count = up->port.fifosize / 4; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + serial_omap_stop_tx(&up->port); +} + +static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) +{ + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_omap_start_tx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + struct circ_buf *xmit; + unsigned int start; + int ret = 0; + + if (!up->use_dma) { + serial_omap_enable_ier_thri(up); + return; + } + + if (up->uart_dma.tx_dma_used) + return; + + xmit = &up->port.state->xmit; + + if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { + ret = omap_request_dma(up->uart_dma.uart_dma_tx, + "UART Tx DMA", + (void *)uart_tx_dma_callback, up, + &(up->uart_dma.tx_dma_channel)); + + if (ret < 0) { + serial_omap_enable_ier_thri(up); + return; + } + } + spin_lock(&(up->uart_dma.tx_lock)); + up->uart_dma.tx_dma_used = true; + spin_unlock(&(up->uart_dma.tx_lock)); + + start = up->uart_dma.tx_buf_dma_phys + + (xmit->tail & (UART_XMIT_SIZE - 1)); + + up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); + /* + * It is a circular buffer. See if the buffer has wounded back. + * If yes it will have to be transferred in two separate dma + * transfers + */ + if (start + up->uart_dma.tx_buf_size >= + up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) + up->uart_dma.tx_buf_size = + (up->uart_dma.tx_buf_dma_phys + + UART_XMIT_SIZE) - start; + + omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, + OMAP_DMA_AMODE_CONSTANT, + up->uart_dma.uart_base, 0, 0); + omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, + OMAP_DMA_AMODE_POST_INC, start, 0, 0); + omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, + OMAP_DMA_DATA_TYPE_S8, + up->uart_dma.tx_buf_size, 1, + OMAP_DMA_SYNC_ELEMENT, + up->uart_dma.uart_dma_tx, 0); + /* FIXME: Cache maintenance needed here? */ + omap_start_dma(up->uart_dma.tx_dma_channel); +} + +static unsigned int check_modem_status(struct uart_omap_port *up) +{ + unsigned int status; + + status = serial_in(up, UART_MSR); + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if ((status & UART_MSR_ANY_DELTA) == 0) + return status; + + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + up->port.state != NULL) { + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change + (&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change + (&up->port, status & UART_MSR_CTS); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + } + + return status; +} + +/** + * serial_omap_irq() - This handles the interrupt from one port + * @irq: uart port irq number + * @dev_id: uart port info + */ +static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) +{ + struct uart_omap_port *up = dev_id; + unsigned int iir, lsr; + unsigned long flags; + + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; + + spin_lock_irqsave(&up->port.lock, flags); + lsr = serial_in(up, UART_LSR); + if (iir & UART_IIR_RLSI) { + if (!up->use_dma) { + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); + } else { + up->ier &= ~(UART_IER_RDI | UART_IER_RLSI); + serial_out(up, UART_IER, up->ier); + if ((serial_omap_start_rxdma(up) != 0) && + (lsr & UART_LSR_DR)) + receive_chars(up, &lsr); + } + } + + check_modem_status(up); + if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) + transmit_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + up->port_activity = jiffies; + return IRQ_HANDLED; +} + +static unsigned int serial_omap_tx_empty(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + unsigned int ret = 0; + + dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id); + spin_lock_irqsave(&up->port.lock, flags); + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; + spin_unlock_irqrestore(&up->port.lock, flags); + + return ret; +} + +static unsigned int serial_omap_get_mctrl(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char status; + unsigned int ret = 0; + + status = check_modem_status(up); + dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id); + + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char mcr = 0; + + dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id); + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr |= up->mcr; + serial_out(up, UART_MCR, mcr); +} + +static void serial_omap_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + + dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id); + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static int serial_omap_startup(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, + up->name, up); + if (retval) + return retval; + + dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial_omap_clear_fifos(up); + /* For Hardware flow control */ + serial_out(up, UART_MCR, UART_MCR_RTS); + + /* + * Clear the interrupt registers. + */ + (void) serial_in(up, UART_LSR); + if (serial_in(up, UART_LSR) & UART_LSR_DR) + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + spin_lock_irqsave(&up->port.lock, flags); + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + up->port.mctrl |= TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + up->msr_saved_flags = 0; + if (up->use_dma) { + free_page((unsigned long)up->port.state->xmit.buf); + up->port.state->xmit.buf = dma_alloc_coherent(NULL, + UART_XMIT_SIZE, + (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), + 0); + init_timer(&(up->uart_dma.rx_timer)); + up->uart_dma.rx_timer.function = serial_omap_rx_timeout; + up->uart_dma.rx_timer.data = up->pdev->id; + /* Currently the buffer size is 4KB. Can increase it */ + up->uart_dma.rx_buf = dma_alloc_coherent(NULL, + up->uart_dma.rx_buf_size, + (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0); + } + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + + up->port_activity = jiffies; + return 0; +} + +static void serial_omap_shutdown(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + + dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_out(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_omap_clear_fifos(up); + + /* + * Read data port to reset things, and then free the irq + */ + if (serial_in(up, UART_LSR) & UART_LSR_DR) + (void) serial_in(up, UART_RX); + if (up->use_dma) { + dma_free_coherent(up->port.dev, + UART_XMIT_SIZE, up->port.state->xmit.buf, + up->uart_dma.tx_buf_dma_phys); + up->port.state->xmit.buf = NULL; + serial_omap_stop_rx(port); + dma_free_coherent(up->port.dev, + up->uart_dma.rx_buf_size, up->uart_dma.rx_buf, + up->uart_dma.rx_buf_dma_phys); + up->uart_dma.rx_buf = NULL; + } + free_irq(up->port.irq, up); +} + +static inline void +serial_omap_configure_xonxoff + (struct uart_omap_port *up, struct ktermios *termios) +{ + unsigned char efr = 0; + + up->lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB); + + serial_out(up, UART_XON1, termios->c_cc[VSTART]); + serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); + + /* clear SW control mode bits */ + efr = up->efr; + efr &= OMAP_UART_SW_CLR; + + /* + * IXON Flag: + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 + */ + if (termios->c_iflag & IXON) + efr |= OMAP_UART_SW_TX; + + /* + * IXOFF Flag: + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. + */ + if (termios->c_iflag & IXOFF) + efr |= OMAP_UART_SW_RX; + + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, UART_LCR_DLAB); + + up->mcr = serial_in(up, UART_MCR); + + /* + * IXANY Flag: + * Enable any character to restart output. + * Operation resumes after receiving any + * character after recognition of the XOFF character + */ + if (termios->c_iflag & IXANY) + up->mcr |= UART_MCR_XONANY; + + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); + /* Enable special char function UARTi.EFR_REG[5] and + * load the new software flow control mode IXON or IXOFF + * and restore the UARTi.EFR_REG[4] ENHANCED_EN value. + */ + serial_out(up, UART_EFR, efr | UART_EFR_SCD); + serial_out(up, UART_LCR, UART_LCR_DLAB); + + serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); + serial_out(up, UART_LCR, up->lcr); +} + +static void +serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char cval = 0; + unsigned char efr = 0; + unsigned long flags = 0; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Ask the core to calculate the divisor for us. + */ + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); + quot = serial_omap_get_divisor(port, baud); + + up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | + UART_FCR_ENABLE_FIFO; + if (up->use_dma) + up->fcr |= UART_FCR_DMA_SELECT; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * Modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); + serial_out(up, UART_LCR, cval); /* reset DLAB */ + + /* FIFOs and DMA Settings */ + + /* FCR can be changed only when the + * baud clock is not running + * DLL_REG and DLH_REG set to 0. + */ + serial_out(up, UART_LCR, UART_LCR_DLAB); + serial_out(up, UART_DLL, 0); + serial_out(up, UART_DLM, 0); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_LCR, UART_LCR_DLAB); + up->mcr = serial_in(up, UART_MCR); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + /* FIFO ENABLE, DMA MODE */ + serial_out(up, UART_FCR, up->fcr); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + + if (up->use_dma) { + serial_out(up, UART_TI752_TLR, 0); + serial_out(up, UART_OMAP_SCR, + (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8)); + } + + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, UART_LCR_DLAB); + serial_out(up, UART_MCR, up->mcr); + + /* Protocol, Baud Rate, and Interrupt Settings */ + + serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_LCR, 0); + serial_out(up, UART_IER, 0); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + + serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ + + serial_out(up, UART_LCR, 0); + serial_out(up, UART_IER, up->ier); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, cval); + + if (baud > 230400 && baud != 3000000) + serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X); + else + serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X); + + /* Hardware Flow Control Configuration */ + + if (termios->c_cflag & CRTSCTS) { + efr |= (UART_EFR_CTS | UART_EFR_RTS); + serial_out(up, UART_LCR, UART_LCR_DLAB); + + up->mcr = serial_in(up, UART_MCR); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); + serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ + serial_out(up, UART_LCR, UART_LCR_DLAB); + serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); + serial_out(up, UART_LCR, cval); + } + + serial_omap_set_mctrl(&up->port, up->port.mctrl); + /* Software Flow Control Configuration */ + if (termios->c_iflag & (IXON | IXOFF)) + serial_omap_configure_xonxoff(up, termios); + + spin_unlock_irqrestore(&up->port.lock, flags); + dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id); +} + +static void +serial_omap_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char efr; + + dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, efr | UART_EFR_ECB); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); + serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB); + serial_out(up, UART_EFR, efr); + serial_out(up, UART_LCR, 0); + /* Enable module level wake up */ + serial_out(up, UART_OMAP_WER, + (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0); +} + +static void serial_omap_release_port(struct uart_port *port) +{ + dev_dbg(port->dev, "serial_omap_release_port+\n"); +} + +static int serial_omap_request_port(struct uart_port *port) +{ + dev_dbg(port->dev, "serial_omap_request_port+\n"); + return 0; +} + +static void serial_omap_config_port(struct uart_port *port, int flags) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", + up->pdev->id); + up->port.type = PORT_OMAP; +} + +static int +serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + dev_dbg(port->dev, "serial_omap_verify_port+\n"); + return -EINVAL; +} + +static const char * +serial_omap_type(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id); + return up->name; +} + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + +static struct uart_omap_port *serial_omap_console_ports[4]; + +static struct uart_driver serial_omap_reg; + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static inline void wait_for_xmitr(struct uart_omap_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + + udelay(1); + } + } +} + +static void serial_omap_console_putchar(struct uart_port *port, int ch) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +static void +serial_omap_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_omap_port *up = serial_omap_console_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + + uart_console_write(&up->port, s, count, serial_omap_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + check_modem_status(up); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init +serial_omap_console_setup(struct console *co, char *options) +{ + struct uart_omap_port *up; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (serial_omap_console_ports[co->index] == NULL) + return -ENODEV; + up = serial_omap_console_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static struct console serial_omap_console = { + .name = OMAP_SERIAL_NAME, + .write = serial_omap_console_write, + .device = uart_console_device, + .setup = serial_omap_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial_omap_reg, +}; + +static void serial_omap_add_console_port(struct uart_omap_port *up) +{ + serial_omap_console_ports[up->pdev->id] = up; +} + +#define OMAP_CONSOLE (&serial_omap_console) + +#else + +#define OMAP_CONSOLE NULL + +static inline void serial_omap_add_console_port(struct uart_omap_port *up) +{} + +#endif + +static struct uart_ops serial_omap_pops = { + .tx_empty = serial_omap_tx_empty, + .set_mctrl = serial_omap_set_mctrl, + .get_mctrl = serial_omap_get_mctrl, + .stop_tx = serial_omap_stop_tx, + .start_tx = serial_omap_start_tx, + .stop_rx = serial_omap_stop_rx, + .enable_ms = serial_omap_enable_ms, + .break_ctl = serial_omap_break_ctl, + .startup = serial_omap_startup, + .shutdown = serial_omap_shutdown, + .set_termios = serial_omap_set_termios, + .pm = serial_omap_pm, + .type = serial_omap_type, + .release_port = serial_omap_release_port, + .request_port = serial_omap_request_port, + .config_port = serial_omap_config_port, + .verify_port = serial_omap_verify_port, +}; + +static struct uart_driver serial_omap_reg = { + .owner = THIS_MODULE, + .driver_name = "OMAP-SERIAL", + .dev_name = OMAP_SERIAL_NAME, + .nr = OMAP_MAX_HSUART_PORTS, + .cons = OMAP_CONSOLE, +}; + +static int +serial_omap_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct uart_omap_port *up = platform_get_drvdata(pdev); + + if (up) + uart_suspend_port(&serial_omap_reg, &up->port); + return 0; +} + +static int serial_omap_resume(struct platform_device *dev) +{ + struct uart_omap_port *up = platform_get_drvdata(dev); + + if (up) + uart_resume_port(&serial_omap_reg, &up->port); + return 0; +} + +static void serial_omap_rx_timeout(unsigned long uart_no) +{ + struct uart_omap_port *up = ui[uart_no]; + unsigned int curr_dma_pos, curr_transmitted_size; + int ret = 0; + + curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel); + if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || + (curr_dma_pos == 0)) { + if (jiffies_to_msecs(jiffies - up->port_activity) < + RX_TIMEOUT) { + mod_timer(&up->uart_dma.rx_timer, jiffies + + usecs_to_jiffies(up->uart_dma.rx_timeout)); + } else { + serial_omap_stop_rxdma(up); + up->ier |= (UART_IER_RDI | UART_IER_RLSI); + serial_out(up, UART_IER, up->ier); + } + return; + } + + curr_transmitted_size = curr_dma_pos - + up->uart_dma.prev_rx_dma_pos; + up->port.icount.rx += curr_transmitted_size; + tty_insert_flip_string(up->port.state->port.tty, + up->uart_dma.rx_buf + + (up->uart_dma.prev_rx_dma_pos - + up->uart_dma.rx_buf_dma_phys), + curr_transmitted_size); + tty_flip_buffer_push(up->port.state->port.tty); + up->uart_dma.prev_rx_dma_pos = curr_dma_pos; + if (up->uart_dma.rx_buf_size + + up->uart_dma.rx_buf_dma_phys == curr_dma_pos) { + ret = serial_omap_start_rxdma(up); + if (ret < 0) { + serial_omap_stop_rxdma(up); + up->ier |= (UART_IER_RDI | UART_IER_RLSI); + serial_out(up, UART_IER, up->ier); + } + } else { + mod_timer(&up->uart_dma.rx_timer, jiffies + + usecs_to_jiffies(up->uart_dma.rx_timeout)); + } + up->port_activity = jiffies; +} + +static void uart_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + return; +} + +static int serial_omap_start_rxdma(struct uart_omap_port *up) +{ + int ret = 0; + + if (up->uart_dma.rx_dma_channel == -1) { + ret = omap_request_dma(up->uart_dma.uart_dma_rx, + "UART Rx DMA", + (void *)uart_rx_dma_callback, up, + &(up->uart_dma.rx_dma_channel)); + if (ret < 0) + return ret; + + omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0, + OMAP_DMA_AMODE_CONSTANT, + up->uart_dma.uart_base, 0, 0); + omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0, + OMAP_DMA_AMODE_POST_INC, + up->uart_dma.rx_buf_dma_phys, 0, 0); + omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel, + OMAP_DMA_DATA_TYPE_S8, + up->uart_dma.rx_buf_size, 1, + OMAP_DMA_SYNC_ELEMENT, + up->uart_dma.uart_dma_rx, 0); + } + up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys; + /* FIXME: Cache maintenance needed here? */ + omap_start_dma(up->uart_dma.rx_dma_channel); + mod_timer(&up->uart_dma.rx_timer, jiffies + + usecs_to_jiffies(up->uart_dma.rx_timeout)); + up->uart_dma.rx_dma_used = true; + return ret; +} + +static void serial_omap_continue_tx(struct uart_omap_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + unsigned int start = up->uart_dma.tx_buf_dma_phys + + (xmit->tail & (UART_XMIT_SIZE - 1)); + + if (uart_circ_empty(xmit)) + return; + + up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); + /* + * It is a circular buffer. See if the buffer has wounded back. + * If yes it will have to be transferred in two separate dma + * transfers + */ + if (start + up->uart_dma.tx_buf_size >= + up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) + up->uart_dma.tx_buf_size = + (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start; + omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, + OMAP_DMA_AMODE_CONSTANT, + up->uart_dma.uart_base, 0, 0); + omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, + OMAP_DMA_AMODE_POST_INC, start, 0, 0); + omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, + OMAP_DMA_DATA_TYPE_S8, + up->uart_dma.tx_buf_size, 1, + OMAP_DMA_SYNC_ELEMENT, + up->uart_dma.uart_dma_tx, 0); + /* FIXME: Cache maintenance needed here? */ + omap_start_dma(up->uart_dma.tx_dma_channel); +} + +static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct uart_omap_port *up = (struct uart_omap_port *)data; + struct circ_buf *xmit = &up->port.state->xmit; + + xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \ + (UART_XMIT_SIZE - 1); + up->port.icount.tx += up->uart_dma.tx_buf_size; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) { + spin_lock(&(up->uart_dma.tx_lock)); + serial_omap_stop_tx(&up->port); + up->uart_dma.tx_dma_used = false; + spin_unlock(&(up->uart_dma.tx_lock)); + } else { + omap_stop_dma(up->uart_dma.tx_dma_channel); + serial_omap_continue_tx(up); + } + up->port_activity = jiffies; + return; +} + +static int serial_omap_probe(struct platform_device *pdev) +{ + struct uart_omap_port *up; + struct resource *mem, *irq, *dma_tx, *dma_rx; + struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; + int ret = -ENOSPC; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } + + if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, + pdev->dev.driver->name)) { + dev_err(&pdev->dev, "memory region already claimed\n"); + return -EBUSY; + } + + dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); + if (!dma_rx) { + ret = -EINVAL; + goto err; + } + + dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); + if (!dma_tx) { + ret = -EINVAL; + goto err; + } + + up = kzalloc(sizeof(*up), GFP_KERNEL); + if (up == NULL) { + ret = -ENOMEM; + goto do_release_region; + } + sprintf(up->name, "OMAP UART%d", pdev->id); + up->pdev = pdev; + up->port.dev = &pdev->dev; + up->port.type = PORT_OMAP; + up->port.iotype = UPIO_MEM; + up->port.irq = irq->start; + + up->port.regshift = 2; + up->port.fifosize = 64; + up->port.ops = &serial_omap_pops; + up->port.line = pdev->id; + + up->port.membase = omap_up_info->membase; + up->port.mapbase = omap_up_info->mapbase; + up->port.flags = omap_up_info->flags; + up->port.irqflags = omap_up_info->irqflags; + up->port.uartclk = omap_up_info->uartclk; + up->uart_dma.uart_base = mem->start; + + if (omap_up_info->dma_enabled) { + up->uart_dma.uart_dma_tx = dma_tx->start; + up->uart_dma.uart_dma_rx = dma_rx->start; + up->use_dma = 1; + up->uart_dma.rx_buf_size = 4096; + up->uart_dma.rx_timeout = 2; + spin_lock_init(&(up->uart_dma.tx_lock)); + spin_lock_init(&(up->uart_dma.rx_lock)); + up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; + up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; + } + + ui[pdev->id] = up; + serial_omap_add_console_port(up); + + ret = uart_add_one_port(&serial_omap_reg, &up->port); + if (ret != 0) + goto do_release_region; + + platform_set_drvdata(pdev, up); + return 0; +err: + dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", + pdev->id, __func__, ret); +do_release_region: + release_mem_region(mem->start, (mem->end - mem->start) + 1); + return ret; +} + +static int serial_omap_remove(struct platform_device *dev) +{ + struct uart_omap_port *up = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + if (up) { + uart_remove_one_port(&serial_omap_reg, &up->port); + kfree(up); + } + return 0; +} + +static struct platform_driver serial_omap_driver = { + .probe = serial_omap_probe, + .remove = serial_omap_remove, + + .suspend = serial_omap_suspend, + .resume = serial_omap_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init serial_omap_init(void) +{ + int ret; + + ret = uart_register_driver(&serial_omap_reg); + if (ret != 0) + return ret; + ret = platform_driver_register(&serial_omap_driver); + if (ret != 0) + uart_unregister_driver(&serial_omap_reg); + return ret; +} + +static void __exit serial_omap_exit(void) +{ + platform_driver_unregister(&serial_omap_driver); + uart_unregister_driver(&serial_omap_reg); +} + +module_init(serial_omap_init); +module_exit(serial_omap_exit); + +MODULE_DESCRIPTION("OMAP High Speed UART driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index cd8511298bc..c4ea14670d4 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1074,10 +1074,10 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ -static int uart_get_count(struct uart_state *state, - struct serial_icounter_struct __user *icnt) +static int uart_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) { - struct serial_icounter_struct icount; + struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport = state->uart_port; @@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state, memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); spin_unlock_irq(&uport->lock); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; - return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; + return 0; } /* @@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, case TIOCMIWAIT: ret = uart_wait_modem_status(state, arg); break; - - case TIOCGICOUNT: - ret = uart_get_count(state, uarg); - break; } if (ret != -ENOIOCTLCMD) @@ -2065,7 +2061,19 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) /* * Re-enable the console device after suspending. */ - if (uart_console(uport)) { + if (console_suspend_enabled && uart_console(uport)) { + /* + * First try to use the console cflag setting. + */ + memset(&termios, 0, sizeof(struct ktermios)); + termios.c_cflag = uport->cons->cflag; + + /* + * If that's unset, use the tty termios setting. + */ + if (port->tty && port->tty->termios && termios.c_cflag == 0) + termios = *(port->tty->termios); + uart_change_pm(state, 0); uport->ops->set_termios(uport, &termios, NULL); console_start(uport->cons); @@ -2283,6 +2291,7 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, .poll_get_char = uart_poll_get_char, diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 9b52f77a930..d2352ac437c 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -140,7 +140,15 @@ # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ # define SCSPTR1 0xffe10024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ + +#if defined(CONFIG_SH_SH2007) +/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */ +# define SCSCR_INIT(port) 0x38 +#else +/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */ +# define SCSCR_INIT(port) 0x3a +#endif + #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SH7786) # define SCSPTR0 0xffea0024 /* 16 bit SCIF */ @@ -616,9 +624,10 @@ static inline int sci_rxd_in(struct uart_port *port) * -- Mitch Davis - 15 Jul 2000 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) +#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786)) && \ + !defined(CONFIG_SH_SH2007) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 9b03d7b3e45..d2fce865b73 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); * Register definitions * * For register details see datasheet: - * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf + * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf */ #define ULITE_RX 0x00 @@ -322,6 +322,26 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) return -EINVAL; } +#ifdef CONFIG_CONSOLE_POLL +static int ulite_get_poll_char(struct uart_port *port) +{ + if (!(ioread32be(port->membase + ULITE_STATUS) + & ULITE_STATUS_RXVALID)) + return NO_POLL_CHAR; + + return ioread32be(port->membase + ULITE_RX); +} + +static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) +{ + while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL) + cpu_relax(); + + /* write char to device */ + iowrite32be(ch, port->membase + ULITE_TX); +} +#endif + static struct uart_ops ulite_ops = { .tx_empty = ulite_tx_empty, .set_mctrl = ulite_set_mctrl, @@ -338,7 +358,11 @@ static struct uart_ops ulite_ops = { .release_port = ulite_release_port, .request_port = ulite_request_port, .config_port = ulite_config_port, - .verify_port = ulite_verify_port + .verify_port = ulite_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = ulite_get_poll_char, + .poll_put_char = ulite_put_poll_char, +#endif }; /* --------------------------------------------------------------------- |