summaryrefslogtreecommitdiff
path: root/drivers/tty/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/68328serial.c1322
-rw-r--r--drivers/tty/serial/8250/8250.h14
-rw-r--r--drivers/tty/serial/8250/8250_accent.c13
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c2
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c146
-rw-r--r--drivers/tty/serial/8250/8250_boca.c41
-rw-r--r--drivers/tty/serial/8250/8250_core.c30
-rw-r--r--drivers/tty/serial/8250/8250_dw.c137
-rw-r--r--drivers/tty/serial/8250/8250_early.c38
-rw-r--r--drivers/tty/serial/8250/8250_exar_st16c554.c17
-rw-r--r--drivers/tty/serial/8250/8250_fourport.c28
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c7
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c27
-rw-r--r--drivers/tty/serial/8250/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c14
-rw-r--r--drivers/tty/serial/8250/8250_mid.c35
-rw-r--r--drivers/tty/serial/8250/8250_moxa.c157
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c51
-rw-r--r--drivers/tty/serial/8250/8250_of.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c40
-rw-r--r--drivers/tty/serial/8250/8250_pci.c150
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c48
-rw-r--r--drivers/tty/serial/8250/8250_port.c453
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig50
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/8250/serial_cs.c90
-rw-r--r--drivers/tty/serial/Kconfig42
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/amba-pl011.c24
-rw-r--r--drivers/tty/serial/arc_uart.c1
-rw-r--r--drivers/tty/serial/atmel_serial.c194
-rw-r--r--drivers/tty/serial/clps711x.c10
-rw-r--r--drivers/tty/serial/crisv10.c33
-rw-r--r--drivers/tty/serial/digicolor-usart.c11
-rw-r--r--drivers/tty/serial/earlycon.c118
-rw-r--r--drivers/tty/serial/ifx6x60.c3
-rw-r--r--drivers/tty/serial/imx.c5
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c13
-rw-r--r--drivers/tty/serial/m32r_sio.c134
-rw-r--r--drivers/tty/serial/m32r_sio.h49
-rw-r--r--drivers/tty/serial/meson_uart.c8
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/mpsc.c178
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c650
-rw-r--r--drivers/tty/serial/omap-serial.c2
-rw-r--r--drivers/tty/serial/samsung.c28
-rw-r--r--drivers/tty/serial/sc16is7xx.c24
-rw-r--r--drivers/tty/serial/serial_core.c125
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c3
-rw-r--r--drivers/tty/serial/sh-sci.c178
-rw-r--r--drivers/tty/serial/sh-sci.h15
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/uartlite.c53
-rw-r--r--drivers/tty/serial/ucc_uart.c3
-rw-r--r--drivers/tty/serial/xilinx_uartps.c543
-rw-r--r--drivers/tty/serial/zs.c4
59 files changed, 2722 insertions, 2662 deletions
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
deleted file mode 100644
index 0982c1a44..000000000
--- a/drivers/tty/serial/68328serial.c
+++ /dev/null
@@ -1,1322 +0,0 @@
-/* 68328serial.c: Serial port driver for 68328 microcontroller
- *
- * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
- * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
- * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
- * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
- *
- * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
- * Multiple UART support Daniel Potts <danielp@cse.unsw.edu.au>
- * Power management support Daniel Potts <danielp@cse.unsw.edu.au>
- * VZ Second Serial Port enable Phil Wilshire
- * 2.4/2.5 port David McCullough
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/serial.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
-#include <linux/reboot.h>
-#include <linux/keyboard.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-
-/* (es) */
-/* note: perhaps we can murge these files, so that you can just
- * define 1 of them, and they can sort that out for themselves
- */
-#if defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#else
-#if defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#else
-#include <asm/MC68328.h>
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_M68EZ328 */
-
-/* Turn off usage of real serial interrupt code, to "support" Copilot */
-#ifdef CONFIG_XCOPILOT_BUGS
-#undef USE_INTS
-#else
-#define USE_INTS
-#endif
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- * -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real 328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- * -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- */
-struct m68k_serial {
- struct tty_port tport;
- char is_cons; /* Is this our console. */
- int magic;
- int baud_base;
- int port;
- int irq;
- int type; /* UART type */
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int line;
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
-};
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-
-static struct m68k_serial m68k_soft[NR_PORTS];
-
-static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
-
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
-
-struct tty_driver *serial_driver;
-
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
-
-/*
- * Setup for console. Argument comes from the boot command line.
- */
-
-/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
-#ifdef CONFIG_M68VZ328
-#define CONSOLE_BAUD_RATE 19200
-#define DEFAULT_CBAUD B19200
-#endif
-
-
-#ifndef CONSOLE_BAUD_RATE
-#define CONSOLE_BAUD_RATE 9600
-#define DEFAULT_CBAUD B9600
-#endif
-
-
-static int m68328_console_initted;
-static int m68328_console_baud = CONSOLE_BAUD_RATE;
-static int m68328_console_cbaud = DEFAULT_CBAUD;
-
-
-static inline int serial_paranoia_check(struct m68k_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char *badinfo =
- "Warning: null m68k_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/* Utility routines */
-static inline int get_baud(struct m68k_serial *ss)
-{
- unsigned long result = 115200;
- unsigned short int baud = uart_addr[ss->line].ubaud;
- if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
- result >>= GET_FIELD(baud, UBAUD_DIVIDE);
-
- return result;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- uart->ustcnt &= ~USTCNT_TXEN;
- local_irq_restore(flags);
-}
-
-static int rs_put_char(char ch)
-{
- unsigned long flags;
- int loops = 0;
-
- local_irq_save(flags);
-
- while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
- loops++;
- udelay(5);
- }
-
- UTX_TXDATA = ch;
- udelay(5);
- local_irq_restore(flags);
- return 1;
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- local_irq_save(flags);
- if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
- }
- local_irq_restore(flags);
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned char ch, flag;
-
- /*
- * This do { } while() loop will get ALL chars out of Rx FIFO
- */
-#ifndef CONFIG_XCOPILOT_BUGS
- do {
-#endif
- ch = GET_FIELD(rx, URX_RXDATA);
-
- if (info->is_cons) {
- if (URX_BREAK & rx) { /* whee, break received */
- return;
-#ifdef CONFIG_MAGIC_SYSRQ
- } else if (ch == 0x10) { /* ^P */
- show_state();
- show_free_areas(0);
- show_buffers();
-/* show_net_buffers(); */
- return;
- } else if (ch == 0x12) { /* ^R */
- emergency_restart();
- return;
-#endif /* CONFIG_MAGIC_SYSRQ */
- }
- }
-
- flag = TTY_NORMAL;
-
- if (rx & URX_PARITY_ERROR)
- flag = TTY_PARITY;
- else if (rx & URX_OVRUN)
- flag = TTY_OVERRUN;
- else if (rx & URX_FRAME_ERROR)
- flag = TTY_FRAME;
-
- tty_insert_flip_char(&info->tport, ch, flag);
-#ifndef CONFIG_XCOPILOT_BUGS
- } while ((rx = uart->urx.w) & URX_DATA_READY);
-#endif
-
- tty_schedule_flip(&info->tport);
-}
-
-static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
-
- if (info->x_char) {
- /* Send next char */
- uart->utx.b.txdata = info->x_char;
- info->x_char = 0;
- goto clear_and_return;
- }
-
- if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
- /* That's peculiar... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
-
- if (info->xmit_cnt <= 0) {
- /* All done for now... TX ints off */
- uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
- goto clear_and_return;
- }
-
-clear_and_return:
- /* Clear interrupt (should be auto)*/
- return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
- struct m68k_serial *info = dev_id;
- struct tty_struct *tty = tty_port_tty_get(&info->tport);
- m68328_uart *uart;
- unsigned short rx;
- unsigned short tx;
-
- uart = &uart_addr[info->line];
- rx = uart->urx.w;
-
-#ifdef USE_INTS
- tx = uart->utx.w;
-
- if (rx & URX_DATA_READY)
- receive_chars(info, rx);
- if (tx & UTX_TX_AVAIL)
- transmit_chars(info, tty);
-#else
- receive_chars(info, rx);
-#endif
- tty_kref_put(tty);
-
- return IRQ_HANDLED;
-}
-
-static int startup(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (info->tport.flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- local_irq_save(flags);
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in change_speed())
- */
-
- uart->ustcnt = USTCNT_UEN;
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
- (void)uart->urx.w;
-
- /*
- * Finally, enable sequencing and interrupts
- */
-#ifdef USE_INTS
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN |
- USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
-#endif
-
- if (tty)
- clear_bit(TTY_IO_ERROR, &tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
-
- change_speed(info, tty);
-
- info->tport.flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- uart->ustcnt = 0; /* All off! */
- if (!(info->tport.flags & ASYNC_INITIALIZED))
- return;
-
- local_irq_save(flags);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
-
- info->tport.flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-struct {
- int divisor, prescale;
-}
-#ifndef CONFIG_M68VZ328
- hw_baud_table[18] = {
- {0, 0}, /* 0 */
- {0, 0}, /* 50 */
- {0, 0}, /* 75 */
- {0, 0}, /* 110 */
- {0, 0}, /* 134 */
- {0, 0}, /* 150 */
- {0, 0}, /* 200 */
- {7, 0x26}, /* 300 */
- {6, 0x26}, /* 600 */
- {5, 0x26}, /* 1200 */
- {0, 0}, /* 1800 */
- {4, 0x26}, /* 2400 */
- {3, 0x26}, /* 4800 */
- {2, 0x26}, /* 9600 */
- {1, 0x26}, /* 19200 */
- {0, 0x26}, /* 38400 */
- {1, 0x38}, /* 57600 */
- {0, 0x38}, /* 115200 */
-};
-#else
- hw_baud_table[18] = {
- {0, 0}, /* 0 */
- {0, 0}, /* 50 */
- {0, 0}, /* 75 */
- {0, 0}, /* 110 */
- {0, 0}, /* 134 */
- {0, 0}, /* 150 */
- {0, 0}, /* 200 */
- {0, 0}, /* 300 */
- {7, 0x26}, /* 600 */
- {6, 0x26}, /* 1200 */
- {0, 0}, /* 1800 */
- {5, 0x26}, /* 2400 */
- {4, 0x26}, /* 4800 */
- {3, 0x26}, /* 9600 */
- {2, 0x26}, /* 19200 */
- {1, 0x26}, /* 38400 */
- {0, 0x26}, /* 57600 */
- {1, 0x38}, /* 115200 */
-};
-#endif
-/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned short port;
- unsigned short ustcnt;
- unsigned cflag;
- int i;
-
- cflag = tty->termios.c_cflag;
- port = info->port;
- if (!port)
- return;
-
- ustcnt = uart->ustcnt;
- uart->ustcnt = ustcnt & ~USTCNT_TXEN;
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i = (i & ~CBAUDEX) + B38400;
- }
-
- uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
-
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
-
- if ((cflag & CSIZE) == CS8)
- ustcnt |= USTCNT_8_7;
-
- if (cflag & CSTOPB)
- ustcnt |= USTCNT_STOP;
-
- if (cflag & PARENB)
- ustcnt |= USTCNT_PARITYEN;
- if (cflag & PARODD)
- ustcnt |= USTCNT_ODD_EVEN;
-
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- if (cflag & CRTSCTS) {
- uart->utx.w &= ~UTX_NOCTS;
- } else {
- uart->utx.w |= UTX_NOCTS;
- }
-#endif
-
- ustcnt |= USTCNT_TXEN;
-
- uart->ustcnt = ustcnt;
- return;
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct m68k_serial *info = &m68k_soft[0];
- char c;
-
- if (info == NULL) return;
- if (info->xmit_buf == NULL) return;
-
- local_irq_save(flags);
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- local_irq_restore(flags);
-
- rs_put_char(c);
-
- local_irq_save(flags);
- left = min(info->xmit_cnt, left-1);
- }
-
- /* Last character is being transmitted now (hopefully). */
- udelay(5);
-
- local_irq_restore(flags);
- return;
-}
-
-/*
- * m68k_console_print is registered for printk.
- */
-void console_print_68328(const char *p)
-{
- char c;
-
- while ((c = *(p++)) != 0) {
- if (c == '\n')
- rs_put_char('\r');
- rs_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-
- return;
-}
-
-static void rs_set_ldisc(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
- return;
-
- info->is_cons = (tty->termios.c_line == N_TTY);
-
- printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-#ifndef USE_INTS
- for (;;) {
-#endif
-
- /* Enable transmitter */
- local_irq_save(flags);
-
- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
- local_irq_restore(flags);
- return;
- }
-
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
-#else
- uart->ustcnt |= USTCNT_TXEN;
-#endif
-
-#ifdef USE_INTS
- if (uart->utx.w & UTX_TX_AVAIL) {
-#else
- if (1) {
-#endif
- /* Send char */
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
- }
-#endif
- local_irq_restore(flags);
-}
-
-extern void console_printn(const char *b, int count);
-
-static int rs_write(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- local_save_flags(flags);
- while (1) {
- local_irq_disable();
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- local_irq_restore(flags);
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
- local_irq_disable();
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt && !tty->stopped) {
- /* Enable transmitter */
- local_irq_disable();
-#ifndef USE_INTS
- while (info->xmit_cnt) {
-#endif
-
- uart->ustcnt |= USTCNT_TXEN;
-#ifdef USE_INTS
- uart->ustcnt |= USTCNT_TX_INTR_MASK;
-#else
- while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
-#endif
- if (uart->utx.w & UTX_TX_AVAIL) {
- uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
-
-#ifndef USE_INTS
- }
-#endif
- local_irq_restore(flags);
- }
-
- return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- local_irq_save(flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
-
- /* Turn off RTS line (do this atomic) */
-}
-
-static void rs_unthrottle(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
-
- /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct m68k_serial *info,
- struct serial_struct *retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->tport.flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->tport.close_delay;
- tmp.closing_wait = info->tport.closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
- struct serial_struct *new_info)
-{
- struct tty_port *port = &info->tport;
- struct serial_struct new_serial;
- struct m68k_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != port->close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (port->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->type = new_serial.type;
- port->close_delay = new_serial.close_delay;
- port->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = startup(info, tty);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct m68k_serial *info, unsigned int *value)
-{
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- m68328_uart *uart = &uart_addr[info->line];
-#endif
- unsigned char status;
- unsigned long flags;
-
- local_irq_save(flags);
-#ifdef CONFIG_SERIAL_68328_RTS_CTS
- status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
-#else
- status = 0;
-#endif
- local_irq_restore(flags);
- return put_user(status, value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(struct m68k_serial *info, unsigned int duration)
-{
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
- if (!info->port)
- return;
- local_irq_save(flags);
-#ifdef USE_INTS
- uart->utx.w |= UTX_SEND_BREAK;
- msleep_interruptible(duration);
- uart->utx.w &= ~UTX_SEND_BREAK;
-#endif
- local_irq_restore(flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- int retval;
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- send_break(info, 250); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- send_break(info, arg ? arg*(100) : 250);
- return 0;
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info, tty,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct m68k_serial *) arg,
- info, sizeof(struct m68k_serial)))
- return -EFAULT;
- return 0;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- change_speed(info, tty);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
- rs_start(tty);
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file *filp)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- struct tty_port *port = &info->tport;
- m68328_uart *uart = &uart_addr[info->line];
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- local_irq_restore(flags);
- return;
- }
-
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "port->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
- local_irq_restore(flags);
- return;
- }
- port->flags |= ASYNC_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, port->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
-
- uart->ustcnt &= ~USTCNT_RXEN;
- uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
-
- shutdown(info, tty);
- rs_flush_buffer(tty);
-
- tty_ldisc_flush(tty);
- tty->closing = 0;
- tty_port_tty_set(&info->tport, NULL);
-#warning "This is not and has never been valid so fix it"
-#if 0
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios.c_line = N_TTY;
- if (tty->ldisc.open)
- (tty->ldisc.open)(tty);
- }
-#endif
- if (port->blocked_open) {
- if (port->close_delay)
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
- wake_up_interruptible(&port->open_wait);
- }
- port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- local_irq_restore(flags);
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void rs_hangup(struct tty_struct *tty)
-{
- struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info, tty);
- info->tport.count = 0;
- info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
- tty_port_tty_set(&info->tport, NULL);
- wake_up_interruptible(&info->tport.open_wait);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its S structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-int rs_open(struct tty_struct *tty, struct file *filp)
-{
- struct m68k_serial *info;
- int retval;
-
- info = &m68k_soft[tty->index];
-
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-
- info->tport.count++;
- tty->driver_data = info;
- tty_port_tty_set(&info->tport, tty);
-
- /*
- * Start up serial port
- */
- retval = startup(info, tty);
- if (retval)
- return retval;
-
- return tty_port_block_til_ready(&info->tport, tty, filp);
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk("MC68328 serial driver version 1.00\n");
-}
-
-static const struct tty_operations rs_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .set_ldisc = rs_set_ldisc,
-};
-
-static const struct tty_port_operations rs_port_ops = {
-};
-
-/* rs_init inits the driver */
-static int __init
-rs68328_init(void)
-{
- unsigned long flags;
- int i;
- struct m68k_serial *info;
-
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* SPARC: Not all of this is exactly right for us. */
-
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &rs_ops);
-
- local_irq_save(flags);
-
- for (i = 0; i < NR_PORTS; i++) {
-
- info = &m68k_soft[i];
- tty_port_init(&info->tport);
- info->tport.ops = &rs_port_ops;
- info->magic = SERIAL_MAGIC;
- info->port = (int) &uart_addr[i];
- info->irq = uart_irqs[i];
- info->custom_divisor = 16;
- info->x_char = 0;
- info->line = i;
- info->is_cons = 1; /* Means shortcuts work */
-
- printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line,
- info->port, info->irq);
- printk(" is a builtin MC68328 UART\n");
-
-#ifdef CONFIG_M68VZ328
- if (i > 0)
- PJSEL &= 0xCF; /* PSW enable second port output */
-#endif
-
- if (request_irq(uart_irqs[i],
- rs_interrupt,
- 0,
- "M68328_UART", info))
- panic("Unable to attach 68328 serial interrupt\n");
-
- tty_port_link_device(&info->tport, serial_driver, i);
- }
- local_irq_restore(flags);
-
- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- for (i = 0; i < NR_PORTS; i++)
- tty_port_destroy(&m68k_soft[i].tport);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-module_init(rs68328_init);
-
-
-
-static void m68328_set_baud(void)
-{
- unsigned short ustcnt;
- int i;
-
- ustcnt = USTCNT;
- USTCNT = ustcnt & ~USTCNT_TXEN;
-
-again:
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == m68328_console_baud)
- break;
- if (i >= ARRAY_SIZE(baud_table)) {
- m68328_console_baud = 9600;
- goto again;
- }
-
- UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
- PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
- ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
- ustcnt |= USTCNT_8_7;
- ustcnt |= USTCNT_TXEN;
- USTCNT = ustcnt;
- m68328_console_initted = 1;
- return;
-}
-
-
-int m68328_console_setup(struct console *cp, char *arg)
-{
- int i, n = CONSOLE_BAUD_RATE;
-
- if (!cp)
- return(-1);
-
- if (arg)
- n = simple_strtoul(arg, NULL, 0);
-
- for (i = 0; i < ARRAY_SIZE(baud_table); i++)
- if (baud_table[i] == n)
- break;
- if (i < ARRAY_SIZE(baud_table)) {
- m68328_console_baud = n;
- m68328_console_cbaud = 0;
- if (i > 15) {
- m68328_console_cbaud |= CBAUDEX;
- i -= 15;
- }
- m68328_console_cbaud |= i;
- }
-
- m68328_set_baud(); /* make sure baud rate changes */
- return 0;
-}
-
-
-static struct tty_driver *m68328_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-
-void m68328_console_write (struct console *co, const char *str,
- unsigned int count)
-{
- if (!m68328_console_initted)
- m68328_set_baud();
- while (count--) {
- if (*str == '\n')
- rs_put_char('\r');
- rs_put_char(*str++);
- }
-}
-
-
-static struct console m68328_driver = {
- .name = "ttyS",
- .write = m68328_console_write,
- .device = m68328_console_device,
- .setup = m68328_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-
-static int __init m68328_console_init(void)
-{
- register_console(&m68328_driver);
- return 0;
-}
-
-console_initcall(m68328_console_init);
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index d54dcd87c..047a7ba67 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -92,6 +92,18 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0
#endif
+#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | (_flags), \
+ }
+
+#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
+
+
static inline int serial_in(struct uart_8250_port *up, int offset)
{
return up->port.serial_in(&up->port, offset);
@@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
+int serial8250_em485_init(struct uart_8250_port *p);
+void serial8250_em485_destroy(struct uart_8250_port *p);
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
diff --git a/drivers/tty/serial/8250/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c
index 34b51c651..522aeae05 100644
--- a/drivers/tty/serial/8250/8250_accent.c
+++ b/drivers/tty/serial/8250/8250_accent.c
@@ -10,18 +10,11 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port accent_data[] = {
- PORT(0x330, 4),
- PORT(0x338, 4),
+ SERIAL8250_PORT(0x330, 4),
+ SERIAL8250_PORT(0x338, 4),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index 549aa07c0..402dfdd49 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
uart.port.regshift = 2;
uart.port.dev = &ec->dev;
- for (i = 0; i < info->num_ports; i ++) {
+ for (i = 0; i < info->num_ports; i++) {
uart.port.membase = info->vaddr + type->offset[i];
uart.port.mapbase = bus_addr + type->offset[i];
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
new file mode 100644
index 000000000..e10f12444
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -0,0 +1,146 @@
+/*
+ * Serial port driver for BCM2835AUX UART
+ *
+ * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
+ *
+ * Based on 8250_lpc18xx.c:
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+struct bcm2835aux_data {
+ struct uart_8250_port uart;
+ struct clk *clk;
+ int line;
+};
+
+static int bcm2835aux_serial_probe(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data;
+ struct resource *res;
+ int ret;
+
+ /* allocate the custom structure */
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* initialize data */
+ spin_lock_init(&data->uart.port.lock);
+ data->uart.capabilities = UART_CAP_FIFO;
+ data->uart.port.dev = &pdev->dev;
+ data->uart.port.regshift = 2;
+ data->uart.port.type = PORT_16550;
+ data->uart.port.iotype = UPIO_MEM;
+ data->uart.port.fifosize = 8;
+ data->uart.port.flags = UPF_SHARE_IRQ |
+ UPF_FIXED_PORT |
+ UPF_FIXED_TYPE |
+ UPF_SKIP_TEST;
+
+ /* get the clock - this also enables the HW */
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ ret = PTR_ERR_OR_ZERO(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+ return ret;
+ }
+
+ /* get the interrupt */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "irq not found - %i", ret);
+ return ret;
+ }
+ data->uart.port.irq = ret;
+
+ /* map the main registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+ data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
+ ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
+ if (ret)
+ return ret;
+
+ /* Check for a fixed line number */
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ data->uart.port.line = ret;
+
+ /* enable the clock as a last step */
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
+ ret);
+ return ret;
+ }
+
+ /* the HW-clock divider for bcm2835aux is 8,
+ * but 8250 expects a divider of 16,
+ * so we have to multiply the actual clock by 2
+ * to get identical baudrates.
+ */
+ data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
+
+ /* register the port */
+ ret = serial8250_register_8250_port(&data->uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
+ ret);
+ goto dis_clk;
+ }
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_clk:
+ clk_disable_unprepare(data->clk);
+ return ret;
+}
+
+static int bcm2835aux_serial_remove(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->uart.port.line);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835aux_serial_match[] = {
+ { .compatible = "brcm,bcm2835-aux-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
+
+static struct platform_driver bcm2835aux_serial_driver = {
+ .driver = {
+ .name = "bcm2835-aux-uart",
+ .of_match_table = bcm2835aux_serial_match,
+ },
+ .probe = bcm2835aux_serial_probe,
+ .remove = bcm2835aux_serial_remove,
+};
+module_platform_driver(bcm2835aux_serial_driver);
+
+MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c
index d125dc107..a63b5998e 100644
--- a/drivers/tty/serial/8250/8250_boca.c
+++ b/drivers/tty/serial/8250/8250_boca.c
@@ -10,32 +10,25 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port boca_data[] = {
- PORT(0x100, 12),
- PORT(0x108, 12),
- PORT(0x110, 12),
- PORT(0x118, 12),
- PORT(0x120, 12),
- PORT(0x128, 12),
- PORT(0x130, 12),
- PORT(0x138, 12),
- PORT(0x140, 12),
- PORT(0x148, 12),
- PORT(0x150, 12),
- PORT(0x158, 12),
- PORT(0x160, 12),
- PORT(0x168, 12),
- PORT(0x170, 12),
- PORT(0x178, 12),
+ SERIAL8250_PORT(0x100, 12),
+ SERIAL8250_PORT(0x108, 12),
+ SERIAL8250_PORT(0x110, 12),
+ SERIAL8250_PORT(0x118, 12),
+ SERIAL8250_PORT(0x120, 12),
+ SERIAL8250_PORT(0x128, 12),
+ SERIAL8250_PORT(0x130, 12),
+ SERIAL8250_PORT(0x138, 12),
+ SERIAL8250_PORT(0x140, 12),
+ SERIAL8250_PORT(0x148, 12),
+ SERIAL8250_PORT(0x150, 12),
+ SERIAL8250_PORT(0x158, 12),
+ SERIAL8250_PORT(0x160, 12),
+ SERIAL8250_PORT(0x168, 12),
+ SERIAL8250_PORT(0x170, 12),
+ SERIAL8250_PORT(0x178, 12),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 279a842cd..11ccfa00c 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s,
static int univ8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ int retval;
/*
* Check whether an invalid uart number has been specified, and
@@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options)
/* link port to console */
port->cons = co;
- return serial8250_console_setup(port, options, false);
+ retval = serial8250_console_setup(port, options, false);
+ if (retval != 0)
+ port->cons = NULL;
+ return retval;
}
/**
@@ -687,7 +691,7 @@ static int __init univ8250_console_init(void)
}
console_initcall(univ8250_console_init);
-#define SERIAL8250_CONSOLE &univ8250_console
+#define SERIAL8250_CONSOLE (&univ8250_console)
#else
#define SERIAL8250_CONSOLE NULL
#endif
@@ -764,6 +768,7 @@ void serial8250_suspend_port(int line)
uart_suspend_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
@@ -789,6 +794,7 @@ void serial8250_resume_port(int line)
}
uart_resume_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_resume_port);
/*
* Register a set of serial devices attached to a platform device. The
@@ -1068,6 +1074,15 @@ void serial8250_unregister_port(int line)
struct uart_8250_port *uart = &serial8250_ports[line];
mutex_lock(&serial_mutex);
+
+ if (uart->em485) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ serial8250_em485_destroy(uart);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+ }
+
uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
@@ -1093,9 +1108,8 @@ static int __init serial8250_init(void)
serial8250_isa_init_ports();
- printk(KERN_INFO "Serial: 8250/16550 driver, "
- "%d ports, IRQ sharing %sabled\n", nr_uarts,
- share_irqs ? "en" : "dis");
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
+ nr_uarts, share_irqs ? "en" : "dis");
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
@@ -1168,15 +1182,11 @@ static void __exit serial8250_exit(void)
module_init(serial8250_init);
module_exit(serial8250_exit);
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
- " (unsafe)");
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a5d319e4a..a3fb95d85 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -68,12 +68,6 @@ struct dw8250_data {
unsigned int uart_16550_compatible:1;
};
-#define BYT_PRV_CLK 0x800
-#define BYT_PRV_CLK_EN (1 << 0)
-#define BYT_PRV_CLK_M_VAL_SHIFT 1
-#define BYT_PRV_CLK_N_VAL_SHIFT 16
-#define BYT_PRV_CLK_UPDATE (1 << 31)
-
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p)
(void)p->serial_in(p, UART_RX);
}
-static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+static void dw8250_check_lcr(struct uart_port *p, int value)
{
- writeb(value, p->membase + (offset << p->regshift));
+ void __iomem *offset = p->membase + (UART_LCR << p->regshift);
+ int tries = 1000;
/* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writeb(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+
+ dw8250_force_idle(p);
+
+#ifdef CONFIG_64BIT
+ __raw_writeq(value & 0xff, offset);
+#else
+ if (p->iotype == UPIO_MEM32)
+ writel(value, offset);
+ else if (p->iotype == UPIO_MEM32BE)
+ iowrite32be(value, offset);
+ else
+ writeb(value, offset);
+#endif
}
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
+}
+
+static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ writeb(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
@@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- __raw_writeq(value & 0xff,
- p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
#endif /* CONFIG_64BIT */
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
writel(value, p->membase + (offset << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writel(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
return dw8250_modify_msr(p, offset, value);
}
+static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ iowrite32be(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
+}
+
+static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
+{
+ unsigned int value = ioread32be(p->membase + (offset << p->regshift));
+
+ return dw8250_modify_msr(p, offset, value);
+}
+
+
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
unsigned int iir = p->serial_in(p, UART_IIR);
- if (serial8250_handle_irq(p, iir)) {
+ if (serial8250_handle_irq(p, iir))
return 1;
- } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+
+ if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
@@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
data->skip_autocfg = true;
}
#endif
+ if (of_device_is_big_endian(p->dev->of_node)) {
+ p->iotype = UPIO_MEM32BE;
+ p->serial_in = dw8250_serial_in32be;
+ p->serial_out = dw8250_serial_out32be;
+ }
} else if (has_acpi_companion(p->dev)) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
@@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p)
* If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
*/
- reg = readl(p->membase + DW_UART_UCV);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_UCV);
+ else
+ reg = readl(p->membase + DW_UART_UCV);
if (!reg)
return;
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
- reg = readl(p->membase + DW_UART_CPR);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_CPR);
+ else
+ reg = readl(p->membase + DW_UART_CPR);
if (!reg)
return;
@@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible) {
- p->serial_out = NULL;
+ if (data->uart_16550_compatible)
p->handle_irq = NULL;
- }
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 2aa151366..d3757a53c 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -39,15 +39,17 @@
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
return readb(port->membase + offset);
case UPIO_MEM16:
- return readw(port->membase + (offset << 1));
+ return readw(port->membase + offset);
case UPIO_MEM32:
- return readl(port->membase + (offset << 2));
+ return readl(port->membase + offset);
case UPIO_MEM32BE:
- return ioread32be(port->membase + (offset << 2));
+ return ioread32be(port->membase + offset);
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -57,18 +59,20 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
writeb(value, port->membase + offset);
break;
case UPIO_MEM16:
- writew(value, port->membase + (offset << 1));
+ writew(value, port->membase + offset);
break;
case UPIO_MEM32:
- writel(value, port->membase + (offset << 2));
+ writel(value, port->membase + offset);
break;
case UPIO_MEM32BE:
- iowrite32be(value, port->membase + (offset << 2));
+ iowrite32be(value, port->membase + offset);
break;
case UPIO_PORT:
outb(value, port->iobase + offset);
@@ -145,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
+
+#ifdef CONFIG_SERIAL_8250_OMAP
+
+static int __init early_omap8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ struct uart_port *port = &device->port;
+
+ if (!(device->port.membase || device->port.iobase))
+ return -ENODEV;
+
+ port->regshift = 2;
+ device->con->write = early_serial8250_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
+
+#endif
diff --git a/drivers/tty/serial/8250/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c
index bf53aabf9..3a7cb8262 100644
--- a/drivers/tty/serial/8250/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250/8250_exar_st16c554.c
@@ -13,20 +13,13 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port exar_data[] = {
- PORT(0x100, 5),
- PORT(0x108, 5),
- PORT(0x110, 5),
- PORT(0x118, 5),
+ SERIAL8250_PORT(0x100, 5),
+ SERIAL8250_PORT(0x108, 5),
+ SERIAL8250_PORT(0x110, 5),
+ SERIAL8250_PORT(0x118, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c
index be1582609..4045180a8 100644
--- a/drivers/tty/serial/8250/8250_fourport.c
+++ b/drivers/tty/serial/8250/8250_fourport.c
@@ -10,24 +10,20 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
- }
+#include "8250.h"
+
+#define SERIAL8250_FOURPORT(_base, _irq) \
+ SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT)
static struct plat_serial8250_port fourport_data[] = {
- PORT(0x1a0, 9),
- PORT(0x1a8, 9),
- PORT(0x1b0, 9),
- PORT(0x1b8, 9),
- PORT(0x2a0, 5),
- PORT(0x2a8, 5),
- PORT(0x2b0, 5),
- PORT(0x2b8, 5),
+ SERIAL8250_FOURPORT(0x1a0, 9),
+ SERIAL8250_FOURPORT(0x1a8, 9),
+ SERIAL8250_FOURPORT(0x1b0, 9),
+ SERIAL8250_FOURPORT(0x1b8, 9),
+ SERIAL8250_FOURPORT(0x2a0, 5),
+ SERIAL8250_FOURPORT(0x2a8, 5),
+ SERIAL8250_FOURPORT(0x2b0, 5),
+ SERIAL8250_FOURPORT(0x2b8, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index 2e3ea1a70..b1e6ae9f1 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
* the user what they're missing.
*/
if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
- printk(KERN_INFO
+ dev_info(&dev->dev,
"Serial: device 0x%llx not configured.\n"
"Enable support for Wax, Lasi, Asp or Dino.\n",
(unsigned long long)dev->hpa.start);
@@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev)
err = serial8250_register_8250_port(&uart);
if (err < 0) {
- printk(KERN_WARNING
- "serial8250_register_8250_port returned error %d\n", err);
+ dev_warn(&dev->dev,
+ "serial8250_register_8250_port returned error %d\n",
+ err);
iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 2891958cd..38166db2b 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -24,8 +24,7 @@
#endif
#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
+struct hp300_port {
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
};
@@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void)
/* Check for APCI console */
if (scode == 256) {
#ifdef CONFIG_HPAPCI
- printk(KERN_INFO "Serial console is HP APCI 1\n");
+ pr_info("Serial console is HP APCI 1\n");
port.uartclk = HPAPCI_BAUD_BASE * 16;
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
@@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void)
port.regshift = 2;
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+ pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
return 0;
#endif
} else {
@@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void)
if (!pa)
return 0;
- printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+ pr_info("Serial console is HP DCA at select code %d\n", scode);
port.uartclk = HPDCA_BAUD_BASE * 16;
port.mapbase = (pa + UART_OFFSET);
@@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void)
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+ pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
return 0;
#endif
}
if (early_serial_setup(&port) < 0)
- printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+ pr_warn("%s: early_serial_setup() failed.\n", __func__);
return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */
@@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d,
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
- " irq %d failed\n", d->scode, uart.port.irq);
+ dev_notice(&d->dev,
+ "8250_hp300: register_serial() DCA scode %d irq %d failed\n",
+ d->scode, uart.port.irq);
return -ENOMEM;
}
@@ -249,8 +249,8 @@ static int __init hp300_8250_init(void)
/* Memory mapped I/O */
uart.port.iotype = UPIO_MEM;
- uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
- | UPF_BOOT_AUTOCONF;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
uart.port.irq = 0;
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
@@ -261,8 +261,9 @@ static int __init hp300_8250_init(void)
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uart.port.irq);
+ dev_notice(uart.port.dev,
+ "8250_hp300: register_serial() APCI %d irq %d failed\n",
+ i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c
index a5c778e83..27124e21e 100644
--- a/drivers/tty/serial/8250/8250_hub6.c
+++ b/drivers/tty/serial/8250/8250_hub6.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define HUB6(card,port) \
+#define HUB6(card, port) \
{ \
.iobase = 0x302, \
.irq = 3, \
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index d6e1ec9b4..b0677f610 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -48,7 +48,7 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6)
-#ifdef CONFIG_SERIAL_EARLYCON
+#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -154,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
break;
case UART_IER:
- /* Enable receive timeout interrupt with the
- * receive line status interrupt */
+ /*
+ * Enable receive timeout interrupt with the receive line
+ * status interrupt.
+ */
value |= (value & 0x4) << 2;
break;
case UART_MCR:
- /* If we have enabled modem status IRQs we should enable modem
- * mode. */
+ /*
+ * If we have enabled modem status IRQs we should enable
+ * modem mode.
+ */
ier = p->serial_in(p, UART_IER);
if (ier & UART_IER_MSI)
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 88531a36b..ed489880e 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
#include "8250.h"
@@ -24,6 +25,7 @@
#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8
/* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR 0x08
#define INTEL_MID_UART_PS 0x30
#define INTEL_MID_UART_MUL 0x34
#define INTEL_MID_UART_DIV 0x38
@@ -31,6 +33,7 @@
struct mid8250;
struct mid8250_board {
+ unsigned int flags;
unsigned long freq;
unsigned int base_baud;
int (*setup)(struct mid8250 *, struct uart_port *p);
@@ -88,16 +91,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
static int dnv_handle_irq(struct uart_port *p)
{
struct mid8250 *mid = p->private_data;
- int ret;
-
- ret = hsu_dma_irq(&mid->dma_chip, 0);
- ret |= hsu_dma_irq(&mid->dma_chip, 1);
-
- /* For now, letting the HW generate separate interrupt for the UART */
- if (ret)
- return ret;
-
- return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
+ int ret = IRQ_NONE;
+
+ if (fisr & BIT(2))
+ ret |= hsu_dma_irq(&mid->dma_chip, 1);
+ if (fisr & BIT(1))
+ ret |= hsu_dma_irq(&mid->dma_chip, 0);
+ if (fisr & BIT(0))
+ ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ return ret;
}
#define DNV_DMA_CHAN_OFFSET 0x80
@@ -106,12 +109,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
{
struct hsu_dma_chip *chip = &mid->dma_chip;
struct pci_dev *pdev = to_pci_dev(p->dev);
+ unsigned int bar = FL_GET_BASE(mid->board->flags);
int ret;
chip->dev = &pdev->dev;
chip->irq = pdev->irq;
chip->regs = p->membase;
- chip->length = pci_resource_len(pdev, 0);
+ chip->length = pci_resource_len(pdev, bar);
chip->offset = DNV_DMA_CHAN_OFFSET;
/* Falling back to PIO mode if DMA probing fails */
@@ -217,6 +221,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct uart_8250_port uart;
struct mid8250 *mid;
+ unsigned int bar;
int ret;
ret = pcim_enable_device(pdev);
@@ -230,6 +235,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
mid->board = (struct mid8250_board *)id->driver_data;
+ bar = FL_GET_BASE(mid->board->flags);
memset(&uart, 0, sizeof(struct uart_8250_port));
@@ -242,8 +248,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.set_termios = mid8250_set_termios;
- uart.port.mapbase = pci_resource_start(pdev, 0);
- uart.port.membase = pcim_iomap(pdev, 0, 0);
+ uart.port.mapbase = pci_resource_start(pdev, bar);
+ uart.port.membase = pcim_iomap(pdev, bar, 0);
if (!uart.port.membase)
return -ENOMEM;
@@ -282,18 +288,21 @@ static void mid8250_remove(struct pci_dev *pdev)
}
static const struct mid8250_board pnw_board = {
+ .flags = FL_BASE0,
.freq = 50000000,
.base_baud = 115200,
.setup = pnw_setup,
};
static const struct mid8250_board tng_board = {
+ .flags = FL_BASE0,
.freq = 38400000,
.base_baud = 1843200,
.setup = tng_setup,
};
static const struct mid8250_board dnv_board = {
+ .flags = FL_BASE1,
.freq = 133333333,
.base_baud = 115200,
.setup = dnv_setup,
diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c
new file mode 100644
index 000000000..26eb5393a
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_moxa.c
@@ -0,0 +1,157 @@
+/*
+ * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver.
+ *
+ * Author: Mathieu OTHACEHE <m.othacehe@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+#define MOXA_BASE_BAUD 921600
+#define MOXA_UART_OFFSET 0x200
+#define MOXA_BASE_BAR 1
+
+struct moxa8250_board {
+ unsigned int num_ports;
+ int line[0];
+};
+
+enum {
+ moxa8250_2p = 0,
+ moxa8250_4p,
+ moxa8250_8p
+};
+
+static struct moxa8250_board moxa8250_boards[] = {
+ [moxa8250_2p] = { .num_ports = 2},
+ [moxa8250_4p] = { .num_ports = 4},
+ [moxa8250_8p] = { .num_ports = 8},
+};
+
+static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct uart_8250_port uart;
+ struct moxa8250_board *brd;
+ void __iomem *ioaddr;
+ resource_size_t baseaddr;
+ unsigned int i, nr_ports;
+ unsigned int offset;
+ int ret;
+
+ brd = &moxa8250_boards[id->driver_data];
+ nr_ports = brd->num_ports;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) +
+ sizeof(unsigned int) * nr_ports, GFP_KERNEL);
+ if (!brd)
+ return -ENOMEM;
+
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = pdev->irq;
+ uart.port.uartclk = MOXA_BASE_BAUD * 16;
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+ baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR);
+ ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0);
+ if (!ioaddr)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_ports; i++) {
+
+ /*
+ * MOXA Smartio MUE boards with 4 ports have
+ * a different offset for port #3
+ */
+ if (nr_ports == 4 && i == 3)
+ offset = 7 * MOXA_UART_OFFSET;
+ else
+ offset = i * MOXA_UART_OFFSET;
+
+ uart.port.iotype = UPIO_MEM;
+ uart.port.iobase = 0;
+ uart.port.mapbase = baseaddr + offset;
+ uart.port.membase = ioaddr + offset;
+ uart.port.regshift = 0;
+
+ dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
+
+ brd->line[i] = serial8250_register_8250_port(&uart);
+ if (brd->line[i] < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq,
+ uart.port.iotype, brd->line[i]);
+ break;
+ }
+ }
+
+ pci_set_drvdata(pdev, brd);
+ return 0;
+}
+
+static void moxa8250_remove(struct pci_dev *pdev)
+{
+ struct moxa8250_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->num_ports; i++)
+ serial8250_unregister_port(brd->line[i]);
+}
+
+#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data }
+
+static const struct pci_device_id pci_ids[] = {
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver moxa8250_pci_driver = {
+ .name = "8250_moxa",
+ .id_table = pci_ids,
+ .probe = moxa8250_probe,
+ .remove = moxa8250_remove,
+};
+
+module_pci_driver(moxa8250_pci_driver);
+
+MODULE_AUTHOR("Mathieu OTHACEHE");
+MODULE_DESCRIPTION("MOXA SmartIO MUE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 0e590b233..3489fbcb7 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -16,7 +16,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -41,12 +41,10 @@ static void
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned int baud, quot;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
-
serial8250_do_set_termios(port, termios, old);
/*
@@ -116,7 +114,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
tty_termios_encode_baud_rate(termios, baud, baud);
}
-static int mtk8250_runtime_suspend(struct device *dev)
+static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev)
return 0;
}
-static int mtk8250_runtime_resume(struct device *dev)
+static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int err;
@@ -245,8 +243,24 @@ static int mtk8250_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int mtk8250_suspend(struct device *dev)
+static int mtk8250_remove(struct platform_device *pdev)
+{
+ struct mtk8250_data *data = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ serial8250_unregister_port(data->line);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mtk8250_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -255,7 +269,7 @@ static int mtk8250_suspend(struct device *dev)
return 0;
}
-static int mtk8250_resume(struct device *dev)
+static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -263,7 +277,6 @@ static int mtk8250_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
@@ -275,20 +288,20 @@ static const struct of_device_id mtk8250_of_match[] = {
{ .compatible = "mediatek,mt6577-uart" },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mtk8250_of_match);
static struct platform_driver mtk8250_platform_driver = {
.driver = {
- .name = "mt6577-uart",
- .pm = &mtk8250_pm_ops,
- .of_match_table = mtk8250_of_match,
- .suppress_bind_attrs = true,
-
+ .name = "mt6577-uart",
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
},
.probe = mtk8250_probe,
+ .remove = mtk8250_remove,
};
-builtin_platform_driver(mtk8250_platform_driver);
+module_platform_driver(mtk8250_platform_driver);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init early_mtk8250_setup(struct earlycon_device *device,
const char *options)
{
@@ -302,3 +315,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
#endif
+
+MODULE_AUTHOR("Matthias Brugger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 33021c1f7..c7ed3d2bc 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -335,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = {
.driver = {
.name = "of_serial",
.of_match_table = of_platform_serial_table,
+ .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index a2c0734c7..6f760510e 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
unsigned char cval = 0;
unsigned int baud;
@@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port)
static void omap_8250_throttle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
+static int omap_8250_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* Clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init and serial8250_em485_destroy
+ * are idempotent
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+
+ return 0;
+}
+
static void omap_8250_unthrottle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
+ up.port.rs485_config = omap_8250_rs485_config;
if (pdev->dev.of_node) {
const struct of_device_id *id;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 7cd6f9a90..4eedd1da3 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -55,7 +55,6 @@ struct pci_serial_quirk {
struct serial_private {
struct pci_dev *dev;
unsigned int nr;
- void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
struct pci_serial_quirk *quirk;
int line[0];
};
@@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
- if (!priv->remapped_bar[bar])
+ if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
@@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
*/
pcibios_resource_to_bus(dev->bus, &region, &dev->resource[bar]);
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
- | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+ | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
writel(device_window, p + MITE_IOWBSR1);
/* Set window access to go to RAMSEL IO address space */
@@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
unsigned int pi;
unsigned short sub_serports;
- pi = (c & 0xff);
+ pi = c & 0xff;
- if (pi == 2) {
+ if (pi == 2)
return 1;
- } else if ((pi == 0) &&
- (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
/* two possibilities: 0x30ps encodes number of parallel and
* serial ports, or 0x1000 indicates *something*. This is not
* immediately obvious, since the 2s1p+4s configuration seems
@@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
* advertising the same function 3 as the 4s+2s1p config.
*/
sub_serports = dev->subsystem_device & 0xf;
- if (sub_serports > 0) {
+ if (sub_serports > 0)
return sub_serports;
- } else {
- dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
- return 0;
- }
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
}
moan_device("unknown NetMos/Mostech program interface", dev);
@@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev)
return 0;
switch (dev->device) { /* FALLTHROUGH on all */
- case PCI_DEVICE_ID_NETMOS_9904:
- case PCI_DEVICE_ID_NETMOS_9912:
- case PCI_DEVICE_ID_NETMOS_9922:
- case PCI_DEVICE_ID_NETMOS_9900:
- num_serial = pci_netmos_9900_numports(dev);
- break;
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
- default:
- if (num_serial == 0 ) {
- moan_device("unknown NetMos/Mostech device", dev);
- }
+ default:
+ break;
}
- if (num_serial == 0)
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
return -ENODEV;
+ }
return num_serial;
}
@@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port)
static int pci_quatech_test(struct uart_8250_port *port)
{
- u8 reg;
- u8 qopr = pci_quatech_rqopr(port);
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
reg = pci_quatech_rqopr(port) & 0xC0;
if (reg != QPCR_TEST_GET1)
@@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev)
unsigned long base = pci_resource_start(dev, 0);
if (base) {
u32 tmp;
+
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
tmp = inl(base + 0x3c);
outl(tmp | 0x01000000, base + 0x3c);
@@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-static int pci_pericom_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- unsigned int bar, offset = board->first_offset, maxnr;
-
- bar = FL_GET_BASE(board->flags);
- if (board->flags & FL_BASE_BARS)
- bar += idx;
- else
- offset += idx * board->uart_offset;
-
- maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
- (board->reg_shift + 3);
-
- if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
- return 1;
-
- port->port.uartclk = 14745600;
-
- return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1401,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
unsigned long m, n;
u32 reg;
+ /* Gracefully handle the B0 case: fall back to B9600 */
+ fuart = fuart ? fuart : 9600 * 16;
+
/* Get Fuart closer to Fref */
fuart *= rounddown_pow_of_two(fref / fuart);
@@ -1541,10 +1520,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
static int pci_fintek_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
+ struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
u8 *index = (u8 *) port->private_data;
- struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
- dev);
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
@@ -1766,7 +1744,7 @@ xr17v35x_has_slave(struct serial_private *priv)
const int dev_id = priv->dev->device;
return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
- (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
}
static int
@@ -1866,8 +1844,8 @@ pci_fastcom335_setup(struct serial_private *priv,
static int
pci_wch_ch353_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
@@ -1876,8 +1854,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
static int
pci_wch_ch38x_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16850;
@@ -2246,16 +2224,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.exit = pci_plx9050_exit,
},
/*
- * Pericom
- */
- {
- .vendor = PCI_VENDOR_ID_PERICOM,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
- },
- /*
* PLX
*/
{
@@ -3733,15 +3701,10 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
- /*
- * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
- * but is overridden by byt_set_termios.
- */
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
- .uart_offset = 0x80,
.reg_shift = 2,
},
[pbn_qrk] = {
@@ -3840,6 +3803,20 @@ static const struct pci_device_id blacklist[] = {
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
+ /* Moxa Smartio MUE boards handled by 8250_moxa */
+ { PCI_VDEVICE(MOXA, 0x1024), },
+ { PCI_VDEVICE(MOXA, 0x1025), },
+ { PCI_VDEVICE(MOXA, 0x1045), },
+ { PCI_VDEVICE(MOXA, 0x1144), },
+ { PCI_VDEVICE(MOXA, 0x1160), },
+ { PCI_VDEVICE(MOXA, 0x1161), },
+ { PCI_VDEVICE(MOXA, 0x1182), },
+ { PCI_VDEVICE(MOXA, 0x1183), },
+ { PCI_VDEVICE(MOXA, 0x1322), },
+ { PCI_VDEVICE(MOXA, 0x1342), },
+ { PCI_VDEVICE(MOXA, 0x1381), },
+ { PCI_VDEVICE(MOXA, 0x1683), },
+
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), },
{ PCI_VDEVICE(INTEL, 0x081c), },
@@ -4027,12 +4004,6 @@ void pciserial_remove_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
- for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
- if (priv->remapped_bar[i])
- iounmap(priv->remapped_bar[i]);
- priv->remapped_bar[i] = NULL;
- }
-
/*
* Find the exit quirks.
*/
@@ -4104,7 +4075,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data];
- rc = pci_enable_device(dev);
+ rc = pcim_enable_device(dev);
pci_save_state(dev);
if (rc)
return rc;
@@ -4123,7 +4094,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
*/
rc = serial_pci_guess_board(dev, &tmp);
if (rc)
- goto disable;
+ return rc;
} else {
/*
* We matched an explicit entry. If we are able to
@@ -4139,16 +4110,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
}
priv = pciserial_init_ports(dev, board);
- if (!IS_ERR(priv)) {
- pci_set_drvdata(dev, priv);
- return 0;
- }
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
- rc = PTR_ERR(priv);
-
- disable:
- pci_disable_device(dev);
- return rc;
+ pci_set_drvdata(dev, priv);
+ return 0;
}
static void pciserial_remove_one(struct pci_dev *dev)
@@ -4156,8 +4122,6 @@ static void pciserial_remove_one(struct pci_dev *dev)
struct serial_private *priv = pci_get_drvdata(dev);
pciserial_remove_ports(priv);
-
- pci_disable_device(dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -4538,7 +4502,7 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
- PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_1152000 },
/*
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 658b392d1..34f05ed78 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Fujitsu Wacom 1FGT Tablet PC device */
{ "FUJ02E9", 0 },
/*
- * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
- * disguise)
+ * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
+ * in disguise).
*/
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
@@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
- /* Winbond CIR port, should not be probed. We should keep track
- of it to prevent the legacy serial driver from probing it */
+ /*
+ * Winbond CIR port, should not be probed. We should keep track of
+ * it to prevent the legacy serial driver from probing it.
+ */
{ "WEC1022", CIR_PORT },
/*
- * SMSC IrCC SIR/FIR port, should not be probed by serial driver
- * as well so its own driver can bind to it.
+ * SMSC IrCC SIR/FIR port, should not be probed by serial driver as
+ * well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 }
@@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-static char *modem_names[] = {
+static const char *modem_names[] = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
};
-static int check_name(char *name)
+static bool check_name(const char *name)
{
- char **tmp;
+ const char **tmp;
for (tmp = modem_names; *tmp; tmp++)
if (strstr(name, *tmp))
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int check_resources(struct pnp_dev *dev)
+static bool check_resources(struct pnp_dev *dev)
{
- resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
- int i;
+ static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(base); i++) {
if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev)
static int serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
- (dev->card && check_name(dev->card->name))))
- return -ENODEV;
+ (dev->card && check_name(dev->card->name))))
+ return -ENODEV;
if (check_resources(dev))
return 0;
@@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
} else
return -ENODEV;
-#ifdef SERIAL_DEBUG_PNP
- printk(KERN_DEBUG
- "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
-#endif
+ dev_dbg(&dev->dev,
+ "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
+ uart.port.iobase, &uart.port.mapbase,
+ uart.port.irq, uart.port.iotype);
+
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index b1a6ba3c3..4743075ae 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -52,7 +53,7 @@
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Here we define the default xmit fifo size used for each type of UART.
@@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
-/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
-workaround of errata A-008006 which states that tx_loadsz should be
-configured less than Maximum supported fifo bytes */
+ /*
+ * tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+ * workaround of errata A-008006 which states that tx_loadsz should
+ * be configured less than Maximum supported fifo bytes.
+ */
[PORT_16550A_FSL64] = {
.name = "16550A_FSL64",
.fifo_size = 64,
@@ -522,6 +525,20 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
+{
+ unsigned char mcr = serial_in(p, UART_MCR);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(p, UART_MCR, mcr);
+}
+
+static void serial8250_em485_handle_start_tx(unsigned long arg);
+static void serial8250_em485_handle_stop_tx(unsigned long arg);
+
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
serial8250_clear_fifos(p);
@@ -546,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
+/**
+ * serial8250_em485_init() - put uart_8250_port into rs485 emulating
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to start rs485 software emulating on the
+ * &struct uart_8250_port* @p. Namely, RTS is switched before/after
+ * transmission. The function is idempotent, so it is safe to call it
+ * multiple times.
+ *
+ * The caller MUST enable interrupt on empty shift register before
+ * calling serial8250_em485_init(). This interrupt is not a part of
+ * 8250 standard, but implementation defined.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_destroy()
+ *
+ * Return 0 - success, -errno - otherwise
+ */
+int serial8250_em485_init(struct uart_8250_port *p)
+{
+ if (p->em485 != NULL)
+ return 0;
+
+ p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
+ if (p->em485 == NULL)
+ return -ENOMEM;
+
+ setup_timer(&p->em485->stop_tx_timer,
+ serial8250_em485_handle_stop_tx, (unsigned long)p);
+ setup_timer(&p->em485->start_tx_timer,
+ serial8250_em485_handle_start_tx, (unsigned long)p);
+ p->em485->active_timer = NULL;
+
+ serial8250_em485_rts_after_send(p);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_init);
+
+/**
+ * serial8250_em485_destroy() - put uart_8250_port into normal state
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to stop rs485 software emulating on the
+ * &struct uart_8250_port* @p. The function is idempotent, so it is safe to
+ * call it multiple times.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_init()
+ */
+void serial8250_em485_destroy(struct uart_8250_port *p)
+{
+ if (p->em485 == NULL)
+ return;
+
+ del_timer(&p->em485->start_tx_timer);
+ del_timer(&p->em485->stop_tx_timer);
+
+ kfree(p->em485);
+ p->em485 = NULL;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -1232,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up)
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
if (up->capabilities != old_capabilities) {
- printk(KERN_WARNING
- "ttyS%d: detected caps %08x should be %08x\n",
+ pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
up->capabilities);
}
@@ -1298,7 +1381,78 @@ static void autoconfig_irq(struct uart_8250_port *up)
port->irq = (irq > 0) ? irq : 0;
}
-static inline void __stop_tx(struct uart_8250_port *p)
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
+}
+
+static void __do_stop_tx_rs485(struct uart_8250_port *p)
+{
+ if (!p->em485)
+ return;
+
+ serial8250_em485_rts_after_send(p);
+ /*
+ * Empty the RX FIFO, we are not interested in anything
+ * received during the half-duplex transmission.
+ * Enable previously disabled RX interrupts.
+ */
+ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+ serial8250_clear_fifos(p);
+
+ serial8250_rpm_get(p);
+
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_port_out(&p->port, UART_IER, p->ier);
+
+ serial8250_rpm_put(p);
+ }
+}
+
+static void serial8250_em485_handle_stop_tx(unsigned long arg)
+{
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->stop_tx_timer) {
+ __do_stop_tx_rs485(p);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
+static void __stop_tx_rs485(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (!em485)
+ return;
+
+ /*
+ * __do_stop_tx_rs485 is going to set RTS according to config
+ * AND flush RX FIFO if required.
+ */
+ if (p->port.rs485.delay_rts_after_send > 0) {
+ em485->active_timer = &em485->stop_tx_timer;
+ mod_timer(&em485->stop_tx_timer, jiffies +
+ p->port.rs485.delay_rts_after_send * HZ / 1000);
+ } else {
+ __do_stop_tx_rs485(p);
+ }
+}
+
+static inline void __do_stop_tx(struct uart_8250_port *p)
{
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
@@ -1307,6 +1461,28 @@ static inline void __stop_tx(struct uart_8250_port *p)
}
}
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (em485) {
+ unsigned char lsr = serial_in(p, UART_LSR);
+ /*
+ * To provide required timeing and allow FIFO transfer,
+ * __stop_tx_rs485 must be called only when both FIFO and
+ * shift register are empty. It is for device driver to enable
+ * interrupt on TEMT.
+ */
+ if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+ return;
+
+ del_timer(&em485->start_tx_timer);
+ em485->active_timer = NULL;
+ }
+ __do_stop_tx(p);
+ __stop_tx_rs485(p);
+}
+
static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -1324,12 +1500,10 @@ static void serial8250_stop_tx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void serial8250_start_tx(struct uart_port *port)
+static inline void __start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- serial8250_rpm_get_tx(up);
-
if (up->dma && !up->dma->tx_dma(up))
return;
@@ -1339,6 +1513,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr;
+
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (lsr & UART_LSR_THRE)
@@ -1355,33 +1530,83 @@ static void serial8250_start_tx(struct uart_port *port)
}
}
-static void serial8250_throttle(struct uart_port *port)
+static inline void start_tx_rs485(struct uart_port *port)
{
- port->throttle(port);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+ unsigned char mcr;
+
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_stop_rx(&up->port);
+
+ del_timer(&em485->stop_tx_timer);
+ em485->active_timer = NULL;
+
+ mcr = serial_in(up, UART_MCR);
+ if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
+ !!(mcr & UART_MCR_RTS)) {
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(up, UART_MCR, mcr);
+
+ if (up->port.rs485.delay_rts_before_send > 0) {
+ em485->active_timer = &em485->start_tx_timer;
+ mod_timer(&em485->start_tx_timer, jiffies +
+ up->port.rs485.delay_rts_before_send * HZ / 1000);
+ return;
+ }
+ }
+
+ __start_tx(port);
}
-static void serial8250_unthrottle(struct uart_port *port)
+static void serial8250_em485_handle_start_tx(unsigned long arg)
{
- port->unthrottle(port);
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer) {
+ __start_tx(&p->port);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
}
-static void serial8250_stop_rx(struct uart_port *port)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
- serial8250_rpm_get(up);
+ serial8250_rpm_get_tx(up);
- up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_port_out(port, UART_IER, up->ier);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer)
+ return;
- serial8250_rpm_put(up);
+ if (em485)
+ start_tx_rs485(port);
+ else
+ __start_tx(port);
+}
+
+static void serial8250_throttle(struct uart_port *port)
+{
+ port->throttle(port);
+}
+
+static void serial8250_unthrottle(struct uart_port *port)
+{
+ port->unthrottle(port);
}
static void serial8250_disable_ms(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1406,81 +1631,85 @@ static void serial8250_enable_ms(struct uart_port *port)
serial8250_rpm_put(up);
}
+static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
+{
+ struct uart_port *port = &up->port;
+ unsigned char ch;
+ char flag = TTY_NORMAL;
+
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+ else
+ /*
+ * Intel 82571 has a Serial Over Lan device that will
+ * set UART_LSR_BI without setting UART_LSR_DR when
+ * it receives a break. To avoid reading from the
+ * receive buffer without UART_LSR_DR bit set, we
+ * just force the read character to be 0
+ */
+ ch = 0;
+
+ port->icount.rx++;
+
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
+
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+ if (lsr & UART_LSR_BI) {
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ 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(port))
+ return;
+ } else if (lsr & UART_LSR_PE)
+ port->icount.parity++;
+ else if (lsr & UART_LSR_FE)
+ port->icount.frame++;
+ if (lsr & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ lsr &= port->read_status_mask;
+
+ if (lsr & UART_LSR_BI) {
+ DEBUG_INTR("handling break....");
+ 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(port, ch))
+ return;
+
+ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+}
+
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
*/
-unsigned char
-serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{
struct uart_port *port = &up->port;
- unsigned char ch;
int max_count = 256;
- char flag;
do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- else
- /*
- * Intel 82571 has a Serial Over Lan device that will
- * set UART_LSR_BI without setting UART_LSR_DR when
- * it receives a break. To avoid reading from the
- * receive buffer without UART_LSR_DR bit set, we
- * just force the read character to be 0
- */
- ch = 0;
-
- flag = TTY_NORMAL;
- port->icount.rx++;
-
- lsr |= up->lsr_saved_flags;
- up->lsr_saved_flags = 0;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- 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(port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE)
- port->icount.parity++;
- else if (lsr & UART_LSR_FE)
- port->icount.frame++;
- if (lsr & UART_LSR_OE)
- port->icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= port->read_status_mask;
-
- if (lsr & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
- 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(port, ch))
- goto ignore_char;
-
- uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
+ serial8250_read_char(up, lsr);
+ if (--max_count == 0)
+ break;
lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
- spin_unlock(&port->lock);
+ } while (lsr & (UART_LSR_DR | UART_LSR_BI));
+
tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
return lsr;
}
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
@@ -1513,11 +1742,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
- if (up->capabilities & UART_CAP_HFIFO) {
- if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
- BOTH_EMPTY)
- break;
- }
+ if ((up->capabilities & UART_CAP_HFIFO) &&
+ (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
+ break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1746,6 +1973,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
+
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@@ -1979,23 +2207,23 @@ int serial8250_do_startup(struct uart_port *port)
serial8250_set_mctrl(port, port->mctrl);
- /* Serial over Lan (SoL) hack:
- Intel 8257x Gigabit ethernet chips have a
- 16550 emulation, to be used for Serial Over Lan.
- Those chips take a longer time than a normal
- serial device to signalize that a transmission
- data was queued. Due to that, the above test generally
- fails. One solution would be to delay the reading of
- iir. However, this is not reliable, since the timeout
- is variable. So, let's just don't test if we receive
- TX irq. This way, we'll never enable UART_BUG_TXEN.
+ /*
+ * Serial over Lan (SoL) hack:
+ * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
+ * used for Serial Over Lan. Those chips take a longer time than a
+ * normal serial device to signalize that a transmission data was
+ * queued. Due to that, the above test generally fails. One solution
+ * would be to delay the reading of iir. However, this is not
+ * reliable, since the timeout is variable. So, let's just don't
+ * test if we receive TX irq. This way, we'll never enable
+ * UART_BUG_TXEN.
*/
if (up->port.flags & UPF_NO_TXEN_TEST)
goto dont_test_tx_en;
/*
- * Do a quick test to see if we receive an
- * interrupt when we enable the TX irq.
+ * Do a quick test to see if we receive an interrupt when we enable
+ * the TX irq.
*/
serial_port_out(port, UART_IER, UART_IER_THRI);
lsr = serial_port_in(port, UART_LSR);
@@ -2078,8 +2306,12 @@ void serial8250_do_shutdown(struct uart_port *port)
/*
* Disable interrupts from this port
*/
+ spin_lock_irqsave(&port->lock, flags);
up->ier = 0;
serial_port_out(port, UART_IER, 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ synchronize_irq(port->irq);
if (up->dma)
serial8250_release_dma(up);
@@ -2245,9 +2477,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac);
}
-static unsigned int
-serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static unsigned int serial8250_get_baud_rate(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int tolerance = port->uartclk / 100;
@@ -2264,7 +2496,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+ struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
@@ -2577,8 +2809,7 @@ static int do_get_rxtrig(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
return -EINVAL;
@@ -2614,8 +2845,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
int rxtrig;
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
@@ -2739,8 +2969,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
-static const char *
-serial8250_type(struct uart_port *port)
+static const char *serial8250_type(struct uart_port *port)
{
int type = port->type;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index bab6b3ae2..1b7bd2655 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -35,7 +35,7 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock;
};
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init uniphier_early_console_setup(struct earlycon_device *device,
const char *options)
{
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index b03cb5175..4d7cb9c04 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -262,7 +262,12 @@ config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
- ::: To be written :::
+ Say Y here if you have a IODATA RSA-DV II/S ISA card and
+ would like to use its >115kbps speeds.
+ You will need to provide module parameter "probe_rsa", or boot-time
+ parameter 8250.probe_rsa with I/O addresses of this card then.
+
+ If you don't have such card, or if unsure, say N.
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
@@ -272,6 +277,30 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+config SERIAL_8250_BCM2835AUX
+ tristate "BCM2835 auxiliar mini UART support"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
+ help
+ Support for the BCM2835 auxiliar mini UART.
+
+ Features and limitations of the UART are
+ Registers are similar to 16650 registers,
+ set bits in the control registers that are unsupported
+ are ignored and read back as 0
+ 7/8 bit operation with 1 start and 1 stop bit
+ 8 symbols deep fifo for rx and tx
+ SW controlled RTS and SW readable CTS
+ Clock rate derived from system clock
+ Uses 8 times oversampling (compared to 16 times for 16650)
+ Missing break detection (but break generation)
+ Missing framing error detection
+ Missing parity bit
+ Missing receive time-out interrupt
+ Missing DCD, DSR, DTR and RI signals
+
+ If unsure, say N.
+
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE
@@ -346,7 +375,7 @@ config SERIAL_8250_LPC18XX
serial port, say Y to this option. If unsure, say Y.
config SERIAL_8250_MT6577
- bool "Mediatek serial port support"
+ tristate "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
@@ -360,9 +389,10 @@ config SERIAL_8250_UNIPHIER
serial ports, say Y to this option. If unsure, say N.
config SERIAL_8250_INGENIC
- bool "Support for Ingenic SoC serial ports"
- depends on OF_FLATTREE
- select LIBFDT
+ tristate "Support for Ingenic SoC serial ports"
+ depends on SERIAL_8250
+ depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
+ depends on MIPS || COMPILE_TEST
help
If you have a system using an Ingenic SoC and wish to make use of
its UARTs, say Y to this option. If unsure, say N.
@@ -378,6 +408,16 @@ config SERIAL_8250_MID
present on the UART found on Intel Medfield SOC and various other
Intel platforms.
+config SERIAL_8250_MOXA
+ tristate "MOXA SmartIO MUE support"
+ depends on SERIAL_8250 && PCI
+ help
+ Say Y here if you have a Moxa SmartIO MUE multiport serial card.
+ If unsure, say N.
+
+ This driver can also be built as a module. The module will be called
+ 8250_moxa. If you want to do that, say M here.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index b9b9bca5b..c9a2d6ed8 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
@@ -28,6 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
+obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 4d180c942..933c2688d 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = {
};
-static int serial_config(struct pcmcia_device * link);
+static int serial_config(struct pcmcia_device *link);
static void serial_remove(struct pcmcia_device *link)
@@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link)
dev_dbg(&link->dev, "serial_attach()\n");
/* Create new serial device */
- info = kzalloc(sizeof (*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->p_dev = link;
@@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link)
/*====================================================================*/
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
@@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* First pass: look for a config entry that looks normal.
- * Two tries: without IO aliases, then with aliases */
+ /*
+ * First pass: look for a config entry that looks normal.
+ * Two tries: without IO aliases, then with aliases.
+ */
link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
+ /*
+ * Second pass: try to find an entry that isn't picky about
+ * its base address, then try to grab any standard serial port
+ * address, and finally try to get any free port.
+ */
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
@@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
if (p_dev->resource[1]->end)
return -EINVAL;
- /* The quad port cards have bad CIS's, so just look for a
- window larger than 8 ports and assume it will be right */
+ /*
+ * The quad port cards have bad CIS's, so just look for a
+ * window larger than 8 ports and assume it will be right.
+ */
if (p_dev->resource[0]->end <= 8)
return -EINVAL;
@@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link)
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- dev_warn(&link->dev, "no usable port range "
- "found, giving up\n");
+ dev_warn(&link->dev,
+ "no usable port range found, giving up\n");
return -ENODEV;
}
}
@@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
}
-static int serial_config(struct pcmcia_device * link)
+static int serial_config(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
int i;
@@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link)
break;
}
- /* Another check for dual-serial cards: look for either serial or
- multifunction cards that ask for appropriate IO port ranges */
+ /*
+ * Another check for dual-serial cards: look for either serial or
+ * multifunction cards that ask for appropriate IO port ranges.
+ */
if ((info->multi == 0) &&
(link->has_func_id) &&
(link->socket->pcmcia_pfc == 0) &&
@@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
- PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
@@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 39721ec4f..13d4ed6ca 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -610,6 +610,7 @@ config SERIAL_UARTLITE_CONSOLE
bool "Support for console on Xilinx uartlite serial port"
depends on SERIAL_UARTLITE=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Say Y here if you wish to use a Xilinx uartlite as the system
console (the system console is the device which receives all kernel
@@ -732,7 +733,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
+ depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -745,6 +746,12 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
+config SERIAL_SH_SCI_EARLYCON
+ bool "Support for early console on SuperH SCI(F)"
+ depends on SERIAL_SH_SCI=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+
config SERIAL_SH_SCI_DMA
bool "DMA support"
depends on SERIAL_SH_SCI && DMA_ENGINE
@@ -793,17 +800,6 @@ config SERIAL_CORE_CONSOLE
config CONSOLE_POLL
bool
-config SERIAL_68328
- bool "68328 serial support"
- depends on M68328 || M68EZ328 || M68VZ328
- help
- This driver supports the built-in serial port of the Motorola 68328
- (standard, EZ and VZ varieties).
-
-config SERIAL_68328_RTS_CTS
- bool "Support RTS/CTS on 68328 serial port"
- depends on SERIAL_68328
-
config SERIAL_MCF
bool "Coldfire serial support"
depends on COLDFIRE
@@ -1606,6 +1602,28 @@ config SERIAL_STM32_CONSOLE
depends on SERIAL_STM32=y
select SERIAL_CORE_CONSOLE
+config SERIAL_MVEBU_UART
+ bool "Marvell EBU serial port support"
+ select SERIAL_CORE
+ help
+ This driver is for Marvell EBU SoC's UART. If you have a machine
+ based on the Armada-3700 SoC and wish to use the on-board serial
+ port,
+ say 'Y' here.
+ Otherwise, say 'N'.
+
+config SERIAL_MVEBU_CONSOLE
+ bool "Console on Marvell EBU serial port"
+ depends on SERIAL_MVEBU_UART
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ default y
+ help
+ Say 'Y' here if you wish to use Armada-3700 UART as the system console.
+ (the system console is the device which receives all kernel messages
+ and warnings and which allows logins in single user mode)
+ Otherwise, say 'N'.
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index b391c9b31..8c261adac 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
-obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
@@ -91,6 +90,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
+obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c0da0ccbb..7c198e0a3 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -187,7 +187,7 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
[REG_DMACR] = ZX_UART011_DMACR,
};
-static struct vendor_data vendor_zte = {
+static struct vendor_data vendor_zte __maybe_unused = {
.reg_offset = pl011_zte_offsets,
.access_32b = true,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
@@ -420,7 +420,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
- if (!chan && plat->dma_rx_param) {
+ if (!chan && plat && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
if (!chan) {
@@ -1167,7 +1167,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
/* Disable RX and TX DMA */
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
- barrier();
+ cpu_relax();
spin_lock_irq(&uap->port.lock);
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
@@ -1611,7 +1611,7 @@ static void pl011_put_poll_char(struct uart_port *port,
container_of(port, struct uart_amba_port, port);
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
- barrier();
+ cpu_relax();
pl011_write(ch, uap, REG_DR);
}
@@ -1947,6 +1947,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
+ if (termios->c_cflag & CMSPAR)
+ lcr_h |= UART011_LCRH_SPS;
}
if (uap->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
@@ -2150,7 +2152,7 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
container_of(port, struct uart_amba_port, port);
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
- barrier();
+ cpu_relax();
pl011_write(ch, uap, REG_DR);
}
@@ -2158,7 +2160,7 @@ static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int status, old_cr = 0, new_cr;
+ unsigned int old_cr = 0, new_cr;
unsigned long flags;
int locked = 1;
@@ -2188,9 +2190,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
- do {
- status = pl011_read(uap, REG_FR);
- } while (status & UART01x_FR_BUSY);
+ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
+ cpu_relax();
if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR);
@@ -2302,13 +2303,13 @@ static struct console amba_console = {
static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
- ;
+ cpu_relax();
if (port->iotype == UPIO_MEM32)
writel(c, port->membase + UART01x_DR);
else
writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
- ;
+ cpu_relax();
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
@@ -2327,7 +2328,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
device->con->write = pl011_early_write;
return 0;
}
-EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 03ebe401f..3a1de5c87 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
dev->con->write = arc_early_serial_write;
return 0;
}
-EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 1c0884d8e..954941dd8 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -159,8 +159,9 @@ struct atmel_uart_port {
u32 rts_high;
u32 rts_low;
bool ms_irq_enabled;
- bool is_usart; /* usart or uart */
- struct timer_list uart_timer; /* uart timer */
+ u32 rtor; /* address of receiver timeout register if it exists */
+ bool has_hw_timer;
+ struct timer_list uart_timer;
bool suspended;
unsigned int pending;
@@ -273,6 +274,13 @@ static bool atmel_use_dma_rx(struct uart_port *port)
return atmel_port->use_dma_rx;
}
+static bool atmel_use_fifo(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->fifo_size;
+}
+
static unsigned int atmel_get_lines_status(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -1710,19 +1718,24 @@ static void atmel_get_ip_name(struct uart_port *port)
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int name = atmel_uart_readl(port, ATMEL_US_NAME);
u32 version;
- int usart, uart;
- /* usart and uart ascii */
- usart = 0x55534152;
- uart = 0x44424755;
-
- atmel_port->is_usart = false;
-
- if (name == usart) {
- dev_dbg(port->dev, "This is usart\n");
- atmel_port->is_usart = true;
- } else if (name == uart) {
- dev_dbg(port->dev, "This is uart\n");
- atmel_port->is_usart = false;
+ u32 usart, dbgu_uart, new_uart;
+ /* ASCII decoding for IP version */
+ usart = 0x55534152; /* USAR(T) */
+ dbgu_uart = 0x44424755; /* DBGU */
+ new_uart = 0x55415254; /* UART */
+
+ atmel_port->has_hw_timer = false;
+
+ if (name == new_uart) {
+ dev_dbg(port->dev, "Uart with hw timer");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_UA_RTOR;
+ } else if (name == usart) {
+ dev_dbg(port->dev, "Usart\n");
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
+ } else if (name == dbgu_uart) {
+ dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else {
/* fallback for older SoCs: use version field */
version = atmel_uart_readl(port, ATMEL_US_VERSION);
@@ -1730,12 +1743,12 @@ static void atmel_get_ip_name(struct uart_port *port)
case 0x302:
case 0x10213:
dev_dbg(port->dev, "This version is usart\n");
- atmel_port->is_usart = true;
+ atmel_port->has_hw_timer = true;
+ atmel_port->rtor = ATMEL_US_RTOR;
break;
case 0x203:
case 0x10202:
dev_dbg(port->dev, "This version is uart\n");
- atmel_port->is_usart = false;
break;
default:
dev_err(port->dev, "Not supported ip name nor version, set to uart\n");
@@ -1835,12 +1848,13 @@ static int atmel_startup(struct uart_port *port)
if (atmel_use_pdc_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -1850,12 +1864,13 @@ static int atmel_startup(struct uart_port *port)
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
} else if (atmel_use_dma_rx(port)) {
/* set UART timeout */
- if (!atmel_port->is_usart) {
+ if (!atmel_port->has_hw_timer) {
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
} else {
- atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
+ atmel_uart_writel(port, atmel_port->rtor,
+ PDC_RX_TIMEOUT);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
atmel_uart_writel(port, ATMEL_US_IER,
@@ -2082,7 +2097,12 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
mode |= ATMEL_US_USMODE_RS485;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
- mode |= ATMEL_US_USMODE_HWHS;
+ if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
+ dev_info(port->dev, "not enabling hardware flow control because DMA is used");
+ termios->c_cflag &= ~CRTSCTS;
+ } else {
+ mode |= ATMEL_US_USMODE_HWHS;
+ }
} else {
/* RS232 without hadware handshake */
mode |= ATMEL_US_USMODE_NORMAL;
@@ -2478,13 +2498,13 @@ static int __init atmel_console_init(void)
struct atmel_uart_data *pdata =
dev_get_platdata(&atmel_default_console_device->dev);
int id = pdata->num;
- struct atmel_uart_port *port = &atmel_ports[id];
+ struct atmel_uart_port *atmel_port = &atmel_ports[id];
- port->backup_imr = 0;
- port->uart.line = id;
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
- ret = atmel_init_port(port, atmel_default_console_device);
+ ret = atmel_init_port(atmel_port, atmel_default_console_device);
if (ret)
return ret;
register_console(&atmel_console);
@@ -2599,23 +2619,23 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
-static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
+static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
- port->fifo_size = 0;
- port->rts_low = 0;
- port->rts_high = 0;
+ atmel_port->fifo_size = 0;
+ atmel_port->rts_low = 0;
+ atmel_port->rts_high = 0;
if (of_property_read_u32(pdev->dev.of_node,
"atmel,fifo-size",
- &port->fifo_size))
+ &atmel_port->fifo_size))
return;
- if (!port->fifo_size)
+ if (!atmel_port->fifo_size)
return;
- if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
- port->fifo_size = 0;
+ if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
+ atmel_port->fifo_size = 0;
dev_err(&pdev->dev, "Invalid FIFO size\n");
return;
}
@@ -2628,22 +2648,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
* Threshold to a reasonably high value respecting this 16 data
* empirical rule when possible.
*/
- port->rts_high = max_t(int, port->fifo_size >> 1,
- port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
- port->rts_low = max_t(int, port->fifo_size >> 2,
- port->fifo_size - ATMEL_RTS_LOW_OFFSET);
+ atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1,
+ atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
+ atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2,
+ atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET);
dev_info(&pdev->dev, "Using FIFO (%u data)\n",
- port->fifo_size);
+ atmel_port->fifo_size);
dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n",
- port->rts_high);
+ atmel_port->rts_high);
dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n",
- port->rts_low);
+ atmel_port->rts_low);
}
static int atmel_serial_probe(struct platform_device *pdev)
{
- struct atmel_uart_port *port;
+ struct atmel_uart_port *atmel_port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
void *data;
@@ -2674,99 +2694,133 @@ static int atmel_serial_probe(struct platform_device *pdev)
goto err;
}
- port = &atmel_ports[ret];
- port->backup_imr = 0;
- port->uart.line = ret;
- atmel_serial_probe_fifos(port, pdev);
+ atmel_port = &atmel_ports[ret];
+ atmel_port->backup_imr = 0;
+ atmel_port->uart.line = ret;
+ atmel_serial_probe_fifos(atmel_port, pdev);
- spin_lock_init(&port->lock_suspended);
+ spin_lock_init(&atmel_port->lock_suspended);
- ret = atmel_init_port(port, pdev);
+ ret = atmel_init_port(atmel_port, pdev);
if (ret)
goto err_clear_bit;
- port->gpios = mctrl_gpio_init(&port->uart, 0);
- if (IS_ERR(port->gpios)) {
- ret = PTR_ERR(port->gpios);
+ atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0);
+ if (IS_ERR(atmel_port->gpios)) {
+ ret = PTR_ERR(atmel_port->gpios);
goto err_clear_bit;
}
- if (!atmel_use_pdc_rx(&port->uart)) {
+ if (!atmel_use_pdc_rx(&atmel_port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
if (!data)
goto err_alloc_ring;
- port->rx_ring.buf = data;
+ atmel_port->rx_ring.buf = data;
}
- rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
+ rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED;
- ret = uart_add_one_port(&atmel_uart, &port->uart);
+ ret = uart_add_one_port(&atmel_uart, &atmel_port->uart);
if (ret)
goto err_add_port;
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
- if (atmel_is_console_port(&port->uart)
+ if (atmel_is_console_port(&atmel_port->uart)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
* The serial core enabled the clock for us, so undo
* the clk_prepare_enable() in atmel_console_setup()
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
}
#endif
device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
+ platform_set_drvdata(pdev, atmel_port);
/*
* The peripheral clock has been disabled by atmel_init_port():
* enable it before accessing I/O registers
*/
- clk_prepare_enable(port->clk);
+ clk_prepare_enable(atmel_port->clk);
if (rs485_enabled) {
- atmel_uart_writel(&port->uart, ATMEL_US_MR,
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR,
ATMEL_US_USMODE_NORMAL);
- atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN);
+ atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR,
+ ATMEL_US_RTSEN);
}
/*
* Get port name of usart or uart
*/
- atmel_get_ip_name(&port->uart);
+ atmel_get_ip_name(&atmel_port->uart);
/*
* The peripheral clock can now safely be disabled till the port
* is used
*/
- clk_disable_unprepare(port->clk);
+ clk_disable_unprepare(atmel_port->clk);
return 0;
err_add_port:
- kfree(port->rx_ring.buf);
- port->rx_ring.buf = NULL;
+ kfree(atmel_port->rx_ring.buf);
+ atmel_port->rx_ring.buf = NULL;
err_alloc_ring:
- if (!atmel_is_console_port(&port->uart)) {
- clk_put(port->clk);
- port->clk = NULL;
+ if (!atmel_is_console_port(&atmel_port->uart)) {
+ clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
}
err_clear_bit:
- clear_bit(port->uart.line, atmel_ports_in_use);
+ clear_bit(atmel_port->uart.line, atmel_ports_in_use);
err:
return ret;
}
+/*
+ * Even if the driver is not modular, it makes sense to be able to
+ * unbind a device: there can be many bound devices, and there are
+ * situations where dynamic binding and unbinding can be useful.
+ *
+ * For example, a connected device can require a specific firmware update
+ * protocol that needs bitbanging on IO lines, but use the regular serial
+ * port in the normal case.
+ */
+static int atmel_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int ret = 0;
+
+ tasklet_kill(&atmel_port->tasklet);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ ret = uart_remove_one_port(&atmel_uart, port);
+
+ kfree(atmel_port->rx_ring.buf);
+
+ /* "port" is allocated statically, so we shouldn't free it */
+
+ clear_bit(port->line, atmel_ports_in_use);
+
+ clk_put(atmel_port->clk);
+ atmel_port->clk = NULL;
+
+ return ret;
+}
+
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
+ .remove = atmel_serial_remove,
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
.name = "atmel_usart",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
- .suppress_bind_attrs = true,
},
};
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b3a4e0cdd..5beafd2d2 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -450,6 +450,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
struct clps711x_port *s;
struct resource *res;
struct clk *uart_clk;
+ int irq;
if (index < 0 || index >= UART_CLPS711X_NR)
return -EINVAL;
@@ -467,12 +468,13 @@ static int uart_clps711x_probe(struct platform_device *pdev)
if (IS_ERR(s->port.membase))
return PTR_ERR(s->port.membase);
- s->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(s->port.irq))
- return s->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ s->port.irq = irq;
s->rx_irq = platform_get_irq(pdev, 1);
- if (IS_ERR_VALUE(s->rx_irq))
+ if (s->rx_irq < 0)
return s->rx_irq;
if (!np) {
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index f13f2ebd2..c0172bf54 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -1413,9 +1413,8 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
local_irq_restore(flags);
@@ -1436,9 +1435,8 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (tty->termios.c_iflag & IXON ) {
+ if (I_IXON(tty))
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
- }
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
if (!info->uses_dma_out &&
@@ -2968,7 +2966,7 @@ static int rs_raw_write(struct tty_struct *tty,
local_save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
- DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line, "ldisc\n"));
/* The local_irq_disable/restore_flags pairs below are needed
@@ -3161,13 +3159,12 @@ rs_throttle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("throttle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("throttle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_throttle\n"));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@@ -3181,13 +3178,12 @@ rs_unthrottle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- printk("unthrottle %s: %lu....\n", tty_name(tty),
- (unsigned long)tty->ldisc.chars_in_buffer(tty));
+ printk("unthrottle %s ....\n", tty_name(tty));
#endif
- DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc\n"));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios.c_cflag & CRTSCTS) {
+ if (C_CRTSCTS(tty)) {
/* Assert RTS line */
e100_rts(info, 1);
}
@@ -3555,8 +3551,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info);
/* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
+ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
rs_start(tty);
}
@@ -3615,7 +3610,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
local_irq_restore(flags);
return;
}
- info->port.flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@@ -3654,7 +3648,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
schedule_timeout_interruptible(info->port.close_delay);
wake_up_interruptible(&info->port.open_wait);
}
- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
local_irq_restore(flags);
/* port closed */
@@ -3767,9 +3761,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios.c_cflag & CLOCAL) {
- do_clocal = 1;
- }
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index a80cdad11..8a1734357 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -394,7 +394,7 @@ static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
}
static void digicolor_uart_console_write(struct console *co, const char *c,
- unsigned n)
+ unsigned n, unsigned loglevel)
{
struct uart_port *port = digicolor_ports[co->index];
u8 status;
@@ -453,7 +453,7 @@ static struct uart_driver digicolor_uart = {
static int digicolor_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret, index;
+ int irq, ret, index;
struct digicolor_port *dp;
struct resource *res;
struct clk *uart_clk;
@@ -481,9 +481,10 @@ static int digicolor_uart_probe(struct platform_device *pdev)
if (IS_ERR(dp->port.membase))
return PTR_ERR(dp->port.membase);
- dp->port.irq = platform_get_irq(pdev, 0);
- if (IS_ERR_VALUE(dp->port.irq))
- return dp->port.irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ dp->port.irq = irq;
dp->port.iotype = UPIO_MEM;
dp->port.uartclk = clk_get_rate(uart_clk);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 3f2423690..067783f05 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -19,7 +19,8 @@
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
-#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@@ -28,22 +29,15 @@
#include <asm/serial.h>
static struct console early_con = {
- .name = "uart", /* 8250 console switch requires this name */
+ .name = "uart", /* fixed up at earlycon registration */
.flags = CON_PRINTBUFFER | CON_BOOT,
- .index = -1,
+ .index = 0,
};
static struct earlycon_device early_console_dev = {
.con = &early_con,
};
-extern struct earlycon_id __earlycon_table[];
-static const struct earlycon_id __earlycon_table_sentinel
- __used __section(__earlycon_table_end);
-
-static const struct of_device_id __earlycon_of_table_sentinel
- __used __section(__earlycon_of_table_end);
-
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
@@ -61,6 +55,39 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
return base;
}
+static void __init earlycon_init(struct earlycon_device *device,
+ const char *name)
+{
+ struct console *earlycon = device->con;
+ struct uart_port *port = &device->port;
+ const char *s;
+ size_t len;
+
+ /* scan backwards from end of string for first non-numeral */
+ for (s = name + strlen(name);
+ s > name && s[-1] >= '0' && s[-1] <= '9';
+ s--)
+ ;
+ if (*s)
+ earlycon->index = simple_strtoul(s, NULL, 10);
+ len = s - name;
+ strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
+ earlycon->data = &early_console_dev;
+
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
+ port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
+ pr_info("%s%d at MMIO%s %pa (options '%s')\n",
+ earlycon->name, earlycon->index,
+ (port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM16) ? "16" :
+ (port->iotype == UPIO_MEM32) ? "32" : "32be",
+ &port->mapbase, device->options);
+ else
+ pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
+ earlycon->name, earlycon->index,
+ port->iobase, device->options);
+}
+
static int __init parse_options(struct earlycon_device *device, char *options)
{
struct uart_port *port = &device->port;
@@ -97,19 +124,6 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
- port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
- pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- (port->iotype == UPIO_MEM) ? "" :
- (port->iotype == UPIO_MEM16) ? "16" :
- (port->iotype == UPIO_MEM32) ? "32" : "32be",
- (unsigned long long)port->mapbase,
- device->options);
- else
- pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
- port->iobase,
- device->options);
-
return 0;
}
@@ -127,7 +141,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
- early_console_dev.con->data = &early_console_dev;
+ earlycon_init(&early_console_dev, match->name);
err = match->setup(&early_console_dev, buf);
if (err < 0)
return err;
@@ -166,7 +180,7 @@ int __init setup_earlycon(char *buf)
if (early_con.flags & CON_ENABLED)
return -EALREADY;
- for (match = __earlycon_table; match->name[0]; match++) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
size_t len = strlen(match->name);
if (strncmp(buf, match->name, len))
@@ -204,20 +218,62 @@ static int __init param_setup_earlycon(char *buf)
}
early_param("earlycon", param_setup_earlycon);
-int __init of_setup_earlycon(unsigned long addr,
- int (*setup)(struct earlycon_device *, const char *))
+#ifdef CONFIG_OF_EARLY_FLATTREE
+
+int __init of_setup_earlycon(const struct earlycon_id *match,
+ unsigned long node,
+ const char *options)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ const __be32 *val;
+ bool big_endian;
+ u64 addr;
spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
+ addr = of_flat_dt_translate_address(node);
+ if (addr == OF_BAD_ADDR) {
+ pr_warn("[%s] bad address\n", match->name);
+ return -ENXIO;
+ }
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
- port->membase = earlycon_map(addr, SZ_4K);
+ port->membase = earlycon_map(port->mapbase, SZ_4K);
+
+ val = of_get_flat_dt_prop(node, "reg-offset", NULL);
+ if (val)
+ port->mapbase += be32_to_cpu(*val);
+ val = of_get_flat_dt_prop(node, "reg-shift", NULL);
+ if (val)
+ port->regshift = be32_to_cpu(*val);
+ big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
+ (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+ of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
+ val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
+ if (val) {
+ switch (be32_to_cpu(*val)) {
+ case 1:
+ port->iotype = UPIO_MEM;
+ break;
+ case 2:
+ port->iotype = UPIO_MEM16;
+ break;
+ case 4:
+ port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
+ break;
+ default:
+ pr_warn("[%s] unsupported reg-io-width\n", match->name);
+ return -EINVAL;
+ }
+ }
- early_console_dev.con->data = &early_console_dev;
- err = setup(&early_console_dev, NULL);
+ if (options) {
+ strlcpy(early_console_dev.options, options,
+ sizeof(early_console_dev.options));
+ }
+ earlycon_init(&early_console_dev, match->name);
+ err = match->setup(&early_console_dev, options);
if (err < 0)
return err;
if (!early_console_dev.con->write)
@@ -227,3 +283,5 @@ int __init of_setup_earlycon(unsigned long addr,
register_console(early_console_dev.con);
return 0;
}
+
+#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 88246f7e4..2085a6cfa 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -395,8 +395,10 @@ static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
if (h1 == 0 && h2 == 0) {
*received_cts = 0;
+ *more = 0;
return IFX_SPI_HEADER_0;
} else if (h1 == 0xffff && h2 == 0xffff) {
+ *more = 0;
/* spi_slave_cts remains as it was */
return IFX_SPI_HEADER_F;
}
@@ -688,6 +690,7 @@ static void ifx_spi_complete(void *ctx)
ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
(size_t)actual_length);
} else {
+ more = 0;
dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
ifx_dev->spi_msg.status);
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 9362f54c8..231e7d5ca 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2166,7 +2166,8 @@ static int imx_serial_port_suspend(struct device *dev)
uart_suspend_port(&imx_reg, &sport->port);
- return 0;
+ /* Needed to enable clock in suspend_noirq */
+ return clk_prepare(sport->clk_ipg);
}
static int imx_serial_port_resume(struct device *dev)
@@ -2179,6 +2180,8 @@ static int imx_serial_port_resume(struct device *dev)
uart_resume_port(&imx_reg, &sport->port);
+ clk_unprepare(sport->clk_ipg);
+
return 0;
}
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 524e86ab3..c5ddfe542 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -529,7 +529,6 @@ void jsm_input(struct jsm_channel *ch)
int data_len;
unsigned long lock_flags;
int len = 0;
- int n = 0;
int s = 0;
int i = 0;
@@ -569,8 +568,7 @@ void jsm_input(struct jsm_channel *ch)
*If the device is not open, or CREAD is off, flush
*input data and return immediately.
*/
- if (!tp ||
- !(tp->termios.c_cflag & CREAD) ) {
+ if (!tp || !C_CREAD(tp)) {
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n",
@@ -598,16 +596,15 @@ void jsm_input(struct jsm_channel *ch)
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
len = tty_buffer_request_room(port, data_len);
- n = len;
/*
- * n now contains the most amount of data we can copy,
+ * len now contains the most amount of data we can copy,
* bounded either by the flip buffer size or the amount
* of data the card actually has pending...
*/
- while (n) {
+ while (len) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
- s = min(s, n);
+ s = min(s, len);
if (s <= 0)
break;
@@ -638,7 +635,7 @@ void jsm_input(struct jsm_channel *ch)
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
}
tail += s;
- n -= s;
+ len -= s;
/* Flip queue if needed */
tail &= rmask;
}
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 0eeb64f24..68765f7c2 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -47,59 +47,26 @@
#define BAUD_RATE 115200
#include <linux/serial_core.h>
-#include "m32r_sio.h"
#include "m32r_sio_reg.h"
-/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#if 0
-#define DEBUG_INTR(fmt...) printk(fmt)
-#else
-#define DEBUG_INTR(fmt...) do { } while (0)
-#endif
-
#define PASS_LIMIT 256
-#define BASE_BAUD 115200
-
/* Standard COM flags */
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism. Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
+static const struct {
+ unsigned int port;
+ unsigned int irq;
+} old_serial_port[] = {
#if defined(CONFIG_PLAT_USRV)
-
-#define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
-
-#else /* !CONFIG_PLAT_USRV */
-
-#if defined(CONFIG_SERIAL_M32R_PLDSIO)
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
- STD_COM_FLAGS }, /* ttyS0 */
+ /* PORT IRQ FLAGS */
+ { 0x3F8, PLD_IRQ_UART0 }, /* ttyS0 */
+ { 0x2F8, PLD_IRQ_UART1 }, /* ttyS1 */
+#elif defined(CONFIG_SERIAL_M32R_PLDSIO)
+ { ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV }, /* ttyS0 */
#else
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \
- STD_COM_FLAGS }, /* ttyS0 */
+ { M32R_SIO_OFFSET, M32R_IRQ_SIO0_R }, /* ttyS0 */
#endif
-
-#endif /* !CONFIG_PLAT_USRV */
-
-static struct old_serial_port old_serial_port[] = {
- SERIAL_PORT_DFNS
};
#define UART_NR ARRAY_SIZE(old_serial_port)
@@ -108,19 +75,7 @@ struct uart_sio_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
- unsigned short rev;
- unsigned char acr;
unsigned char ier;
- unsigned char lcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
-
- /*
- * We provide a per-port pm hook.
- */
- void (*pm)(struct uart_port *port,
- unsigned int state, unsigned int old);
};
struct irq_info {
@@ -345,14 +300,8 @@ static void receive_chars(struct uart_sio_port *up, int *status)
*/
*status &= up->port.read_status_mask;
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-
if (*status & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
+ pr_debug("handling break....\n");
flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
@@ -413,7 +362,7 @@ static void transmit_chars(struct uart_sio_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- DEBUG_INTR("THRE...");
+ pr_debug("THRE...\n");
if (uart_circ_empty(xmit))
m32r_sio_stop_tx(&up->port);
@@ -425,7 +374,7 @@ static void transmit_chars(struct uart_sio_port *up)
static inline void m32r_sio_handle_port(struct uart_sio_port *up,
unsigned int status)
{
- DEBUG_INTR("status = %x...", status);
+ pr_debug("status = %x...\n", status);
if (status & 0x04)
receive_chars(up, &status);
@@ -453,7 +402,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL;
int pass_counter = 0;
- DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+ pr_debug("m32r_sio_interrupt(%d)...\n", irq);
#ifdef CONFIG_SERIAL_M32R_PLDSIO
// if (irq == PLD_IRQ_SIO0_SND)
@@ -493,7 +442,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
spin_unlock(&i->lock);
- DEBUG_INTR("end.\n");
+ pr_debug("end.\n");
return IRQ_HANDLED;
}
@@ -782,20 +731,9 @@ static void m32r_sio_set_termios(struct uart_port *port,
serial_out(up, UART_IER, up->ier);
- up->lcr = cval; /* Save LCR */
spin_unlock_irqrestore(&up->port.lock, flags);
}
-static void m32r_sio_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- struct uart_sio_port *up =
- container_of(port, struct uart_sio_port, port);
-
- if (up->pm)
- up->pm(port, state, oldstate);
-}
-
/*
* Resource handling. This is complicated by the fact that resources
* depend on the port type. Maybe we should be claiming the standard
@@ -932,7 +870,6 @@ static struct uart_ops m32r_sio_pops = {
.startup = m32r_sio_startup,
.shutdown = m32r_sio_shutdown,
.set_termios = m32r_sio_set_termios,
- .pm = m32r_sio_pm,
.release_port = m32r_sio_release_port,
.request_port = m32r_sio_request_port,
.config_port = m32r_sio_config_port,
@@ -951,15 +888,14 @@ static void __init m32r_sio_init_ports(void)
return;
first = 0;
- for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
- i++, up++) {
+ for (i = 0, up = m32r_sio_ports; i < UART_NR; i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
- up->port.uartclk = old_serial_port[i].baud_base * 16;
- up->port.flags = old_serial_port[i].flags;
- up->port.membase = old_serial_port[i].iomem_base;
- up->port.iotype = old_serial_port[i].io_type;
- up->port.regshift = old_serial_port[i].iomem_reg_shift;
+ up->port.uartclk = BAUD_RATE * 16;
+ up->port.flags = STD_COM_FLAGS;
+ up->port.membase = 0;
+ up->port.iotype = 0;
+ up->port.regshift = 0;
up->port.ops = &m32r_sio_pops;
}
}
@@ -978,9 +914,6 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
init_timer(&up->timer);
up->timer.function = m32r_sio_timeout;
- up->mcr_mask = ~0;
- up->mcr_force = 0;
-
uart_add_one_port(drv, &up->port);
}
}
@@ -1112,28 +1045,6 @@ static struct uart_driver m32r_sio_reg = {
.cons = M32R_SIO_CONSOLE,
};
-/**
- * m32r_sio_suspend_port - suspend one serial port
- * @line: serial line number
- *
- * Suspend one serial port.
- */
-void m32r_sio_suspend_port(int line)
-{
- uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
-/**
- * m32r_sio_resume_port - resume one serial port
- * @line: serial line number
- *
- * Resume one serial port.
- */
-void m32r_sio_resume_port(int line)
-{
- uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
-}
-
static int __init m32r_sio_init(void)
{
int ret, i;
@@ -1163,8 +1074,5 @@ static void __exit m32r_sio_exit(void)
module_init(m32r_sio_init);
module_exit(m32r_sio_exit);
-EXPORT_SYMBOL(m32r_sio_suspend_port);
-EXPORT_SYMBOL(m32r_sio_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
deleted file mode 100644
index 812982449..000000000
--- a/drivers/tty/serial/m32r_sio.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * m32r_sio.h
- *
- * Driver for M32R serial ports
- *
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- * Based on drivers/serial/8250.h.
- *
- * Copyright (C) 2001 Russell King.
- * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
- *
- * 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.
- */
-
-#include <linux/pci.h>
-
-struct m32r_sio_probe {
- struct module *owner;
- int (*pci_init_one)(struct pci_dev *dev);
- void (*pci_remove_one)(struct pci_dev *dev);
- void (*pnp_init)(void);
-};
-
-int m32r_sio_register_probe(struct m32r_sio_probe *probe);
-void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
-void m32r_sio_get_irq_map(unsigned int *map);
-void m32r_sio_suspend_port(int line);
-void m32r_sio_resume_port(int line);
-
-struct old_serial_port {
- unsigned int uart;
- unsigned int baud_base;
- unsigned int port;
- unsigned int irq;
- unsigned int flags;
- unsigned char io_type;
- unsigned char __iomem *iomem_base;
- unsigned short iomem_reg_shift;
-};
-
-#define _INLINE_ inline
-
-#define PROBE_RSA (1 << 0)
-#define PROBE_ANY (~0)
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index b12a37bd3..024445aa0 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -78,6 +78,7 @@
/* AML_UART_REG5 bits */
#define AML_UART_BAUD_MASK 0x7fffff
#define AML_UART_BAUD_USE BIT(23)
+#define AML_UART_BAUD_XTAL BIT(24)
#define AML_UART_PORT_NUM 6
#define AML_UART_DEV_NAME "ttyAML"
@@ -299,7 +300,12 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
val = readl(port->membase + AML_UART_REG5);
val &= ~AML_UART_BAUD_MASK;
- val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ if (port->uartclk == 24000000) {
+ val = ((port->uartclk / 3) / baud) - 1;
+ val |= AML_UART_BAUD_XTAL;
+ } else {
+ val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ }
val |= AML_UART_BAUD_USE;
writel(val, port->membase + AML_UART_REG5);
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 8c3e51314..3970d6a9a 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -346,7 +346,7 @@ static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
return mpc5xxx_uart_process_int(port);
}
-static struct psc_ops mpc52xx_psc_ops = {
+static const struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -376,7 +376,7 @@ static struct psc_ops mpc52xx_psc_ops = {
.get_mr1 = mpc52xx_psc_get_mr1,
};
-static struct psc_ops mpc5200b_psc_ops = {
+static const struct psc_ops mpc5200b_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
@@ -969,7 +969,7 @@ static u8 mpc5125_psc_get_mr1(struct uart_port *port)
return in_8(&PSC_5125(port)->mr1);
}
-static struct psc_ops mpc5125_psc_ops = {
+static const struct psc_ops mpc5125_psc_ops = {
.fifo_init = mpc5125_psc_fifo_init,
.raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
.raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
@@ -1004,7 +1004,7 @@ static struct psc_ops mpc5125_psc_ops = {
.get_mr1 = mpc5125_psc_get_mr1,
};
-static struct psc_ops mpc512x_psc_ops = {
+static const struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
.raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index cadfd1cfa..4a3021bcc 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -137,8 +137,6 @@ struct mpsc_port_info {
/* Internal driver state for this ctlr */
u8 ready;
u8 rcv_data;
- tcflag_t c_iflag; /* save termios->c_iflag */
- tcflag_t c_cflag; /* save termios->c_cflag */
/* Info passed in from platform */
u8 mirror_regs; /* Need to mirror regs? */
@@ -1407,9 +1405,6 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
ulong flags;
u32 chr_bits, stop_bits, par;
- pi->c_iflag = termios->c_iflag;
- pi->c_cflag = termios->c_cflag;
-
switch (termios->c_cflag & CSIZE) {
case CS5:
chr_bits = MPSC_MPCR_CL_5;
@@ -1870,12 +1865,12 @@ static int mpsc_shared_map_regs(struct platform_device *pd)
static void mpsc_shared_unmap_regs(void)
{
- if (!mpsc_shared_regs.mpsc_routing_base) {
+ if (mpsc_shared_regs.mpsc_routing_base) {
iounmap(mpsc_shared_regs.mpsc_routing_base);
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
MPSC_ROUTING_REG_BLOCK_SIZE);
}
- if (!mpsc_shared_regs.sdma_intr_base) {
+ if (mpsc_shared_regs.sdma_intr_base) {
iounmap(mpsc_shared_regs.sdma_intr_base);
release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
MPSC_SDMA_INTR_REG_BLOCK_SIZE);
@@ -1891,44 +1886,39 @@ static void mpsc_shared_unmap_regs(void)
static int mpsc_shared_drv_probe(struct platform_device *dev)
{
struct mpsc_shared_pdata *pdata;
- int rc = -ENODEV;
-
- if (dev->id == 0) {
- rc = mpsc_shared_map_regs(dev);
- if (!rc) {
- pdata = (struct mpsc_shared_pdata *)
- dev_get_platdata(&dev->dev);
-
- mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
- mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
- mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m =
- pdata->intr_cause_val;
- mpsc_shared_regs.SDMA_INTR_MASK_m =
- pdata->intr_mask_val;
-
- rc = 0;
- }
- }
+ int rc;
- return rc;
+ if (dev->id != 0)
+ return -ENODEV;
+
+ rc = mpsc_shared_map_regs(dev);
+ if (rc)
+ return rc;
+
+ pdata = dev_get_platdata(&dev->dev);
+
+ mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
+ mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
+ mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
+
+ return 0;
}
static int mpsc_shared_drv_remove(struct platform_device *dev)
{
- int rc = -ENODEV;
+ if (dev->id != 0)
+ return -ENODEV;
- if (dev->id == 0) {
- mpsc_shared_unmap_regs();
- mpsc_shared_regs.MPSC_MRR_m = 0;
- mpsc_shared_regs.MPSC_RCRR_m = 0;
- mpsc_shared_regs.MPSC_TCRR_m = 0;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
- mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- rc = 0;
- }
+ mpsc_shared_unmap_regs();
+ mpsc_shared_regs.MPSC_MRR_m = 0;
+ mpsc_shared_regs.MPSC_RCRR_m = 0;
+ mpsc_shared_regs.MPSC_TCRR_m = 0;
+ mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
+ mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
- return rc;
+ return 0;
}
static struct platform_driver mpsc_shared_driver = {
@@ -1979,10 +1969,6 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->sdma_base_p = r->start;
} else {
mpsc_resource_err("SDMA base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
goto err;
}
@@ -1993,33 +1979,33 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
pi->brg_base_p = r->start;
} else {
mpsc_resource_err("BRG base");
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
- if (pi->sdma_base) {
- iounmap(pi->sdma_base);
- pi->sdma_base = NULL;
- }
goto err;
}
return 0;
err:
+ if (pi->sdma_base) {
+ iounmap(pi->sdma_base);
+ pi->sdma_base = NULL;
+ }
+ if (pi->mpsc_base) {
+ iounmap(pi->mpsc_base);
+ pi->mpsc_base = NULL;
+ }
return -ENOMEM;
}
static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
{
- if (!pi->mpsc_base) {
+ if (pi->mpsc_base) {
iounmap(pi->mpsc_base);
release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
}
- if (!pi->sdma_base) {
+ if (pi->sdma_base) {
iounmap(pi->sdma_base);
release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
}
- if (!pi->brg_base) {
+ if (pi->brg_base) {
iounmap(pi->brg_base);
release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
}
@@ -2073,36 +2059,37 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
static int mpsc_drv_probe(struct platform_device *dev)
{
- struct mpsc_port_info *pi;
- int rc = -ENODEV;
-
- pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
- if (dev->id < MPSC_NUM_CTLRS) {
- pi = &mpsc_ports[dev->id];
-
- rc = mpsc_drv_map_regs(pi, dev);
- if (!rc) {
- mpsc_drv_get_platform_data(pi, dev, dev->id);
- pi->port.dev = &dev->dev;
-
- rc = mpsc_make_ready(pi);
- if (!rc) {
- spin_lock_init(&pi->tx_lock);
- rc = uart_add_one_port(&mpsc_reg, &pi->port);
- if (!rc) {
- rc = 0;
- } else {
- mpsc_release_port((struct uart_port *)
- pi);
- mpsc_drv_unmap_regs(pi);
- }
- } else {
- mpsc_drv_unmap_regs(pi);
- }
- }
- }
+ struct mpsc_port_info *pi;
+ int rc;
+
+ dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
+
+ if (dev->id >= MPSC_NUM_CTLRS)
+ return -ENODEV;
+
+ pi = &mpsc_ports[dev->id];
+
+ rc = mpsc_drv_map_regs(pi, dev);
+ if (rc)
+ return rc;
+ mpsc_drv_get_platform_data(pi, dev, dev->id);
+ pi->port.dev = &dev->dev;
+
+ rc = mpsc_make_ready(pi);
+ if (rc)
+ goto err_unmap;
+
+ spin_lock_init(&pi->tx_lock);
+ rc = uart_add_one_port(&mpsc_reg, &pi->port);
+ if (rc)
+ goto err_relport;
+
+ return 0;
+err_relport:
+ mpsc_release_port(&pi->port);
+err_unmap:
+ mpsc_drv_unmap_regs(pi);
return rc;
}
@@ -2124,19 +2111,22 @@ static int __init mpsc_drv_init(void)
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
rc = uart_register_driver(&mpsc_reg);
- if (!rc) {
- rc = platform_driver_register(&mpsc_shared_driver);
- if (!rc) {
- rc = platform_driver_register(&mpsc_driver);
- if (rc) {
- platform_driver_unregister(&mpsc_shared_driver);
- uart_unregister_driver(&mpsc_reg);
- }
- } else {
- uart_unregister_driver(&mpsc_reg);
- }
- }
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&mpsc_shared_driver);
+ if (rc)
+ goto err_unreg_uart;
+ rc = platform_driver_register(&mpsc_driver);
+ if (rc)
+ goto err_unreg_plat;
+
+ return 0;
+err_unreg_plat:
+ platform_driver_unregister(&mpsc_shared_driver);
+err_unreg_uart:
+ uart_unregister_driver(&mpsc_reg);
return rc;
}
device_initcall(mpsc_drv_init);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index dcde95547..96d3ce8dc 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1478,7 +1478,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
device->con->write = msm_serial_early_write;
return 0;
}
-EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
msm_serial_early_console_setup);
@@ -1500,7 +1499,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
device->con->write = msm_serial_early_write_dm;
return 0;
}
-EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
msm_serial_early_console_setup_dm);
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
new file mode 100644
index 000000000..0ff27818b
--- /dev/null
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -0,0 +1,650 @@
+/*
+* ***************************************************************************
+* Copyright (C) 2015 Marvell International Ltd.
+* ***************************************************************************
+* 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 any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+* ***************************************************************************
+*/
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* Register Map */
+#define UART_RBR 0x00
+#define RBR_BRK_DET BIT(15)
+#define RBR_FRM_ERR_DET BIT(14)
+#define RBR_PAR_ERR_DET BIT(13)
+#define RBR_OVR_ERR_DET BIT(12)
+
+#define UART_TSH 0x04
+
+#define UART_CTRL 0x08
+#define CTRL_SOFT_RST BIT(31)
+#define CTRL_TXFIFO_RST BIT(15)
+#define CTRL_RXFIFO_RST BIT(14)
+#define CTRL_ST_MIRR_EN BIT(13)
+#define CTRL_LPBK_EN BIT(12)
+#define CTRL_SND_BRK_SEQ BIT(11)
+#define CTRL_PAR_EN BIT(10)
+#define CTRL_TWO_STOP BIT(9)
+#define CTRL_TX_HFL_INT BIT(8)
+#define CTRL_RX_HFL_INT BIT(7)
+#define CTRL_TX_EMP_INT BIT(6)
+#define CTRL_TX_RDY_INT BIT(5)
+#define CTRL_RX_RDY_INT BIT(4)
+#define CTRL_BRK_DET_INT BIT(3)
+#define CTRL_FRM_ERR_INT BIT(2)
+#define CTRL_PAR_ERR_INT BIT(1)
+#define CTRL_OVR_ERR_INT BIT(0)
+#define CTRL_RX_INT (CTRL_RX_RDY_INT | CTRL_BRK_DET_INT |\
+ CTRL_FRM_ERR_INT | CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
+
+#define UART_STAT 0x0c
+#define STAT_TX_FIFO_EMP BIT(13)
+#define STAT_RX_FIFO_EMP BIT(12)
+#define STAT_TX_FIFO_FUL BIT(11)
+#define STAT_TX_FIFO_HFL BIT(10)
+#define STAT_RX_TOGL BIT(9)
+#define STAT_RX_FIFO_FUL BIT(8)
+#define STAT_RX_FIFO_HFL BIT(7)
+#define STAT_TX_EMP BIT(6)
+#define STAT_TX_RDY BIT(5)
+#define STAT_RX_RDY BIT(4)
+#define STAT_BRK_DET BIT(3)
+#define STAT_FRM_ERR BIT(2)
+#define STAT_PAR_ERR BIT(1)
+#define STAT_OVR_ERR BIT(0)
+#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\
+ | STAT_PAR_ERR | STAT_OVR_ERR)
+
+#define UART_BRDV 0x10
+
+#define MVEBU_NR_UARTS 1
+
+#define MVEBU_UART_TYPE "mvebu-uart"
+
+static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
+
+struct mvebu_uart_data {
+ struct uart_port *port;
+ struct clk *clk;
+};
+
+/* Core UART Driver Operations */
+static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int st;
+
+ spin_lock_irqsave(&port->lock, flags);
+ st = readl(port->membase + UART_STAT);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int mvebu_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void mvebu_uart_set_mctrl(struct uart_port *port,
+ unsigned int mctrl)
+{
+/*
+ * Even if we do not support configuring the modem control lines, this
+ * function must be proided to the serial core
+ */
+}
+
+static void mvebu_uart_stop_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_start_tx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl |= CTRL_TX_RDY_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_stop_rx(struct uart_port *port)
+{
+ unsigned int ctl = readl(port->membase + UART_CTRL);
+
+ ctl &= ~CTRL_RX_INT;
+ writel(ctl, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
+{
+ unsigned int ctl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ctl = readl(port->membase + UART_CTRL);
+ if (brk == -1)
+ ctl |= CTRL_SND_BRK_SEQ;
+ else
+ ctl &= ~CTRL_SND_BRK_SEQ;
+ writel(ctl, port->membase + UART_CTRL);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch = 0;
+ char flag = 0;
+
+ do {
+ if (status & STAT_RX_RDY) {
+ ch = readl(port->membase + UART_RBR);
+ ch &= 0xff;
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & STAT_PAR_ERR)
+ port->icount.parity++;
+ }
+
+ if (status & STAT_BRK_DET) {
+ port->icount.brk++;
+ status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
+ if (uart_handle_break(port))
+ goto ignore_char;
+ }
+
+ if (status & STAT_OVR_ERR)
+ port->icount.overrun++;
+
+ if (status & STAT_FRM_ERR)
+ port->icount.frame++;
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ if (status & port->ignore_status_mask & STAT_PAR_ERR)
+ status &= ~STAT_RX_RDY;
+
+ status &= port->read_status_mask;
+
+ if (status & STAT_PAR_ERR)
+ flag = TTY_PARITY;
+
+ status &= ~port->ignore_status_mask;
+
+ if (status & STAT_RX_RDY)
+ tty_insert_flip_char(tport, ch, flag);
+
+ if (status & STAT_BRK_DET)
+ tty_insert_flip_char(tport, 0, TTY_BREAK);
+
+ if (status & STAT_FRM_ERR)
+ tty_insert_flip_char(tport, 0, TTY_FRAME);
+
+ if (status & STAT_OVR_ERR)
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+
+ignore_char:
+ status = readl(port->membase + UART_STAT);
+ } while (status & (STAT_RX_RDY | STAT_BRK_DET));
+
+ tty_flip_buffer_push(tport);
+}
+
+static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int count;
+ unsigned int st;
+
+ if (port->x_char) {
+ writel(port->x_char, port->membase + UART_TSH);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ mvebu_uart_stop_tx(port);
+ return;
+ }
+
+ for (count = 0; count < port->fifosize; count++) {
+ writel(xmit->buf[xmit->tail], port->membase + UART_TSH);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_FUL)
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ mvebu_uart_stop_tx(port);
+}
+
+static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (st & (STAT_RX_RDY | STAT_OVR_ERR | STAT_FRM_ERR | STAT_BRK_DET))
+ mvebu_uart_rx_chars(port, st);
+
+ if (st & STAT_TX_RDY)
+ mvebu_uart_tx_chars(port, st);
+
+ return IRQ_HANDLED;
+}
+
+static int mvebu_uart_startup(struct uart_port *port)
+{
+ int ret;
+
+ writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST,
+ port->membase + UART_CTRL);
+ udelay(1);
+ writel(CTRL_RX_INT, port->membase + UART_CTRL);
+
+ ret = request_irq(port->irq, mvebu_uart_isr, port->irqflags, "serial",
+ port);
+ if (ret) {
+ dev_err(port->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mvebu_uart_shutdown(struct uart_port *port)
+{
+ writel(0, port->membase + UART_CTRL);
+}
+
+static void mvebu_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = STAT_RX_RDY | STAT_OVR_ERR |
+ STAT_TX_RDY | STAT_TX_FIFO_FUL;
+
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR;
+
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR;
+
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR;
+
+ if (old)
+ tty_termios_copy_hw(termios, old);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *mvebu_uart_type(struct uart_port *port)
+{
+ return MVEBU_UART_TYPE;
+}
+
+static void mvebu_uart_release_port(struct uart_port *port)
+{
+ /* Nothing to do here */
+}
+
+static int mvebu_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int mvebu_uart_get_poll_char(struct uart_port *port)
+{
+ unsigned int st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_RX_RDY))
+ return NO_POLL_CHAR;
+
+ return readl(port->membase + UART_RBR);
+}
+
+static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+
+ udelay(1);
+ }
+
+ writel(c, port->membase + UART_TSH);
+}
+#endif
+
+static const struct uart_ops mvebu_uart_ops = {
+ .tx_empty = mvebu_uart_tx_empty,
+ .set_mctrl = mvebu_uart_set_mctrl,
+ .get_mctrl = mvebu_uart_get_mctrl,
+ .stop_tx = mvebu_uart_stop_tx,
+ .start_tx = mvebu_uart_start_tx,
+ .stop_rx = mvebu_uart_stop_rx,
+ .break_ctl = mvebu_uart_break_ctl,
+ .startup = mvebu_uart_startup,
+ .shutdown = mvebu_uart_shutdown,
+ .set_termios = mvebu_uart_set_termios,
+ .type = mvebu_uart_type,
+ .release_port = mvebu_uart_release_port,
+ .request_port = mvebu_uart_request_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = mvebu_uart_get_poll_char,
+ .poll_put_char = mvebu_uart_put_poll_char,
+#endif
+};
+
+/* Console Driver Operations */
+
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+/* Early Console */
+static void mvebu_uart_putc(struct uart_port *port, int c)
+{
+ unsigned int st;
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (!(st & STAT_TX_FIFO_FUL))
+ break;
+ }
+
+ writel(c, port->membase + UART_TSH);
+
+ for (;;) {
+ st = readl(port->membase + UART_STAT);
+ if (st & STAT_TX_FIFO_EMP)
+ break;
+ }
+}
+
+static void mvebu_uart_putc_early_write(struct console *con,
+ const char *s,
+ unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, mvebu_uart_putc);
+}
+
+static int __init
+mvebu_uart_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = mvebu_uart_putc_early_write;
+
+ return 0;
+}
+
+EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup);
+OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart",
+ mvebu_uart_early_console_setup);
+
+static void wait_for_xmitr(struct uart_port *port)
+{
+ u32 val;
+
+ readl_poll_timeout_atomic(port->membase + UART_STAT, val,
+ (val & STAT_TX_EMP), 1, 10000);
+}
+
+static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmitr(port);
+ writel(ch, port->membase + UART_TSH);
+}
+
+static void mvebu_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &mvebu_uart_ports[co->index];
+ unsigned long flags;
+ unsigned int ier;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ ier = readl(port->membase + UART_CTRL) &
+ (CTRL_RX_INT | CTRL_TX_RDY_INT);
+ writel(0, port->membase + UART_CTRL);
+
+ uart_console_write(port, s, count, mvebu_uart_console_putchar);
+
+ wait_for_xmitr(port);
+
+ if (ier)
+ writel(ier, port->membase + UART_CTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int mvebu_uart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= MVEBU_NR_UARTS)
+ return -EINVAL;
+
+ port = &mvebu_uart_ports[co->index];
+
+ if (!port->mapbase || !port->membase) {
+ pr_debug("console on ttyMV%i not present\n", co->index);
+ return -ENODEV;
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mvebu_uart_driver;
+
+static struct console mvebu_uart_console = {
+ .name = "ttyMV",
+ .write = mvebu_uart_console_write,
+ .device = uart_console_device,
+ .setup = mvebu_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mvebu_uart_driver,
+};
+
+static int __init mvebu_uart_console_init(void)
+{
+ register_console(&mvebu_uart_console);
+ return 0;
+}
+
+console_initcall(mvebu_uart_console_init);
+
+
+#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */
+
+static struct uart_driver mvebu_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "mvebu_serial",
+ .dev_name = "ttyMV",
+ .nr = MVEBU_NR_UARTS,
+#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
+ .cons = &mvebu_uart_console,
+#endif
+};
+
+static int mvebu_uart_probe(struct platform_device *pdev)
+{
+ struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct uart_port *port;
+ struct mvebu_uart_data *data;
+ int ret;
+
+ if (!reg || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ port = &mvebu_uart_ports[0];
+
+ spin_lock_init(&port->lock);
+
+ port->dev = &pdev->dev;
+ port->type = PORT_MVEBU;
+ port->ops = &mvebu_uart_ops;
+ port->regshift = 0;
+
+ port->fifosize = 32;
+ port->iotype = UPIO_MEM32;
+ port->flags = UPF_FIXED_PORT;
+ port->line = 0; /* single port: force line number to 0 */
+
+ port->irq = irq->start;
+ port->irqflags = 0;
+ port->mapbase = reg->start;
+
+ port->membase = devm_ioremap_resource(&pdev->dev, reg);
+ if (IS_ERR(port->membase))
+ return -PTR_ERR(port->membase);
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->port = port;
+
+ port->private_data = data;
+ platform_set_drvdata(pdev, data);
+
+ ret = uart_add_one_port(&mvebu_uart_driver, port);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static int mvebu_uart_remove(struct platform_device *pdev)
+{
+ struct mvebu_uart_data *data = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&mvebu_uart_driver, data->port);
+ data->port->private_data = NULL;
+ data->port->mapbase = 0;
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id mvebu_uart_of_match[] = {
+ { .compatible = "marvell,armada-3700-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
+
+static struct platform_driver mvebu_uart_platform_driver = {
+ .probe = mvebu_uart_probe,
+ .remove = mvebu_uart_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mvebu-uart",
+ .of_match_table = of_match_ptr(mvebu_uart_of_match),
+ },
+};
+
+static int __init mvebu_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&mvebu_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&mvebu_uart_platform_driver);
+ if (ret)
+ uart_unregister_driver(&mvebu_uart_driver);
+
+ return ret;
+}
+
+static void __exit mvebu_uart_exit(void)
+{
+ platform_driver_unregister(&mvebu_uart_platform_driver);
+ uart_unregister_driver(&mvebu_uart_driver);
+}
+
+arch_initcall(mvebu_uart_init);
+module_exit(mvebu_uart_exit);
+
+MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>");
+MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index fa49eb1e2..a2a529994 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1870,7 +1870,7 @@ static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
- .name = DRIVER_NAME,
+ .name = OMAP_SERIAL_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d72cd736b..99bb23161 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -601,14 +601,21 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ufcon, ch, flag, ufstat, uerstat;
+ unsigned int fifocnt = 0;
int max_count = port->fifosize;
while (max_count-- > 0) {
- ufcon = rd_regl(port, S3C2410_UFCON);
- ufstat = rd_regl(port, S3C2410_UFSTAT);
-
- if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
- break;
+ /*
+ * Receive all characters known to be in FIFO
+ * before reading FIFO level again
+ */
+ if (fifocnt == 0) {
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+ fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+ if (fifocnt == 0)
+ break;
+ }
+ fifocnt--;
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
@@ -623,6 +630,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
}
} else {
if (txe) {
+ ufcon = rd_regl(port, S3C2410_UFCON);
ufcon |= S3C2410_UFCON_RESETRX;
wr_regl(port, S3C2410_UFCON, ufcon);
rx_enabled(port) = 1;
@@ -1263,6 +1271,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
/* check to see if we need to change clock source */
if (ourport->baudclk != clk) {
+ clk_prepare_enable(clk);
+
s3c24xx_serial_setsource(port, clk_sel);
if (!IS_ERR(ourport->baudclk)) {
@@ -1270,8 +1280,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
ourport->baudclk = ERR_PTR(-EINVAL);
}
- clk_prepare_enable(clk);
-
ourport->baudclk = clk;
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
}
@@ -2451,7 +2459,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
-EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
@@ -2470,9 +2477,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
-EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
@@ -2489,8 +2493,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
-EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
-EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
#endif
MODULE_ALIAS("platform:samsung-uart");
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 13f8d5f70..025a42644 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -196,14 +196,14 @@
* or (IO6)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4)
+#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
+#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7)
+#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6)
+#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
* - only on 75x/76x
*/
#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
@@ -240,7 +240,7 @@
/* IOControl register bits (Only 750/760) */
#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
-#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */
+#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */
#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
/* EFCR register bits */
@@ -687,7 +687,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
case SC16IS7XX_IIR_CTSRTS_SRC:
msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
uart_handle_cts_change(port,
- !!(msr & SC16IS7XX_MSR_CTS_BIT));
+ !!(msr & SC16IS7XX_MSR_DCTS_BIT));
break;
case SC16IS7XX_IIR_THRI_SRC:
sc16is7xx_handle_tx(port);
@@ -761,12 +761,20 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
memset(&one->config, 0, sizeof(one->config));
spin_unlock_irqrestore(&one->port.lock, irqflags);
- if (config.flags & SC16IS7XX_RECONF_MD)
+ if (config.flags & SC16IS7XX_RECONF_MD) {
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_LOOP_BIT,
(one->port.mctrl & TIOCM_LOOP) ?
SC16IS7XX_MCR_LOOP_BIT : 0);
-
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_RTS_BIT,
+ (one->port.mctrl & TIOCM_RTS) ?
+ SC16IS7XX_MCR_RTS_BIT : 0);
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_DTR_BIT,
+ (one->port.mctrl & TIOCM_DTR) ?
+ SC16IS7XX_MCR_DTR_BIT : 0);
+ }
if (config.flags & SC16IS7XX_RECONF_IER)
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
config.ier_clear, 0);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index b1f54ab18..a126a603b 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -171,14 +171,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
*/
uart_change_speed(tty, state, NULL);
- if (init_hw) {
- /*
- * Setup the RTS and DTR signals once the
- * port is open and ready to respond.
- */
- if (tty->termios.c_cflag & CBAUD)
- uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
- }
+ /*
+ * Setup the RTS and DTR signals once the
+ * port is open and ready to respond.
+ */
+ if (init_hw && C_BAUD(tty))
+ uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
/*
@@ -240,7 +238,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
if (uart_console(uport) && tty)
uport->cons->cflag = tty->termios.c_cflag;
- if (!tty || (tty->termios.c_cflag & HUPCL))
+ if (!tty || C_HUPCL(tty))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_shutdown(port);
@@ -485,12 +483,15 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
spin_unlock_irq(&uport->lock);
}
-static inline int __uart_put_char(struct uart_port *port,
- struct circ_buf *circ, unsigned char c)
+static int uart_put_char(struct tty_struct *tty, unsigned char c)
{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ struct circ_buf *circ;
unsigned long flags;
int ret = 0;
+ circ = &state->xmit;
if (!circ->buf)
return 0;
@@ -504,13 +505,6 @@ static inline int __uart_put_char(struct uart_port *port,
return ret;
}
-static int uart_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct uart_state *state = tty->driver_data;
-
- return __uart_put_char(state->uart_port, &state->xmit, ch);
-}
-
static void uart_flush_chars(struct tty_struct *tty)
{
uart_start(tty);
@@ -639,7 +633,7 @@ static void uart_throttle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -647,11 +641,11 @@ static void uart_throttle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, STOP_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_clear_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, STOP_CHAR(tty));
}
static void uart_unthrottle(struct tty_struct *tty)
@@ -662,7 +656,7 @@ static void uart_unthrottle(struct tty_struct *tty)
if (I_IXOFF(tty))
mask |= UPSTAT_AUTOXOFF;
- if (tty->termios.c_cflag & CRTSCTS)
+ if (C_CRTSCTS(tty))
mask |= UPSTAT_AUTORTS;
if (port->status & mask) {
@@ -670,21 +664,25 @@ static void uart_unthrottle(struct tty_struct *tty)
mask &= ~port->status;
}
- if (mask & UPSTAT_AUTOXOFF)
- uart_send_xchar(tty, START_CHAR(tty));
-
if (mask & UPSTAT_AUTORTS)
uart_set_mctrl(port, TIOCM_RTS);
+
+ if (mask & UPSTAT_AUTOXOFF)
+ uart_send_xchar(tty, START_CHAR(tty));
}
-static void do_uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
+static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
memset(retinfo, 0, sizeof(*retinfo));
+ /*
+ * Ensure the state we copy is consistent and no hardware changes
+ * occur as we go
+ */
+ mutex_lock(&port->mutex);
retinfo->type = uport->type;
retinfo->line = uport->line;
retinfo->port = uport->iobase;
@@ -703,15 +701,6 @@ static void do_uart_get_info(struct tty_port *port,
retinfo->io_type = uport->iotype;
retinfo->iomem_reg_shift = uport->regshift;
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
-}
-
-static void uart_get_info(struct tty_port *port,
- struct serial_struct *retinfo)
-{
- /* Ensure the state we copy is consistent and no hardware changes
- occur as we go */
- mutex_lock(&port->mutex);
- do_uart_get_info(port, retinfo);
mutex_unlock(&port->mutex);
}
@@ -719,6 +708,7 @@ static int uart_get_info_user(struct tty_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
+
uart_get_info(port, &tmp);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
@@ -1391,8 +1381,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
uport = state->uart_port;
port = &state->port;
-
- pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
+ pr_debug("uart_close(%d) called\n", tty->index);
if (!port->count || tty_port_close_start(port, tty, filp) == 0)
return;
@@ -1434,7 +1423,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* Wake up anyone trying to open this port.
*/
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
- clear_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irq(&port->lock);
wake_up_interruptible(&port->open_wait);
@@ -1510,7 +1498,7 @@ static void uart_hangup(struct tty_struct *tty)
struct tty_port *port = &state->port;
unsigned long flags;
- pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+ pr_debug("uart_hangup(%d)\n", tty->index);
mutex_lock(&port->mutex);
if (port->flags & ASYNC_NORMAL_ACTIVE) {
@@ -1591,7 +1579,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
*/
static int uart_open(struct tty_struct *tty, struct file *filp)
{
- struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+ struct uart_driver *drv = tty->driver->driver_state;
int retval, line = tty->index;
struct uart_state *state = drv->state + line;
struct tty_port *port = &state->port;
@@ -1633,15 +1621,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If we succeeded, wait until the port is ready.
*/
+err_unlock:
mutex_unlock(&port->mutex);
if (retval == 0)
retval = tty_port_block_til_ready(port, tty, filp);
-
end:
return retval;
-err_unlock:
- mutex_unlock(&port->mutex);
- goto end;
}
static const char *uart_type(struct uart_port *port)
@@ -1700,17 +1685,13 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
seq_printf(m, " tx:%d rx:%d",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d",
- uport->icount.frame);
+ seq_printf(m, " fe:%d", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d",
- uport->icount.parity);
+ seq_printf(m, " pe:%d", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d",
- uport->icount.brk);
+ seq_printf(m, " brk:%d", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d",
- uport->icount.overrun);
+ seq_printf(m, " oe:%d", uport->icount.overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -1745,8 +1726,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
struct uart_driver *drv = ttydrv->driver_state;
int i;
- seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
- "", "", "");
+ seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
uart_line_info(m, drv, i);
return 0;
@@ -1895,26 +1875,6 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
}
EXPORT_SYMBOL_GPL(uart_parse_options);
-struct baud_rates {
- unsigned int rate;
- unsigned int cflag;
-};
-
-static const struct baud_rates baud_rates[] = {
- { 921600, B921600 },
- { 460800, B460800 },
- { 230400, B230400 },
- { 115200, B115200 },
- { 57600, B57600 },
- { 38400, B38400 },
- { 19200, B19200 },
- { 9600, B9600 },
- { 4800, B4800 },
- { 2400, B2400 },
- { 1200, B1200 },
- { 0, B38400 }
-};
-
/**
* uart_set_options - setup the serial console parameters
* @port: pointer to the serial ports uart_port structure
@@ -1930,7 +1890,6 @@ uart_set_options(struct uart_port *port, struct console *co,
{
struct ktermios termios;
static struct ktermios dummy;
- int i;
/*
* Ensure that the serial console lock is initialised
@@ -1945,16 +1904,8 @@ uart_set_options(struct uart_port *port, struct console *co,
memset(&termios, 0, sizeof(struct ktermios));
- termios.c_cflag = CREAD | HUPCL | CLOCAL;
-
- /*
- * Construct a cflag setting.
- */
- for (i = 0; baud_rates[i].rate; i++)
- if (baud_rates[i].rate <= baud)
- break;
-
- termios.c_cflag |= baud_rates[i].cflag;
+ termios.c_cflag |= CREAD | HUPCL | CLOCAL;
+ tty_termios_encode_baud_rate(&termios, baud, baud);
if (bits == 7)
termios.c_cflag |= CS7;
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index b4decf878..57f152394 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -554,7 +554,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
.uartclk = KS8695_CLOCK_RATE * 16,
.fifosize = 16,
.ops = &ks8695uart_pops,
- .flags = ASYNC_BOOT_AUTOCONF,
+ .flags = UPF_BOOT_AUTOCONF,
.line = 0,
}
};
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 226ad23b1..02147361e 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -20,6 +20,7 @@
#include <linux/gpio/consumer.h>
#include <linux/termios.h>
#include <linux/serial_core.h>
+#include <linux/module.h>
#include "serial_mctrl_gpio.h"
@@ -249,3 +250,5 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
}
}
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4646a9f53..0130feb06 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -84,6 +84,22 @@ enum SCI_CLKS {
SCI_NUM_CLKS
};
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
+ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
+ SCI_SR(19) | SCI_SR(27)
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+/* Iterate over all supported sampling rates, from high to low */
+#define for_each_sr(_sr, _port) \
+ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
+ if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
+
struct sci_port {
struct uart_port port;
@@ -93,7 +109,7 @@ struct sci_port {
unsigned int overrun_mask;
unsigned int error_mask;
unsigned int error_clear;
- unsigned int sampling_rate;
+ unsigned int sampling_rate_mask;
resource_size_t reg_size;
/* Break timer */
@@ -637,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
}
}
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
#ifdef CONFIG_CONSOLE_POLL
static int sci_poll_get_char(struct uart_port *port)
@@ -678,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
serial_port_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
+ CONFIG_SERIAL_SH_SCI_EARLYCON */
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -1902,19 +1920,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
unsigned int *srr)
{
unsigned long freq = s->clk_rates[SCI_SCK];
- unsigned int min_sr, max_sr, sr;
int err, min_err = INT_MAX;
+ unsigned int sr;
- if (s->sampling_rate) {
- /* SCI(F) has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
err = DIV_ROUND_CLOSEST(freq, sr) - bps;
if (abs(err) >= abs(min_err))
continue;
@@ -1935,19 +1947,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
unsigned long freq, unsigned int *dlr,
unsigned int *srr)
{
- unsigned int min_sr, max_sr, sr, dl;
int err, min_err = INT_MAX;
+ unsigned int sr, dl;
- if (s->sampling_rate) {
- /* SCIF has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
dl = DIV_ROUND_CLOSEST(freq, sr * bps);
dl = clamp(dl, 1U, 65535U);
@@ -1973,19 +1979,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
unsigned int *brr, unsigned int *srr,
unsigned int *cks)
{
- unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
unsigned long freq = s->clk_rates[SCI_FCK];
+ unsigned int sr, br, prediv, scrate, c;
int err, min_err = INT_MAX;
- if (s->sampling_rate) {
- min_sr = max_sr = s->sampling_rate;
- shift = 0;
- } else {
- /* HSCIF has a variable sample rate */
- min_sr = 8;
- max_sr = 32;
- shift = 1;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
/*
* Find the combination of sample rate and clock select with the
@@ -2002,10 +2001,10 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
* (|D - 0.5| / N * (1 + F))|
* NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
*/
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- prediv = sr * (1 << (2 * c + shift));
+ prediv = sr * (1 << (2 * c + 1));
/*
* We need to calculate:
@@ -2062,7 +2061,7 @@ static void sci_reset(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- unsigned int baud, smr_val = 0, scr_val = 0, i;
+ unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i;
unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
struct sci_port *s = to_sci_port(port);
@@ -2096,8 +2095,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
for (i = 0; i < SCI_NUM_CLKS; i++)
max_freq = max(max_freq, s->clk_rates[i]);
- baud = uart_get_baud_rate(port, termios, old, 0,
- max_freq / max(s->sampling_rate, 8U));
+ baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
if (!baud)
goto done;
@@ -2185,6 +2183,17 @@ done:
uart_update_timeout(port, termios->c_cflag, baud);
if (best_clk >= 0) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ switch (srr + 1) {
+ case 5: smr_val |= SCSMR_SRC_5; break;
+ case 7: smr_val |= SCSMR_SRC_7; break;
+ case 11: smr_val |= SCSMR_SRC_11; break;
+ case 13: smr_val |= SCSMR_SRC_13; break;
+ case 16: smr_val |= SCSMR_SRC_16; break;
+ case 17: smr_val |= SCSMR_SRC_17; break;
+ case 19: smr_val |= SCSMR_SRC_19; break;
+ case 27: smr_val |= SCSMR_SRC_27; break;
+ }
smr_val |= cks;
dev_dbg(port->dev,
"SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
@@ -2200,7 +2209,8 @@ done:
} else {
/* Don't touch the bit rate configuration */
scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
- smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
+ smr_val |= serial_port_in(port, SCSMR) &
+ (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
serial_port_out(port, SCSCR, scr_val);
serial_port_out(port, SCSMR, smr_val);
@@ -2232,6 +2242,16 @@ done:
scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
serial_port_out(port, SCSCR, scr_val);
+ if ((srr + 1 == 5) &&
+ (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
+ /*
+ * In asynchronous mode, when the sampling rate is 1/5, first
+ * received data may become invalid on some SCIFA and SCIFB.
+ * To avoid this problem wait more than 1 serial data time (1
+ * bit time x serial data number) after setting SCSCR.RE = 1.
+ */
+ udelay(DIV_ROUND_UP(10 * 1000000, baud));
+ }
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -2528,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev,
port->fifosize = 256;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_HSCIF:
port->fifosize = 128;
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 0;
+ sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
break;
case PORT_SCIFA:
port->fifosize = 64;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_SCIF:
port->fifosize = 16;
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR(16);
} else {
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
}
break;
default:
port->fifosize = 1;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCI_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
break;
}
@@ -2567,7 +2587,7 @@ static int sci_init_single(struct platform_device *dev,
* data override the sampling rate for now.
*/
if (p->sampling_rate)
- sci_port->sampling_rate = p->sampling_rate;
+ sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
if (!early) {
ret = sci_init_clocks(sci_port, &dev->dev);
@@ -2632,7 +2652,8 @@ static void sci_cleanup_single(struct sci_port *port)
pm_runtime_disable(port->port.dev);
}
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, int ch)
{
sci_poll_put_char(port, ch);
@@ -2652,9 +2673,12 @@ static void serial_console_write(struct console *co, const char *s,
int locked = 1;
local_irq_save(flags);
+#if defined(SUPPORT_SYSRQ)
if (port->sysrq)
locked = 0;
- else if (oops_in_progress)
+ else
+#endif
+ if (oops_in_progress)
locked = spin_trylock(&port->lock);
else
spin_lock(&port->lock);
@@ -2764,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
#define SCI_CONSOLE NULL
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
@@ -2998,6 +3022,62 @@ static void __exit sci_exit(void)
early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+static struct __init plat_sci_port port_cfg;
+
+static int __init early_console_setup(struct earlycon_device *device,
+ int type)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.serial_in = sci_serial_in;
+ device->port.serial_out = sci_serial_out;
+ device->port.type = type;
+ memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
+ sci_ports[0].cfg = &port_cfg;
+ sci_ports[0].cfg->type = type;
+ sci_probe_regmap(sci_ports[0].cfg);
+ port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) |
+ SCSCR_RE | SCSCR_TE;
+ sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr);
+
+ device->con->write = serial_console_write;
+ return 0;
+}
+static int __init sci_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCI);
+}
+static int __init scif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIF);
+}
+static int __init scifa_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFA);
+}
+static int __init scifb_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFB);
+}
+static int __init hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_HSCIF);
+}
+
+OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
+OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
+OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
+OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
+#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
+
module_init(sci_init);
module_exit(sci_exit);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index fb1760250..7a4fa185b 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -35,12 +35,27 @@ enum {
/* SCSMR (Serial Mode Register) */
+#define SCSMR_C_A BIT(7) /* Communication Mode */
+#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
+#define SCSMR_ASYNC 0 /* - Asynchronous mode */
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
#define SCSMR_PE BIT(5) /* Parity Enable */
#define SCSMR_ODD BIT(4) /* Odd Parity */
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
#define SCSMR_CKS 0x0003 /* Clock Select */
+/* Serial Mode Register, SCIFA/SCIFB only bits */
+#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
+#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
+#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
+#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
+#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
+#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
+#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
+#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
+#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
+#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
+
/* Serial Control Register, SCIFA/SCIFB only bits */
#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index ef26c4a60..18971063f 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -624,8 +624,6 @@ static int __init sprd_early_console_setup(
device->con->write = sprd_early_write;
return 0;
}
-
-EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
sprd_early_console_setup);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index b1c6bd3d4..d08baa668 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -28,7 +28,7 @@
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
-#define ULITE_NR_UARTS 4
+#define ULITE_NR_UARTS 16
/* ---------------------------------------------------------------------
* Register definitions
@@ -193,12 +193,15 @@ static int ulite_transmit(struct uart_port *port, int stat)
static irqreturn_t ulite_isr(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- int busy, n = 0;
+ int stat, busy, n = 0;
+ unsigned long flags;
do {
- int stat = uart_in32(ULITE_STATUS, port);
+ spin_lock_irqsave(&port->lock, flags);
+ stat = uart_in32(ULITE_STATUS, port);
busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat);
+ spin_unlock_irqrestore(&port->lock, flags);
n++;
} while (busy);
@@ -259,7 +262,8 @@ static int ulite_startup(struct uart_port *port)
{
int ret;
- ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port);
+ ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING,
+ "uartlite", port);
if (ret)
return ret;
@@ -519,6 +523,47 @@ static int __init ulite_console_init(void)
console_initcall(ulite_console_init);
+static void early_uartlite_putc(struct uart_port *port, int c)
+{
+ /*
+ * Limit how many times we'll spin waiting for TX FIFO status.
+ * This will prevent lockups if the base address is incorrectly
+ * set, or any other issue on the UARTLITE.
+ * This limit is pretty arbitrary, unless we are at about 10 baud
+ * we'll never timeout on a working UART.
+ */
+
+ unsigned retries = 1000000;
+ /* read status bit - 0x8 offset */
+ while (--retries && (readl(port->membase + 8) & (1 << 3)))
+ ;
+
+ /* Only attempt the iowrite if we didn't timeout */
+ /* write to TX_FIFO - 0x4 offset */
+ if (retries)
+ writel(c & 0xff, port->membase + 4);
+}
+
+static void early_uartlite_write(struct console *console,
+ const char *s, unsigned n)
+{
+ struct earlycon_device *device = console->data;
+ uart_console_write(&device->port, s, n, early_uartlite_putc);
+}
+
+static int __init early_uartlite_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = early_uartlite_write;
+ return 0;
+}
+EARLYCON_DECLARE(uartlite, early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_b, "xlnx,opb-uartlite-1.00.b", early_uartlite_setup);
+OF_EARLYCON_DECLARE(uartlite_a, "xlnx,xps-uartlite-1.00.a", early_uartlite_setup);
+
#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
static struct uart_driver ulite_uart_driver = {
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 5414b25bc..82e5b9b7c 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1478,6 +1478,9 @@ static const struct of_device_id ucc_uart_match[] = {
.type = "serial",
.compatible = "ucc_uart",
},
+ {
+ .compatible = "fsl,t1040-ucc-uart",
+ },
{},
};
MODULE_DEVICE_TABLE(of, ucc_uart_match);
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 009e0dbc1..cd46e64c4 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -50,24 +50,24 @@ module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
/* Register offsets for the UART. */
-#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
-#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
-#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
-#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
-#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
-#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
-#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
-#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
-#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
-#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
-#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
-#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
-#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
-#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
-#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
-#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
-#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
-#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
+#define CDNS_UART_CR 0x00 /* Control Register */
+#define CDNS_UART_MR 0x04 /* Mode Register */
+#define CDNS_UART_IER 0x08 /* Interrupt Enable */
+#define CDNS_UART_IDR 0x0C /* Interrupt Disable */
+#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
+#define CDNS_UART_ISR 0x14 /* Interrupt Status */
+#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
+#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
+#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
+#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
+#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
+#define CDNS_UART_SR 0x2C /* Channel Status */
+#define CDNS_UART_FIFO 0x30 /* FIFO */
+#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
+#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
+#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
+#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
+#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
/* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
@@ -126,6 +126,10 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
+#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
+ CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
+ CDNS_UART_IXR_TOUT)
+
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
#define CDNS_UART_IXR_BRK 0x80000000
@@ -172,43 +176,22 @@ struct cdns_uart {
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb);
-/**
- * cdns_uart_isr - Interrupt handler
- * @irq: Irq number
- * @dev_id: Id of the port
- *
- * Return: IRQHANDLED
- */
-static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
{
- struct uart_port *port = (struct uart_port *)dev_id;
- unsigned long flags;
- unsigned int isrstatus, numbytes;
- unsigned int data;
- char status = TTY_NORMAL;
-
- spin_lock_irqsave(&port->lock, flags);
-
- /* Read the interrupt status register to determine which
- * interrupt(s) is/are active.
- */
- isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
-
/*
* There is no hardware break detection, so we interpret framing
* error with all-zeros data as a break sequence. Most of the time,
* there's another non-zero byte at the end of the sequence.
*/
if (isrstatus & CDNS_UART_IXR_FRAMING) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY)) {
- if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
+ if (!readl(port->membase + CDNS_UART_FIFO)) {
port->read_status_mask |= CDNS_UART_IXR_BRK;
isrstatus &= ~CDNS_UART_IXR_FRAMING;
}
}
- writel(CDNS_UART_IXR_FRAMING,
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR);
}
/* drop byte with parity error if IGNPAR specified */
@@ -218,94 +201,106 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask;
- if ((isrstatus & CDNS_UART_IXR_TOUT) ||
- (isrstatus & CDNS_UART_IXR_RXTRIG)) {
- /* Receive Timeout Interrupt */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_RXEMPTY)) {
- data = readl(port->membase + CDNS_UART_FIFO_OFFSET);
-
- /* Non-NULL byte after BREAK is garbage (99%) */
- if (data && (port->read_status_mask &
- CDNS_UART_IXR_BRK)) {
- port->read_status_mask &= ~CDNS_UART_IXR_BRK;
- port->icount.brk++;
- if (uart_handle_break(port))
- continue;
- }
+ if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
+ return;
-#ifdef SUPPORT_SYSRQ
- /*
- * uart_handle_sysrq_char() doesn't work if
- * spinlocked, for some reason
- */
- if (port->sysrq) {
- spin_unlock(&port->lock);
- if (uart_handle_sysrq_char(port,
- (unsigned char)data)) {
- spin_lock(&port->lock);
- continue;
- }
- spin_lock(&port->lock);
- }
-#endif
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
+ u32 data;
+ char status = TTY_NORMAL;
- port->icount.rx++;
+ data = readl(port->membase + CDNS_UART_FIFO);
- if (isrstatus & CDNS_UART_IXR_PARITY) {
- port->icount.parity++;
- status = TTY_PARITY;
- } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
- port->icount.frame++;
- status = TTY_FRAME;
- } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
- port->icount.overrun++;
- }
+ /* Non-NULL byte after BREAK is garbage (99%) */
+ if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
+ port->read_status_mask &= ~CDNS_UART_IXR_BRK;
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ }
+
+ if (uart_handle_sysrq_char(port, data))
+ continue;
+
+ port->icount.rx++;
- uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
- data, status);
+ if (isrstatus & CDNS_UART_IXR_PARITY) {
+ port->icount.parity++;
+ status = TTY_PARITY;
+ } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ port->icount.frame++;
+ status = TTY_FRAME;
+ } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
+ port->icount.overrun++;
}
- spin_unlock(&port->lock);
- tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
+
+ uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
+ data, status);
}
+ tty_flip_buffer_push(&port->state->port);
+}
- /* Dispatch an appropriate handler */
- if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
- if (uart_circ_empty(&port->state->xmit)) {
- writel(CDNS_UART_IXR_TXEMPTY,
- port->membase + CDNS_UART_IDR_OFFSET);
- } else {
- numbytes = port->fifosize;
- /* Break if no more data available in the UART buffer */
- while (numbytes--) {
- if (uart_circ_empty(&port->state->xmit))
- break;
- /* Get the data from the UART circular buffer
- * and write it to the cdns_uart's TX_FIFO
- * register.
- */
- writel(port->state->xmit.buf[
- port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
-
- port->icount.tx++;
-
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail =
- (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
+static void cdns_uart_handle_tx(struct uart_port *port)
+{
+ unsigned int numbytes;
- if (uart_circ_chars_pending(
- &port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
- }
+ if (uart_circ_empty(&port->state->xmit)) {
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
+ return;
+ }
+
+ numbytes = port->fifosize;
+ while (numbytes && !uart_circ_empty(&port->state->xmit) &&
+ !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+ /*
+ * Get the data from the UART circular buffer
+ * and write it to the cdns_uart's TX_FIFO
+ * register.
+ */
+ writel(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + CDNS_UART_FIFO);
+ port->icount.tx++;
+
+ /*
+ * Adjust the tail of the UART buffer and wrap
+ * the buffer if it reaches limit.
+ */
+ port->state->xmit.tail =
+ (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
+
+ numbytes--;
}
- writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
+ if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+/**
+ * cdns_uart_isr - Interrupt handler
+ * @irq: Irq number
+ * @dev_id: Id of the port
+ *
+ * Return: IRQHANDLED
+ */
+static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned long flags;
+ unsigned int isrstatus;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Read the interrupt status register to determine which
+ * interrupt(s) is/are active.
+ */
+ isrstatus = readl(port->membase + CDNS_UART_ISR);
+
+ if (isrstatus & CDNS_UART_RX_IRQS)
+ cdns_uart_handle_rx(port, isrstatus);
+
+ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
+ cdns_uart_handle_tx(port);
+
+ writel(isrstatus, port->membase + CDNS_UART_ISR);
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore(&port->lock, flags);
@@ -395,14 +390,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
&div8);
/* Write new divisors to hardware */
- mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mreg = readl(port->membase + CDNS_UART_MR);
if (div8)
mreg |= CDNS_UART_MR_CLKSEL;
else
mreg &= ~CDNS_UART_MR_CLKSEL;
- writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
- writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
- writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
+ writel(mreg, port->membase + CDNS_UART_MR);
+ writel(cd, port->membase + CDNS_UART_BAUDGEN);
+ writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
cdns_uart->baud = baud;
return calc_baud;
@@ -449,9 +444,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -476,11 +471,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
@@ -489,11 +484,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
* enable bit and RX enable bit to enable the transmitter and
* receiver.
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -510,43 +505,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
*/
static void cdns_uart_start_tx(struct uart_port *port)
{
- unsigned int status, numbytes = port->fifosize;
+ unsigned int status;
- if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
+ if (uart_tx_stopped(port))
return;
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
- /* Set the TX enable bit and clear the TX disable bit to enable the
+ /*
+ * Set the TX enable bit and clear the TX disable bit to enable the
* transmitter.
*/
- writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= ~CDNS_UART_CR_TX_DIS;
+ status |= CDNS_UART_CR_TX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
- while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
- /* Break if no more data available in the UART buffer */
- if (uart_circ_empty(&port->state->xmit))
- break;
+ if (uart_circ_empty(&port->state->xmit))
+ return;
- /* Get the data from the UART circular buffer and
- * write it to the cdns_uart's TX_FIFO register.
- */
- writel(port->state->xmit.buf[port->state->xmit.tail],
- port->membase + CDNS_UART_FIFO_OFFSET);
- port->icount.tx++;
+ cdns_uart_handle_tx(port);
- /* Adjust the tail of the UART buffer and wrap
- * the buffer if it reaches limit.
- */
- port->state->xmit.tail = (port->state->xmit.tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
/* Enable the TX Empty interrupt */
- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET);
-
- if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
}
/**
@@ -557,10 +537,10 @@ static void cdns_uart_stop_tx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
regval |= CDNS_UART_CR_TX_DIS;
/* Disable the transmitter */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -571,10 +551,13 @@ static void cdns_uart_stop_rx(struct uart_port *port)
{
unsigned int regval;
- regval = readl(port->membase + CDNS_UART_CR_OFFSET);
- regval |= CDNS_UART_CR_RX_DIS;
+ /* Disable RX IRQs */
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR);
+
/* Disable the receiver */
- writel(regval, port->membase + CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR);
+ regval |= CDNS_UART_CR_RX_DIS;
+ writel(regval, port->membase + CDNS_UART_CR);
}
/**
@@ -587,7 +570,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
- status = readl(port->membase + CDNS_UART_SR_OFFSET) &
+ status = readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY;
return status ? TIOCSER_TEMT : 0;
}
@@ -605,15 +588,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
if (ctl == -1)
writel(CDNS_UART_CR_STARTBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
else {
if ((status & CDNS_UART_CR_STOPBRK) == 0)
writel(CDNS_UART_CR_STOPBRK | status,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
}
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -636,18 +619,18 @@ static void cdns_uart_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
/* Wait for the transmit FIFO to empty before making changes */
- if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
+ if (!(readl(port->membase + CDNS_UART_CR) &
CDNS_UART_CR_TX_DIS)) {
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_TXEMPTY)) {
cpu_relax();
}
}
/* Disable the TX and RX to set baud rate */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
@@ -666,20 +649,20 @@ static void cdns_uart_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
/*
* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver.
*/
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
@@ -699,7 +682,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
- mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
+ mode_reg = readl(port->membase + CDNS_UART_MR);
/* Handling Data Size */
switch (termios->c_cflag & CSIZE) {
@@ -740,7 +723,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
cval |= CDNS_UART_MR_PARITY_NONE;
}
cval |= mode_reg & 1;
- writel(cval, port->membase + CDNS_UART_MR_OFFSET);
+ writel(cval, port->membase + CDNS_UART_MR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -753,63 +736,67 @@ static void cdns_uart_set_termios(struct uart_port *port,
*/
static int cdns_uart_startup(struct uart_port *port)
{
- unsigned int retval = 0, status = 0;
+ int ret;
+ unsigned long flags;
+ unsigned int status = 0;
- retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,
- (void *)port);
- if (retval)
- return retval;
+ spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars.
*/
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
- port->membase + CDNS_UART_CR_OFFSET);
-
- status = readl(port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
- /* Clear the RX disable and TX disable bits and then set the TX enable
- * bit and RX enable bit to enable the transmitter and receiver.
+ /*
+ * Clear the RX disable bit and then set the RX enable bit to enable
+ * the receiver.
*/
- writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS))
- | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN |
- CDNS_UART_CR_STOPBRK),
- port->membase + CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR);
+ status &= CDNS_UART_CR_RX_DIS;
+ status |= CDNS_UART_CR_RX_EN;
+ writel(status, port->membase + CDNS_UART_CR);
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity.
*/
writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
- port->membase + CDNS_UART_MR_OFFSET);
+ port->membase + CDNS_UART_MR);
/*
* Set the RX FIFO Trigger level to use most of the FIFO, but it
* can be tuned with a module parameter
*/
- writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Clear out any pending interrupts before enabling them */
- writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
- port->membase + CDNS_UART_ISR_OFFSET);
+ writel(readl(port->membase + CDNS_UART_ISR),
+ port->membase + CDNS_UART_ISR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
+ if (ret) {
+ dev_err(port->dev, "request_irq '%d' failed with %d\n",
+ port->irq, ret);
+ return ret;
+ }
/* Set the Interrupt Registers with desired interrupts */
- writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY |
- CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN |
- CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
- return retval;
+ return 0;
}
/**
@@ -819,14 +806,21 @@ static int cdns_uart_startup(struct uart_port *port)
static void cdns_uart_shutdown(struct uart_port *port)
{
int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
/* Disable interrupts */
- status = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(status, port->membase + CDNS_UART_IDR_OFFSET);
+ status = readl(port->membase + CDNS_UART_IMR);
+ writel(status, port->membase + CDNS_UART_IDR);
+ writel(0xffffffff, port->membase + CDNS_UART_ISR);
/* Disable the TX and RX */
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- port->membase + CDNS_UART_CR_OFFSET);
+ port->membase + CDNS_UART_CR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
free_irq(port->irq, port);
}
@@ -928,7 +922,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 val;
- val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
+ val = readl(port->membase + CDNS_UART_MODEMCR);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
@@ -937,55 +931,46 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR;
- writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
+ writel(val, port->membase + CDNS_UART_MODEMCR);
}
#ifdef CONFIG_CONSOLE_POLL
static int cdns_uart_poll_get_char(struct uart_port *port)
{
- u32 imr;
int c;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Check if FIFO is empty */
- if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
+ if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
c = NO_POLL_CHAR;
else /* Read a character */
- c = (unsigned char) readl(
- port->membase + CDNS_UART_FIFO_OFFSET);
+ c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return c;
}
static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
- u32 imr;
+ unsigned long flags;
- /* Disable all interrupts */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ spin_lock_irqsave(&port->lock, flags);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Write a character */
- writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(c, port->membase + CDNS_UART_FIFO);
/* Wait until FIFO is empty */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
- /* Enable interrupts */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ spin_unlock_irqrestore(&port->lock, flags);
return;
}
@@ -1059,8 +1044,7 @@ static struct uart_port *cdns_uart_get_port(int id)
*/
static void cdns_uart_console_wait_tx(struct uart_port *port)
{
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
barrier();
}
@@ -1072,7 +1056,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port)
static void cdns_uart_console_putchar(struct uart_port *port, int ch)
{
cdns_uart_console_wait_tx(port);
- writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
+ writel(ch, port->membase + CDNS_UART_FIFO);
}
static void __init cdns_early_write(struct console *con, const char *s,
@@ -1093,7 +1077,9 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
return 0;
}
-EARLYCON_DECLARE(cdns, cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
/**
* cdns_uart_console_write - perform write operation
@@ -1109,30 +1095,33 @@ static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int imr, ctrl;
int locked = 1;
- if (oops_in_progress)
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */
- imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
- writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR);
+ writel(imr, port->membase + CDNS_UART_IDR);
/*
* Make sure that the tx part is enabled. Set the TX enable bit and
* clear the TX disable bit to enable the transmitter.
*/
- ctrl = readl(port->membase + CDNS_UART_CR_OFFSET);
- writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- port->membase + CDNS_UART_CR_OFFSET);
+ ctrl = readl(port->membase + CDNS_UART_CR);
+ ctrl &= ~CDNS_UART_CR_TX_DIS;
+ ctrl |= CDNS_UART_CR_TX_EN;
+ writel(ctrl, port->membase + CDNS_UART_CR);
uart_console_write(port, s, count, cdns_uart_console_putchar);
cdns_uart_console_wait_tx(port);
- writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl, port->membase + CDNS_UART_CR);
/* restore interrupt state */
- writel(imr, port->membase + CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
@@ -1244,14 +1233,13 @@ static int cdns_uart_suspend(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY))
- readl(port->membase + CDNS_UART_FIFO_OFFSET);
+ readl(port->membase + CDNS_UART_FIFO);
/* set RX trigger level to 1 */
- writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(1, port->membase + CDNS_UART_RXWM);
/* disable RX timeout interrups */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IDR_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1290,30 +1278,28 @@ static int cdns_uart_resume(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
- while (readl(port->membase + CDNS_UART_CR_OFFSET) &
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
+ while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* restore rx timeout value */
- writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
/* Enable Tx/Rx */
- ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR);
spin_unlock_irqrestore(&port->lock, flags);
} else {
spin_lock_irqsave(&port->lock, flags);
/* restore original rx trigger level */
- writel(rx_trigger_level,
- port->membase + CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
/* enable RX timeout interrupt */
- writel(CDNS_UART_IXR_TOUT,
- port->membase + CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1406,27 +1392,30 @@ static int cdns_uart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
rc = -ENODEV;
goto err_out_notif_unreg;
- } else {
- /* Register the port.
- * This function also registers this device with the tty layer
- * and triggers invocation of the config_port() entry point.
- */
- port->mapbase = res->start;
- port->irq = irq;
- port->dev = &pdev->dev;
- port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
- port->private_data = cdns_uart_data;
- cdns_uart_data->port = port;
- platform_set_drvdata(pdev, port);
- rc = uart_add_one_port(&cdns_uart_uart_driver, port);
- if (rc) {
- dev_err(&pdev->dev,
- "uart_add_one_port() failed; err=%i\n", rc);
- goto err_out_notif_unreg;
- }
- return 0;
}
+ /*
+ * Register the port.
+ * This function also registers this device with the tty layer
+ * and triggers invocation of the config_port() entry point.
+ */
+ port->mapbase = res->start;
+ port->irq = irq;
+ port->dev = &pdev->dev;
+ port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
+ port->private_data = cdns_uart_data;
+ cdns_uart_data->port = port;
+ platform_set_drvdata(pdev, port);
+
+ rc = uart_add_one_port(&cdns_uart_uart_driver, port);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "uart_add_one_port() failed; err=%i\n", rc);
+ goto err_out_notif_unreg;
+ }
+
+ return 0;
+
err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 2b65bb7ff..eeefd76a3 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -1181,6 +1181,10 @@ static void zs_console_write(struct console *co, const char *s,
if (txint & TxINT_ENAB) {
zport->regs[1] |= TxINT_ENAB;
write_zsreg(zport, R1, zport->regs[1]);
+
+ /* Resume any transmission as the TxIP bit won't be set. */
+ if (!zport->tx_stopped)
+ zs_raw_transmit_chars(zport);
}
spin_unlock_irqrestore(&scc->zlock, flags);
}