summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig47
-rw-r--r--drivers/tty/Makefile1
-rw-r--r--drivers/tty/bfin_jtag_comm.c13
-rw-r--r--drivers/tty/goldfish.c2
-rw-r--r--drivers/tty/hvc/hvc_opal.c2
-rw-r--r--drivers/tty/ipwireless/hardware.c2
-rw-r--r--drivers/tty/mips_ejtag_fdc.c1303
-rw-r--r--drivers/tty/n_gsm.c12
-rw-r--r--drivers/tty/serial/8250/8250.h23
-rw-r--r--drivers/tty/serial/8250/8250_core.c524
-rw-r--r--drivers/tty/serial/8250/8250_dw.c93
-rw-r--r--drivers/tty/serial/8250/8250_early.c74
-rw-r--r--drivers/tty/serial/8250/8250_em.c1
-rw-r--r--drivers/tty/serial/8250/8250_fintek.c13
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c1
-rw-r--r--drivers/tty/serial/8250/8250_pci.c424
-rw-r--r--drivers/tty/serial/8250/Kconfig1
-rw-r--r--drivers/tty/serial/Kconfig32
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/amba-pl011.c234
-rw-r--r--drivers/tty/serial/apbuart.c2
-rw-r--r--drivers/tty/serial/ar933x_uart.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c78
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c4
-rw-r--r--drivers/tty/serial/bfin_uart.c2
-rw-r--r--drivers/tty/serial/clps711x.c2
-rw-r--r--drivers/tty/serial/cpm_uart/Makefile2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/tty/serial/earlycon.c140
-rw-r--r--drivers/tty/serial/fsl_lpuart.c7
-rw-r--r--drivers/tty/serial/imx.c317
-rw-r--r--drivers/tty/serial/jsm/jsm_cls.c2
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c6
-rw-r--r--drivers/tty/serial/max3100.c2
-rw-r--r--drivers/tty/serial/mfd.c1505
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c2
-rw-r--r--drivers/tty/serial/msm_serial.h9
-rw-r--r--drivers/tty/serial/msm_serial_hs.c1874
-rw-r--r--drivers/tty/serial/mxs-auart.c18
-rw-r--r--drivers/tty/serial/of_serial.c12
-rw-r--r--drivers/tty/serial/omap-serial.c10
-rw-r--r--drivers/tty/serial/pmac_zilog.c2
-rw-r--r--drivers/tty/serial/pxa.c2
-rw-r--r--drivers/tty/serial/samsung.c1
-rw-r--r--drivers/tty/serial/sc16is7xx.c46
-rw-r--r--drivers/tty/serial/serial-tegra.c2
-rw-r--r--drivers/tty/serial/serial_core.c52
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c50
-rw-r--r--drivers/tty/serial/sh-sci.c88
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c2
-rw-r--r--drivers/tty/serial/sprd_serial.c10
-rw-r--r--drivers/tty/serial/st-asc.c2
-rw-r--r--drivers/tty/serial/uartlite.c2
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c242
-rw-r--r--drivers/tty/sysrq.c1
-rw-r--r--drivers/tty/tty_io.c26
-rw-r--r--drivers/tty/tty_ioctl.c16
-rw-r--r--drivers/tty/vt/vt.c74
-rw-r--r--drivers/tty/vt/vt_ioctl.c2
62 files changed, 2928 insertions, 4499 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index b24aa010f68c..c01f45095877 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -419,4 +419,51 @@ config DA_CONSOLE
help
This enables a console on a Dash channel.
+config MIPS_EJTAG_FDC_TTY
+ bool "MIPS EJTAG Fast Debug Channel TTY"
+ depends on MIPS_CDMM
+ help
+ This enables a TTY and console on the MIPS EJTAG Fast Debug Channels,
+ if they are present. This can be useful when working with an EJTAG
+ probe which supports it, to get console output and a login prompt via
+ EJTAG without needing to connect a serial cable.
+
+ TTY devices are named e.g. ttyFDC3c2 (for FDC channel 2 of the FDC on
+ CPU3).
+
+ The console can be enabled with console=fdc1 (for FDC channel 1 on all
+ CPUs). Do not use the console unless there is a debug probe attached
+ to drain the FDC TX FIFO.
+
+ If unsure, say N.
+
+config MIPS_EJTAG_FDC_EARLYCON
+ bool "Early FDC console"
+ depends on MIPS_EJTAG_FDC_TTY
+ help
+ This registers a console on FDC channel 1 very early during boot (from
+ MIPS arch code). This is useful for bring-up and debugging early boot
+ issues.
+
+ Do not enable unless there is a debug probe attached to drain the FDC
+ TX FIFO.
+
+ If unsure, say N.
+
+config MIPS_EJTAG_FDC_KGDB
+ bool "Use KGDB over an FDC channel"
+ depends on MIPS_EJTAG_FDC_TTY && KGDB
+ default y
+ help
+ This enables the use of KGDB over an FDC channel, allowing KGDB to be
+ used remotely or when a serial port isn't available.
+
+config MIPS_EJTAG_FDC_KGDB_CHAN
+ int "KGDB FDC channel"
+ depends on MIPS_EJTAG_FDC_KGDB
+ range 2 15
+ default 3
+ help
+ FDC channel number to use for KGDB.
+
endif # TTY
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 58ad1c05b7f8..5817e2397463 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -29,5 +29,6 @@ obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
obj-$(CONFIG_DA_TTY) += metag_da.o
+obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
obj-y += ipwireless/
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index d7b198c400c7..ce24182f8514 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -210,18 +210,6 @@ bfin_jc_chars_in_buffer(struct tty_struct *tty)
return circ_cnt(&bfin_jc_write_buf);
}
-static void
-bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- unsigned long expire = jiffies + timeout;
- while (!circ_empty(&bfin_jc_write_buf)) {
- if (signal_pending(current))
- break;
- if (time_after(jiffies, expire))
- break;
- }
-}
-
static const struct tty_operations bfin_jc_ops = {
.open = bfin_jc_open,
.close = bfin_jc_close,
@@ -230,7 +218,6 @@ static const struct tty_operations bfin_jc_ops = {
.flush_chars = bfin_jc_flush_chars,
.write_room = bfin_jc_write_room,
.chars_in_buffer = bfin_jc_chars_in_buffer,
- .wait_until_sent = bfin_jc_wait_until_sent,
};
static int __init bfin_jc_init(void)
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 967b2c2b7cf1..0655fecf8240 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -229,7 +229,6 @@ static int goldfish_tty_probe(struct platform_device *pdev)
{
struct goldfish_tty *qtty;
int ret = -EINVAL;
- int i;
struct resource *r;
struct device *ttydev;
void __iomem *base;
@@ -293,7 +292,6 @@ static int goldfish_tty_probe(struct platform_device *pdev)
mutex_unlock(&goldfish_tty_lock);
return 0;
- tty_unregister_device(goldfish_tty_driver, i);
err_tty_register_device_failed:
free_irq(irq, pdev);
err_request_irq_failed:
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 071551bf3e9a..543b234e70fc 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -41,7 +41,7 @@
static const char hvc_opal_name[] = "hvc_opal";
-static struct of_device_id hvc_opal_match[] = {
+static const struct of_device_id hvc_opal_match[] = {
{ .name = "serial", .compatible = "ibm,opal-console-raw" },
{ .name = "serial", .compatible = "ibm,opal-console-hvsi" },
{ },
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c
index 5c77e1eac4ee..ad7031a4f3c4 100644
--- a/drivers/tty/ipwireless/hardware.c
+++ b/drivers/tty/ipwireless/hardware.c
@@ -1455,7 +1455,7 @@ static void __handle_setup_get_version_rsp(struct ipw_hardware *hw)
return;
}
- set_RTS(hw, PRIO_SETUP, channel_idx,
+ ret = set_RTS(hw, PRIO_SETUP, channel_idx,
(hw->control_lines [channel_idx] &
IPW_CONTROL_LINE_RTS) != 0);
if (ret) {
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
new file mode 100644
index 000000000000..04d9e23d1ee1
--- /dev/null
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -0,0 +1,1303 @@
+/*
+ * TTY driver for MIPS EJTAG Fast Debug Channels.
+ *
+ * Copyright (C) 2007-2015 Imagination Technologies Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for more
+ * details.
+ */
+
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kgdb.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+
+#include <asm/cdmm.h>
+#include <asm/irq.h>
+
+/* Register offsets */
+#define REG_FDACSR 0x00 /* FDC Access Control and Status Register */
+#define REG_FDCFG 0x08 /* FDC Configuration Register */
+#define REG_FDSTAT 0x10 /* FDC Status Register */
+#define REG_FDRX 0x18 /* FDC Receive Register */
+#define REG_FDTX(N) (0x20+0x8*(N)) /* FDC Transmit Register n (0..15) */
+
+/* Register fields */
+
+#define REG_FDCFG_TXINTTHRES_SHIFT 18
+#define REG_FDCFG_TXINTTHRES (0x3 << REG_FDCFG_TXINTTHRES_SHIFT)
+#define REG_FDCFG_TXINTTHRES_DISABLED (0x0 << REG_FDCFG_TXINTTHRES_SHIFT)
+#define REG_FDCFG_TXINTTHRES_EMPTY (0x1 << REG_FDCFG_TXINTTHRES_SHIFT)
+#define REG_FDCFG_TXINTTHRES_NOTFULL (0x2 << REG_FDCFG_TXINTTHRES_SHIFT)
+#define REG_FDCFG_TXINTTHRES_NEAREMPTY (0x3 << REG_FDCFG_TXINTTHRES_SHIFT)
+#define REG_FDCFG_RXINTTHRES_SHIFT 16
+#define REG_FDCFG_RXINTTHRES (0x3 << REG_FDCFG_RXINTTHRES_SHIFT)
+#define REG_FDCFG_RXINTTHRES_DISABLED (0x0 << REG_FDCFG_RXINTTHRES_SHIFT)
+#define REG_FDCFG_RXINTTHRES_FULL (0x1 << REG_FDCFG_RXINTTHRES_SHIFT)
+#define REG_FDCFG_RXINTTHRES_NOTEMPTY (0x2 << REG_FDCFG_RXINTTHRES_SHIFT)
+#define REG_FDCFG_RXINTTHRES_NEARFULL (0x3 << REG_FDCFG_RXINTTHRES_SHIFT)
+#define REG_FDCFG_TXFIFOSIZE_SHIFT 8
+#define REG_FDCFG_TXFIFOSIZE (0xff << REG_FDCFG_TXFIFOSIZE_SHIFT)
+#define REG_FDCFG_RXFIFOSIZE_SHIFT 0
+#define REG_FDCFG_RXFIFOSIZE (0xff << REG_FDCFG_RXFIFOSIZE_SHIFT)
+
+#define REG_FDSTAT_TXCOUNT_SHIFT 24
+#define REG_FDSTAT_TXCOUNT (0xff << REG_FDSTAT_TXCOUNT_SHIFT)
+#define REG_FDSTAT_RXCOUNT_SHIFT 16
+#define REG_FDSTAT_RXCOUNT (0xff << REG_FDSTAT_RXCOUNT_SHIFT)
+#define REG_FDSTAT_RXCHAN_SHIFT 4
+#define REG_FDSTAT_RXCHAN (0xf << REG_FDSTAT_RXCHAN_SHIFT)
+#define REG_FDSTAT_RXE BIT(3) /* Rx Empty */
+#define REG_FDSTAT_RXF BIT(2) /* Rx Full */
+#define REG_FDSTAT_TXE BIT(1) /* Tx Empty */
+#define REG_FDSTAT_TXF BIT(0) /* Tx Full */
+
+/* Default channel for the early console */
+#define CONSOLE_CHANNEL 1
+
+#define NUM_TTY_CHANNELS 16
+
+#define RX_BUF_SIZE 1024
+
+/*
+ * When the IRQ is unavailable, the FDC state must be polled for incoming data
+ * and space becoming available in TX FIFO.
+ */
+#define FDC_TTY_POLL (HZ / 50)
+
+struct mips_ejtag_fdc_tty;
+
+/**
+ * struct mips_ejtag_fdc_tty_port - Wrapper struct for FDC tty_port.
+ * @port: TTY port data
+ * @driver: TTY driver.
+ * @rx_lock: Lock for rx_buf.
+ * This protects between the hard interrupt and user
+ * context. It's also held during read SWITCH operations.
+ * @rx_buf: Read buffer.
+ * @xmit_lock: Lock for xmit_*, and port.xmit_buf.
+ * This protects between user context and kernel thread.
+ * It is used from chars_in_buffer()/write_room() TTY
+ * callbacks which are used during wait operations, so a
+ * mutex is unsuitable.
+ * @xmit_cnt: Size of xmit buffer contents.
+ * @xmit_head: Head of xmit buffer where data is written.
+ * @xmit_tail: Tail of xmit buffer where data is read.
+ * @xmit_empty: Completion for xmit buffer being empty.
+ */
+struct mips_ejtag_fdc_tty_port {
+ struct tty_port port;
+ struct mips_ejtag_fdc_tty *driver;
+ raw_spinlock_t rx_lock;
+ void *rx_buf;
+ spinlock_t xmit_lock;
+ unsigned int xmit_cnt;
+ unsigned int xmit_head;
+ unsigned int xmit_tail;
+ struct completion xmit_empty;
+};
+
+/**
+ * struct mips_ejtag_fdc_tty - Driver data for FDC as a whole.
+ * @dev: FDC device (for dev_*() logging).
+ * @driver: TTY driver.
+ * @cpu: CPU number for this FDC.
+ * @fdc_name: FDC name (not for base of channel names).
+ * @driver_name: Base of driver name.
+ * @ports: Per-channel data.
+ * @waitqueue: Wait queue for waiting for TX data, or for space in TX
+ * FIFO.
+ * @lock: Lock to protect FDCFG (interrupt enable).
+ * @thread: KThread for writing out data to FDC.
+ * @reg: FDC registers.
+ * @tx_fifo: TX FIFO size.
+ * @xmit_size: Size of each port's xmit buffer.
+ * @xmit_total: Total number of bytes (from all ports) to transmit.
+ * @xmit_next: Next port number to transmit from (round robin).
+ * @xmit_full: Indicates TX FIFO is full, we're waiting for space.
+ * @irq: IRQ number (negative if no IRQ).
+ * @removing: Indicates the device is being removed and @poll_timer
+ * should not be restarted.
+ * @poll_timer: Timer for polling for interrupt events when @irq < 0.
+ * @sysrq_pressed: Whether the magic sysrq key combination has been
+ * detected. See mips_ejtag_fdc_handle().
+ */
+struct mips_ejtag_fdc_tty {
+ struct device *dev;
+ struct tty_driver *driver;
+ unsigned int cpu;
+ char fdc_name[16];
+ char driver_name[16];
+ struct mips_ejtag_fdc_tty_port ports[NUM_TTY_CHANNELS];
+ wait_queue_head_t waitqueue;
+ raw_spinlock_t lock;
+ struct task_struct *thread;
+
+ void __iomem *reg;
+ u8 tx_fifo;
+
+ unsigned int xmit_size;
+ atomic_t xmit_total;
+ unsigned int xmit_next;
+ bool xmit_full;
+
+ int irq;
+ bool removing;
+ struct timer_list poll_timer;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+ bool sysrq_pressed;
+#endif
+};
+
+/* Hardware access */
+
+static inline void mips_ejtag_fdc_write(struct mips_ejtag_fdc_tty *priv,
+ unsigned int offs, unsigned int data)
+{
+ iowrite32(data, priv->reg + offs);
+}
+
+static inline unsigned int mips_ejtag_fdc_read(struct mips_ejtag_fdc_tty *priv,
+ unsigned int offs)
+{
+ return ioread32(priv->reg + offs);
+}
+
+/* Encoding of byte stream in FDC words */
+
+/**
+ * struct fdc_word - FDC word encoding some number of bytes of data.
+ * @word: Raw FDC word.
+ * @bytes: Number of bytes encoded by @word.
+ */
+struct fdc_word {
+ u32 word;
+ unsigned int bytes;
+};
+
+/*
+ * This is a compact encoding which allows every 1 byte, 2 byte, and 3 byte
+ * sequence to be encoded in a single word, while allowing the majority of 4
+ * byte sequences (including all ASCII and common binary data) to be encoded in
+ * a single word too.
+ * _______________________ _____________
+ * | FDC Word | |
+ * |31-24|23-16|15-8 | 7-0 | Bytes |
+ * |_____|_____|_____|_____|_____________|
+ * | | | | | |
+ * |0x80 |0x80 |0x80 | WW | WW |
+ * |0x81 |0x81 | XX | WW | WW XX |
+ * |0x82 | YY | XX | WW | WW XX YY |
+ * | ZZ | YY | XX | WW | WW XX YY ZZ |
+ * |_____|_____|_____|_____|_____________|
+ *
+ * Note that the 4-byte encoding can only be used where none of the other 3
+ * encodings match, otherwise it must fall back to the 3 byte encoding.
+ */
+
+/* ranges >= 1 && sizes[0] >= 1 */
+static struct fdc_word mips_ejtag_fdc_encode(const char **ptrs,
+ unsigned int *sizes,
+ unsigned int ranges)
+{
+ struct fdc_word word = { 0, 0 };
+ const char **ptrs_end = ptrs + ranges;
+
+ for (; ptrs < ptrs_end; ++ptrs) {
+ const char *ptr = *(ptrs++);
+ const char *end = ptr + *(sizes++);
+
+ for (; ptr < end; ++ptr) {
+ word.word |= (u8)*ptr << (8*word.bytes);
+ ++word.bytes;
+ if (word.bytes == 4)
+ goto done;
+ }
+ }
+done:
+ /* Choose the appropriate encoding */
+ switch (word.bytes) {
+ case 4:
+ /* 4 byte encoding, but don't match the 1-3 byte encodings */
+ if ((word.word >> 8) != 0x808080 &&
+ (word.word >> 16) != 0x8181 &&
+ (word.word >> 24) != 0x82)
+ break;
+ /* Fall back to a 3 byte encoding */
+ word.bytes = 3;
+ word.word &= 0x00ffffff;
+ case 3:
+ /* 3 byte encoding */
+ word.word |= 0x82000000;
+ break;
+ case 2:
+ /* 2 byte encoding */
+ word.word |= 0x81810000;
+ break;
+ case 1:
+ /* 1 byte encoding */
+ word.word |= 0x80808000;
+ break;
+ }
+ return word;
+}
+
+static unsigned int mips_ejtag_fdc_decode(u32 word, char *buf)
+{
+ buf[0] = (u8)word;
+ word >>= 8;
+ if (word == 0x808080)
+ return 1;
+ buf[1] = (u8)word;
+ word >>= 8;
+ if (word == 0x8181)
+ return 2;
+ buf[2] = (u8)word;
+ word >>= 8;
+ if (word == 0x82)
+ return 3;
+ buf[3] = (u8)word;
+ return 4;
+}
+
+/* Console operations */
+
+/**
+ * struct mips_ejtag_fdc_console - Wrapper struct for FDC consoles.
+ * @cons: Console object.
+ * @tty_drv: TTY driver associated with this console.
+ * @lock: Lock to protect concurrent access to other fields.
+ * This is raw because it may be used very early.
+ * @initialised: Whether the console is initialised.
+ * @regs: Registers base address for each CPU.
+ */
+struct mips_ejtag_fdc_console {
+ struct console cons;
+ struct tty_driver *tty_drv;
+ raw_spinlock_t lock;
+ bool initialised;
+ void __iomem *regs[NR_CPUS];
+};
+
+/* Low level console write shared by early console and normal console */
+static void mips_ejtag_fdc_console_write(struct console *c, const char *s,
+ unsigned int count)
+{
+ struct mips_ejtag_fdc_console *cons =
+ container_of(c, struct mips_ejtag_fdc_console, cons);
+ void __iomem *regs;
+ struct fdc_word word;
+ unsigned long flags;
+ unsigned int i, buf_len, cpu;
+ bool done_cr = false;
+ char buf[4];
+ const char *buf_ptr = buf;
+ /* Number of bytes of input data encoded up to each byte in buf */
+ u8 inc[4];
+
+ local_irq_save(flags);
+ cpu = smp_processor_id();
+ regs = cons->regs[cpu];
+ /* First console output on this CPU? */
+ if (!regs) {
+ regs = mips_cdmm_early_probe(0xfd);
+ cons->regs[cpu] = regs;
+ }
+ /* Already tried and failed to find FDC on this CPU? */
+ if (IS_ERR(regs))
+ goto out;
+ while (count) {
+ /*
+ * Copy the next few characters to a buffer so we can inject
+ * carriage returns before newlines.
+ */
+ for (buf_len = 0, i = 0; buf_len < 4 && i < count; ++buf_len) {
+ if (s[i] == '\n' && !done_cr) {
+ buf[buf_len] = '\r';
+ done_cr = true;
+ } else {
+ buf[buf_len] = s[i];
+ done_cr = false;
+ ++i;
+ }
+ inc[buf_len] = i;
+ }
+ word = mips_ejtag_fdc_encode(&buf_ptr, &buf_len, 1);
+ count -= inc[word.bytes - 1];
+ s += inc[word.bytes - 1];
+
+ /* Busy wait until there's space in fifo */
+ while (ioread32(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
+ ;
+ iowrite32(word.word, regs + REG_FDTX(c->index));
+ }
+out:
+ local_irq_restore(flags);
+}
+
+static struct tty_driver *mips_ejtag_fdc_console_device(struct console *c,
+ int *index)
+{
+ struct mips_ejtag_fdc_console *cons =
+ container_of(c, struct mips_ejtag_fdc_console, cons);
+
+ *index = c->index;
+ return cons->tty_drv;
+}
+
+/* Initialise an FDC console (early or normal */
+static int __init mips_ejtag_fdc_console_init(struct mips_ejtag_fdc_console *c)
+{
+ void __iomem *regs;
+ unsigned long flags;
+ int ret = 0;
+
+ raw_spin_lock_irqsave(&c->lock, flags);
+ /* Don't init twice */
+ if (c->initialised)
+ goto out;
+ /* Look for the FDC device */
+ regs = mips_cdmm_early_probe(0xfd);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
+ goto out;
+ }
+
+ c->initialised = true;
+ c->regs[smp_processor_id()] = regs;
+ register_console(&c->cons);
+out:
+ raw_spin_unlock_irqrestore(&c->lock, flags);
+ return ret;
+}
+
+static struct mips_ejtag_fdc_console mips_ejtag_fdc_con = {
+ .cons = {
+ .name = "fdc",
+ .write = mips_ejtag_fdc_console_write,
+ .device = mips_ejtag_fdc_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ },
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(mips_ejtag_fdc_con.lock),
+};
+
+/* TTY RX/TX operations */
+
+/**
+ * mips_ejtag_fdc_put_chan() - Write out a block of channel data.
+ * @priv: Pointer to driver private data.
+ * @chan: Channel number.
+ *
+ * Write a single block of data out to the debug adapter. If the circular buffer
+ * is wrapped then only the first block is written.
+ *
+ * Returns: The number of bytes that were written.
+ */
+static unsigned int mips_ejtag_fdc_put_chan(struct mips_ejtag_fdc_tty *priv,
+ unsigned int chan)
+{
+ struct mips_ejtag_fdc_tty_port *dport;
+ struct tty_struct *tty;
+ const char *ptrs[2];
+ unsigned int sizes[2] = { 0 };
+ struct fdc_word word = { .bytes = 0 };
+ unsigned long flags;
+
+ dport = &priv->ports[chan];
+ spin_lock(&dport->xmit_lock);
+ if (dport->xmit_cnt) {
+ ptrs[0] = dport->port.xmit_buf + dport->xmit_tail;
+ sizes[0] = min_t(unsigned int,
+ priv->xmit_size - dport->xmit_tail,
+ dport->xmit_cnt);
+ ptrs[1] = dport->port.xmit_buf;
+ sizes[1] = dport->xmit_cnt - sizes[0];
+ word = mips_ejtag_fdc_encode(ptrs, sizes, 1 + !!sizes[1]);
+
+ dev_dbg(priv->dev, "%s%u: out %08x: \"%*pE%*pE\"\n",
+ priv->driver_name, chan, word.word,
+ min_t(int, word.bytes, sizes[0]), ptrs[0],
+ max_t(int, 0, word.bytes - sizes[0]), ptrs[1]);
+
+ local_irq_save(flags);
+ /* Maybe we raced with the console and TX FIFO is full */
+ if (mips_ejtag_fdc_read(priv, REG_FDSTAT) & REG_FDSTAT_TXF)
+ word.bytes = 0;
+ else
+ mips_ejtag_fdc_write(priv, REG_FDTX(chan), word.word);
+ local_irq_restore(flags);
+
+ dport->xmit_cnt -= word.bytes;
+ if (!dport->xmit_cnt) {
+ /* Reset pointers to avoid wraps */
+ dport->xmit_head = 0;
+ dport->xmit_tail = 0;
+ complete(&dport->xmit_empty);
+ } else {
+ dport->xmit_tail += word.bytes;
+ if (dport->xmit_tail >= priv->xmit_size)
+ dport->xmit_tail -= priv->xmit_size;
+ }
+ atomic_sub(word.bytes, &priv->xmit_total);
+ }
+ spin_unlock(&dport->xmit_lock);
+
+ /* If we've made more data available, wake up tty */
+ if (sizes[0] && word.bytes) {
+ tty = tty_port_tty_get(&dport->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
+ }
+
+ return word.bytes;
+}
+
+/**
+ * mips_ejtag_fdc_put() - Kernel thread to write out channel data to FDC.
+ * @arg: Driver pointer.
+ *
+ * This kernel thread runs while @priv->xmit_total != 0, and round robins the
+ * channels writing out blocks of buffered data to the FDC TX FIFO.
+ */
+static int mips_ejtag_fdc_put(void *arg)
+{
+ struct mips_ejtag_fdc_tty *priv = arg;
+ struct mips_ejtag_fdc_tty_port *dport;
+ unsigned int ret;
+ u32 cfg;
+
+ __set_current_state(TASK_RUNNING);
+ while (!kthread_should_stop()) {
+ /* Wait for data to actually write */
+ wait_event_interruptible(priv->waitqueue,
+ atomic_read(&priv->xmit_total) ||
+ kthread_should_stop());
+ if (kthread_should_stop())
+ break;
+
+ /* Wait for TX FIFO space to write data */
+ raw_spin_lock_irq(&priv->lock);
+ if (mips_ejtag_fdc_read(priv, REG_FDSTAT) & REG_FDSTAT_TXF) {
+ priv->xmit_full = true;
+ if (priv->irq >= 0) {
+ /* Enable TX interrupt */
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ cfg &= ~REG_FDCFG_TXINTTHRES;
+ cfg |= REG_FDCFG_TXINTTHRES_NOTFULL;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ }
+ }
+ raw_spin_unlock_irq(&priv->lock);
+ wait_event_interruptible(priv->waitqueue,
+ !(mips_ejtag_fdc_read(priv, REG_FDSTAT)
+ & REG_FDSTAT_TXF) ||
+ kthread_should_stop());
+ if (kthread_should_stop())
+ break;
+
+ /* Find next channel with data to output */
+ for (;;) {
+ dport = &priv->ports[priv->xmit_next];
+ spin_lock(&dport->xmit_lock);
+ ret = dport->xmit_cnt;
+ spin_unlock(&dport->xmit_lock);
+ if (ret)
+ break;
+ /* Round robin */
+ ++priv->xmit_next;
+ if (priv->xmit_next >= NUM_TTY_CHANNELS)
+ priv->xmit_next = 0;
+ }
+
+ /* Try writing data to the chosen channel */
+ ret = mips_ejtag_fdc_put_chan(priv, priv->xmit_next);
+
+ /*
+ * If anything was output, move on to the next channel so as not
+ * to starve other channels.
+ */
+ if (ret) {
+ ++priv->xmit_next;
+ if (priv->xmit_next >= NUM_TTY_CHANNELS)
+ priv->xmit_next = 0;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * mips_ejtag_fdc_handle() - Handle FDC events.
+ * @priv: Pointer to driver private data.
+ *
+ * Handle FDC events, such as new incoming data which needs draining out of the
+ * RX FIFO and feeding into the appropriate TTY ports, and space becoming
+ * available in the TX FIFO which would allow more data to be written out.
+ */
+static void mips_ejtag_fdc_handle(struct mips_ejtag_fdc_tty *priv)
+{
+ struct mips_ejtag_fdc_tty_port *dport;
+ unsigned int stat, channel, data, cfg, i, flipped;
+ int len;
+ char buf[4];
+
+ for (;;) {
+ /* Find which channel the next FDC word is destined for */
+ stat = mips_ejtag_fdc_read(priv, REG_FDSTAT);
+ if (stat & REG_FDSTAT_RXE)
+ break;
+ channel = (stat & REG_FDSTAT_RXCHAN) >> REG_FDSTAT_RXCHAN_SHIFT;
+ dport = &priv->ports[channel];
+
+ /* Read out the FDC word, decode it, and pass to tty layer */
+ raw_spin_lock(&dport->rx_lock);
+ data = mips_ejtag_fdc_read(priv, REG_FDRX);
+
+ len = mips_ejtag_fdc_decode(data, buf);
+ dev_dbg(priv->dev, "%s%u: in %08x: \"%*pE\"\n",
+ priv->driver_name, channel, data, len, buf);
+
+ flipped = 0;
+ for (i = 0; i < len; ++i) {
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MIPS_EJTAG_FDC_KGDB
+ /* Support just Ctrl+C with KGDB channel */
+ if (channel == CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN) {
+ if (buf[i] == '\x03') { /* ^C */
+ handle_sysrq('g');
+ continue;
+ }
+ }
+#endif
+ /* Support Ctrl+O for console channel */
+ if (channel == mips_ejtag_fdc_con.cons.index) {
+ if (buf[i] == '\x0f') { /* ^O */
+ priv->sysrq_pressed =
+ !priv->sysrq_pressed;
+ if (priv->sysrq_pressed)
+ continue;
+ } else if (priv->sysrq_pressed) {
+ handle_sysrq(buf[i]);
+ priv->sysrq_pressed = false;
+ continue;
+ }
+ }
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+ /* Check the port isn't being shut down */
+ if (!dport->rx_buf)
+ continue;
+
+ flipped += tty_insert_flip_char(&dport->port, buf[i],
+ TTY_NORMAL);
+ }
+ if (flipped)
+ tty_flip_buffer_push(&dport->port);
+
+ raw_spin_unlock(&dport->rx_lock);
+ }
+
+ /* If TX FIFO no longer full we may be able to write more data */
+ raw_spin_lock(&priv->lock);
+ if (priv->xmit_full && !(stat & REG_FDSTAT_TXF)) {
+ priv->xmit_full = false;
+
+ /* Disable TX interrupt */
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ cfg &= ~REG_FDCFG_TXINTTHRES;
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+
+ /* Wait the kthread so it can try writing more data */
+ wake_up_interruptible(&priv->waitqueue);
+ }
+ raw_spin_unlock(&priv->lock);
+}
+
+/**
+ * mips_ejtag_fdc_isr() - Interrupt handler.
+ * @irq: IRQ number.
+ * @dev_id: Pointer to driver private data.
+ *
+ * This is the interrupt handler, used when interrupts are enabled.
+ *
+ * It simply triggers the common FDC handler code.
+ *
+ * Returns: IRQ_HANDLED if an FDC interrupt was pending.
+ * IRQ_NONE otherwise.
+ */
+static irqreturn_t mips_ejtag_fdc_isr(int irq, void *dev_id)
+{
+ struct mips_ejtag_fdc_tty *priv = dev_id;
+
+ /*
+ * We're not using proper per-cpu IRQs, so we must be careful not to
+ * handle IRQs on CPUs we're not interested in.
+ *
+ * Ideally proper per-cpu IRQ handlers could be used, but that doesn't
+ * fit well with the whole sharing of the main CPU IRQ lines. When we
+ * have something with a GIC that routes the FDC IRQs (i.e. no sharing
+ * between handlers) then support could be added more easily.
+ */
+ if (smp_processor_id() != priv->cpu)
+ return IRQ_NONE;
+
+ /* If no FDC interrupt pending, it wasn't for us */
+ if (!(read_c0_cause() & CAUSEF_FDCI))
+ return IRQ_NONE;
+
+ mips_ejtag_fdc_handle(priv);
+ return IRQ_HANDLED;
+}
+
+/**
+ * mips_ejtag_fdc_tty_timer() - Poll FDC for incoming data.
+ * @opaque: Pointer to driver private data.
+ *
+ * This is the timer handler for when interrupts are disabled and polling the
+ * FDC state is required.
+ *
+ * It simply triggers the common FDC handler code and arranges for further
+ * polling.
+ */
+static void mips_ejtag_fdc_tty_timer(unsigned long opaque)
+{
+ struct mips_ejtag_fdc_tty *priv = (void *)opaque;
+
+ mips_ejtag_fdc_handle(priv);
+ if (!priv->removing)
+ mod_timer_pinned(&priv->poll_timer, jiffies + FDC_TTY_POLL);
+}
+
+/* TTY Port operations */
+
+static int mips_ejtag_fdc_tty_port_activate(struct tty_port *port,
+ struct tty_struct *tty)
+{
+ struct mips_ejtag_fdc_tty_port *dport =
+ container_of(port, struct mips_ejtag_fdc_tty_port, port);
+ void *rx_buf;
+
+ /* Allocate the buffer we use for writing data */
+ if (tty_port_alloc_xmit_buf(port) < 0)
+ goto err;
+
+ /* Allocate the buffer we use for reading data */
+ rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
+ if (!rx_buf)
+ goto err_free_xmit;
+
+ raw_spin_lock_irq(&dport->rx_lock);
+ dport->rx_buf = rx_buf;
+ raw_spin_unlock_irq(&dport->rx_lock);
+
+ return 0;
+err_free_xmit:
+ tty_port_free_xmit_buf(port);
+err:
+ return -ENOMEM;
+}
+
+static void mips_ejtag_fdc_tty_port_shutdown(struct tty_port *port)
+{
+ struct mips_ejtag_fdc_tty_port *dport =
+ container_of(port, struct mips_ejtag_fdc_tty_port, port);
+ struct mips_ejtag_fdc_tty *priv = dport->driver;
+ void *rx_buf;
+ unsigned int count;
+
+ spin_lock(&dport->xmit_lock);
+ count = dport->xmit_cnt;
+ spin_unlock(&dport->xmit_lock);
+ if (count) {
+ /*
+ * There's still data to write out, so wake and wait for the
+ * writer thread to drain the buffer.
+ */
+ wake_up_interruptible(&priv->waitqueue);
+ wait_for_completion(&dport->xmit_empty);
+ }
+
+ /* Null the read buffer (timer could still be running!) */
+ raw_spin_lock_irq(&dport->rx_lock);
+ rx_buf = dport->rx_buf;
+ dport->rx_buf = NULL;
+ raw_spin_unlock_irq(&dport->rx_lock);
+ /* Free the read buffer */
+ kfree(rx_buf);
+
+ /* Free the write buffer */
+ tty_port_free_xmit_buf(port);
+}
+
+static const struct tty_port_operations mips_ejtag_fdc_tty_port_ops = {
+ .activate = mips_ejtag_fdc_tty_port_activate,
+ .shutdown = mips_ejtag_fdc_tty_port_shutdown,
+};
+
+/* TTY operations */
+
+static int mips_ejtag_fdc_tty_install(struct tty_driver *driver,
+ struct tty_struct *tty)
+{
+ struct mips_ejtag_fdc_tty *priv = driver->driver_state;
+
+ tty->driver_data = &priv->ports[tty->index];
+ return tty_port_install(&priv->ports[tty->index].port, driver, tty);
+}
+
+static int mips_ejtag_fdc_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ return tty_port_open(tty->port, tty, filp);
+}
+
+static void mips_ejtag_fdc_tty_close(struct tty_struct *tty, struct file *filp)
+{
+ return tty_port_close(tty->port, tty, filp);
+}
+
+static void mips_ejtag_fdc_tty_hangup(struct tty_struct *tty)
+{
+ struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
+ struct mips_ejtag_fdc_tty *priv = dport->driver;
+
+ /* Drop any data in the xmit buffer */
+ spin_lock(&dport->xmit_lock);
+ if (dport->xmit_cnt) {
+ atomic_sub(dport->xmit_cnt, &priv->xmit_total);
+ dport->xmit_cnt = 0;
+ dport->xmit_head = 0;
+ dport->xmit_tail = 0;
+ complete(&dport->xmit_empty);
+ }
+ spin_unlock(&dport->xmit_lock);
+
+ tty_port_hangup(tty->port);
+}
+
+static int mips_ejtag_fdc_tty_write(struct tty_struct *tty,
+ const unsigned char *buf, int total)
+{
+ int count, block;
+ struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
+ struct mips_ejtag_fdc_tty *priv = dport->driver;
+
+ /*
+ * Write to output buffer.
+ *
+ * The reason that we asynchronously write the buffer is because if we
+ * were to write the buffer synchronously then because the channels are
+ * per-CPU the buffer would be written to the channel of whatever CPU
+ * we're running on.
+ *
+ * What we actually want to happen is have all input and output done on
+ * one CPU.
+ */
+ spin_lock(&dport->xmit_lock);
+ /* Work out how many bytes we can write to the xmit buffer */
+ total = min(total, (int)(priv->xmit_size - dport->xmit_cnt));
+ atomic_add(total, &priv->xmit_total);
+ dport->xmit_cnt += total;
+ /* Write the actual bytes (may need splitting if it wraps) */
+ for (count = total; count; count -= block) {
+ block = min(count, (int)(priv->xmit_size - dport->xmit_head));
+ memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block);
+ dport->xmit_head += block;
+ if (dport->xmit_head >= priv->xmit_size)
+ dport->xmit_head -= priv->xmit_size;
+ buf += block;
+ }
+ count = dport->xmit_cnt;
+ /* Xmit buffer no longer empty? */
+ if (count)
+ reinit_completion(&dport->xmit_empty);
+ spin_unlock(&dport->xmit_lock);
+
+ /* Wake up the kthread */
+ if (total)
+ wake_up_interruptible(&priv->waitqueue);
+ return total;
+}
+
+static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
+{
+ struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
+ struct mips_ejtag_fdc_tty *priv = dport->driver;
+ int room;
+
+ /* Report the space in the xmit buffer */
+ spin_lock(&dport->xmit_lock);
+ room = priv->xmit_size - dport->xmit_cnt;
+ spin_unlock(&dport->xmit_lock);
+
+ return room;
+}
+
+static int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
+ int chars;
+
+ /* Report the number of bytes in the xmit buffer */
+ spin_lock(&dport->xmit_lock);
+ chars = dport->xmit_cnt;
+ spin_unlock(&dport->xmit_lock);
+
+ return chars;
+}
+
+static const struct tty_operations mips_ejtag_fdc_tty_ops = {
+ .install = mips_ejtag_fdc_tty_install,
+ .open = mips_ejtag_fdc_tty_open,
+ .close = mips_ejtag_fdc_tty_close,
+ .hangup = mips_ejtag_fdc_tty_hangup,
+ .write = mips_ejtag_fdc_tty_write,
+ .write_room = mips_ejtag_fdc_tty_write_room,
+ .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer,
+};
+
+static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
+{
+ int ret, nport;
+ struct mips_ejtag_fdc_tty_port *dport;
+ struct mips_ejtag_fdc_tty *priv;
+ struct tty_driver *driver;
+ unsigned int cfg, tx_fifo;
+
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->cpu = dev->cpu;
+ priv->dev = &dev->dev;
+ mips_cdmm_set_drvdata(dev, priv);
+ atomic_set(&priv->xmit_total, 0);
+ raw_spin_lock_init(&priv->lock);
+
+ priv->reg = devm_ioremap_nocache(priv->dev, dev->res.start,
+ resource_size(&dev->res));
+ if (!priv->reg) {
+ dev_err(priv->dev, "ioremap failed for resource %pR\n",
+ &dev->res);
+ return -ENOMEM;
+ }
+
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ tx_fifo = (cfg & REG_FDCFG_TXFIFOSIZE) >> REG_FDCFG_TXFIFOSIZE_SHIFT;
+ /* Disable interrupts */
+ cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+
+ /* Make each port's xmit FIFO big enough to fill FDC TX FIFO */
+ priv->xmit_size = min(tx_fifo * 4, (unsigned int)SERIAL_XMIT_SIZE);
+
+ driver = tty_alloc_driver(NUM_TTY_CHANNELS, TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(driver))
+ return PTR_ERR(driver);
+ priv->driver = driver;
+
+ driver->driver_name = "ejtag_fdc";
+ snprintf(priv->fdc_name, sizeof(priv->fdc_name), "ttyFDC%u", dev->cpu);
+ snprintf(priv->driver_name, sizeof(priv->driver_name), "%sc",
+ priv->fdc_name);
+ driver->name = priv->driver_name;
+ driver->major = 0; /* Auto-allocate */
+ driver->minor_start = 0;
+ driver->type = TTY_DRIVER_TYPE_SERIAL;
+ driver->subtype = SERIAL_TYPE_NORMAL;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag |= CLOCAL;
+ driver->driver_state = priv;
+
+ tty_set_operations(driver, &mips_ejtag_fdc_tty_ops);
+ for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
+ dport = &priv->ports[nport];
+ dport->driver = priv;
+ tty_port_init(&dport->port);
+ dport->port.ops = &mips_ejtag_fdc_tty_port_ops;
+ raw_spin_lock_init(&dport->rx_lock);
+ spin_lock_init(&dport->xmit_lock);
+ /* The xmit buffer starts empty, i.e. completely written */
+ init_completion(&dport->xmit_empty);
+ complete(&dport->xmit_empty);
+ }
+
+ /* Set up the console */
+ mips_ejtag_fdc_con.regs[dev->cpu] = priv->reg;
+ if (dev->cpu == 0)
+ mips_ejtag_fdc_con.tty_drv = driver;
+
+ init_waitqueue_head(&priv->waitqueue);
+ priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name);
+ if (IS_ERR(priv->thread)) {
+ ret = PTR_ERR(priv->thread);
+ dev_err(priv->dev, "Couldn't create kthread (%d)\n", ret);
+ goto err_destroy_ports;
+ }
+ /*
+ * Bind the writer thread to the right CPU so it can't migrate.
+ * The channels are per-CPU and we want all channel I/O to be on a
+ * single predictable CPU.
+ */
+ kthread_bind(priv->thread, dev->cpu);
+ wake_up_process(priv->thread);
+
+ /* Look for an FDC IRQ */
+ priv->irq = -1;
+ if (get_c0_fdc_int)
+ priv->irq = get_c0_fdc_int();
+
+ /* Try requesting the IRQ */
+ if (priv->irq >= 0) {
+ /*
+ * IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with
+ * other local interrupts such as the timer which sets
+ * IRQF_TIMER (including IRQF_NO_SUSPEND).
+ *
+ * IRQF_NO_THREAD: The FDC IRQ isn't individually maskable so it
+ * cannot be deferred and handled by a thread on RT kernels. For
+ * this reason any spinlocks used from the ISR are raw.
+ */
+ ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
+ IRQF_PERCPU | IRQF_SHARED |
+ IRQF_NO_THREAD | IRQF_NO_SUSPEND,
+ priv->fdc_name, priv);
+ if (ret)
+ priv->irq = -1;
+ }
+ if (priv->irq >= 0) {
+ /* IRQ is usable, enable RX interrupt */
+ raw_spin_lock_irq(&priv->lock);
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ cfg &= ~REG_FDCFG_RXINTTHRES;
+ cfg |= REG_FDCFG_RXINTTHRES_NOTEMPTY;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ raw_spin_unlock_irq(&priv->lock);
+ } else {
+ /* If we didn't get an usable IRQ, poll instead */
+ setup_timer(&priv->poll_timer, mips_ejtag_fdc_tty_timer,
+ (unsigned long)priv);
+ priv->poll_timer.expires = jiffies + FDC_TTY_POLL;
+ /*
+ * Always attach the timer to the right CPU. The channels are
+ * per-CPU so all polling should be from a single CPU.
+ */
+ add_timer_on(&priv->poll_timer, dev->cpu);
+
+ dev_info(priv->dev, "No usable IRQ, polling enabled\n");
+ }
+
+ ret = tty_register_driver(driver);
+ if (ret < 0) {
+ dev_err(priv->dev, "Couldn't install tty driver (%d)\n", ret);
+ goto err_stop_irq;
+ }
+
+ return 0;
+
+err_stop_irq:
+ if (priv->irq >= 0) {
+ raw_spin_lock_irq(&priv->lock);
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ /* Disable interrupts */
+ cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ raw_spin_unlock_irq(&priv->lock);
+ } else {
+ priv->removing = true;
+ del_timer_sync(&priv->poll_timer);
+ }
+ kthread_stop(priv->thread);
+err_destroy_ports:
+ if (dev->cpu == 0)
+ mips_ejtag_fdc_con.tty_drv = NULL;
+ for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
+ dport = &priv->ports[nport];
+ tty_port_destroy(&dport->port);
+ }
+ put_tty_driver(priv->driver);
+ return ret;
+}
+
+static int mips_ejtag_fdc_tty_remove(struct mips_cdmm_device *dev)
+{
+ struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
+ struct mips_ejtag_fdc_tty_port *dport;
+ int nport;
+ unsigned int cfg;
+
+ if (priv->irq >= 0) {
+ raw_spin_lock_irq(&priv->lock);
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ /* Disable interrupts */
+ cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ raw_spin_unlock_irq(&priv->lock);
+ } else {
+ priv->removing = true;
+ del_timer_sync(&priv->poll_timer);
+ }
+ kthread_stop(priv->thread);
+ if (dev->cpu == 0)
+ mips_ejtag_fdc_con.tty_drv = NULL;
+ tty_unregister_driver(priv->driver);
+ for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
+ dport = &priv->ports[nport];
+ tty_port_destroy(&dport->port);
+ }
+ put_tty_driver(priv->driver);
+ return 0;
+}
+
+static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
+{
+ struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
+ unsigned int cfg;
+
+ if (priv->irq >= 0) {
+ raw_spin_lock_irq(&priv->lock);
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ /* Disable interrupts */
+ cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ raw_spin_unlock_irq(&priv->lock);
+ } else {
+ priv->removing = true;
+ del_timer_sync(&priv->poll_timer);
+ }
+ kthread_stop(priv->thread);
+
+ return 0;
+}
+
+static int mips_ejtag_fdc_tty_cpu_up(struct mips_cdmm_device *dev)
+{
+ struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
+ unsigned int cfg;
+ int ret = 0;
+
+ if (priv->irq >= 0) {
+ /*
+ * IRQ is usable, enable RX interrupt
+ * This must be before kthread is restarted, as kthread may
+ * enable TX interrupt.
+ */
+ raw_spin_lock_irq(&priv->lock);
+ cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
+ cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
+ cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
+ cfg |= REG_FDCFG_RXINTTHRES_NOTEMPTY;
+ mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
+ raw_spin_unlock_irq(&priv->lock);
+ } else {
+ /* Restart poll timer */
+ priv->removing = false;
+ add_timer_on(&priv->poll_timer, dev->cpu);
+ }
+
+ /* Restart the kthread */
+ priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name);
+ if (IS_ERR(priv->thread)) {
+ ret = PTR_ERR(priv->thread);
+ dev_err(priv->dev, "Couldn't re-create kthread (%d)\n", ret);
+ goto out;
+ }
+ /* Bind it back to the right CPU and set it off */
+ kthread_bind(priv->thread, dev->cpu);
+ wake_up_process(priv->thread);
+out:
+ return ret;
+}
+
+static struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = {
+ { .type = 0xfd },
+ { }
+};
+
+static struct mips_cdmm_driver mips_ejtag_fdc_tty_driver = {
+ .drv = {
+ .name = "mips_ejtag_fdc",
+ },
+ .probe = mips_ejtag_fdc_tty_probe,
+ .remove = mips_ejtag_fdc_tty_remove,
+ .cpu_down = mips_ejtag_fdc_tty_cpu_down,
+ .cpu_up = mips_ejtag_fdc_tty_cpu_up,
+ .id_table = mips_ejtag_fdc_tty_ids,
+};
+module_mips_cdmm_driver(mips_ejtag_fdc_tty_driver);
+
+static int __init mips_ejtag_fdc_init_console(void)
+{
+ return mips_ejtag_fdc_console_init(&mips_ejtag_fdc_con);
+}
+console_initcall(mips_ejtag_fdc_init_console);
+
+#ifdef CONFIG_MIPS_EJTAG_FDC_EARLYCON
+static struct mips_ejtag_fdc_console mips_ejtag_fdc_earlycon = {
+ .cons = {
+ .name = "early_fdc",
+ .write = mips_ejtag_fdc_console_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = CONSOLE_CHANNEL,
+ },
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(mips_ejtag_fdc_earlycon.lock),
+};
+
+int __init setup_early_fdc_console(void)
+{
+ return mips_ejtag_fdc_console_init(&mips_ejtag_fdc_earlycon);
+}
+#endif
+
+#ifdef CONFIG_MIPS_EJTAG_FDC_KGDB
+
+/* read buffer to allow decompaction */
+static unsigned int kgdbfdc_rbuflen;
+static unsigned int kgdbfdc_rpos;
+static char kgdbfdc_rbuf[4];
+
+/* write buffer to allow compaction */
+static unsigned int kgdbfdc_wbuflen;
+static char kgdbfdc_wbuf[4];
+
+static void __iomem *kgdbfdc_setup(void)
+{
+ void __iomem *regs;
+ unsigned int cpu;
+
+ /* Find address, piggy backing off console percpu regs */
+ cpu = smp_processor_id();
+ regs = mips_ejtag_fdc_con.regs[cpu];
+ /* First console output on this CPU? */
+ if (!regs) {
+ regs = mips_cdmm_early_probe(0xfd);
+ mips_ejtag_fdc_con.regs[cpu] = regs;
+ }
+ /* Already tried and failed to find FDC on this CPU? */
+ if (IS_ERR(regs))
+ return regs;
+
+ return regs;
+}
+
+/* read a character from the read buffer, filling from FDC RX FIFO */
+static int kgdbfdc_read_char(void)
+{
+ unsigned int stat, channel, data;
+ void __iomem *regs;
+
+ /* No more data, try and read another FDC word from RX FIFO */
+ if (kgdbfdc_rpos >= kgdbfdc_rbuflen) {
+ kgdbfdc_rpos = 0;
+ kgdbfdc_rbuflen = 0;
+
+ regs = kgdbfdc_setup();
+ if (IS_ERR(regs))
+ return NO_POLL_CHAR;
+
+ /* Read next word from KGDB channel */
+ do {
+ stat = ioread32(regs + REG_FDSTAT);
+
+ /* No data waiting? */
+ if (stat & REG_FDSTAT_RXE)
+ return NO_POLL_CHAR;
+
+ /* Read next word */
+ channel = (stat & REG_FDSTAT_RXCHAN) >>
+ REG_FDSTAT_RXCHAN_SHIFT;
+ data = ioread32(regs + REG_FDRX);
+ } while (channel != CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN);
+
+ /* Decode into rbuf */
+ kgdbfdc_rbuflen = mips_ejtag_fdc_decode(data, kgdbfdc_rbuf);
+ }
+ pr_devel("kgdbfdc r %c\n", kgdbfdc_rbuf[kgdbfdc_rpos]);
+ return kgdbfdc_rbuf[kgdbfdc_rpos++];
+}
+
+/* push an FDC word from write buffer to TX FIFO */
+static void kgdbfdc_push_one(void)
+{
+ const char *bufs[1] = { kgdbfdc_wbuf };
+ struct fdc_word word;
+ void __iomem *regs;
+ unsigned int i;
+
+ /* Construct a word from any data in buffer */
+ word = mips_ejtag_fdc_encode(bufs, &kgdbfdc_wbuflen, 1);
+ /* Relocate any remaining data to beginnning of buffer */
+ kgdbfdc_wbuflen -= word.bytes;
+ for (i = 0; i < kgdbfdc_wbuflen; ++i)
+ kgdbfdc_wbuf[i] = kgdbfdc_wbuf[i + word.bytes];
+
+ regs = kgdbfdc_setup();
+ if (IS_ERR(regs))
+ return;
+
+ /* Busy wait until there's space in fifo */
+ while (ioread32(regs + REG_FDSTAT) & REG_FDSTAT_TXF)
+ ;
+ iowrite32(word.word, regs + REG_FDTX(CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN));
+}
+
+/* flush the whole write buffer to the TX FIFO */
+static void kgdbfdc_flush(void)
+{
+ while (kgdbfdc_wbuflen)
+ kgdbfdc_push_one();
+}
+
+/* write a character into the write buffer, writing out if full */
+static void kgdbfdc_write_char(u8 chr)
+{
+ pr_devel("kgdbfdc w %c\n", chr);
+ kgdbfdc_wbuf[kgdbfdc_wbuflen++] = chr;
+ if (kgdbfdc_wbuflen >= sizeof(kgdbfdc_wbuf))
+ kgdbfdc_push_one();
+}
+
+static struct kgdb_io kgdbfdc_io_ops = {
+ .name = "kgdbfdc",
+ .read_char = kgdbfdc_read_char,
+ .write_char = kgdbfdc_write_char,
+ .flush = kgdbfdc_flush,
+};
+
+static int __init kgdbfdc_init(void)
+{
+ kgdb_register_io_module(&kgdbfdc_io_ops);
+ return 0;
+}
+early_initcall(kgdbfdc_init);
+#endif
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c4343764cc5b..91abc00aa833 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2669,7 +2669,7 @@ static inline void muxnet_put(struct gsm_mux_net *mux_net)
static int gsm_mux_net_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
- struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+ struct gsm_mux_net *mux_net = netdev_priv(net);
struct gsm_dlci *dlci = mux_net->dlci;
muxnet_get(mux_net);
@@ -2698,7 +2698,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
{
struct net_device *net = dlci->net;
struct sk_buff *skb;
- struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+ struct gsm_mux_net *mux_net = netdev_priv(net);
muxnet_get(mux_net);
/* Allocate an sk_buff */
@@ -2727,7 +2727,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
static int gsm_change_mtu(struct net_device *net, int new_mtu)
{
- struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+ struct gsm_mux_net *mux_net = netdev_priv(net);
if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu))
return -EINVAL;
net->mtu = new_mtu;
@@ -2763,7 +2763,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci)
pr_debug("destroy network interface");
if (!dlci->net)
return;
- mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net);
+ mux_net = netdev_priv(dlci->net);
muxnet_put(mux_net);
}
@@ -2801,7 +2801,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
return -ENOMEM;
}
net->mtu = dlci->gsm->mtu;
- mux_net = (struct gsm_mux_net *)netdev_priv(net);
+ mux_net = netdev_priv(net);
mux_net->dlci = dlci;
kref_init(&mux_net->ref);
strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */
@@ -2824,7 +2824,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
}
/* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
+static struct tty_ldisc_ops tty_ldisc_packet = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "n_gsm",
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index b00836851061..c43f74c53cd9 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -21,7 +21,6 @@ struct uart_8250_dma {
/* Filter function */
dma_filter_fn fn;
-
/* Parameter to the filter function */
void *rx_param;
void *tx_param;
@@ -53,7 +52,7 @@ struct old_serial_port {
unsigned int baud_base;
unsigned int port;
unsigned int irq;
- unsigned int flags;
+ upf_t flags;
unsigned char hub6;
unsigned char io_type;
unsigned char __iomem *iomem_base;
@@ -85,9 +84,6 @@ struct serial8250_config {
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
-#define PROBE_RSA (1 << 0)
-#define PROBE_ANY (~0)
-
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
@@ -198,3 +194,20 @@ static inline int serial8250_request_dma(struct uart_8250_port *p)
}
static inline void serial8250_release_dma(struct uart_8250_port *p) { }
#endif
+
+static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
+{
+ unsigned char status;
+
+ status = serial_in(up, 0x04); /* EXCR2 */
+#define PRESL(x) ((x) & 0x30)
+ if (PRESL(status) == 0x10) {
+ /* already in high speed mode */
+ return 0;
+ } else {
+ status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+ status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
+ serial_out(up, 0x04, status);
+ }
+ return 1;
+}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index e3b9570a1eff..4506e405c8f3 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -31,7 +31,6 @@
#include <linux/tty.h>
#include <linux/ratelimit.h>
#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/nmi.h>
@@ -61,7 +60,7 @@ static struct uart_driver serial8250_reg;
static int serial_index(struct uart_port *port)
{
- return (serial8250_reg.minor - 64) + port->line;
+ return port->minor - 64;
}
static unsigned int skip_txen_test; /* force skip of txen test at init time */
@@ -358,34 +357,46 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
/* Au1x00/RT288x UART hardware has a weird register layout */
-static const u8 au_io_in_map[] = {
- [UART_RX] = 0,
- [UART_IER] = 2,
- [UART_IIR] = 3,
- [UART_LCR] = 5,
- [UART_MCR] = 6,
- [UART_LSR] = 7,
- [UART_MSR] = 8,
+static const s8 au_io_in_map[8] = {
+ 0, /* UART_RX */
+ 2, /* UART_IER */
+ 3, /* UART_IIR */
+ 5, /* UART_LCR */
+ 6, /* UART_MCR */
+ 7, /* UART_LSR */
+ 8, /* UART_MSR */
+ -1, /* UART_SCR (unmapped) */
};
-static const u8 au_io_out_map[] = {
- [UART_TX] = 1,
- [UART_IER] = 2,
- [UART_FCR] = 4,
- [UART_LCR] = 5,
- [UART_MCR] = 6,
+static const s8 au_io_out_map[8] = {
+ 1, /* UART_TX */
+ 2, /* UART_IER */
+ 4, /* UART_FCR */
+ 5, /* UART_LCR */
+ 6, /* UART_MCR */
+ -1, /* UART_LSR (unmapped) */
+ -1, /* UART_MSR (unmapped) */
+ -1, /* UART_SCR (unmapped) */
};
static unsigned int au_serial_in(struct uart_port *p, int offset)
{
- offset = au_io_in_map[offset] << p->regshift;
- return __raw_readl(p->membase + offset);
+ if (offset >= ARRAY_SIZE(au_io_in_map))
+ return UINT_MAX;
+ offset = au_io_in_map[offset];
+ if (offset < 0)
+ return UINT_MAX;
+ return __raw_readl(p->membase + (offset << p->regshift));
}
static void au_serial_out(struct uart_port *p, int offset, int value)
{
- offset = au_io_out_map[offset] << p->regshift;
- __raw_writel(value, p->membase + offset);
+ if (offset >= ARRAY_SIZE(au_io_out_map))
+ return;
+ offset = au_io_out_map[offset];
+ if (offset < 0)
+ return;
+ __raw_writel(value, p->membase + (offset << p->regshift));
}
/* Au1x00 haven't got a standard divisor latch */
@@ -439,6 +450,18 @@ static unsigned int mem32_serial_in(struct uart_port *p, int offset)
return readl(p->membase + offset);
}
+static void mem32be_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = offset << p->regshift;
+ iowrite32be(value, p->membase + offset);
+}
+
+static unsigned int mem32be_serial_in(struct uart_port *p, int offset)
+{
+ offset = offset << p->regshift;
+ return ioread32be(p->membase + offset);
+}
+
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -477,6 +500,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem32_serial_out;
break;
+ case UPIO_MEM32BE:
+ p->serial_in = mem32be_serial_in;
+ p->serial_out = mem32be_serial_out;
+ break;
+
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
case UPIO_AU:
p->serial_in = au_serial_in;
@@ -502,6 +530,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_AU:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
@@ -895,7 +924,7 @@ static int broken_efr(struct uart_8250_port *up)
/*
* Exar ST16C2550 "A2" devices incorrectly detect as
* having an EFR, and report an ID of 0x0201. See
- * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html
+ * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html
*/
if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
return 1;
@@ -903,23 +932,6 @@ static int broken_efr(struct uart_8250_port *up)
return 0;
}
-static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
-{
- unsigned char status;
-
- status = serial_in(up, 0x04); /* EXCR2 */
-#define PRESL(x) ((x) & 0x30)
- if (PRESL(status) == 0x10) {
- /* already in high speed mode */
- return 0;
- } else {
- status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
- status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
- serial_out(up, 0x04, status);
- }
- return 1;
-}
-
/*
* We know that the chip has FIFOs. Does it have an EFR? The
* EFR is located in the same register position as the IIR and
@@ -1122,7 +1134,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* whether or not this UART is a 16550A or not, since this will
* determine whether or not we can use its FIFO features or not.
*/
-static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+static void autoconfig(struct uart_8250_port *up)
{
unsigned char status1, scratch, scratch2, scratch3;
unsigned char save_lcr, save_mcr;
@@ -1245,22 +1257,15 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
/*
* Only probe for RSA ports if we got the region.
*/
- if (port->type == PORT_16550A && probeflags & PROBE_RSA) {
- int i;
-
- for (i = 0 ; i < probe_rsa_count; ++i) {
- if (probe_rsa[i] == port->iobase && __enable_rsa(up)) {
- port->type = PORT_RSA;
- break;
- }
- }
- }
+ if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA &&
+ __enable_rsa(up))
+ port->type = PORT_RSA;
#endif
serial_out(up, UART_LCR, save_lcr);
port->fifosize = uart_config[up->port.type].fifo_size;
- old_capabilities = up->capabilities;
+ old_capabilities = up->capabilities;
up->capabilities = uart_config[port->type].flags;
up->tx_loadsz = uart_config[port->type].tx_loadsz;
@@ -1907,6 +1912,48 @@ static void serial8250_backup_timeout(unsigned long data)
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
}
+static int univ8250_setup_irq(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+ int retval = 0;
+
+ /*
+ * The above check will only give an accurate result the first time
+ * the port is opened so this value needs to be preserved.
+ */
+ if (up->bugs & UART_BUG_THRE) {
+ pr_debug("ttyS%d - using backup timer\n", serial_index(port));
+
+ up->timer.function = serial8250_backup_timeout;
+ up->timer.data = (unsigned long)up;
+ mod_timer(&up->timer, jiffies +
+ uart_poll_timeout(port) + HZ / 5);
+ }
+
+ /*
+ * If the "interrupt" for this port doesn't correspond with any
+ * hardware interrupt, we use a timer-based system. The original
+ * driver used to do this with IRQ0.
+ */
+ if (!port->irq) {
+ up->timer.data = (unsigned long)up;
+ mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
+ } else
+ retval = serial_link_irq_chain(up);
+
+ return retval;
+}
+
+static void univ8250_release_irq(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+
+ del_timer_sync(&up->timer);
+ up->timer.function = serial8250_timeout;
+ if (port->irq)
+ serial_unlink_irq_chain(up);
+}
+
static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2138,8 +2185,8 @@ int serial8250_do_startup(struct uart_port *port)
/*
* Clear the interrupt registers.
*/
- if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
- serial_port_in(port, UART_RX);
+ serial_port_in(port, UART_LSR);
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
@@ -2211,35 +2258,12 @@ int serial8250_do_startup(struct uart_port *port)
if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) ||
up->port.flags & UPF_BUG_THRE) {
up->bugs |= UART_BUG_THRE;
- pr_debug("ttyS%d - using backup timer\n",
- serial_index(port));
}
}
- /*
- * The above check will only give an accurate result the first time
- * the port is opened so this value needs to be preserved.
- */
- if (up->bugs & UART_BUG_THRE) {
- up->timer.function = serial8250_backup_timeout;
- up->timer.data = (unsigned long)up;
- mod_timer(&up->timer, jiffies +
- uart_poll_timeout(port) + HZ / 5);
- }
-
- /*
- * If the "interrupt" for this port doesn't correspond with any
- * hardware interrupt, we use a timer-based system. The original
- * driver used to do this with IRQ0.
- */
- if (!port->irq) {
- up->timer.data = (unsigned long)up;
- mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
- } else {
- retval = serial_link_irq_chain(up);
- if (retval)
- goto out;
- }
+ retval = up->ops->setup_irq(up);
+ if (retval)
+ goto out;
/*
* Now, initialize the UART
@@ -2270,7 +2294,7 @@ int serial8250_do_startup(struct uart_port *port)
is variable. So, let's just don't test if we receive
TX irq. This way, we'll never enable UART_BUG_TXEN.
*/
- if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST)
+ if (up->port.flags & UPF_NO_TXEN_TEST)
goto dont_test_tx_en;
/*
@@ -2300,8 +2324,8 @@ dont_test_tx_en:
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
- if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
- serial_port_in(port, UART_RX);
+ serial_port_in(port, UART_LSR);
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
up->lsr_saved_flags = 0;
@@ -2394,14 +2418,10 @@ void serial8250_do_shutdown(struct uart_port *port)
* Read data port to reset things, and then unlink from
* the IRQ chain.
*/
- if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
- serial_port_in(port, UART_RX);
+ serial_port_in(port, UART_RX);
serial8250_rpm_put(up);
- del_timer_sync(&up->timer);
- up->timer.function = serial8250_timeout;
- if (port->irq)
- serial_unlink_irq_chain(up);
+ up->ops->release_irq(up);
}
EXPORT_SYMBOL_GPL(serial8250_do_shutdown);
@@ -2720,6 +2740,8 @@ serial8250_pm(struct uart_port *port, unsigned int state,
static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
+ if (pt->port.mapsize)
+ return pt->port.mapsize;
if (pt->port.iotype == UPIO_AU) {
if (pt->port.type == PORT_RT2880)
return 0x100;
@@ -2744,6 +2766,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2780,6 +2803,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2799,6 +2823,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
}
}
+#ifdef CONFIG_SERIAL_8250_RSA
static int serial8250_request_rsa_resource(struct uart_8250_port *up)
{
unsigned long start = UART_RSA_BASE << up->port.regshift;
@@ -2833,14 +2858,13 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
break;
}
}
+#endif
static void serial8250_release_port(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
serial8250_release_std_resource(up);
- if (port->type == PORT_RSA)
- serial8250_release_rsa_resource(up);
}
static int serial8250_request_port(struct uart_port *port)
@@ -2852,11 +2876,6 @@ static int serial8250_request_port(struct uart_port *port)
return -ENODEV;
ret = serial8250_request_std_resource(up);
- if (ret == 0 && port->type == PORT_RSA) {
- ret = serial8250_request_rsa_resource(up);
- if (ret < 0)
- serial8250_release_std_resource(up);
- }
return ret;
}
@@ -3004,7 +3023,6 @@ static void register_dev_spec_attr_grp(struct uart_8250_port *up)
static void serial8250_config_port(struct uart_port *port, int flags)
{
struct uart_8250_port *up = up_to_u8250p(port);
- int probeflags = PROBE_ANY;
int ret;
if (port->type == PORT_8250_CIR)
@@ -3018,15 +3036,11 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (ret < 0)
return;
- ret = serial8250_request_rsa_resource(up);
- if (ret < 0)
- probeflags &= ~PROBE_RSA;
-
if (port->iotype != up->cur_iotype)
set_io_from_upio(port);
if (flags & UART_CONFIG_TYPE)
- autoconfig(up, probeflags);
+ autoconfig(up);
/* if access method is AU, it is a 16550 with a quirk */
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
@@ -3039,8 +3053,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);
- if (port->type != PORT_RSA && probeflags & PROBE_RSA)
- serial8250_release_rsa_resource(up);
if (port->type == PORT_UNKNOWN)
serial8250_release_std_resource(up);
@@ -3074,7 +3086,7 @@ serial8250_type(struct uart_port *port)
return uart_config[type].name;
}
-static struct uart_ops serial8250_pops = {
+static const struct uart_ops serial8250_pops = {
.tx_empty = serial8250_tx_empty,
.set_mctrl = serial8250_set_mctrl,
.get_mctrl = serial8250_get_mctrl,
@@ -3101,6 +3113,14 @@ static struct uart_ops serial8250_pops = {
#endif
};
+static const struct uart_ops *base_ops;
+static struct uart_ops univ8250_port_ops;
+
+static const struct uart_8250_ops univ8250_driver_ops = {
+ .setup_irq = univ8250_setup_irq,
+ .release_irq = univ8250_release_irq,
+};
+
static struct uart_8250_port serial8250_ports[UART_NR];
/**
@@ -3131,6 +3151,105 @@ void serial8250_set_isa_configurator(
}
EXPORT_SYMBOL(serial8250_set_isa_configurator);
+static void serial8250_init_port(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+
+ spin_lock_init(&port->lock);
+ port->ops = &serial8250_pops;
+
+ up->cur_iotype = 0xFF;
+}
+
+static void serial8250_set_defaults(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+
+ if (up->port.flags & UPF_FIXED_TYPE) {
+ unsigned int type = up->port.type;
+
+ if (!up->port.fifosize)
+ up->port.fifosize = uart_config[type].fifo_size;
+ if (!up->tx_loadsz)
+ up->tx_loadsz = uart_config[type].tx_loadsz;
+ if (!up->capabilities)
+ up->capabilities = uart_config[type].flags;
+ }
+
+ set_io_from_upio(port);
+
+ /* default dma handlers */
+ if (up->dma) {
+ if (!up->dma->tx_dma)
+ up->dma->tx_dma = serial8250_tx_dma;
+ if (!up->dma->rx_dma)
+ up->dma->rx_dma = serial8250_rx_dma;
+ }
+}
+
+#ifdef CONFIG_SERIAL_8250_RSA
+
+static void univ8250_config_port(struct uart_port *port, int flags)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ up->probe &= ~UART_PROBE_RSA;
+ if (port->type == PORT_RSA) {
+ if (serial8250_request_rsa_resource(up) == 0)
+ up->probe |= UART_PROBE_RSA;
+ } else if (flags & UART_CONFIG_TYPE) {
+ int i;
+
+ for (i = 0; i < probe_rsa_count; i++) {
+ if (probe_rsa[i] == up->port.iobase) {
+ if (serial8250_request_rsa_resource(up) == 0)
+ up->probe |= UART_PROBE_RSA;
+ break;
+ }
+ }
+ }
+
+ base_ops->config_port(port, flags);
+
+ if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
+ serial8250_release_rsa_resource(up);
+}
+
+static int univ8250_request_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ int ret;
+
+ ret = base_ops->request_port(port);
+ if (ret == 0 && port->type == PORT_RSA) {
+ ret = serial8250_request_rsa_resource(up);
+ if (ret < 0)
+ base_ops->release_port(port);
+ }
+
+ return ret;
+}
+
+static void univ8250_release_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ if (port->type == PORT_RSA)
+ serial8250_release_rsa_resource(up);
+ base_ops->release_port(port);
+}
+
+static void univ8250_rsa_support(struct uart_ops *ops)
+{
+ ops->config_port = univ8250_config_port;
+ ops->request_port = univ8250_request_port;
+ ops->release_port = univ8250_release_port;
+}
+
+#else
+#define univ8250_rsa_support(x) do { } while (0)
+#endif /* CONFIG_SERIAL_8250_RSA */
+
static void __init serial8250_isa_init_ports(void)
{
struct uart_8250_port *up;
@@ -3149,21 +3268,27 @@ static void __init serial8250_isa_init_ports(void)
struct uart_port *port = &up->port;
port->line = i;
- spin_lock_init(&port->lock);
+ serial8250_init_port(up);
+ if (!base_ops)
+ base_ops = port->ops;
+ port->ops = &univ8250_port_ops;
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
- up->cur_iotype = 0xFF;
+
+ up->ops = &univ8250_driver_ops;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
-
- port->ops = &serial8250_pops;
}
+ /* chain base port ops to support Remote Supervisor Adapter */
+ univ8250_port_ops = *base_ops;
+ univ8250_rsa_support(&univ8250_port_ops);
+
if (share_irqs)
irqflag = IRQF_SHARED;
@@ -3181,26 +3306,14 @@ static void __init serial8250_isa_init_ports(void)
port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
- set_io_from_upio(port);
+ serial8250_set_defaults(up);
+
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
-
}
}
-static void
-serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
-{
- up->port.type = type;
- if (!up->port.fifosize)
- up->port.fifosize = uart_config[type].fifo_size;
- if (!up->tx_loadsz)
- up->tx_loadsz = uart_config[type].tx_loadsz;
- if (!up->capabilities)
- up->capabilities = uart_config[type].flags;
-}
-
static void __init
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{
@@ -3214,8 +3327,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
up->port.dev = dev;
- if (up->port.flags & UPF_FIXED_TYPE)
- serial8250_init_fixed_type_port(up, up->port.type);
+ if (skip_txen_test)
+ up->port.flags |= UPF_NO_TXEN_TEST;
uart_add_one_port(drv, &up->port);
}
@@ -3237,10 +3350,9 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
*
* The console_lock must be held when we get here.
*/
-static void
-serial8250_console_write(struct console *co, const char *s, unsigned int count)
+static void serial8250_console_write(struct uart_8250_port *up, const char *s,
+ unsigned int count)
{
- struct uart_8250_port *up = &serial8250_ports[co->index];
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier;
@@ -3312,14 +3424,51 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
serial8250_rpm_put(up);
}
-static int serial8250_console_setup(struct console *co, char *options)
+static void univ8250_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_8250_port *up = &serial8250_ports[co->index];
+
+ serial8250_console_write(up, s, count);
+}
+
+static unsigned int probe_baud(struct uart_port *port)
+{
+ unsigned char lcr, dll, dlm;
+ unsigned int quot;
+
+ lcr = serial_port_in(port, UART_LCR);
+ serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+ dll = serial_port_in(port, UART_DLL);
+ dlm = serial_port_in(port, UART_DLM);
+ serial_port_out(port, UART_LCR, lcr);
+
+ quot = (dlm << 8) | dll;
+ return (port->uartclk / 16) / quot;
+}
+
+static int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
{
- struct uart_port *port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
+ if (!port->iobase && !port->membase)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else if (probe)
+ baud = probe_baud(port);
+
+ return uart_set_options(port, port->cons, baud, parity, bits, flow);
+}
+
+static int univ8250_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
@@ -3328,53 +3477,84 @@ static int serial8250_console_setup(struct console *co, char *options)
if (co->index >= nr_uarts)
co->index = 0;
port = &serial8250_ports[co->index].port;
- if (!port->iobase && !port->membase)
- return -ENODEV;
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
+ /* link port to console */
+ port->cons = co;
- return uart_set_options(port, co, baud, parity, bits, flow);
+ return serial8250_console_setup(port, options, false);
}
-static int serial8250_console_early_setup(void)
+/**
+ * univ8250_console_match - non-standard console matching
+ * @co: registering console
+ * @name: name from console command line
+ * @idx: index from console command line
+ * @options: ptr to option string from console command line
+ *
+ * Only attempts to match console command lines of the form:
+ * console=uart[8250],io|mmio|mmio32,<addr>[,<options>]
+ * console=uart[8250],0x<addr>[,<options>]
+ * This form is used to register an initial earlycon boot console and
+ * replace it with the serial8250_console at 8250 driver init.
+ *
+ * Performs console setup for a match (as required by interface)
+ * If no <options> are specified, then assume the h/w is already setup.
+ *
+ * Returns 0 if console matches; otherwise non-zero to use default matching
+ */
+static int univ8250_console_match(struct console *co, char *name, int idx,
+ char *options)
{
- return serial8250_find_port_for_earlycon();
+ char match[] = "uart"; /* 8250-specific earlycon name */
+ unsigned char iotype;
+ unsigned long addr;
+ int i;
+
+ if (strncmp(name, match, 4) != 0)
+ return -ENODEV;
+
+ if (uart_parse_earlycon(options, &iotype, &addr, &options))
+ return -ENODEV;
+
+ /* try to match the port specified on the command line */
+ for (i = 0; i < nr_uarts; i++) {
+ struct uart_port *port = &serial8250_ports[i].port;
+
+ if (port->iotype != iotype)
+ continue;
+ if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) &&
+ (port->mapbase != addr))
+ continue;
+ if (iotype == UPIO_PORT && port->iobase != addr)
+ continue;
+
+ co->index = i;
+ port->cons = co;
+ return serial8250_console_setup(port, options, true);
+ }
+
+ return -ENODEV;
}
-static struct console serial8250_console = {
+static struct console univ8250_console = {
.name = "ttyS",
- .write = serial8250_console_write,
+ .write = univ8250_console_write,
.device = uart_console_device,
- .setup = serial8250_console_setup,
- .early_setup = serial8250_console_early_setup,
+ .setup = univ8250_console_setup,
+ .match = univ8250_console_match,
.flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &serial8250_reg,
};
-static int __init serial8250_console_init(void)
+static int __init univ8250_console_init(void)
{
serial8250_isa_init_ports();
- register_console(&serial8250_console);
+ register_console(&univ8250_console);
return 0;
}
-console_initcall(serial8250_console_init);
-
-int serial8250_find_port(struct uart_port *p)
-{
- int line;
- struct uart_port *port;
-
- for (line = 0; line < nr_uarts; line++) {
- port = &serial8250_ports[line].port;
- if (uart_match_port(p, port))
- return line;
- }
- return -ENODEV;
-}
+console_initcall(univ8250_console_init);
-#define SERIAL8250_CONSOLE &serial8250_console
+#define SERIAL8250_CONSOLE &univ8250_console
#else
#define SERIAL8250_CONSOLE NULL
#endif
@@ -3413,19 +3593,19 @@ int __init early_serial_setup(struct uart_port *port)
p->iotype = port->iotype;
p->flags = port->flags;
p->mapbase = port->mapbase;
+ p->mapsize = port->mapsize;
p->private_data = port->private_data;
p->type = port->type;
p->line = port->line;
- set_io_from_upio(p);
+ serial8250_set_defaults(up_to_u8250p(p));
+
if (port->serial_in)
p->serial_in = port->serial_in;
if (port->serial_out)
p->serial_out = port->serial_out;
if (port->handle_irq)
p->handle_irq = port->handle_irq;
- else
- p->handle_irq = serial8250_default_handle_irq;
return 0;
}
@@ -3445,7 +3625,8 @@ void serial8250_suspend_port(int line)
port->type != PORT_8250) {
unsigned char canary = 0xa5;
serial_out(up, UART_SCR, canary);
- up->canary = canary;
+ if (serial_in(up, UART_SCR) == canary)
+ up->canary = canary;
}
uart_suspend_port(&serial8250_reg, port);
@@ -3667,6 +3848,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
+ uart->port.mapsize = up->port.mapsize;
uart->port.private_data = up->port.private_data;
uart->port.fifosize = up->port.fifosize;
uart->tx_loadsz = up->tx_loadsz;
@@ -3675,6 +3857,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.unthrottle = up->port.unthrottle;
uart->port.rs485_config = up->port.rs485_config;
uart->port.rs485 = up->port.rs485;
+ uart->dma = up->dma;
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
@@ -3683,10 +3866,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.dev)
uart->port.dev = up->port.dev;
+ if (skip_txen_test)
+ uart->port.flags |= UPF_NO_TXEN_TEST;
+
if (up->port.flags & UPF_FIXED_TYPE)
- serial8250_init_fixed_type_port(uart, up->port.type);
+ uart->port.type = up->port.type;
+
+ serial8250_set_defaults(uart);
- set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
if (up->port.serial_in)
uart->port.serial_in = up->port.serial_in;
@@ -3711,13 +3898,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->dl_read = up->dl_read;
if (up->dl_write)
uart->dl_write = up->dl_write;
- if (up->dma) {
- uart->dma = up->dma;
- if (!uart->dma->tx_dma)
- uart->dma->tx_dma = serial8250_tx_dma;
- if (!uart->dma->rx_dma)
- uart->dma->rx_dma = serial8250_rx_dma;
- }
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
@@ -3748,9 +3928,11 @@ void serial8250_unregister_port(int line)
uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
+ if (skip_txen_test)
+ uart->port.flags |= UPF_NO_TXEN_TEST;
uart->port.type = PORT_UNKNOWN;
uart->port.dev = &serial8250_isa_devs->dev;
- uart->capabilities = uart_config[uart->port.type].flags;
+ uart->capabilities = 0;
uart_add_one_port(&serial8250_reg, &uart->port);
} else {
uart->port.dev = NULL;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index e60116235836..176f18f2e3ab 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -17,7 +17,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -59,6 +58,8 @@ struct dw8250_data {
u8 usr_reg;
int last_mcr;
int line;
+ int msr_mask_on;
+ int msr_mask_off;
struct clk *clk;
struct clk *pclk;
struct reset_control *rst;
@@ -81,6 +82,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
value &= ~UART_MSR_DCTS;
}
+ /* Override any modem control signals if needed */
+ if (offset == UART_MSR) {
+ value |= d->msr_mask_on;
+ value &= ~d->msr_mask_off;
+ }
+
return value;
}
@@ -111,7 +118,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
dw8250_force_idle(p);
writeb(value, p->membase + (UART_LCR << p->regshift));
}
- dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
}
}
@@ -155,7 +165,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
__raw_writeq(value & 0xff,
p->membase + (UART_LCR << p->regshift));
}
- dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
}
}
#endif /* CONFIG_64BIT */
@@ -179,7 +192,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
dw8250_force_idle(p);
writel(value, p->membase + (UART_LCR << p->regshift));
}
- dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
}
}
@@ -334,16 +350,29 @@ static int dw8250_probe_of(struct uart_port *p,
if (id >= 0)
p->line = id;
- /* clock got configured through clk api, all done */
- if (p->uartclk)
- return 0;
+ if (of_property_read_bool(np, "dcd-override")) {
+ /* Always report DCD as active */
+ data->msr_mask_on |= UART_MSR_DCD;
+ data->msr_mask_off |= UART_MSR_DDCD;
+ }
- /* try to find out clock frequency from DT as fallback */
- if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(p->dev, "clk or clock-frequency not defined\n");
- return -EINVAL;
+ if (of_property_read_bool(np, "dsr-override")) {
+ /* Always report DSR as active */
+ data->msr_mask_on |= UART_MSR_DSR;
+ data->msr_mask_off |= UART_MSR_DDSR;
+ }
+
+ if (of_property_read_bool(np, "cts-override")) {
+ /* Always report CTS as active */
+ data->msr_mask_on |= UART_MSR_CTS;
+ data->msr_mask_off |= UART_MSR_DCTS;
+ }
+
+ if (of_property_read_bool(np, "ri-override")) {
+ /* Always report Ring indicator as inactive */
+ data->msr_mask_off |= UART_MSR_RI;
+ data->msr_mask_off |= UART_MSR_TERI;
}
- p->uartclk = val;
return 0;
}
@@ -351,20 +380,10 @@ static int dw8250_probe_of(struct uart_port *p,
static int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
- const struct acpi_device_id *id;
struct uart_port *p = &up->port;
dw8250_setup_port(up);
- id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
- if (!id)
- return -ENODEV;
-
- if (!p->uartclk)
- if (device_property_read_u32(p->dev, "clock-frequency",
- &p->uartclk))
- return -EINVAL;
-
p->iotype = UPIO_MEM32;
p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32;
@@ -384,18 +403,24 @@ static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ int irq = platform_get_irq(pdev, 0);
struct dw8250_data *data;
int err;
- if (!regs || !irq) {
- dev_err(&pdev->dev, "no registers/irq defined\n");
+ if (!regs) {
+ dev_err(&pdev->dev, "no registers defined\n");
return -EINVAL;
}
+ if (irq < 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "cannot get irq\n");
+ return irq;
+ }
+
spin_lock_init(&uart.port.lock);
uart.port.mapbase = regs->start;
- uart.port.irq = irq->start;
+ uart.port.irq = irq;
uart.port.handle_irq = dw8250_handle_irq;
uart.port.pm = dw8250_do_pm;
uart.port.type = PORT_8250;
@@ -412,12 +437,18 @@ static int dw8250_probe(struct platform_device *pdev)
return -ENOMEM;
data->usr_reg = DW_UART_USR;
+
+ /* Always ask for fixed clock rate from a property. */
+ device_property_read_u32(&pdev->dev, "clock-frequency",
+ &uart.port.uartclk);
+
+ /* If there is separate baudclk, get the rate from it. */
data->clk = devm_clk_get(&pdev->dev, "baudclk");
if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- if (!IS_ERR(data->clk)) {
+ if (!IS_ERR_OR_NULL(data->clk)) {
err = clk_prepare_enable(data->clk);
if (err)
dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
@@ -426,6 +457,12 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.uartclk = clk_get_rate(data->clk);
}
+ /* If no clock rate is defined, fail. */
+ if (!uart.port.uartclk) {
+ dev_err(&pdev->dev, "clock rate not defined\n");
+ return -EINVAL;
+ }
+
data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
err = -EPROBE_DEFER;
@@ -588,6 +625,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "80860F0A", 0 },
{ "8086228A", 0 },
{ "APMC0D08", 0},
+ { "AMD0020", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@@ -608,3 +646,4 @@ module_platform_driver(dw8250_platform_driver);
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
+MODULE_ALIAS("platform:dw-apb-uart");
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index c31a22b4f845..6c0fd8b9d1c3 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -29,15 +29,12 @@
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/console.h>
-#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
-static struct earlycon_device *early_device;
-
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
{
switch (port->iotype) {
@@ -45,6 +42,8 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse
return readb(port->membase + offset);
case UPIO_MEM32:
return readl(port->membase + (offset << 2));
+ case UPIO_MEM32BE:
+ return ioread32be(port->membase + (offset << 2));
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -61,6 +60,9 @@ void __weak __init serial8250_early_out(struct uart_port *port, int offset, int
case UPIO_MEM32:
writel(value, port->membase + (offset << 2));
break;
+ case UPIO_MEM32BE:
+ iowrite32be(value, port->membase + (offset << 2));
+ break;
case UPIO_PORT:
outb(value, port->iobase + offset);
break;
@@ -90,7 +92,8 @@ static void __init serial_putc(struct uart_port *port, int c)
static void __init early_serial8250_write(struct console *console,
const char *s, unsigned int count)
{
- struct uart_port *port = &early_device->port;
+ struct earlycon_device *device = console->data;
+ struct uart_port *port = &device->port;
unsigned int ier;
/* Save the IER and disable interrupts preserving the UUE bit */
@@ -107,21 +110,6 @@ static void __init early_serial8250_write(struct console *console,
serial8250_early_out(port, UART_IER, ier);
}
-static unsigned int __init probe_baud(struct uart_port *port)
-{
- unsigned char lcr, dll, dlm;
- unsigned int quot;
-
- lcr = serial8250_early_in(port, UART_LCR);
- serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB);
- dll = serial8250_early_in(port, UART_DLL);
- dlm = serial8250_early_in(port, UART_DLM);
- serial8250_early_out(port, UART_LCR, lcr);
-
- quot = (dlm << 8) | dll;
- return (port->uartclk / 16) / quot;
-}
-
static void __init init_port(struct earlycon_device *device)
{
struct uart_port *port = &device->port;
@@ -147,52 +135,20 @@ static int __init early_serial8250_setup(struct earlycon_device *device,
const char *options)
{
if (!(device->port.membase || device->port.iobase))
- return 0;
+ return -ENODEV;
if (!device->baud) {
- device->baud = probe_baud(&device->port);
- snprintf(device->options, sizeof(device->options), "%u",
- device->baud);
- }
+ struct uart_port *port = &device->port;
+ unsigned int ier;
- init_port(device);
+ /* assume the device was initialized, only mask interrupts */
+ ier = serial8250_early_in(port, UART_IER);
+ serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
+ } else
+ init_port(device);
- early_device = device;
device->con->write = early_serial8250_write;
return 0;
}
EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
-
-int __init setup_early_serial8250_console(char *cmdline)
-{
- char match[] = "uart8250";
-
- if (cmdline && cmdline[4] == ',')
- match[4] = '\0';
-
- return setup_earlycon(cmdline, match, early_serial8250_setup);
-}
-
-int serial8250_find_port_for_earlycon(void)
-{
- struct earlycon_device *device = early_device;
- struct uart_port *port = device ? &device->port : NULL;
- int line;
- int ret;
-
- if (!port || (!port->membase && !port->iobase))
- return -ENODEV;
-
- line = serial8250_find_port(port);
- if (line < 0)
- return -ENODEV;
-
- ret = update_console_cmdline("uart", 8250,
- "ttyS", line, device->options);
- if (ret < 0)
- ret = update_console_cmdline("uart", 0,
- "ttyS", line, device->options);
-
- return ret;
-}
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index ae5eaed6aa85..0b6381214917 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -21,7 +21,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index 1e6899bc9429..5815e81b5fc6 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -234,18 +234,7 @@ static struct pnp_driver fintek_8250_driver = {
.id_table = fintek_dev_table,
};
-static int fintek_8250_init(void)
-{
- return pnp_register_driver(&fintek_8250_driver);
-}
-module_init(fintek_8250_init);
-
-static void fintek_8250_exit(void)
-{
- pnp_unregister_driver(&fintek_8250_driver);
-}
-module_exit(fintek_8250_exit);
-
+module_pnp_driver(fintek_8250_driver);
MODULE_DESCRIPTION("Fintek F812164 module");
MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index b4882082b247..2891958cd842 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -10,7 +10,6 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/serial.h>
-#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/delay.h>
#include <linux/dio.h>
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index fe6d2e51da09..9289999cb7c6 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -11,7 +11,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index daf2c82984e9..08da4d3e2162 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -21,12 +21,14 @@
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
#include <linux/bitops.h>
+#include <linux/rational.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h>
+#include <linux/platform_data/dma-hsu.h>
#include "8250.h"
@@ -69,7 +71,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
"Please send the output of lspci -vv, this\n"
"message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
"manufacturer and name of serial board or\n"
- "modem board to rmk+serial@arm.linux.org.uk.\n",
+ "modem board to <linux-serial@vger.kernel.org>.\n",
pci_name(dev), str, dev->vendor, dev->device,
dev->subsystem_vendor, dev->subsystem_device);
}
@@ -1392,45 +1394,22 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
- unsigned int m, n;
+ unsigned long fref = 100000000, fuart = baud * 16;
+ unsigned long w = BIT(15) - 1;
+ unsigned long m, n;
u32 reg;
+ /* Get Fuart closer to Fref */
+ fuart *= rounddown_pow_of_two(fref / fuart);
+
/*
* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
* dividers must be adjusted.
*
* uartclk = (m / n) * 100 MHz, where m <= n
*/
- switch (baud) {
- case 500000:
- case 1000000:
- case 2000000:
- case 4000000:
- m = 64;
- n = 100;
- p->uartclk = 64000000;
- break;
- case 3500000:
- m = 56;
- n = 100;
- p->uartclk = 56000000;
- break;
- case 1500000:
- case 3000000:
- m = 48;
- n = 100;
- p->uartclk = 48000000;
- break;
- case 2500000:
- m = 40;
- n = 100;
- p->uartclk = 40000000;
- break;
- default:
- m = 2304;
- n = 3125;
- p->uartclk = 73728000;
- }
+ rational_best_approximation(fuart, fref, w, w, &m, &n);
+ p->uartclk = fuart;
/* Reset the clock */
reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
@@ -1525,6 +1504,167 @@ byt_serial_setup(struct serial_private *priv,
return ret;
}
+#define INTEL_MID_UART_PS 0x30
+#define INTEL_MID_UART_MUL 0x34
+#define INTEL_MID_UART_DIV 0x38
+
+static void intel_mid_set_termios(struct uart_port *p,
+ struct ktermios *termios,
+ struct ktermios *old,
+ unsigned long fref)
+{
+ unsigned int baud = tty_termios_baud_rate(termios);
+ unsigned short ps = 16;
+ unsigned long fuart = baud * ps;
+ unsigned long w = BIT(24) - 1;
+ unsigned long mul, div;
+
+ if (fref < fuart) {
+ /* Find prescaler value that satisfies Fuart < Fref */
+ if (fref > baud)
+ ps = fref / baud; /* baud rate too high */
+ else
+ ps = 1; /* PLL case */
+ fuart = baud * ps;
+ } else {
+ /* Get Fuart closer to Fref */
+ fuart *= rounddown_pow_of_two(fref / fuart);
+ }
+
+ rational_best_approximation(fuart, fref, w, w, &mul, &div);
+ p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
+
+ writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
+ writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
+ writel(div, p->membase + INTEL_MID_UART_DIV);
+
+ serial8250_do_set_termios(p, termios, old);
+}
+
+static void intel_mid_set_termios_38_4M(struct uart_port *p,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ intel_mid_set_termios(p, termios, old, 38400000);
+}
+
+static void intel_mid_set_termios_50M(struct uart_port *p,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ /*
+ * The uart clk is 50Mhz, and the baud rate come from:
+ * baud = 50M * MUL / (DIV * PS * DLAB)
+ */
+ intel_mid_set_termios(p, termios, old, 50000000);
+}
+
+static bool intel_mid_dma_filter(struct dma_chan *chan, void *param)
+{
+ struct hsu_dma_slave *s = param;
+
+ if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
+ return false;
+
+ chan->private = s;
+ return true;
+}
+
+static int intel_mid_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx,
+ int index, struct pci_dev *dma_dev)
+{
+ struct device *dev = port->port.dev;
+ struct uart_8250_dma *dma;
+ struct hsu_dma_slave *tx_param, *rx_param;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+ if (!tx_param)
+ return -ENOMEM;
+
+ rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+ if (!rx_param)
+ return -ENOMEM;
+
+ rx_param->chan_id = index * 2 + 1;
+ tx_param->chan_id = index * 2;
+
+ dma->rxconf.src_maxburst = 64;
+ dma->txconf.dst_maxburst = 64;
+
+ rx_param->dma_dev = &dma_dev->dev;
+ tx_param->dma_dev = &dma_dev->dev;
+
+ dma->fn = intel_mid_dma_filter;
+ dma->rx_param = rx_param;
+ dma->tx_param = tx_param;
+
+ port->port.type = PORT_16750;
+ port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ port->dma = dma;
+
+ return pci_default_setup(priv, board, port, idx);
+}
+
+#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b
+#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c
+#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d
+
+static int pnw_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *pdev = priv->dev;
+ struct pci_dev *dma_dev;
+ int index;
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_PNW_UART1:
+ index = 0;
+ break;
+ case PCI_DEVICE_ID_INTEL_PNW_UART2:
+ index = 1;
+ break;
+ case PCI_DEVICE_ID_INTEL_PNW_UART3:
+ index = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
+
+ port->port.set_termios = intel_mid_set_termios_50M;
+
+ return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
+}
+
+#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191
+
+static int tng_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *pdev = priv->dev;
+ struct pci_dev *dma_dev;
+ int index = PCI_FUNC(pdev->devfn);
+
+ /* Currently no support for HSU port0 */
+ if (index-- == 0)
+ return -ENODEV;
+
+ dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0));
+
+ port->port.set_termios = intel_mid_set_termios_38_4M;
+
+ return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
+}
+
static int
pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1550,95 +1690,71 @@ static int pci_fintek_setup(struct serial_private *priv,
struct uart_8250_port *port, int idx)
{
struct pci_dev *pdev = priv->dev;
- unsigned long base;
- unsigned long iobase;
- unsigned long ciobase = 0;
u8 config_base;
+ u16 iobase;
+
+ config_base = 0x40 + 0x08 * idx;
+
+ /* Get the io address from configuration space */
+ pci_read_config_word(pdev, config_base + 4, &iobase);
+
+ dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase);
+
+ port->port.iotype = UPIO_PORT;
+ port->port.iobase = iobase;
+
+ return 0;
+}
+
+static int pci_fintek_init(struct pci_dev *dev)
+{
+ unsigned long iobase;
+ u32 max_port, i;
u32 bar_data[3];
+ u8 config_base;
- /*
- * Find each UARTs offset in PCI configuraion space
- */
- switch (idx) {
- case 0:
- config_base = 0x40;
- break;
- case 1:
- config_base = 0x48;
- break;
- case 2:
- config_base = 0x50;
- break;
- case 3:
- config_base = 0x58;
- break;
- case 4:
- config_base = 0x60;
- break;
- case 5:
- config_base = 0x68;
- break;
- case 6:
- config_base = 0x70;
+ switch (dev->device) {
+ case 0x1104: /* 4 ports */
+ case 0x1108: /* 8 ports */
+ max_port = dev->device & 0xff;
break;
- case 7:
- config_base = 0x78;
- break;
- case 8:
- config_base = 0x80;
- break;
- case 9:
- config_base = 0x88;
- break;
- case 10:
- config_base = 0x90;
- break;
- case 11:
- config_base = 0x98;
+ case 0x1112: /* 12 ports */
+ max_port = 12;
break;
default:
- /* Unknown number of ports, get out of here */
return -EINVAL;
}
- if (idx < 4) {
- base = pci_resource_start(priv->dev, 3);
- ciobase = (int)(base + (0x8 * idx));
- }
-
/* Get the io address dispatch from the BIOS */
- pci_read_config_dword(pdev, 0x24, &bar_data[0]);
- pci_read_config_dword(pdev, 0x20, &bar_data[1]);
- pci_read_config_dword(pdev, 0x1c, &bar_data[2]);
-
- /* Calculate Real IO Port */
- iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8;
+ pci_read_config_dword(dev, 0x24, &bar_data[0]);
+ pci_read_config_dword(dev, 0x20, &bar_data[1]);
+ pci_read_config_dword(dev, 0x1c, &bar_data[2]);
- dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n",
- __func__, idx, iobase, ciobase, config_base);
+ for (i = 0; i < max_port; ++i) {
+ /* UART0 configuration offset start from 0x40 */
+ config_base = 0x40 + 0x08 * i;
- /* Enable UART I/O port */
- pci_write_config_byte(pdev, config_base + 0x00, 0x01);
+ /* Calculate Real IO Port */
+ iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8;
- /* Select 128-byte FIFO and 8x FIFO threshold */
- pci_write_config_byte(pdev, config_base + 0x01, 0x33);
+ /* Enable UART I/O port */
+ pci_write_config_byte(dev, config_base + 0x00, 0x01);
- /* LSB UART */
- pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff));
+ /* Select 128-byte FIFO and 8x FIFO threshold */
+ pci_write_config_byte(dev, config_base + 0x01, 0x33);
- /* MSB UART */
- pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8));
+ /* LSB UART */
+ pci_write_config_byte(dev, config_base + 0x04,
+ (u8)(iobase & 0xff));
- /* irq number, this usually fails, but the spec says to do it anyway. */
- pci_write_config_byte(pdev, config_base + 0x06, pdev->irq);
+ /* MSB UART */
+ pci_write_config_byte(dev, config_base + 0x05,
+ (u8)((iobase & 0xff00) >> 8));
- port->port.iotype = UPIO_PORT;
- port->port.iobase = iobase;
- port->port.mapbase = 0;
- port->port.membase = NULL;
- port->port.regshift = 0;
+ pci_write_config_byte(dev, config_base + 0x06, dev->irq);
+ }
- return 0;
+ return max_port;
}
static int skip_tx_en_setup(struct serial_private *priv,
@@ -1989,10 +2105,31 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
},
{
.vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_QRK_UART,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_default_setup,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART3,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_TNG_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = tng_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
@@ -2201,13 +2338,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
*/
{
.vendor = PCI_VENDOR_ID_PLX,
- .device = PCI_DEVICE_ID_PLX_9030,
- .subvendor = PCI_SUBVENDOR_ID_PERLE,
- .subdevice = PCI_ANY_ID,
- .setup = pci_default_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_PLX,
.device = PCI_DEVICE_ID_PLX_9050,
.subvendor = PCI_SUBVENDOR_ID_EXSYS,
.subdevice = PCI_SUBDEVICE_ID_EXSYS_4055,
@@ -2667,6 +2797,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_setup,
+ .init = pci_fintek_init,
},
{
.vendor = 0x1c29,
@@ -2674,6 +2805,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_setup,
+ .init = pci_fintek_init,
},
{
.vendor = 0x1c29,
@@ -2681,6 +2813,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_setup,
+ .init = pci_fintek_init,
},
/*
@@ -2878,6 +3011,8 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200,
pbn_byt,
+ pbn_pnw,
+ pbn_tng,
pbn_qrk,
pbn_omegapci,
pbn_NETMOS9900_2s_115200,
@@ -3644,6 +3779,16 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 0x80,
.reg_shift = 2,
},
+ [pbn_pnw] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ },
+ [pbn_tng] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 1843200,
+ },
[pbn_qrk] = {
.flags = FL_BASE0,
.num_ports = 1,
@@ -4020,41 +4165,41 @@ static void pciserial_remove_one(struct pci_dev *dev)
pci_disable_device(dev);
}
-#ifdef CONFIG_PM
-static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pciserial_suspend_one(struct device *dev)
{
- struct serial_private *priv = pci_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct serial_private *priv = pci_get_drvdata(pdev);
if (priv)
pciserial_suspend_ports(priv);
- pci_save_state(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
-static int pciserial_resume_one(struct pci_dev *dev)
+static int pciserial_resume_one(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct serial_private *priv = pci_get_drvdata(pdev);
int err;
- struct serial_private *priv = pci_get_drvdata(dev);
-
- pci_set_power_state(dev, PCI_D0);
- pci_restore_state(dev);
if (priv) {
/*
* The device may have been disabled. Re-enable it.
*/
- err = pci_enable_device(dev);
+ err = pci_enable_device(pdev);
/* FIXME: We cannot simply error out here */
if (err)
- dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n");
+ dev_err(dev, "Unable to re-enable ports, trying to continue.\n");
pciserial_resume_ports(priv);
}
return 0;
}
#endif
+static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one,
+ pciserial_resume_one);
+
static struct pci_device_id serial_pci_tbl[] = {
/* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
@@ -5377,6 +5522,26 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_byt },
/*
+ * Intel Penwell
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+
+ /*
+ * Intel Tangier
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_tng},
+
+ /*
* Intel Quark x1000
*/
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
@@ -5415,10 +5580,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
- { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, pbn_b0_bt_2_115200 },
-
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_4 },
@@ -5528,10 +5689,9 @@ static struct pci_driver serial_pci_driver = {
.name = "serial",
.probe = pciserial_init_one,
.remove = pciserial_remove_one,
-#ifdef CONFIG_PM
- .suspend = pciserial_suspend_one,
- .resume = pciserial_resume_one,
-#endif
+ .driver = {
+ .pm = &pciserial_pm_ops,
+ },
.id_table = serial_pci_tbl,
.err_handler = &serial8250_err_handler,
};
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 6f7f2d753def..c35070356528 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -108,6 +108,7 @@ config SERIAL_8250_PCI
tristate "8250/16550 PCI device support" if EXPERT
depends on SERIAL_8250 && PCI
default SERIAL_8250
+ select RATIONAL
help
This builds standard PCI serial support. You may be able to
disable this feature if you only need legacy serial support.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index d2501f01cd03..f8120c1bde14 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -20,7 +20,7 @@ comment "Non-8250 serial port support"
config SERIAL_AMBA_PL010
tristate "ARM AMBA PL010 serial port support"
- depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
+ depends on ARM_AMBA
select SERIAL_CORE
help
This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have
@@ -483,16 +483,6 @@ config SERIAL_SA1100_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_MFD_HSU
- tristate "Medfield High Speed UART support"
- depends on PCI
- select SERIAL_CORE
-
-config SERIAL_MFD_HSU_CONSOLE
- bool "Medfile HSU serial console support"
- depends on SERIAL_MFD_HSU=y
- select SERIAL_CORE_CONSOLE
-
config SERIAL_BFIN
tristate "Blackfin serial port support"
depends on BLACKFIN
@@ -835,7 +825,7 @@ config SERIAL_MCF_CONSOLE
config SERIAL_PMACZILOG
tristate "Mac or PowerMac z85c30 ESCC support"
- depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
+ depends on (M68K && MAC) || PPC_PMAC
select SERIAL_CORE
help
This driver supports the Zilog z85C30 serial ports found on
@@ -878,7 +868,7 @@ config SERIAL_PMACZILOG_CONSOLE
config SERIAL_CPM
tristate "CPM SCC/SMC serial port support"
- depends on CPM2 || 8xx
+ depends on CPM2 || CPM1
select SERIAL_CORE
help
This driver supports the SCC and SMC serial ports on Motorola
@@ -1054,7 +1044,7 @@ config SERIAL_SGI_IOC3
config SERIAL_MSM
bool "MSM on-chip serial port support"
- depends on ARCH_MSM || ARCH_QCOM
+ depends on ARCH_QCOM
select SERIAL_CORE
config SERIAL_MSM_CONSOLE
@@ -1063,18 +1053,6 @@ config SERIAL_MSM_CONSOLE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
-config SERIAL_MSM_HS
- tristate "MSM UART High Speed: Serial Driver"
- depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
- select SERIAL_CORE
- help
- If you have a machine based on MSM family of SoCs, you
- can enable its onboard high speed serial port by enabling
- this option.
-
- Choose M here to compile it as a module. The module will be
- called msm_serial_hs.
-
config SERIAL_VT8500
bool "VIA VT8500 on-chip serial port support"
depends on ARCH_VT8500
@@ -1153,7 +1131,7 @@ config SERIAL_OMAP_CONSOLE
config SERIAL_OF_PLATFORM_NWPSERIAL
tristate "NWP serial port driver"
- depends on PPC_OF && PPC_DCR
+ depends on PPC_DCR
select SERIAL_OF_PLATFORM
select SERIAL_CORE_CONSOLE
select SERIAL_CORE
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 599be4b05a26..c3ac3d930b33 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -62,7 +62,6 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
-obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
@@ -78,7 +77,6 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
-obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8d94c194f090..5a4e9d579585 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,6 +58,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
#include <linux/io.h>
+#include <linux/workqueue.h>
#define UART_NR 14
@@ -156,7 +157,9 @@ struct uart_amba_port {
unsigned int lcrh_tx; /* vendor-specific */
unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
+ struct delayed_work tx_softirq_work;
bool autorts;
+ unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
@@ -164,6 +167,7 @@ struct uart_amba_port {
bool using_rx_dma;
struct pl011_dmarx_data dmarx;
struct pl011_dmatx_data dmatx;
+ bool dma_probed;
#endif
};
@@ -261,10 +265,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
}
}
-static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap)
+static void pl011_dma_probe(struct uart_amba_port *uap)
{
/* DMA is the sole user of the platform data right now */
struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
+ struct device *dev = uap->port.dev;
struct dma_slave_config tx_conf = {
.dst_addr = uap->port.mapbase + UART01x_DR,
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
@@ -275,9 +280,14 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
struct dma_chan *chan;
dma_cap_mask_t mask;
- chan = dma_request_slave_channel(dev, "tx");
+ uap->dma_probed = true;
+ chan = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR(chan)) {
+ if (PTR_ERR(chan) == -EPROBE_DEFER) {
+ uap->dma_probed = false;
+ return;
+ }
- if (!chan) {
/* We need platform data */
if (!plat || !plat->dma_filter) {
dev_info(uap->port.dev, "no DMA platform data\n");
@@ -385,63 +395,17 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
}
}
-#ifndef MODULE
-/*
- * Stack up the UARTs and let the above initcall be done at device
- * initcall time, because the serial driver is called as an arch
- * initcall, and at this time the DMA subsystem is not yet registered.
- * At this point the driver will switch over to using DMA where desired.
- */
-struct dma_uap {
- struct list_head node;
- struct uart_amba_port *uap;
- struct device *dev;
-};
-
-static LIST_HEAD(pl011_dma_uarts);
-
-static int __init pl011_dma_initcall(void)
-{
- struct list_head *node, *tmp;
-
- list_for_each_safe(node, tmp, &pl011_dma_uarts) {
- struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
- pl011_dma_probe_initcall(dmau->dev, dmau->uap);
- list_del(node);
- kfree(dmau);
- }
- return 0;
-}
-
-device_initcall(pl011_dma_initcall);
-
-static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
-{
- struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
- if (dmau) {
- dmau->uap = uap;
- dmau->dev = dev;
- list_add_tail(&dmau->node, &pl011_dma_uarts);
- }
-}
-#else
-static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
-{
- pl011_dma_probe_initcall(dev, uap);
-}
-#endif
-
static void pl011_dma_remove(struct uart_amba_port *uap)
{
- /* TODO: remove the initcall if it has not yet executed */
if (uap->dmatx.chan)
dma_release_channel(uap->dmatx.chan);
if (uap->dmarx.chan)
dma_release_channel(uap->dmarx.chan);
}
-/* Forward declare this for the refill routine */
+/* Forward declare these for the refill routine */
static int pl011_dma_tx_refill(struct uart_amba_port *uap);
+static void pl011_start_tx_pio(struct uart_amba_port *uap);
/*
* The current DMA TX buffer has been sent.
@@ -479,14 +443,13 @@ static void pl011_dma_tx_callback(void *data)
return;
}
- if (pl011_dma_tx_refill(uap) <= 0) {
+ if (pl011_dma_tx_refill(uap) <= 0)
/*
* We didn't queue a DMA buffer for some reason, but we
* have data pending to be sent. Re-enable the TX IRQ.
*/
- uap->im |= UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- }
+ pl011_start_tx_pio(uap);
+
spin_unlock_irqrestore(&uap->port.lock, flags);
}
@@ -664,12 +627,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
if (!uap->dmatx.queued) {
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
- ret = true;
- } else {
- uap->im |= UART011_TXIM;
+ writew(uap->im, uap->port.membase +
+ UART011_IMSC);
+ } else
ret = false;
- }
- writew(uap->im, uap->port.membase + UART011_IMSC);
} else if (!(uap->dmacr & UART011_TXDMAE)) {
uap->dmacr |= UART011_TXDMAE;
writew(uap->dmacr,
@@ -1021,6 +982,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
{
int ret;
+ if (!uap->dma_probed)
+ pl011_dma_probe(uap);
+
if (!uap->dmatx.chan)
return;
@@ -1142,7 +1106,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#else
/* Blank functions if the DMA engine is not available */
-static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
+static inline void pl011_dma_probe(struct uart_amba_port *uap)
{
}
@@ -1208,15 +1172,24 @@ static void pl011_stop_tx(struct uart_port *port)
pl011_dma_tx_stop(uap);
}
+static bool pl011_tx_chars(struct uart_amba_port *uap);
+
+/* Start TX with programmed I/O only (no DMA) */
+static void pl011_start_tx_pio(struct uart_amba_port *uap)
+{
+ uap->im |= UART011_TXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ if (!uap->tx_irq_seen)
+ pl011_tx_chars(uap);
+}
+
static void pl011_start_tx(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- if (!pl011_dma_tx_start(uap)) {
- uap->im |= UART011_TXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- }
+ if (!pl011_dma_tx_start(uap))
+ pl011_start_tx_pio(uap);
}
static void pl011_stop_rx(struct uart_port *port)
@@ -1274,40 +1247,87 @@ __acquires(&uap->port.lock)
spin_lock(&uap->port.lock);
}
-static void pl011_tx_chars(struct uart_amba_port *uap)
+/*
+ * Transmit a character
+ * There must be at least one free entry in the TX FIFO to accept the char.
+ *
+ * Returns true if the FIFO might have space in it afterwards;
+ * returns false if the FIFO definitely became full.
+ */
+static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
+{
+ writew(c, uap->port.membase + UART01x_DR);
+ uap->port.icount.tx++;
+
+ if (likely(uap->tx_irq_seen > 1))
+ return true;
+
+ return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF);
+}
+
+static bool pl011_tx_chars(struct uart_amba_port *uap)
{
struct circ_buf *xmit = &uap->port.state->xmit;
int count;
+ if (unlikely(uap->tx_irq_seen < 2))
+ /*
+ * Initial FIFO fill level unknown: we must check TXFF
+ * after each write, so just try to fill up the FIFO.
+ */
+ count = uap->fifosize;
+ else /* tx_irq_seen >= 2 */
+ /*
+ * FIFO initially at least half-empty, so we can simply
+ * write half the FIFO without polling TXFF.
+
+ * Note: the *first* TX IRQ can still race with
+ * pl011_start_tx_pio(), which can result in the FIFO
+ * being fuller than expected in that case.
+ */
+ count = uap->fifosize >> 1;
+
+ /*
+ * If the FIFO is full we're guaranteed a TX IRQ at some later point,
+ * and can't transmit immediately in any case:
+ */
+ if (unlikely(uap->tx_irq_seen < 2 &&
+ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF))
+ return false;
+
if (uap->port.x_char) {
- writew(uap->port.x_char, uap->port.membase + UART01x_DR);
- uap->port.icount.tx++;
+ pl011_tx_char(uap, uap->port.x_char);
uap->port.x_char = 0;
- return;
+ --count;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
pl011_stop_tx(&uap->port);
- return;
+ goto done;
}
/* If we are using DMA mode, try to send some characters. */
if (pl011_dma_tx_irq(uap))
- return;
+ goto done;
- count = uap->fifosize >> 1;
- do {
- writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+ while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) {
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- uap->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
- } while (--count > 0);
+ }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
- if (uart_circ_empty(xmit))
+ if (uart_circ_empty(xmit)) {
pl011_stop_tx(&uap->port);
+ goto done;
+ }
+
+ if (unlikely(!uap->tx_irq_seen))
+ schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout);
+
+done:
+ return false;
}
static void pl011_modem_status(struct uart_amba_port *uap)
@@ -1334,6 +1354,28 @@ static void pl011_modem_status(struct uart_amba_port *uap)
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
}
+static void pl011_tx_softirq(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct uart_amba_port *uap =
+ container_of(dwork, struct uart_amba_port, tx_softirq_work);
+
+ spin_lock(&uap->port.lock);
+ while (pl011_tx_chars(uap)) ;
+ spin_unlock(&uap->port.lock);
+}
+
+static void pl011_tx_irq_seen(struct uart_amba_port *uap)
+{
+ if (likely(uap->tx_irq_seen > 1))
+ return;
+
+ uap->tx_irq_seen++;
+ if (uap->tx_irq_seen < 2)
+ /* first TX IRQ */
+ cancel_delayed_work(&uap->tx_softirq_work);
+}
+
static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
@@ -1372,8 +1414,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
- if (status & UART011_TXIS)
+ if (status & UART011_TXIS) {
+ pl011_tx_irq_seen(uap);
pl011_tx_chars(uap);
+ }
if (pass_counter-- == 0)
break;
@@ -1577,7 +1621,7 @@ static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- unsigned int cr, lcr_h, fbrd, ibrd;
+ unsigned int cr;
int retval;
retval = pl011_hwinit(port);
@@ -1595,30 +1639,8 @@ static int pl011_startup(struct uart_port *port)
writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
- /*
- * Provoke TX FIFO interrupt into asserting. Taking care to preserve
- * baud rate and data format specified by FBRD, IBRD and LCRH as the
- * UART may already be in use as a console.
- */
spin_lock_irq(&uap->port.lock);
- fbrd = readw(uap->port.membase + UART011_FBRD);
- ibrd = readw(uap->port.membase + UART011_IBRD);
- lcr_h = readw(uap->port.membase + uap->lcrh_rx);
-
- cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
- writew(cr, uap->port.membase + UART011_CR);
- writew(0, uap->port.membase + UART011_FBRD);
- writew(1, uap->port.membase + UART011_IBRD);
- pl011_write_lcr_h(uap, 0);
- writew(0, uap->port.membase + UART01x_DR);
- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
- barrier();
-
- writew(fbrd, uap->port.membase + UART011_FBRD);
- writew(ibrd, uap->port.membase + UART011_IBRD);
- pl011_write_lcr_h(uap, lcr_h);
-
/* restore RTS and DTR */
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
@@ -1672,13 +1694,15 @@ static void pl011_shutdown(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
unsigned int cr;
+ cancel_delayed_work_sync(&uap->tx_softirq_work);
+
/*
* disable all interrupts
*/
spin_lock_irq(&uap->port.lock);
uap->im = 0;
writew(uap->im, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR);
spin_unlock_irq(&uap->port.lock);
pl011_dma_shutdown(uap);
@@ -2218,7 +2242,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = i;
- pl011_dma_probe(&dev->dev, uap);
+ INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
/* Ensure interrupts from this UART are masked and cleared */
writew(0, uap->port.membase + UART011_IMSC);
@@ -2233,7 +2257,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (!amba_reg.state) {
ret = uart_register_driver(&amba_reg);
if (ret < 0) {
- pr_err("Failed to register AMBA-PL011 driver\n");
+ dev_err(&dev->dev,
+ "Failed to register AMBA-PL011 driver\n");
return ret;
}
}
@@ -2242,7 +2267,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (ret) {
amba_ports[i] = NULL;
uart_unregister_driver(&amba_reg);
- pl011_dma_remove(uap);
}
return ret;
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 4f0f95e358e8..f3af317131ac 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -572,7 +572,7 @@ static int apbuart_probe(struct platform_device *op)
return 0;
}
-static struct of_device_id apbuart_match[] = {
+static const struct of_device_id apbuart_match[] = {
{
.name = "GAISLER_APBUART",
},
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 77fc9faa74a4..1519d2ca7705 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -649,7 +649,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
id = 0;
}
- if (id > CONFIG_SERIAL_AR933X_NR_UARTS)
+ if (id >= CONFIG_SERIAL_AR933X_NR_UARTS)
return -EINVAL;
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 846552bff67d..d58fe4763d9e 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -47,6 +47,7 @@
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/irq.h>
+#include <linux/suspend.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -173,6 +174,12 @@ struct atmel_uart_port {
bool ms_irq_enabled;
bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
+
+ bool suspended;
+ unsigned int pending;
+ unsigned int pending_status;
+ spinlock_t lock_suspended;
+
int (*prepare_rx)(struct uart_port *port);
int (*prepare_tx)(struct uart_port *port);
void (*schedule_rx)(struct uart_port *port);
@@ -848,7 +855,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
spin_lock_init(&atmel_port->lock_tx);
sg_init_table(&atmel_port->sg_tx, 1);
/* UART circular tx buffer is an aligned page. */
- BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+ BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf));
sg_set_page(&atmel_port->sg_tx,
virt_to_page(port->state->xmit.buf),
UART_XMIT_SIZE,
@@ -1027,10 +1034,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
spin_lock_init(&atmel_port->lock_rx);
sg_init_table(&atmel_port->sg_rx, 1);
/* UART circular rx buffer is an aligned page. */
- BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+ BUG_ON(!PAGE_ALIGNED(ring->buf));
sg_set_page(&atmel_port->sg_rx,
virt_to_page(ring->buf),
- ATMEL_SERIAL_RINGSIZE,
+ sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
(int)ring->buf & ~PAGE_MASK);
nent = dma_map_sg(port->dev,
&atmel_port->sg_rx,
@@ -1179,12 +1186,15 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- unsigned int status, pending, pass_counter = 0;
+ unsigned int status, pending, mask, pass_counter = 0;
bool gpio_handled = false;
+ spin_lock(&atmel_port->lock_suspended);
+
do {
status = atmel_get_lines_status(port);
- pending = status & UART_GET_IMR(port);
+ mask = UART_GET_IMR(port);
+ pending = status & mask;
if (!gpio_handled) {
/*
* Dealing with GPIO interrupt
@@ -1206,11 +1216,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
if (!pending)
break;
+ if (atmel_port->suspended) {
+ atmel_port->pending |= pending;
+ atmel_port->pending_status = status;
+ UART_PUT_IDR(port, mask);
+ pm_system_wakeup();
+ break;
+ }
+
atmel_handle_receive(port, pending);
atmel_handle_status(port, pending, status);
atmel_handle_transmit(port, pending);
} while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
+ spin_unlock(&atmel_port->lock_suspended);
+
return pass_counter ? IRQ_HANDLED : IRQ_NONE;
}
@@ -1534,7 +1554,7 @@ static void atmel_tasklet_func(unsigned long data)
spin_unlock(&port->lock);
}
-static int atmel_init_property(struct atmel_uart_port *atmel_port,
+static void atmel_init_property(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1575,7 +1595,6 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port,
atmel_port->use_dma_tx = false;
}
- return 0;
}
static void atmel_init_rs485(struct uart_port *port,
@@ -1742,7 +1761,8 @@ static int atmel_startup(struct uart_port *port)
/*
* Allocate the IRQ
*/
- retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+ retval = request_irq(port->irq, atmel_interrupt,
+ IRQF_SHARED | IRQF_COND_SUSPEND,
tty ? tty->name : "atmel_serial", port);
if (retval) {
dev_err(port->dev, "atmel_startup - Can't get irq\n");
@@ -1756,10 +1776,13 @@ static int atmel_startup(struct uart_port *port)
if (retval)
goto free_irq;
+ tasklet_enable(&atmel_port->tasklet);
+
/*
* Initialize DMA (if necessary)
*/
atmel_init_property(atmel_port, pdev);
+ atmel_set_ops(port);
if (atmel_port->prepare_rx) {
retval = atmel_port->prepare_rx(port);
@@ -1858,6 +1881,7 @@ static void atmel_shutdown(struct uart_port *port)
* Clear out any scheduled tasklets before
* we destroy the buffers
*/
+ tasklet_disable(&atmel_port->tasklet);
tasklet_kill(&atmel_port->tasklet);
/*
@@ -2235,8 +2259,8 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
- if (!atmel_init_property(atmel_port, pdev))
- atmel_set_ops(port);
+ atmel_init_property(atmel_port, pdev);
+ atmel_set_ops(port);
atmel_init_rs485(port, pdev);
@@ -2251,6 +2275,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
(unsigned long)port);
+ tasklet_disable(&atmel_port->tasklet);
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
@@ -2513,8 +2538,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
/* we can not wake up if we're running on slow clock */
atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
- if (atmel_serial_clk_will_stop())
+ if (atmel_serial_clk_will_stop()) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+ atmel_port->suspended = true;
+ spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
device_set_wakeup_enable(&pdev->dev, 0);
+ }
uart_suspend_port(&atmel_uart, port);
@@ -2525,6 +2556,18 @@ static int atmel_serial_resume(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&atmel_port->lock_suspended, flags);
+ if (atmel_port->pending) {
+ atmel_handle_receive(port, atmel_port->pending);
+ atmel_handle_status(port, atmel_port->pending,
+ atmel_port->pending_status);
+ atmel_handle_transmit(port, atmel_port->pending);
+ atmel_port->pending = 0;
+ }
+ atmel_port->suspended = false;
+ spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
uart_resume_port(&atmel_uart, port);
device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
@@ -2542,8 +2585,8 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
struct gpio_desc *gpiod;
p->gpios = mctrl_gpio_init(dev, 0);
- if (IS_ERR_OR_NULL(p->gpios))
- return -1;
+ if (IS_ERR(p->gpios))
+ return PTR_ERR(p->gpios);
for (i = 0; i < UART_GPIO_MAX; i++) {
gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
@@ -2593,10 +2636,13 @@ static int atmel_serial_probe(struct platform_device *pdev)
port->backup_imr = 0;
port->uart.line = ret;
+ spin_lock_init(&port->lock_suspended);
+
ret = atmel_init_gpios(port, &pdev->dev);
- if (ret < 0)
- dev_err(&pdev->dev, "%s",
- "Failed to initialize GPIOs. The serial port may not work as expected");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to initialize GPIOs.");
+ goto err;
+ }
ret = atmel_init_port(port, pdev);
if (ret)
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 01d83df08e3d..681e0f3d5e0e 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -854,7 +854,7 @@ static int bcm_uart_probe(struct platform_device *pdev)
ret = uart_add_one_port(&bcm_uart_driver, port);
if (ret) {
- ports[pdev->id].membase = 0;
+ ports[pdev->id].membase = NULL;
return ret;
}
platform_set_drvdata(pdev, port);
@@ -868,7 +868,7 @@ static int bcm_uart_remove(struct platform_device *pdev)
port = platform_get_drvdata(pdev);
uart_remove_one_port(&bcm_uart_driver, port);
/* mark port as free */
- ports[pdev->id].membase = 0;
+ ports[pdev->id].membase = NULL;
return 0;
}
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 43b3e2c233ff..155781ece050 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -464,6 +464,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
int x_pos, pos;
unsigned long flags;
+ dma_disable_irq_nosync(uart->rx_dma_channel);
spin_lock_irqsave(&uart->rx_lock, flags);
/* 2D DMA RX buffer ring is used. Because curr_y_count and
@@ -496,6 +497,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
}
spin_unlock_irqrestore(&uart->rx_lock, flags);
+ dma_enable_irq(uart->rx_dma_channel);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 6e11c275f2ab..d5d2dd7c7917 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -501,6 +501,8 @@ static int uart_clps711x_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, s);
s->gpios = mctrl_gpio_init(&pdev->dev, 0);
+ if (IS_ERR(s->gpios))
+ return PTR_ERR(s->gpios);
ret = uart_add_one_port(&clps711x_uart, &s->port);
if (ret)
diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile
index e072724ea754..896a5d57881c 100644
--- a/drivers/tty/serial/cpm_uart/Makefile
+++ b/drivers/tty/serial/cpm_uart/Makefile
@@ -6,6 +6,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
# Select the correct platform objects.
cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o
-cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o
+cpm_uart-objs-$(CONFIG_CPM1) += cpm_uart_cpm1.o
cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
index cf34d26ff6cd..0ad027b95873 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart.h
@@ -19,7 +19,7 @@
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
-#elif defined(CONFIG_8xx)
+#elif defined(CONFIG_CPM1)
#include "cpm_uart_cpm1.h"
#endif
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index fddb1fd4d9d3..08431adeacd5 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1435,7 +1435,7 @@ static int cpm_uart_remove(struct platform_device *ofdev)
return uart_remove_one_port(&cpm_reg, &pinfo->port);
}
-static struct of_device_id cpm_uart_match[] = {
+static const struct of_device_id cpm_uart_match[] = {
{
.compatible = "fsl,cpm1-smc-uart",
},
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 64fe25a4285c..5fdc9f3ecd64 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -10,6 +10,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -34,6 +37,10 @@ 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);
@@ -54,44 +61,29 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
return base;
}
-static int __init parse_options(struct earlycon_device *device,
- char *options)
+static int __init parse_options(struct earlycon_device *device, char *options)
{
struct uart_port *port = &device->port;
- int mmio, mmio32, length;
+ int length;
unsigned long addr;
- if (!options)
- return -ENODEV;
+ if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
+ return -EINVAL;
- mmio = !strncmp(options, "mmio,", 5);
- mmio32 = !strncmp(options, "mmio32,", 7);
- if (mmio || mmio32) {
- port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
- options += mmio ? 5 : 7;
- addr = simple_strtoul(options, NULL, 0);
+ switch (port->iotype) {
+ case UPIO_MEM32:
+ port->regshift = 2; /* fall-through */
+ case UPIO_MEM:
port->mapbase = addr;
- if (mmio32)
- port->regshift = 2;
- } else if (!strncmp(options, "io,", 3)) {
- port->iotype = UPIO_PORT;
- options += 3;
- addr = simple_strtoul(options, NULL, 0);
+ break;
+ case UPIO_PORT:
port->iobase = addr;
- mmio = 0;
- } else if (!strncmp(options, "0x", 2)) {
- port->iotype = UPIO_MEM;
- addr = simple_strtoul(options, NULL, 0);
- port->mapbase = addr;
- } else {
+ break;
+ default:
return -EINVAL;
}
- port->uartclk = BASE_BAUD * 16;
-
- options = strchr(options, ',');
if (options) {
- options++;
device->baud = simple_strtoul(options, NULL, 0);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
@@ -100,7 +92,7 @@ static int __init parse_options(struct earlycon_device *device,
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- mmio32 ? "32" : "",
+ (port->iotype == UPIO_MEM32) ? "32" : "",
(unsigned long long)port->mapbase,
device->options);
else
@@ -111,34 +103,21 @@ static int __init parse_options(struct earlycon_device *device,
return 0;
}
-int __init setup_earlycon(char *buf, const char *match,
- int (*setup)(struct earlycon_device *, const char *))
+static int __init register_earlycon(char *buf, const struct earlycon_id *match)
{
int err;
- size_t len;
struct uart_port *port = &early_console_dev.port;
- if (!buf || !match || !setup)
- return 0;
-
- len = strlen(match);
- if (strncmp(buf, match, len))
- return 0;
- if (buf[len] && (buf[len] != ','))
- return 0;
-
- buf += len + 1;
-
- err = parse_options(&early_console_dev, buf);
/* On parsing error, pass the options buf to the setup function */
- if (!err)
+ if (buf && !parse_options(&early_console_dev, buf))
buf = NULL;
+ port->uartclk = BASE_BAUD * 16;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
early_console_dev.con->data = &early_console_dev;
- err = setup(&early_console_dev, buf);
+ err = match->setup(&early_console_dev, buf);
if (err < 0)
return err;
if (!early_console_dev.con->write)
@@ -148,6 +127,77 @@ int __init setup_earlycon(char *buf, const char *match,
return 0;
}
+/**
+ * setup_earlycon - match and register earlycon console
+ * @buf: earlycon param string
+ *
+ * Registers the earlycon console matching the earlycon specified
+ * in the param string @buf. Acceptable param strings are of the form
+ * <name>,io|mmio|mmio32,<addr>,<options>
+ * <name>,0x<addr>,<options>
+ * <name>,<options>
+ * <name>
+ *
+ * Only for the third form does the earlycon setup() method receive the
+ * <options> string in the 'options' parameter; all other forms set
+ * the parameter to NULL.
+ *
+ * Returns 0 if an attempt to register the earlycon was made,
+ * otherwise negative error code
+ */
+int __init setup_earlycon(char *buf)
+{
+ const struct earlycon_id *match;
+
+ if (!buf || !buf[0])
+ return -EINVAL;
+
+ if (early_con.flags & CON_ENABLED)
+ return -EALREADY;
+
+ for (match = __earlycon_table; match->name[0]; match++) {
+ size_t len = strlen(match->name);
+
+ if (strncmp(buf, match->name, len))
+ continue;
+
+ if (buf[len]) {
+ if (buf[len] != ',')
+ continue;
+ buf += len + 1;
+ } else
+ buf = NULL;
+
+ return register_earlycon(buf, match);
+ }
+
+ return -ENOENT;
+}
+
+/* early_param wrapper for setup_earlycon() */
+static int __init param_setup_earlycon(char *buf)
+{
+ int err;
+
+ /*
+ * Just 'earlycon' is a valid param for devicetree earlycons;
+ * don't generate a warning from parse_early_params() in that case
+ */
+ if (!buf || !buf[0])
+ return 0;
+
+ err = setup_earlycon(buf);
+ if (err == -ENOENT) {
+ pr_warn("no match for %s\n", buf);
+ err = 0;
+ } else if (err == -EALREADY) {
+ pr_warn("already registered\n");
+ err = 0;
+ }
+ return err;
+}
+early_param("earlycon", param_setup_earlycon);
+
int __init of_setup_earlycon(unsigned long addr,
int (*setup)(struct earlycon_device *, const char *))
{
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index b1893f3f88f1..08ce76f4f261 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -257,7 +257,7 @@ struct lpuart_port {
struct timer_list lpuart_timer;
};
-static struct of_device_id lpuart_dt_ids[] = {
+static const struct of_device_id lpuart_dt_ids[] = {
{
.compatible = "fsl,vf610-lpuart",
},
@@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
+ /* explicitly clear RDRF */
+ readb(sport->port.membase + UARTSR1);
+
/* flush Tx and Rx FIFO */
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
@@ -1076,6 +1079,8 @@ static int lpuart_startup(struct uart_port *port)
sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
+ sport->port.fifosize = sport->txfifo_size;
+
sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 0eb29b1c47ac..c8cfa0637128 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1,13 +1,10 @@
/*
- * Driver for Motorola IMX serial ports
+ * Driver for Motorola/Freescale IMX serial ports
*
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
- * Author: Sascha Hauer <sascha@saschahauer.de>
- * Copyright (C) 2004 Pengutronix
- *
- * Copyright (C) 2009 emlix GmbH
- * Author: Fabian Godehardt (added IrDA support for iMX)
+ * Author: Sascha Hauer <sascha@saschahauer.de>
+ * Copyright (C) 2004 Pengutronix
*
* 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
@@ -18,13 +15,6 @@
* 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * [29-Mar-2005] Mike Lee
- * Added hardware handshake
*/
#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -189,7 +179,7 @@
#define UART_NR 8
-/* i.mx21 type uart runs on all i.mx except i.mx1 */
+/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
enum imx_uart_type {
IMX1_UART,
IMX21_UART,
@@ -206,10 +196,8 @@ struct imx_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status;
- int txirq, rxirq, rtsirq;
unsigned int have_rtscts:1;
unsigned int dte_mode:1;
- unsigned int use_irda:1;
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short trcv_delay; /* transceiver delay */
@@ -236,12 +224,6 @@ struct imx_port_ucrs {
unsigned int ucr3;
};
-#ifdef CONFIG_IRDA
-#define USE_IRDA(sport) ((sport)->use_irda)
-#else
-#define USE_IRDA(sport) (0)
-#endif
-
static struct imx_uart_data imx_uart_devdata[] = {
[IMX1_UART] = {
.uts_reg = IMX1_UTS,
@@ -273,7 +255,7 @@ static struct platform_device_id imx_uart_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
-static struct of_device_id imx_uart_dt_ids[] = {
+static const struct of_device_id imx_uart_dt_ids[] = {
{ .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
@@ -376,48 +358,6 @@ static void imx_stop_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- if (USE_IRDA(sport)) {
- /* half duplex - wait for end of transmission */
- int n = 256;
- while ((--n > 0) &&
- !(readl(sport->port.membase + USR2) & USR2_TXDC)) {
- udelay(5);
- barrier();
- }
- /*
- * irda transceiver - wait a bit more to avoid
- * cutoff, hardware dependent
- */
- udelay(sport->trcv_delay);
-
- /*
- * half duplex - reactivate receive mode,
- * flush receive pipe echo crap
- */
- if (readl(sport->port.membase + USR2) & USR2_TXDC) {
- temp = readl(sport->port.membase + UCR1);
- temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
- writel(temp, sport->port.membase + UCR1);
-
- temp = readl(sport->port.membase + UCR4);
- temp &= ~(UCR4_TCEN);
- writel(temp, sport->port.membase + UCR4);
-
- while (readl(sport->port.membase + URXD0) &
- URXD_CHARRDY)
- barrier();
-
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_RRDYEN;
- writel(temp, sport->port.membase + UCR1);
-
- temp = readl(sport->port.membase + UCR4);
- temp |= UCR4_DREN;
- writel(temp, sport->port.membase + UCR4);
- }
- return;
- }
-
/*
* We are maybe in the SMP context, so if the DMA TX thread is running
* on other cpu, we have to wait for it to finish.
@@ -425,8 +365,23 @@ static void imx_stop_tx(struct uart_port *port)
if (sport->dma_is_enabled && sport->dma_is_txing)
return;
- temp = readl(sport->port.membase + UCR1);
- writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
+ temp = readl(port->membase + UCR1);
+ writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1);
+
+ /* in rs485 mode disable transmitter if shifter is empty */
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ readl(port->membase + USR2) & USR2_TXDC) {
+ temp = readl(port->membase + UCR2);
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ temp &= ~UCR2_CTS;
+ else
+ temp |= UCR2_CTS;
+ writel(temp, port->membase + UCR2);
+
+ temp = readl(port->membase + UCR4);
+ temp &= ~UCR4_TCEN;
+ writel(temp, port->membase + UCR4);
+ }
}
/*
@@ -620,15 +575,18 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- if (USE_IRDA(sport)) {
- /* half duplex in IrDA mode; have to disable receive mode */
- temp = readl(sport->port.membase + UCR4);
- temp &= ~(UCR4_DREN);
- writel(temp, sport->port.membase + UCR4);
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ /* enable transmitter and shifter empty irq */
+ temp = readl(port->membase + UCR2);
+ if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
+ temp &= ~UCR2_CTS;
+ else
+ temp |= UCR2_CTS;
+ writel(temp, port->membase + UCR2);
- temp = readl(sport->port.membase + UCR1);
- temp &= ~(UCR1_RRDYEN);
- writel(temp, sport->port.membase + UCR1);
+ temp = readl(port->membase + UCR4);
+ temp |= UCR4_TCEN;
+ writel(temp, port->membase + UCR4);
}
if (!sport->dma_is_enabled) {
@@ -636,16 +594,6 @@ static void imx_start_tx(struct uart_port *port)
writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
}
- if (USE_IRDA(sport)) {
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_TRDYEN;
- writel(temp, sport->port.membase + UCR1);
-
- temp = readl(sport->port.membase + UCR4);
- temp |= UCR4_TCEN;
- writel(temp, sport->port.membase + UCR4);
- }
-
if (sport->dma_is_enabled) {
if (sport->port.x_char) {
/* We have X-char to send, so enable TX IRQ and
@@ -796,6 +744,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
unsigned int sts2;
sts = readl(sport->port.membase + USR1);
+ sts2 = readl(sport->port.membase + USR2);
if (sts & USR1_RRDY) {
if (sport->dma_is_enabled)
@@ -804,8 +753,10 @@ static irqreturn_t imx_int(int irq, void *dev_id)
imx_rxint(irq, dev_id);
}
- if (sts & USR1_TRDY &&
- readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+ if ((sts & USR1_TRDY &&
+ readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
+ (sts2 & USR2_TXDC &&
+ readl(sport->port.membase + UCR4) & UCR4_TCEN))
imx_txint(irq, dev_id);
if (sts & USR1_RTSD)
@@ -814,11 +765,10 @@ static irqreturn_t imx_int(int irq, void *dev_id)
if (sts & USR1_AWAKE)
writel(USR1_AWAKE, sport->port.membase + USR1);
- sts2 = readl(sport->port.membase + USR2);
if (sts2 & USR2_ORE) {
dev_err(sport->port.dev, "Rx FIFO overrun\n");
sport->port.icount.overrun++;
- writel(sts2 | USR2_ORE, sport->port.membase + USR2);
+ writel(USR2_ORE, sport->port.membase + USR2);
}
return IRQ_HANDLED;
@@ -866,11 +816,13 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC);
- if (mctrl & TIOCM_RTS)
- temp |= UCR2_CTS | UCR2_CTSC;
-
- writel(temp, sport->port.membase + UCR2);
+ if (!(port->rs485.flags & SER_RS485_ENABLED)) {
+ temp = readl(sport->port.membase + UCR2);
+ temp &= ~(UCR2_CTS | UCR2_CTSC);
+ if (mctrl & TIOCM_RTS)
+ temp |= UCR2_CTS | UCR2_CTSC;
+ writel(temp, sport->port.membase + UCR2);
+ }
temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
if (mctrl & TIOCM_LOOP)
@@ -1156,9 +1108,6 @@ static int imx_startup(struct uart_port *port)
*/
temp = readl(sport->port.membase + UCR4);
- if (USE_IRDA(sport))
- temp |= UCR4_IRSC;
-
/* set the trigger level for CTS */
temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF);
temp |= CTSTL << UCR4_CTSTL_SHF;
@@ -1181,10 +1130,12 @@ static int imx_startup(struct uart_port *port)
imx_uart_dma_init(sport);
spin_lock_irqsave(&sport->port.lock, flags);
+
/*
* Finally, clear and enable interrupts
*/
writel(USR1_RTSD, sport->port.membase + USR1);
+ writel(USR2_ORE, sport->port.membase + USR2);
if (sport->dma_is_inited && !sport->dma_is_enabled)
imx_enable_dma(sport);
@@ -1192,17 +1143,8 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
- if (USE_IRDA(sport)) {
- temp |= UCR1_IREN;
- temp &= ~(UCR1_RTSDEN);
- }
-
writel(temp, sport->port.membase + UCR1);
- /* Clear any pending ORE flag before enabling interrupt */
- temp = readl(sport->port.membase + USR2);
- writel(temp | USR2_ORE, sport->port.membase + USR2);
-
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_OREN;
writel(temp, sport->port.membase + UCR4);
@@ -1219,38 +1161,12 @@ static int imx_startup(struct uart_port *port)
writel(temp, sport->port.membase + UCR3);
}
- if (USE_IRDA(sport)) {
- temp = readl(sport->port.membase + UCR4);
- if (sport->irda_inv_rx)
- temp |= UCR4_INVR;
- else
- temp &= ~(UCR4_INVR);
- writel(temp | UCR4_DREN, sport->port.membase + UCR4);
-
- temp = readl(sport->port.membase + UCR3);
- if (sport->irda_inv_tx)
- temp |= UCR3_INVT;
- else
- temp &= ~(UCR3_INVT);
- writel(temp, sport->port.membase + UCR3);
- }
-
/*
* Enable modem status interrupts
*/
imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags);
- if (USE_IRDA(sport)) {
- struct imxuart_platform_data *pdata;
- pdata = dev_get_platdata(sport->port.dev);
- sport->irda_inv_rx = pdata->irda_inv_rx;
- sport->irda_inv_tx = pdata->irda_inv_tx;
- sport->trcv_delay = pdata->transceiver_delay;
- if (pdata->irda_enable)
- pdata->irda_enable(1);
- }
-
return 0;
}
@@ -1286,13 +1202,6 @@ static void imx_shutdown(struct uart_port *port)
writel(temp, sport->port.membase + UCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
- if (USE_IRDA(sport)) {
- struct imxuart_platform_data *pdata;
- pdata = dev_get_platdata(sport->port.dev);
- if (pdata->irda_enable)
- pdata->irda_enable(0);
- }
-
/*
* Stop our timer.
*/
@@ -1305,8 +1214,6 @@ static void imx_shutdown(struct uart_port *port)
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
- if (USE_IRDA(sport))
- temp &= ~(UCR1_IREN);
writel(temp, sport->port.membase + UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1320,7 +1227,7 @@ static void imx_flush_buffer(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
struct scatterlist *sgl = &sport->tx_sgl[0];
unsigned long temp;
- int i = 100, ubir, ubmr, ubrc, uts;
+ int i = 100, ubir, ubmr, uts;
if (!sport->dma_chan_tx)
return;
@@ -1345,7 +1252,6 @@ static void imx_flush_buffer(struct uart_port *port)
*/
ubir = readl(sport->port.membase + UBIR);
ubmr = readl(sport->port.membase + UBMR);
- ubrc = readl(sport->port.membase + UBRC);
uts = readl(sport->port.membase + IMX21_UTS);
temp = readl(sport->port.membase + UCR2);
@@ -1358,7 +1264,6 @@ static void imx_flush_buffer(struct uart_port *port)
/* Restore the registers */
writel(ubir, sport->port.membase + UBIR);
writel(ubmr, sport->port.membase + UBMR);
- writel(ubrc, sport->port.membase + UBRC);
writel(uts, sport->port.membase + IMX21_UTS);
}
@@ -1375,15 +1280,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
uint64_t tdiv64;
/*
- * If we don't support modem control lines, don't allow
- * these to be set.
- */
- if (0) {
- termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
- termios->c_cflag |= CLOCAL;
- }
-
- /*
* We only support CS7 and CS8.
*/
while ((termios->c_cflag & CSIZE) != CS7 &&
@@ -1401,11 +1297,26 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CRTSCTS) {
if (sport->have_rtscts) {
ucr2 &= ~UCR2_IRTS;
- ucr2 |= UCR2_CTSC;
+
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ /*
+ * RTS is mandatory for rs485 operation, so keep
+ * it under manual control and keep transmitter
+ * disabled.
+ */
+ if (!(port->rs485.flags &
+ SER_RS485_RTS_AFTER_SEND))
+ ucr2 |= UCR2_CTS;
+ } else {
+ ucr2 |= UCR2_CTSC;
+ }
} else {
termios->c_cflag &= ~CRTSCTS;
}
- }
+ } else if (port->rs485.flags & SER_RS485_ENABLED)
+ /* disable transmitter */
+ if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
+ ucr2 |= UCR2_CTS;
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
@@ -1471,24 +1382,16 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.membase + UCR2);
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
- if (USE_IRDA(sport)) {
- /*
- * use maximum available submodule frequency to
- * avoid missing short pulses due to low sampling rate
- */
+ /* custom-baudrate handling */
+ div = sport->port.uartclk / (baud * 16);
+ if (baud == 38400 && quot != div)
+ baud = sport->port.uartclk / (quot * 16);
+
+ div = sport->port.uartclk / (baud * 16);
+ if (div > 7)
+ div = 7;
+ if (!div)
div = 1;
- } else {
- /* custom-baudrate handling */
- div = sport->port.uartclk / (baud * 16);
- if (baud == 38400 && quot != div)
- baud = sport->port.uartclk / (quot * 16);
-
- div = sport->port.uartclk / (baud * 16);
- if (div > 7)
- div = 7;
- if (!div)
- div = 1;
- }
rational_best_approximation(16 * div * baud, sport->port.uartclk,
1 << 16, 1 << 16, &num, &denom);
@@ -1635,6 +1538,38 @@ static void imx_poll_put_char(struct uart_port *port, unsigned char c)
}
#endif
+static int imx_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485conf)
+{
+ struct imx_port *sport = (struct imx_port *)port;
+
+ /* unimplemented */
+ rs485conf->delay_rts_before_send = 0;
+ rs485conf->delay_rts_after_send = 0;
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+ /* RTS is required to control the transmitter */
+ if (!sport->have_rtscts)
+ rs485conf->flags &= ~SER_RS485_ENABLED;
+
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+ unsigned long temp;
+
+ /* disable transmitter */
+ temp = readl(sport->port.membase + UCR2);
+ temp &= ~UCR2_CTSC;
+ if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+ temp &= ~UCR2_CTS;
+ else
+ temp |= UCR2_CTS;
+ writel(temp, sport->port.membase + UCR2);
+ }
+
+ port->rs485 = *rs485conf;
+
+ return 0;
+}
+
static struct uart_ops imx_pops = {
.tx_empty = imx_tx_empty,
.set_mctrl = imx_set_mctrl,
@@ -1927,9 +1862,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,
if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
sport->have_rtscts = 1;
- if (of_get_property(np, "fsl,irda-mode", NULL))
- sport->use_irda = 1;
-
if (of_get_property(np, "fsl,dte-mode", NULL))
sport->dte_mode = 1;
@@ -1958,9 +1890,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport,
if (pdata->flags & IMXUART_HAVE_RTSCTS)
sport->have_rtscts = 1;
-
- if (pdata->flags & IMXUART_IRDA)
- sport->use_irda = 1;
}
static int serial_imx_probe(struct platform_device *pdev)
@@ -1969,6 +1898,7 @@ static int serial_imx_probe(struct platform_device *pdev)
void __iomem *base;
int ret = 0;
struct resource *res;
+ int txirq, rxirq, rtsirq;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
@@ -1985,17 +1915,21 @@ static int serial_imx_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
+ rxirq = platform_get_irq(pdev, 0);
+ txirq = platform_get_irq(pdev, 1);
+ rtsirq = platform_get_irq(pdev, 2);
+
sport->port.dev = &pdev->dev;
sport->port.mapbase = res->start;
sport->port.membase = base;
sport->port.type = PORT_IMX,
sport->port.iotype = UPIO_MEM;
- sport->port.irq = platform_get_irq(pdev, 0);
- sport->rxirq = platform_get_irq(pdev, 0);
- sport->txirq = platform_get_irq(pdev, 1);
- sport->rtsirq = platform_get_irq(pdev, 2);
+ sport->port.irq = rxirq;
sport->port.fifosize = 32;
sport->port.ops = &imx_pops;
+ sport->port.rs485_config = imx_rs485_config;
+ sport->port.rs485.flags =
+ SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX;
sport->port.flags = UPF_BOOT_AUTOCONF;
init_timer(&sport->timer);
sport->timer.function = imx_timeout;
@@ -2021,27 +1955,18 @@ static int serial_imx_probe(struct platform_device *pdev)
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt.
*/
- if (sport->txirq > 0) {
- ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0,
+ if (txirq > 0) {
+ ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
dev_name(&pdev->dev), sport);
if (ret)
return ret;
- ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0,
+ ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
dev_name(&pdev->dev), sport);
if (ret)
return ret;
-
- /* do not use RTS IRQ on IrDA */
- if (!USE_IRDA(sport)) {
- ret = devm_request_irq(&pdev->dev, sport->rtsirq,
- imx_rtsint, 0,
- dev_name(&pdev->dev), sport);
- if (ret)
- return ret;
- }
} else {
- ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0,
+ ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
dev_name(&pdev->dev), sport);
if (ret)
return ret;
diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c
index bfb0681195b6..4eb12a9cae76 100644
--- a/drivers/tty/serial/jsm/jsm_cls.c
+++ b/drivers/tty/serial/jsm/jsm_cls.c
@@ -570,7 +570,7 @@ static inline void cls_parse_isr(struct jsm_board *brd, uint port)
* verified in the interrupt routine.
*/
- if (port > brd->nasync)
+ if (port >= brd->nasync)
return;
ch = brd->channels[port];
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 7291c2117daa..932b2accd06f 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -724,7 +724,7 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port)
if (!brd)
return;
- if (port > brd->maxports)
+ if (port >= brd->maxports)
return;
ch = brd->channels[port];
@@ -840,7 +840,7 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
if (!brd)
return;
- if (port > brd->maxports)
+ if (port >= brd->maxports)
return;
ch = brd->channels[port];
@@ -1180,7 +1180,7 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
*/
/* Verify the port is in range. */
- if (port > brd->nasync)
+ if (port >= brd->nasync)
continue;
ch = brd->channels[port];
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 79f9a9eff545..077377259a2c 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -782,7 +782,7 @@ static int max3100_probe(struct spi_device *spi)
pdata = dev_get_platdata(&spi->dev);
max3100s[i]->crystal = pdata->crystal;
max3100s[i]->loopback = pdata->loopback;
- max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
+ max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time);
if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
max3100s[i]->poll_time = 1;
max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
deleted file mode 100644
index 8fe4501d7565..000000000000
--- a/drivers/tty/serial/mfd.c
+++ /dev/null
@@ -1,1505 +0,0 @@
-/*
- * mfd.c: driver for High Speed UART device of Intel Medfield platform
- *
- * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
- *
- * (C) Copyright 2010 Intel Corporation
- *
- * 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; version 2
- * of the License.
- */
-
-/* Notes:
- * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
- * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
- * are used for RX, odd chans for TX
- *
- * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
- * asserted, only when the HW is reset the DDCD and DDSR will
- * be triggered
- */
-
-#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/slab.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_mfd.h>
-#include <linux/dma-mapping.h>
-#include <linux/pci.h>
-#include <linux/nmi.h>
-#include <linux/io.h>
-#include <linux/debugfs.h>
-#include <linux/pm_runtime.h>
-
-#define HSU_DMA_BUF_SIZE 2048
-
-#define chan_readl(chan, offset) readl(chan->reg + offset)
-#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
-
-#define mfd_readl(obj, offset) readl(obj->reg + offset)
-#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
-
-static int hsu_dma_enable;
-module_param(hsu_dma_enable, int, 0);
-MODULE_PARM_DESC(hsu_dma_enable,
- "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
-
-struct hsu_dma_buffer {
- u8 *buf;
- dma_addr_t dma_addr;
- u32 dma_size;
- u32 ofs;
-};
-
-struct hsu_dma_chan {
- u32 id;
- enum dma_data_direction dirt;
- struct uart_hsu_port *uport;
- void __iomem *reg;
-};
-
-struct uart_hsu_port {
- struct uart_port port;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned int lsr_break_flag;
- char name[12];
- int index;
- struct device *dev;
-
- struct hsu_dma_chan *txc;
- struct hsu_dma_chan *rxc;
- struct hsu_dma_buffer txbuf;
- struct hsu_dma_buffer rxbuf;
- int use_dma; /* flag for DMA/PIO */
- int running;
- int dma_tx_on;
-};
-
-/* Top level data structure of HSU */
-struct hsu_port {
- void __iomem *reg;
- unsigned long paddr;
- unsigned long iolen;
- u32 irq;
-
- struct uart_hsu_port port[3];
- struct hsu_dma_chan chans[10];
-
- struct dentry *debugfs;
-};
-
-static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
-{
- unsigned int val;
-
- if (offset > UART_MSR) {
- offset <<= 2;
- val = readl(up->port.membase + offset);
- } else
- val = (unsigned int)readb(up->port.membase + offset);
-
- return val;
-}
-
-static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
-{
- if (offset > UART_MSR) {
- offset <<= 2;
- writel(value, up->port.membase + offset);
- } else {
- unsigned char val = value & 0xff;
- writeb(val, up->port.membase + offset);
- }
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#define HSU_REGS_BUFSIZE 1024
-
-
-static ssize_t port_show_regs(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct uart_hsu_port *up = file->private_data;
- char *buf;
- u32 len = 0;
- ssize_t ret;
-
- buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
- if (!buf)
- return 0;
-
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MFD HSU port[%d] regs:\n", up->index);
-
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "=================================\n");
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
-
- if (len > HSU_REGS_BUFSIZE)
- len = HSU_REGS_BUFSIZE;
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- kfree(buf);
- return ret;
-}
-
-static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct hsu_dma_chan *chan = file->private_data;
- char *buf;
- u32 len = 0;
- ssize_t ret;
-
- buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
- if (!buf)
- return 0;
-
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MFD HSU DMA channel [%d] regs:\n", chan->id);
-
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "=================================\n");
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
-
- if (len > HSU_REGS_BUFSIZE)
- len = HSU_REGS_BUFSIZE;
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- kfree(buf);
- return ret;
-}
-
-static const struct file_operations port_regs_ops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = port_show_regs,
- .llseek = default_llseek,
-};
-
-static const struct file_operations dma_regs_ops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = dma_show_regs,
- .llseek = default_llseek,
-};
-
-static int hsu_debugfs_init(struct hsu_port *hsu)
-{
- int i;
- char name[32];
-
- hsu->debugfs = debugfs_create_dir("hsu", NULL);
- if (!hsu->debugfs)
- return -ENOMEM;
-
- for (i = 0; i < 3; i++) {
- snprintf(name, sizeof(name), "port_%d_regs", i);
- debugfs_create_file(name, S_IFREG | S_IRUGO,
- hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
- }
-
- for (i = 0; i < 6; i++) {
- snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
- debugfs_create_file(name, S_IFREG | S_IRUGO,
- hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
- }
-
- return 0;
-}
-
-static void hsu_debugfs_remove(struct hsu_port *hsu)
-{
- if (hsu->debugfs)
- debugfs_remove_recursive(hsu->debugfs);
-}
-
-#else
-static inline int hsu_debugfs_init(struct hsu_port *hsu)
-{
- return 0;
-}
-
-static inline void hsu_debugfs_remove(struct hsu_port *hsu)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void serial_hsu_enable_ms(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
-
- up->ier |= UART_IER_MSI;
- serial_out(up, UART_IER, up->ier);
-}
-
-static void hsu_dma_tx(struct uart_hsu_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- struct hsu_dma_buffer *dbuf = &up->txbuf;
- int count;
-
- /* test_and_set_bit may be better, but anyway it's in lock protected mode */
- if (up->dma_tx_on)
- return;
-
- /* Update the circ buf info */
- xmit->tail += dbuf->ofs;
- xmit->tail &= UART_XMIT_SIZE - 1;
-
- up->port.icount.tx += dbuf->ofs;
- dbuf->ofs = 0;
-
- /* Disable the channel */
- chan_writel(up->txc, HSU_CH_CR, 0x0);
-
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
- dma_sync_single_for_device(up->port.dev,
- dbuf->dma_addr,
- dbuf->dma_size,
- DMA_TO_DEVICE);
-
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- dbuf->ofs = count;
-
- /* Reprogram the channel */
- chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
- chan_writel(up->txc, HSU_CH_D0TSR, count);
-
- /* Reenable the channel */
- chan_writel(up->txc, HSU_CH_DCR, 0x1
- | (0x1 << 8)
- | (0x1 << 16)
- | (0x1 << 24));
- up->dma_tx_on = 1;
- chan_writel(up->txc, HSU_CH_CR, 0x1);
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-}
-
-/* The buffer is already cache coherent */
-static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc,
- struct hsu_dma_buffer *dbuf)
-{
- dbuf->ofs = 0;
-
- chan_writel(rxc, HSU_CH_BSR, 32);
- chan_writel(rxc, HSU_CH_MOTSR, 4);
-
- chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
- chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
- chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
- | (0x1 << 16)
- | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
- );
- chan_writel(rxc, HSU_CH_CR, 0x3);
-}
-
-/* Protected by spin_lock_irqsave(port->lock) */
-static void serial_hsu_start_tx(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
-
- if (up->use_dma) {
- hsu_dma_tx(up);
- } else if (!(up->ier & UART_IER_THRI)) {
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static void serial_hsu_stop_tx(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- struct hsu_dma_chan *txc = up->txc;
-
- if (up->use_dma)
- chan_writel(txc, HSU_CH_CR, 0x0);
- else if (up->ier & UART_IER_THRI) {
- up->ier &= ~UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-/* This is always called in spinlock protected mode, so
- * modify timeout timer is safe here */
-static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts,
- unsigned long *flags)
-{
- struct hsu_dma_buffer *dbuf = &up->rxbuf;
- struct hsu_dma_chan *chan = up->rxc;
- struct uart_port *port = &up->port;
- struct tty_port *tport = &port->state->port;
- int count;
-
- /*
- * First need to know how many is already transferred,
- * then check if its a timeout DMA irq, and return
- * the trail bytes out, push them up and reenable the
- * channel
- */
-
- /* Timeout IRQ, need wait some time, see Errata 2 */
- if (int_sts & 0xf00)
- udelay(2);
-
- /* Stop the channel */
- chan_writel(chan, HSU_CH_CR, 0x0);
-
- count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
- if (!count) {
- /* Restart the channel before we leave */
- chan_writel(chan, HSU_CH_CR, 0x3);
- return;
- }
-
- dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
- dbuf->dma_size, DMA_FROM_DEVICE);
-
- /*
- * Head will only wrap around when we recycle
- * the DMA buffer, and when that happens, we
- * explicitly set tail to 0. So head will
- * always be greater than tail.
- */
- tty_insert_flip_string(tport, dbuf->buf, count);
- port->icount.rx += count;
-
- dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
- dbuf->dma_size, DMA_FROM_DEVICE);
-
- /* Reprogram the channel */
- chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
- chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
- chan_writel(chan, HSU_CH_DCR, 0x1
- | (0x1 << 8)
- | (0x1 << 16)
- | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
- );
- spin_unlock_irqrestore(&up->port.lock, *flags);
- tty_flip_buffer_push(tport);
- spin_lock_irqsave(&up->port.lock, *flags);
-
- chan_writel(chan, HSU_CH_CR, 0x3);
-
-}
-
-static void serial_hsu_stop_rx(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- struct hsu_dma_chan *chan = up->rxc;
-
- if (up->use_dma)
- chan_writel(chan, HSU_CH_CR, 0x2);
- else {
- up->ier &= ~UART_IER_RLSI;
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static inline void receive_chars(struct uart_hsu_port *up, int *status,
- unsigned long *flags)
-{
- unsigned int ch, flag;
- unsigned int max_count = 256;
-
- do {
- ch = serial_in(up, UART_RX);
- flag = TTY_NORMAL;
- up->port.icount.rx++;
-
- if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
-
- dev_warn(up->dev, "We really rush into ERR/BI case"
- "status = 0x%02x", *status);
- /* For statistics only */
- if (*status & UART_LSR_BI) {
- *status &= ~(UART_LSR_FE | UART_LSR_PE);
- up->port.icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(&up->port))
- goto ignore_char;
- } else if (*status & UART_LSR_PE)
- up->port.icount.parity++;
- else if (*status & UART_LSR_FE)
- up->port.icount.frame++;
- if (*status & UART_LSR_OE)
- up->port.icount.overrun++;
-
- /* Mask off conditions which should be ignored. */
- *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
- if (up->port.cons &&
- up->port.cons->index == up->port.line) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-#endif
- if (*status & UART_LSR_BI) {
- flag = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (*status & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(&up->port, ch))
- goto ignore_char;
-
- uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
- ignore_char:
- *status = serial_in(up, UART_LSR);
- } while ((*status & UART_LSR_DR) && max_count--);
-
- spin_unlock_irqrestore(&up->port.lock, *flags);
- tty_flip_buffer_push(&up->port.state->port);
- spin_lock_irqsave(&up->port.lock, *flags);
-}
-
-static void transmit_chars(struct uart_hsu_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- int count;
-
- if (up->port.x_char) {
- serial_out(up, UART_TX, up->port.x_char);
- up->port.icount.tx++;
- up->port.x_char = 0;
- return;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial_hsu_stop_tx(&up->port);
- return;
- }
-
- /* The IRQ is for TX FIFO half-empty */
- count = up->port.fifosize / 2;
-
- do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-
- up->port.icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- } while (--count > 0);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-
- if (uart_circ_empty(xmit))
- serial_hsu_stop_tx(&up->port);
-}
-
-static inline void check_modem_status(struct uart_hsu_port *up)
-{
- int status;
-
- status = serial_in(up, UART_MSR);
-
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- up->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
- /* We may only get DDCD when HW init and reset */
- if (status & UART_MSR_DDCD)
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
- /* Will start/stop_tx accordingly */
- if (status & UART_MSR_DCTS)
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
- wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static irqreturn_t port_irq(int irq, void *dev_id)
-{
- struct uart_hsu_port *up = dev_id;
- unsigned int iir, lsr;
- unsigned long flags;
-
- if (unlikely(!up->running))
- return IRQ_NONE;
-
- spin_lock_irqsave(&up->port.lock, flags);
- if (up->use_dma) {
- lsr = serial_in(up, UART_LSR);
- if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE)))
- dev_warn(up->dev,
- "Got lsr irq while using DMA, lsr = 0x%2x\n",
- lsr);
- check_modem_status(up);
- spin_unlock_irqrestore(&up->port.lock, flags);
- return IRQ_HANDLED;
- }
-
- iir = serial_in(up, UART_IIR);
- if (iir & UART_IIR_NO_INT) {
- spin_unlock_irqrestore(&up->port.lock, flags);
- return IRQ_NONE;
- }
-
- lsr = serial_in(up, UART_LSR);
- if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr, &flags);
- check_modem_status(up);
-
- /* lsr will be renewed during the receive_chars */
- if (lsr & UART_LSR_THRE)
- transmit_chars(up);
-
- spin_unlock_irqrestore(&up->port.lock, flags);
- return IRQ_HANDLED;
-}
-
-static inline void dma_chan_irq(struct hsu_dma_chan *chan)
-{
- struct uart_hsu_port *up = chan->uport;
- unsigned long flags;
- u32 int_sts;
-
- spin_lock_irqsave(&up->port.lock, flags);
-
- if (!up->use_dma || !up->running)
- goto exit;
-
- /*
- * No matter what situation, need read clear the IRQ status
- * There is a bug, see Errata 5, HSD 2900918
- */
- int_sts = chan_readl(chan, HSU_CH_SR);
-
- /* Rx channel */
- if (chan->dirt == DMA_FROM_DEVICE)
- hsu_dma_rx(up, int_sts, &flags);
-
- /* Tx channel */
- if (chan->dirt == DMA_TO_DEVICE) {
- chan_writel(chan, HSU_CH_CR, 0x0);
- up->dma_tx_on = 0;
- hsu_dma_tx(up);
- }
-
-exit:
- spin_unlock_irqrestore(&up->port.lock, flags);
- return;
-}
-
-static irqreturn_t dma_irq(int irq, void *dev_id)
-{
- struct hsu_port *hsu = dev_id;
- u32 int_sts, i;
-
- int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
-
- /* Currently we only have 6 channels may be used */
- for (i = 0; i < 6; i++) {
- if (int_sts & 0x1)
- dma_chan_irq(&hsu->chans[i]);
- int_sts >>= 1;
- }
-
- return IRQ_HANDLED;
-}
-
-static unsigned int serial_hsu_tx_empty(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- return ret;
-}
-
-static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned char status;
- unsigned int ret;
-
- status = serial_in(up, UART_MSR);
-
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned char mcr = 0;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- mcr |= up->mcr;
-
- serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned long flags;
-
- spin_lock_irqsave(&up->port.lock, flags);
- if (break_state == -1)
- up->lcr |= UART_LCR_SBC;
- else
- up->lcr &= ~UART_LCR_SBC;
- serial_out(up, UART_LCR, up->lcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-/*
- * What special to do:
- * 1. chose the 64B fifo mode
- * 2. start dma or pio depends on configuration
- * 3. we only allocate dma memory when needed
- */
-static int serial_hsu_startup(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned long flags;
-
- pm_runtime_get_sync(up->dev);
-
- /*
- * Clear the FIFO buffers and disable them.
- * (they will be reenabled in set_termios())
- */
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-
- /* Clear the interrupt registers. */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- /* Now, initialize the UART, default is 8n1 */
- serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
- spin_lock_irqsave(&up->port.lock, flags);
-
- up->port.mctrl |= TIOCM_OUT2;
- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
-
- /*
- * Finally, enable interrupts. Note: Modem status interrupts
- * are set via set_termios(), which will be occurring imminently
- * anyway, so we don't enable them here.
- */
- if (!up->use_dma)
- up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
- else
- up->ier = 0;
- serial_out(up, UART_IER, up->ier);
-
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /* DMA init */
- if (up->use_dma) {
- struct hsu_dma_buffer *dbuf;
- struct circ_buf *xmit = &port->state->xmit;
-
- up->dma_tx_on = 0;
-
- /* First allocate the RX buffer */
- dbuf = &up->rxbuf;
- dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
- if (!dbuf->buf) {
- up->use_dma = 0;
- goto exit;
- }
- dbuf->dma_addr = dma_map_single(port->dev,
- dbuf->buf,
- HSU_DMA_BUF_SIZE,
- DMA_FROM_DEVICE);
- dbuf->dma_size = HSU_DMA_BUF_SIZE;
-
- /* Start the RX channel right now */
- hsu_dma_start_rx_chan(up->rxc, dbuf);
-
- /* Next init the TX DMA */
- dbuf = &up->txbuf;
- dbuf->buf = xmit->buf;
- dbuf->dma_addr = dma_map_single(port->dev,
- dbuf->buf,
- UART_XMIT_SIZE,
- DMA_TO_DEVICE);
- dbuf->dma_size = UART_XMIT_SIZE;
-
- /* This should not be changed all around */
- chan_writel(up->txc, HSU_CH_BSR, 32);
- chan_writel(up->txc, HSU_CH_MOTSR, 4);
- dbuf->ofs = 0;
- }
-
-exit:
- /* And clear the interrupt registers again for luck. */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- up->running = 1;
- return 0;
-}
-
-static void serial_hsu_shutdown(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned long flags;
-
- /* Disable interrupts from this port */
- up->ier = 0;
- serial_out(up, UART_IER, 0);
- up->running = 0;
-
- spin_lock_irqsave(&up->port.lock, flags);
- up->port.mctrl &= ~TIOCM_OUT2;
- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /* Disable break condition and FIFOs */
- serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-
- pm_runtime_put(up->dev);
-}
-
-static void
-serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- unsigned char cval, fcr = 0;
- unsigned long flags;
- unsigned int baud, quot;
- u32 ps, mul;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = UART_LCR_WLEN5;
- break;
- case CS6:
- cval = UART_LCR_WLEN6;
- break;
- case CS7:
- cval = UART_LCR_WLEN7;
- break;
- default:
- case CS8:
- cval = UART_LCR_WLEN8;
- break;
- }
-
- /* CMSPAR isn't supported by this driver */
- termios->c_cflag &= ~CMSPAR;
-
- if (termios->c_cflag & CSTOPB)
- cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(termios->c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- /*
- * The base clk is 50Mhz, and the baud rate come from:
- * baud = 50M * MUL / (DIV * PS * DLAB)
- *
- * For those basic low baud rate we can get the direct
- * scalar from 2746800, like 115200 = 2746800/24. For those
- * higher baud rate, we handle them case by case, mainly by
- * adjusting the MUL/PS registers, and DIV register is kept
- * as default value 0x3d09 to make things simple
- */
- baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-
- quot = 1;
- ps = 0x10;
- mul = 0x3600;
- switch (baud) {
- case 3500000:
- mul = 0x3345;
- ps = 0xC;
- break;
- case 1843200:
- mul = 0x2400;
- break;
- case 3000000:
- case 2500000:
- case 2000000:
- case 1500000:
- case 1000000:
- case 500000:
- /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
- mul = baud / 500000 * 0x9C4;
- break;
- default:
- /* Use uart_get_divisor to get quot for other baud rates */
- quot = 0;
- }
-
- if (!quot)
- quot = uart_get_divisor(port, baud);
-
- if ((up->port.uartclk / quot) < (2400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
- else if ((up->port.uartclk / quot) < (230400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
-
- fcr |= UART_FCR_HSU_64B_FIFO;
-
- /*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
- */
- spin_lock_irqsave(&up->port.lock, flags);
-
- /* Update the per-port timeout */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (termios->c_iflag & INPCK)
- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- up->port.read_status_mask |= UART_LSR_BI;
-
- /* Characters to ignore */
- up->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (termios->c_iflag & IGNBRK) {
- up->port.ignore_status_mask |= UART_LSR_BI;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_OE;
- }
-
- /* Ignore all characters if CREAD is not set */
- if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= UART_LSR_DR;
-
- /*
- * CTS flow control flag and modem status interrupts, disable
- * MSI by default
- */
- up->ier &= ~UART_IER_MSI;
- if (UART_ENABLE_MS(&up->port, termios->c_cflag))
- up->ier |= UART_IER_MSI;
-
- serial_out(up, UART_IER, up->ier);
-
- if (termios->c_cflag & CRTSCTS)
- up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
- else
- up->mcr &= ~UART_MCR_AFE;
-
- serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
- serial_out(up, UART_LCR, cval); /* reset DLAB */
- serial_out(up, UART_MUL, mul); /* set MUL */
- serial_out(up, UART_PS, ps); /* set PS */
- up->lcr = cval; /* Save LCR */
- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
- serial_out(up, UART_FCR, fcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_hsu_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
-}
-
-static void serial_hsu_release_port(struct uart_port *port)
-{
-}
-
-static int serial_hsu_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void serial_hsu_config_port(struct uart_port *port, int flags)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- up->port.type = PORT_MFD;
-}
-
-static int
-serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- /* We don't want the core code to modify any port params */
- return -EINVAL;
-}
-
-static const char *
-serial_hsu_type(struct uart_port *port)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
- return up->name;
-}
-
-/* Mainly for uart console use */
-static struct uart_hsu_port *serial_hsu_ports[3];
-static struct uart_driver serial_hsu_reg;
-
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/* Wait for transmitter & holding register to empty */
-static inline void wait_for_xmitr(struct uart_hsu_port *up)
-{
- unsigned int status, tmout = 1000;
-
- /* Wait up to 1ms for the character to be sent. */
- do {
- status = serial_in(up, UART_LSR);
-
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while (!(status & BOTH_EMPTY));
-
- /* Wait up to 1s for flow control if necessary */
- if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (--tmout &&
- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
- udelay(1);
- }
-}
-
-static void serial_hsu_console_putchar(struct uart_port *port, int ch)
-{
- struct uart_hsu_port *up =
- container_of(port, struct uart_hsu_port, port);
-
- wait_for_xmitr(up);
- serial_out(up, UART_TX, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- */
-static void
-serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_hsu_port *up = serial_hsu_ports[co->index];
- unsigned long flags;
- unsigned int ier;
- int locked = 1;
-
- touch_nmi_watchdog();
-
- local_irq_save(flags);
- if (up->port.sysrq)
- locked = 0;
- else if (oops_in_progress) {
- locked = spin_trylock(&up->port.lock);
- } else
- spin_lock(&up->port.lock);
-
- /* First save the IER then disable the interrupts */
- ier = serial_in(up, UART_IER);
- serial_out(up, UART_IER, 0);
-
- uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore the IER
- */
- wait_for_xmitr(up);
- serial_out(up, UART_IER, ier);
-
- if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
-}
-
-static struct console serial_hsu_console;
-
-static int __init
-serial_hsu_console_setup(struct console *co, char *options)
-{
- struct uart_hsu_port *up;
- int baud = 115200;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (co->index == -1 || co->index >= serial_hsu_reg.nr)
- co->index = 0;
- up = serial_hsu_ports[co->index];
- if (!up)
- return -ENODEV;
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_hsu_console = {
- .name = "ttyMFD",
- .write = serial_hsu_console_write,
- .device = uart_console_device,
- .setup = serial_hsu_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &serial_hsu_reg,
-};
-
-#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
-#else
-#define SERIAL_HSU_CONSOLE NULL
-#endif
-
-static struct uart_ops serial_hsu_pops = {
- .tx_empty = serial_hsu_tx_empty,
- .set_mctrl = serial_hsu_set_mctrl,
- .get_mctrl = serial_hsu_get_mctrl,
- .stop_tx = serial_hsu_stop_tx,
- .start_tx = serial_hsu_start_tx,
- .stop_rx = serial_hsu_stop_rx,
- .enable_ms = serial_hsu_enable_ms,
- .break_ctl = serial_hsu_break_ctl,
- .startup = serial_hsu_startup,
- .shutdown = serial_hsu_shutdown,
- .set_termios = serial_hsu_set_termios,
- .pm = serial_hsu_pm,
- .type = serial_hsu_type,
- .release_port = serial_hsu_release_port,
- .request_port = serial_hsu_request_port,
- .config_port = serial_hsu_config_port,
- .verify_port = serial_hsu_verify_port,
-};
-
-static struct uart_driver serial_hsu_reg = {
- .owner = THIS_MODULE,
- .driver_name = "MFD serial",
- .dev_name = "ttyMFD",
- .major = TTY_MAJOR,
- .minor = 128,
- .nr = 3,
- .cons = SERIAL_HSU_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- void *priv = pci_get_drvdata(pdev);
- struct uart_hsu_port *up;
-
- /* Make sure this is not the internal dma controller */
- if (priv && (pdev->device != 0x081E)) {
- up = priv;
- uart_suspend_port(&serial_hsu_reg, &up->port);
- }
-
- pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return 0;
-}
-
-static int serial_hsu_resume(struct pci_dev *pdev)
-{
- void *priv = pci_get_drvdata(pdev);
- struct uart_hsu_port *up;
- int ret;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
- ret = pci_enable_device(pdev);
- if (ret)
- dev_warn(&pdev->dev,
- "HSU: can't re-enable device, try to continue\n");
-
- if (priv && (pdev->device != 0x081E)) {
- up = priv;
- uart_resume_port(&serial_hsu_reg, &up->port);
- }
- return 0;
-}
-
-static int serial_hsu_runtime_idle(struct device *dev)
-{
- pm_schedule_suspend(dev, 500);
- return -EBUSY;
-}
-
-static int serial_hsu_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int serial_hsu_runtime_resume(struct device *dev)
-{
- return 0;
-}
-#else
-#define serial_hsu_suspend NULL
-#define serial_hsu_resume NULL
-#define serial_hsu_runtime_idle NULL
-#define serial_hsu_runtime_suspend NULL
-#define serial_hsu_runtime_resume NULL
-#endif
-
-static const struct dev_pm_ops serial_hsu_pm_ops = {
- .runtime_suspend = serial_hsu_runtime_suspend,
- .runtime_resume = serial_hsu_runtime_resume,
- .runtime_idle = serial_hsu_runtime_idle,
-};
-
-/* temp global pointer before we settle down on using one or four PCI dev */
-static struct hsu_port *phsu;
-
-static int serial_hsu_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct uart_hsu_port *uport;
- int index, ret;
-
- printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
- pdev->vendor, pdev->device);
-
- switch (pdev->device) {
- case 0x081B:
- index = 0;
- break;
- case 0x081C:
- index = 1;
- break;
- case 0x081D:
- index = 2;
- break;
- case 0x081E:
- /* internal DMA controller */
- index = 3;
- break;
- default:
- dev_err(&pdev->dev, "HSU: out of index!");
- return -ENODEV;
- }
-
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
-
- if (index == 3) {
- /* DMA controller */
- ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
- if (ret) {
- dev_err(&pdev->dev, "can not get IRQ\n");
- goto err_disable;
- }
- pci_set_drvdata(pdev, phsu);
- } else {
- /* UART port 0~2 */
- uport = &phsu->port[index];
- uport->port.irq = pdev->irq;
- uport->port.dev = &pdev->dev;
- uport->dev = &pdev->dev;
-
- ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
- if (ret) {
- dev_err(&pdev->dev, "can not get IRQ\n");
- goto err_disable;
- }
- uart_add_one_port(&serial_hsu_reg, &uport->port);
-
- pci_set_drvdata(pdev, uport);
- }
-
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
-
- return 0;
-
-err_disable:
- pci_disable_device(pdev);
- return ret;
-}
-
-static void hsu_global_init(void)
-{
- struct hsu_port *hsu;
- struct uart_hsu_port *uport;
- struct hsu_dma_chan *dchan;
- int i, ret;
-
- hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
- if (!hsu)
- return;
-
- /* Get basic io resource and map it */
- hsu->paddr = 0xffa28000;
- hsu->iolen = 0x1000;
-
- if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
- pr_warn("HSU: error in request mem region\n");
-
- hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
- if (!hsu->reg) {
- pr_err("HSU: error in ioremap\n");
- ret = -ENOMEM;
- goto err_free_region;
- }
-
- /* Initialise the 3 UART ports */
- uport = hsu->port;
- for (i = 0; i < 3; i++) {
- uport->port.type = PORT_MFD;
- uport->port.iotype = UPIO_MEM;
- uport->port.mapbase = (resource_size_t)hsu->paddr
- + HSU_PORT_REG_OFFSET
- + i * HSU_PORT_REG_LENGTH;
- uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
- + i * HSU_PORT_REG_LENGTH;
-
- sprintf(uport->name, "hsu_port%d", i);
- uport->port.fifosize = 64;
- uport->port.ops = &serial_hsu_pops;
- uport->port.line = i;
- uport->port.flags = UPF_IOREMAP;
- /* set the scalable maxim support rate to 2746800 bps */
- uport->port.uartclk = 115200 * 24 * 16;
-
- uport->running = 0;
- uport->txc = &hsu->chans[i * 2];
- uport->rxc = &hsu->chans[i * 2 + 1];
-
- serial_hsu_ports[i] = uport;
- uport->index = i;
-
- if (hsu_dma_enable & (1<<i))
- uport->use_dma = 1;
- else
- uport->use_dma = 0;
-
- uport++;
- }
-
- /* Initialise 6 dma channels */
- dchan = hsu->chans;
- for (i = 0; i < 6; i++) {
- dchan->id = i;
- dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- dchan->uport = &hsu->port[i/2];
- dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
- i * HSU_DMA_CHANS_REG_LENGTH;
-
- dchan++;
- }
-
- phsu = hsu;
- hsu_debugfs_init(hsu);
- return;
-
-err_free_region:
- release_mem_region(hsu->paddr, hsu->iolen);
- kfree(hsu);
- return;
-}
-
-static void serial_hsu_remove(struct pci_dev *pdev)
-{
- void *priv = pci_get_drvdata(pdev);
- struct uart_hsu_port *up;
-
- if (!priv)
- return;
-
- pm_runtime_forbid(&pdev->dev);
- pm_runtime_get_noresume(&pdev->dev);
-
- /* For port 0/1/2, priv is the address of uart_hsu_port */
- if (pdev->device != 0x081E) {
- up = priv;
- uart_remove_one_port(&serial_hsu_reg, &up->port);
- }
-
- free_irq(pdev->irq, priv);
- pci_disable_device(pdev);
-}
-
-/* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
- {},
-};
-
-static struct pci_driver hsu_pci_driver = {
- .name = "HSU serial",
- .id_table = pci_ids,
- .probe = serial_hsu_probe,
- .remove = serial_hsu_remove,
- .suspend = serial_hsu_suspend,
- .resume = serial_hsu_resume,
- .driver = {
- .pm = &serial_hsu_pm_ops,
- },
-};
-
-static int __init hsu_pci_init(void)
-{
- int ret;
-
- hsu_global_init();
-
- ret = uart_register_driver(&serial_hsu_reg);
- if (ret)
- return ret;
-
- return pci_register_driver(&hsu_pci_driver);
-}
-
-static void __exit hsu_pci_exit(void)
-{
- pci_unregister_driver(&hsu_pci_driver);
- uart_unregister_driver(&serial_hsu_reg);
-
- hsu_debugfs_remove(phsu);
-
- kfree(phsu);
-}
-
-module_init(hsu_pci_init);
-module_exit(hsu_pci_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(pci, pci_ids);
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 3308ef243dc3..1589f17c1fca 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1717,7 +1717,7 @@ static struct uart_driver mpc52xx_uart_driver = {
/* OF Platform Driver */
/* ======================================================================== */
-static struct of_device_id mpc52xx_uart_of_match[] = {
+static const struct of_device_id mpc52xx_uart_of_match[] = {
#ifdef CONFIG_PPC_MPC52xx
{ .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index 3e1c7138d8cd..737f69fe7113 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -170,15 +170,6 @@ void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
msm_serial_set_mnd_regs_tcxoby4(port);
}
-/*
- * TROUT has a specific defect that makes it report it's uartclk
- * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
- * cases TROUT to use the right clock.
- */
-#ifdef CONFIG_MACH_TROUT
-#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
-#else
#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
-#endif
#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
deleted file mode 100644
index 62da8534ba75..000000000000
--- a/drivers/tty/serial/msm_serial_hs.c
+++ /dev/null
@@ -1,1874 +0,0 @@
-/*
- * MSM 7k/8k High speed uart driver
- *
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
- * Copyright (c) 2008 Google Inc.
- * Modified: Nick Pelly <npelly@google.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.
- *
- * 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.
- *
- * Has optional support for uart power management independent of linux
- * suspend/resume:
- *
- * RX wakeup.
- * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the
- * UART RX pin). This should only be used if there is not a wakeup
- * GPIO on the UART CTS, and the first RX byte is known (for example, with the
- * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will
- * always be lost. RTS will be asserted even while the UART is off in this mode
- * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq.
- */
-
-#include <linux/module.h>
-
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-#include <linux/atomic.h>
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <linux/platform_data/msm_serial_hs.h>
-
-/* HSUART Registers */
-#define UARTDM_MR1_ADDR 0x0
-#define UARTDM_MR2_ADDR 0x4
-
-/* Data Mover result codes */
-#define RSLT_FIFO_CNTR_BMSK (0xE << 28)
-#define RSLT_VLD BIT(1)
-
-/* write only register */
-#define UARTDM_CSR_ADDR 0x8
-#define UARTDM_CSR_115200 0xFF
-#define UARTDM_CSR_57600 0xEE
-#define UARTDM_CSR_38400 0xDD
-#define UARTDM_CSR_28800 0xCC
-#define UARTDM_CSR_19200 0xBB
-#define UARTDM_CSR_14400 0xAA
-#define UARTDM_CSR_9600 0x99
-#define UARTDM_CSR_7200 0x88
-#define UARTDM_CSR_4800 0x77
-#define UARTDM_CSR_3600 0x66
-#define UARTDM_CSR_2400 0x55
-#define UARTDM_CSR_1200 0x44
-#define UARTDM_CSR_600 0x33
-#define UARTDM_CSR_300 0x22
-#define UARTDM_CSR_150 0x11
-#define UARTDM_CSR_75 0x00
-
-/* write only register */
-#define UARTDM_TF_ADDR 0x70
-#define UARTDM_TF2_ADDR 0x74
-#define UARTDM_TF3_ADDR 0x78
-#define UARTDM_TF4_ADDR 0x7C
-
-/* write only register */
-#define UARTDM_CR_ADDR 0x10
-#define UARTDM_IMR_ADDR 0x14
-
-#define UARTDM_IPR_ADDR 0x18
-#define UARTDM_TFWR_ADDR 0x1c
-#define UARTDM_RFWR_ADDR 0x20
-#define UARTDM_HCR_ADDR 0x24
-#define UARTDM_DMRX_ADDR 0x34
-#define UARTDM_IRDA_ADDR 0x38
-#define UARTDM_DMEN_ADDR 0x3c
-
-/* UART_DM_NO_CHARS_FOR_TX */
-#define UARTDM_NCF_TX_ADDR 0x40
-
-#define UARTDM_BADR_ADDR 0x44
-
-#define UARTDM_SIM_CFG_ADDR 0x80
-/* Read Only register */
-#define UARTDM_SR_ADDR 0x8
-
-/* Read Only register */
-#define UARTDM_RF_ADDR 0x70
-#define UARTDM_RF2_ADDR 0x74
-#define UARTDM_RF3_ADDR 0x78
-#define UARTDM_RF4_ADDR 0x7C
-
-/* Read Only register */
-#define UARTDM_MISR_ADDR 0x10
-
-/* Read Only register */
-#define UARTDM_ISR_ADDR 0x14
-#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
-
-#define UARTDM_RXFS_ADDR 0x50
-
-/* Register field Mask Mapping */
-#define UARTDM_SR_PAR_FRAME_BMSK BIT(5)
-#define UARTDM_SR_OVERRUN_BMSK BIT(4)
-#define UARTDM_SR_TXEMT_BMSK BIT(3)
-#define UARTDM_SR_TXRDY_BMSK BIT(2)
-#define UARTDM_SR_RXRDY_BMSK BIT(0)
-
-#define UARTDM_CR_TX_DISABLE_BMSK BIT(3)
-#define UARTDM_CR_RX_DISABLE_BMSK BIT(1)
-#define UARTDM_CR_TX_EN_BMSK BIT(2)
-#define UARTDM_CR_RX_EN_BMSK BIT(0)
-
-/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */
-#define RESET_RX 0x10
-#define RESET_TX 0x20
-#define RESET_ERROR_STATUS 0x30
-#define RESET_BREAK_INT 0x40
-#define START_BREAK 0x50
-#define STOP_BREAK 0x60
-#define RESET_CTS 0x70
-#define RESET_STALE_INT 0x80
-#define RFR_LOW 0xD0
-#define RFR_HIGH 0xE0
-#define CR_PROTECTION_EN 0x100
-#define STALE_EVENT_ENABLE 0x500
-#define STALE_EVENT_DISABLE 0x600
-#define FORCE_STALE_EVENT 0x400
-#define CLEAR_TX_READY 0x300
-#define RESET_TX_ERROR 0x800
-#define RESET_TX_DONE 0x810
-
-#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00
-#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f
-#define UARTDM_MR1_CTS_CTL_BMSK 0x40
-#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
-
-#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
-#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
-
-/* bits per character configuration */
-#define FIVE_BPC (0 << 4)
-#define SIX_BPC (1 << 4)
-#define SEVEN_BPC (2 << 4)
-#define EIGHT_BPC (3 << 4)
-
-#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc
-#define STOP_BIT_ONE (1 << 2)
-#define STOP_BIT_TWO (3 << 2)
-
-#define UARTDM_MR2_PARITY_MODE_BMSK 0x3
-
-/* Parity configuration */
-#define NO_PARITY 0x0
-#define EVEN_PARITY 0x1
-#define ODD_PARITY 0x2
-#define SPACE_PARITY 0x3
-
-#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80
-#define UARTDM_IPR_STALE_LSB_BMSK 0x1f
-
-/* These can be used for both ISR and IMR register */
-#define UARTDM_ISR_TX_READY_BMSK BIT(7)
-#define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6)
-#define UARTDM_ISR_DELTA_CTS_BMSK BIT(5)
-#define UARTDM_ISR_RXLEV_BMSK BIT(4)
-#define UARTDM_ISR_RXSTALE_BMSK BIT(3)
-#define UARTDM_ISR_RXBREAK_BMSK BIT(2)
-#define UARTDM_ISR_RXHUNT_BMSK BIT(1)
-#define UARTDM_ISR_TXLEV_BMSK BIT(0)
-
-/* Field definitions for UART_DM_DMEN*/
-#define UARTDM_TX_DM_EN_BMSK 0x1
-#define UARTDM_RX_DM_EN_BMSK 0x2
-
-#define UART_FIFOSIZE 64
-#define UARTCLK 7372800
-
-/* Rx DMA request states */
-enum flush_reason {
- FLUSH_NONE,
- FLUSH_DATA_READY,
- FLUSH_DATA_INVALID, /* values after this indicate invalid data */
- FLUSH_IGNORE = FLUSH_DATA_INVALID,
- FLUSH_STOP,
- FLUSH_SHUTDOWN,
-};
-
-/* UART clock states */
-enum msm_hs_clk_states_e {
- MSM_HS_CLK_PORT_OFF, /* port not in use */
- MSM_HS_CLK_OFF, /* clock disabled */
- MSM_HS_CLK_REQUEST_OFF, /* disable after TX and RX flushed */
- MSM_HS_CLK_ON, /* clock enabled */
-};
-
-/* Track the forced RXSTALE flush during clock off sequence.
- * These states are only valid during MSM_HS_CLK_REQUEST_OFF */
-enum msm_hs_clk_req_off_state_e {
- CLK_REQ_OFF_START,
- CLK_REQ_OFF_RXSTALE_ISSUED,
- CLK_REQ_OFF_FLUSH_ISSUED,
- CLK_REQ_OFF_RXSTALE_FLUSHED,
-};
-
-/**
- * struct msm_hs_tx
- * @tx_ready_int_en: ok to dma more tx?
- * @dma_in_flight: tx dma in progress
- * @xfer: top level DMA command pointer structure
- * @command_ptr: third level command struct pointer
- * @command_ptr_ptr: second level command list struct pointer
- * @mapped_cmd_ptr: DMA view of third level command struct
- * @mapped_cmd_ptr_ptr: DMA view of second level command list struct
- * @tx_count: number of bytes to transfer in DMA transfer
- * @dma_base: DMA view of UART xmit buffer
- *
- * This structure describes a single Tx DMA transaction. MSM DMA
- * commands have two levels of indirection. The top level command
- * ptr points to a list of command ptr which in turn points to a
- * single DMA 'command'. In our case each Tx transaction consists
- * of a single second level pointer pointing to a 'box type' command.
- */
-struct msm_hs_tx {
- unsigned int tx_ready_int_en;
- unsigned int dma_in_flight;
- struct msm_dmov_cmd xfer;
- dmov_box *command_ptr;
- u32 *command_ptr_ptr;
- dma_addr_t mapped_cmd_ptr;
- dma_addr_t mapped_cmd_ptr_ptr;
- int tx_count;
- dma_addr_t dma_base;
-};
-
-/**
- * struct msm_hs_rx
- * @flush: Rx DMA request state
- * @xfer: top level DMA command pointer structure
- * @cmdptr_dmaaddr: DMA view of second level command structure
- * @command_ptr: third level DMA command pointer structure
- * @command_ptr_ptr: second level DMA command list pointer
- * @mapped_cmd_ptr: DMA view of the third level command structure
- * @wait: wait for DMA completion before shutdown
- * @buffer: destination buffer for RX DMA
- * @rbuffer: DMA view of buffer
- * @pool: dma pool out of which coherent rx buffer is allocated
- * @tty_work: private work-queue for tty flip buffer push task
- *
- * This structure describes a single Rx DMA transaction. Rx DMA
- * transactions use box mode DMA commands.
- */
-struct msm_hs_rx {
- enum flush_reason flush;
- struct msm_dmov_cmd xfer;
- dma_addr_t cmdptr_dmaaddr;
- dmov_box *command_ptr;
- u32 *command_ptr_ptr;
- dma_addr_t mapped_cmd_ptr;
- wait_queue_head_t wait;
- dma_addr_t rbuffer;
- unsigned char *buffer;
- struct dma_pool *pool;
- struct work_struct tty_work;
-};
-
-/**
- * struct msm_hs_rx_wakeup
- * @irq: IRQ line to be configured as interrupt source on Rx activity
- * @ignore: boolean value. 1 = ignore the wakeup interrupt
- * @rx_to_inject: extra character to be inserted to Rx tty on wakeup
- * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character
- *
- * This is an optional structure required for UART Rx GPIO IRQ based
- * wakeup from low power state. UART wakeup can be triggered by RX activity
- * (using a wakeup GPIO on the UART RX pin). This should only be used if
- * there is not a wakeup GPIO on the UART CTS, and the first RX byte is
- * known (eg., with the Bluetooth Texas Instruments HCILL protocol),
- * since the first RX byte will always be lost. RTS will be asserted even
- * while the UART is clocked off in this mode of operation.
- */
-struct msm_hs_rx_wakeup {
- int irq; /* < 0 indicates low power wakeup disabled */
- unsigned char ignore;
- unsigned char inject_rx;
- char rx_to_inject;
-};
-
-/**
- * struct msm_hs_port
- * @uport: embedded uart port structure
- * @imr_reg: shadow value of UARTDM_IMR
- * @clk: uart input clock handle
- * @tx: Tx transaction related data structure
- * @rx: Rx transaction related data structure
- * @dma_tx_channel: Tx DMA command channel
- * @dma_rx_channel Rx DMA command channel
- * @dma_tx_crci: Tx channel rate control interface number
- * @dma_rx_crci: Rx channel rate control interface number
- * @clk_off_timer: Timer to poll DMA event completion before clock off
- * @clk_off_delay: clk_off_timer poll interval
- * @clk_state: overall clock state
- * @clk_req_off_state: post flush clock states
- * @rx_wakeup: optional rx_wakeup feature related data
- * @exit_lpm_cb: optional callback to exit low power mode
- *
- * Low level serial port structure.
- */
-struct msm_hs_port {
- struct uart_port uport;
- unsigned long imr_reg;
- struct clk *clk;
- struct msm_hs_tx tx;
- struct msm_hs_rx rx;
-
- int dma_tx_channel;
- int dma_rx_channel;
- int dma_tx_crci;
- int dma_rx_crci;
-
- struct hrtimer clk_off_timer;
- ktime_t clk_off_delay;
- enum msm_hs_clk_states_e clk_state;
- enum msm_hs_clk_req_off_state_e clk_req_off_state;
-
- struct msm_hs_rx_wakeup rx_wakeup;
- void (*exit_lpm_cb)(struct uart_port *);
-};
-
-#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
-#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE
-#define UARTDM_RX_BUF_SIZE 512
-
-#define UARTDM_NR 2
-
-static struct msm_hs_port q_uart_port[UARTDM_NR];
-static struct platform_driver msm_serial_hs_platform_driver;
-static struct uart_driver msm_hs_driver;
-static struct uart_ops msm_hs_ops;
-static struct workqueue_struct *msm_hs_workqueue;
-
-#define UARTDM_TO_MSM(uart_port) \
- container_of((uart_port), struct msm_hs_port, uport)
-
-static unsigned int use_low_power_rx_wakeup(struct msm_hs_port
- *msm_uport)
-{
- return (msm_uport->rx_wakeup.irq >= 0);
-}
-
-static unsigned int msm_hs_read(struct uart_port *uport,
- unsigned int offset)
-{
- return ioread32(uport->membase + offset);
-}
-
-static void msm_hs_write(struct uart_port *uport, unsigned int offset,
- unsigned int value)
-{
- iowrite32(value, uport->membase + offset);
-}
-
-static void msm_hs_release_port(struct uart_port *port)
-{
- iounmap(port->membase);
-}
-
-static int msm_hs_request_port(struct uart_port *port)
-{
- port->membase = ioremap(port->mapbase, PAGE_SIZE);
- if (unlikely(!port->membase))
- return -ENOMEM;
-
- /* configure the CR Protection to Enable */
- msm_hs_write(port, UARTDM_CR_ADDR, CR_PROTECTION_EN);
- return 0;
-}
-
-static int msm_hs_remove(struct platform_device *pdev)
-{
-
- struct msm_hs_port *msm_uport;
- struct device *dev;
-
- if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
- printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
- return -EINVAL;
- }
-
- msm_uport = &q_uart_port[pdev->id];
- dev = msm_uport->uport.dev;
-
- dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box),
- DMA_TO_DEVICE);
- dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
- msm_uport->rx.rbuffer);
- dma_pool_destroy(msm_uport->rx.pool);
-
- dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
- DMA_TO_DEVICE);
- dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
- DMA_TO_DEVICE);
- dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
- DMA_TO_DEVICE);
-
- uart_remove_one_port(&msm_hs_driver, &msm_uport->uport);
- clk_put(msm_uport->clk);
-
- /* Free the tx resources */
- kfree(msm_uport->tx.command_ptr);
- kfree(msm_uport->tx.command_ptr_ptr);
-
- /* Free the rx resources */
- kfree(msm_uport->rx.command_ptr);
- kfree(msm_uport->rx.command_ptr_ptr);
-
- iounmap(msm_uport->uport.membase);
-
- return 0;
-}
-
-static int msm_hs_init_clk_locked(struct uart_port *uport)
-{
- int ret;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- ret = clk_enable(msm_uport->clk);
- if (ret) {
- printk(KERN_ERR "Error could not turn on UART clk\n");
- return ret;
- }
-
- /* Set up the MREG/NREG/DREG/MNDREG */
- ret = clk_set_rate(msm_uport->clk, uport->uartclk);
- if (ret) {
- printk(KERN_WARNING "Error setting clock rate on UART\n");
- clk_disable(msm_uport->clk);
- return ret;
- }
-
- msm_uport->clk_state = MSM_HS_CLK_ON;
- return 0;
-}
-
-/* Enable and Disable clocks (Used for power management) */
-static void msm_hs_pm(struct uart_port *uport, unsigned int state,
- unsigned int oldstate)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- if (use_low_power_rx_wakeup(msm_uport) ||
- msm_uport->exit_lpm_cb)
- return; /* ignore linux PM states,
- use msm_hs_request_clock API */
-
- switch (state) {
- case 0:
- clk_enable(msm_uport->clk);
- break;
- case 3:
- clk_disable(msm_uport->clk);
- break;
- default:
- dev_err(uport->dev, "msm_serial: Unknown PM state %d\n",
- state);
- }
-}
-
-/*
- * programs the UARTDM_CSR register with correct bit rates
- *
- * Interrupts should be disabled before we are called, as
- * we modify Set Baud rate
- * Set receive stale interrupt level, dependent on Bit Rate
- * Goal is to have around 8 ms before indicate stale.
- * roundup (((Bit Rate * .008) / 10) + 1
- */
-static void msm_hs_set_bps_locked(struct uart_port *uport,
- unsigned int bps)
-{
- unsigned long rxstale;
- unsigned long data;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- switch (bps) {
- case 300:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_75);
- rxstale = 1;
- break;
- case 600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_150);
- rxstale = 1;
- break;
- case 1200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_300);
- rxstale = 1;
- break;
- case 2400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_600);
- rxstale = 1;
- break;
- case 4800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_1200);
- rxstale = 1;
- break;
- case 9600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400);
- rxstale = 2;
- break;
- case 14400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_3600);
- rxstale = 3;
- break;
- case 19200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_4800);
- rxstale = 4;
- break;
- case 28800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_7200);
- rxstale = 6;
- break;
- case 38400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_9600);
- rxstale = 8;
- break;
- case 57600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_14400);
- rxstale = 16;
- break;
- case 76800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_19200);
- rxstale = 16;
- break;
- case 115200:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_28800);
- rxstale = 31;
- break;
- case 230400:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_57600);
- rxstale = 31;
- break;
- case 460800:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200);
- rxstale = 31;
- break;
- case 4000000:
- case 3686400:
- case 3200000:
- case 3500000:
- case 3000000:
- case 2500000:
- case 1500000:
- case 1152000:
- case 1000000:
- case 921600:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200);
- rxstale = 31;
- break;
- default:
- msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400);
- /* default to 9600 */
- bps = 9600;
- rxstale = 2;
- break;
- }
- if (bps > 460800)
- uport->uartclk = bps * 16;
- else
- uport->uartclk = UARTCLK;
-
- if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
- printk(KERN_WARNING "Error setting clock rate on UART\n");
- return;
- }
-
- data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
- data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
-
- msm_hs_write(uport, UARTDM_IPR_ADDR, data);
-}
-
-/*
- * termios : new ktermios
- * oldtermios: old ktermios previous setting
- *
- * Configure the serial port
- */
-static void msm_hs_set_termios(struct uart_port *uport,
- struct ktermios *termios,
- struct ktermios *oldtermios)
-{
- unsigned int bps;
- unsigned long data;
- unsigned long flags;
- unsigned int c_cflag = termios->c_cflag;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- spin_lock_irqsave(&uport->lock, flags);
- clk_enable(msm_uport->clk);
-
- /* 300 is the minimum baud support by the driver */
- bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000);
-
- /* Temporary remapping 200 BAUD to 3.2 mbps */
- if (bps == 200)
- bps = 3200000;
-
- msm_hs_set_bps_locked(uport, bps);
-
- data = msm_hs_read(uport, UARTDM_MR2_ADDR);
- data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
- /* set parity */
- if (PARENB == (c_cflag & PARENB)) {
- if (PARODD == (c_cflag & PARODD))
- data |= ODD_PARITY;
- else if (CMSPAR == (c_cflag & CMSPAR))
- data |= SPACE_PARITY;
- else
- data |= EVEN_PARITY;
- }
-
- /* Set bits per char */
- data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK;
-
- switch (c_cflag & CSIZE) {
- case CS5:
- data |= FIVE_BPC;
- break;
- case CS6:
- data |= SIX_BPC;
- break;
- case CS7:
- data |= SEVEN_BPC;
- break;
- default:
- data |= EIGHT_BPC;
- break;
- }
- /* stop bits */
- if (c_cflag & CSTOPB) {
- data |= STOP_BIT_TWO;
- } else {
- /* otherwise 1 stop bit */
- data |= STOP_BIT_ONE;
- }
- data |= UARTDM_MR2_ERROR_MODE_BMSK;
- /* write parity/bits per char/stop bit configuration */
- msm_hs_write(uport, UARTDM_MR2_ADDR, data);
-
- /* Configure HW flow control */
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
-
- data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
-
- if (c_cflag & CRTSCTS) {
- data |= UARTDM_MR1_CTS_CTL_BMSK;
- data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- }
-
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
-
- uport->ignore_status_mask = termios->c_iflag & INPCK;
- uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
- uport->read_status_mask = (termios->c_cflag & CREAD);
-
- msm_hs_write(uport, UARTDM_IMR_ADDR, 0);
-
- /* Set Transmit software time out */
- uart_update_timeout(uport, c_cflag, bps);
-
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
-
- if (msm_uport->rx.flush == FLUSH_NONE) {
- msm_uport->rx.flush = FLUSH_IGNORE;
- msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1);
- }
-
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
-
- clk_disable(msm_uport->clk);
- spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-/*
- * Standard API, Transmitter
- * Any character in the transmit shift register is sent
- */
-static unsigned int msm_hs_tx_empty(struct uart_port *uport)
-{
- unsigned int data;
- unsigned int ret = 0;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
-
- data = msm_hs_read(uport, UARTDM_SR_ADDR);
- if (data & UARTDM_SR_TXEMT_BMSK)
- ret = TIOCSER_TEMT;
-
- clk_disable(msm_uport->clk);
-
- return ret;
-}
-
-/*
- * Standard API, Stop transmitter.
- * Any character in the transmit shift register is sent as
- * well as the current data mover transfer .
- */
-static void msm_hs_stop_tx_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- msm_uport->tx.tx_ready_int_en = 0;
-}
-
-/*
- * Standard API, Stop receiver as soon as possible.
- *
- * Function immediately terminates the operation of the
- * channel receiver and any incoming characters are lost. None
- * of the receiver status bits are affected by this command and
- * characters that are already in the receive FIFO there.
- */
-static void msm_hs_stop_rx_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- unsigned int data;
-
- clk_enable(msm_uport->clk);
-
- /* disable dlink */
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data &= ~UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
-
- /* Disable the receiver */
- if (msm_uport->rx.flush == FLUSH_NONE)
- msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1);
-
- if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
- msm_uport->rx.flush = FLUSH_STOP;
-
- clk_disable(msm_uport->clk);
-}
-
-/* Transmit the next chunk of data */
-static void msm_hs_submit_tx_locked(struct uart_port *uport)
-{
- int left;
- int tx_count;
- dma_addr_t src_addr;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- struct msm_hs_tx *tx = &msm_uport->tx;
- struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
-
- if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
- msm_hs_stop_tx_locked(uport);
- return;
- }
-
- tx->dma_in_flight = 1;
-
- tx_count = uart_circ_chars_pending(tx_buf);
-
- if (UARTDM_TX_BUF_SIZE < tx_count)
- tx_count = UARTDM_TX_BUF_SIZE;
-
- left = UART_XMIT_SIZE - tx_buf->tail;
-
- if (tx_count > left)
- tx_count = left;
-
- src_addr = tx->dma_base + tx_buf->tail;
- dma_sync_single_for_device(uport->dev, src_addr, tx_count,
- DMA_TO_DEVICE);
-
- tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) |
- ((tx_count + 15) >> 4);
- tx->command_ptr->src_row_addr = src_addr;
-
- dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
-
- *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
-
- dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
-
- /* Save tx_count to use in Callback */
- tx->tx_count = tx_count;
- msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count);
-
- /* Disable the tx_ready interrupt */
- msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
- msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
-}
-
-/* Start to receive the next chunk of data */
-static void msm_hs_start_rx_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
- msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
- msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
-
- msm_uport->rx.flush = FLUSH_NONE;
- msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer);
-
- /* might have finished RX and be ready to clock off */
- hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay,
- HRTIMER_MODE_REL);
-}
-
-/* Enable the transmitter Interrupt */
-static void msm_hs_start_tx_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
-
- if (msm_uport->exit_lpm_cb)
- msm_uport->exit_lpm_cb(uport);
-
- if (msm_uport->tx.tx_ready_int_en == 0) {
- msm_uport->tx.tx_ready_int_en = 1;
- msm_hs_submit_tx_locked(uport);
- }
-
- clk_disable(msm_uport->clk);
-}
-
-/*
- * This routine is called when we are done with a DMA transfer
- *
- * This routine is registered with Data mover when we set
- * up a Data Mover transfer. It is called from Data mover ISR
- * when the DMA transfer is done.
- */
-static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr,
- unsigned int result,
- struct msm_dmov_errdata *err)
-{
- unsigned long flags;
- struct msm_hs_port *msm_uport;
-
- /* DMA did not finish properly */
- WARN_ON((((result & RSLT_FIFO_CNTR_BMSK) >> 28) == 1) &&
- !(result & RSLT_VLD));
-
- msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer);
-
- spin_lock_irqsave(&msm_uport->uport.lock, flags);
- clk_enable(msm_uport->clk);
-
- msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
-
- clk_disable(msm_uport->clk);
- spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
-}
-
-/*
- * This routine is called when we are done with a DMA transfer or the
- * a flush has been sent to the data mover driver.
- *
- * This routine is registered with Data mover when we set up a Data Mover
- * transfer. It is called from Data mover ISR when the DMA transfer is done.
- */
-static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
- unsigned int result,
- struct msm_dmov_errdata *err)
-{
- int retval;
- int rx_count;
- unsigned long status;
- unsigned int error_f = 0;
- unsigned long flags;
- unsigned int flush;
- struct tty_port *port;
- struct uart_port *uport;
- struct msm_hs_port *msm_uport;
-
- msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
- uport = &msm_uport->uport;
-
- spin_lock_irqsave(&uport->lock, flags);
- clk_enable(msm_uport->clk);
-
- port = &uport->state->port;
-
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
-
- status = msm_hs_read(uport, UARTDM_SR_ADDR);
-
- /* overflow is not connect to data in a FIFO */
- if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
- (uport->read_status_mask & CREAD))) {
- tty_insert_flip_char(port, 0, TTY_OVERRUN);
- uport->icount.buf_overrun++;
- error_f = 1;
- }
-
- if (!(uport->ignore_status_mask & INPCK))
- status = status & ~(UARTDM_SR_PAR_FRAME_BMSK);
-
- if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) {
- /* Can not tell difference between parity & frame error */
- uport->icount.parity++;
- error_f = 1;
- if (uport->ignore_status_mask & IGNPAR)
- tty_insert_flip_char(port, 0, TTY_PARITY);
- }
-
- if (error_f)
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
-
- if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
-
- flush = msm_uport->rx.flush;
- if (flush == FLUSH_IGNORE)
- msm_hs_start_rx_locked(uport);
- if (flush == FLUSH_STOP)
- msm_uport->rx.flush = FLUSH_SHUTDOWN;
- if (flush >= FLUSH_DATA_INVALID)
- goto out;
-
- rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
-
- if (0 != (uport->read_status_mask & CREAD)) {
- retval = tty_insert_flip_string(port, msm_uport->rx.buffer,
- rx_count);
- BUG_ON(retval != rx_count);
- }
-
- msm_hs_start_rx_locked(uport);
-
-out:
- clk_disable(msm_uport->clk);
-
- spin_unlock_irqrestore(&uport->lock, flags);
-
- if (flush < FLUSH_DATA_INVALID)
- queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work);
-}
-
-static void msm_hs_tty_flip_buffer_work(struct work_struct *work)
-{
- struct msm_hs_port *msm_uport =
- container_of(work, struct msm_hs_port, rx.tty_work);
-
- tty_flip_buffer_push(&msm_uport->uport.state->port);
-}
-
-/*
- * Standard API, Current states of modem control inputs
- *
- * Since CTS can be handled entirely by HARDWARE we always
- * indicate clear to send and count on the TX FIFO to block when
- * it fills up.
- *
- * - TIOCM_DCD
- * - TIOCM_CTS
- * - TIOCM_DSR
- * - TIOCM_RI
- * (Unsupported) DCD and DSR will return them high. RI will return low.
- */
-static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport)
-{
- return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
-}
-
-/*
- * True enables UART auto RFR, which indicates we are ready for data if the RX
- * buffer is not full. False disables auto RFR, and deasserts RFR to indicate
- * we are not ready for data. Must be called with UART clock on.
- */
-static void set_rfr_locked(struct uart_port *uport, int auto_rfr)
-{
- unsigned int data;
-
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
-
- if (auto_rfr) {
- /* enable auto ready-for-receiving */
- data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
- } else {
- /* disable auto ready-for-receiving */
- data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
- /* RFR is active low, set high */
- msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH);
- }
-}
-
-/*
- * Standard API, used to set or clear RFR
- */
-static void msm_hs_set_mctrl_locked(struct uart_port *uport,
- unsigned int mctrl)
-{
- unsigned int auto_rfr;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
-
- auto_rfr = TIOCM_RTS & mctrl ? 1 : 0;
- set_rfr_locked(uport, auto_rfr);
-
- clk_disable(msm_uport->clk);
-}
-
-/* Standard API, Enable modem status (CTS) interrupt */
-static void msm_hs_enable_ms_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
-
- /* Enable DELTA_CTS Interrupt */
- msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
-
- clk_disable(msm_uport->clk);
-
-}
-
-/*
- * Standard API, Break Signal
- *
- * Control the transmission of a break signal. ctl eq 0 => break
- * signal terminate ctl ne 0 => start break signal
- */
-static void msm_hs_break_ctl(struct uart_port *uport, int ctl)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
- msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK);
- clk_disable(msm_uport->clk);
-}
-
-static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&uport->lock, flags);
- if (cfg_flags & UART_CONFIG_TYPE) {
- uport->type = PORT_MSM;
- msm_hs_request_port(uport);
- }
- spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-/* Handle CTS changes (Called from interrupt handler) */
-static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- clk_enable(msm_uport->clk);
-
- /* clear interrupt */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
- uport->icount.cts++;
-
- clk_disable(msm_uport->clk);
-
- /* clear the IOCTL TIOCMIWAIT if called */
- wake_up_interruptible(&uport->state->port.delta_msr_wait);
-}
-
-/* check if the TX path is flushed, and if so clock off
- * returns 0 did not clock off, need to retry (still sending final byte)
- * -1 did not clock off, do not retry
- * 1 if we clocked off
- */
-static int msm_hs_check_clock_off_locked(struct uart_port *uport)
-{
- unsigned long sr_status;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- struct circ_buf *tx_buf = &uport->state->xmit;
-
- /* Cancel if tx tty buffer is not empty, dma is in flight,
- * or tx fifo is not empty, or rx fifo is not empty */
- if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
- !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
- (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) ||
- !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK)) {
- return -1;
- }
-
- /* Make sure the uart is finished with the last byte */
- sr_status = msm_hs_read(uport, UARTDM_SR_ADDR);
- if (!(sr_status & UARTDM_SR_TXEMT_BMSK))
- return 0; /* retry */
-
- /* Make sure forced RXSTALE flush complete */
- switch (msm_uport->clk_req_off_state) {
- case CLK_REQ_OFF_START:
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
- msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_ISSUED:
- case CLK_REQ_OFF_FLUSH_ISSUED:
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_FLUSHED:
- break; /* continue */
- }
-
- if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
- if (msm_uport->rx.flush == FLUSH_NONE)
- msm_hs_stop_rx_locked(uport);
- return 0; /* come back later to really clock off */
- }
-
- /* we really want to clock off */
- clk_disable(msm_uport->clk);
- msm_uport->clk_state = MSM_HS_CLK_OFF;
-
- if (use_low_power_rx_wakeup(msm_uport)) {
- msm_uport->rx_wakeup.ignore = 1;
- enable_irq(msm_uport->rx_wakeup.irq);
- }
- return 1;
-}
-
-static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer)
-{
- unsigned long flags;
- int ret = HRTIMER_NORESTART;
- struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port,
- clk_off_timer);
- struct uart_port *uport = &msm_uport->uport;
-
- spin_lock_irqsave(&uport->lock, flags);
-
- if (!msm_hs_check_clock_off_locked(uport)) {
- hrtimer_forward_now(timer, msm_uport->clk_off_delay);
- ret = HRTIMER_RESTART;
- }
-
- spin_unlock_irqrestore(&uport->lock, flags);
-
- return ret;
-}
-
-static irqreturn_t msm_hs_isr(int irq, void *dev)
-{
- unsigned long flags;
- unsigned long isr_status;
- struct msm_hs_port *msm_uport = dev;
- struct uart_port *uport = &msm_uport->uport;
- struct circ_buf *tx_buf = &uport->state->xmit;
- struct msm_hs_tx *tx = &msm_uport->tx;
- struct msm_hs_rx *rx = &msm_uport->rx;
-
- spin_lock_irqsave(&uport->lock, flags);
-
- isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR);
-
- /* Uart RX starting */
- if (isr_status & UARTDM_ISR_RXLEV_BMSK) {
- msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
- }
- /* Stale rx interrupt */
- if (isr_status & UARTDM_ISR_RXSTALE_BMSK) {
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
-
- if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED)
- msm_uport->clk_req_off_state =
- CLK_REQ_OFF_FLUSH_ISSUED;
- if (rx->flush == FLUSH_NONE) {
- rx->flush = FLUSH_DATA_READY;
- msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1);
- }
- }
- /* tx ready interrupt */
- if (isr_status & UARTDM_ISR_TX_READY_BMSK) {
- /* Clear TX Ready */
- msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY);
-
- if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
- msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR,
- msm_uport->imr_reg);
- }
-
- /* Complete DMA TX transactions and submit new transactions */
- tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE;
-
- tx->dma_in_flight = 0;
-
- uport->icount.tx += tx->tx_count;
- if (tx->tx_ready_int_en)
- msm_hs_submit_tx_locked(uport);
-
- if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS)
- uart_write_wakeup(uport);
- }
- if (isr_status & UARTDM_ISR_TXLEV_BMSK) {
- /* TX FIFO is empty */
- msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
- if (!msm_hs_check_clock_off_locked(uport))
- hrtimer_start(&msm_uport->clk_off_timer,
- msm_uport->clk_off_delay,
- HRTIMER_MODE_REL);
- }
-
- /* Change in CTS interrupt */
- if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK)
- msm_hs_handle_delta_cts_locked(uport);
-
- spin_unlock_irqrestore(&uport->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-void msm_hs_request_clock_off_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- if (msm_uport->clk_state == MSM_HS_CLK_ON) {
- msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
- msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
- if (!use_low_power_rx_wakeup(msm_uport))
- set_rfr_locked(uport, 0);
- msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
- }
-}
-
-/**
- * msm_hs_request_clock_off - request to (i.e. asynchronously) turn off uart
- * clock once pending TX is flushed and Rx DMA command is terminated.
- * @uport: uart_port structure for the device instance.
- *
- * This functions puts the device into a partially active low power mode. It
- * waits to complete all pending tx transactions, flushes ongoing Rx DMA
- * command and terminates UART side Rx transaction, puts UART HW in non DMA
- * mode and then clocks off the device. A client calls this when no UART
- * data is expected. msm_request_clock_on() must be called before any further
- * UART can be sent or received.
- */
-void msm_hs_request_clock_off(struct uart_port *uport)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&uport->lock, flags);
- msm_hs_request_clock_off_locked(uport);
- spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-void msm_hs_request_clock_on_locked(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- unsigned int data;
-
- switch (msm_uport->clk_state) {
- case MSM_HS_CLK_OFF:
- clk_enable(msm_uport->clk);
- disable_irq_nosync(msm_uport->rx_wakeup.irq);
- /* fall-through */
- case MSM_HS_CLK_REQUEST_OFF:
- if (msm_uport->rx.flush == FLUSH_STOP ||
- msm_uport->rx.flush == FLUSH_SHUTDOWN) {
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data |= UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
- }
- hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
- if (msm_uport->rx.flush == FLUSH_SHUTDOWN)
- msm_hs_start_rx_locked(uport);
- if (!use_low_power_rx_wakeup(msm_uport))
- set_rfr_locked(uport, 1);
- if (msm_uport->rx.flush == FLUSH_STOP)
- msm_uport->rx.flush = FLUSH_IGNORE;
- msm_uport->clk_state = MSM_HS_CLK_ON;
- break;
- case MSM_HS_CLK_ON:
- break;
- case MSM_HS_CLK_PORT_OFF:
- break;
- }
-}
-
-/**
- * msm_hs_request_clock_on - Switch the device from partially active low
- * power mode to fully active (i.e. clock on) mode.
- * @uport: uart_port structure for the device.
- *
- * This function switches on the input clock, puts UART HW into DMA mode
- * and enqueues an Rx DMA command if the device was in partially active
- * mode. It has no effect if called with the device in inactive state.
- */
-void msm_hs_request_clock_on(struct uart_port *uport)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&uport->lock, flags);
- msm_hs_request_clock_on_locked(uport);
- spin_unlock_irqrestore(&uport->lock, flags);
-}
-
-static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev)
-{
- unsigned int wakeup = 0;
- unsigned long flags;
- struct msm_hs_port *msm_uport = dev;
- struct uart_port *uport = &msm_uport->uport;
-
- spin_lock_irqsave(&uport->lock, flags);
- if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
- /* ignore the first irq - it is a pending irq that occurred
- * before enable_irq() */
- if (msm_uport->rx_wakeup.ignore)
- msm_uport->rx_wakeup.ignore = 0;
- else
- wakeup = 1;
- }
-
- if (wakeup) {
- /* the uart was clocked off during an rx, wake up and
- * optionally inject char into tty rx */
- msm_hs_request_clock_on_locked(uport);
- if (msm_uport->rx_wakeup.inject_rx) {
- tty_insert_flip_char(&uport->state->port,
- msm_uport->rx_wakeup.rx_to_inject,
- TTY_NORMAL);
- queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work);
- }
- }
-
- spin_unlock_irqrestore(&uport->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static const char *msm_hs_type(struct uart_port *port)
-{
- return (port->type == PORT_MSM) ? "MSM_HS_UART" : NULL;
-}
-
-/* Called when port is opened */
-static int msm_hs_startup(struct uart_port *uport)
-{
- int ret;
- int rfr_level;
- unsigned long flags;
- unsigned int data;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- struct circ_buf *tx_buf = &uport->state->xmit;
- struct msm_hs_tx *tx = &msm_uport->tx;
- struct msm_hs_rx *rx = &msm_uport->rx;
-
- rfr_level = uport->fifosize;
- if (rfr_level > 16)
- rfr_level -= 16;
-
- tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE,
- DMA_TO_DEVICE);
-
- /* do not let tty layer execute RX in global workqueue, use a
- * dedicated workqueue managed by this driver */
- uport->state->port.low_latency = 1;
-
- /* turn on uart clk */
- ret = msm_hs_init_clk_locked(uport);
- if (unlikely(ret)) {
- printk(KERN_ERR "Turning uartclk failed!\n");
- goto err_msm_hs_init_clk;
- }
-
- /* Set auto RFR Level */
- data = msm_hs_read(uport, UARTDM_MR1_ADDR);
- data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
- data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK;
- data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2));
- data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level);
- msm_hs_write(uport, UARTDM_MR1_ADDR, data);
-
- /* Make sure RXSTALE count is non-zero */
- data = msm_hs_read(uport, UARTDM_IPR_ADDR);
- if (!data) {
- data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK;
- msm_hs_write(uport, UARTDM_IPR_ADDR, data);
- }
-
- /* Enable Data Mover Mode */
- data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
-
- /* Reset TX */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS);
- msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW);
- /* Turn on Uart Receiver */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK);
-
- /* Turn on Uart Transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK);
-
- /* Initialize the tx */
- tx->tx_ready_int_en = 0;
- tx->dma_in_flight = 0;
-
- tx->xfer.complete_func = msm_hs_dmov_tx_callback;
- tx->xfer.execute_func = NULL;
-
- tx->command_ptr->cmd = CMD_LC |
- CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
-
- tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
- | (MSM_UARTDM_BURST_SIZE);
-
- tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
-
- tx->command_ptr->dst_row_addr =
- msm_uport->uport.mapbase + UARTDM_TF_ADDR;
-
-
- /* Turn on Uart Receive */
- rx->xfer.complete_func = msm_hs_dmov_rx_callback;
- rx->xfer.execute_func = NULL;
-
- rx->command_ptr->cmd = CMD_LC |
- CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX;
-
- rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
- | (MSM_UARTDM_BURST_SIZE);
- rx->command_ptr->row_offset = MSM_UARTDM_BURST_SIZE;
- rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR;
-
-
- msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
- /* Enable reading the current CTS, no harm even if CTS is ignored */
- msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
-
- msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */
-
-
- ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH,
- "msm_hs_uart", msm_uport);
- if (unlikely(ret)) {
- printk(KERN_ERR "Request msm_hs_uart IRQ failed!\n");
- goto err_request_irq;
- }
- if (use_low_power_rx_wakeup(msm_uport)) {
- ret = request_irq(msm_uport->rx_wakeup.irq,
- msm_hs_rx_wakeup_isr,
- IRQF_TRIGGER_FALLING,
- "msm_hs_rx_wakeup", msm_uport);
- if (unlikely(ret)) {
- printk(KERN_ERR "Request msm_hs_rx_wakeup IRQ failed!\n");
- free_irq(uport->irq, msm_uport);
- goto err_request_irq;
- }
- disable_irq(msm_uport->rx_wakeup.irq);
- }
-
- spin_lock_irqsave(&uport->lock, flags);
-
- msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
- msm_hs_start_rx_locked(uport);
-
- spin_unlock_irqrestore(&uport->lock, flags);
- ret = pm_runtime_set_active(uport->dev);
- if (ret)
- dev_err(uport->dev, "set active error:%d\n", ret);
- pm_runtime_enable(uport->dev);
-
- return 0;
-
-err_request_irq:
-err_msm_hs_init_clk:
- dma_unmap_single(uport->dev, tx->dma_base,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
- return ret;
-}
-
-/* Initialize tx and rx data structures */
-static int uartdm_init_port(struct uart_port *uport)
-{
- int ret = 0;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- struct msm_hs_tx *tx = &msm_uport->tx;
- struct msm_hs_rx *rx = &msm_uport->rx;
-
- /* Allocate the command pointer. Needs to be 64 bit aligned */
- tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
- if (!tx->command_ptr)
- return -ENOMEM;
-
- tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
- if (!tx->command_ptr_ptr) {
- ret = -ENOMEM;
- goto err_tx_command_ptr_ptr;
- }
-
- tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
- tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
- tx->command_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
- tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
-
- init_waitqueue_head(&rx->wait);
-
- rx->pool = dma_pool_create("rx_buffer_pool", uport->dev,
- UARTDM_RX_BUF_SIZE, 16, 0);
- if (!rx->pool) {
- pr_err("%s(): cannot allocate rx_buffer_pool", __func__);
- ret = -ENOMEM;
- goto err_dma_pool_create;
- }
-
- rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer);
- if (!rx->buffer) {
- pr_err("%s(): cannot allocate rx->buffer", __func__);
- ret = -ENOMEM;
- goto err_dma_pool_alloc;
- }
-
- /* Allocate the command pointer. Needs to be 64 bit aligned */
- rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
- if (!rx->command_ptr) {
- pr_err("%s(): cannot allocate rx->command_ptr", __func__);
- ret = -ENOMEM;
- goto err_rx_command_ptr;
- }
-
- rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
- if (!rx->command_ptr_ptr) {
- pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
- ret = -ENOMEM;
- goto err_rx_command_ptr_ptr;
- }
-
- rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) |
- (UARTDM_RX_BUF_SIZE >> 4);
-
- rx->command_ptr->dst_row_addr = rx->rbuffer;
-
- rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
-
- *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
-
- rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
- rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
-
- INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work);
-
- return ret;
-
-err_rx_command_ptr_ptr:
- kfree(rx->command_ptr);
-err_rx_command_ptr:
- dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
- msm_uport->rx.rbuffer);
-err_dma_pool_alloc:
- dma_pool_destroy(msm_uport->rx.pool);
-err_dma_pool_create:
- dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
- dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
- kfree(msm_uport->tx.command_ptr_ptr);
-err_tx_command_ptr_ptr:
- kfree(msm_uport->tx.command_ptr);
- return ret;
-}
-
-static int msm_hs_probe(struct platform_device *pdev)
-{
- int ret;
- struct uart_port *uport;
- struct msm_hs_port *msm_uport;
- struct resource *resource;
- const struct msm_serial_hs_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
-
- if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
- printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
- return -EINVAL;
- }
-
- msm_uport = &q_uart_port[pdev->id];
- uport = &msm_uport->uport;
-
- uport->dev = &pdev->dev;
-
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
- return -ENXIO;
-
- uport->mapbase = resource->start;
- uport->irq = platform_get_irq(pdev, 0);
- if (unlikely(uport->irq < 0))
- return -ENXIO;
-
- if (unlikely(irq_set_irq_wake(uport->irq, 1)))
- return -ENXIO;
-
- if (pdata == NULL || pdata->rx_wakeup_irq < 0)
- msm_uport->rx_wakeup.irq = -1;
- else {
- msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq;
- msm_uport->rx_wakeup.ignore = 1;
- msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup;
- msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject;
-
- if (unlikely(msm_uport->rx_wakeup.irq < 0))
- return -ENXIO;
-
- if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1)))
- return -ENXIO;
- }
-
- if (pdata == NULL)
- msm_uport->exit_lpm_cb = NULL;
- else
- msm_uport->exit_lpm_cb = pdata->exit_lpm_cb;
-
- resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- "uartdm_channels");
- if (unlikely(!resource))
- return -ENXIO;
-
- msm_uport->dma_tx_channel = resource->start;
- msm_uport->dma_rx_channel = resource->end;
-
- resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- "uartdm_crci");
- if (unlikely(!resource))
- return -ENXIO;
-
- msm_uport->dma_tx_crci = resource->start;
- msm_uport->dma_rx_crci = resource->end;
-
- uport->iotype = UPIO_MEM;
- uport->fifosize = UART_FIFOSIZE;
- uport->ops = &msm_hs_ops;
- uport->flags = UPF_BOOT_AUTOCONF;
- uport->uartclk = UARTCLK;
- msm_uport->imr_reg = 0x0;
- msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk");
- if (IS_ERR(msm_uport->clk))
- return PTR_ERR(msm_uport->clk);
-
- ret = uartdm_init_port(uport);
- if (unlikely(ret))
- return ret;
-
- msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
- hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- msm_uport->clk_off_timer.function = msm_hs_clk_off_retry;
- msm_uport->clk_off_delay = ktime_set(0, 1000000); /* 1ms */
-
- uport->line = pdev->id;
- return uart_add_one_port(&msm_hs_driver, uport);
-}
-
-static int __init msm_serial_hs_init(void)
-{
- int ret, i;
-
- /* Init all UARTS as non-configured */
- for (i = 0; i < UARTDM_NR; i++)
- q_uart_port[i].uport.type = PORT_UNKNOWN;
-
- msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs");
- if (unlikely(!msm_hs_workqueue))
- return -ENOMEM;
-
- ret = uart_register_driver(&msm_hs_driver);
- if (unlikely(ret)) {
- printk(KERN_ERR "%s failed to load\n", __func__);
- goto err_uart_register_driver;
- }
-
- ret = platform_driver_register(&msm_serial_hs_platform_driver);
- if (ret) {
- printk(KERN_ERR "%s failed to load\n", __func__);
- goto err_platform_driver_register;
- }
-
- return ret;
-
-err_platform_driver_register:
- uart_unregister_driver(&msm_hs_driver);
-err_uart_register_driver:
- destroy_workqueue(msm_hs_workqueue);
- return ret;
-}
-module_init(msm_serial_hs_init);
-
-/*
- * Called by the upper layer when port is closed.
- * - Disables the port
- * - Unhook the ISR
- */
-static void msm_hs_shutdown(struct uart_port *uport)
-{
- unsigned long flags;
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
-
- spin_lock_irqsave(&uport->lock, flags);
- clk_enable(msm_uport->clk);
-
- /* Disable the transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
- /* Disable the receiver */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK);
-
- pm_runtime_disable(uport->dev);
- pm_runtime_set_suspended(uport->dev);
-
- /* Free the interrupt */
- free_irq(uport->irq, msm_uport);
- if (use_low_power_rx_wakeup(msm_uport))
- free_irq(msm_uport->rx_wakeup.irq, msm_uport);
-
- msm_uport->imr_reg = 0;
- msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
-
- wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
-
- clk_disable(msm_uport->clk); /* to balance local clk_enable() */
- if (msm_uport->clk_state != MSM_HS_CLK_OFF)
- clk_disable(msm_uport->clk); /* to balance clk_state */
- msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
-
- dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
-
- spin_unlock_irqrestore(&uport->lock, flags);
-
- if (cancel_work_sync(&msm_uport->rx.tty_work))
- msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work);
-}
-
-static void __exit msm_serial_hs_exit(void)
-{
- flush_workqueue(msm_hs_workqueue);
- destroy_workqueue(msm_hs_workqueue);
- platform_driver_unregister(&msm_serial_hs_platform_driver);
- uart_unregister_driver(&msm_hs_driver);
-}
-module_exit(msm_serial_hs_exit);
-
-#ifdef CONFIG_PM
-static int msm_hs_runtime_idle(struct device *dev)
-{
- /*
- * returning success from idle results in runtime suspend to be
- * called
- */
- return 0;
-}
-
-static int msm_hs_runtime_resume(struct device *dev)
-{
- struct platform_device *pdev = container_of(dev, struct
- platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
-
- msm_hs_request_clock_on(&msm_uport->uport);
- return 0;
-}
-
-static int msm_hs_runtime_suspend(struct device *dev)
-{
- struct platform_device *pdev = container_of(dev, struct
- platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
-
- msm_hs_request_clock_off(&msm_uport->uport);
- return 0;
-}
-#else
-#define msm_hs_runtime_idle NULL
-#define msm_hs_runtime_resume NULL
-#define msm_hs_runtime_suspend NULL
-#endif
-
-static const struct dev_pm_ops msm_hs_dev_pm_ops = {
- .runtime_suspend = msm_hs_runtime_suspend,
- .runtime_resume = msm_hs_runtime_resume,
- .runtime_idle = msm_hs_runtime_idle,
-};
-
-static struct platform_driver msm_serial_hs_platform_driver = {
- .probe = msm_hs_probe,
- .remove = msm_hs_remove,
- .driver = {
- .name = "msm_serial_hs",
- .pm = &msm_hs_dev_pm_ops,
- },
-};
-
-static struct uart_driver msm_hs_driver = {
- .owner = THIS_MODULE,
- .driver_name = "msm_serial_hs",
- .dev_name = "ttyHS",
- .nr = UARTDM_NR,
- .cons = 0,
-};
-
-static struct uart_ops msm_hs_ops = {
- .tx_empty = msm_hs_tx_empty,
- .set_mctrl = msm_hs_set_mctrl_locked,
- .get_mctrl = msm_hs_get_mctrl_locked,
- .stop_tx = msm_hs_stop_tx_locked,
- .start_tx = msm_hs_start_tx_locked,
- .stop_rx = msm_hs_stop_rx_locked,
- .enable_ms = msm_hs_enable_ms_locked,
- .break_ctl = msm_hs_break_ctl,
- .startup = msm_hs_startup,
- .shutdown = msm_hs_shutdown,
- .set_termios = msm_hs_set_termios,
- .pm = msm_hs_pm,
- .type = msm_hs_type,
- .config_port = msm_hs_config_port,
- .release_port = msm_hs_release_port,
- .request_port = msm_hs_request_port,
-};
-
-MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset");
-MODULE_VERSION("1.2");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index d1298b6cc68e..f7e5825b55ab 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -176,7 +176,7 @@ static struct platform_device_id mxs_auart_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);
-static struct of_device_id mxs_auart_dt_ids[] = {
+static const struct of_device_id mxs_auart_dt_ids[] = {
{
.compatible = "fsl,imx28-auart",
.data = &mxs_auart_devtype[IMX28_AUART]
@@ -1155,14 +1155,14 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
return 0;
}
-static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
+static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
{
enum mctrl_gpio_idx i;
struct gpio_desc *gpiod;
s->gpios = mctrl_gpio_init(dev, 0);
- if (IS_ERR_OR_NULL(s->gpios))
- return false;
+ if (IS_ERR(s->gpios))
+ return PTR_ERR(s->gpios);
/* Block (enabled before) DMA option if RTS or CTS is GPIO line */
if (!RTS_AT_AUART() || !CTS_AT_AUART()) {
@@ -1180,7 +1180,7 @@ static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
s->gpio_irq[i] = -EINVAL;
}
- return true;
+ return 0;
}
static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
@@ -1276,9 +1276,11 @@ static int mxs_auart_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, s);
- if (!mxs_auart_init_gpios(s, &pdev->dev))
- dev_err(&pdev->dev,
- "Failed to initialize GPIOs. The serial port may not work as expected\n");
+ ret = mxs_auart_init_gpios(s, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
+ return ret;
+ }
/*
* Get the GPIO lines IRQ
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 7ff61e24a195..5b73afb9f9f3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -89,6 +89,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
spin_lock_init(&port->lock);
port->mapbase = resource.start;
+ port->mapsize = resource_size(&resource);
/* Check for shifted address mapping */
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
@@ -115,7 +116,8 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->iotype = UPIO_MEM;
break;
case 4:
- port->iotype = UPIO_MEM32;
+ port->iotype = of_device_is_big_endian(np) ?
+ UPIO_MEM32BE : UPIO_MEM32;
break;
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
@@ -133,10 +135,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_find_property(np, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;
- ret = of_alias_get_id(np, "serial");
- if (ret >= 0)
- port->line = ret;
-
port->dev = &ofdev->dev;
switch (type) {
@@ -159,7 +157,7 @@ out:
/*
* Try to register a serial port
*/
-static struct of_device_id of_platform_serial_table[];
+static const struct of_device_id of_platform_serial_table[];
static int of_platform_serial_probe(struct platform_device *ofdev)
{
const struct of_device_id *match;
@@ -324,7 +322,7 @@ static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume);
/*
* A few common types, add more as needed.
*/
-static struct of_device_id of_platform_serial_table[] = {
+static const struct of_device_id of_platform_serial_table[] = {
{ .compatible = "ns8250", .data = (void *)PORT_8250, },
{ .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .compatible = "ns16550a", .data = (void *)PORT_16550A, },
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 10256fa04b40..211479aa34bb 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1654,11 +1654,6 @@ static int serial_omap_probe(struct platform_device *pdev)
up->port.type = PORT_OMAP;
up->port.iotype = UPIO_MEM;
up->port.irq = uartirq;
- up->wakeirq = wakeirq;
- if (!up->wakeirq)
- dev_info(up->port.dev, "no wakeirq for uart%d\n",
- up->port.line);
-
up->port.regshift = 2;
up->port.fifosize = 64;
up->port.ops = &serial_omap_pops;
@@ -1682,6 +1677,11 @@ static int serial_omap_probe(struct platform_device *pdev)
goto err_port_line;
}
+ up->wakeirq = wakeirq;
+ if (!up->wakeirq)
+ dev_info(up->port.dev, "no wakeirq for uart%d\n",
+ up->port.line);
+
ret = serial_omap_probe_rs485(up, pdev->dev.of_node);
if (ret < 0)
goto err_rs485;
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 8f515799c9c1..e156e39d620c 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1846,7 +1846,7 @@ static int __init pmz_register(void)
#ifdef CONFIG_PPC_PMAC
-static struct of_device_id pmz_match[] =
+static const struct of_device_id pmz_match[] =
{
{
.name = "ch-a",
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index d5d062694bd3..9becba654892 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -824,7 +824,7 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
};
#endif
-static struct of_device_id serial_pxa_dt_ids[] = {
+static const struct of_device_id serial_pxa_dt_ids[] = {
{ .compatible = "mrvl,pxa-uart", },
{ .compatible = "mrvl,mmp-uart", },
{}
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index af821a908720..cf08876922f1 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
free_irq(ourport->tx_irq, ourport);
tx_enabled(port) = 0;
ourport->tx_claimed = 0;
+ ourport->tx_mode = 0;
}
if (ourport->rx_claimed) {
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index df9a384dfbda..468354ef7baa 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -829,16 +829,32 @@ static void sc16is7xx_set_termios(struct uart_port *port,
}
static int sc16is7xx_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485)
{
- if (port->rs485.flags & SER_RS485_ENABLED)
- sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
- SC16IS7XX_EFCR_AUTO_RS485_BIT,
- SC16IS7XX_EFCR_AUTO_RS485_BIT);
- else
- sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
- SC16IS7XX_EFCR_AUTO_RS485_BIT,
- 0);
+ const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
+ SC16IS7XX_EFCR_RTS_INVERT_BIT;
+ u32 efcr = 0;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ bool rts_during_rx, rts_during_tx;
+
+ rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND;
+ rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND;
+
+ efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
+
+ if (!rts_during_rx && rts_during_tx)
+ /* default */;
+ else if (rts_during_rx && !rts_during_tx)
+ efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
+ else
+ dev_err(port->dev,
+ "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n",
+ rts_during_tx, rts_during_rx);
+ }
+
+ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
+
port->rs485 = *rs485;
return 0;
@@ -903,9 +919,11 @@ static void sc16is7xx_shutdown(struct uart_port *port)
/* Disable all interrupts */
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
/* Disable TX/RX */
- sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG,
- SC16IS7XX_EFCR_RXDISABLE_BIT |
- SC16IS7XX_EFCR_TXDISABLE_BIT);
+ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT);
sc16is7xx_power(port, 0);
}
@@ -1048,6 +1066,7 @@ static int sc16is7xx_probe(struct device *dev,
else
return PTR_ERR(s->clk);
} else {
+ clk_prepare_enable(s->clk);
freq = clk_get_rate(s->clk);
}
@@ -1120,6 +1139,9 @@ static int sc16is7xx_probe(struct device *dev,
if (!ret)
return 0;
+ for (i = 0; i < s->uart.nr; i++)
+ uart_remove_one_port(&s->uart, &s->p[i].port);
+
mutex_destroy(&s->mutex);
#ifdef CONFIG_GPIOLIB
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 48e6e41636b2..1d5ea3964ee5 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -1251,7 +1251,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = {
.support_clk_src_div = true,
};
-static struct of_device_id tegra_uart_of_match[] = {
+static const struct of_device_id tegra_uart_of_match[] = {
{
.compatible = "nvidia,tegra30-hsuart",
.data = &tegra30_uart_chip_data,
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 6a1055ae3437..eb5b03be9dfd 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1118,8 +1118,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
cprev = cnow;
}
-
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&port->delta_msr_wait, &wait);
return ret;
@@ -1766,7 +1765,7 @@ static const struct file_operations uart_proc_fops = {
#endif
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
-/*
+/**
* uart_console_write - write a console message to a serial port
* @port: the port to write the message
* @s: array of characters
@@ -1810,6 +1809,52 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
}
/**
+ * uart_parse_earlycon - Parse earlycon options
+ * @p: ptr to 2nd field (ie., just beyond '<name>,')
+ * @iotype: ptr for decoded iotype (out)
+ * @addr: ptr for decoded mapbase/iobase (out)
+ * @options: ptr for <options> field; NULL if not present (out)
+ *
+ * Decodes earlycon kernel command line parameters of the form
+ * earlycon=<name>,io|mmio|mmio32,<addr>,<options>
+ * console=<name>,io|mmio|mmio32,<addr>,<options>
+ *
+ * The optional form
+ * earlycon=<name>,0x<addr>,<options>
+ * console=<name>,0x<addr>,<options>
+ * is also accepted; the returned @iotype will be UPIO_MEM.
+ *
+ * Returns 0 on success or -EINVAL on failure
+ */
+int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
+ char **options)
+{
+ if (strncmp(p, "mmio,", 5) == 0) {
+ *iotype = UPIO_MEM;
+ p += 5;
+ } else if (strncmp(p, "mmio32,", 7) == 0) {
+ *iotype = UPIO_MEM32;
+ p += 7;
+ } else if (strncmp(p, "io,", 3) == 0) {
+ *iotype = UPIO_PORT;
+ p += 3;
+ } else if (strncmp(p, "0x", 2) == 0) {
+ *iotype = UPIO_MEM;
+ } else {
+ return -EINVAL;
+ }
+
+ *addr = simple_strtoul(p, NULL, 0);
+ p = strchr(p, ',');
+ if (p)
+ p++;
+
+ *options = p;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uart_parse_earlycon);
+
+/**
* uart_parse_options - Parse serial port baud/parity/bits/flow control.
* @options: pointer to option string
* @baud: pointer to an 'int' variable for the baud rate.
@@ -2637,6 +2682,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
state->pm_state = UART_PM_STATE_UNDEFINED;
uport->cons = drv->cons;
+ uport->minor = drv->tty_driver->minor_start + uport->line;
/*
* If this port is a console, then the spinlock is already
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index a38596c5194e..0ec756c62bcf 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -48,9 +48,6 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
int value_array[UART_GPIO_MAX];
unsigned int count = 0;
- if (IS_ERR_OR_NULL(gpios))
- return;
-
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
mctrl_gpios_desc[i].dir_out) {
@@ -65,10 +62,7 @@ EXPORT_SYMBOL_GPL(mctrl_gpio_set);
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
- if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
- return gpios->gpio[gidx];
- else
- return NULL;
+ return gpios->gpio[gidx];
}
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
@@ -76,15 +70,8 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
- /*
- * return it unchanged if the structure is not allocated
- */
- if (IS_ERR_OR_NULL(gpios))
- return *mctrl;
-
for (i = 0; i < UART_GPIO_MAX; i++) {
- if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
- !mctrl_gpios_desc[i].dir_out) {
+ if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
@@ -100,34 +87,26 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
{
struct mctrl_gpios *gpios;
enum mctrl_gpio_idx i;
- int err;
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
if (!gpios)
return ERR_PTR(-ENOMEM);
for (i = 0; i < UART_GPIO_MAX; i++) {
- gpios->gpio[i] = devm_gpiod_get_index(dev,
- mctrl_gpios_desc[i].name,
- idx);
-
- /*
- * The GPIOs are maybe not all filled,
- * this is not an error.
- */
- if (IS_ERR_OR_NULL(gpios->gpio[i]))
- continue;
+ enum gpiod_flags flags;
if (mctrl_gpios_desc[i].dir_out)
- err = gpiod_direction_output(gpios->gpio[i], 0);
+ flags = GPIOD_OUT_LOW;
else
- err = gpiod_direction_input(gpios->gpio[i]);
- if (err) {
- dev_dbg(dev, "Unable to set direction for %s GPIO",
- mctrl_gpios_desc[i].name);
- devm_gpiod_put(dev, gpios->gpio[i]);
- gpios->gpio[i] = NULL;
- }
+ flags = GPIOD_IN;
+
+ gpios->gpio[i] =
+ devm_gpiod_get_index_optional(dev,
+ mctrl_gpios_desc[i].name,
+ idx, flags);
+
+ if (IS_ERR(gpios->gpio[i]))
+ return ERR_CAST(gpios->gpio[i]);
}
return gpios;
@@ -138,9 +117,6 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
- if (IS_ERR_OR_NULL(gpios))
- return;
-
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]))
devm_gpiod_put(dev, gpios->gpio[i]);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 5b50c792ad5f..e7d6566fafaf 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -844,14 +844,32 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
struct plat_sci_reg *reg;
- int copied = 0;
+ int copied = 0, offset;
+ u16 status, bit;
+
+ switch (port->type) {
+ case PORT_SCIF:
+ case PORT_HSCIF:
+ offset = SCLSR;
+ break;
+ case PORT_SCIFA:
+ case PORT_SCIFB:
+ offset = SCxSR;
+ break;
+ default:
+ return 0;
+ }
- reg = sci_getreg(port, SCLSR);
+ reg = sci_getreg(port, offset);
if (!reg->size)
return 0;
- if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) {
- serial_port_out(port, SCLSR, 0);
+ status = serial_port_in(port, offset);
+ bit = 1 << s->overrun_bit;
+
+ if (status & bit) {
+ status &= ~bit;
+ serial_port_out(port, offset, status);
port->icount.overrun++;
@@ -996,16 +1014,24 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port)
static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
- unsigned short ssr_status, scr_status, err_enabled;
- unsigned short slr_status = 0;
+ unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
struct uart_port *port = ptr;
struct sci_port *s = to_sci_port(port);
irqreturn_t ret = IRQ_NONE;
ssr_status = serial_port_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR);
- if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
- slr_status = serial_port_in(port, SCLSR);
+ switch (port->type) {
+ case PORT_SCIF:
+ case PORT_HSCIF:
+ orer_status = serial_port_in(port, SCLSR);
+ break;
+ case PORT_SCIFA:
+ case PORT_SCIFB:
+ orer_status = ssr_status;
+ break;
+ }
+
err_enabled = scr_status & port_rx_irq_mask(port);
/* Tx Interrupt */
@@ -1033,10 +1059,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ret = sci_br_interrupt(irq, ptr);
/* Overrun Interrupt */
- if (port->type == PORT_SCIF || port->type == PORT_HSCIF) {
- if (slr_status & 0x01)
- sci_handle_fifo_overrun(port);
- }
+ if (orer_status & (1 << s->overrun_bit))
+ sci_handle_fifo_overrun(port);
return ret;
}
@@ -1967,18 +1991,40 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
- * Calculate delay for 1.5 DMA buffers: see
- * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
- * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+ * Calculate delay for 2 DMA buffers (4 FIFO).
+ * See drivers/serial/serial_core.c::uart_update_timeout(). With 10
+ * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
* calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
- * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
- * sizes), but it has been found out experimentally, that this is not
- * enough: the driver too often needlessly runs on a DMA timeout. 20ms
- * as a minimum seem to work perfectly.
+ * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO
+ * sizes), but when performing a faster transfer, value obtained by
+ * this formula is may not enough. Therefore, if value is smaller than
+ * 20msec, this sets 20msec as timeout of DMA.
*/
if (s->chan_rx) {
- s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
- port->fifosize / 2;
+ unsigned int bits;
+
+ /* byte size and parity */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ bits = 7;
+ break;
+ case CS6:
+ bits = 8;
+ break;
+ case CS7:
+ bits = 9;
+ break;
+ default:
+ bits = 10;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ bits++;
+ if (termios->c_cflag & PARENB)
+ bits++;
+ s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) /
+ (baud / 10), 10);
dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
s->rx_timeout * 1000 / HZ, port->timeout);
if (s->rx_timeout < msecs_to_jiffies(20))
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 27ed0e960880..9de3eabe5737 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -1269,7 +1269,7 @@ static struct uart_driver sirfsoc_uart_drv = {
#endif
};
-static struct of_device_id sirfsoc_uart_ids[] = {
+static const struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 594b63331ef4..582d2729f700 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -293,8 +293,10 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
ims = serial_in(port, SPRD_IMSR);
- if (!ims)
+ if (!ims) {
+ spin_unlock(&port->lock);
return IRQ_NONE;
+ }
serial_out(port, SPRD_ICLR, ~0);
@@ -491,6 +493,8 @@ static int sprd_verify_port(struct uart_port *port,
return -EINVAL;
if (port->irq != ser->irq)
return -EINVAL;
+ if (port->iotype != ser->io_type)
+ return -EINVAL;
return 0;
}
@@ -705,7 +709,7 @@ static int sprd_probe(struct platform_device *pdev)
up->dev = &pdev->dev;
up->line = index;
up->type = PORT_SPRD;
- up->iotype = SERIAL_IO_PORT;
+ up->iotype = UPIO_MEM;
up->uartclk = SPRD_DEF_RATE;
up->fifosize = SPRD_FIFO_SIZE;
up->ops = &serial_sprd_ops;
@@ -752,6 +756,7 @@ static int sprd_probe(struct platform_device *pdev)
return ret;
}
+#ifdef CONFIG_PM_SLEEP
static int sprd_suspend(struct device *dev)
{
struct sprd_uart_port *sup = dev_get_drvdata(dev);
@@ -769,6 +774,7 @@ static int sprd_resume(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume);
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 712b03a076b8..d625664ce1b5 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -720,7 +720,7 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id asc_match[] = {
+static const struct of_device_id asc_match[] = {
{ .compatible = "st,asc", },
{},
};
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 189f52e3111f..708eead850b0 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -622,7 +622,7 @@ static int ulite_release(struct device *dev)
#if defined(CONFIG_OF)
/* Match table for of_platform binding */
-static struct of_device_id ulite_of_match[] = {
+static const struct of_device_id ulite_of_match[] = {
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
{ .compatible = "xlnx,xps-uartlite-1.00.a", },
{}
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 14d10fcfd210..7d2532b23969 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1473,7 +1473,7 @@ static int ucc_uart_remove(struct platform_device *ofdev)
return 0;
}
-static struct of_device_id ucc_uart_match[] = {
+static const struct of_device_id ucc_uart_match[] = {
{
.type = "serial",
.compatible = "ucc_uart",
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index cff531a51a78..f218ec658f5d 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -37,10 +37,7 @@
#define CDNS_UART_MINOR 0 /* works best with devtmpfs */
#define CDNS_UART_NR_PORTS 2
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
-#define CDNS_UART_REGISTER_SPACE 0xFFF
-
-#define cdns_uart_readl(offset) ioread32(port->membase + offset)
-#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset)
+#define CDNS_UART_REGISTER_SPACE 0x1000
/* Rx Trigger level */
static int rx_trigger_level = 56;
@@ -195,7 +192,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
/* Read the interrupt status register to determine which
* interrupt(s) is/are active.
*/
- isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET);
+ isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
/*
* There is no hardware break detection, so we interpret framing
@@ -203,14 +200,15 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
* there's another non-zero byte at the end of the sequence.
*/
if (isrstatus & CDNS_UART_IXR_FRAMING) {
- while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
CDNS_UART_SR_RXEMPTY)) {
- if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) {
+ if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
port->read_status_mask |= CDNS_UART_IXR_BRK;
isrstatus &= ~CDNS_UART_IXR_FRAMING;
}
}
- cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_FRAMING,
+ port->membase + CDNS_UART_ISR_OFFSET);
}
/* drop byte with parity error if IGNPAR specified */
@@ -223,9 +221,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
if ((isrstatus & CDNS_UART_IXR_TOUT) ||
(isrstatus & CDNS_UART_IXR_RXTRIG)) {
/* Receive Timeout Interrupt */
- while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
- data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
+ 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 &
@@ -275,8 +273,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
/* Dispatch an appropriate handler */
if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
if (uart_circ_empty(&port->state->xmit)) {
- cdns_uart_writel(CDNS_UART_IXR_TXEMPTY,
- CDNS_UART_IDR_OFFSET);
+ 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 */
@@ -287,9 +285,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
* and write it to the cdns_uart's TX_FIFO
* register.
*/
- cdns_uart_writel(
- port->state->xmit.buf[port->state->xmit.
- tail], CDNS_UART_FIFO_OFFSET);
+ writel(port->state->xmit.buf[
+ port->state->xmit.tail],
+ port->membase + CDNS_UART_FIFO_OFFSET);
port->icount.tx++;
@@ -307,7 +305,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
}
}
- cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET);
+ writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore(&port->lock, flags);
@@ -397,14 +395,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
&div8);
/* Write new divisors to hardware */
- mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET);
+ mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
if (div8)
mreg |= CDNS_UART_MR_CLKSEL;
else
mreg &= ~CDNS_UART_MR_CLKSEL;
- cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET);
- cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET);
- cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET);
+ writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
+ writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
+ writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
cdns_uart->baud = baud;
return calc_baud;
@@ -451,9 +449,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 = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -478,11 +476,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 = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
- while (cdns_uart_readl(CDNS_UART_CR_OFFSET) &
+ while (readl(port->membase + CDNS_UART_CR_OFFSET) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
@@ -491,11 +489,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
* enable bit and RX enable bit to enable the transmitter and
* receiver.
*/
- cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
- ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
@@ -517,14 +515,14 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
return;
- status = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR_OFFSET);
/* Set the TX enable bit and clear the TX disable bit to enable the
* transmitter.
*/
- cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- CDNS_UART_CR_OFFSET);
+ writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
+ port->membase + CDNS_UART_CR_OFFSET);
- while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ 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))
@@ -533,9 +531,8 @@ static void cdns_uart_start_tx(struct uart_port *port)
/* Get the data from the UART circular buffer and
* write it to the cdns_uart's TX_FIFO register.
*/
- cdns_uart_writel(
- port->state->xmit.buf[port->state->xmit.tail],
- CDNS_UART_FIFO_OFFSET);
+ 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
@@ -544,9 +541,9 @@ static void cdns_uart_start_tx(struct uart_port *port)
port->state->xmit.tail = (port->state->xmit.tail + 1) &
(UART_XMIT_SIZE - 1);
}
- cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET);
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
/* Enable the TX Empty interrupt */
- cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET);
+ 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);
@@ -560,10 +557,10 @@ static void cdns_uart_stop_tx(struct uart_port *port)
{
unsigned int regval;
- regval = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR_OFFSET);
regval |= CDNS_UART_CR_TX_DIS;
/* Disable the transmitter */
- cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);
+ writel(regval, port->membase + CDNS_UART_CR_OFFSET);
}
/**
@@ -574,10 +571,10 @@ static void cdns_uart_stop_rx(struct uart_port *port)
{
unsigned int regval;
- regval = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ regval = readl(port->membase + CDNS_UART_CR_OFFSET);
regval |= CDNS_UART_CR_RX_DIS;
/* Disable the receiver */
- cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);
+ writel(regval, port->membase + CDNS_UART_CR_OFFSET);
}
/**
@@ -590,7 +587,8 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
- status = cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY;
+ status = readl(port->membase + CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXEMPTY;
return status ? TIOCSER_TEMT : 0;
}
@@ -607,15 +605,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
- status = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR_OFFSET);
if (ctl == -1)
- cdns_uart_writel(CDNS_UART_CR_STARTBRK | status,
- CDNS_UART_CR_OFFSET);
+ writel(CDNS_UART_CR_STARTBRK | status,
+ port->membase + CDNS_UART_CR_OFFSET);
else {
if ((status & CDNS_UART_CR_STOPBRK) == 0)
- cdns_uart_writel(CDNS_UART_CR_STOPBRK | status,
- CDNS_UART_CR_OFFSET);
+ writel(CDNS_UART_CR_STOPBRK | status,
+ port->membase + CDNS_UART_CR_OFFSET);
}
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -638,17 +636,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 (!(cdns_uart_readl(CDNS_UART_CR_OFFSET) & CDNS_UART_CR_TX_DIS)) {
- while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
+ CDNS_UART_CR_TX_DIS)) {
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
CDNS_UART_SR_TXEMPTY)) {
cpu_relax();
}
}
/* Disable the TX and RX to set baud rate */
- ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
/*
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
@@ -667,20 +666,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 = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
/*
* 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 = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
- cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
@@ -700,7 +699,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 = cdns_uart_readl(CDNS_UART_MR_OFFSET);
+ mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
/* Handling Data Size */
switch (termios->c_cflag & CSIZE) {
@@ -741,7 +740,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
cval |= CDNS_UART_MR_PARITY_NONE;
}
cval |= mode_reg & 1;
- cdns_uart_writel(cval, CDNS_UART_MR_OFFSET);
+ writel(cval, port->membase + CDNS_UART_MR_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -762,52 +761,53 @@ static int cdns_uart_startup(struct uart_port *port)
return retval;
/* Disable the TX and RX */
- cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- CDNS_UART_CR_OFFSET);
+ writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
+ port->membase + CDNS_UART_CR_OFFSET);
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars.
*/
- cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
- CDNS_UART_CR_OFFSET);
+ writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
+ port->membase + CDNS_UART_CR_OFFSET);
- status = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ status = readl(port->membase + CDNS_UART_CR_OFFSET);
/* 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.
*/
- cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS))
+ 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), CDNS_UART_CR_OFFSET);
+ CDNS_UART_CR_STOPBRK),
+ port->membase + CDNS_UART_CR_OFFSET);
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity.
*/
- cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
+ writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
- CDNS_UART_MR_OFFSET);
+ port->membase + CDNS_UART_MR_OFFSET);
/*
* Set the RX FIFO Trigger level to use most of the FIFO, but it
* can be tuned with a module parameter
*/
- cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
- cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
/* Clear out any pending interrupts before enabling them */
- cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET),
- CDNS_UART_ISR_OFFSET);
+ writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
+ port->membase + CDNS_UART_ISR_OFFSET);
/* Set the Interrupt Registers with desired interrupts */
- cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY |
+ 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,
- CDNS_UART_IER_OFFSET);
+ port->membase + CDNS_UART_IER_OFFSET);
return retval;
}
@@ -821,12 +821,12 @@ static void cdns_uart_shutdown(struct uart_port *port)
int status;
/* Disable interrupts */
- status = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
- cdns_uart_writel(status, CDNS_UART_IDR_OFFSET);
+ status = readl(port->membase + CDNS_UART_IMR_OFFSET);
+ writel(status, port->membase + CDNS_UART_IDR_OFFSET);
/* Disable the TX and RX */
- cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
- CDNS_UART_CR_OFFSET);
+ writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
+ port->membase + CDNS_UART_CR_OFFSET);
free_irq(port->irq, port);
}
@@ -928,7 +928,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 val;
- val = cdns_uart_readl(CDNS_UART_MODEMCR_OFFSET);
+ val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
@@ -937,7 +937,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR;
- cdns_uart_writel(val, CDNS_UART_MODEMCR_OFFSET);
+ writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
}
#ifdef CONFIG_CONSOLE_POLL
@@ -947,17 +947,18 @@ static int cdns_uart_poll_get_char(struct uart_port *port)
int c;
/* Disable all interrupts */
- imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
- cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
/* Check if FIFO is empty */
- if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
+ if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
c = NO_POLL_CHAR;
else /* Read a character */
- c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
+ c = (unsigned char) readl(
+ port->membase + CDNS_UART_FIFO_OFFSET);
/* Enable interrupts */
- cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER_OFFSET);
return c;
}
@@ -967,22 +968,24 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
u32 imr;
/* Disable all interrupts */
- imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
- cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
/* Wait until FIFO is empty */
- while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Write a character */
- cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET);
+ writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
/* Wait until FIFO is empty */
- while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY))
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Enable interrupts */
- cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER_OFFSET);
return;
}
@@ -1010,7 +1013,7 @@ static struct uart_ops cdns_uart_ops = {
#endif
};
-static struct uart_port cdns_uart_port[2];
+static struct uart_port cdns_uart_port[CDNS_UART_NR_PORTS];
/**
* cdns_uart_get_port - Configure the port from platform device resource info
@@ -1038,7 +1041,6 @@ static struct uart_port *cdns_uart_get_port(int id)
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
port->membase = NULL;
- port->iobase = 1; /* mark port in use */
port->irq = 0;
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
@@ -1057,8 +1059,8 @@ static struct uart_port *cdns_uart_get_port(int id)
*/
static void cdns_uart_console_wait_tx(struct uart_port *port)
{
- while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)
- != CDNS_UART_SR_TXEMPTY)
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXEMPTY))
barrier();
}
@@ -1070,7 +1072,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);
- cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET);
+ writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
}
static void cdns_early_write(struct console *con, const char *s, unsigned n)
@@ -1112,24 +1114,24 @@ static void cdns_uart_console_write(struct console *co, const char *s,
spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */
- imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
- cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET);
+ imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
/*
* Make sure that the tx part is enabled. Set the TX enable bit and
* clear the TX disable bit to enable the transmitter.
*/
- ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET);
- cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
- CDNS_UART_CR_OFFSET);
+ 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);
uart_console_write(port, s, count, cdns_uart_console_putchar);
cdns_uart_console_wait_tx(port);
- cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET);
+ writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
/* restore interrupt state */
- cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
+ writel(imr, port->membase + CDNS_UART_IER_OFFSET);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
@@ -1153,8 +1155,9 @@ static int __init cdns_uart_console_setup(struct console *co, char *options)
if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS)
return -EINVAL;
- if (!port->mapbase) {
- pr_debug("console on ttyPS%i not present\n", co->index);
+ if (!port->membase) {
+ pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n",
+ co->index);
return -ENODEV;
}
@@ -1240,13 +1243,14 @@ static int cdns_uart_suspend(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
CDNS_UART_SR_RXEMPTY))
- cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
+ readl(port->membase + CDNS_UART_FIFO_OFFSET);
/* set RX trigger level to 1 */
- cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET);
+ writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
/* disable RX timeout interrups */
- cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET);
+ writel(CDNS_UART_IXR_TOUT,
+ port->membase + CDNS_UART_IDR_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1285,28 +1289,30 @@ static int cdns_uart_resume(struct device *device)
spin_lock_irqsave(&port->lock, flags);
/* Set TX/RX Reset */
- ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
- while (cdns_uart_readl(CDNS_UART_CR_OFFSET) &
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
+ while (readl(port->membase + CDNS_UART_CR_OFFSET) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* restore rx timeout value */
- cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
+ writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
/* Enable Tx/Rx */
- ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
- cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
+ writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
} else {
spin_lock_irqsave(&port->lock, flags);
/* restore original rx trigger level */
- cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET);
+ writel(rx_trigger_level,
+ port->membase + CDNS_UART_RXWM_OFFSET);
/* enable RX timeout interrupt */
- cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET);
+ writel(CDNS_UART_IXR_TOUT,
+ port->membase + CDNS_UART_IER_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1458,7 +1464,7 @@ static int cdns_uart_remove(struct platform_device *pdev)
}
/* Match table for of_platform binding */
-static struct of_device_id cdns_uart_of_match[] = {
+static const struct of_device_id cdns_uart_of_match[] = {
{ .compatible = "xlnx,xuartps", },
{ .compatible = "cdns,uart-r1p8", },
{}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 259a4d5a4e8f..843f2cdc280b 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -275,6 +275,7 @@ static struct sysrq_key_op sysrq_showregs_op = {
static void sysrq_handle_showstate(int key)
{
show_state();
+ show_workqueue_state();
}
static struct sysrq_key_op sysrq_showstate_op = {
.handler = sysrq_handle_showstate,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 51f066aa375e..e5695467598f 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1025,11 +1025,17 @@ void start_tty(struct tty_struct *tty)
}
EXPORT_SYMBOL(start_tty);
-/* We limit tty time update visibility to every 8 seconds or so. */
static void tty_update_time(struct timespec *time)
{
- unsigned long sec = get_seconds() & ~7;
- if ((long)(sec - time->tv_sec) > 0)
+ unsigned long sec = get_seconds();
+
+ /*
+ * We only care if the two values differ in anything other than the
+ * lower three bits (i.e every 8 seconds). If so, then we can update
+ * the time of the tty device, otherwise it could be construded as a
+ * security leak to let userspace know the exact timing of the tty.
+ */
+ if ((sec ^ time->tv_sec) & ~7)
time->tv_sec = sec;
}
@@ -3593,6 +3599,13 @@ static ssize_t show_cons_active(struct device *dev,
}
static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
+static struct attribute *cons_dev_attrs[] = {
+ &dev_attr_active.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(cons_dev);
+
static struct device *consdev;
void console_sysfs_notify(void)
@@ -3617,12 +3630,11 @@ int __init tty_init(void)
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
- consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
- "console");
+ consdev = device_create_with_groups(tty_class, NULL,
+ MKDEV(TTYAUX_MAJOR, 1), NULL,
+ cons_dev_groups, "console");
if (IS_ERR(consdev))
consdev = NULL;
- else
- WARN_ON(device_create_file(consdev, &dev_attr_active) < 0);
#ifdef CONFIG_VT
vty_init(&console_fops);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index a5cf253b2544..632fc8152061 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -217,11 +217,17 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
#endif
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
- if (wait_event_interruptible_timeout(tty->write_wait,
- !tty_chars_in_buffer(tty), timeout) >= 0) {
- if (tty->ops->wait_until_sent)
- tty->ops->wait_until_sent(tty, timeout);
- }
+
+ timeout = wait_event_interruptible_timeout(tty->write_wait,
+ !tty_chars_in_buffer(tty), timeout);
+ if (timeout <= 0)
+ return;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT)
+ timeout = 0;
+
+ if (tty->ops->wait_until_sent)
+ tty->ops->wait_until_sent(tty, timeout);
}
EXPORT_SYMBOL(tty_wait_until_sent);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 6e00572cbeb9..4a24eb2b0ede 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1237,7 +1237,7 @@ static void default_attr(struct vc_data *vc)
struct rgb { u8 r; u8 g; u8 b; };
-struct rgb rgb_from_256(int i)
+static struct rgb rgb_from_256(int i)
{
struct rgb c;
if (i < 8) { /* Standard colours. */
@@ -1573,7 +1573,7 @@ static void setterm_command(struct vc_data *vc)
case 11: /* set bell duration in msec */
if (vc->vc_npar >= 1)
vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
- vc->vc_par[1] * HZ / 1000 : 0;
+ msecs_to_jiffies(vc->vc_par[1]) : 0;
else
vc->vc_bell_duration = DEFAULT_BELL_DURATION;
break;
@@ -3041,17 +3041,24 @@ static ssize_t show_tty_active(struct device *dev,
}
static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
+static struct attribute *vt_dev_attrs[] = {
+ &dev_attr_active.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(vt_dev);
+
int __init vty_init(const struct file_operations *console_fops)
{
cdev_init(&vc0_cdev, console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
- tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+ tty0dev = device_create_with_groups(tty_class, NULL,
+ MKDEV(TTY_MAJOR, 0), NULL,
+ vt_dev_groups, "tty0");
if (IS_ERR(tty0dev))
tty0dev = NULL;
- else
- WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0);
vcs_init();
@@ -3423,42 +3430,26 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
}
-static struct device_attribute device_attrs[] = {
- __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
- __ATTR(name, S_IRUGO, show_name, NULL),
+static DEVICE_ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *con_dev_attrs[] = {
+ &dev_attr_bind.attr,
+ &dev_attr_name.attr,
+ NULL
};
+ATTRIBUTE_GROUPS(con_dev);
+
static int vtconsole_init_device(struct con_driver *con)
{
- int i;
- int error = 0;
-
con->flag |= CON_DRIVER_FLAG_ATTR;
- dev_set_drvdata(con->dev, con);
- for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
- error = device_create_file(con->dev, &device_attrs[i]);
- if (error)
- break;
- }
-
- if (error) {
- while (--i >= 0)
- device_remove_file(con->dev, &device_attrs[i]);
- con->flag &= ~CON_DRIVER_FLAG_ATTR;
- }
-
- return error;
+ return 0;
}
static void vtconsole_deinit_device(struct con_driver *con)
{
- int i;
-
- if (con->flag & CON_DRIVER_FLAG_ATTR) {
- for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
- device_remove_file(con->dev, &device_attrs[i]);
- con->flag &= ~CON_DRIVER_FLAG_ATTR;
- }
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
}
/**
@@ -3621,11 +3612,11 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
if (retval)
goto err;
- con_driver->dev = device_create(vtconsole_class, NULL,
- MKDEV(0, con_driver->node),
- NULL, "vtcon%i",
- con_driver->node);
-
+ con_driver->dev =
+ device_create_with_groups(vtconsole_class, NULL,
+ MKDEV(0, con_driver->node),
+ con_driver, con_dev_groups,
+ "vtcon%i", con_driver->node);
if (IS_ERR(con_driver->dev)) {
printk(KERN_WARNING "Unable to create device for %s; "
"errno = %ld\n", con_driver->desc,
@@ -3739,10 +3730,11 @@ static int __init vtconsole_class_init(void)
struct con_driver *con = &registered_con_driver[i];
if (con->con && !con->dev) {
- con->dev = device_create(vtconsole_class, NULL,
- MKDEV(0, con->node),
- NULL, "vtcon%i",
- con->node);
+ con->dev =
+ device_create_with_groups(vtconsole_class, NULL,
+ MKDEV(0, con->node),
+ con, con_dev_groups,
+ "vtcon%i", con->node);
if (IS_ERR(con->dev)) {
printk(KERN_WARNING "Unable to create "
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 2bd78e2ac8ec..97d5a74558a3 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -388,7 +388,7 @@ int vt_ioctl(struct tty_struct *tty,
* Generate the tone for the appropriate number of ticks.
* If the time is zero, turn off sound ourselves.
*/
- ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+ ticks = msecs_to_jiffies((arg >> 16) & 0xffff);
count = ticks ? (arg & 0xffff) : 0;
if (count)
count = PIT_TICK_RATE / count;