summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/cyclades.c2
-rw-r--r--drivers/tty/goldfish.c68
-rw-r--r--drivers/tty/hvc/hvc_console.c9
-rw-r--r--drivers/tty/hvc/hvc_dcc.c42
-rw-r--r--drivers/tty/hvc/hvc_tile.c10
-rw-r--r--drivers/tty/ipwireless/tty.c5
-rw-r--r--drivers/tty/n_gsm.c22
-rw-r--r--drivers/tty/n_hdlc.c8
-rw-r--r--drivers/tty/n_tty.c21
-rw-r--r--drivers/tty/pty.c21
-rw-r--r--drivers/tty/serial/21285.c5
-rw-r--r--drivers/tty/serial/8250/8250.h2
-rw-r--r--drivers/tty/serial/8250/8250_core.c243
-rw-r--r--drivers/tty/serial/8250/8250_dma.c17
-rw-r--r--drivers/tty/serial/8250/8250_dw.c129
-rw-r--r--drivers/tty/serial/8250/8250_early.c139
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c3
-rw-r--r--drivers/tty/serial/8250/8250_pci.c25
-rw-r--r--drivers/tty/serial/8250/Kconfig6
-rw-r--r--drivers/tty/serial/Kconfig61
-rw-r--r--drivers/tty/serial/Makefile8
-rw-r--r--drivers/tty/serial/altera_jtaguart.c19
-rw-r--r--drivers/tty/serial/altera_uart.c19
-rw-r--r--drivers/tty/serial/amba-pl010.c50
-rw-r--r--drivers/tty/serial/amba-pl011.c63
-rw-r--r--drivers/tty/serial/apbuart.c6
-rw-r--r--drivers/tty/serial/ar933x_uart.c5
-rw-r--r--drivers/tty/serial/arc_uart.c339
-rw-r--r--drivers/tty/serial/atmel_serial.c240
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c2
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c17
-rw-r--r--drivers/tty/serial/bfin_uart.c24
-rw-r--r--drivers/tty/serial/clps711x.c1
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c17
-rw-r--r--drivers/tty/serial/crisv10.c15
-rw-r--r--drivers/tty/serial/dz.c8
-rw-r--r--drivers/tty/serial/earlycon-arm-semihost.c61
-rw-r--r--drivers/tty/serial/earlycon.c172
-rw-r--r--drivers/tty/serial/efm32-uart.c17
-rw-r--r--drivers/tty/serial/fsl_lpuart.c691
-rw-r--r--drivers/tty/serial/icom.c6
-rw-r--r--drivers/tty/serial/imx.c42
-rw-r--r--drivers/tty/serial/ioc3_serial.c1
-rw-r--r--drivers/tty/serial/ioc4_serial.c1
-rw-r--r--drivers/tty/serial/ip22zilog.c4
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c6
-rw-r--r--drivers/tty/serial/kgdb_nmi.c95
-rw-r--r--drivers/tty/serial/lantiq.c8
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c7
-rw-r--r--drivers/tty/serial/m32r_sio.c10
-rw-r--r--drivers/tty/serial/max310x.c3
-rw-r--r--drivers/tty/serial/mcf.c17
-rw-r--r--drivers/tty/serial/men_z135_uart.c867
-rw-r--r--drivers/tty/serial/mfd.c2
-rw-r--r--drivers/tty/serial/mpsc.c7
-rw-r--r--drivers/tty/serial/mrst_max3110.c5
-rw-r--r--drivers/tty/serial/msm_serial.c84
-rw-r--r--drivers/tty/serial/msm_serial.h9
-rw-r--r--drivers/tty/serial/mux.c15
-rw-r--r--drivers/tty/serial/mxs-auart.c12
-rw-r--r--drivers/tty/serial/netx-serial.c2
-rw-r--r--drivers/tty/serial/nwpserial.c6
-rw-r--r--drivers/tty/serial/of_serial.c5
-rw-r--r--drivers/tty/serial/omap-serial.c94
-rw-r--r--drivers/tty/serial/pch_uart.c22
-rw-r--r--drivers/tty/serial/pmac_zilog.c5
-rw-r--r--drivers/tty/serial/pnx8xxx_uart.c2
-rw-r--r--drivers/tty/serial/pxa.c9
-rw-r--r--drivers/tty/serial/samsung.c81
-rw-r--r--drivers/tty/serial/samsung.h23
-rw-r--r--drivers/tty/serial/sb1250-duart.c2
-rw-r--r--drivers/tty/serial/sc16is7xx.c1275
-rw-r--r--drivers/tty/serial/sccnxp.c14
-rw-r--r--drivers/tty/serial/serial-tegra.c4
-rw-r--r--drivers/tty/serial/serial_core.c74
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c143
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h110
-rw-r--r--drivers/tty/serial/serial_txx9.c14
-rw-r--r--drivers/tty/serial/sh-sci.c94
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c56
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h6
-rw-r--r--drivers/tty/serial/sn_console.c10
-rw-r--r--drivers/tty/serial/st-asc.c30
-rw-r--r--drivers/tty/serial/sunhv.c6
-rw-r--r--drivers/tty/serial/sunsab.c21
-rw-r--r--drivers/tty/serial/sunsu.c2
-rw-r--r--drivers/tty/serial/sunzilog.c4
-rw-r--r--drivers/tty/serial/tilegx.c18
-rw-r--r--drivers/tty/serial/timbuart.c6
-rw-r--r--drivers/tty/serial/uartlite.c23
-rw-r--r--drivers/tty/serial/ucc_uart.c13
-rw-r--r--drivers/tty/serial/vr41xx_siu.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c1131
-rw-r--r--drivers/tty/serial/zs.c2
-rw-r--r--drivers/tty/synclink.c10
-rw-r--r--drivers/tty/synclink_gt.c15
-rw-r--r--drivers/tty/synclinkmp.c11
-rw-r--r--drivers/tty/sysrq.c31
-rw-r--r--drivers/tty/tty_io.c39
-rw-r--r--drivers/tty/tty_port.c43
-rw-r--r--drivers/tty/vt/consolemap.c54
-rw-r--r--drivers/tty/vt/vt.c113
103 files changed, 5358 insertions, 2082 deletions
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index a57bb5ab761c..fd66f57390d0 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1579,7 +1579,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
/*
* If the port is the middle of closing, bail out now
*/
- if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
+ if (info->port.flags & ASYNC_CLOSING) {
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 75dc9d25f326..09495f515fa9 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/goldfish.h>
enum {
GOLDFISH_TTY_PUT_CHAR = 0x00,
@@ -29,6 +30,7 @@ enum {
GOLDFISH_TTY_DATA_PTR = 0x10,
GOLDFISH_TTY_DATA_LEN = 0x14,
+ GOLDFISH_TTY_DATA_PTR_HIGH = 0x18,
GOLDFISH_TTY_CMD_INT_DISABLE = 0,
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
@@ -57,7 +59,8 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
struct goldfish_tty *qtty = &goldfish_ttys[line];
void __iomem *base = qtty->base;
spin_lock_irqsave(&qtty->lock, irq_flags);
- writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
+ gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR,
+ base + GOLDFISH_TTY_DATA_PTR_HIGH);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
@@ -73,12 +76,13 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
u32 count;
count = readl(base + GOLDFISH_TTY_BYTES_READY);
- if(count == 0)
+ if (count == 0)
return IRQ_NONE;
count = tty_prepare_flip_string(&qtty->port, &buf, count);
spin_lock_irqsave(&qtty->lock, irq_flags);
- writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
+ gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR,
+ base + GOLDFISH_TTY_DATA_PTR_HIGH);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
@@ -88,24 +92,26 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
- struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
+ struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
+ port);
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
return 0;
}
static void goldfish_tty_shutdown(struct tty_port *port)
{
- struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
+ struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
+ port);
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
}
-static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
+static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
return tty_port_open(&qtty->port, tty, filp);
}
-static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
+static void goldfish_tty_close(struct tty_struct *tty, struct file *filp)
{
tty_port_close(tty->port, tty, filp);
}
@@ -115,7 +121,8 @@ static void goldfish_tty_hangup(struct tty_struct *tty)
tty_port_hangup(tty->port);
}
-static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
{
goldfish_tty_do_write(tty->index, buf, count);
return count;
@@ -133,12 +140,14 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
return readl(base + GOLDFISH_TTY_BYTES_READY);
}
-static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
+static void goldfish_tty_console_write(struct console *co, const char *b,
+ unsigned count)
{
goldfish_tty_do_write(co->index, b, count);
}
-static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
+static struct tty_driver *goldfish_tty_console_device(struct console *c,
+ int *index)
{
*index = c->index;
return goldfish_tty_driver;
@@ -146,9 +155,9 @@ static struct tty_driver *goldfish_tty_console_device(struct console *c, int *in
static int goldfish_tty_console_setup(struct console *co, char *options)
{
- if((unsigned)co->index > goldfish_tty_line_count)
+ if ((unsigned)co->index > goldfish_tty_line_count)
return -ENODEV;
- if(goldfish_ttys[co->index].base == 0)
+ if (goldfish_ttys[co->index].base == 0)
return -ENODEV;
return 0;
}
@@ -158,7 +167,7 @@ static struct tty_port_operations goldfish_port_ops = {
.shutdown = goldfish_tty_shutdown
};
-static struct tty_operations goldfish_tty_ops = {
+static const struct tty_operations goldfish_tty_ops = {
.open = goldfish_tty_open,
.close = goldfish_tty_close,
.hangup = goldfish_tty_hangup,
@@ -172,13 +181,14 @@ static int goldfish_tty_create_driver(void)
int ret;
struct tty_driver *tty;
- goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
- if(goldfish_ttys == NULL) {
+ goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) *
+ goldfish_tty_line_count, GFP_KERNEL);
+ if (goldfish_ttys == NULL) {
ret = -ENOMEM;
goto err_alloc_goldfish_ttys_failed;
}
tty = alloc_tty_driver(goldfish_tty_line_count);
- if(tty == NULL) {
+ if (tty == NULL) {
ret = -ENOMEM;
goto err_alloc_tty_driver_failed;
}
@@ -187,10 +197,11 @@ static int goldfish_tty_create_driver(void)
tty->type = TTY_DRIVER_TYPE_SERIAL;
tty->subtype = SERIAL_TYPE_NORMAL;
tty->init_termios = tty_std_termios;
- tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(tty, &goldfish_tty_ops);
ret = tty_register_driver(tty);
- if(ret)
+ if (ret)
goto err_tty_register_driver_failed;
goldfish_tty_driver = tty;
@@ -225,7 +236,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
u32 irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if(r == NULL)
+ if (r == NULL)
return -EINVAL;
base = ioremap(r->start, 0x1000);
@@ -233,18 +244,18 @@ static int goldfish_tty_probe(struct platform_device *pdev)
pr_err("goldfish_tty: unable to remap base\n");
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if(r == NULL)
+ if (r == NULL)
goto err_unmap;
irq = r->start;
- if(pdev->id >= goldfish_tty_line_count)
+ if (pdev->id >= goldfish_tty_line_count)
goto err_unmap;
mutex_lock(&goldfish_tty_lock);
- if(goldfish_tty_current_line_count == 0) {
+ if (goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver();
- if(ret)
+ if (ret)
goto err_create_driver_failed;
}
goldfish_tty_current_line_count++;
@@ -258,14 +269,15 @@ static int goldfish_tty_probe(struct platform_device *pdev)
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
- ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
- if(ret)
+ ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
+ "goldfish_tty", pdev);
+ if (ret)
goto err_request_irq_failed;
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
pdev->id, &pdev->dev);
- if(IS_ERR(ttydev)) {
+ if (IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed;
}
@@ -286,7 +298,7 @@ err_tty_register_device_failed:
free_irq(irq, pdev);
err_request_irq_failed:
goldfish_tty_current_line_count--;
- if(goldfish_tty_current_line_count == 0)
+ if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
err_create_driver_failed:
mutex_unlock(&goldfish_tty_lock);
@@ -308,7 +320,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)
qtty->base = 0;
free_irq(qtty->irq, pdev);
goldfish_tty_current_line_count--;
- if(goldfish_tty_current_line_count == 0)
+ if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock);
return 0;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 0ff7fda0742f..4fcec1d793a7 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -760,10 +760,17 @@ static int khvcd(void *unused)
if (poll_mask == 0)
schedule();
else {
+ unsigned long j_timeout;
+
if (timeout < MAX_TIMEOUT)
timeout += (timeout >> 6) + 1;
- msleep_interruptible(timeout);
+ /*
+ * We don't use msleep_interruptible otherwise
+ * "kick" will fail to wake us up
+ */
+ j_timeout = msecs_to_jiffies(timeout) + 1;
+ schedule_timeout_interruptible(j_timeout);
}
}
__set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index 3502a7bbb69e..809920d80a66 100644
--- a/drivers/tty/hvc/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -8,20 +8,11 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/err.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
+#include <asm/dcc.h>
#include <asm/processor.h>
#include "hvc_console.h"
@@ -30,35 +21,6 @@
#define DCC_STATUS_RX (1 << 30)
#define DCC_STATUS_TX (1 << 29)
-static inline u32 __dcc_getstatus(void)
-{
- u32 __ret;
- asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
- : "=r" (__ret) : : "cc");
-
- return __ret;
-}
-
-
-static inline char __dcc_getchar(void)
-{
- char __c;
-
- asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
- : "=r" (__c));
- isb();
-
- return __c;
-}
-
-static inline void __dcc_putchar(char c)
-{
- asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
- : /* no output register */
- : "r" (c));
- isb();
-}
-
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
{
int i;
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
index af8cdaa1dcb9..df374860037c 100644
--- a/drivers/tty/hvc/hvc_tile.c
+++ b/drivers/tty/hvc/hvc_tile.c
@@ -133,14 +133,14 @@ static int hvc_tile_probe(struct platform_device *pdev)
int tile_hvc_irq;
/* Create our IRQ and register it. */
- tile_hvc_irq = create_irq();
- if (tile_hvc_irq < 0)
+ tile_hvc_irq = irq_alloc_hwirq(-1);
+ if (!tile_hvc_irq)
return -ENXIO;
tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);
hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);
if (IS_ERR(hp)) {
- destroy_irq(tile_hvc_irq);
+ irq_free_hwirq(tile_hvc_irq);
return PTR_ERR(hp);
}
dev_set_drvdata(&pdev->dev, hp);
@@ -155,7 +155,7 @@ static int hvc_tile_remove(struct platform_device *pdev)
rc = hvc_remove(hp);
if (rc == 0)
- destroy_irq(hp->data);
+ irq_free_hwirq(hp->data);
return rc;
}
@@ -196,7 +196,7 @@ static int __init hvc_tile_init(void)
#ifndef __tilegx__
struct hvc_struct *hp;
hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
- return IS_ERR(hp) ? PTR_ERR(hp) : 0;
+ return PTR_ERR_OR_ZERO(hp);
#else
platform_device_register(&hvc_tile_pdev);
return platform_driver_register(&hvc_tile_driver);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 17ee3bf0926b..345cebb07ae7 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -93,11 +93,6 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
-
- if (tty->closing) {
- mutex_unlock(&tty->ipw_tty_mutex);
- return -ENODEV;
- }
if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 2ebe47b78a3e..c4343764cc5b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2088,9 +2088,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
struct gsm_dlci *dlci;
int i = 0;
- init_timer(&gsm->t2_timer);
- gsm->t2_timer.function = gsm_control_retransmit;
- gsm->t2_timer.data = (unsigned long)gsm;
+ setup_timer(&gsm->t2_timer, gsm_control_retransmit, (unsigned long)gsm);
init_waitqueue_head(&gsm->event);
spin_lock_init(&gsm->control_lock);
spin_lock_init(&gsm->tx_lock);
@@ -2230,8 +2228,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
{
- int ret, i;
- int base = gsm->num << 6; /* Base for this MUX */
+ int ret, i, base;
gsm->tty = tty_kref_get(tty);
gsm->output = gsmld_output;
@@ -2241,6 +2238,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
else {
/* Don't register device 0 - this is the control channel and not
a usable tty interface */
+ base = gsm->num << 6; /* Base for this MUX */
for (i = 1; i < NUM_DLCI; i++)
tty_register_device(gsm_tty_driver, base + i, NULL);
}
@@ -2368,6 +2366,7 @@ static void gsmld_close(struct tty_struct *tty)
static int gsmld_open(struct tty_struct *tty)
{
struct gsm_mux *gsm;
+ int ret;
if (tty->ops->write == NULL)
return -EINVAL;
@@ -2382,7 +2381,13 @@ static int gsmld_open(struct tty_struct *tty)
/* Attach the initial passive connection */
gsm->encoding = 1;
- return gsmld_attach_gsm(tty, gsm);
+
+ ret = gsmld_attach_gsm(tty, gsm);
+ if (ret != 0) {
+ gsm_cleanup_mux(gsm);
+ mux_put(gsm);
+ }
+ return ret;
}
/**
@@ -2789,9 +2794,8 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
netname = "gsm%d";
if (nc->if_name[0] != '\0')
netname = nc->if_name;
- net = alloc_netdev(sizeof(struct gsm_mux_net),
- netname,
- gsm_mux_net_init);
+ net = alloc_netdev(sizeof(struct gsm_mux_net), netname,
+ NET_NAME_UNKNOWN, gsm_mux_net_init);
if (!net) {
pr_err("alloc_netdev failed");
return -ENOMEM;
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 1b2db9a3038c..644ddb841d9f 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -848,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)
{
struct n_hdlc_buf *buf;
int i;
- struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
+ struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
if (!n_hdlc)
return NULL;
- memset(n_hdlc, 0, sizeof(*n_hdlc));
-
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
@@ -952,8 +950,6 @@ static char hdlc_register_ok[] __initdata =
KERN_INFO "N_HDLC line discipline registered.\n";
static char hdlc_register_fail[] __initdata =
KERN_ERR "error registering line discipline: %d\n";
-static char hdlc_init_fail[] __initdata =
- KERN_INFO "N_HDLC: init failure %d\n";
static int __init n_hdlc_init(void)
{
@@ -973,8 +969,6 @@ static int __init n_hdlc_init(void)
else
printk(hdlc_register_fail, status);
- if (status)
- printk(hdlc_init_fail, status);
return status;
} /* end of init_module() */
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index fe9d129c8735..f44f1ba762c3 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1214,15 +1214,16 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
- if (I_IGNPAR(tty))
- return;
- if (I_PARMRK(tty)) {
- put_tty_queue('\377', ldata);
- put_tty_queue('\0', ldata);
- put_tty_queue(c, ldata);
- } else if (I_INPCK(tty))
- put_tty_queue('\0', ldata);
- else
+ if (I_INPCK(tty)) {
+ if (I_IGNPAR(tty))
+ return;
+ if (I_PARMRK(tty)) {
+ put_tty_queue('\377', ldata);
+ put_tty_queue('\0', ldata);
+ put_tty_queue(c, ldata);
+ } else
+ put_tty_queue('\0', ldata);
+ } else
put_tty_queue(c, ldata);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
@@ -2041,7 +2042,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (found)
clear_bit(eol, ldata->read_flags);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
ldata->read_tail += c;
if (found) {
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 25c9bc783722..9bbdb1de12e2 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -316,7 +316,7 @@ done:
* pty_common_install - set up the pty pair
* @driver: the pty driver
* @tty: the tty being instantiated
- * @bool: legacy, true if this is BSD style
+ * @legacy: true if this is BSD style
*
* Perform the initial set up for the tty/pty pair. Called from the
* tty layer when the port is first opened.
@@ -331,18 +331,17 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
int idx = tty->index;
int retval = -ENOMEM;
- o_tty = alloc_tty_struct();
- if (!o_tty)
- goto err;
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
if (!ports[0] || !ports[1])
- goto err_free_tty;
+ goto err;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
- goto err_free_tty;
+ goto err;
}
- initialize_tty_struct(o_tty, driver->other, idx);
+ o_tty = alloc_tty_struct(driver->other, idx);
+ if (!o_tty)
+ goto err_put_module;
if (legacy) {
/* We always use new tty termios data so we can do this
@@ -387,12 +386,12 @@ err_free_termios:
tty_free_termios(tty);
err_deinit_tty:
deinitialize_tty_struct(o_tty);
- module_put(o_tty->driver->owner);
-err_free_tty:
- kfree(ports[0]);
- kfree(ports[1]);
free_tty_struct(o_tty);
+err_put_module:
+ module_put(driver->other->owner);
err:
+ kfree(ports[0]);
+ kfree(ports[1]);
return retval;
}
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index c7e8b60b6177..9b208bd686e6 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -78,10 +78,6 @@ static void serial21285_stop_rx(struct uart_port *port)
}
}
-static void serial21285_enable_ms(struct uart_port *port)
-{
-}
-
static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
@@ -345,7 +341,6 @@ static struct uart_ops serial21285_ops = {
.stop_tx = serial21285_stop_tx,
.start_tx = serial21285_start_tx,
.stop_rx = serial21285_stop_rx,
- .enable_ms = serial21285_enable_ms,
.break_ctl = serial21285_break_ctl,
.startup = serial21285_startup,
.shutdown = serial21285_shutdown,
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 1ebf8538b4fa..1b08c918cd51 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -12,6 +12,7 @@
*/
#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
#include <linux/dmaengine.h>
struct uart_8250_dma {
@@ -60,6 +61,7 @@ struct serial8250_config {
unsigned short fifo_size;
unsigned short tx_loadsz;
unsigned char fcr;
+ unsigned char rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE];
unsigned int flags;
};
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 2d4bd3929e50..1d42dba6121d 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_reg.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
@@ -161,6 +160,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO,
},
[PORT_CIRRUS] = {
@@ -180,6 +180,7 @@ static const struct serial8250_config uart_config[] = {
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_00,
+ .rxtrig_bytes = {8, 16, 24, 28},
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_16750] = {
@@ -188,6 +189,7 @@ static const struct serial8250_config uart_config[] = {
.tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
UART_FCR7_64BYTE,
+ .rxtrig_bytes = {1, 16, 32, 56},
.flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE,
},
[PORT_STARTECH] = {
@@ -209,6 +211,7 @@ static const struct serial8250_config uart_config[] = {
.tx_loadsz = 32,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_10,
+ .rxtrig_bytes = {8, 16, 56, 60},
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
[PORT_16850] = {
@@ -266,6 +269,7 @@ static const struct serial8250_config uart_config[] = {
.tx_loadsz = 8,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
UART_FCR_T_TRIG_01,
+ .rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO | UART_CAP_RTOIE,
},
[PORT_XR17D15X] = {
@@ -439,8 +443,7 @@ static int exar_handle_irq(struct uart_port *port);
static void set_io_from_upio(struct uart_port *p)
{
- struct uart_8250_port *up =
- container_of(p, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(p);
up->dl_read = default_serial_dl_read;
up->dl_write = default_serial_dl_write;
@@ -531,11 +534,8 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
- unsigned char fcr;
-
serial8250_clear_fifos(p);
- fcr = uart_config[p->port.type].fcr;
- serial_out(p, UART_FCR, fcr);
+ serial_out(p, UART_FCR, p->fcr);
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
@@ -1277,8 +1277,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
static void serial8250_stop_tx(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
__stop_tx(up);
@@ -1293,8 +1292,7 @@ static void serial8250_stop_tx(struct uart_port *port)
static void serial8250_start_tx(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
if (up->dma && !serial8250_tx_dma(up)) {
return;
@@ -1322,8 +1320,7 @@ static void serial8250_start_tx(struct uart_port *port)
static void serial8250_stop_rx(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
@@ -1332,8 +1329,7 @@ static void serial8250_stop_rx(struct uart_port *port)
static void serial8250_enable_ms(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1499,8 +1495,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
unsigned char status;
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
int dma_err = 0;
if (iir & UART_IIR_NO_INT)
@@ -1785,8 +1780,7 @@ static void serial8250_backup_timeout(unsigned long data)
static unsigned int serial8250_tx_empty(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned int lsr;
@@ -1800,8 +1794,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned int status;
unsigned int ret;
@@ -1821,8 +1814,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned char mcr = 0;
if (mctrl & TIOCM_RTS)
@@ -1843,8 +1835,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
@@ -1911,8 +1902,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
unsigned char c)
{
unsigned int ier;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/*
* First save the IER then disable the interrupts
@@ -1926,13 +1916,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
wait_for_xmitr(up, BOTH_EMPTY);
/*
* Send the character out.
- * If a LF, also do CR...
*/
serial_port_out(port, UART_TX, c);
- if (c == 10) {
- wait_for_xmitr(up, BOTH_EMPTY);
- serial_port_out(port, UART_TX, 13);
- }
/*
* Finally, wait for transmitter to become empty
@@ -1946,8 +1931,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
static int serial8250_startup(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned char lsr, iir;
int retval;
@@ -2199,8 +2183,7 @@ dont_test_tx_en:
static void serial8250_shutdown(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
/*
@@ -2273,12 +2256,10 @@ void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
- unsigned char cval, fcr = 0;
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char cval;
unsigned long flags;
unsigned int baud, quot;
- int fifo_bug = 0;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -2301,7 +2282,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
if (up->bugs & UART_BUG_PARITY)
- fifo_bug = 1;
+ up->fifo_bug = true;
}
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
@@ -2325,10 +2306,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
quot++;
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
- fcr = uart_config[port->type].fcr;
- if ((baud < 2400 && !up->dma) || fifo_bug) {
- fcr &= ~UART_FCR_TRIGGER_MASK;
- fcr |= UART_FCR_TRIGGER_1;
+ /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */
+ if ((baud < 2400 && !up->dma) || up->fifo_bug) {
+ up->fcr &= ~UART_FCR_TRIGGER_MASK;
+ up->fcr |= UART_FCR_TRIGGER_1;
}
}
@@ -2338,9 +2319,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
- * UART to respond. IOW, at least 32 bytes of FIFO.
+ * UART to respond. IOW, at least 32 bytes of FIFO. Also enable
+ * AFE if hw flow control is supported
*/
- if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
+ if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
+ (port->flags & UPF_HARD_FLOW)) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;
@@ -2360,7 +2343,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART_LSR_BI;
/*
@@ -2459,15 +2442,15 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* is written without DLAB set, this mode will be disabled.
*/
if (port->type == PORT_16750)
- serial_port_out(port, UART_FCR, fcr);
+ serial_port_out(port, UART_FCR, up->fcr);
serial_port_out(port, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
if (port->type != PORT_16750) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
- if (fcr & UART_FCR_ENABLE_FIFO)
+ if (up->fcr & UART_FCR_ENABLE_FIFO)
serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_port_out(port, UART_FCR, fcr); /* set fcr */
+ serial_port_out(port, UART_FCR, up->fcr); /* set fcr */
}
serial8250_set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
@@ -2501,8 +2484,7 @@ serial8250_set_ldisc(struct uart_port *port, int new)
void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_8250_port *p =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *p = up_to_u8250p(port);
serial8250_set_sleep(p, state != 0);
}
@@ -2633,8 +2615,7 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
static void serial8250_release_port(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
serial8250_release_std_resource(up);
if (port->type == PORT_RSA)
@@ -2643,8 +2624,7 @@ static void serial8250_release_port(struct uart_port *port)
static int serial8250_request_port(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
int ret;
if (port->type == PORT_8250_CIR)
@@ -2660,10 +2640,149 @@ static int serial8250_request_port(struct uart_port *port)
return ret;
}
-static void serial8250_config_port(struct uart_port *port, int flags)
+static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
+{
+ const struct serial8250_config *conf_type = &uart_config[up->port.type];
+ unsigned char bytes;
+
+ bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)];
+
+ return bytes ? bytes : -EOPNOTSUPP;
+}
+
+static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes)
{
+ const struct serial8250_config *conf_type = &uart_config[up->port.type];
+ int i;
+
+ if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)])
+ return -EOPNOTSUPP;
+
+ for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) {
+ if (bytes < conf_type->rxtrig_bytes[i])
+ /* Use the nearest lower value */
+ return (--i) << UART_FCR_R_TRIG_SHIFT;
+ }
+
+ return UART_FCR_R_TRIG_11;
+}
+
+static int do_get_rxtrig(struct tty_port *port)
+{
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ container_of(uport, struct uart_8250_port, port);
+
+ if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
+ return -EINVAL;
+
+ return fcr_get_rxtrig_bytes(up);
+}
+
+static int do_serial8250_get_rxtrig(struct tty_port *port)
+{
+ int rxtrig_bytes;
+
+ mutex_lock(&port->mutex);
+ rxtrig_bytes = do_get_rxtrig(port);
+ mutex_unlock(&port->mutex);
+
+ return rxtrig_bytes;
+}
+
+static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tty_port *port = dev_get_drvdata(dev);
+ int rxtrig_bytes;
+
+ rxtrig_bytes = do_serial8250_get_rxtrig(port);
+ if (rxtrig_bytes < 0)
+ return rxtrig_bytes;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes);
+}
+
+static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
+{
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
+ struct uart_8250_port *up =
+ container_of(uport, struct uart_8250_port, port);
+ int rxtrig;
+
+ if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
+ up->fifo_bug)
+ return -EINVAL;
+
+ rxtrig = bytes_to_fcr_rxtrig(up, bytes);
+ if (rxtrig < 0)
+ return rxtrig;
+
+ serial8250_clear_fifos(up);
+ up->fcr &= ~UART_FCR_TRIGGER_MASK;
+ up->fcr |= (unsigned char)rxtrig;
+ serial_out(up, UART_FCR, up->fcr);
+ return 0;
+}
+
+static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes)
+{
+ int ret;
+
+ mutex_lock(&port->mutex);
+ ret = do_set_rxtrig(port, bytes);
+ mutex_unlock(&port->mutex);
+
+ return ret;
+}
+
+static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tty_port *port = dev_get_drvdata(dev);
+ unsigned char bytes;
+ int ret;
+
+ if (!count)
+ return -EINVAL;
+
+ ret = kstrtou8(buf, 10, &bytes);
+ if (ret < 0)
+ return ret;
+
+ ret = do_serial8250_set_rxtrig(port, bytes);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP,
+ serial8250_get_attr_rx_trig_bytes,
+ serial8250_set_attr_rx_trig_bytes);
+
+static struct attribute *serial8250_dev_attrs[] = {
+ &dev_attr_rx_trig_bytes.attr,
+ NULL,
+ };
+
+static struct attribute_group serial8250_dev_attr_group = {
+ .attrs = serial8250_dev_attrs,
+ };
+
+static void register_dev_spec_attr_grp(struct uart_8250_port *up)
+{
+ const struct serial8250_config *conf_type = &uart_config[up->port.type];
+
+ if (conf_type->rxtrig_bytes[0])
+ up->port.attr_group = &serial8250_dev_attr_group;
+}
+
+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;
@@ -2708,6 +2827,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if ((port->type == PORT_XR17V35X) ||
(port->type == PORT_XR17D15X))
port->handle_irq = exar_handle_irq;
+
+ register_dev_spec_attr_grp(up);
+ up->fcr = uart_config[up->port.type].fcr;
}
static int
@@ -2862,8 +2984,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
static void serial8250_console_putchar(struct uart_port *port, int ch)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
wait_for_xmitr(up, UART_LSR_THRE);
serial_port_out(port, UART_TX, ch);
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index ab9096dc3849..148ffe4c232f 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -192,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
- if (!dma->rx_buf) {
- dma_release_channel(dma->rxchan);
- dma_release_channel(dma->txchan);
- return -ENOMEM;
- }
+ if (!dma->rx_buf)
+ goto err;
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
+ if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
+ dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
+ dma->rx_buf, dma->rx_addr);
+ goto err;
+ }
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
return 0;
+err:
+ dma_release_channel(dma->rxchan);
+ dma_release_channel(dma->txchan);
+
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(serial8250_request_dma);
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index ed3113576740..4db7987ec225 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/clk.h>
+#include <linux/reset.h>
#include <linux/pm_runtime.h>
#include <asm/byteorder.h>
@@ -59,9 +60,17 @@ struct dw8250_data {
int last_mcr;
int line;
struct clk *clk;
+ struct clk *pclk;
+ struct reset_control *rst;
struct uart_8250_dma dma;
};
+#define BYT_PRV_CLK 0x800
+#define BYT_PRV_CLK_EN (1 << 0)
+#define BYT_PRV_CLK_M_VAL_SHIFT 1
+#define BYT_PRV_CLK_N_VAL_SHIFT 16
+#define BYT_PRV_CLK_UPDATE (1 << 31)
+
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -77,8 +86,9 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
static void dw8250_force_idle(struct uart_port *p)
{
- serial8250_clear_and_reinit_fifos(container_of
- (p, struct uart_8250_port, port));
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ serial8250_clear_and_reinit_fifos(up);
(void)p->serial_in(p, UART_RX);
}
@@ -178,6 +188,32 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
pm_runtime_put_sync_suspend(port->dev);
}
+static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud = tty_termios_baud_rate(termios);
+ struct dw8250_data *d = p->private_data;
+ unsigned int rate;
+ int ret;
+
+ if (IS_ERR(d->clk) || !old)
+ goto out;
+
+ /* Not requesting clock rates below 1.8432Mhz */
+ if (baud < 115200)
+ baud = 115200;
+
+ clk_disable_unprepare(d->clk);
+ rate = clk_round_rate(d->clk, baud * 16);
+ ret = clk_set_rate(d->clk, rate);
+ clk_prepare_enable(d->clk);
+
+ if (!ret)
+ p->uartclk = rate;
+out:
+ serial8250_do_set_termios(p, termios, old);
+}
+
static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
{
struct dw8250_data *data = param;
@@ -222,6 +258,7 @@ static int dw8250_probe_of(struct uart_port *p,
struct dw8250_data *data)
{
struct device_node *np = p->dev->of_node;
+ struct uart_8250_port *up = up_to_u8250p(p);
u32 val;
bool has_ucv = true;
@@ -235,7 +272,7 @@ static int dw8250_probe_of(struct uart_port *p,
p->membase += 7;
#endif
p->serial_out = dw8250_serial_out_rb;
- p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
data->usr_reg = 0x27;
has_ucv = false;
@@ -254,7 +291,7 @@ static int dw8250_probe_of(struct uart_port *p,
}
}
if (has_ucv)
- dw8250_setup_port(container_of(p, struct uart_8250_port, port));
+ dw8250_setup_port(up);
if (!of_property_read_u32(np, "reg-shift", &val))
p->regshift = val;
@@ -276,28 +313,22 @@ 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;
-
p->iotype = UPIO_MEM32;
p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
- if (!p->uartclk)
- p->uartclk = (unsigned int)id->driver_data;
-
up->dma = &data->dma;
up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
+ up->port.set_termios = dw8250_set_termios;
+
return 0;
}
@@ -333,11 +364,40 @@ static int dw8250_probe(struct platform_device *pdev)
return -ENOMEM;
data->usr_reg = DW_UART_USR;
- data->clk = devm_clk_get(&pdev->dev, NULL);
+ 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)) {
- clk_prepare_enable(data->clk);
- uart.port.uartclk = clk_get_rate(data->clk);
+ err = clk_prepare_enable(data->clk);
+ if (err)
+ dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
+ err);
+ else
+ uart.port.uartclk = clk_get_rate(data->clk);
+ }
+
+ data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+ if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
+ err = -EPROBE_DEFER;
+ goto err_clk;
+ }
+ if (!IS_ERR(data->pclk)) {
+ err = clk_prepare_enable(data->pclk);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable apb_pclk\n");
+ goto err_clk;
+ }
+ }
+
+ data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
+ if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
+ err = -EPROBE_DEFER;
+ goto err_pclk;
}
+ if (!IS_ERR(data->rst))
+ reset_control_deassert(data->rst);
data->dma.rx_chan_id = -1;
data->dma.tx_chan_id = -1;
@@ -353,18 +413,21 @@ static int dw8250_probe(struct platform_device *pdev)
if (pdev->dev.of_node) {
err = dw8250_probe_of(&uart.port, data);
if (err)
- return err;
+ goto err_reset;
} else if (ACPI_HANDLE(&pdev->dev)) {
err = dw8250_probe_acpi(&uart, data);
if (err)
- return err;
+ goto err_reset;
} else {
- return -ENODEV;
+ err = -ENODEV;
+ goto err_reset;
}
data->line = serial8250_register_8250_port(&uart);
- if (data->line < 0)
- return data->line;
+ if (data->line < 0) {
+ err = data->line;
+ goto err_reset;
+ }
platform_set_drvdata(pdev, data);
@@ -372,6 +435,20 @@ static int dw8250_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
+
+err_reset:
+ if (!IS_ERR(data->rst))
+ reset_control_assert(data->rst);
+
+err_pclk:
+ if (!IS_ERR(data->pclk))
+ clk_disable_unprepare(data->pclk);
+
+err_clk:
+ if (!IS_ERR(data->clk))
+ clk_disable_unprepare(data->clk);
+
+ return err;
}
static int dw8250_remove(struct platform_device *pdev)
@@ -382,6 +459,12 @@ static int dw8250_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line);
+ if (!IS_ERR(data->rst))
+ reset_control_assert(data->rst);
+
+ if (!IS_ERR(data->pclk))
+ clk_disable_unprepare(data->pclk);
+
if (!IS_ERR(data->clk))
clk_disable_unprepare(data->clk);
@@ -419,6 +502,9 @@ static int dw8250_runtime_suspend(struct device *dev)
if (!IS_ERR(data->clk))
clk_disable_unprepare(data->clk);
+ if (!IS_ERR(data->pclk))
+ clk_disable_unprepare(data->pclk);
+
return 0;
}
@@ -426,6 +512,9 @@ static int dw8250_runtime_resume(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
+ if (!IS_ERR(data->pclk))
+ clk_prepare_enable(data->pclk);
+
if (!IS_ERR(data->clk))
clk_prepare_enable(data->clk);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index c100d6343d50..4858b8a99d3b 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -35,18 +35,8 @@
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
-#ifdef CONFIG_FIX_EARLYCON_MEM
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#endif
-struct early_serial8250_device {
- struct uart_port port;
- char options[16]; /* e.g., 115200n8 */
- unsigned int baud;
-};
-
-static struct early_serial8250_device early_device;
+static struct earlycon_device *early_device;
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
{
@@ -100,7 +90,7 @@ 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 uart_port *port = &early_device->port;
unsigned int ier;
/* Save the IER and disable interrupts */
@@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
return (port->uartclk / 16) / quot;
}
-static void __init init_port(struct early_serial8250_device *device)
+static void __init init_port(struct earlycon_device *device)
{
struct uart_port *port = &device->port;
unsigned int divisor;
@@ -148,128 +138,45 @@ static void __init init_port(struct early_serial8250_device *device)
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
-static int __init parse_options(struct early_serial8250_device *device,
- char *options)
+static int __init early_serial8250_setup(struct earlycon_device *device,
+ const char *options)
{
- struct uart_port *port = &device->port;
- int mmio, mmio32, length;
-
- if (!options)
- return -ENODEV;
-
- port->uartclk = BASE_BAUD * 16;
-
- mmio = !strncmp(options, "mmio,", 5);
- mmio32 = !strncmp(options, "mmio32,", 7);
- if (mmio || mmio32) {
- port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
- port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
- &options, 0);
- if (mmio32)
- port->regshift = 2;
-#ifdef CONFIG_FIX_EARLYCON_MEM
- set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
- port->mapbase & PAGE_MASK);
- port->membase =
- (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
- port->membase += port->mapbase & ~PAGE_MASK;
-#else
- port->membase = ioremap_nocache(port->mapbase, 64);
- if (!port->membase) {
- printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
- __func__,
- (unsigned long long) port->mapbase);
- return -ENOMEM;
- }
-#endif
- } else if (!strncmp(options, "io,", 3)) {
- port->iotype = UPIO_PORT;
- port->iobase = simple_strtoul(options + 3, &options, 0);
- mmio = 0;
- } else
- return -EINVAL;
+ if (!(device->port.membase || device->port.iobase))
+ return 0;
- options = strchr(options, ',');
- if (options) {
- options++;
- device->baud = simple_strtoul(options, NULL, 0);
- length = min(strcspn(options, " ") + 1,
- (size_t)(sizeof(device->options)));
- strlcpy(device->options, options, length);
- } else {
- device->baud = probe_baud(port);
+ if (!device->baud) {
+ device->baud = probe_baud(&device->port);
snprintf(device->options, sizeof(device->options), "%u",
- device->baud);
+ device->baud);
}
- if (mmio || mmio32)
- printk(KERN_INFO
- "Early serial console at MMIO%s 0x%llx (options '%s')\n",
- mmio32 ? "32" : "",
- (unsigned long long)port->mapbase,
- device->options);
- else
- printk(KERN_INFO
- "Early serial console at I/O port 0x%lx (options '%s')\n",
- port->iobase,
- device->options);
-
- return 0;
-}
-
-static struct console early_serial8250_console __initdata = {
- .name = "uart",
- .write = early_serial8250_write,
- .flags = CON_PRINTBUFFER | CON_BOOT,
- .index = -1,
-};
-
-static int __init early_serial8250_setup(char *options)
-{
- struct early_serial8250_device *device = &early_device;
- int err;
-
- if (device->port.membase || device->port.iobase)
- return 0;
-
- err = parse_options(device, options);
- if (err < 0)
- return err;
-
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 *options;
- int err;
+ char match[] = "uart8250";
- options = strstr(cmdline, "uart8250,");
- if (!options) {
- options = strstr(cmdline, "uart,");
- if (!options)
- return 0;
- }
-
- options = strchr(cmdline, ',') + 1;
- err = early_serial8250_setup(options);
- if (err < 0)
- return err;
-
- register_console(&early_serial8250_console);
+ if (cmdline && cmdline[4] == ',')
+ match[4] = '\0';
- return 0;
+ return setup_earlycon(cmdline, match, early_serial8250_setup);
}
int serial8250_find_port_for_earlycon(void)
{
- struct early_serial8250_device *device = &early_device;
- struct uart_port *port = &device->port;
+ struct earlycon_device *device = early_device;
+ struct uart_port *port = device ? &device->port : NULL;
int line;
int ret;
- if (!device->port.membase && !device->port.iobase)
+ if (!port || (!port->membase && !port->iobase))
return -ENODEV;
line = serial8250_find_port(port);
@@ -284,5 +191,3 @@ int serial8250_find_port_for_earlycon(void)
return ret;
}
-
-early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index f4d3c47b88e8..c0533a57ec53 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -28,8 +28,7 @@ int fsl8250_handle_irq(struct uart_port *port)
unsigned char lsr, orig_lsr;
unsigned long flags;
unsigned int iir;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
spin_lock_irqsave(&up->port.lock, flags);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index b14bcba96c25..61830b1792eb 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1581,8 +1581,7 @@ static int skip_tx_en_setup(struct serial_private *priv,
static void kt_handle_break(struct uart_port *p)
{
- struct uart_8250_port *up =
- container_of(p, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(p);
/*
* On receipt of a BI, serial device in Intel ME (Intel
* management engine) needs to have its fifos cleared for sane
@@ -1593,8 +1592,7 @@ static void kt_handle_break(struct uart_port *p)
static unsigned int kt_serial_in(struct uart_port *p, int offset)
{
- struct uart_8250_port *up =
- container_of(p, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(p);
unsigned int val;
/*
@@ -1753,6 +1751,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
+#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
+#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
#define PCI_DEVICE_ID_TITAN_200I 0x8028
#define PCI_DEVICE_ID_TITAN_400I 0x8048
#define PCI_DEVICE_ID_TITAN_800I 0x8088
@@ -1778,6 +1778,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
@@ -2410,6 +2411,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
},
+ /* WCH CH353 1S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_1S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
/* WCH CH353 2S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
@@ -3526,6 +3535,7 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
+ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
};
/*
@@ -3880,6 +3890,13 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
pbn_b2_8_921600 },
+ /* Advantech also use 0x3618 and 0xf618 */
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 23329918f229..349ee598b34c 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
---help---
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
@@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE
If unsure, say N.
-config FIX_EARLYCON_MEM
- bool
- depends on X86
- default y
-
config SERIAL_8250_GSC
tristate
depends on SERIAL_8250 && GSC
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 5d9b01aa54f4..26cec64dadd7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -7,6 +7,13 @@ if TTY
menu "Serial drivers"
depends on HAS_IOMEM
+config SERIAL_EARLYCON
+ bool
+ help
+ Support for early consoles with the earlycon parameter. This enables
+ the console before standard serial driver is probed. The console is
+ enabled when early_param is processed.
+
source "drivers/tty/serial/8250/Kconfig"
comment "Non-8250 serial port support"
@@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL011=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
---help---
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
@@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_EARLYCON_ARM_SEMIHOST
+ bool "Early console using ARM semihosting"
+ depends on ARM64 || ARM
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ help
+ Support for early debug console using ARM semihosting. This enables
+ the console before standard serial driver is probed. This is enabled
+ with "earlycon=smh" on the kernel command line. The console is
+ enabled when early_param is processed.
+
config SERIAL_SB1250_DUART
tristate "BCM1xxx on-chip DUART serial support"
depends on SIBYTE_SB1xxx_SOC=y
@@ -97,6 +117,7 @@ config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
depends on ARCH_AT91 || AVR32
select SERIAL_CORE
+ select SERIAL_MCTRL_GPIO
help
This enables the driver for the on-chip UARTs of the Atmel
AT91 and AT32 processors.
@@ -217,7 +238,6 @@ config SERIAL_SAMSUNG_UARTS_4
config SERIAL_SAMSUNG_UARTS
int
depends on PLAT_SAMSUNG
- default 6 if CPU_S5P6450
default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416
default 3
help
@@ -753,7 +773,7 @@ config SERIAL_HS_LPC32XX
config SERIAL_HS_LPC32XX_CONSOLE
bool "Enable LPC32XX high speed UART serial console"
- depends on SERIAL_HS_LPC32XX
+ depends on SERIAL_HS_LPC32XX=y
select SERIAL_CORE_CONSOLE
help
If you would like to be able to use one of the high speed serial
@@ -1160,6 +1180,16 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
+config SERIAL_SC16IS7XX
+ tristate "SC16IS7xx serial support"
+ depends on I2C
+ select SERIAL_CORE
+ select REGMAP_I2C if I2C
+ help
+ This selects support for SC16IS7xx serial ports.
+ Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
+ SC16IS760 and SC16IS762.
+
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
@@ -1323,7 +1353,7 @@ config SERIAL_IFX6X60
config SERIAL_PCH_UART
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
select SERIAL_CORE
help
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
@@ -1369,18 +1399,19 @@ config SERIAL_MXS_AUART_CONSOLE
Enable a MXS AUART port to be the system console.
config SERIAL_XILINX_PS_UART
- tristate "Xilinx PS UART support"
+ tristate "Cadence (Xilinx Zynq) UART support"
depends on OF
select SERIAL_CORE
help
- This driver supports the Xilinx PS UART port.
+ This driver supports the Cadence UART. It is found e.g. in Xilinx
+ Zynq.
config SERIAL_XILINX_PS_UART_CONSOLE
- bool "Xilinx PS UART console support"
+ bool "Cadence UART console support"
depends on SERIAL_XILINX_PS_UART=y
select SERIAL_CORE_CONSOLE
help
- Enable a Xilinx PS UART port to be the system console.
+ Enable a Cadence UART port to be the system console.
config SERIAL_AR933X
tristate "AR933X serial port support"
@@ -1441,6 +1472,7 @@ config SERIAL_ARC_CONSOLE
bool "Console on ARC UART"
depends on SERIAL_ARC=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Enable system Console on ARC UART
@@ -1479,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS
config SERIAL_FSL_LPUART
tristate "Freescale lpuart serial port support"
+ depends on HAS_DMA
select SERIAL_CORE
help
Support for the on-chip lpuart on some Freescale SOCs.
@@ -1508,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE
depends on SERIAL_ST_ASC=y
select SERIAL_CORE_CONSOLE
+config SERIAL_MEN_Z135
+ tristate "MEN 16z135 Support"
+ select SERIAL_CORE
+ depends on MCB
+ help
+ Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core
+ on a MCB carrier.
+
+ This driver can also be build as a module. If so, the module will be called
+ men_z135_uart.ko
+
endmenu
+config SERIAL_MCTRL_GPIO
+ tristate
+
endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 3680854fef41..0080cc362e09 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -5,6 +5,9 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
+obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
+obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
+
# These Sparc drivers have to appear before others such as 8250
# which share ttySx minor node space. Otherwise console device
# names change and other unplesantries.
@@ -48,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
+obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@@ -87,3 +91,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
+obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
+
+# GPIOLIB helpers for modem control lines
+obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 59b3da9bcc3f..d22e3d98ae23 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -109,10 +109,6 @@ static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
{
}
-static void altera_jtaguart_enable_ms(struct uart_port *port)
-{
-}
-
static void altera_jtaguart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
@@ -291,7 +287,6 @@ static struct uart_ops altera_jtaguart_ops = {
.start_tx = altera_jtaguart_start_tx,
.stop_tx = altera_jtaguart_stop_tx,
.stop_rx = altera_jtaguart_stop_rx,
- .enable_ms = altera_jtaguart_enable_ms,
.break_ctl = altera_jtaguart_break_ctl,
.startup = altera_jtaguart_startup,
.shutdown = altera_jtaguart_shutdown,
@@ -309,9 +304,8 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
-static void altera_jtaguart_console_putc(struct console *co, const char c)
+static void altera_jtaguart_console_putc(struct uart_port *port, int c)
{
- struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long status;
unsigned long flags;
@@ -330,9 +324,8 @@ static void altera_jtaguart_console_putc(struct console *co, const char c)
spin_unlock_irqrestore(&port->lock, flags);
}
#else
-static void altera_jtaguart_console_putc(struct console *co, const char c)
+static void altera_jtaguart_console_putc(struct uart_port *port, int c)
{
- struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
@@ -350,11 +343,9 @@ static void altera_jtaguart_console_putc(struct console *co, const char c)
static void altera_jtaguart_console_write(struct console *co, const char *s,
unsigned int count)
{
- for (; count; count--, s++) {
- altera_jtaguart_console_putc(co, *s);
- if (*s == '\n')
- altera_jtaguart_console_putc(co, '\r');
- }
+ struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+
+ uart_console_write(port, s, count, altera_jtaguart_console_putc);
}
static int __init altera_jtaguart_console_setup(struct console *co,
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 501667e3e3f5..6a243239dbef 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -163,10 +163,6 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
-static void altera_uart_enable_ms(struct uart_port *port)
-{
-}
-
static void altera_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
@@ -185,6 +181,12 @@ static void altera_uart_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
spin_unlock_irqrestore(&port->lock, flags);
+
+ /*
+ * FIXME: port->read_status_mask and port->ignore_status_mask
+ * need to be initialized based on termios settings for
+ * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
+ */
}
static void altera_uart_rx_chars(struct altera_uart *pp)
@@ -409,7 +411,6 @@ static struct uart_ops altera_uart_ops = {
.start_tx = altera_uart_start_tx,
.stop_tx = altera_uart_stop_tx,
.stop_rx = altera_uart_stop_rx,
- .enable_ms = altera_uart_enable_ms,
.break_ctl = altera_uart_break_ctl,
.startup = altera_uart_startup,
.shutdown = altera_uart_shutdown,
@@ -429,7 +430,7 @@ static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
-static void altera_uart_console_putc(struct uart_port *port, const char c)
+static void altera_uart_console_putc(struct uart_port *port, int c)
{
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK))
@@ -443,11 +444,7 @@ static void altera_uart_console_write(struct console *co, const char *s,
{
struct uart_port *port = &(altera_uart_ports + co->index)->port;
- for (; count; count--, s++) {
- altera_uart_console_putc(port, *s);
- if (*s == '\n')
- altera_uart_console_putc(port, '\r');
- }
+ uart_console_write(port, s, count, altera_uart_console_putc);
}
static int __init altera_uart_console_setup(struct console *co, char *options)
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 01c9e72433e1..2064d31d0c8b 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -46,8 +46,7 @@
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/slab.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#define UART_NR 8
@@ -420,7 +419,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
uap->port.read_status_mask = UART01x_RSR_OE;
if (termios->c_iflag & INPCK)
uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
uap->port.read_status_mask |= UART01x_RSR_BE;
/*
@@ -688,28 +687,22 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
if (amba_ports[i] == NULL)
break;
- if (i == ARRAY_SIZE(amba_ports)) {
- ret = -EBUSY;
- goto out;
- }
+ if (i == ARRAY_SIZE(amba_ports))
+ return -EBUSY;
- uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
- if (!uap) {
- ret = -ENOMEM;
- goto out;
- }
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
+ if (!uap)
+ return -ENOMEM;
- base = ioremap(dev->res.start, resource_size(&dev->res));
- if (!base) {
- ret = -ENOMEM;
- goto free;
- }
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
+ if (!base)
+ return -ENOMEM;
- uap->clk = clk_get(&dev->dev, NULL);
- if (IS_ERR(uap->clk)) {
- ret = PTR_ERR(uap->clk);
- goto unmap;
- }
+ uap->clk = devm_clk_get(&dev->dev, NULL);
+ if (IS_ERR(uap->clk))
+ return PTR_ERR(uap->clk);
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
@@ -727,15 +720,9 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, uap);
ret = uart_add_one_port(&amba_reg, &uap->port);
- if (ret) {
+ if (ret)
amba_ports[i] = NULL;
- clk_put(uap->clk);
- unmap:
- iounmap(base);
- free:
- kfree(uap);
- }
- out:
+
return ret;
}
@@ -750,9 +737,6 @@ static int pl010_remove(struct amba_device *dev)
if (amba_ports[i] == uap)
amba_ports[i] = NULL;
- iounmap(uap->port.membase);
- clk_put(uap->clk);
- kfree(uap);
return 0;
}
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index dacf0a09ab24..8572f2a57fc8 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -303,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
-
+
if (!chan && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
@@ -1484,7 +1484,7 @@ static int pl011_hwinit(struct uart_port *port)
*/
retval = clk_prepare_enable(uap->clk);
if (retval)
- goto out;
+ return retval;
uap->port.uartclk = clk_get_rate(uap->clk);
@@ -1507,8 +1507,6 @@ static int pl011_hwinit(struct uart_port *port)
plat->init();
}
return 0;
- out:
- return retval;
}
static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
@@ -1744,7 +1742,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = UART011_DR_OE | 255;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART011_DR_BE;
/*
@@ -2045,6 +2043,35 @@ static struct console amba_console = {
};
#define AMBA_CONSOLE (&amba_console)
+
+static void pl011_putc(struct uart_port *port, int c)
+{
+ while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
+ ;
+ writeb(c, port->membase + UART01x_DR);
+ while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
+ ;
+}
+
+static void pl011_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, pl011_putc);
+}
+
+static int __init pl011_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = pl011_early_write;
+ return 0;
+}
+EARLYCON_DECLARE(pl011, pl011_early_console_setup);
+OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
+
#else
#define AMBA_CONSOLE NULL
#endif
@@ -2102,32 +2129,24 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (amba_ports[i] == NULL)
break;
- if (i == ARRAY_SIZE(amba_ports)) {
- ret = -EBUSY;
- goto out;
- }
+ if (i == ARRAY_SIZE(amba_ports))
+ return -EBUSY;
uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
GFP_KERNEL);
- if (uap == NULL) {
- ret = -ENOMEM;
- goto out;
- }
+ if (uap == NULL)
+ return -ENOMEM;
i = pl011_probe_dt_alias(i, &dev->dev);
base = devm_ioremap(&dev->dev, dev->res.start,
resource_size(&dev->res));
- if (!base) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!base)
+ return -ENOMEM;
uap->clk = devm_clk_get(&dev->dev, NULL);
- if (IS_ERR(uap->clk)) {
- ret = PTR_ERR(uap->clk);
- goto out;
- }
+ if (IS_ERR(uap->clk))
+ return PTR_ERR(uap->clk);
uap->vendor = vendor;
uap->lcrh_rx = vendor->lcrh_rx;
@@ -2169,7 +2188,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uart_unregister_driver(&amba_reg);
pl011_dma_remove(uap);
}
- out:
+
return ret;
}
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index de11ab8ffd91..a34a0cec1685 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -71,11 +71,6 @@ static void apbuart_stop_rx(struct uart_port *port)
UART_PUT_CTRL(port, cr);
}
-static void apbuart_enable_ms(struct uart_port *port)
-{
- /* No modem status change interrupts for APBUART */
-}
-
static void apbuart_rx_chars(struct uart_port *port)
{
unsigned int status, ch, rsr, flag;
@@ -337,7 +332,6 @@ static struct uart_ops grlib_apbuart_ops = {
.stop_tx = apbuart_stop_tx,
.start_tx = apbuart_start_tx,
.stop_rx = apbuart_stop_rx,
- .enable_ms = apbuart_enable_ms,
.break_ctl = apbuart_break_ctl,
.startup = apbuart_startup,
.shutdown = apbuart_shutdown,
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index acd03af7cd52..0be1c45efd65 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -176,10 +176,6 @@ static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&up->port.lock, flags);
}
-static void ar933x_uart_enable_ms(struct uart_port *port)
-{
-}
-
/*
* baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
*/
@@ -495,7 +491,6 @@ static struct uart_ops ar933x_uart_ops = {
.stop_tx = ar933x_uart_stop_tx,
.start_tx = ar933x_uart_start_tx,
.stop_rx = ar933x_uart_stop_rx,
- .enable_ms = ar933x_uart_enable_ms,
.break_ctl = ar933x_uart_break_ctl,
.startup = ar933x_uart_startup,
.shutdown = ar933x_uart_shutdown,
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index c9f5c9dcc15c..a59d1d77e750 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -37,8 +37,8 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
/*************************************
* ARC UART Hardware Specs
@@ -72,7 +72,7 @@
#define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */
/* Uart bit fiddling helpers: lowest level */
-#define RBASE(uart, reg) (uart->port.membase + reg)
+#define RBASE(port, reg) (port->membase + reg)
#define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r))
#define UART_REG_GET(u, r) readb(RBASE(u, r))
@@ -102,7 +102,6 @@
struct arc_uart_port {
struct uart_port port;
unsigned long baud;
- int is_emulated; /* H/w vs. Instruction Set Simulator */
};
#define to_arc_port(uport) container_of(uport, struct arc_uart_port, port)
@@ -129,19 +128,15 @@ static struct uart_driver arc_uart_driver = {
static void arc_serial_stop_rx(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
- UART_RX_IRQ_DISABLE(uart);
+ UART_RX_IRQ_DISABLE(port);
}
static void arc_serial_stop_tx(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
- while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ while (!(UART_GET_STATUS(port) & TXEMPTY))
cpu_relax();
- UART_TX_IRQ_DISABLE(uart);
+ UART_TX_IRQ_DISABLE(port);
}
/*
@@ -149,10 +144,9 @@ static void arc_serial_stop_tx(struct uart_port *port)
*/
static unsigned int arc_serial_tx_empty(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
unsigned int stat;
- stat = UART_GET_STATUS(uart);
+ stat = UART_GET_STATUS(port);
if (stat & TXEMPTY)
return TIOCSER_TEMT;
@@ -166,24 +160,24 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
* = by uart_start( ) before calling us
* = tx_ist checks that too before calling
*/
-static void arc_serial_tx_chars(struct arc_uart_port *uart)
+static void arc_serial_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &uart->port.state->xmit;
+ struct circ_buf *xmit = &port->state->xmit;
int sent = 0;
unsigned char ch;
- if (unlikely(uart->port.x_char)) {
- UART_SET_DATA(uart, uart->port.x_char);
- uart->port.icount.tx++;
- uart->port.x_char = 0;
+ if (unlikely(port->x_char)) {
+ UART_SET_DATA(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
sent = 1;
- } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */
+ } else if (!uart_circ_empty(xmit)) {
ch = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- uart->port.icount.tx++;
- while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ port->icount.tx++;
+ while (!(UART_GET_STATUS(port) & TXEMPTY))
cpu_relax();
- UART_SET_DATA(uart, ch);
+ UART_SET_DATA(port, ch);
sent = 1;
}
@@ -192,10 +186,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart)
* By Hard ISR to schedule processing in software interrupt part
*/
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&uart->port);
+ uart_write_wakeup(port);
if (sent)
- UART_TX_IRQ_ENABLE(uart);
+ UART_TX_IRQ_ENABLE(port);
}
/*
@@ -204,12 +198,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart)
*/
static void arc_serial_start_tx(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
- arc_serial_tx_chars(uart);
+ arc_serial_tx_chars(port);
}
-static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
+static void arc_serial_rx_chars(struct uart_port *port, unsigned int status)
{
unsigned int ch, flg = 0;
@@ -229,15 +221,15 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
*/
if (unlikely(status & (RXOERR | RXFERR))) {
if (status & RXOERR) {
- uart->port.icount.overrun++;
+ port->icount.overrun++;
flg = TTY_OVERRUN;
- UART_CLR_STATUS(uart, RXOERR);
+ UART_CLR_STATUS(port, RXOERR);
}
if (status & RXFERR) {
- uart->port.icount.frame++;
+ port->icount.frame++;
flg = TTY_FRAME;
- UART_CLR_STATUS(uart, RXFERR);
+ UART_CLR_STATUS(port, RXFERR);
}
} else
flg = TTY_NORMAL;
@@ -245,16 +237,16 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
if (status & RXEMPTY)
continue;
- ch = UART_GET_DATA(uart);
- uart->port.icount.rx++;
+ ch = UART_GET_DATA(port);
+ port->icount.rx++;
- if (!(uart_handle_sysrq_char(&uart->port, ch)))
- uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+ if (!(uart_handle_sysrq_char(port, ch)))
+ uart_insert_char(port, status, RXOERR, ch, flg);
- spin_unlock(&uart->port.lock);
- tty_flip_buffer_push(&uart->port.state->port);
- spin_lock(&uart->port.lock);
- } while (!((status = UART_GET_STATUS(uart)) & RXEMPTY));
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
+ } while (!((status = UART_GET_STATUS(port)) & RXEMPTY));
}
/*
@@ -287,10 +279,10 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
static irqreturn_t arc_serial_isr(int irq, void *dev_id)
{
- struct arc_uart_port *uart = dev_id;
+ struct uart_port *port = dev_id;
unsigned int status;
- status = UART_GET_STATUS(uart);
+ status = UART_GET_STATUS(port);
/*
* Single IRQ for both Rx (data available) Tx (room available) Interrupt
@@ -300,9 +292,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
if (status & RXIENB) {
/* already in ISR, no need of xx_irqsave */
- spin_lock(&uart->port.lock);
- arc_serial_rx_chars(uart, status);
- spin_unlock(&uart->port.lock);
+ spin_lock(&port->lock);
+ arc_serial_rx_chars(port, status);
+ spin_unlock(&port->lock);
}
if ((status & TXIENB) && (status & TXEMPTY)) {
@@ -310,14 +302,14 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
/* Unconditionally disable further Tx-Interrupts.
* will be enabled by tx_chars() if needed.
*/
- UART_TX_IRQ_DISABLE(uart);
+ UART_TX_IRQ_DISABLE(port);
- spin_lock(&uart->port.lock);
+ spin_lock(&port->lock);
- if (!uart_tx_stopped(&uart->port))
- arc_serial_tx_chars(uart);
+ if (!uart_tx_stopped(port))
+ arc_serial_tx_chars(port);
- spin_unlock(&uart->port.lock);
+ spin_unlock(&port->lock);
}
return IRQ_HANDLED;
@@ -340,13 +332,6 @@ static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
/* MCR not present */
}
-/* Enable Modem Status Interrupts */
-
-static void arc_serial_enable_ms(struct uart_port *port)
-{
- /* MSR not present */
-}
-
static void arc_serial_break_ctl(struct uart_port *port, int break_state)
{
/* ARC UART doesn't support sending Break signal */
@@ -354,18 +339,15 @@ static void arc_serial_break_ctl(struct uart_port *port, int break_state)
static int arc_serial_startup(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
/* Before we hook up the ISR, Disable all UART Interrupts */
- UART_ALL_IRQ_DISABLE(uart);
+ UART_ALL_IRQ_DISABLE(port);
- if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx",
- uart)) {
- dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n");
+ if (request_irq(port->irq, arc_serial_isr, 0, "arc uart rx-tx", port)) {
+ dev_warn(port->dev, "Unable to attach ARC UART intr\n");
return -EBUSY;
}
- UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */
+ UART_RX_IRQ_ENABLE(port); /* Only Rx IRQ enabled to begin with */
return 0;
}
@@ -373,8 +355,7 @@ static int arc_serial_startup(struct uart_port *port)
/* This is not really needed */
static void arc_serial_shutdown(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
- free_irq(uart->port.irq, uart);
+ free_irq(port->irq, port);
}
static void
@@ -398,25 +379,14 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
uartl = hw_val & 0xFF;
uarth = (hw_val >> 8) & 0xFF;
- /*
- * UART ISS(Instruction Set simulator) emulation has a subtle bug:
- * A existing value of Baudh = 0 is used as a indication to startup
- * it's internal state machine.
- * Thus if baudh is set to 0, 2 times, it chokes.
- * This happens with BAUD=115200 and the formaula above
- * Until that is fixed, when running on ISS, we will set baudh to !0
- */
- if (uart->is_emulated)
- uarth = 1;
-
spin_lock_irqsave(&port->lock, flags);
- UART_ALL_IRQ_DISABLE(uart);
+ UART_ALL_IRQ_DISABLE(port);
- UART_SET_BAUDL(uart, uartl);
- UART_SET_BAUDH(uart, uarth);
+ UART_SET_BAUDL(port, uartl);
+ UART_SET_BAUDH(port, uarth);
- UART_RX_IRQ_ENABLE(uart);
+ UART_RX_IRQ_ENABLE(port);
/*
* UART doesn't support Parity/Hardware Flow Control;
@@ -439,9 +409,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
static const char *arc_serial_type(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
- return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL;
+ return port->type == PORT_ARC ? DRIVER_NAME : NULL;
}
static void arc_serial_release_port(struct uart_port *port)
@@ -470,35 +438,28 @@ arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
*/
static void arc_serial_config_port(struct uart_port *port, int flags)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
if (flags & UART_CONFIG_TYPE)
- uart->port.type = PORT_ARC;
+ port->type = PORT_ARC;
}
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE)
+#ifdef CONFIG_CONSOLE_POLL
static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr)
{
- struct arc_uart_port *uart = to_arc_port(port);
-
- while (!(UART_GET_STATUS(uart) & TXEMPTY))
+ while (!(UART_GET_STATUS(port) & TXEMPTY))
cpu_relax();
- UART_SET_DATA(uart, chr);
+ UART_SET_DATA(port, chr);
}
-#endif
-#ifdef CONFIG_CONSOLE_POLL
static int arc_serial_poll_getchar(struct uart_port *port)
{
- struct arc_uart_port *uart = to_arc_port(port);
unsigned char chr;
- while (!(UART_GET_STATUS(uart) & RXEMPTY))
+ while (!(UART_GET_STATUS(port) & RXEMPTY))
cpu_relax();
- chr = UART_GET_DATA(uart);
+ chr = UART_GET_DATA(port);
return chr;
}
#endif
@@ -510,7 +471,6 @@ static struct uart_ops arc_serial_pops = {
.stop_tx = arc_serial_stop_tx,
.start_tx = arc_serial_start_tx,
.stop_rx = arc_serial_stop_rx,
- .enable_ms = arc_serial_enable_ms,
.break_ctl = arc_serial_break_ctl,
.startup = arc_serial_startup,
.shutdown = arc_serial_shutdown,
@@ -526,71 +486,6 @@ static struct uart_ops arc_serial_pops = {
#endif
};
-static int
-arc_uart_init_one(struct platform_device *pdev, int dev_id)
-{
- struct resource *res, *res2;
- unsigned long *plat_data;
- struct arc_uart_port *uart = &arc_uart_ports[dev_id];
-
- plat_data = dev_get_platdata(&pdev->dev);
- if (!plat_data)
- return -ENODEV;
-
- uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */
-
- if (is_early_platform_device(pdev)) {
- uart->port.uartclk = plat_data[1];
- uart->baud = plat_data[2];
- } else {
- struct device_node *np = pdev->dev.of_node;
- u32 val;
-
- if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(&pdev->dev, "clock-frequency property NOTset\n");
- return -EINVAL;
- }
- uart->port.uartclk = val;
-
- if (of_property_read_u32(np, "current-speed", &val)) {
- dev_err(&pdev->dev, "current-speed property NOT set\n");
- return -EINVAL;
- }
- uart->baud = val;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res2)
- return -ENODEV;
-
- uart->port.mapbase = res->start;
- uart->port.membase = ioremap_nocache(res->start, resource_size(res));
- if (!uart->port.membase)
- /* No point of dev_err since UART itself is hosed here */
- return -ENXIO;
-
- uart->port.irq = res2->start;
- uart->port.dev = &pdev->dev;
- uart->port.iotype = UPIO_MEM;
- uart->port.flags = UPF_BOOT_AUTOCONF;
- uart->port.line = dev_id;
- uart->port.ops = &arc_serial_pops;
-
- uart->port.fifosize = ARC_UART_TX_FIFO_SIZE;
-
- /*
- * uart_insert_char( ) uses it in decideding whether to ignore a
- * char or not. Explicitly setting it here, removes the subtelty
- */
- uart->port.ignore_status_mask = 0;
-
- return 0;
-}
-
#ifdef CONFIG_SERIAL_ARC_CONSOLE
static int arc_serial_console_setup(struct console *co, char *options)
@@ -624,7 +519,10 @@ static int arc_serial_console_setup(struct console *co, char *options)
static void arc_serial_console_putchar(struct uart_port *port, int ch)
{
- arc_serial_poll_putchar(port, (unsigned char)ch);
+ while (!(UART_GET_STATUS(port) & TXEMPTY))
+ cpu_relax();
+
+ UART_SET_DATA(port, (unsigned char)ch);
}
/*
@@ -651,48 +549,45 @@ static struct console arc_console = {
.data = &arc_uart_driver
};
-static __init void early_serial_write(struct console *con, const char *s,
- unsigned int n)
+static __init void arc_early_serial_write(struct console *con, const char *s,
+ unsigned int n)
{
- struct uart_port *port = &arc_uart_ports[con->index].port;
- unsigned int i;
+ struct earlycon_device *dev = con->data;
- for (i = 0; i < n; i++, s++) {
- if (*s == '\n')
- arc_serial_poll_putchar(port, '\r');
- arc_serial_poll_putchar(port, *s);
- }
+ uart_console_write(&dev->port, s, n, arc_serial_console_putchar);
}
-static struct console arc_early_serial_console __initdata = {
- .name = "early_ARCuart",
- .write = early_serial_write,
- .flags = CON_PRINTBUFFER | CON_BOOT,
- .index = -1
-};
-
-static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev)
+static int __init arc_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
{
- int dev_id = pdev->id < 0 ? 0 : pdev->id;
- int rc;
+ struct uart_port *port = &dev->port;
+ unsigned int l, h, hw_val;
- arc_early_serial_console.index = dev_id;
+ if (!dev->port.membase)
+ return -ENODEV;
- rc = arc_uart_init_one(pdev, dev_id);
- if (rc)
- panic("early console init failed\n");
+ hw_val = port->uartclk / (dev->baud * 4) - 1;
+ l = hw_val & 0xFF;
+ h = (hw_val >> 8) & 0xFF;
- arc_serial_console_setup(&arc_early_serial_console, NULL);
+ UART_SET_BAUDL(port, l);
+ UART_SET_BAUDH(port, h);
- register_console(&arc_early_serial_console);
+ dev->con->write = arc_early_serial_write;
return 0;
}
+EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
+OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
+
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
static int arc_serial_probe(struct platform_device *pdev)
{
- int rc, dev_id;
struct device_node *np = pdev->dev.of_node;
+ struct arc_uart_port *uart;
+ struct uart_port *port;
+ int dev_id;
+ u32 val;
/* no device tree device */
if (!np)
@@ -702,12 +597,43 @@ static int arc_serial_probe(struct platform_device *pdev)
if (dev_id < 0)
dev_id = 0;
- rc = arc_uart_init_one(pdev, dev_id);
- if (rc)
- return rc;
+ uart = &arc_uart_ports[dev_id];
+ port = &uart->port;
+
+ if (of_property_read_u32(np, "clock-frequency", &val)) {
+ dev_err(&pdev->dev, "clock-frequency property NOTset\n");
+ return -EINVAL;
+ }
+ port->uartclk = val;
+
+ if (of_property_read_u32(np, "current-speed", &val)) {
+ dev_err(&pdev->dev, "current-speed property NOT set\n");
+ return -EINVAL;
+ }
+ uart->baud = val;
+
+ port->membase = of_iomap(np, 0);
+ if (!port->membase)
+ /* No point of dev_err since UART itself is hosed here */
+ return -ENXIO;
+
+ port->irq = irq_of_parse_and_map(np, 0);
- rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);
- return rc;
+ port->dev = &pdev->dev;
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->line = dev_id;
+ port->ops = &arc_serial_pops;
+
+ port->fifosize = ARC_UART_TX_FIFO_SIZE;
+
+ /*
+ * uart_insert_char( ) uses it in decideding whether to ignore a
+ * char or not. Explicitly setting it here, removes the subtelty
+ */
+ port->ignore_status_mask = 0;
+
+ return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);
}
static int arc_serial_remove(struct platform_device *pdev)
@@ -732,27 +658,6 @@ static struct platform_driver arc_platform_driver = {
},
};
-#ifdef CONFIG_SERIAL_ARC_CONSOLE
-
-static struct platform_driver early_arc_platform_driver __initdata = {
- .probe = arc_serial_probe_earlyprintk,
- .remove = arc_serial_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-/*
- * Register an early platform driver of "earlyprintk" class.
- * ARCH platform code installs the driver and probes the early devices
- * The installation could rely on user specifying earlyprintk=xyx in cmd line
- * or it could be done independently, for all "earlyprintk" class drivers.
- * [see arch/arc/plat-arcfpga/platform.c]
- */
-early_platform_init("earlyprintk", &early_arc_platform_driver);
-
-#endif /* CONFIG_SERIAL_ARC_CONSOLE */
-
static int __init arc_serial_init(void)
{
int ret;
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 53eeea13ff16..7b63677475c1 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -43,6 +43,9 @@
#include <linux/platform_data/atmel.h>
#include <linux/timer.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/err.h>
+#include <linux/irq.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -57,6 +60,8 @@
#include <linux/serial_core.h>
+#include "serial_mctrl_gpio.h"
+
static void atmel_start_rx(struct uart_port *port);
static void atmel_stop_rx(struct uart_port *port);
@@ -162,8 +167,10 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct serial_rs485 rs485; /* rs485 settings */
- int rts_gpio; /* optional RTS GPIO */
+ struct mctrl_gpios *gpios;
+ int gpio_irq[UART_GPIO_MAX];
unsigned int tx_done_mask;
+ bool ms_irq_enabled;
bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
int (*prepare_rx)(struct uart_port *port);
@@ -237,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
return atmel_port->use_dma_rx;
}
+static unsigned int atmel_get_lines_status(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int status, ret = 0;
+
+ status = UART_GET_CSR(port);
+
+ mctrl_gpio_get(atmel_port->gpios, &ret);
+
+ if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+ UART_GPIO_CTS))) {
+ if (ret & TIOCM_CTS)
+ status &= ~ATMEL_US_CTS;
+ else
+ status |= ATMEL_US_CTS;
+ }
+
+ if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+ UART_GPIO_DSR))) {
+ if (ret & TIOCM_DSR)
+ status &= ~ATMEL_US_DSR;
+ else
+ status |= ATMEL_US_DSR;
+ }
+
+ if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+ UART_GPIO_RI))) {
+ if (ret & TIOCM_RI)
+ status &= ~ATMEL_US_RI;
+ else
+ status |= ATMEL_US_RI;
+ }
+
+ if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+ UART_GPIO_DCD))) {
+ if (ret & TIOCM_CD)
+ status &= ~ATMEL_US_DCD;
+ else
+ status |= ATMEL_US_DCD;
+ }
+
+ return status;
+}
+
/* Enable or disable the rs485 support */
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{
@@ -296,17 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
unsigned int mode;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- /*
- * AT91RM9200 Errata #39: RTS0 is not internally connected
- * to PA21. We need to drive the pin as a GPIO.
- */
- if (gpio_is_valid(atmel_port->rts_gpio)) {
- if (mctrl & TIOCM_RTS)
- gpio_set_value(atmel_port->rts_gpio, 0);
- else
- gpio_set_value(atmel_port->rts_gpio, 1);
- }
-
if (mctrl & TIOCM_RTS)
control |= ATMEL_US_RTSEN;
else
@@ -319,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
UART_PUT_CR(port, control);
+ mctrl_gpio_set(atmel_port->gpios, mctrl);
+
/* Local loopback mode? */
mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
if (mctrl & TIOCM_LOOP)
@@ -346,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
*/
static u_int atmel_get_mctrl(struct uart_port *port)
{
- unsigned int status, ret = 0;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int ret = 0, status;
status = UART_GET_CSR(port);
@@ -362,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
if (!(status & ATMEL_US_RI))
ret |= TIOCM_RI;
- return ret;
+ return mctrl_gpio_get(atmel_port->gpios, &ret);
}
/*
@@ -449,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
*/
static void atmel_enable_ms(struct uart_port *port)
{
- UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
- | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ uint32_t ier = 0;
+
+ /*
+ * Interrupt should not be enabled twice
+ */
+ if (atmel_port->ms_irq_enabled)
+ return;
+
+ atmel_port->ms_irq_enabled = true;
+
+ if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
+ else
+ ier |= ATMEL_US_CTSIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
+ else
+ ier |= ATMEL_US_DSRIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
+ else
+ ier |= ATMEL_US_RIIC;
+
+ if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
+ enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
+ else
+ ier |= ATMEL_US_DCDIC;
+
+ UART_PUT_IER(port, ier);
}
/*
@@ -633,7 +706,7 @@ static void atmel_release_tx_dma(struct uart_port *port)
dmaengine_terminate_all(chan);
dma_release_channel(chan);
dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
- DMA_MEM_TO_DEV);
+ DMA_TO_DEVICE);
}
atmel_port->desc_tx = NULL;
@@ -731,7 +804,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
nent = dma_map_sg(port->dev,
&atmel_port->sg_tx,
1,
- DMA_MEM_TO_DEV);
+ DMA_TO_DEVICE);
if (!nent) {
dev_dbg(port->dev, "need to release resource of dma\n");
@@ -810,7 +883,7 @@ static void atmel_release_rx_dma(struct uart_port *port)
dmaengine_terminate_all(chan);
dma_release_channel(chan);
dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
- DMA_DEV_TO_MEM);
+ DMA_FROM_DEVICE);
}
atmel_port->desc_rx = NULL;
@@ -895,7 +968,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
nent = dma_map_sg(port->dev,
&atmel_port->sg_rx,
1,
- DMA_DEV_TO_MEM);
+ DMA_FROM_DEVICE);
if (!nent) {
dev_dbg(port->dev, "need to release resource of dma\n");
@@ -1039,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
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;
+ bool gpio_handled = false;
do {
- status = UART_GET_CSR(port);
+ status = atmel_get_lines_status(port);
pending = status & UART_GET_IMR(port);
+ if (!gpio_handled) {
+ /*
+ * Dealing with GPIO interrupt
+ */
+ if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
+ pending |= ATMEL_US_CTSIC;
+
+ if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
+ pending |= ATMEL_US_DSRIC;
+
+ if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
+ pending |= ATMEL_US_RIIC;
+
+ if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
+ pending |= ATMEL_US_DCDIC;
+
+ gpio_handled = true;
+ }
if (!pending)
break;
@@ -1523,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
}
}
+static void atmel_free_gpio_irq(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ enum mctrl_gpio_idx i;
+
+ for (i = 0; i < UART_GPIO_MAX; i++)
+ if (atmel_port->gpio_irq[i] >= 0)
+ free_irq(atmel_port->gpio_irq[i], port);
+}
+
+static int atmel_request_gpio_irq(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int *irq = atmel_port->gpio_irq;
+ enum mctrl_gpio_idx i;
+ int err = 0;
+
+ for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
+ if (irq[i] < 0)
+ continue;
+
+ irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
+ err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
+ "atmel_serial", port);
+ if (err)
+ dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
+ irq[i]);
+ }
+
+ /*
+ * If something went wrong, rollback.
+ */
+ while (err && (--i >= 0))
+ if (irq[i] >= 0)
+ free_irq(irq[i], port);
+
+ return err;
+}
+
/*
* Perform initialization and enable port for reception
*/
@@ -1539,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
* handle an unexpected interrupt
*/
UART_PUT_IDR(port, -1);
+ atmel_port->ms_irq_enabled = false;
/*
* Allocate the IRQ
@@ -1551,6 +1684,13 @@ static int atmel_startup(struct uart_port *port)
}
/*
+ * Get the GPIO lines IRQ
+ */
+ retval = atmel_request_gpio_irq(port);
+ if (retval)
+ goto free_irq;
+
+ /*
* Initialize DMA (if necessary)
*/
atmel_init_property(atmel_port, pdev);
@@ -1568,7 +1708,7 @@ static int atmel_startup(struct uart_port *port)
}
/* Save current CSR for comparison in atmel_tasklet_func() */
- atmel_port->irq_status_prev = UART_GET_CSR(port);
+ atmel_port->irq_status_prev = atmel_get_lines_status(port);
atmel_port->irq_status = atmel_port->irq_status_prev;
/*
@@ -1614,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
+
+free_irq:
+ free_irq(port->irq, port);
+
+ return retval;
}
/*
@@ -1661,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
atmel_port->rx_ring.tail = 0;
/*
- * Free the interrupt
+ * Free the interrupts
*/
free_irq(port->irq, port);
+ atmel_free_gpio_irq(port);
+
+ atmel_port->ms_irq_enabled = false;
}
/*
@@ -1784,7 +1932,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = ATMEL_US_OVRE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= ATMEL_US_RXBRK;
if (atmel_use_pdc_rx(port))
@@ -2324,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
+static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
+{
+ enum mctrl_gpio_idx i;
+ struct gpio_desc *gpiod;
+
+ p->gpios = mctrl_gpio_init(dev, 0);
+ if (IS_ERR_OR_NULL(p->gpios))
+ return -1;
+
+ for (i = 0; i < UART_GPIO_MAX; i++) {
+ gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
+ if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
+ p->gpio_irq[i] = gpiod_to_irq(gpiod);
+ else
+ p->gpio_irq[i] = -EINVAL;
+ }
+
+ return 0;
+}
+
static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
@@ -2359,25 +2527,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
port = &atmel_ports[ret];
port->backup_imr = 0;
port->uart.line = ret;
- port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
- if (pdata)
- port->rts_gpio = pdata->rts_gpio;
- else if (np)
- port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
-
- if (gpio_is_valid(port->rts_gpio)) {
- ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
- if (ret) {
- dev_err(&pdev->dev, "error requesting RTS GPIO\n");
- goto err;
- }
- /* Default to 1 as RTS is active low */
- ret = gpio_direction_output(port->rts_gpio, 1);
- if (ret) {
- dev_err(&pdev->dev, "error setting up RTS GPIO\n");
- goto err;
- }
- }
+
+ 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");
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 a47421e4627c..231519022b73 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -567,7 +567,7 @@ static void bcm_uart_set_termios(struct uart_port *port,
port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
port->read_status_mask |= UART_FIFO_PARERR_MASK;
}
- if (new->c_iflag & (BRKINT))
+ if (new->c_iflag & (IGNBRK | BRKINT))
port->read_status_mask |= UART_FIFO_BRKDET_MASK;
port->ignore_status_mask = 0;
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index 4f229703328b..7810aa290edf 100644
--- a/drivers/tty/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
@@ -426,11 +426,6 @@ static void sport_stop_rx(struct uart_port *port)
SSYNC();
}
-static void sport_enable_ms(struct uart_port *port)
-{
- pr_debug("%s enter\n", __func__);
-}
-
static void sport_break_ctl(struct uart_port *port, int break_state)
{
pr_debug("%s enter\n", __func__);
@@ -500,6 +495,13 @@ static void sport_set_termios(struct uart_port *port,
pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
+ if (old == NULL && up->cts_pin != -1)
+ termios->c_cflag |= CRTSCTS;
+ else if (up->cts_pin == -1)
+ termios->c_cflag &= ~CRTSCTS;
+#endif
+
switch (termios->c_cflag & CSIZE) {
case CS8:
up->csize = 8;
@@ -587,7 +589,6 @@ struct uart_ops sport_uart_ops = {
.stop_tx = sport_stop_tx,
.start_tx = sport_start_tx,
.stop_rx = sport_stop_rx,
- .enable_ms = sport_enable_ms,
.break_ctl = sport_break_ctl,
.startup = sport_startup,
.shutdown = sport_shutdown,
@@ -813,10 +814,8 @@ static int sport_uart_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
sport->cts_pin = -1;
- else {
+ else
sport->cts_pin = res->start;
- sport->port.flags |= ASYNC_CTS_FLOW;
- }
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL)
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 869ceba2ec57..dec0fd725d80 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -200,14 +200,6 @@ static void bfin_serial_stop_rx(struct uart_port *port)
UART_CLEAR_IER(uart, ERBFI);
}
-/*
- * Set the modem control timer to fire immediately.
- */
-static void bfin_serial_enable_ms(struct uart_port *port)
-{
-}
-
-
#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
@@ -793,6 +785,13 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int ier, lcr = 0;
unsigned long timeout;
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (old == NULL && uart->cts_pin != -1)
+ termios->c_cflag |= CRTSCTS;
+ else if (uart->cts_pin == -1)
+ termios->c_cflag &= ~CRTSCTS;
+#endif
+
switch (termios->c_cflag & CSIZE) {
case CS8:
lcr = WLS(8);
@@ -833,7 +832,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= (FE | PE);
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= BI;
/*
@@ -1014,7 +1013,6 @@ static struct uart_ops bfin_serial_pops = {
.stop_tx = bfin_serial_stop_tx,
.start_tx = bfin_serial_start_tx,
.stop_rx = bfin_serial_stop_rx,
- .enable_ms = bfin_serial_enable_ms,
.break_ctl = bfin_serial_break_ctl,
.startup = bfin_serial_startup,
.shutdown = bfin_serial_shutdown,
@@ -1325,12 +1323,8 @@ static int bfin_serial_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
uart->cts_pin = -1;
- else {
+ else
uart->cts_pin = res->start;
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
- uart->port.flags |= ASYNC_CTS_FLOW;
-#endif
- }
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 14aaea0d4131..f5b4c3d7e38f 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -352,7 +352,6 @@ static const struct uart_ops uart_clps711x_ops = {
.stop_tx = uart_clps711x_stop_tx,
.start_tx = uart_clps711x_start_tx,
.stop_rx = uart_clps711x_nop_void,
- .enable_ms = uart_clps711x_nop_void,
.break_ctl = uart_clps711x_break_ctl,
.set_ldisc = uart_clps711x_set_ldisc,
.startup = uart_clps711x_startup,
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index 7d76214612c7..533852eb8778 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -202,14 +202,6 @@ static void cpm_uart_stop_rx(struct uart_port *port)
}
/*
- * Enable Modem status interrupts
- */
-static void cpm_uart_enable_ms(struct uart_port *port)
-{
- pr_debug("CPM uart[%d]:enable ms\n", port->line);
-}
-
-/*
* Generate a break.
*/
static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
@@ -971,7 +963,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
* Note that this is called with interrupts already disabled
*/
static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
- const char *string, u_int count)
+ const char *string, u_int count, bool handle_linefeed)
{
unsigned int i;
cbd_t __iomem *bdp, *bdbase;
@@ -1013,7 +1005,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
bdp++;
/* if a LF, also do CR... */
- if (*string == 10) {
+ if (handle_linefeed && *string == 10) {
while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
@@ -1111,7 +1103,7 @@ static void cpm_put_poll_char(struct uart_port *port,
static char ch[2];
ch[0] = (char)c;
- cpm_uart_early_write(pinfo, ch, 1);
+ cpm_uart_early_write(pinfo, ch, 1, false);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -1122,7 +1114,6 @@ static struct uart_ops cpm_uart_pops = {
.stop_tx = cpm_uart_stop_tx,
.start_tx = cpm_uart_start_tx,
.stop_rx = cpm_uart_stop_rx,
- .enable_ms = cpm_uart_enable_ms,
.break_ctl = cpm_uart_break_ctl,
.startup = cpm_uart_startup,
.shutdown = cpm_uart_shutdown,
@@ -1275,7 +1266,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
spin_lock_irqsave(&pinfo->port.lock, flags);
}
- cpm_uart_early_write(pinfo, s, count);
+ cpm_uart_early_write(pinfo, s, count, true);
if (unlikely(nolock)) {
local_irq_restore(flags);
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index d567ac5d3af4..58e6f61a87e4 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -3831,14 +3831,13 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int retval;
- int do_clocal = 0, extra_count = 0;
+ int do_clocal = 0;
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
- if (tty_hung_up_p(filp) ||
- (info->port.flags & ASYNC_CLOSING)) {
+ if (info->port.flags & ASYNC_CLOSING) {
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
@@ -3879,10 +3878,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
info->line, info->port.count);
#endif
local_irq_save(flags);
- if (!tty_hung_up_p(filp)) {
- extra_count++;
- info->port.count--;
- }
+ info->port.count--;
local_irq_restore(flags);
info->port.blocked_open++;
while (1) {
@@ -3921,7 +3917,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
- if (extra_count)
+ if (!tty_hung_up_p(filp))
info->port.count++;
info->port.blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
@@ -3976,8 +3972,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
/*
* If the port is in the middle of closing, bail out now
*/
- if (tty_hung_up_p(filp) ||
- (info->port.flags & ASYNC_CLOSING)) {
+ if (info->port.flags & ASYNC_CLOSING) {
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index 2f2b2e538a54..c121f16a973f 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -151,11 +151,6 @@ static void dz_stop_rx(struct uart_port *uport)
dz_out(dport, DZ_LPR, dport->cflag);
}
-static void dz_enable_ms(struct uart_port *uport)
-{
- /* nothing to do */
-}
-
/*
* ------------------------------------------------------------
*
@@ -625,7 +620,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
dport->port.read_status_mask = DZ_OERR;
if (termios->c_iflag & INPCK)
dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
dport->port.read_status_mask |= DZ_BREAK;
/* characters to ignore */
@@ -751,7 +746,6 @@ static struct uart_ops dz_ops = {
.stop_tx = dz_stop_tx,
.start_tx = dz_start_tx,
.stop_rx = dz_stop_rx,
- .enable_ms = dz_enable_ms,
.break_ctl = dz_break_ctl,
.startup = dz_startup,
.shutdown = dz_shutdown,
diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c
new file mode 100644
index 000000000000..383db10fbb49
--- /dev/null
+++ b/drivers/tty/serial/earlycon-arm-semihost.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Adapted for ARM and earlycon:
+ * Copyright (C) 2014 Linaro Ltd.
+ * Author: Rob Herring <robh@kernel.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define SEMIHOST_SWI "0xab"
+#else
+#define SEMIHOST_SWI "0x123456"
+#endif
+
+/*
+ * Semihosting-based debug console
+ */
+static void smh_putc(struct uart_port *port, int c)
+{
+#ifdef CONFIG_ARM64
+ asm volatile("mov x1, %0\n"
+ "mov x0, #3\n"
+ "hlt 0xf000\n"
+ : : "r" (&c) : "x0", "x1", "memory");
+#else
+ asm volatile("mov r1, %0\n"
+ "mov r0, #3\n"
+ "svc " SEMIHOST_SWI "\n"
+ : : "r" (&c) : "r0", "r1", "memory");
+#endif
+}
+
+static void smh_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+ uart_console_write(&dev->port, s, n, smh_putc);
+}
+
+int __init early_smh_setup(struct earlycon_device *device, const char *opt)
+{
+ device->con->write = smh_write;
+ return 0;
+}
+EARLYCON_DECLARE(smh, early_smh_setup);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
new file mode 100644
index 000000000000..a514ee6f5406
--- /dev/null
+++ b/drivers/tty/serial/earlycon.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ * Author: Rob Herring <robh@kernel.org>
+ *
+ * Based on 8250 earlycon:
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <linux/sizes.h>
+#include <linux/mod_devicetable.h>
+
+#ifdef CONFIG_FIX_EARLYCON_MEM
+#include <asm/fixmap.h>
+#endif
+
+#include <asm/serial.h>
+
+static struct console early_con = {
+ .name = "uart", /* 8250 console switch requires this name */
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+static struct earlycon_device early_console_dev = {
+ .con = &early_con,
+};
+
+static const struct of_device_id __earlycon_of_table_sentinel
+ __used __section(__earlycon_of_table_end);
+
+static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
+{
+ void __iomem *base;
+#ifdef CONFIG_FIX_EARLYCON_MEM
+ set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
+ base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+ base += paddr & ~PAGE_MASK;
+#else
+ base = ioremap(paddr, size);
+#endif
+ if (!base)
+ pr_err("%s: Couldn't map 0x%llx\n", __func__,
+ (unsigned long long)paddr);
+
+ return base;
+}
+
+static int __init parse_options(struct earlycon_device *device,
+ char *options)
+{
+ struct uart_port *port = &device->port;
+ int mmio, mmio32, length;
+ unsigned long addr;
+
+ if (!options)
+ return -ENODEV;
+
+ 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);
+ 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);
+ 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 {
+ 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)));
+ strlcpy(device->options, options, length);
+ }
+
+ if (mmio || mmio32)
+ pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
+ mmio32 ? "32" : "",
+ (unsigned long long)port->mapbase,
+ device->options);
+ else
+ pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
+ port->iobase,
+ device->options);
+
+ return 0;
+}
+
+int __init setup_earlycon(char *buf, const char *match,
+ int (*setup)(struct earlycon_device *, const char *))
+{
+ 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)
+ buf = NULL;
+
+ if (port->mapbase)
+ port->membase = earlycon_map(port->mapbase, 64);
+
+ early_console_dev.con->data = &early_console_dev;
+ err = setup(&early_console_dev, buf);
+ if (err < 0)
+ return err;
+ if (!early_console_dev.con->write)
+ return -ENODEV;
+
+ register_console(early_console_dev.con);
+ return 0;
+}
+
+int __init of_setup_earlycon(unsigned long addr,
+ int (*setup)(struct earlycon_device *, const char *))
+{
+ int err;
+ struct uart_port *port = &early_console_dev.port;
+
+ port->iotype = UPIO_MEM;
+ port->mapbase = addr;
+ port->uartclk = BASE_BAUD * 16;
+ port->membase = earlycon_map(addr, SZ_4K);
+
+ early_console_dev.con->data = &early_console_dev;
+ err = setup(&early_console_dev, NULL);
+ if (err < 0)
+ return err;
+ if (!early_console_dev.con->write)
+ return -ENODEV;
+
+
+ register_console(early_console_dev.con);
+ return 0;
+}
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index c167a710dc39..55d9c00112cc 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -185,11 +185,6 @@ static void efm32_uart_stop_rx(struct uart_port *port)
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
}
-static void efm32_uart_enable_ms(struct uart_port *port)
-{
- /* no handshake lines, no modem status interrupts */
-}
-
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
{
/* not possible without fiddling with gpios */
@@ -407,7 +402,7 @@ static void efm32_uart_set_termios(struct uart_port *port,
if (new->c_iflag & INPCK)
port->read_status_mask |=
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
- if (new->c_iflag & (BRKINT | PARMRK))
+ if (new->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
port->ignore_status_mask = 0;
@@ -499,7 +494,6 @@ static struct uart_ops efm32_uart_pops = {
.stop_tx = efm32_uart_stop_tx,
.start_tx = efm32_uart_start_tx,
.stop_rx = efm32_uart_stop_rx,
- .enable_ms = efm32_uart_enable_ms,
.break_ctl = efm32_uart_break_ctl,
.startup = efm32_uart_startup,
.shutdown = efm32_uart_shutdown,
@@ -671,10 +665,16 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
if (!np)
return 1;
- ret = of_property_read_u32(np, "efm32,location", &location);
+ ret = of_property_read_u32(np, "energymicro,location", &location);
+
+ if (ret)
+ /* fall back to wrongly namespaced property */
+ ret = of_property_read_u32(np, "efm32,location", &location);
+
if (ret)
/* fall back to old and (wrongly) generic property "location" */
ret = of_property_read_u32(np, "location", &location);
+
if (!ret) {
if (location > 5) {
dev_err(&pdev->dev, "invalid location\n");
@@ -842,6 +842,7 @@ static void __exit efm32_uart_exit(void)
platform_driver_unregister(&efm32_uart_driver);
uart_unregister_driver(&efm32_uart_reg);
}
+module_exit(efm32_uart_exit);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 UART/USART driver");
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index c5eb897de9de..6dd53af546a3 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1,7 +1,7 @@
/*
* Freescale lpuart serial port driver
*
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2014 Freescale Semiconductor, Inc.
*
* 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
@@ -117,8 +117,113 @@
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
-#define DMA_MAXBURST 16
-#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1)
+/* 32-bit register defination */
+#define UARTBAUD 0x00
+#define UARTSTAT 0x04
+#define UARTCTRL 0x08
+#define UARTDATA 0x0C
+#define UARTMATCH 0x10
+#define UARTMODIR 0x14
+#define UARTFIFO 0x18
+#define UARTWATER 0x1c
+
+#define UARTBAUD_MAEN1 0x80000000
+#define UARTBAUD_MAEN2 0x40000000
+#define UARTBAUD_M10 0x20000000
+#define UARTBAUD_TDMAE 0x00800000
+#define UARTBAUD_RDMAE 0x00200000
+#define UARTBAUD_MATCFG 0x00400000
+#define UARTBAUD_BOTHEDGE 0x00020000
+#define UARTBAUD_RESYNCDIS 0x00010000
+#define UARTBAUD_LBKDIE 0x00008000
+#define UARTBAUD_RXEDGIE 0x00004000
+#define UARTBAUD_SBNS 0x00002000
+#define UARTBAUD_SBR 0x00000000
+#define UARTBAUD_SBR_MASK 0x1fff
+
+#define UARTSTAT_LBKDIF 0x80000000
+#define UARTSTAT_RXEDGIF 0x40000000
+#define UARTSTAT_MSBF 0x20000000
+#define UARTSTAT_RXINV 0x10000000
+#define UARTSTAT_RWUID 0x08000000
+#define UARTSTAT_BRK13 0x04000000
+#define UARTSTAT_LBKDE 0x02000000
+#define UARTSTAT_RAF 0x01000000
+#define UARTSTAT_TDRE 0x00800000
+#define UARTSTAT_TC 0x00400000
+#define UARTSTAT_RDRF 0x00200000
+#define UARTSTAT_IDLE 0x00100000
+#define UARTSTAT_OR 0x00080000
+#define UARTSTAT_NF 0x00040000
+#define UARTSTAT_FE 0x00020000
+#define UARTSTAT_PE 0x00010000
+#define UARTSTAT_MA1F 0x00008000
+#define UARTSTAT_M21F 0x00004000
+
+#define UARTCTRL_R8T9 0x80000000
+#define UARTCTRL_R9T8 0x40000000
+#define UARTCTRL_TXDIR 0x20000000
+#define UARTCTRL_TXINV 0x10000000
+#define UARTCTRL_ORIE 0x08000000
+#define UARTCTRL_NEIE 0x04000000
+#define UARTCTRL_FEIE 0x02000000
+#define UARTCTRL_PEIE 0x01000000
+#define UARTCTRL_TIE 0x00800000
+#define UARTCTRL_TCIE 0x00400000
+#define UARTCTRL_RIE 0x00200000
+#define UARTCTRL_ILIE 0x00100000
+#define UARTCTRL_TE 0x00080000
+#define UARTCTRL_RE 0x00040000
+#define UARTCTRL_RWU 0x00020000
+#define UARTCTRL_SBK 0x00010000
+#define UARTCTRL_MA1IE 0x00008000
+#define UARTCTRL_MA2IE 0x00004000
+#define UARTCTRL_IDLECFG 0x00000100
+#define UARTCTRL_LOOPS 0x00000080
+#define UARTCTRL_DOZEEN 0x00000040
+#define UARTCTRL_RSRC 0x00000020
+#define UARTCTRL_M 0x00000010
+#define UARTCTRL_WAKE 0x00000008
+#define UARTCTRL_ILT 0x00000004
+#define UARTCTRL_PE 0x00000002
+#define UARTCTRL_PT 0x00000001
+
+#define UARTDATA_NOISY 0x00008000
+#define UARTDATA_PARITYE 0x00004000
+#define UARTDATA_FRETSC 0x00002000
+#define UARTDATA_RXEMPT 0x00001000
+#define UARTDATA_IDLINE 0x00000800
+#define UARTDATA_MASK 0x3ff
+
+#define UARTMODIR_IREN 0x00020000
+#define UARTMODIR_TXCTSSRC 0x00000020
+#define UARTMODIR_TXCTSC 0x00000010
+#define UARTMODIR_RXRTSE 0x00000008
+#define UARTMODIR_TXRTSPOL 0x00000004
+#define UARTMODIR_TXRTSE 0x00000002
+#define UARTMODIR_TXCTSE 0x00000001
+
+#define UARTFIFO_TXEMPT 0x00800000
+#define UARTFIFO_RXEMPT 0x00400000
+#define UARTFIFO_TXOF 0x00020000
+#define UARTFIFO_RXUF 0x00010000
+#define UARTFIFO_TXFLUSH 0x00008000
+#define UARTFIFO_RXFLUSH 0x00004000
+#define UARTFIFO_TXOFE 0x00000200
+#define UARTFIFO_RXUFE 0x00000100
+#define UARTFIFO_TXFE 0x00000080
+#define UARTFIFO_FIFOSIZE_MASK 0x7
+#define UARTFIFO_TXSIZE_OFF 4
+#define UARTFIFO_RXFE 0x00000008
+#define UARTFIFO_RXSIZE_OFF 0
+
+#define UARTWATER_COUNT_MASK 0xff
+#define UARTWATER_TXCNT_OFF 8
+#define UARTWATER_RXCNT_OFF 24
+#define UARTWATER_WATER_MASK 0xff
+#define UARTWATER_TXWATER_OFF 0
+#define UARTWATER_RXWATER_OFF 16
+
#define FSL_UART_RX_DMA_BUFFER_SIZE 64
#define DRIVER_NAME "fsl-lpuart"
@@ -130,6 +235,7 @@ struct lpuart_port {
struct clk *clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
+ bool lpuart32;
bool lpuart_dma_use;
struct dma_chan *dma_tx_chan;
@@ -154,6 +260,9 @@ static struct of_device_id lpuart_dt_ids[] = {
{
.compatible = "fsl,vf610-lpuart",
},
+ {
+ .compatible = "fsl,ls1021a-lpuart",
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -162,6 +271,16 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
static void lpuart_dma_tx_complete(void *arg);
static void lpuart_dma_rx_complete(void *arg);
+static u32 lpuart32_read(void __iomem *addr)
+{
+ return ioread32be(addr);
+}
+
+static void lpuart32_write(u32 val, void __iomem *addr)
+{
+ iowrite32be(val, addr);
+}
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -171,6 +290,15 @@ static void lpuart_stop_tx(struct uart_port *port)
writeb(temp, port->membase + UARTCR2);
}
+static void lpuart32_stop_tx(struct uart_port *port)
+{
+ unsigned long temp;
+
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(temp, port->membase + UARTCTRL);
+}
+
static void lpuart_stop_rx(struct uart_port *port)
{
unsigned char temp;
@@ -179,8 +307,12 @@ static void lpuart_stop_rx(struct uart_port *port)
writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2);
}
-static void lpuart_enable_ms(struct uart_port *port)
+static void lpuart32_stop_rx(struct uart_port *port)
{
+ unsigned long temp;
+
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
}
static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
@@ -240,7 +372,7 @@ static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
UART_XMIT_SIZE, DMA_TO_DEVICE);
- sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
+ sport->dma_tx_bytes = count & ~(sport->txfifo_size - 1);
tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
tx_bus_addr, sport->dma_tx_bytes,
@@ -269,7 +401,7 @@ static void lpuart_prepare_tx(struct lpuart_port *sport)
if (!count)
return;
- if (count < DMA_MAXBURST)
+ if (count < sport->txfifo_size)
writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
sport->port.membase + UARTCR5);
else {
@@ -405,6 +537,30 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
lpuart_stop_tx(&sport->port);
}
+static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long txcnt;
+
+ txcnt = lpuart32_read(sport->port.membase + UARTWATER);
+ txcnt = txcnt >> UARTWATER_TXCNT_OFF;
+ txcnt &= UARTWATER_COUNT_MASK;
+ while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
+ lpuart32_write(xmit->buf[xmit->tail], sport->port.membase + UARTDATA);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ txcnt = lpuart32_read(sport->port.membase + UARTWATER);
+ txcnt = txcnt >> UARTWATER_TXCNT_OFF;
+ txcnt &= UARTWATER_COUNT_MASK;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ lpuart32_stop_tx(&sport->port);
+}
+
static void lpuart_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
@@ -424,6 +580,18 @@ static void lpuart_start_tx(struct uart_port *port)
}
}
+static void lpuart32_start_tx(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ unsigned long temp;
+
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
+
+ if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)
+ lpuart32_transmit_buffer(sport);
+}
+
static irqreturn_t lpuart_txint(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
@@ -432,16 +600,25 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
spin_lock_irqsave(&sport->port.lock, flags);
if (sport->port.x_char) {
- writeb(sport->port.x_char, sport->port.membase + UARTDR);
+ if (sport->lpuart32)
+ lpuart32_write(sport->port.x_char, sport->port.membase + UARTDATA);
+ else
+ writeb(sport->port.x_char, sport->port.membase + UARTDR);
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- lpuart_stop_tx(&sport->port);
+ if (sport->lpuart32)
+ lpuart32_stop_tx(&sport->port);
+ else
+ lpuart_stop_tx(&sport->port);
goto out;
}
- lpuart_transmit_buffer(sport);
+ if (sport->lpuart32)
+ lpuart32_transmit_buffer(sport);
+ else
+ lpuart_transmit_buffer(sport);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
@@ -514,6 +691,70 @@ out:
return IRQ_HANDLED;
}
+static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
+{
+ struct lpuart_port *sport = dev_id;
+ unsigned int flg, ignored = 0;
+ struct tty_port *port = &sport->port.state->port;
+ unsigned long flags;
+ unsigned long rx, sr;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) {
+ flg = TTY_NORMAL;
+ sport->port.icount.rx++;
+ /*
+ * to clear the FE, OR, NF, FE, PE flags,
+ * read STAT then read DATA reg
+ */
+ sr = lpuart32_read(sport->port.membase + UARTSTAT);
+ rx = lpuart32_read(sport->port.membase + UARTDATA);
+ rx &= 0x3ff;
+
+ if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+ continue;
+
+ if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) {
+ if (sr & UARTSTAT_PE)
+ sport->port.icount.parity++;
+ else if (sr & UARTSTAT_FE)
+ sport->port.icount.frame++;
+
+ if (sr & UARTSTAT_OR)
+ sport->port.icount.overrun++;
+
+ if (sr & sport->port.ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ continue;
+ }
+
+ sr &= sport->port.read_status_mask;
+
+ if (sr & UARTSTAT_PE)
+ flg = TTY_PARITY;
+ else if (sr & UARTSTAT_FE)
+ flg = TTY_FRAME;
+
+ if (sr & UARTSTAT_OR)
+ flg = TTY_OVERRUN;
+
+#ifdef SUPPORT_SYSRQ
+ sport->port.sysrq = 0;
+#endif
+ }
+
+ tty_insert_flip_char(port, rx, flg);
+ }
+
+out:
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ tty_flip_buffer_push(port);
+ return IRQ_HANDLED;
+}
+
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
@@ -538,6 +779,26 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t lpuart32_int(int irq, void *dev_id)
+{
+ struct lpuart_port *sport = dev_id;
+ unsigned long sts, rxcount;
+
+ sts = lpuart32_read(sport->port.membase + UARTSTAT);
+ rxcount = lpuart32_read(sport->port.membase + UARTWATER);
+ rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+
+ if (sts & UARTSTAT_RDRF || rxcount > 0)
+ lpuart32_rxint(irq, dev_id);
+
+ if ((sts & UARTSTAT_TDRE) &&
+ !(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE))
+ lpuart_txint(irq, dev_id);
+
+ lpuart32_write(sts, sport->port.membase + UARTSTAT);
+ return IRQ_HANDLED;
+}
+
/* return TIOCSER_TEMT when transmitter is not busy */
static unsigned int lpuart_tx_empty(struct uart_port *port)
{
@@ -545,6 +806,12 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
TIOCSER_TEMT : 0;
}
+static unsigned int lpuart32_tx_empty(struct uart_port *port)
+{
+ return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
+ TIOCSER_TEMT : 0;
+}
+
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
unsigned int temp = 0;
@@ -560,6 +827,21 @@ static unsigned int lpuart_get_mctrl(struct uart_port *port)
return temp;
}
+static unsigned int lpuart32_get_mctrl(struct uart_port *port)
+{
+ unsigned int temp = 0;
+ unsigned long reg;
+
+ reg = lpuart32_read(port->membase + UARTMODIR);
+ if (reg & UARTMODIR_TXCTSE)
+ temp |= TIOCM_CTS;
+
+ if (reg & UARTMODIR_RXRTSE)
+ temp |= TIOCM_RTS;
+
+ return temp;
+}
+
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned char temp;
@@ -576,6 +858,22 @@ static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
writeb(temp, port->membase + UARTMODEM);
}
+static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned long temp;
+
+ temp = lpuart32_read(port->membase + UARTMODIR) &
+ ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
+
+ if (mctrl & TIOCM_RTS)
+ temp |= UARTMODIR_RXRTSE;
+
+ if (mctrl & TIOCM_CTS)
+ temp |= UARTMODIR_TXCTSE;
+
+ lpuart32_write(temp, port->membase + UARTMODIR);
+}
+
static void lpuart_break_ctl(struct uart_port *port, int break_state)
{
unsigned char temp;
@@ -588,6 +886,18 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
writeb(temp, port->membase + UARTCR2);
}
+static void lpuart32_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long temp;
+
+ temp = lpuart32_read(port->membase + UARTCTRL) & ~UARTCTRL_SBK;
+
+ if (break_state != 0)
+ temp |= UARTCTRL_SBK;
+
+ lpuart32_write(temp, port->membase + UARTCTRL);
+}
+
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
unsigned char val, cr2;
@@ -599,15 +909,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
- /* determine FIFO size and enable FIFO mode */
val = readb(sport->port.membase + UARTPFIFO);
-
- sport->txfifo_size = 0x1 << (((val >> UARTPFIFO_TXSIZE_OFF) &
- UARTPFIFO_FIFOSIZE_MASK) + 1);
-
- sport->rxfifo_size = 0x1 << (((val >> UARTPFIFO_RXSIZE_OFF) &
- UARTPFIFO_FIFOSIZE_MASK) + 1);
-
writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
@@ -622,6 +924,31 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(cr2_saved, sport->port.membase + UARTCR2);
}
+static void lpuart32_setup_watermark(struct lpuart_port *sport)
+{
+ unsigned long val, ctrl;
+ unsigned long ctrl_saved;
+
+ ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
+ ctrl_saved = ctrl;
+ ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
+ UARTCTRL_RIE | UARTCTRL_RE);
+ lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
+
+ /* enable FIFO mode */
+ val = lpuart32_read(sport->port.membase + UARTFIFO);
+ val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
+ val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(val, sport->port.membase + UARTFIFO);
+
+ /* set the watermark */
+ val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
+ lpuart32_write(val, sport->port.membase + UARTWATER);
+
+ /* Restore cr2 */
+ lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
+}
+
static int lpuart_dma_tx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
@@ -652,7 +979,7 @@ static int lpuart_dma_tx_request(struct uart_port *port)
dma_buf = sport->port.state->xmit.buf;
dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
+ dma_tx_sconfig.dst_maxburst = sport->txfifo_size;
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
@@ -724,13 +1051,6 @@ static int lpuart_dma_rx_request(struct uart_port *port)
sport->dma_rx_buf_bus = dma_bus;
sport->dma_rx_in_progress = 0;
- sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
- FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
- sport->rxfifo_size / 2;
-
- if (sport->dma_rx_timeout < msecs_to_jiffies(20))
- sport->dma_rx_timeout = msecs_to_jiffies(20);
-
return 0;
}
@@ -772,7 +1092,16 @@ static int lpuart_startup(struct uart_port *port)
unsigned long flags;
unsigned char temp;
- /*whether use dma support by dma request results*/
+ /* determine FIFO size and enable FIFO mode */
+ temp = readb(sport->port.membase + UARTPFIFO);
+
+ sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) &
+ UARTPFIFO_FIFOSIZE_MASK) + 1);
+
+ sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
+ UARTPFIFO_FIFOSIZE_MASK) + 1);
+
+ /* Whether use dma support by dma request results */
if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
sport->lpuart_dma_use = false;
} else {
@@ -798,6 +1127,40 @@ static int lpuart_startup(struct uart_port *port)
return 0;
}
+static int lpuart32_startup(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ int ret;
+ unsigned long flags;
+ unsigned long temp;
+
+ /* determine FIFO size */
+ temp = lpuart32_read(sport->port.membase + UARTFIFO);
+
+ sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
+ UARTFIFO_FIFOSIZE_MASK) - 1);
+
+ sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) &
+ UARTFIFO_FIFOSIZE_MASK) - 1);
+
+ ret = devm_request_irq(port->dev, port->irq, lpuart32_int, 0,
+ DRIVER_NAME, sport);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ lpuart32_setup_watermark(sport);
+
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
+ temp |= UARTCTRL_ILIE;
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return 0;
+}
+
static void lpuart_shutdown(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
@@ -822,6 +1185,25 @@ static void lpuart_shutdown(struct uart_port *port)
}
}
+static void lpuart32_shutdown(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ unsigned long temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* disable Rx/Tx and interrupts */
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
+ UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
+ lpuart32_write(temp, port->membase + UARTCTRL);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ devm_free_irq(port->dev, port->irq, sport);
+}
+
static void
lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
@@ -902,7 +1284,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.read_status_mask = 0;
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE);
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
sport->port.read_status_mask |= UARTSR1_FE;
/* characters to ignore */
@@ -922,6 +1304,17 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
+ if (sport->lpuart_dma_use) {
+ /* Calculate delay for 1.5 DMA buffers */
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
+ sport->rxfifo_size / 2;
+ dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+ sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout);
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+ }
+
/* wait transmit engin complete */
while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC))
barrier();
@@ -948,6 +1341,125 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+static void
+lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ unsigned long flags;
+ unsigned long ctrl, old_ctrl, bd, modem;
+ unsigned int baud;
+ unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+ unsigned int sbr;
+
+ ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
+ bd = lpuart32_read(sport->port.membase + UARTBAUD);
+ modem = lpuart32_read(sport->port.membase + UARTMODIR);
+ /*
+ * only support CS8 and CS7, and for CS7 must enable PE.
+ * supported mode:
+ * - (7,e/o,1)
+ * - (8,n,1)
+ * - (8,m/s,1)
+ * - (8,e/o,1)
+ */
+ while ((termios->c_cflag & CSIZE) != CS8 &&
+ (termios->c_cflag & CSIZE) != CS7) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= old_csize;
+ old_csize = CS8;
+ }
+
+ if ((termios->c_cflag & CSIZE) == CS8 ||
+ (termios->c_cflag & CSIZE) == CS7)
+ ctrl = old_ctrl & ~UARTCTRL_M;
+
+ if (termios->c_cflag & CMSPAR) {
+ if ((termios->c_cflag & CSIZE) != CS8) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
+ }
+ ctrl |= UARTCTRL_M;
+ }
+
+ if (termios->c_cflag & CRTSCTS) {
+ modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
+ } else {
+ termios->c_cflag &= ~CRTSCTS;
+ modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ termios->c_cflag &= ~CSTOPB;
+
+ /* parity must be enabled when CS7 to match 8-bits format */
+ if ((termios->c_cflag & CSIZE) == CS7)
+ termios->c_cflag |= PARENB;
+
+ if ((termios->c_cflag & PARENB)) {
+ if (termios->c_cflag & CMSPAR) {
+ ctrl &= ~UARTCTRL_PE;
+ ctrl |= UARTCTRL_M;
+ } else {
+ ctrl |= UARTCR1_PE;
+ if ((termios->c_cflag & CSIZE) == CS8)
+ ctrl |= UARTCTRL_M;
+ if (termios->c_cflag & PARODD)
+ ctrl |= UARTCTRL_PT;
+ else
+ ctrl &= ~UARTCTRL_PT;
+ }
+ }
+
+ /* ask the core to calculate the divisor */
+ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->port.read_status_mask = 0;
+ if (termios->c_iflag & INPCK)
+ sport->port.read_status_mask |= (UARTSTAT_FE | UARTSTAT_PE);
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+ sport->port.read_status_mask |= UARTSTAT_FE;
+
+ /* characters to ignore */
+ sport->port.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |= UARTSTAT_PE;
+ if (termios->c_iflag & IGNBRK) {
+ sport->port.ignore_status_mask |= UARTSTAT_FE;
+ /*
+ * if we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |= UARTSTAT_OR;
+ }
+
+ /* update the per-port timeout */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /* wait transmit engin complete */
+ while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
+ barrier();
+
+ /* disable transmit and receive */
+ lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
+ sport->port.membase + UARTCTRL);
+
+ sbr = sport->port.uartclk / (16 * baud);
+ bd &= ~UARTBAUD_SBR_MASK;
+ bd |= sbr & UARTBAUD_SBR_MASK;
+ bd |= UARTBAUD_BOTHEDGE;
+ bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
+ lpuart32_write(bd, sport->port.membase + UARTBAUD);
+ lpuart32_write(modem, sport->port.membase + UARTMODIR);
+ lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
+ /* restore control register */
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
static const char *lpuart_type(struct uart_port *port)
{
return "FSL_LPUART";
@@ -996,7 +1508,6 @@ static struct uart_ops lpuart_pops = {
.stop_tx = lpuart_stop_tx,
.start_tx = lpuart_start_tx,
.stop_rx = lpuart_stop_rx,
- .enable_ms = lpuart_enable_ms,
.break_ctl = lpuart_break_ctl,
.startup = lpuart_startup,
.shutdown = lpuart_shutdown,
@@ -1008,6 +1519,24 @@ static struct uart_ops lpuart_pops = {
.verify_port = lpuart_verify_port,
};
+static struct uart_ops lpuart32_pops = {
+ .tx_empty = lpuart32_tx_empty,
+ .set_mctrl = lpuart32_set_mctrl,
+ .get_mctrl = lpuart32_get_mctrl,
+ .stop_tx = lpuart32_stop_tx,
+ .start_tx = lpuart32_start_tx,
+ .stop_rx = lpuart32_stop_rx,
+ .break_ctl = lpuart32_break_ctl,
+ .startup = lpuart32_startup,
+ .shutdown = lpuart32_shutdown,
+ .set_termios = lpuart32_set_termios,
+ .type = lpuart_type,
+ .request_port = lpuart_request_port,
+ .release_port = lpuart_release_port,
+ .config_port = lpuart_config_port,
+ .verify_port = lpuart_verify_port,
+};
+
static struct lpuart_port *lpuart_ports[UART_NR];
#ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE
@@ -1019,6 +1548,14 @@ static void lpuart_console_putchar(struct uart_port *port, int ch)
writeb(ch, port->membase + UARTDR);
}
+static void lpuart32_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE))
+ barrier();
+
+ lpuart32_write(ch, port->membase + UARTDATA);
+}
+
static void
lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
@@ -1040,6 +1577,27 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
writeb(old_cr2, sport->port.membase + UARTCR2);
}
+static void
+lpuart32_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct lpuart_port *sport = lpuart_ports[co->index];
+ unsigned long old_cr, cr;
+
+ /* first save CR2 and then disable interrupts */
+ cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
+ cr |= (UARTCTRL_TE | UARTCTRL_RE);
+ cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
+ lpuart32_write(cr, sport->port.membase + UARTCTRL);
+
+ uart_console_write(&sport->port, s, count, lpuart32_console_putchar);
+
+ /* wait for transmitter finish complete and restore CR2 */
+ while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
+ barrier();
+
+ lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
+}
+
/*
* if the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
@@ -1093,6 +1651,49 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
"from %d to %d\n", baud_raw, *baud);
}
+static void __init
+lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
+ int *parity, int *bits)
+{
+ unsigned long cr, bd;
+ unsigned int sbr, uartclk, baud_raw;
+
+ cr = lpuart32_read(sport->port.membase + UARTCTRL);
+ cr &= UARTCTRL_TE | UARTCTRL_RE;
+ if (!cr)
+ return;
+
+ /* ok, the port was enabled */
+
+ cr = lpuart32_read(sport->port.membase + UARTCTRL);
+
+ *parity = 'n';
+ if (cr & UARTCTRL_PE) {
+ if (cr & UARTCTRL_PT)
+ *parity = 'o';
+ else
+ *parity = 'e';
+ }
+
+ if (cr & UARTCTRL_M)
+ *bits = 9;
+ else
+ *bits = 8;
+
+ bd = lpuart32_read(sport->port.membase + UARTBAUD);
+ bd &= UARTBAUD_SBR_MASK;
+ sbr = bd;
+ uartclk = clk_get_rate(sport->clk);
+ /*
+ * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
+ */
+ baud_raw = uartclk / (16 * sbr);
+
+ if (*baud != baud_raw)
+ printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
+ "from %d to %d\n", baud_raw, *baud);
+}
+
static int __init lpuart_console_setup(struct console *co, char *options)
{
struct lpuart_port *sport;
@@ -1116,9 +1717,15 @@ static int __init lpuart_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- lpuart_console_get_options(sport, &baud, &parity, &bits);
+ if (sport->lpuart32)
+ lpuart32_console_get_options(sport, &baud, &parity, &bits);
+ else
+ lpuart_console_get_options(sport, &baud, &parity, &bits);
- lpuart_setup_watermark(sport);
+ if (sport->lpuart32)
+ lpuart32_setup_watermark(sport);
+ else
+ lpuart_setup_watermark(sport);
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
}
@@ -1134,9 +1741,21 @@ static struct console lpuart_console = {
.data = &lpuart_reg,
};
+static struct console lpuart32_console = {
+ .name = DEV_NAME,
+ .write = lpuart32_console_write,
+ .device = uart_console_device,
+ .setup = lpuart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &lpuart_reg,
+};
+
#define LPUART_CONSOLE (&lpuart_console)
+#define LPUART32_CONSOLE (&lpuart32_console)
#else
#define LPUART_CONSOLE NULL
+#define LPUART32_CONSOLE NULL
#endif
static struct uart_driver lpuart_reg = {
@@ -1166,7 +1785,7 @@ static int lpuart_probe(struct platform_device *pdev)
return ret;
}
sport->port.line = ret;
-
+ sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
@@ -1180,7 +1799,10 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.type = PORT_LPUART;
sport->port.iotype = UPIO_MEM;
sport->port.irq = platform_get_irq(pdev, 0);
- sport->port.ops = &lpuart_pops;
+ if (sport->lpuart32)
+ sport->port.ops = &lpuart32_pops;
+ else
+ sport->port.ops = &lpuart_pops;
sport->port.flags = UPF_BOOT_AUTOCONF;
sport->clk = devm_clk_get(&pdev->dev, "ipg");
@@ -1202,6 +1824,11 @@ static int lpuart_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &sport->port);
+ if (sport->lpuart32)
+ lpuart_reg.cons = LPUART32_CONSOLE;
+ else
+ lpuart_reg.cons = LPUART_CONSOLE;
+
ret = uart_add_one_port(&lpuart_reg, &sport->port);
if (ret) {
clk_disable_unprepare(sport->clk);
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 67423805e6d9..d4620fe5da2e 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1052,11 +1052,6 @@ static void icom_stop_rx(struct uart_port *port)
writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
}
-static void icom_enable_ms(struct uart_port *port)
-{
- /* no-op */
-}
-
static void icom_break(struct uart_port *port, int break_state)
{
unsigned char cmdReg;
@@ -1300,7 +1295,6 @@ static struct uart_ops icom_ops = {
.start_tx = icom_start_tx,
.send_xchar = icom_send_xchar,
.stop_rx = icom_stop_rx,
- .enable_ms = icom_enable_ms,
.break_ctl = icom_break,
.startup = icom_open,
.shutdown = icom_close,
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 3b6c1a2e25de..044e86d528ae 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -116,7 +116,7 @@
#define UCR3_DSR (1<<10) /* Data set ready */
#define UCR3_DCD (1<<9) /* Data carrier detect */
#define UCR3_RI (1<<8) /* Ring indicator */
-#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
+#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
@@ -444,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port)
temp = readl(sport->port.membase + UCR2);
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
+
+ /* disable the `Receiver Ready Interrrupt` */
+ temp = readl(sport->port.membase + UCR1);
+ writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
}
/*
@@ -563,6 +567,9 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
+ if (uart_circ_empty(&port->state->xmit))
+ return;
+
if (USE_IRDA(sport)) {
/* half duplex in IrDA mode; have to disable receive mode */
temp = readl(sport->port.membase + UCR4);
@@ -1070,7 +1077,7 @@ static void imx_disable_dma(struct imx_port *sport)
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- int retval;
+ int retval, i;
unsigned long flags, temp;
retval = clk_prepare_enable(sport->clk_per);
@@ -1098,17 +1105,15 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
- if (USE_IRDA(sport)) {
- /* reset fifo's and state machines */
- int i = 100;
- temp = readl(sport->port.membase + UCR2);
- temp &= ~UCR2_SRST;
- writel(temp, sport->port.membase + UCR2);
- while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
- (--i > 0)) {
- udelay(1);
- }
- }
+ /* Reset fifo's and state machines */
+ i = 100;
+
+ temp = readl(sport->port.membase + UCR2);
+ temp &= ~UCR2_SRST;
+ writel(temp, sport->port.membase + UCR2);
+
+ while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+ udelay(1);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
@@ -1163,18 +1168,9 @@ static int imx_startup(struct uart_port *port)
temp |= UCR2_IRTS;
writel(temp, sport->port.membase + UCR2);
- if (USE_IRDA(sport)) {
- /* clear RX-FIFO */
- int i = 64;
- while ((--i > 0) &&
- (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
- barrier();
- }
- }
-
if (!is_imx1_uart(sport)) {
temp = readl(sport->port.membase + UCR3);
- temp |= IMX21_UCR3_RXDMUXSEL;
+ temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
writel(temp, sport->port.membase + UCR3);
}
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index 6e4c715c5d26..abd7ea26ed9a 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -1880,7 +1880,6 @@ static struct uart_ops ioc3_ops = {
.stop_tx = ic3_stop_tx,
.start_tx = ic3_start_tx,
.stop_rx = ic3_stop_rx,
- .enable_ms = null_void_function,
.break_ctl = ic3_break_ctl,
.startup = ic3_startup,
.shutdown = ic3_shutdown,
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index 1274499850fc..aa28209f44c1 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -2597,7 +2597,6 @@ static struct uart_ops ioc4_ops = {
.stop_tx = ic4_stop_tx,
.start_tx = ic4_start_tx,
.stop_rx = null_void_function,
- .enable_ms = null_void_function,
.break_ctl = ic4_break_ctl,
.startup = ic4_startup,
.shutdown = ic4_shutdown,
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index 1d9420548e16..99b7b8697861 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -603,6 +603,8 @@ static void ip22zilog_start_tx(struct uart_port *port)
} else {
struct circ_buf *xmit = &port->state->xmit;
+ if (uart_circ_empty(xmit))
+ return;
writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -850,7 +852,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
up->port.read_status_mask = Rx_OVR;
if (iflag & INPCK)
up->port.read_status_mask |= CRC_ERR | PAR_ERR;
- if (iflag & (BRKINT | PARMRK))
+ if (iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= BRK_ABRT;
up->port.ignore_status_mask = 0;
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 27bb75070c96..3e5c1563afe2 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -177,11 +177,6 @@ static void jsm_tty_stop_rx(struct uart_port *port)
channel->ch_bd->bd_ops->disable_receiver(channel);
}
-static void jsm_tty_enable_ms(struct uart_port *port)
-{
- /* Nothing needed */
-}
-
static void jsm_tty_break(struct uart_port *port, int break_state)
{
unsigned long lock_flags;
@@ -354,7 +349,6 @@ static struct uart_ops jsm_ops = {
.start_tx = jsm_tty_start_tx,
.send_xchar = jsm_tty_send_xchar,
.stop_rx = jsm_tty_stop_rx,
- .enable_ms = jsm_tty_enable_ms,
.break_ctl = jsm_tty_break,
.startup = jsm_tty_open,
.shutdown = jsm_tty_close,
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 5f673b7ca50e..6ec7501b464d 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -42,15 +42,24 @@ static char *kgdb_nmi_magic = "$3#33";
module_param_named(magic, kgdb_nmi_magic, charp, 0600);
MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
-static bool kgdb_nmi_tty_enabled;
+static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
+
+static int kgdb_nmi_console_setup(struct console *co, char *options)
+{
+ /* The NMI console uses the dbg_io_ops to issue console messages. To
+ * avoid duplicate messages during kdb sessions we must inform kdb's
+ * I/O utilities that messages sent to the console will automatically
+ * be displayed on the dbg_io.
+ */
+ dbg_io_ops->is_console = true;
+
+ return 0;
+}
static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
{
int i;
- if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
- return;
-
for (i = 0; i < c; i++)
dbg_io_ops->write_char(s[i]);
}
@@ -65,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
static struct console kgdb_nmi_console = {
.name = "ttyNMI",
+ .setup = kgdb_nmi_console_setup,
.write = kgdb_nmi_console_write,
.device = kgdb_nmi_console_device,
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
@@ -80,29 +90,10 @@ static struct console kgdb_nmi_console = {
struct kgdb_nmi_tty_priv {
struct tty_port port;
- struct tasklet_struct tlet;
+ struct timer_list timer;
STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
};
-static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
-{
- return container_of(port, struct kgdb_nmi_tty_priv, port);
-}
-
-/*
- * Our debugging console is polled in a tasklet, so we'll check for input
- * every tick. In HZ-less mode, we should program the next tick. We have
- * to use the lowlevel stuff as no locks should be grabbed.
- */
-#ifdef CONFIG_HIGH_RES_TIMERS
-static void kgdb_tty_poke(void)
-{
- tick_program_event(ktime_get(), 0);
-}
-#else
-static inline void kgdb_tty_poke(void) {}
-#endif
-
static struct tty_port *kgdb_nmi_port;
static void kgdb_tty_recv(int ch)
@@ -113,14 +104,13 @@ static void kgdb_tty_recv(int ch)
if (!kgdb_nmi_port || ch < 0)
return;
/*
- * Can't use port->tty->driver_data as tty might be not there. Tasklet
+ * Can't use port->tty->driver_data as tty might be not there. Timer
* will check for tty and will get the ref, but here we don't have to
* do that, and actually, we can't: we're in NMI context, no locks are
* possible.
*/
- priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
+ priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
kfifo_in(&priv->fifo, &c, 1);
- kgdb_tty_poke();
}
static int kgdb_nmi_poll_one_knock(void)
@@ -146,7 +136,7 @@ static int kgdb_nmi_poll_one_knock(void)
n = 0;
}
- if (kgdb_nmi_tty_enabled) {
+ if (atomic_read(&kgdb_nmi_num_readers)) {
kgdb_tty_recv(c);
return 0;
}
@@ -204,9 +194,11 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
struct kgdb_nmi_tty_priv *priv = (void *)data;
char ch;
- tasklet_schedule(&priv->tlet);
+ priv->timer.expires = jiffies + (HZ/100);
+ add_timer(&priv->timer);
- if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
+ if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
+ !kfifo_len(&priv->fifo)))
return;
while (kfifo_out(&priv->fifo, &ch, 1))
@@ -216,18 +208,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+ struct kgdb_nmi_tty_priv *priv =
+ container_of(port, struct kgdb_nmi_tty_priv, port);
kgdb_nmi_port = port;
- tasklet_schedule(&priv->tlet);
+ priv->timer.expires = jiffies + (HZ/100);
+ add_timer(&priv->timer);
+
return 0;
}
static void kgdb_nmi_tty_shutdown(struct tty_port *port)
{
- struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
+ struct kgdb_nmi_tty_priv *priv =
+ container_of(port, struct kgdb_nmi_tty_priv, port);
- tasklet_kill(&priv->tlet);
+ del_timer(&priv->timer);
kgdb_nmi_port = NULL;
}
@@ -246,7 +242,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
return -ENOMEM;
INIT_KFIFO(priv->fifo);
- tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
+ setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv);
tty_port_init(&priv->port);
priv->port.ops = &kgdb_nmi_tty_port_ops;
tty->driver_data = priv;
@@ -275,13 +271,23 @@ static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
{
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+ unsigned int mode = file->f_flags & O_ACCMODE;
+ int ret;
- return tty_port_open(&priv->port, tty, file);
+ ret = tty_port_open(&priv->port, tty, file);
+ if (!ret && (mode == O_RDONLY || mode == O_RDWR))
+ atomic_inc(&kgdb_nmi_num_readers);
+
+ return ret;
}
static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
{
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+ unsigned int mode = file->f_flags & O_ACCMODE;
+
+ if (mode == O_RDONLY || mode == O_RDWR)
+ atomic_dec(&kgdb_nmi_num_readers);
tty_port_close(&priv->port, tty, file);
}
@@ -318,12 +324,6 @@ static const struct tty_operations kgdb_nmi_tty_ops = {
.write = kgdb_nmi_tty_write,
};
-static int kgdb_nmi_enable_console(int argc, const char *argv[])
-{
- kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off"));
- return 0;
-}
-
int kgdb_register_nmi_console(void)
{
int ret;
@@ -353,19 +353,10 @@ int kgdb_register_nmi_console(void)
goto err_drv_reg;
}
- ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]",
- "switch to Linux NMI console", 0);
- if (ret) {
- pr_err("%s: can't register kdb command: %d\n", __func__, ret);
- goto err_kdb_reg;
- }
-
register_console(&kgdb_nmi_console);
arch_kgdb_ops.enable_nmi(1);
return 0;
-err_kdb_reg:
- tty_unregister_driver(kgdb_nmi_tty_driver);
err_drv_reg:
put_tty_driver(kgdb_nmi_tty_driver);
return ret;
@@ -380,8 +371,6 @@ int kgdb_unregister_nmi_console(void)
return 0;
arch_kgdb_ops.enable_nmi(0);
- kdb_unregister("nmi_console");
-
ret = unregister_console(&kgdb_nmi_console);
if (ret)
return ret;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 88d01e0bb0c8..4675fe198d31 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -154,11 +154,6 @@ lqasc_stop_rx(struct uart_port *port)
ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
}
-static void
-lqasc_enable_ms(struct uart_port *port)
-{
-}
-
static int
lqasc_rx_chars(struct uart_port *port)
{
@@ -568,7 +563,6 @@ static struct uart_ops lqasc_pops = {
.stop_tx = lqasc_stop_tx,
.start_tx = lqasc_start_tx,
.stop_rx = lqasc_stop_rx,
- .enable_ms = lqasc_enable_ms,
.break_ctl = lqasc_break_ctl,
.startup = lqasc_startup,
.shutdown = lqasc_shutdown,
@@ -709,7 +703,7 @@ lqasc_probe(struct platform_device *pdev)
port = &ltq_port->port;
port->iotype = SERIAL_IO_MEM;
- port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
port->ops = &lqasc_pops;
port->fifosize = 16;
port->type = PORT_LTQ_ASC,
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index 701644f06820..6f0f89282847 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -427,12 +427,6 @@ static void serial_lpc32xx_stop_rx(struct uart_port *port)
LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
}
-/* port->lock held by caller. */
-static void serial_lpc32xx_enable_ms(struct uart_port *port)
-{
- /* Modem status is not supported */
-}
-
/* port->lock is not held. */
static void serial_lpc32xx_break_ctl(struct uart_port *port,
int break_state)
@@ -658,7 +652,6 @@ static struct uart_ops serial_lpc32xx_pops = {
.stop_tx = serial_lpc32xx_stop_tx,
.start_tx = serial_lpc32xx_start_tx,
.stop_rx = serial_lpc32xx_stop_rx,
- .enable_ms = serial_lpc32xx_enable_ms,
.break_ctl = serial_lpc32xx_break_ctl,
.startup = serial_lpc32xx_startup,
.shutdown = serial_lpc32xx_shutdown,
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index 9cd9b4eba9fc..5702828fb62e 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -266,9 +266,11 @@ static void m32r_sio_start_tx(struct uart_port *port)
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
- 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)) {
+ serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ up->port.icount.tx++;
+ }
}
while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
#else
@@ -737,7 +739,7 @@ static void m32r_sio_set_termios(struct uart_port *port,
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 2a99d0c61b9e..82573dc4d8cf 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -835,7 +835,7 @@ static void max310x_set_termios(struct uart_port *port,
if (termios->c_iflag & INPCK)
port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |
MAX310X_LSR_FRERR_BIT;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;
/* Set status ignore mask */
@@ -1008,7 +1008,6 @@ static const struct uart_ops max310x_ops = {
.stop_tx = max310x_null_void,
.start_tx = max310x_start_tx,
.stop_rx = max310x_null_void,
- .enable_ms = max310x_null_void,
.break_ctl = max310x_break_ctl,
.startup = max310x_startup,
.shutdown = max310x_shutdown,
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 0edfaf8cd269..bc896dc7d2ed 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -150,12 +150,6 @@ static void mcf_break_ctl(struct uart_port *port, int break_state)
/****************************************************************************/
-static void mcf_enable_ms(struct uart_port *port)
-{
-}
-
-/****************************************************************************/
-
static int mcf_startup(struct uart_port *port)
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
@@ -248,6 +242,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
mr1 |= MCFUART_MR1_PARITYNONE;
}
+ /*
+ * FIXME: port->read_status_mask and port->ignore_status_mask
+ * need to be initialized based on termios settings for
+ * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
+ */
+
if (termios->c_cflag & CSTOPB)
mr2 |= MCFUART_MR2_STOP2;
else
@@ -501,7 +501,6 @@ static const struct uart_ops mcf_uart_ops = {
.start_tx = mcf_start_tx,
.stop_tx = mcf_stop_tx,
.stop_rx = mcf_stop_rx,
- .enable_ms = mcf_enable_ms,
.break_ctl = mcf_break_ctl,
.startup = mcf_startup,
.shutdown = mcf_shutdown,
@@ -538,7 +537,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp)
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
- port->flags = ASYNC_BOOT_AUTOCONF;
+ port->flags = UPF_BOOT_AUTOCONF;
port->ops = &mcf_uart_ops;
}
@@ -663,7 +662,7 @@ static int mcf_probe(struct platform_device *pdev)
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
port->ops = &mcf_uart_ops;
- port->flags = ASYNC_BOOT_AUTOCONF;
+ port->flags = UPF_BOOT_AUTOCONF;
uart_add_one_port(&mcf_driver, port);
}
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
new file mode 100644
index 000000000000..30e9e60bc5cd
--- /dev/null
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -0,0 +1,867 @@
+/*
+ * MEN 16z135 High Speed UART
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
+ *
+ * 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.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/tty_flip.h>
+#include <linux/bitops.h>
+#include <linux/mcb.h>
+
+#define MEN_Z135_MAX_PORTS 12
+#define MEN_Z135_BASECLK 29491200
+#define MEN_Z135_FIFO_SIZE 1024
+#define MEN_Z135_NUM_MSI_VECTORS 2
+#define MEN_Z135_FIFO_WATERMARK 1020
+
+#define MEN_Z135_STAT_REG 0x0
+#define MEN_Z135_RX_RAM 0x4
+#define MEN_Z135_TX_RAM 0x400
+#define MEN_Z135_RX_CTRL 0x800
+#define MEN_Z135_TX_CTRL 0x804
+#define MEN_Z135_CONF_REG 0x808
+#define MEN_Z135_UART_FREQ 0x80c
+#define MEN_Z135_BAUD_REG 0x810
+#define MENZ135_TIMEOUT 0x814
+
+#define MEN_Z135_MEM_SIZE 0x818
+
+#define IS_IRQ(x) ((x) & 1)
+#define IRQ_ID(x) (((x) >> 1) & 7)
+
+#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
+#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
+#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */
+#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */
+#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \
+ | MEN_Z135_IER_RLSIEN \
+ | MEN_Z135_IER_MSIEN \
+ | MEN_Z135_IER_TXCIEN)
+
+#define MEN_Z135_MCR_DTR BIT(24)
+#define MEN_Z135_MCR_RTS BIT(25)
+#define MEN_Z135_MCR_OUT1 BIT(26)
+#define MEN_Z135_MCR_OUT2 BIT(27)
+#define MEN_Z135_MCR_LOOP BIT(28)
+#define MEN_Z135_MCR_RCFC BIT(29)
+
+#define MEN_Z135_MSR_DCTS BIT(0)
+#define MEN_Z135_MSR_DDSR BIT(1)
+#define MEN_Z135_MSR_DRI BIT(2)
+#define MEN_Z135_MSR_DDCD BIT(3)
+#define MEN_Z135_MSR_CTS BIT(4)
+#define MEN_Z135_MSR_DSR BIT(5)
+#define MEN_Z135_MSR_RI BIT(6)
+#define MEN_Z135_MSR_DCD BIT(7)
+
+#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */
+
+#define MEN_Z135_WL5 0 /* CS5 */
+#define MEN_Z135_WL6 1 /* CS6 */
+#define MEN_Z135_WL7 2 /* CS7 */
+#define MEN_Z135_WL8 3 /* CS8 */
+
+#define MEN_Z135_STB_SHIFT 2 /* Stopbits */
+#define MEN_Z135_NSTB1 0
+#define MEN_Z135_NSTB2 1
+
+#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */
+#define MEN_Z135_PAR_DIS 0
+#define MEN_Z135_PAR_ENA 1
+
+#define MEN_Z135_PTY_SHIFT 4 /* Parity type */
+#define MEN_Z135_PTY_ODD 0
+#define MEN_Z135_PTY_EVN 1
+
+#define MEN_Z135_LSR_DR BIT(0)
+#define MEN_Z135_LSR_OE BIT(1)
+#define MEN_Z135_LSR_PE BIT(2)
+#define MEN_Z135_LSR_FE BIT(3)
+#define MEN_Z135_LSR_BI BIT(4)
+#define MEN_Z135_LSR_THEP BIT(5)
+#define MEN_Z135_LSR_TEXP BIT(6)
+#define MEN_Z135_LSR_RXFIFOERR BIT(7)
+
+#define MEN_Z135_IRQ_ID_MST 0
+#define MEN_Z135_IRQ_ID_TSA 1
+#define MEN_Z135_IRQ_ID_RDA 2
+#define MEN_Z135_IRQ_ID_RLS 3
+#define MEN_Z135_IRQ_ID_CTI 6
+
+#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
+
+#define BYTES_TO_ALIGN(x) ((x) & 0x3)
+
+static int line;
+
+static int txlvl = 5;
+module_param(txlvl, int, S_IRUGO);
+MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)");
+
+static int rxlvl = 6;
+module_param(rxlvl, int, S_IRUGO);
+MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)");
+
+static int align;
+module_param(align, int, S_IRUGO);
+MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
+
+struct men_z135_port {
+ struct uart_port port;
+ struct mcb_device *mdev;
+ unsigned char *rxbuf;
+ u32 stat_reg;
+ spinlock_t lock;
+};
+#define to_men_z135(port) container_of((port), struct men_z135_port, port)
+
+/**
+ * men_z135_reg_set() - Set value in register
+ * @uart: The UART port
+ * @addr: Register address
+ * @val: value to set
+ */
+static inline void men_z135_reg_set(struct men_z135_port *uart,
+ u32 addr, u32 val)
+{
+ struct uart_port *port = &uart->port;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&uart->lock, flags);
+
+ reg = ioread32(port->membase + addr);
+ reg |= val;
+ iowrite32(reg, port->membase + addr);
+
+ spin_unlock_irqrestore(&uart->lock, flags);
+}
+
+/**
+ * men_z135_reg_clr() - Unset value in register
+ * @uart: The UART port
+ * @addr: Register address
+ * @val: value to clear
+ */
+static inline void men_z135_reg_clr(struct men_z135_port *uart,
+ u32 addr, u32 val)
+{
+ struct uart_port *port = &uart->port;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&uart->lock, flags);
+
+ reg = ioread32(port->membase + addr);
+ reg &= ~val;
+ iowrite32(reg, port->membase + addr);
+
+ spin_unlock_irqrestore(&uart->lock, flags);
+}
+
+/**
+ * men_z135_handle_modem_status() - Handle change of modem status
+ * @port: The UART port
+ *
+ * Handle change of modem status register. This is done by reading the "delta"
+ * versions of DCD (Data Carrier Detect) and CTS (Clear To Send).
+ */
+static void men_z135_handle_modem_status(struct men_z135_port *uart)
+{
+ if (uart->stat_reg & MEN_Z135_MSR_DDCD)
+ uart_handle_dcd_change(&uart->port,
+ uart->stat_reg & ~MEN_Z135_MSR_DCD);
+ if (uart->stat_reg & MEN_Z135_MSR_DCTS)
+ uart_handle_cts_change(&uart->port,
+ uart->stat_reg & ~MEN_Z135_MSR_CTS);
+}
+
+static void men_z135_handle_lsr(struct men_z135_port *uart)
+{
+ struct uart_port *port = &uart->port;
+ u8 lsr;
+
+ lsr = (uart->stat_reg >> 16) & 0xff;
+
+ if (lsr & MEN_Z135_LSR_OE)
+ port->icount.overrun++;
+ if (lsr & MEN_Z135_LSR_PE)
+ port->icount.parity++;
+ if (lsr & MEN_Z135_LSR_FE)
+ port->icount.frame++;
+ if (lsr & MEN_Z135_LSR_BI) {
+ port->icount.brk++;
+ uart_handle_break(port);
+ }
+}
+
+/**
+ * get_rx_fifo_content() - Get the number of bytes in RX FIFO
+ * @uart: The UART port
+ *
+ * Read RXC register from hardware and return current FIFO fill size.
+ */
+static u16 get_rx_fifo_content(struct men_z135_port *uart)
+{
+ struct uart_port *port = &uart->port;
+ u32 stat_reg;
+ u16 rxc;
+ u8 rxc_lo;
+ u8 rxc_hi;
+
+ stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
+ rxc_lo = stat_reg >> 24;
+ rxc_hi = (stat_reg & 0xC0) >> 6;
+
+ rxc = rxc_lo | (rxc_hi << 8);
+
+ return rxc;
+}
+
+/**
+ * men_z135_handle_rx() - RX tasklet routine
+ * @arg: Pointer to struct men_z135_port
+ *
+ * Copy from RX FIFO and acknowledge number of bytes copied.
+ */
+static void men_z135_handle_rx(struct men_z135_port *uart)
+{
+ struct uart_port *port = &uart->port;
+ struct tty_port *tport = &port->state->port;
+ int copied;
+ u16 size;
+ int room;
+
+ size = get_rx_fifo_content(uart);
+
+ if (size == 0)
+ return;
+
+ /* Avoid accidently accessing TX FIFO instead of RX FIFO. Last
+ * longword in RX FIFO cannot be read.(0x004-0x3FF)
+ */
+ if (size > MEN_Z135_FIFO_WATERMARK)
+ size = MEN_Z135_FIFO_WATERMARK;
+
+ room = tty_buffer_request_room(tport, size);
+ if (room != size)
+ dev_warn(&uart->mdev->dev,
+ "Not enough room in flip buffer, truncating to %d\n",
+ room);
+
+ if (room == 0)
+ return;
+
+ memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room);
+ /* Be sure to first copy all data and then acknowledge it */
+ mb();
+ iowrite32(room, port->membase + MEN_Z135_RX_CTRL);
+
+ copied = tty_insert_flip_string(tport, uart->rxbuf, room);
+ if (copied != room)
+ dev_warn(&uart->mdev->dev,
+ "Only copied %d instead of %d bytes\n",
+ copied, room);
+
+ port->icount.rx += copied;
+
+ tty_flip_buffer_push(tport);
+
+}
+
+/**
+ * men_z135_handle_tx() - TX tasklet routine
+ * @arg: Pointer to struct men_z135_port
+ *
+ */
+static void men_z135_handle_tx(struct men_z135_port *uart)
+{
+ struct uart_port *port = &uart->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ u32 txc;
+ u32 wptr;
+ int qlen;
+ int n;
+ int txfree;
+ int head;
+ int tail;
+ int s;
+
+ if (uart_circ_empty(xmit))
+ goto out;
+
+ if (uart_tx_stopped(port))
+ goto out;
+
+ if (port->x_char)
+ goto out;
+
+ /* calculate bytes to copy */
+ qlen = uart_circ_chars_pending(xmit);
+ if (qlen <= 0)
+ goto out;
+
+ wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
+ txc = (wptr >> 16) & 0x3ff;
+ wptr &= 0x3ff;
+
+ if (txc > MEN_Z135_FIFO_WATERMARK)
+ txc = MEN_Z135_FIFO_WATERMARK;
+
+ txfree = MEN_Z135_FIFO_WATERMARK - txc;
+ if (txfree <= 0) {
+ pr_err("Not enough room in TX FIFO have %d, need %d\n",
+ txfree, qlen);
+ goto irq_en;
+ }
+
+ /* if we're not aligned, it's better to copy only 1 or 2 bytes and
+ * then the rest.
+ */
+ if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr))
+ n = 4 - BYTES_TO_ALIGN(wptr);
+ else if (qlen > txfree)
+ n = txfree;
+ else
+ n = qlen;
+
+ if (n <= 0)
+ goto irq_en;
+
+ head = xmit->head & (UART_XMIT_SIZE - 1);
+ tail = xmit->tail & (UART_XMIT_SIZE - 1);
+
+ s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
+ n = min(n, s);
+
+ memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
+ xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
+ mmiowb();
+
+ iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
+
+ port->icount.tx += n;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+irq_en:
+ if (!uart_circ_empty(xmit))
+ men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
+ else
+ men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
+
+out:
+ return;
+
+}
+
+/**
+ * men_z135_intr() - Handle legacy IRQs
+ * @irq: The IRQ number
+ * @data: Pointer to UART port
+ *
+ * Check IIR register to see which tasklet to start.
+ */
+static irqreturn_t men_z135_intr(int irq, void *data)
+{
+ struct men_z135_port *uart = (struct men_z135_port *)data;
+ struct uart_port *port = &uart->port;
+ int irq_id;
+
+ uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
+ /* IRQ pending is low active */
+ if (IS_IRQ(uart->stat_reg))
+ return IRQ_NONE;
+
+ irq_id = IRQ_ID(uart->stat_reg);
+ switch (irq_id) {
+ case MEN_Z135_IRQ_ID_MST:
+ men_z135_handle_modem_status(uart);
+ break;
+ case MEN_Z135_IRQ_ID_TSA:
+ men_z135_handle_tx(uart);
+ break;
+ case MEN_Z135_IRQ_ID_CTI:
+ dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
+ /* Fallthrough */
+ case MEN_Z135_IRQ_ID_RDA:
+ /* Reading data clears RX IRQ */
+ men_z135_handle_rx(uart);
+ break;
+ case MEN_Z135_IRQ_ID_RLS:
+ men_z135_handle_lsr(uart);
+ break;
+ default:
+ dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * men_z135_request_irq() - Request IRQ for 16z135 core
+ * @uart: z135 private uart port structure
+ *
+ * Request an IRQ for 16z135 to use. First try using MSI, if it fails
+ * fall back to using legacy interrupts.
+ */
+static int men_z135_request_irq(struct men_z135_port *uart)
+{
+ struct device *dev = &uart->mdev->dev;
+ struct uart_port *port = &uart->port;
+ int err = 0;
+
+ err = request_irq(port->irq, men_z135_intr, IRQF_SHARED,
+ "men_z135_intr", uart);
+ if (err)
+ dev_err(dev, "Error %d getting interrupt\n", err);
+
+ return err;
+}
+
+/**
+ * men_z135_tx_empty() - Handle tx_empty call
+ * @port: The UART port
+ *
+ * This function tests whether the TX FIFO and shifter for the port
+ * described by @port is empty.
+ */
+static unsigned int men_z135_tx_empty(struct uart_port *port)
+{
+ u32 wptr;
+ u16 txc;
+
+ wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
+ txc = (wptr >> 16) & 0x3ff;
+
+ if (txc == 0)
+ return TIOCSER_TEMT;
+ else
+ return 0;
+}
+
+/**
+ * men_z135_set_mctrl() - Set modem control lines
+ * @port: The UART port
+ * @mctrl: The modem control lines
+ *
+ * This function sets the modem control lines for a port described by @port
+ * to the state described by @mctrl
+ */
+static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+ u32 conf_reg = 0;
+
+ if (mctrl & TIOCM_RTS)
+ conf_reg |= MEN_Z135_MCR_RTS;
+ if (mctrl & TIOCM_DTR)
+ conf_reg |= MEN_Z135_MCR_DTR;
+ if (mctrl & TIOCM_OUT1)
+ conf_reg |= MEN_Z135_MCR_OUT1;
+ if (mctrl & TIOCM_OUT2)
+ conf_reg |= MEN_Z135_MCR_OUT2;
+ if (mctrl & TIOCM_LOOP)
+ conf_reg |= MEN_Z135_MCR_LOOP;
+
+ men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
+}
+
+/**
+ * men_z135_get_mctrl() - Get modem control lines
+ * @port: The UART port
+ *
+ * Retruns the current state of modem control inputs.
+ */
+static unsigned int men_z135_get_mctrl(struct uart_port *port)
+{
+ unsigned int mctrl = 0;
+ u32 stat_reg;
+ u8 msr;
+
+ stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
+
+ msr = ~((stat_reg >> 8) & 0xff);
+
+ if (msr & MEN_Z135_MSR_CTS)
+ mctrl |= TIOCM_CTS;
+ if (msr & MEN_Z135_MSR_DSR)
+ mctrl |= TIOCM_DSR;
+ if (msr & MEN_Z135_MSR_RI)
+ mctrl |= TIOCM_RI;
+ if (msr & MEN_Z135_MSR_DCD)
+ mctrl |= TIOCM_CAR;
+
+ return mctrl;
+}
+
+/**
+ * men_z135_stop_tx() - Stop transmitting characters
+ * @port: The UART port
+ *
+ * Stop transmitting characters. This might be due to CTS line becomming
+ * inactive or the tty layer indicating we want to stop transmission due to
+ * an XOFF character.
+ */
+static void men_z135_stop_tx(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+
+ men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
+}
+
+/**
+ * men_z135_start_tx() - Start transmitting characters
+ * @port: The UART port
+ *
+ * Start transmitting character. This actually doesn't transmit anything, but
+ * fires off the TX tasklet.
+ */
+static void men_z135_start_tx(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+
+ men_z135_handle_tx(uart);
+}
+
+/**
+ * men_z135_stop_rx() - Stop receiving characters
+ * @port: The UART port
+ *
+ * Stop receiving characters; the port is in the process of being closed.
+ */
+static void men_z135_stop_rx(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+
+ men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN);
+}
+
+/**
+ * men_z135_enable_ms() - Enable Modem Status
+ * port:
+ *
+ * Enable Modem Status IRQ.
+ */
+static void men_z135_enable_ms(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+
+ men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
+}
+
+static int men_z135_startup(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+ int err;
+ u32 conf_reg = 0;
+
+ err = men_z135_request_irq(uart);
+ if (err)
+ return -ENODEV;
+
+ conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
+
+ /* Activate all but TX space available IRQ */
+ conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN;
+ conf_reg &= ~(0xff << 16);
+ conf_reg |= (txlvl << 16);
+ conf_reg |= (rxlvl << 20);
+
+ iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
+
+ return 0;
+}
+
+static void men_z135_shutdown(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+ u32 conf_reg = 0;
+
+ conf_reg |= MEN_Z135_ALL_IRQS;
+
+ men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg);
+
+ free_irq(uart->port.irq, uart);
+}
+
+static void men_z135_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud;
+ u32 conf_reg;
+ u32 bd_reg;
+ u32 uart_freq;
+ u8 lcr;
+
+ conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
+ lcr = LCR(conf_reg);
+
+ /* byte size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr |= MEN_Z135_WL5;
+ break;
+ case CS6:
+ lcr |= MEN_Z135_WL6;
+ break;
+ case CS7:
+ lcr |= MEN_Z135_WL7;
+ break;
+ case CS8:
+ lcr |= MEN_Z135_WL8;
+ break;
+ }
+
+ /* stop bits */
+ if (termios->c_cflag & CSTOPB)
+ lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT;
+
+ /* parity */
+ if (termios->c_cflag & PARENB) {
+ lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT;
+
+ if (termios->c_cflag & PARODD)
+ lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT;
+ else
+ lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT;
+ } else
+ lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
+
+ termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+ conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
+ iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
+
+ uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ);
+ if (uart_freq == 0)
+ uart_freq = MEN_Z135_BASECLK;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16);
+
+ spin_lock(&port->lock);
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+ bd_reg = uart_freq / (4 * baud);
+ iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG);
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+ spin_unlock(&port->lock);
+}
+
+static const char *men_z135_type(struct uart_port *port)
+{
+ return KBUILD_MODNAME;
+}
+
+static void men_z135_release_port(struct uart_port *port)
+{
+ iounmap(port->membase);
+ port->membase = NULL;
+
+ release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
+}
+
+static int men_z135_request_port(struct uart_port *port)
+{
+ int size = MEN_Z135_MEM_SIZE;
+
+ if (!request_mem_region(port->mapbase, size, "men_z135_port"))
+ return -EBUSY;
+
+ port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
+ if (port->membase == NULL) {
+ release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void men_z135_config_port(struct uart_port *port, int type)
+{
+ port->type = PORT_MEN_Z135;
+ men_z135_request_port(port);
+}
+
+static int men_z135_verify_port(struct uart_port *port,
+ struct serial_struct *serinfo)
+{
+ return -EINVAL;
+}
+
+static struct uart_ops men_z135_ops = {
+ .tx_empty = men_z135_tx_empty,
+ .set_mctrl = men_z135_set_mctrl,
+ .get_mctrl = men_z135_get_mctrl,
+ .stop_tx = men_z135_stop_tx,
+ .start_tx = men_z135_start_tx,
+ .stop_rx = men_z135_stop_rx,
+ .enable_ms = men_z135_enable_ms,
+ .startup = men_z135_startup,
+ .shutdown = men_z135_shutdown,
+ .set_termios = men_z135_set_termios,
+ .type = men_z135_type,
+ .release_port = men_z135_release_port,
+ .request_port = men_z135_request_port,
+ .config_port = men_z135_config_port,
+ .verify_port = men_z135_verify_port,
+};
+
+static struct uart_driver men_z135_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = KBUILD_MODNAME,
+ .dev_name = "ttyHSU",
+ .major = 0,
+ .minor = 0,
+ .nr = MEN_Z135_MAX_PORTS,
+};
+
+/**
+ * men_z135_probe() - Probe a z135 instance
+ * @mdev: The MCB device
+ * @id: The MCB device ID
+ *
+ * men_z135_probe does the basic setup of hardware resources and registers the
+ * new uart port to the tty layer.
+ */
+static int men_z135_probe(struct mcb_device *mdev,
+ const struct mcb_device_id *id)
+{
+ struct men_z135_port *uart;
+ struct resource *mem;
+ struct device *dev;
+ int err;
+
+ dev = &mdev->dev;
+
+ uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL);
+ if (!uart)
+ return -ENOMEM;
+
+ uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!uart->rxbuf)
+ return -ENOMEM;
+
+ mem = &mdev->mem;
+
+ mcb_set_drvdata(mdev, uart);
+
+ uart->port.uartclk = MEN_Z135_BASECLK * 16;
+ uart->port.fifosize = MEN_Z135_FIFO_SIZE;
+ uart->port.iotype = UPIO_MEM;
+ uart->port.ops = &men_z135_ops;
+ uart->port.irq = mcb_get_irq(mdev);
+ uart->port.iotype = UPIO_MEM;
+ uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ uart->port.line = line++;
+ uart->port.dev = dev;
+ uart->port.type = PORT_MEN_Z135;
+ uart->port.mapbase = mem->start;
+ uart->port.membase = NULL;
+ uart->mdev = mdev;
+
+ spin_lock_init(&uart->port.lock);
+ spin_lock_init(&uart->lock);
+
+ err = uart_add_one_port(&men_z135_driver, &uart->port);
+ if (err)
+ goto err;
+
+ return 0;
+
+err:
+ free_page((unsigned long) uart->rxbuf);
+ dev_err(dev, "Failed to add UART: %d\n", err);
+
+ return err;
+}
+
+/**
+ * men_z135_remove() - Remove a z135 instance from the system
+ *
+ * @mdev: The MCB device
+ */
+static void men_z135_remove(struct mcb_device *mdev)
+{
+ struct men_z135_port *uart = mcb_get_drvdata(mdev);
+
+ line--;
+ uart_remove_one_port(&men_z135_driver, &uart->port);
+ free_page((unsigned long) uart->rxbuf);
+}
+
+static const struct mcb_device_id men_z135_ids[] = {
+ { .device = 0x87 },
+};
+MODULE_DEVICE_TABLE(mcb, men_z135_ids);
+
+static struct mcb_driver mcb_driver = {
+ .driver = {
+ .name = "z135-uart",
+ .owner = THIS_MODULE,
+ },
+ .probe = men_z135_probe,
+ .remove = men_z135_remove,
+ .id_table = men_z135_ids,
+};
+
+/**
+ * men_z135_init() - Driver Registration Routine
+ *
+ * men_z135_init is the first routine called when the driver is loaded. All it
+ * does is register with the legacy MEN Chameleon subsystem.
+ */
+static int __init men_z135_init(void)
+{
+ int err;
+
+ err = uart_register_driver(&men_z135_driver);
+ if (err) {
+ pr_err("Failed to register UART: %d\n", err);
+ return err;
+ }
+
+ err = mcb_register_driver(&mcb_driver);
+ if (err) {
+ pr_err("Failed to register MCB driver: %d\n", err);
+ uart_unregister_driver(&men_z135_driver);
+ return err;
+ }
+
+ return 0;
+}
+module_init(men_z135_init);
+
+/**
+ * men_z135_exit() - Driver Exit Routine
+ *
+ * men_z135_exit is called just before the driver is removed from memory.
+ */
+static void __exit men_z135_exit(void)
+{
+ mcb_unregister_driver(&mcb_driver);
+ uart_unregister_driver(&men_z135_driver);
+}
+module_exit(men_z135_exit);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
+MODULE_ALIAS("mcb:16z135");
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index 52c930fac210..445799dc9846 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -977,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/* Characters to ignore */
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index e30a3ca3cea3..ae49856ef6c7 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -1336,10 +1336,6 @@ static void mpsc_stop_rx(struct uart_port *port)
mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
}
-static void mpsc_enable_ms(struct uart_port *port)
-{
-}
-
static void mpsc_break_ctl(struct uart_port *port, int ctl)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1458,7 +1454,7 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
| SDMA_DESC_CMDSTAT_FR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
/* Characters/events to ignore */
@@ -1674,7 +1670,6 @@ static struct uart_ops mpsc_pops = {
.stop_tx = mpsc_stop_tx,
.start_tx = mpsc_start_tx,
.stop_rx = mpsc_stop_rx,
- .enable_ms = mpsc_enable_ms,
.break_ctl = mpsc_break_ctl,
.startup = mpsc_startup,
.shutdown = mpsc_shutdown,
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index db0448ae59dc..1504a14ec1a6 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -698,10 +698,6 @@ static void serial_m3110_pm(struct uart_port *port, unsigned int state,
{
}
-static void serial_m3110_enable_ms(struct uart_port *port)
-{
-}
-
static struct uart_ops serial_m3110_ops = {
.tx_empty = serial_m3110_tx_empty,
.set_mctrl = serial_m3110_set_mctrl,
@@ -709,7 +705,6 @@ static struct uart_ops serial_m3110_ops = {
.stop_tx = serial_m3110_stop_tx,
.start_tx = serial_m3110_start_tx,
.stop_rx = serial_m3110_stop_rx,
- .enable_ms = serial_m3110_enable_ms,
.break_ctl = serial_m3110_break_ctl,
.startup = serial_m3110_startup,
.shutdown = serial_m3110_shutdown,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 053b98eb46c8..0da0b5474e98 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -52,7 +52,6 @@ struct msm_port {
struct clk *clk;
struct clk *pclk;
unsigned int imr;
- void __iomem *gsbi_base;
int is_uartdm;
unsigned int old_snap_state;
};
@@ -126,14 +125,14 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
port->icount.rx += count;
while (count > 0) {
- unsigned int c;
+ unsigned char buf[4];
sr = msm_read(port, UART_SR);
if ((sr & UART_SR_RX_READY) == 0) {
msm_port->old_snap_state -= count;
break;
}
- c = msm_read(port, UARTDM_RF);
+ ioread32_rep(port->membase + UARTDM_RF, buf, 1);
if (sr & UART_SR_RX_BREAK) {
port->icount.brk++;
if (uart_handle_break(port))
@@ -142,8 +141,7 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
port->icount.frame++;
/* TODO: handle sysrq */
- tty_insert_flip_string(tport, (char *)&c,
- (count > 4) ? 4 : count);
+ tty_insert_flip_string(tport, buf, min(count, 4));
count -= 4;
}
@@ -220,6 +218,12 @@ static void handle_tx(struct uart_port *port)
struct msm_port *msm_port = UART_TO_MSM(port);
unsigned int tx_count, num_chars;
unsigned int tf_pointer = 0;
+ void __iomem *tf;
+
+ if (msm_port->is_uartdm)
+ tf = port->membase + UARTDM_TF;
+ else
+ tf = port->membase + UART_TF;
tx_count = uart_circ_chars_pending(xmit);
tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
@@ -229,8 +233,7 @@ static void handle_tx(struct uart_port *port)
if (msm_port->is_uartdm)
reset_dm_count(port, tx_count + 1);
- msm_write(port, port->x_char,
- msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+ iowrite8_rep(tf, &port->x_char, 1);
port->icount.tx++;
port->x_char = 0;
} else if (tx_count && msm_port->is_uartdm) {
@@ -240,7 +243,6 @@ static void handle_tx(struct uart_port *port)
while (tf_pointer < tx_count) {
int i;
char buf[4] = { 0 };
- unsigned int *bf = (unsigned int *)&buf;
if (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
break;
@@ -256,7 +258,7 @@ static void handle_tx(struct uart_port *port)
port->icount.tx++;
}
- msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+ iowrite32_rep(tf, buf, 1);
xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1);
tf_pointer += num_chars;
}
@@ -583,7 +585,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART_SR_RX_BREAK;
uart_update_timeout(port, termios->c_cflag, baud);
@@ -599,9 +601,7 @@ static const char *msm_type(struct uart_port *port)
static void msm_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
- struct msm_port *msm_port = UART_TO_MSM(port);
struct resource *uart_resource;
- struct resource *gsbi_resource;
resource_size_t size;
uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -612,28 +612,12 @@ static void msm_release_port(struct uart_port *port)
release_mem_region(port->mapbase, size);
iounmap(port->membase);
port->membase = NULL;
-
- if (msm_port->gsbi_base) {
- writel_relaxed(GSBI_PROTOCOL_IDLE,
- msm_port->gsbi_base + GSBI_CONTROL);
-
- gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (unlikely(!gsbi_resource))
- return;
-
- size = resource_size(gsbi_resource);
- release_mem_region(gsbi_resource->start, size);
- iounmap(msm_port->gsbi_base);
- msm_port->gsbi_base = NULL;
- }
}
static int msm_request_port(struct uart_port *port)
{
- struct msm_port *msm_port = UART_TO_MSM(port);
struct platform_device *pdev = to_platform_device(port->dev);
struct resource *uart_resource;
- struct resource *gsbi_resource;
resource_size_t size;
int ret;
@@ -652,30 +636,8 @@ static int msm_request_port(struct uart_port *port)
goto fail_release_port;
}
- gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- /* Is this a GSBI-based port? */
- if (gsbi_resource) {
- size = resource_size(gsbi_resource);
-
- if (!request_mem_region(gsbi_resource->start, size,
- "msm_serial")) {
- ret = -EBUSY;
- goto fail_release_port_membase;
- }
-
- msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
- if (!msm_port->gsbi_base) {
- ret = -EBUSY;
- goto fail_release_gsbi;
- }
- }
-
return 0;
-fail_release_gsbi:
- release_mem_region(gsbi_resource->start, size);
-fail_release_port_membase:
- iounmap(port->membase);
fail_release_port:
release_mem_region(port->mapbase, size);
return ret;
@@ -683,7 +645,6 @@ fail_release_port:
static void msm_config_port(struct uart_port *port, int flags)
{
- struct msm_port *msm_port = UART_TO_MSM(port);
int ret;
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_MSM;
@@ -691,9 +652,6 @@ static void msm_config_port(struct uart_port *port, int flags)
if (ret)
return;
}
- if (msm_port->gsbi_base)
- writel_relaxed(GSBI_PROTOCOL_UART,
- msm_port->gsbi_base + GSBI_CONTROL);
}
static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -906,12 +864,18 @@ static void msm_console_write(struct console *co, const char *s,
struct msm_port *msm_port;
int num_newlines = 0;
bool replaced = false;
+ void __iomem *tf;
BUG_ON(co->index < 0 || co->index >= UART_NR);
port = get_port_from_line(co->index);
msm_port = UART_TO_MSM(port);
+ if (msm_port->is_uartdm)
+ tf = port->membase + UARTDM_TF;
+ else
+ tf = port->membase + UART_TF;
+
/* Account for newlines that will get a carriage return added */
for (i = 0; i < count; i++)
if (s[i] == '\n')
@@ -927,7 +891,6 @@ static void msm_console_write(struct console *co, const char *s,
int j;
unsigned int num_chars;
char buf[4] = { 0 };
- unsigned int *bf = (unsigned int *)&buf;
if (msm_port->is_uartdm)
num_chars = min(count - i, (unsigned int)sizeof(buf));
@@ -952,7 +915,7 @@ static void msm_console_write(struct console *co, const char *s,
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
cpu_relax();
- msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+ iowrite32_rep(tf, buf, 1);
i += num_chars;
}
spin_unlock(&port->lock);
@@ -962,7 +925,7 @@ static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
struct msm_port *msm_port;
- int baud, flow, bits, parity;
+ int baud = 0, flow, bits, parity;
if (unlikely(co->index >= UART_NR || co->index < 0))
return -ENXIO;
@@ -1036,7 +999,7 @@ static const struct of_device_id msm_uartdm_table[] = {
{ }
};
-static int __init msm_serial_probe(struct platform_device *pdev)
+static int msm_serial_probe(struct platform_device *pdev)
{
struct msm_port *msm_port;
struct resource *resource;
@@ -1102,7 +1065,7 @@ static int msm_serial_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id msm_match_table[] = {
+static const struct of_device_id msm_match_table[] = {
{ .compatible = "qcom,msm-uart" },
{ .compatible = "qcom,msm-uartdm" },
{}
@@ -1110,6 +1073,7 @@ static struct of_device_id msm_match_table[] = {
static struct platform_driver msm_platform_driver = {
.remove = msm_serial_remove,
+ .probe = msm_serial_probe,
.driver = {
.name = "msm_serial",
.owner = THIS_MODULE,
@@ -1125,7 +1089,7 @@ static int __init msm_serial_init(void)
if (unlikely(ret))
return ret;
- ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+ ret = platform_driver_register(&msm_platform_driver);
if (unlikely(ret))
uart_unregister_driver(&msm_uart_driver);
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index 1e9b68b6f9eb..73d3abe71e79 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -109,11 +109,6 @@
#define UART_ISR 0x0014
#define UART_ISR_TX_READY (1 << 7)
-#define GSBI_CONTROL 0x0
-#define GSBI_PROTOCOL_CODE 0x30
-#define GSBI_PROTOCOL_UART 0x40
-#define GSBI_PROTOCOL_IDLE 0x0
-
#define UARTDM_RXFS 0x50
#define UARTDM_RXFS_BUF_SHIFT 0x7
#define UARTDM_RXFS_BUF_MASK 0x7
@@ -131,13 +126,13 @@
static inline
void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
{
- __raw_writel(val, port->membase + off);
+ writel_relaxed(val, port->membase + off);
}
static inline
unsigned int msm_read(struct uart_port *port, unsigned int off)
{
- return __raw_readl(port->membase + off);
+ return readl_relaxed(port->membase + off);
}
/*
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 7fd6aaaacd8e..dd26511ad875 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -29,7 +29,7 @@
#include <asm/irq.h>
#include <asm/parisc-device.h>
-#ifdef CONFIG_MAGIC_SYSRQ
+#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#include <linux/sysrq.h>
#define SUPPORT_SYSRQ
#endif
@@ -169,16 +169,6 @@ static void mux_stop_rx(struct uart_port *port)
}
/**
- * mux_enable_ms - Enable modum status interrupts.
- * @port: Ptr to the uart_port.
- *
- * The Serial Mux does not support this function.
- */
-static void mux_enable_ms(struct uart_port *port)
-{
-}
-
-/**
* mux_break_ctl - Control the transmitssion of a break signal.
* @port: Ptr to the uart_port.
* @break_state: Raise/Lower the break signal.
@@ -449,7 +439,6 @@ static struct uart_ops mux_pops = {
.stop_tx = mux_stop_tx,
.start_tx = mux_start_tx,
.stop_rx = mux_stop_rx,
- .enable_ms = mux_enable_ms,
.break_ctl = mux_break_ctl,
.startup = mux_startup,
.shutdown = mux_shutdown,
@@ -613,7 +602,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
- del_timer(&mux_timer);
+ del_timer_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index aa97fd845b4d..b5c329248c81 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -200,7 +200,7 @@ static void dma_tx_callback(void *param)
/* clear the bit used to serialize the DMA tx. */
clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
/* wake up the possible processes. */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -275,7 +275,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
mxs_auart_dma_tx(s, i);
} else {
clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
}
return;
}
@@ -604,7 +604,7 @@ static void mxs_auart_settermios(struct uart_port *u,
if (termios->c_iflag & INPCK)
u->read_status_mask |= AUART_STAT_PERR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
u->read_status_mask |= AUART_STAT_BERR;
/*
@@ -815,17 +815,11 @@ static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
u->membase + AUART_LINECTRL_CLR);
}
-static void mxs_auart_enable_ms(struct uart_port *port)
-{
- /* just empty */
-}
-
static struct uart_ops mxs_auart_ops = {
.tx_empty = mxs_auart_tx_empty,
.start_tx = mxs_auart_start_tx,
.stop_tx = mxs_auart_stop_tx,
.stop_rx = mxs_auart_stop_rx,
- .enable_ms = mxs_auart_enable_ms,
.break_ctl = mxs_auart_break_ctl,
.set_mctrl = mxs_auart_set_mctrl,
.get_mctrl = mxs_auart_get_mctrl,
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
index 0a4dd70d29eb..7a6745601d4e 100644
--- a/drivers/tty/serial/netx-serial.c
+++ b/drivers/tty/serial/netx-serial.c
@@ -419,7 +419,7 @@ netx_set_termios(struct uart_port *port, struct ktermios *termios,
}
port->read_status_mask = 0;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= SR_BE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= SR_PE | SR_FE;
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index 693bc6c2561e..c06366b6bc29 100644
--- a/drivers/tty/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
@@ -240,11 +240,6 @@ static void nwpserial_break_ctl(struct uart_port *port, int ctl)
/* N/A */
}
-static void nwpserial_enable_ms(struct uart_port *port)
-{
- /* N/A */
-}
-
static void nwpserial_stop_rx(struct uart_port *port)
{
struct nwpserial_port *up;
@@ -315,7 +310,6 @@ static struct uart_ops nwpserial_pops = {
.stop_tx = nwpserial_stop_tx,
.start_tx = nwpserial_start_tx,
.stop_rx = nwpserial_stop_rx,
- .enable_ms = nwpserial_enable_ms,
.break_ctl = nwpserial_break_ctl,
.startup = nwpserial_startup,
.shutdown = nwpserial_shutdown,
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 99246606a256..68d4455f3cf9 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -173,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
{
struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250));
+ port.type = port_type;
port8250.port = port;
if (port.fifosize)
@@ -182,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
"auto-flow-control"))
port8250.capabilities |= UART_CAP_AFE;
+ if (of_property_read_bool(ofdev->dev.of_node,
+ "has-hw-flow-control"))
+ port8250.port.flags |= UPF_HARD_FLOW;
+
ret = serial8250_register_8250_port(&port8250);
break;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 08b6b9419f0d..d017cec8a34a 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -163,10 +163,6 @@ struct uart_omap_port {
u8 wakeups_enabled;
u32 features;
- int DTR_gpio;
- int DTR_inverted;
- int DTR_active;
-
struct serial_rs485 rs485;
int rts_gpio;
@@ -184,8 +180,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
-static struct workqueue_struct *serial_omap_uart_wq;
-
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{
offset <<= up->port.regshift;
@@ -398,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
break;
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
- spin_unlock(&up->port.lock);
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- spin_lock(&up->port.lock);
- }
if (uart_circ_empty(xmit))
serial_omap_stop_tx(&up->port);
@@ -697,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_out(up, UART_MCR, up->mcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
-
- if (gpio_is_valid(up->DTR_gpio) &&
- !!(mctrl & TIOCM_DTR) != up->DTR_active) {
- up->DTR_active = !up->DTR_active;
- if (gpio_cansleep(up->DTR_gpio))
- schedule_work(&up->qos_work);
- else
- gpio_set_value(up->DTR_gpio,
- up->DTR_active != up->DTR_inverted);
- }
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -850,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
- if (gpio_is_valid(up->DTR_gpio))
- gpio_set_value_cansleep(up->DTR_gpio,
- up->DTR_active != up->DTR_inverted);
}
static void
@@ -1420,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
switch (cmd) {
case TIOCSRS485:
- if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ if (copy_from_user(&rs485conf, (void __user *) arg,
sizeof(rs485conf)))
return -EFAULT;
@@ -1428,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
break;
case TIOCGRS485:
- if (copy_to_user((struct serial_rs485 *) arg,
+ if (copy_to_user((void __user *) arg,
&(to_uart_omap_port(port)->rs485),
sizeof(rs485conf)))
return -EFAULT;
@@ -1614,7 +1592,7 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
/* check for tx enable gpio */
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
if (gpio_is_valid(up->rts_gpio)) {
- ret = gpio_request(up->rts_gpio, "omap-serial");
+ ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");
if (ret < 0)
return ret;
ret = gpio_direction_output(up->rts_gpio,
@@ -1644,10 +1622,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
static int serial_omap_probe(struct platform_device *pdev)
{
- struct uart_omap_port *up;
- struct resource *mem, *irq;
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
- int ret, uartirq = 0, wakeirq = 0;
+ struct uart_omap_port *up;
+ struct resource *mem;
+ void __iomem *base;
+ int uartirq = 0;
+ int wakeirq = 0;
+ int ret;
/* The optional wakeirq may be specified in the board dts file */
if (pdev->dev.of_node) {
@@ -1658,48 +1639,19 @@ static int serial_omap_probe(struct platform_device *pdev)
omap_up_info = of_get_uart_port_info(&pdev->dev);
pdev->dev.platform_data = omap_up_info;
} else {
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq) {
- dev_err(&pdev->dev, "no irq resource?\n");
- return -ENODEV;
- }
- uartirq = irq->start;
- }
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
- if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
- pdev->dev.driver->name)) {
- dev_err(&pdev->dev, "memory region already claimed\n");
- return -EBUSY;
- }
-
- if (gpio_is_valid(omap_up_info->DTR_gpio) &&
- omap_up_info->DTR_present) {
- ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
- if (ret < 0)
- return ret;
- ret = gpio_direction_output(omap_up_info->DTR_gpio,
- omap_up_info->DTR_inverted);
- if (ret < 0)
- return ret;
+ uartirq = platform_get_irq(pdev, 0);
+ if (uartirq < 0)
+ return -EPROBE_DEFER;
}
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
- if (gpio_is_valid(omap_up_info->DTR_gpio) &&
- omap_up_info->DTR_present) {
- up->DTR_gpio = omap_up_info->DTR_gpio;
- up->DTR_inverted = omap_up_info->DTR_inverted;
- } else
- up->DTR_gpio = -EINVAL;
- up->DTR_active = 0;
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
up->dev = &pdev->dev;
up->port.dev = &pdev->dev;
@@ -1733,14 +1685,7 @@ static int serial_omap_probe(struct platform_device *pdev)
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
- up->port.membase = devm_ioremap(&pdev->dev, mem->start,
- resource_size(mem));
- if (!up->port.membase) {
- dev_err(&pdev->dev, "can't ioremap UART\n");
- ret = -ENOMEM;
- goto err_ioremap;
- }
-
+ up->port.membase = base;
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
if (!up->port.uartclk) {
@@ -1754,12 +1699,12 @@ static int serial_omap_probe(struct platform_device *pdev)
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
pm_qos_add_request(&up->pm_qos_request,
PM_QOS_CPU_DMA_LATENCY, up->latency);
- serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
platform_set_drvdata(pdev, up);
if (omap_up_info->autosuspend_timeout == 0)
omap_up_info->autosuspend_timeout = -1;
+
device_init_wakeup(up->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
@@ -1786,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev)
err_add_port:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-err_ioremap:
err_rs485:
err_port_line:
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 0931b3fe9edf..ea4ffc2ebb2f 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -257,6 +257,8 @@ struct eg20t_port {
dma_addr_t rx_buf_dma;
struct dentry *debugfs;
+#define IRQ_NAME_SIZE 17
+ char irq_name[IRQ_NAME_SIZE];
/* protect the eg20t_port private structure and io access to membase */
spinlock_t lock;
@@ -734,9 +736,10 @@ static void pch_request_dma(struct uart_port *port)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number,
- PCI_DEVFN(0xa, 0)); /* Get DMA's dev
- information */
+ /* Get DMA's dev information */
+ dma_dev = pci_get_slot(priv->pdev->bus,
+ PCI_DEVFN(PCI_SLOT(priv->pdev->devfn), 0));
+
/* Set Tx DMA */
param = &priv->param_tx;
param->dma_dev = &dma_dev->dev;
@@ -1045,7 +1048,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
- dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
+ dev_err(priv->port.dev, "%s:dmaengine_prep_slave_sg Failed\n",
__func__);
return 0;
}
@@ -1343,7 +1346,7 @@ static int pch_uart_startup(struct uart_port *port)
return ret;
ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
- KBUILD_MODNAME, priv);
+ priv->irq_name, priv);
if (ret < 0)
return ret;
@@ -1588,13 +1591,8 @@ static void pch_uart_put_poll_char(struct uart_port *port,
wait_for_xmitr(priv, UART_LSR_THRE);
/*
* Send the character out.
- * If a LF, also do CR...
*/
iowrite8(c, priv->membase + PCH_UART_THR);
- if (c == 10) {
- wait_for_xmitr(priv, UART_LSR_THRE);
- iowrite8(13, priv->membase + PCH_UART_THR);
- }
/*
* Finally, wait for transmitter to become empty
@@ -1818,6 +1816,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.line = board->line_no;
priv->trigger = PCH_UART_HAL_TRIGGER_M;
+ snprintf(priv->irq_name, IRQ_NAME_SIZE,
+ KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
+ priv->port.line);
+
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index e9d420ff3931..f7ad5b903055 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -653,6 +653,8 @@ static void pmz_start_tx(struct uart_port *port)
} else {
struct circ_buf *xmit = &port->state->xmit;
+ if (uart_circ_empty(xmit))
+ goto out;
write_zsdata(uap, xmit->buf[xmit->tail]);
zssync(uap);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -661,6 +663,7 @@ static void pmz_start_tx(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
}
+ out:
pmz_debug("pmz: start_tx() done.\n");
}
@@ -1092,7 +1095,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
uap->port.read_status_mask = Rx_OVR;
if (iflag & INPCK)
uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
- if (iflag & (BRKINT | PARMRK))
+ if (iflag & (IGNBRK | BRKINT | PARMRK))
uap->port.read_status_mask |= BRK_ABRT;
uap->port.ignore_status_mask = 0;
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
index de6c05c63683..2ba24a45c97f 100644
--- a/drivers/tty/serial/pnx8xxx_uart.c
+++ b/drivers/tty/serial/pnx8xxx_uart.c
@@ -477,7 +477,7 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.read_status_mask |=
FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
sport->port.read_status_mask |=
ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index f9f20f383760..21b7d8b86493 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -492,7 +492,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
@@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port,
wait_for_xmitr(up);
/*
* Send the character out.
- * If a LF, also do CR...
*/
serial_out(up, UART_TX, c);
- if (c == 10) {
- wait_for_xmitr(up);
- serial_out(up, UART_TX, 13);
- }
/*
* Finally, wait for transmitter to become empty
@@ -783,7 +778,7 @@ static struct uart_ops serial_pxa_pops = {
.request_port = serial_pxa_request_port,
.config_port = serial_pxa_config_port,
.verify_port = serial_pxa_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
+#if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_PXA_CONSOLE)
.poll_get_char = serial_pxa_get_poll_char,
.poll_put_char = serial_pxa_put_poll_char,
#endif
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 1f5505e7f90d..c78f43a481ce 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -47,12 +47,31 @@
#include <asm/irq.h>
-#ifdef CONFIG_SAMSUNG_CLOCK
-#include <plat/clock.h>
-#endif
-
#include "samsung.h"
+#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
+ defined(CONFIG_DEBUG_LL) && \
+ !defined(MODULE)
+
+extern void printascii(const char *);
+
+__printf(1, 2)
+static void dbg(const char *fmt, ...)
+{
+ va_list va;
+ char buff[256];
+
+ va_start(va, fmt);
+ vscnprintf(buff, sizeof(buff), fmt, va);
+ va_end(va);
+
+ printascii(buff);
+}
+
+#else
+#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
+#endif
+
/* UART name and device definitions */
#define S3C24XX_SERIAL_NAME "ttySAC"
@@ -180,10 +199,6 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
}
}
-static void s3c24xx_serial_enable_ms(struct uart_port *port)
-{
-}
-
static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
{
return to_ourport(port)->info;
@@ -468,8 +483,8 @@ static int s3c24xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
- dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
- port->mapbase, port->membase);
+ dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
+ port, (unsigned long long)port->mapbase, port->membase);
rx_enabled(port) = 1;
@@ -514,8 +529,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
- dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
- port->mapbase, port->membase);
+ dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
+ port, (unsigned long long)port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
@@ -929,7 +944,6 @@ static struct uart_ops s3c24xx_serial_ops = {
.stop_tx = s3c24xx_serial_stop_tx,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
- .enable_ms = s3c24xx_serial_enable_ms,
.break_ctl = s3c24xx_serial_break_ctl,
.startup = s3c24xx_serial_startup,
.shutdown = s3c24xx_serial_shutdown,
@@ -1160,7 +1174,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return -EINVAL;
}
- dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
+ dbg("resource %pR)\n", res);
port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
if (!port->membase) {
@@ -1203,8 +1217,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
wr_regl(port, S3C64XX_UINTSP, 0xf);
}
- dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
- port->mapbase, port->membase, port->irq,
+ dbg("port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
+ &port->mapbase, port->membase, port->irq,
ourport->rx_irq, ourport->tx_irq, port->uartclk);
/* reset the fifos (and setup the uart) */
@@ -1251,12 +1265,20 @@ static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
static int s3c24xx_serial_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct s3c24xx_uart_port *ourport;
+ int index = probe_index;
int ret;
- dbg("s3c24xx_serial_probe(%p) %d\n", pdev, probe_index);
+ if (np) {
+ ret = of_alias_get_id(np, "serial");
+ if (ret >= 0)
+ index = ret;
+ }
+
+ dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index);
- ourport = &s3c24xx_serial_ports[probe_index];
+ ourport = &s3c24xx_serial_ports[index];
ourport->drv_data = s3c24xx_get_driver_data(pdev);
if (!ourport->drv_data) {
@@ -1270,9 +1292,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
dev_get_platdata(&pdev->dev) :
ourport->drv_data->def_cfg;
- ourport->port.fifosize = (ourport->info->fifosize) ?
- ourport->info->fifosize :
- ourport->drv_data->fifosize[probe_index];
+ if (np)
+ of_property_read_u32(np,
+ "samsung,uart-fifosize", &ourport->port.fifosize);
+
+ if (!ourport->port.fifosize) {
+ ourport->port.fifosize = (ourport->info->fifosize) ?
+ ourport->info->fifosize :
+ ourport->drv_data->fifosize[index];
+ }
probe_index++;
@@ -1280,7 +1308,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
ret = s3c24xx_serial_init_port(ourport, pdev);
if (ret < 0)
- goto probe_err;
+ return ret;
if (!s3c24xx_uart_drv.state) {
ret = uart_register_driver(&s3c24xx_uart_drv);
@@ -1312,9 +1340,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
return 0;
-
- probe_err:
- return ret;
}
static int s3c24xx_serial_remove(struct platform_device *dev)
@@ -1514,8 +1539,8 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
case S3C2410_LCON_CS7:
*bits = 7;
break;
- default:
case S3C2410_LCON_CS8:
+ default:
*bits = 8;
break;
}
@@ -1689,9 +1714,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL
#endif
-#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) || \
- defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) || \
- defined(CONFIG_CPU_S5PC100)
+#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
.info = &(struct s3c24xx_uart_info) {
.name = "Samsung S3C6400 UART",
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 8827e5424cef..eb071dd19b2d 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -1,3 +1,6 @@
+#ifndef __SAMSUNG_H
+#define __SAMSUNG_H
+
/*
* Driver for Samsung SoC onboard UARTs.
*
@@ -77,24 +80,4 @@ struct s3c24xx_uart_port {
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
-#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
- defined(CONFIG_DEBUG_LL) && \
- !defined(MODULE)
-
-extern void printascii(const char *);
-
-static void dbg(const char *fmt, ...)
-{
- va_list va;
- char buff[256];
-
- va_start(va, fmt);
- vsprintf(buff, fmt, va);
- va_end(va);
-
- printascii(buff);
-}
-
-#else
-#define dbg(x...) do { } while (0)
#endif
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index a7cdec2962dd..771f361c47ea 100644
--- a/drivers/tty/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
@@ -596,7 +596,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
if (termios->c_iflag & INPCK)
uport->read_status_mask |= M_DUART_FRM_ERR |
M_DUART_PARITY_ERR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
uport->read_status_mask |= M_DUART_RCVD_BRK;
uport->ignore_status_mask = 0;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
new file mode 100644
index 000000000000..3284c31085a7
--- /dev/null
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -0,0 +1,1275 @@
+/*
+ * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint
+ * Author: Jon Ringle <jringle@gridpoint.com>
+ *
+ * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+
+#define SC16IS7XX_NAME "sc16is7xx"
+
+/* SC16IS7XX register definitions */
+#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
+#define SC16IS7XX_THR_REG (0x00) /* TX FIFO */
+#define SC16IS7XX_IER_REG (0x01) /* Interrupt enable */
+#define SC16IS7XX_IIR_REG (0x02) /* Interrupt Identification */
+#define SC16IS7XX_FCR_REG (0x02) /* FIFO control */
+#define SC16IS7XX_LCR_REG (0x03) /* Line Control */
+#define SC16IS7XX_MCR_REG (0x04) /* Modem Control */
+#define SC16IS7XX_LSR_REG (0x05) /* Line Status */
+#define SC16IS7XX_MSR_REG (0x06) /* Modem Status */
+#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */
+#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */
+#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */
+#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */
+
+/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */
+#define SC16IS7XX_TCR_REG (0x06) /* Transmit control */
+#define SC16IS7XX_TLR_REG (0x07) /* Trigger level */
+
+/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */
+#define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */
+#define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */
+
+/* Enhanced Register set: Only if (LCR == 0xBF) */
+#define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */
+#define SC16IS7XX_XON1_REG (0x04) /* Xon1 word */
+#define SC16IS7XX_XON2_REG (0x05) /* Xon2 word */
+#define SC16IS7XX_XOFF1_REG (0x06) /* Xoff1 word */
+#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */
+
+/* IER register bits */
+#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */
+#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register
+ * interrupt */
+#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status
+ * interrupt */
+#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status
+ * interrupt */
+
+/* IER register bits - write only if (EFR[4] == 1) */
+#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */
+#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */
+#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */
+#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */
+
+/* FCR register bits */
+#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */
+#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */
+#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */
+#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */
+#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */
+
+/* FCR register bits - write only if (EFR[4] == 1) */
+#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */
+#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */
+
+/* IIR register bits */
+#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */
+#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */
+#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */
+#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */
+#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */
+#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */
+#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
+#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
+ * from active (LOW)
+ * to inactive (HIGH)
+ */
+/* LCR register bits */
+#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
+#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
+ *
+ * Word length bits table:
+ * 00 -> 5 bit words
+ * 01 -> 6 bit words
+ * 10 -> 7 bit words
+ * 11 -> 8 bit words
+ */
+#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
+ *
+ * STOP length bit table:
+ * 0 -> 1 stop bit
+ * 1 -> 1-1.5 stop bits if
+ * word length is 5,
+ * 2 stop bits otherwise
+ */
+#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
+#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
+#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
+#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
+#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */
+#define SC16IS7XX_LCR_WORD_LEN_5 (0x00)
+#define SC16IS7XX_LCR_WORD_LEN_6 (0x01)
+#define SC16IS7XX_LCR_WORD_LEN_7 (0x02)
+#define SC16IS7XX_LCR_WORD_LEN_8 (0x03)
+#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special
+ * reg set */
+#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced
+ * reg set */
+
+/* MCR register bits */
+#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */
+#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */
+#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */
+#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any
+ * - write enabled
+ * if (EFR[4] == 1)
+ */
+#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode
+ * - write enabled
+ * if (EFR[4] == 1)
+ */
+#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4
+ * - write enabled
+ * if (EFR[4] == 1)
+ */
+
+/* LSR register bits */
+#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */
+#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */
+#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */
+#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */
+#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */
+#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */
+#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */
+#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */
+#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */
+
+/* MSR register bits */
+#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */
+#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready
+ * or (IO4)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator
+ * or (IO7)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect
+ * or (IO6)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */
+#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6)
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
+
+/*
+ * TCR register bits
+ * TCR trigger levels are available from 0 to 60 characters with a granularity
+ * of four.
+ * The programmer must program the TCR such that TCR[3:0] > TCR[7:4]. There is
+ * no built-in hardware check to make sure this condition is met. Also, the TCR
+ * must be programmed with this condition before auto RTS or software flow
+ * control is enabled to avoid spurious operation of the device.
+ */
+#define SC16IS7XX_TCR_RX_HALT(words) ((((words) / 4) & 0x0f) << 0)
+#define SC16IS7XX_TCR_RX_RESUME(words) ((((words) / 4) & 0x0f) << 4)
+
+/*
+ * TLR register bits
+ * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the
+ * FIFO Control Register (FCR) are used for the transmit and receive FIFO
+ * trigger levels. Trigger levels from 4 characters to 60 characters are
+ * available with a granularity of four.
+ *
+ * When the trigger level setting in TLR is zero, the SC16IS740/750/760 uses the
+ * trigger level setting defined in FCR. If TLR has non-zero trigger level value
+ * the trigger level defined in FCR is discarded. This applies to both transmit
+ * FIFO and receive FIFO trigger level setting.
+ *
+ * When TLR is used for RX trigger level control, FCR[7:6] should be left at the
+ * default state, that is, '00'.
+ */
+#define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0)
+#define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4)
+
+/* IOControl register bits (Only 750/760) */
+#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
+#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */
+#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
+
+/* EFCR register bits */
+#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop
+ * mode (RS485) */
+#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */
+#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */
+#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */
+#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */
+#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode
+ * 0 = rate upto 115.2 kbit/s
+ * - Only 750/760
+ * 1 = rate upto 1.152 Mbit/s
+ * - Only 760
+ */
+
+/* EFR register bits */
+#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */
+#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */
+#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */
+#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions
+ * and writing to IER[7:4],
+ * FCR[5:4], MCR[7:5]
+ */
+#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */
+#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2
+ *
+ * SWFLOW bits 3 & 2 table:
+ * 00 -> no transmitter flow
+ * control
+ * 01 -> transmitter generates
+ * XON2 and XOFF2
+ * 10 -> transmitter generates
+ * XON1 and XOFF1
+ * 11 -> transmitter generates
+ * XON1, XON2, XOFF1 and
+ * XOFF2
+ */
+#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */
+#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3
+ *
+ * SWFLOW bits 3 & 2 table:
+ * 00 -> no received flow
+ * control
+ * 01 -> receiver compares
+ * XON2 and XOFF2
+ * 10 -> receiver compares
+ * XON1 and XOFF1
+ * 11 -> receiver compares
+ * XON1, XON2, XOFF1 and
+ * XOFF2
+ */
+
+/* Misc definitions */
+#define SC16IS7XX_FIFO_SIZE (64)
+#define SC16IS7XX_REG_SHIFT 2
+
+struct sc16is7xx_devtype {
+ char name[10];
+ int nr_gpio;
+ int nr_uart;
+};
+
+struct sc16is7xx_one {
+ struct uart_port port;
+ struct work_struct tx_work;
+ struct work_struct md_work;
+
+ struct serial_rs485 rs485;
+};
+
+struct sc16is7xx_port {
+ struct uart_driver uart;
+ struct sc16is7xx_devtype *devtype;
+ struct regmap *regmap;
+ struct mutex mutex;
+ struct clk *clk;
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio;
+#endif
+ unsigned char buf[SC16IS7XX_FIFO_SIZE];
+ struct sc16is7xx_one p[0];
+};
+
+#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
+
+static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ unsigned int val = 0;
+
+ regmap_read(s->regmap,
+ (reg << SC16IS7XX_REG_SHIFT) | port->line, &val);
+
+ return val;
+}
+
+static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+
+ regmap_write(s->regmap,
+ (reg << SC16IS7XX_REG_SHIFT) | port->line, val);
+}
+
+static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
+ u8 mask, u8 val)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+
+ regmap_update_bits(s->regmap,
+ (reg << SC16IS7XX_REG_SHIFT) | port->line,
+ mask, val);
+}
+
+
+static void sc16is7xx_power(struct uart_port *port, int on)
+{
+ sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
+ SC16IS7XX_IER_SLEEP_BIT,
+ on ? 0 : SC16IS7XX_IER_SLEEP_BIT);
+}
+
+static const struct sc16is7xx_devtype sc16is74x_devtype = {
+ .name = "SC16IS74X",
+ .nr_gpio = 0,
+ .nr_uart = 1,
+};
+
+static const struct sc16is7xx_devtype sc16is750_devtype = {
+ .name = "SC16IS750",
+ .nr_gpio = 8,
+ .nr_uart = 1,
+};
+
+static const struct sc16is7xx_devtype sc16is752_devtype = {
+ .name = "SC16IS752",
+ .nr_gpio = 8,
+ .nr_uart = 2,
+};
+
+static const struct sc16is7xx_devtype sc16is760_devtype = {
+ .name = "SC16IS760",
+ .nr_gpio = 8,
+ .nr_uart = 1,
+};
+
+static const struct sc16is7xx_devtype sc16is762_devtype = {
+ .name = "SC16IS762",
+ .nr_gpio = 8,
+ .nr_uart = 2,
+};
+
+static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg >> SC16IS7XX_REG_SHIFT) {
+ case SC16IS7XX_RHR_REG:
+ case SC16IS7XX_IIR_REG:
+ case SC16IS7XX_LSR_REG:
+ case SC16IS7XX_MSR_REG:
+ case SC16IS7XX_TXLVL_REG:
+ case SC16IS7XX_RXLVL_REG:
+ case SC16IS7XX_IOSTATE_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg)
+{
+ switch (reg >> SC16IS7XX_REG_SHIFT) {
+ case SC16IS7XX_RHR_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int sc16is7xx_set_baud(struct uart_port *port, int baud)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ u8 lcr;
+ u8 prescaler = 0;
+ unsigned long clk = port->uartclk, div = clk / 16 / baud;
+
+ if (div > 0xffff) {
+ prescaler = SC16IS7XX_MCR_CLKSEL_BIT;
+ div /= 4;
+ }
+
+ lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
+
+ /* Open the LCR divisors for configuration */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+ SC16IS7XX_LCR_CONF_MODE_B);
+
+ /* Enable enhanced features */
+ regcache_cache_bypass(s->regmap, true);
+ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
+ SC16IS7XX_EFR_ENABLE_BIT);
+ regcache_cache_bypass(s->regmap, false);
+
+ /* Put LCR back to the normal mode */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+
+ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_CLKSEL_BIT,
+ prescaler);
+
+ /* Open the LCR divisors for configuration */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+ SC16IS7XX_LCR_CONF_MODE_A);
+
+ /* Write the new divisor */
+ regcache_cache_bypass(s->regmap, true);
+ sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256);
+ sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256);
+ regcache_cache_bypass(s->regmap, false);
+
+ /* Put LCR back to the normal mode */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+
+ return DIV_ROUND_CLOSEST(clk / 16, div);
+}
+
+static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
+ unsigned int iir)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ unsigned int lsr = 0, ch, flag, bytes_read, i;
+ bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
+
+ if (unlikely(rxlen >= sizeof(s->buf))) {
+ dev_warn_ratelimited(port->dev,
+ "Port %i: Possible RX FIFO overrun: %d\n",
+ port->line, rxlen);
+ port->icount.buf_overrun++;
+ /* Ensure sanity of RX level */
+ rxlen = sizeof(s->buf);
+ }
+
+ while (rxlen) {
+ /* Only read lsr if there are possible errors in FIFO */
+ if (read_lsr) {
+ lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
+ if (!(lsr & SC16IS7XX_LSR_FIFOE_BIT))
+ read_lsr = false; /* No errors left in FIFO */
+ } else
+ lsr = 0;
+
+ if (read_lsr) {
+ s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
+ bytes_read = 1;
+ } else {
+ regcache_cache_bypass(s->regmap, true);
+ regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG,
+ s->buf, rxlen);
+ regcache_cache_bypass(s->regmap, false);
+ bytes_read = rxlen;
+ }
+
+ lsr &= SC16IS7XX_LSR_BRK_ERROR_MASK;
+
+ port->icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (unlikely(lsr)) {
+ if (lsr & SC16IS7XX_LSR_BI_BIT) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (lsr & SC16IS7XX_LSR_PE_BIT)
+ port->icount.parity++;
+ else if (lsr & SC16IS7XX_LSR_FE_BIT)
+ port->icount.frame++;
+ else if (lsr & SC16IS7XX_LSR_OE_BIT)
+ port->icount.overrun++;
+
+ lsr &= port->read_status_mask;
+ if (lsr & SC16IS7XX_LSR_BI_BIT)
+ flag = TTY_BREAK;
+ else if (lsr & SC16IS7XX_LSR_PE_BIT)
+ flag = TTY_PARITY;
+ else if (lsr & SC16IS7XX_LSR_FE_BIT)
+ flag = TTY_FRAME;
+ else if (lsr & SC16IS7XX_LSR_OE_BIT)
+ flag = TTY_OVERRUN;
+ }
+
+ for (i = 0; i < bytes_read; ++i) {
+ ch = s->buf[i];
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ if (lsr & port->ignore_status_mask)
+ continue;
+
+ uart_insert_char(port, lsr, SC16IS7XX_LSR_OE_BIT, ch,
+ flag);
+ }
+ rxlen -= bytes_read;
+ }
+
+ tty_flip_buffer_push(&port->state->port);
+}
+
+static void sc16is7xx_handle_tx(struct uart_port *port)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int txlen, to_send, i;
+
+ if (unlikely(port->x_char)) {
+ sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ return;
+
+ /* Get length of data pending in circular buffer */
+ to_send = uart_circ_chars_pending(xmit);
+ if (likely(to_send)) {
+ /* Limit to size of TX FIFO */
+ txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
+ to_send = (to_send > txlen) ? txlen : to_send;
+
+ /* Add data to send */
+ port->icount.tx += to_send;
+
+ /* Convert to linear buffer */
+ for (i = 0; i < to_send; ++i) {
+ s->buf[i] = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ }
+ regcache_cache_bypass(s->regmap, true);
+ regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send);
+ regcache_cache_bypass(s->regmap, false);
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
+{
+ struct uart_port *port = &s->p[portno].port;
+
+ do {
+ unsigned int iir, msr, rxlen;
+
+ iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
+ if (iir & SC16IS7XX_IIR_NO_INT_BIT)
+ break;
+
+ iir &= SC16IS7XX_IIR_ID_MASK;
+
+ switch (iir) {
+ case SC16IS7XX_IIR_RDI_SRC:
+ case SC16IS7XX_IIR_RLSE_SRC:
+ case SC16IS7XX_IIR_RTOI_SRC:
+ case SC16IS7XX_IIR_XOFFI_SRC:
+ rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
+ if (rxlen)
+ sc16is7xx_handle_rx(port, rxlen, iir);
+ break;
+
+ case SC16IS7XX_IIR_CTSRTS_SRC:
+ msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
+ uart_handle_cts_change(port,
+ !!(msr & SC16IS7XX_MSR_CTS_BIT));
+ break;
+ case SC16IS7XX_IIR_THRI_SRC:
+ mutex_lock(&s->mutex);
+ sc16is7xx_handle_tx(port);
+ mutex_unlock(&s->mutex);
+ break;
+ default:
+ dev_err_ratelimited(port->dev,
+ "Port %i: Unexpected interrupt: %x",
+ port->line, iir);
+ break;
+ }
+ } while (1);
+}
+
+static irqreturn_t sc16is7xx_ist(int irq, void *dev_id)
+{
+ struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+ int i;
+
+ for (i = 0; i < s->uart.nr; ++i)
+ sc16is7xx_port_irq(s, i);
+
+ return IRQ_HANDLED;
+}
+
+static void sc16is7xx_wq_proc(struct work_struct *ws)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work);
+ struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
+
+ mutex_lock(&s->mutex);
+ sc16is7xx_handle_tx(&one->port);
+ mutex_unlock(&s->mutex);
+}
+
+static void sc16is7xx_stop_tx(struct uart_port* port)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct circ_buf *xmit = &one->port.state->xmit;
+
+ /* handle rs485 */
+ if (one->rs485.flags & SER_RS485_ENABLED) {
+ /* do nothing if current tx not yet completed */
+ int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
+ if (!(lsr & SC16IS7XX_LSR_TEMT_BIT))
+ return;
+
+ if (uart_circ_empty(xmit) &&
+ (one->rs485.delay_rts_after_send > 0))
+ mdelay(one->rs485.delay_rts_after_send);
+ }
+
+ sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
+ SC16IS7XX_IER_THRI_BIT,
+ 0);
+}
+
+static void sc16is7xx_stop_rx(struct uart_port* port)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT;
+ sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
+ SC16IS7XX_LSR_DR_BIT,
+ 0);
+}
+
+static void sc16is7xx_start_tx(struct uart_port *port)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ /* handle rs485 */
+ if ((one->rs485.flags & SER_RS485_ENABLED) &&
+ (one->rs485.delay_rts_before_send > 0)) {
+ mdelay(one->rs485.delay_rts_before_send);
+ }
+
+ if (!work_pending(&one->tx_work))
+ schedule_work(&one->tx_work);
+}
+
+static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
+{
+ unsigned int lvl, lsr;
+
+ lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
+ lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
+
+ return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
+{
+ /* DCD and DSR are not wired and CTS/RTS is handled automatically
+ * so just indicate DSR and CAR asserted
+ */
+ return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sc16is7xx_md_proc(struct work_struct *ws)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work);
+
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_LOOP_BIT,
+ (one->port.mctrl & TIOCM_LOOP) ?
+ SC16IS7XX_MCR_LOOP_BIT : 0);
+}
+
+static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ schedule_work(&one->md_work);
+}
+
+static void sc16is7xx_break_ctl(struct uart_port *port, int break_state)
+{
+ sc16is7xx_port_update(port, SC16IS7XX_LCR_REG,
+ SC16IS7XX_LCR_TXBREAK_BIT,
+ break_state ? SC16IS7XX_LCR_TXBREAK_BIT : 0);
+}
+
+static void sc16is7xx_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ unsigned int lcr, flow = 0;
+ int baud;
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+
+ /* Word size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr = SC16IS7XX_LCR_WORD_LEN_5;
+ break;
+ case CS6:
+ lcr = SC16IS7XX_LCR_WORD_LEN_6;
+ break;
+ case CS7:
+ lcr = SC16IS7XX_LCR_WORD_LEN_7;
+ break;
+ case CS8:
+ lcr = SC16IS7XX_LCR_WORD_LEN_8;
+ break;
+ default:
+ lcr = SC16IS7XX_LCR_WORD_LEN_8;
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
+ break;
+ }
+
+ /* Parity */
+ if (termios->c_cflag & PARENB) {
+ lcr |= SC16IS7XX_LCR_PARITY_BIT;
+ if (!(termios->c_cflag & PARODD))
+ lcr |= SC16IS7XX_LCR_EVENPARITY_BIT;
+ }
+
+ /* Stop bits */
+ if (termios->c_cflag & CSTOPB)
+ lcr |= SC16IS7XX_LCR_STOPLEN_BIT; /* 2 stops */
+
+ /* Set read status mask */
+ port->read_status_mask = SC16IS7XX_LSR_OE_BIT;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= SC16IS7XX_LSR_PE_BIT |
+ SC16IS7XX_LSR_FE_BIT;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SC16IS7XX_LSR_BI_BIT;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK)
+ port->ignore_status_mask |= SC16IS7XX_LSR_BI_BIT;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
+
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+ SC16IS7XX_LCR_CONF_MODE_B);
+
+ /* Configure flow control */
+ regcache_cache_bypass(s->regmap, true);
+ sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
+ sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
+ if (termios->c_cflag & CRTSCTS)
+ flow |= SC16IS7XX_EFR_AUTOCTS_BIT |
+ SC16IS7XX_EFR_AUTORTS_BIT;
+ if (termios->c_iflag & IXON)
+ flow |= SC16IS7XX_EFR_SWFLOW3_BIT;
+ if (termios->c_iflag & IXOFF)
+ flow |= SC16IS7XX_EFR_SWFLOW1_BIT;
+
+ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow);
+ regcache_cache_bypass(s->regmap, false);
+
+ /* Update LCR register */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+
+ /* Get baud rate generator configuration */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 4 / 0xffff,
+ port->uartclk / 16);
+
+ /* Setup baudrate generator */
+ baud = sc16is7xx_set_baud(port, baud);
+
+ /* Update timeout according to new baud rate */
+ uart_update_timeout(port, termios->c_cflag, baud);
+}
+
+#if defined(TIOCSRS485) && defined(TIOCGRS485)
+static void sc16is7xx_config_rs485(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ one->rs485 = *rs485;
+
+ if (one->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);
+ }
+}
+#endif
+
+static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd,
+ unsigned long arg)
+{
+#if defined(TIOCSRS485) && defined(TIOCGRS485)
+ struct serial_rs485 rs485;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485)))
+ return -EFAULT;
+
+ sc16is7xx_config_rs485(port, &rs485);
+ return 0;
+ case TIOCGRS485:
+ if (copy_to_user((void __user *)arg,
+ &(to_sc16is7xx_one(port, port)->rs485),
+ sizeof(rs485)))
+ return -EFAULT;
+ return 0;
+ default:
+ break;
+ }
+#endif
+
+ return -ENOIOCTLCMD;
+}
+
+static int sc16is7xx_startup(struct uart_port *port)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ unsigned int val;
+
+ sc16is7xx_power(port, 1);
+
+ /* Reset FIFOs*/
+ val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT;
+ sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val);
+ udelay(5);
+ sc16is7xx_port_write(port, SC16IS7XX_FCR_REG,
+ SC16IS7XX_FCR_FIFO_BIT);
+
+ /* Enable EFR */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+ SC16IS7XX_LCR_CONF_MODE_B);
+
+ regcache_cache_bypass(s->regmap, true);
+
+ /* Enable write access to enhanced features and internal clock div */
+ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
+ SC16IS7XX_EFR_ENABLE_BIT);
+
+ /* Enable TCR/TLR */
+ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_TCRTLR_BIT,
+ SC16IS7XX_MCR_TCRTLR_BIT);
+
+ /* Configure flow control levels */
+ /* Flow control halt level 48, resume level 24 */
+ sc16is7xx_port_write(port, SC16IS7XX_TCR_REG,
+ SC16IS7XX_TCR_RX_RESUME(24) |
+ SC16IS7XX_TCR_RX_HALT(48));
+
+ regcache_cache_bypass(s->regmap, false);
+
+ /* Now, initialize the UART */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8);
+
+ /* Enable the Rx and Tx FIFO */
+ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT,
+ 0);
+
+ /* Enable RX, TX, CTS change interrupts */
+ val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT |
+ SC16IS7XX_IER_CTSI_BIT;
+ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
+
+ return 0;
+}
+
+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_power(port, 0);
+}
+
+static const char *sc16is7xx_type(struct uart_port *port)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+
+ return (port->type == PORT_SC16IS7XX) ? s->devtype->name : NULL;
+}
+
+static int sc16is7xx_request_port(struct uart_port *port)
+{
+ /* Do nothing */
+ return 0;
+}
+
+static void sc16is7xx_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_SC16IS7XX;
+}
+
+static int sc16is7xx_verify_port(struct uart_port *port,
+ struct serial_struct *s)
+{
+ if ((s->type != PORT_UNKNOWN) && (s->type != PORT_SC16IS7XX))
+ return -EINVAL;
+ if (s->irq != port->irq)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void sc16is7xx_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ sc16is7xx_power(port, (state == UART_PM_STATE_ON) ? 1 : 0);
+}
+
+static void sc16is7xx_null_void(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static const struct uart_ops sc16is7xx_ops = {
+ .tx_empty = sc16is7xx_tx_empty,
+ .set_mctrl = sc16is7xx_set_mctrl,
+ .get_mctrl = sc16is7xx_get_mctrl,
+ .stop_tx = sc16is7xx_stop_tx,
+ .start_tx = sc16is7xx_start_tx,
+ .stop_rx = sc16is7xx_stop_rx,
+ .break_ctl = sc16is7xx_break_ctl,
+ .startup = sc16is7xx_startup,
+ .shutdown = sc16is7xx_shutdown,
+ .set_termios = sc16is7xx_set_termios,
+ .type = sc16is7xx_type,
+ .request_port = sc16is7xx_request_port,
+ .release_port = sc16is7xx_null_void,
+ .config_port = sc16is7xx_config_port,
+ .verify_port = sc16is7xx_verify_port,
+ .ioctl = sc16is7xx_ioctl,
+ .pm = sc16is7xx_pm,
+};
+
+#ifdef CONFIG_GPIOLIB
+static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned int val;
+ struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
+ gpio);
+ struct uart_port *port = &s->p[0].port;
+
+ val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG);
+
+ return !!(val & BIT(offset));
+}
+
+static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
+ gpio);
+ struct uart_port *port = &s->p[0].port;
+
+ sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
+ val ? BIT(offset) : 0);
+}
+
+static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
+ gpio);
+ struct uart_port *port = &s->p[0].port;
+
+ sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0);
+
+ return 0;
+}
+
+static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int val)
+{
+ struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
+ gpio);
+ struct uart_port *port = &s->p[0].port;
+
+ sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
+ val ? BIT(offset) : 0);
+ sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset),
+ BIT(offset));
+
+ return 0;
+}
+#endif
+
+static int sc16is7xx_probe(struct device *dev,
+ struct sc16is7xx_devtype *devtype,
+ struct regmap *regmap, int irq, unsigned long flags)
+{
+ unsigned long freq, *pfreq = dev_get_platdata(dev);
+ int i, ret;
+ struct sc16is7xx_port *s;
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Alloc port structure */
+ s = devm_kzalloc(dev, sizeof(*s) +
+ sizeof(struct sc16is7xx_one) * devtype->nr_uart,
+ GFP_KERNEL);
+ if (!s) {
+ dev_err(dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+
+ s->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(s->clk)) {
+ if (pfreq)
+ freq = *pfreq;
+ else
+ return PTR_ERR(s->clk);
+ } else {
+ freq = clk_get_rate(s->clk);
+ }
+
+ s->regmap = regmap;
+ s->devtype = devtype;
+ dev_set_drvdata(dev, s);
+
+ /* Register UART driver */
+ s->uart.owner = THIS_MODULE;
+ s->uart.dev_name = "ttySC";
+ s->uart.nr = devtype->nr_uart;
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(dev, "Registering UART driver failed\n");
+ goto out_clk;
+ }
+
+#ifdef CONFIG_GPIOLIB
+ if (devtype->nr_gpio) {
+ /* Setup GPIO cotroller */
+ s->gpio.owner = THIS_MODULE;
+ s->gpio.dev = dev;
+ s->gpio.label = dev_name(dev);
+ s->gpio.direction_input = sc16is7xx_gpio_direction_input;
+ s->gpio.get = sc16is7xx_gpio_get;
+ s->gpio.direction_output = sc16is7xx_gpio_direction_output;
+ s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.base = -1;
+ s->gpio.ngpio = devtype->nr_gpio;
+ s->gpio.can_sleep = 1;
+ ret = gpiochip_add(&s->gpio);
+ if (ret)
+ goto out_uart;
+ }
+#endif
+
+ mutex_init(&s->mutex);
+
+ for (i = 0; i < devtype->nr_uart; ++i) {
+ /* Initialize port data */
+ s->p[i].port.line = i;
+ s->p[i].port.dev = dev;
+ s->p[i].port.irq = irq;
+ s->p[i].port.type = PORT_SC16IS7XX;
+ s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE;
+ s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+ s->p[i].port.iotype = UPIO_PORT;
+ s->p[i].port.uartclk = freq;
+ s->p[i].port.ops = &sc16is7xx_ops;
+ /* Disable all interrupts */
+ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0);
+ /* Disable TX/RX */
+ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT);
+ /* Initialize queue for start TX */
+ INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc);
+ /* Initialize queue for changing mode */
+ INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc);
+ /* Register port */
+ uart_add_one_port(&s->uart, &s->p[i].port);
+ /* Go to suspend mode */
+ sc16is7xx_power(&s->p[i].port, 0);
+ }
+
+ /* Setup interrupt */
+ ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist,
+ IRQF_ONESHOT | flags, dev_name(dev), s);
+ if (!ret)
+ return 0;
+
+ mutex_destroy(&s->mutex);
+
+#ifdef CONFIG_GPIOLIB
+ if (devtype->nr_gpio)
+ WARN_ON(gpiochip_remove(&s->gpio));
+
+out_uart:
+#endif
+ uart_unregister_driver(&s->uart);
+
+out_clk:
+ if (!IS_ERR(s->clk))
+ clk_disable_unprepare(s->clk);
+
+ return ret;
+}
+
+static int sc16is7xx_remove(struct device *dev)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(dev);
+ int i, ret = 0;
+
+#ifdef CONFIG_GPIOLIB
+ if (s->devtype->nr_gpio) {
+ ret = gpiochip_remove(&s->gpio);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ for (i = 0; i < s->uart.nr; i++) {
+ cancel_work_sync(&s->p[i].tx_work);
+ cancel_work_sync(&s->p[i].md_work);
+ uart_remove_one_port(&s->uart, &s->p[i].port);
+ sc16is7xx_power(&s->p[i].port, 0);
+ }
+
+ mutex_destroy(&s->mutex);
+ uart_unregister_driver(&s->uart);
+ if (!IS_ERR(s->clk))
+ clk_disable_unprepare(s->clk);
+
+ return ret;
+}
+
+static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
+ { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, },
+ { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, },
+ { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, },
+ { .compatible = "nxp,sc16is752", .data = &sc16is752_devtype, },
+ { .compatible = "nxp,sc16is760", .data = &sc16is760_devtype, },
+ { .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids);
+
+static struct regmap_config regcfg = {
+ .reg_bits = 7,
+ .pad_bits = 1,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = sc16is7xx_regmap_volatile,
+ .precious_reg = sc16is7xx_regmap_precious,
+};
+
+static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct sc16is7xx_devtype *devtype;
+ unsigned long flags = 0;
+ struct regmap *regmap;
+
+ if (i2c->dev.of_node) {
+ const struct of_device_id *of_id =
+ of_match_device(sc16is7xx_dt_ids, &i2c->dev);
+
+ devtype = (struct sc16is7xx_devtype *)of_id->data;
+ } else {
+ devtype = (struct sc16is7xx_devtype *)id->driver_data;
+ flags = IRQF_TRIGGER_FALLING;
+ }
+
+ regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
+ (devtype->nr_uart - 1);
+ regmap = devm_regmap_init_i2c(i2c, &regcfg);
+
+ return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags);
+}
+
+static int sc16is7xx_i2c_remove(struct i2c_client *client)
+{
+ return sc16is7xx_remove(&client->dev);
+}
+
+static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
+ { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
+ { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
+ { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
+ { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
+
+static struct i2c_driver sc16is7xx_i2c_uart_driver = {
+ .driver = {
+ .name = SC16IS7XX_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sc16is7xx_dt_ids),
+ },
+ .probe = sc16is7xx_i2c_probe,
+ .remove = sc16is7xx_i2c_remove,
+ .id_table = sc16is7xx_i2c_id_table,
+};
+module_i2c_driver(sc16is7xx_i2c_uart_driver);
+MODULE_ALIAS("i2c:sc16is7xx");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
+MODULE_DESCRIPTION("SC16IS7XX serial driver");
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index a447f71538ef..75850f70b479 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data)
sccnxp_handle_events(s);
spin_unlock_irqrestore(&s->lock, flags);
- if (!timer_pending(&s->timer))
- mod_timer(&s->timer, jiffies +
- usecs_to_jiffies(s->pdata.poll_time_us));
+ mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us));
}
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
@@ -535,11 +533,6 @@ static unsigned int sccnxp_tx_empty(struct uart_port *port)
return (val & SR_TXEMT) ? TIOCSER_TEMT : 0;
}
-static void sccnxp_enable_ms(struct uart_port *port)
-{
- /* Do nothing */
-}
-
static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sccnxp_port *s = dev_get_drvdata(port->dev);
@@ -667,13 +660,15 @@ static void sccnxp_set_termios(struct uart_port *port,
port->read_status_mask = SR_OVR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= SR_PE | SR_FE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= SR_BRK;
/* Set status ignore mask */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNBRK)
port->ignore_status_mask |= SR_BRK;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= SR_PE;
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;
@@ -790,7 +785,6 @@ static const struct uart_ops sccnxp_ops = {
.stop_tx = sccnxp_stop_tx,
.start_tx = sccnxp_start_tx,
.stop_rx = sccnxp_stop_rx,
- .enable_ms = sccnxp_enable_ms,
.break_ctl = sccnxp_break_ctl,
.startup = sccnxp_startup,
.shutdown = sccnxp_shutdown,
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index d5c2a287b7e7..53d7c31ce098 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -482,6 +482,9 @@ static void tegra_uart_stop_tx(struct uart_port *u)
struct dma_tx_state state;
int count;
+ if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
+ return;
+
dmaengine_terminate_all(tup->tx_dma_chan);
dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
count = tup->tx_bytes_requested - state.residue;
@@ -599,6 +602,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
dmaengine_terminate_all(tup->rx_dma_chan);
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+ async_tx_ack(tup->rx_dma_desc);
count = tup->rx_bytes_requested - state.residue;
/* If we are here, DMA is stopped */
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index b68550d95a40..8bb19da01639 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -174,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
-
- if (tty_port_cts_enabled(port)) {
+ /*
+ * if hw support flow control without software intervention,
+ * then skip the below check
+ */
+ if (tty_port_cts_enabled(port) &&
+ !(uport->flags & UPF_HARD_FLOW)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -239,6 +243,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
+ if (uart_console(uport) && tty)
+ uport->cons->cflag = tty->termios.c_cflag;
+
if (!tty || (tty->termios.c_cflag & HUPCL))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
@@ -443,6 +450,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
return;
termios = &tty->termios;
+ uport->ops->set_termios(uport, termios, old_termios);
/*
* Set flags based on termios cflag
@@ -456,8 +464,6 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
clear_bit(ASYNCB_CHECK_CD, &port->flags);
else
set_bit(ASYNCB_CHECK_CD, &port->flags);
-
- uport->ops->set_termios(uport, termios, old_termios);
}
static inline int __uart_put_char(struct uart_port *port,
@@ -1046,6 +1052,15 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
return ret;
}
+static void uart_enable_ms(struct uart_port *uport)
+{
+ /*
+ * Force modem status interrupts on
+ */
+ if (uport->ops->enable_ms)
+ uport->ops->enable_ms(uport);
+}
+
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1069,11 +1084,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
*/
spin_lock_irq(&uport->lock);
memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
-
- /*
- * Force modem status interrupts on
- */
- uport->ops->enable_ms(uport);
+ uart_enable_ms(uport);
spin_unlock_irq(&uport->lock);
add_wait_queue(&port->delta_msr_wait, &wait);
@@ -1270,6 +1281,8 @@ static void uart_set_termios(struct tty_struct *tty,
}
uart_change_speed(tty, state, old_termios);
+ /* reload cflag from termios; port driver may have overriden flags */
+ cflag = tty->termios.c_cflag;
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
@@ -1356,8 +1369,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
tty_ldisc_flush(tty);
tty_port_tty_set(port, NULL);
- spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
+ spin_lock_irqsave(&port->lock, flags);
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
@@ -1504,7 +1517,7 @@ static int uart_carrier_raised(struct tty_port *port)
struct uart_port *uport = state->uart_port;
int mctrl;
spin_lock_irq(&uport->lock);
- uport->ops->enable_ms(uport);
+ uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
if (mctrl & TIOCM_CAR)
@@ -1572,14 +1585,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
tty_port_tty_set(port, tty);
/*
- * If the port is in the middle of closing, bail out now.
- */
- if (tty_hung_up_p(filp)) {
- retval = -EAGAIN;
- goto err_dec_count;
- }
-
- /*
* Start up the serial port.
*/
retval = uart_startup(tty, state, 0);
@@ -2239,6 +2244,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
return;
port = state->uart_port;
+
+ if (ch == '\n')
+ port->ops->poll_put_char(port, '\r');
port->ops->poll_put_char(port, ch);
}
#endif
@@ -2556,12 +2564,6 @@ static const struct attribute_group tty_dev_attr_group = {
.attrs = tty_dev_attrs,
};
-static const struct attribute_group *tty_dev_attr_groups[] = {
- &tty_dev_attr_group,
- NULL
- };
-
-
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
@@ -2578,6 +2580,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
struct tty_port *port;
int ret = 0;
struct device *tty_dev;
+ int num_groups;
BUG_ON(in_interrupt());
@@ -2611,12 +2614,26 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
uart_configure_port(drv, state, uport);
+ num_groups = 2;
+ if (uport->attr_group)
+ num_groups++;
+
+ uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
+ GFP_KERNEL);
+ if (!uport->tty_groups) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ uport->tty_groups[0] = &tty_dev_attr_group;
+ if (uport->attr_group)
+ uport->tty_groups[1] = uport->attr_group;
+
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this port's parameters.
*/
tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
- uport->line, uport->dev, port, tty_dev_attr_groups);
+ uport->line, uport->dev, port, uport->tty_groups);
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
@@ -2695,6 +2712,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
*/
if (uport->type != PORT_UNKNOWN)
uport->ops->release_port(uport);
+ kfree(uport->tty_groups);
/*
* Indicate that there isn't a port here anymore.
@@ -2772,7 +2790,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
- if (tty_port_cts_enabled(port)) {
+ /* skip below code if the hw flow control is supported */
+ if (tty_port_cts_enabled(port) &&
+ !(uport->flags & UPF_HARD_FLOW)) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index e1caa99e3d3b..5c79bdab985d 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -437,7 +437,7 @@ static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *term
port->read_status_mask = URLS_URROE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= (URLS_URFE | URLS_URPE);
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= URLS_URBI;
/*
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
new file mode 100644
index 000000000000..bf9560ffe3f4
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -0,0 +1,143 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <uapi/asm-generic/termios.h>
+
+#include "serial_mctrl_gpio.h"
+
+struct mctrl_gpios {
+ struct gpio_desc *gpio[UART_GPIO_MAX];
+};
+
+static const struct {
+ const char *name;
+ unsigned int mctrl;
+ bool dir_out;
+} mctrl_gpios_desc[UART_GPIO_MAX] = {
+ { "cts", TIOCM_CTS, false, },
+ { "dsr", TIOCM_DSR, false, },
+ { "dcd", TIOCM_CD, false, },
+ { "rng", TIOCM_RNG, false, },
+ { "rts", TIOCM_RTS, true, },
+ { "dtr", TIOCM_DTR, true, },
+ { "out1", TIOCM_OUT1, true, },
+ { "out2", TIOCM_OUT2, true, },
+};
+
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+ 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]) &&
+ mctrl_gpios_desc[i].dir_out)
+ gpiod_set_value(gpios->gpio[i],
+ !!(mctrl & mctrl_gpios_desc[i].mctrl));
+}
+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;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
+
+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 (gpiod_get_value(gpios->gpio[i]))
+ *mctrl |= mctrl_gpios_desc[i].mctrl;
+ else
+ *mctrl &= ~mctrl_gpios_desc[i].mctrl;
+ }
+ }
+
+ return *mctrl;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_get);
+
+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;
+
+ if (mctrl_gpios_desc[i].dir_out)
+ err = gpiod_direction_output(gpios->gpio[i], 0);
+ 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;
+ }
+ }
+
+ return gpios;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
+
+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]);
+ devm_kfree(dev, gpios);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_free);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
new file mode 100644
index 000000000000..400ba0494a17
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -0,0 +1,110 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __SERIAL_MCTRL_GPIO__
+#define __SERIAL_MCTRL_GPIO__
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+
+enum mctrl_gpio_idx {
+ UART_GPIO_CTS,
+ UART_GPIO_DSR,
+ UART_GPIO_DCD,
+ UART_GPIO_RNG,
+ UART_GPIO_RI = UART_GPIO_RNG,
+ UART_GPIO_RTS,
+ UART_GPIO_DTR,
+ UART_GPIO_OUT1,
+ UART_GPIO_OUT2,
+ UART_GPIO_MAX,
+};
+
+/*
+ * Opaque descriptor for modem lines controlled by GPIOs
+ */
+struct mctrl_gpios;
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * Set state of the modem control output lines via GPIOs.
+ */
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
+
+/*
+ * Get state of the modem control output lines from GPIOs.
+ * The mctrl flags are updated and returned.
+ */
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
+
+/*
+ * Returns the associated struct gpio_desc to the modem line gidx
+ */
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+ enum mctrl_gpio_idx gidx);
+
+/*
+ * Request and set direction of modem control lines GPIOs.
+ * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
+ * allocation error.
+ */
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
+
+/*
+ * Free the mctrl_gpios structure.
+ * Normally, this function will not be called, as the GPIOs will
+ * be disposed of by the resource management code.
+ */
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+
+#else /* GPIOLIB */
+
+static inline
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+}
+
+static inline
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+ return *mctrl;
+}
+
+static inline
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+ enum mctrl_gpio_idx gidx)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+{
+}
+
+#endif /* GPIOLIB */
+
+#endif
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index 90a080b1f9ee..af115645c51f 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -142,7 +142,6 @@ struct uart_txx9_port {
#define TXX9_SIFCR_RDIL_12 0x00000180
#define TXX9_SIFCR_RDIL_MAX 0x00000180
#define TXX9_SIFCR_TDIL_MASK 0x00000018
-#define TXX9_SIFCR_TDIL_MASK 0x00000018
#define TXX9_SIFCR_TDIL_1 0x00000000
#define TXX9_SIFCR_TDIL_4 0x00000001
#define TXX9_SIFCR_TDIL_8 0x00000010
@@ -244,11 +243,6 @@ static void serial_txx9_stop_rx(struct uart_port *port)
up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
}
-static void serial_txx9_enable_ms(struct uart_port *port)
-{
- /* TXX9-SIO can not control DTR... */
-}
-
static void serial_txx9_initialize(struct uart_port *port)
{
struct uart_txx9_port *up = to_uart_txx9_port(port);
@@ -535,13 +529,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
wait_for_xmitr(up);
/*
* Send the character out.
- * If a LF, also do CR...
*/
sio_out(up, TXX9_SITFIFO, c);
- if (c == 10) {
- wait_for_xmitr(up);
- sio_out(up, TXX9_SITFIFO, 13);
- }
/*
* Finally, wait for transmitter to become empty
@@ -702,7 +691,7 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= TXX9_SIDISR_UBRK;
/*
@@ -863,7 +852,6 @@ static struct uart_ops serial_txx9_pops = {
.stop_tx = serial_txx9_stop_tx,
.start_tx = serial_txx9_start_tx,
.stop_rx = serial_txx9_stop_rx,
- .enable_ms = serial_txx9_enable_ms,
.break_ctl = serial_txx9_break_ctl,
.startup = serial_txx9_startup,
.shutdown = serial_txx9_shutdown,
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 88236da0ddf7..3081e46085ce 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1560,13 +1560,6 @@ static void sci_stop_rx(struct uart_port *port)
serial_port_out(port, SCSCR, ctrl);
}
-static void sci_enable_ms(struct uart_port *port)
-{
- /*
- * Not supported by hardware, always a nop.
- */
-}
-
static void sci_break_ctl(struct uart_port *port, int break_state)
{
struct sci_port *s = to_sci_port(port);
@@ -1783,30 +1776,71 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
return ((freq + 16 * bps) / (32 * bps) - 1);
}
+/* calculate frame length from SMR */
+static int sci_baud_calc_frame_len(unsigned int smr_val)
+{
+ int len = 10;
+
+ if (smr_val & SCSMR_CHR)
+ len--;
+ if (smr_val & SCSMR_PE)
+ len++;
+ if (smr_val & SCSMR_STOP)
+ len++;
+
+ return len;
+}
+
+
/* calculate sample rate, BRR, and clock select for HSCIF */
static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
int *brr, unsigned int *srr,
- unsigned int *cks)
+ unsigned int *cks, int frame_len)
{
- int sr, c, br, err;
+ int sr, c, br, err, recv_margin;
int min_err = 1000; /* 100% */
+ int recv_max_margin = 0;
/* Find the combination of sample rate and clock select with the
smallest deviation from the desired baud rate. */
for (sr = 8; sr <= 32; sr++) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- br = freq / (sr * (1 << (2 * c + 1)) * bps) - 1;
- if (br < 0 || br > 255)
+ br = DIV_ROUND_CLOSEST(freq, (sr *
+ (1 << (2 * c + 1)) * bps)) - 1;
+ br = clamp(br, 0, 255);
+ err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr *
+ (1 << (2 * c + 1)) / 1000)) -
+ 1000;
+ if (err < 0)
continue;
- err = freq / ((br + 1) * bps * sr *
- (1 << (2 * c + 1)) / 1000) - 1000;
+
+ /* Calc recv margin
+ * M: Receive margin (%)
+ * N: Ratio of bit rate to clock (N = sampling rate)
+ * D: Clock duty (D = 0 to 1.0)
+ * L: Frame length (L = 9 to 12)
+ * F: Absolute value of clock frequency deviation
+ *
+ * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
+ * (|D - 0.5| / N * (1 + F))|
+ * NOTE: Usually, treat D for 0.5, F is 0 by this
+ * calculation.
+ */
+ recv_margin = abs((500 -
+ DIV_ROUND_CLOSEST(1000, sr << 1)) / 10);
if (min_err > err) {
min_err = err;
- *brr = br;
- *srr = sr - 1;
- *cks = c;
- }
+ recv_max_margin = recv_margin;
+ } else if ((min_err == err) &&
+ (recv_margin > recv_max_margin))
+ recv_max_margin = recv_margin;
+ else
+ continue;
+
+ *brr = br;
+ *srr = sr - 1;
+ *cks = c;
}
}
@@ -1840,10 +1874,19 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct sci_port *s = to_sci_port(port);
struct plat_sci_reg *reg;
- unsigned int baud, smr_val, max_baud, cks = 0;
+ unsigned int baud, smr_val = 0, max_baud, cks = 0;
int t = -1;
unsigned int srr = 15;
+ if ((termios->c_cflag & CSIZE) == CS7)
+ smr_val |= SCSMR_CHR;
+ if (termios->c_cflag & PARENB)
+ smr_val |= SCSMR_PE;
+ if (termios->c_cflag & PARODD)
+ smr_val |= SCSMR_PE | SCSMR_ODD;
+ if (termios->c_cflag & CSTOPB)
+ smr_val |= SCSMR_STOP;
+
/*
* earlyprintk comes here early on with port->uartclk set to zero.
* the clock framework is not up and running at this point so here
@@ -1857,8 +1900,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
if (likely(baud && port->uartclk)) {
if (s->cfg->type == PORT_HSCIF) {
+ int frame_len = sci_baud_calc_frame_len(smr_val);
sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
- &cks);
+ &cks, frame_len);
} else {
t = sci_scbrr_calc(s, baud, port->uartclk);
for (cks = 0; t >= 256 && cks <= 3; cks++)
@@ -1870,16 +1914,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_reset(port);
- smr_val = serial_port_in(port, SCSMR) & 3;
-
- if ((termios->c_cflag & CSIZE) == CS7)
- smr_val |= SCSMR_CHR;
- if (termios->c_cflag & PARENB)
- smr_val |= SCSMR_PE;
- if (termios->c_cflag & PARODD)
- smr_val |= SCSMR_PE | SCSMR_ODD;
- if (termios->c_cflag & CSTOPB)
- smr_val |= SCSMR_STOP;
+ smr_val |= serial_port_in(port, SCSMR) & 3;
uart_update_timeout(port, termios->c_cflag, baud);
@@ -2080,7 +2115,6 @@ static struct uart_ops sci_uart_ops = {
.start_tx = sci_start_tx,
.stop_tx = sci_stop_tx,
.stop_rx = sci_stop_rx,
- .enable_ms = sci_enable_ms,
.break_ctl = sci_break_ctl,
.startup = sci_startup,
.shutdown = sci_shutdown,
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 68b0fd4b9a6a..4102192687ee 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -290,7 +290,8 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
else {
- sirfsoc_uart_pio_tx_chars(sirfport, 1);
+ sirfsoc_uart_pio_tx_chars(sirfport,
+ SIRFSOC_UART_IO_TX_REASONABLE_CNT);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
if (!sirfport->is_marco)
wr_regl(port, ureg->sirfsoc_int_en_reg,
@@ -358,9 +359,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
struct uart_port *port = &sirfport->port;
+ spin_lock(&port->lock);
if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
uart_handle_cts_change(port,
!gpio_get_value(sirfport->cts_gpio));
+ spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@@ -428,10 +431,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
sirfport->rx_io_count += rx_count;
port->icount.rx += rx_count;
- spin_unlock(&port->lock);
- tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
-
return rx_count;
}
@@ -465,6 +464,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
+ spin_lock_irqsave(&port->lock, flags);
xmit->tail = (xmit->tail + sirfport->transfer_size) &
(UART_XMIT_SIZE - 1);
port->icount.tx += sirfport->transfer_size;
@@ -473,10 +473,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
if (sirfport->tx_dma_addr)
dma_unmap_single(port->dev, sirfport->tx_dma_addr,
sirfport->transfer_size, DMA_TO_DEVICE);
- spin_lock_irqsave(&sirfport->tx_lock, flags);
sirfport->tx_dma_state = TX_DMA_IDLE;
sirfsoc_uart_tx_with_dma(sirfport);
- spin_unlock_irqrestore(&sirfport->tx_lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
static void sirfsoc_uart_insert_rx_buf_to_tty(
@@ -489,7 +488,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(
inserted = tty_insert_flip_string(tport,
sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
port->icount.rx += inserted;
- tty_flip_buffer_push(tport);
}
static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
@@ -525,7 +523,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
unsigned long flags;
struct dma_tx_state tx_state;
- spin_lock_irqsave(&sirfport->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -541,12 +539,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
- spin_lock(&port->lock);
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
- spin_unlock(&port->lock);
if (sirfport->rx_io_count == 4) {
- spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
@@ -557,11 +551,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_done_en);
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
-
sirfsoc_uart_start_next_rx_dma(port);
} else {
- spin_lock_irqsave(&sirfport->rx_lock, flags);
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
if (!sirfport->is_marco)
@@ -571,8 +562,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
uint_en->sirfsoc_rx_done_en);
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
@@ -581,8 +573,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
struct dma_tx_state tx_state;
- spin_lock(&sirfport->rx_lock);
-
dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
dmaengine_terminate_all(sirfport->rx_dma_chan);
@@ -595,7 +585,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_timeout_en);
- spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
}
@@ -659,7 +648,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
intr_status &= port->read_status_mask;
uart_insert_char(port, intr_status,
uint_en->sirfsoc_rx_oflow_en, 0, flag);
- tty_flip_buffer_push(&state->port);
}
recv_char:
if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
@@ -684,6 +672,9 @@ recv_char:
sirfsoc_uart_pio_rx_chars(port,
SIRFSOC_UART_IO_RX_MAX_CNT);
}
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(&state->port);
+ spin_lock(&port->lock);
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
@@ -702,6 +693,7 @@ recv_char:
}
}
spin_unlock(&port->lock);
+
return IRQ_HANDLED;
}
@@ -713,7 +705,7 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
struct dma_tx_state tx_state;
- spin_lock_irqsave(&sirfport->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -726,17 +718,20 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
sirfport->rx_completed++;
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
}
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_rx_dma_complete_callback(void *param)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
- spin_lock(&sirfport->rx_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sirfport->port.lock, flags);
sirfport->rx_issued++;
sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
- spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
+ spin_unlock_irqrestore(&sirfport->port.lock, flags);
}
/* submit rx dma task into dmaengine */
@@ -745,18 +740,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
- unsigned long flags;
int i;
- spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
~SIRFUART_IO_MODE);
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
sirfsoc_rx_submit_one_dma_desc(port, i);
sirfport->rx_completed = sirfport->rx_issued = 0;
- spin_lock_irqsave(&sirfport->rx_lock, flags);
if (!sirfport->is_marco)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
@@ -764,7 +755,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
SIRFUART_RX_DMA_INT_EN(port, uint_en));
- spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
@@ -907,7 +897,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
if (termios->c_iflag & INPCK)
port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
}
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
if (termios->c_iflag & IGNPAR)
@@ -1228,7 +1218,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
while (rd_regl(port,
ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
cpu_relax();
- wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
}
static void sirfsoc_uart_console_write(struct console *co, const char *s,
@@ -1369,8 +1359,6 @@ usp_no_flow_control:
ret = -EFAULT;
goto err;
}
- spin_lock_init(&sirfport->rx_lock);
- spin_lock_init(&sirfport->tx_lock);
tasklet_init(&sirfport->rx_dma_complete_tasklet,
sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
tasklet_init(&sirfport->rx_tmo_process_tasklet,
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 8a6eddad2f3c..6a7ebf7ef130 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -424,8 +424,6 @@ struct sirfsoc_uart_port {
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
struct dma_async_tx_descriptor *tx_dma_desc;
- spinlock_t rx_lock;
- spinlock_t tx_lock;
struct tasklet_struct rx_dma_complete_tasklet;
struct tasklet_struct rx_tmo_process_tasklet;
unsigned int rx_io_count;
@@ -441,9 +439,7 @@ struct sirfsoc_uart_port {
/* Register Access Control */
#define portaddr(port, reg) ((port)->membase + (reg))
-#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
-#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */
@@ -453,4 +449,4 @@ struct sirfsoc_uart_port {
/* I/O Mode */
#define SIRFSOC_UART_IO_RX_MAX_CNT 256
-#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 6
+#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
index f51ffdc696fd..33e94e56dcdb 100644
--- a/drivers/tty/serial/sn_console.c
+++ b/drivers/tty/serial/sn_console.c
@@ -275,15 +275,6 @@ static void snp_release_port(struct uart_port *port)
}
/**
- * snp_enable_ms - Force modem status interrupts on - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_enable_ms(struct uart_port *port)
-{
-}
-
-/**
* snp_shutdown - shut down the port - free irq and disable - no-op for us
* @port: Port to shut down - we ignore
*
@@ -396,7 +387,6 @@ static struct uart_ops sn_console_ops = {
.stop_tx = snp_stop_tx,
.start_tx = snp_start_tx,
.stop_rx = snp_stop_rx,
- .enable_ms = snp_enable_ms,
.break_ctl = snp_break_ctl,
.startup = snp_startup,
.shutdown = snp_shutdown,
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index dd3a96e07026..8b2d7356611d 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port)
return asc_in(port, ASC_STA) & ASC_STA_TE;
}
-static inline int asc_txfifo_is_full(struct uart_port *port)
+static inline u32 asc_txfifo_is_half_empty(struct uart_port *port)
{
- return asc_in(port, ASC_STA) & ASC_STA_TF;
+ return asc_in(port, ASC_STA) & ASC_STA_THE;
}
static inline const char *asc_port_name(struct uart_port *port)
@@ -411,12 +411,6 @@ static void asc_stop_rx(struct uart_port *port)
asc_disable_rx_interrupts(port);
}
-/* Force modem status interrupts on */
-static void asc_enable_ms(struct uart_port *port)
-{
- /* Nothing here yet .. */
-}
-
/* Handle breaks - ignored by us */
static void asc_break_ctl(struct uart_port *port, int break_state)
{
@@ -533,12 +527,12 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
* ASCBaudRate = ------------------------
* inputclock
*
- * However to keep the maths inside 32bits we divide top and
- * bottom by 64. The +1 is to avoid a divide by zero if the
- * input clock rate is something unexpected.
+ * To keep maths inside 64bits, we divide inputclock by 16.
*/
- u32 counter = (baud * 16384) / ((port->uartclk / 64) + 1);
- asc_out(port, ASC_BAUDRATE, counter);
+ u64 dividend = (u64)baud * (1 << 16);
+
+ do_div(dividend, port->uartclk / 16);
+ asc_out(port, ASC_BAUDRATE, dividend);
ctrl_val |= ASC_CTL_BAUDMODE;
}
@@ -547,7 +541,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE;
if (termios->c_iflag & INPCK)
ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE;
/*
@@ -628,7 +622,7 @@ static int asc_get_poll_char(struct uart_port *port)
static void asc_put_poll_char(struct uart_port *port, unsigned char c)
{
- while (asc_txfifo_is_full(port))
+ while (!asc_txfifo_is_half_empty(port))
cpu_relax();
asc_out(port, ASC_TXBUF, c);
}
@@ -644,7 +638,6 @@ static struct uart_ops asc_uart_ops = {
.start_tx = asc_start_tx,
.stop_tx = asc_stop_tx,
.stop_rx = asc_stop_rx,
- .enable_ms = asc_enable_ms,
.break_ctl = asc_break_ctl,
.startup = asc_startup,
.shutdown = asc_shutdown,
@@ -783,7 +776,7 @@ static void asc_console_putchar(struct uart_port *port, int ch)
unsigned int timeout = 1000000;
/* Wait for upto 1 second in case flow control is stopping us. */
- while (--timeout && asc_txfifo_is_full(port))
+ while (--timeout && !asc_txfifo_is_half_empty(port))
udelay(1);
asc_out(port, ASC_TXBUF, ch);
@@ -849,7 +842,8 @@ static int asc_console_setup(struct console *co, char *options)
* this to be called during the uart port registration when the
* driver gets probed and the port should be mapped at that point.
*/
- BUG_ON(ascport->port.mapbase == 0 || ascport->port.membase == NULL);
+ if (ascport->port.mapbase == 0 || ascport->port.membase == NULL)
+ return -ENXIO;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index dc697cee248a..20521db2189f 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -285,11 +285,6 @@ static void sunhv_stop_rx(struct uart_port *port)
{
}
-/* port->lock held by caller. */
-static void sunhv_enable_ms(struct uart_port *port)
-{
-}
-
/* port->lock is not held. */
static void sunhv_break_ctl(struct uart_port *port, int break_state)
{
@@ -379,7 +374,6 @@ static struct uart_ops sunhv_pops = {
.start_tx = sunhv_start_tx,
.send_xchar = sunhv_send_xchar,
.stop_rx = sunhv_stop_rx,
- .enable_ms = sunhv_enable_ms,
.break_ctl = sunhv_break_ctl,
.startup = sunhv_startup,
.shutdown = sunhv_shutdown,
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 5faa8e905e98..b9598b227a45 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -157,6 +157,15 @@ receive_chars(struct uart_sunsab_port *up,
(up->port.line == up->port.cons->index))
saw_console_brk = 1;
+ if (count == 0) {
+ if (unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) {
+ stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR |
+ SAB82532_ISR0_FERR);
+ up->port.icount.brk++;
+ uart_handle_break(&up->port);
+ }
+ }
+
for (i = 0; i < count; i++) {
unsigned char ch = buf[i], flag;
@@ -427,6 +436,9 @@ static void sunsab_start_tx(struct uart_port *port)
struct circ_buf *xmit = &up->port.state->xmit;
int i;
+ if (uart_circ_empty(xmit))
+ return;
+
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
writeb(up->interrupt_mask1, &up->regs->w.imr1);
@@ -473,12 +485,6 @@ static void sunsab_stop_rx(struct uart_port *port)
writeb(up->interrupt_mask1, &up->regs->w.imr0);
}
-/* port->lock held by caller. */
-static void sunsab_enable_ms(struct uart_port *port)
-{
- /* For now we always receive these interrupts. */
-}
-
/* port->lock is not held. */
static void sunsab_break_ctl(struct uart_port *port, int break_state)
{
@@ -719,7 +725,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
if (iflag & INPCK)
up->port.read_status_mask |= (SAB82532_ISR0_PERR |
SAB82532_ISR0_FERR);
- if (iflag & (BRKINT | PARMRK))
+ if (iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
/*
@@ -807,7 +813,6 @@ static struct uart_ops sunsab_pops = {
.start_tx = sunsab_start_tx,
.send_xchar = sunsab_send_xchar,
.stop_rx = sunsab_stop_rx,
- .enable_ms = sunsab_enable_ms,
.break_ctl = sunsab_break_ctl,
.startup = sunsab_startup,
.shutdown = sunsab_shutdown,
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 9a0f24f83720..5326ae195e5f 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -834,7 +834,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (iflag & (BRKINT | PARMRK))
+ if (iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index a2c40ed287d2..02df3940b95e 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -703,6 +703,8 @@ static void sunzilog_start_tx(struct uart_port *port)
} else {
struct circ_buf *xmit = &port->state->xmit;
+ if (uart_circ_empty(xmit))
+ return;
writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -915,7 +917,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
up->port.read_status_mask = Rx_OVR;
if (iflag & INPCK)
up->port.read_status_mask |= CRC_ERR | PAR_ERR;
- if (iflag & (BRKINT | PARMRK))
+ if (iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= BRK_ABRT;
up->port.ignore_status_mask = 0;
diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c
index f92d7e6bd876..453215f5420d 100644
--- a/drivers/tty/serial/tilegx.c
+++ b/drivers/tty/serial/tilegx.c
@@ -314,15 +314,6 @@ static void tilegx_stop_rx(struct uart_port *port)
mutex_unlock(&tile_uart->mutex);
}
-
-/*
- * Enable modem status interrupts.
- */
-static void tilegx_enable_ms(struct uart_port *port)
-{
- /* N/A */
-}
-
/*
* Control the transmission of a break signal.
*/
@@ -359,8 +350,8 @@ static int tilegx_startup(struct uart_port *port)
}
/* Create our IRQs. */
- port->irq = create_irq();
- if (port->irq < 0)
+ port->irq = irq_alloc_hwirq(-1);
+ if (!port->irq)
goto err_uart_dest;
tile_irq_activate(port->irq, TILE_IRQ_PERCPU);
@@ -395,7 +386,7 @@ static int tilegx_startup(struct uart_port *port)
err_free_irq:
free_irq(port->irq, port);
err_dest_irq:
- destroy_irq(port->irq);
+ irq_free_hwirq(port->irq);
err_uart_dest:
gxio_uart_destroy(context);
ret = -ENXIO;
@@ -435,7 +426,7 @@ static void tilegx_shutdown(struct uart_port *port)
if (port->irq > 0) {
free_irq(port->irq, port);
- destroy_irq(port->irq);
+ irq_free_hwirq(port->irq);
port->irq = 0;
}
@@ -614,7 +605,6 @@ static const struct uart_ops tilegx_ops = {
.stop_tx = tilegx_stop_tx,
.start_tx = tilegx_start_tx,
.stop_rx = tilegx_stop_rx,
- .enable_ms = tilegx_enable_ms,
.break_ctl = tilegx_break_ctl,
.startup = tilegx_startup,
.shutdown = tilegx_shutdown,
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index f87097acd8ab..0d11d5032b93 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -244,11 +244,6 @@ static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
*ier |= CTS_DELTA;
}
-static void timbuart_enable_ms(struct uart_port *port)
-{
- /* N/A */
-}
-
static void timbuart_break_ctl(struct uart_port *port, int ctl)
{
/* N/A */
@@ -405,7 +400,6 @@ static struct uart_ops timbuart_ops = {
.start_tx = timbuart_start_tx,
.flush_buffer = timbuart_flush_buffer,
.stop_rx = timbuart_stop_rx,
- .enable_ms = timbuart_enable_ms,
.break_ctl = timbuart_break_ctl,
.startup = timbuart_startup,
.shutdown = timbuart_shutdown,
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 5f90ef24d475..9fc22f40796e 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -250,11 +250,6 @@ static void ulite_stop_rx(struct uart_port *port)
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
}
-static void ulite_enable_ms(struct uart_port *port)
-{
- /* N/A */
-}
-
static void ulite_break_ctl(struct uart_port *port, int ctl)
{
/* N/A */
@@ -395,7 +390,6 @@ static struct uart_ops ulite_ops = {
.stop_tx = ulite_stop_tx,
.start_tx = ulite_start_tx,
.stop_rx = ulite_stop_rx,
- .enable_ms = ulite_enable_ms,
.break_ctl = ulite_break_ctl,
.startup = ulite_startup,
.shutdown = ulite_shutdown,
@@ -418,14 +412,23 @@ static struct uart_ops ulite_ops = {
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
- int i;
u8 val;
-
- /* Spin waiting for TX fifo to have space available */
- for (i = 0; i < 100000; i++) {
+ unsigned long timeout;
+
+ /*
+ * Spin waiting for TX fifo to have space available.
+ * When using the Microblaze Debug Module this can take up to 1s
+ */
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (1) {
val = uart_in32(ULITE_STATUS, port);
if ((val & ULITE_STATUS_TXFULL) == 0)
break;
+ if (time_after(jiffies, timeout)) {
+ dev_warn(port->dev,
+ "timeout waiting for TX buffer empty\n");
+ break;
+ }
cpu_relax();
}
}
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index d569ca58bab6..c107a0f0e72f 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -435,16 +435,6 @@ static void qe_uart_stop_rx(struct uart_port *port)
clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX);
}
-/*
- * Enable status change interrupts
- *
- * We don't support status change interrupts, but we need to define this
- * function otherwise the kernel will panic.
- */
-static void qe_uart_enable_ms(struct uart_port *port)
-{
-}
-
/* Start or stop sending break signal
*
* This function controls the sending of a break signal. If break_state=1,
@@ -936,7 +926,7 @@ static void qe_uart_set_termios(struct uart_port *port,
port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
if (termios->c_iflag & INPCK)
port->read_status_mask |= BD_SC_FR | BD_SC_PR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= BD_SC_BR;
/*
@@ -1102,7 +1092,6 @@ static struct uart_ops qe_uart_pops = {
.stop_tx = qe_uart_stop_tx,
.start_tx = qe_uart_start_tx,
.stop_rx = qe_uart_stop_rx,
- .enable_ms = qe_uart_enable_ms,
.break_ctl = qe_uart_break_ctl,
.startup = qe_uart_startup,
.shutdown = qe_uart_shutdown,
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index a63c14bc9a24..db0c8a4ab03e 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -559,7 +559,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new,
port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
if (c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (c_iflag & (BRKINT | PARMRK))
+ if (c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART_LSR_BI;
port->ignore_status_mask = 0;
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index f619ad5b5eae..01951d27cc03 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1,7 +1,7 @@
/*
- * Xilinx PS UART driver
+ * Cadence UART driver (found in Xilinx Zynq)
*
- * 2011 - 2013 (C) Xilinx Inc.
+ * 2011 - 2014 (C) Xilinx Inc.
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public
@@ -9,6 +9,9 @@
* either version 2 of the License, or (at your option) any
* later version.
*
+ * This driver has originally been pushed by Xilinx using a Zynq-branding. This
+ * still shows in the naming of this file, the kconfig symbols and some symbols
+ * in the code.
*/
#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -28,16 +31,16 @@
#include <linux/of.h>
#include <linux/module.h>
-#define XUARTPS_TTY_NAME "ttyPS"
-#define XUARTPS_NAME "xuartps"
-#define XUARTPS_MAJOR 0 /* use dynamic node allocation */
-#define XUARTPS_MINOR 0 /* works best with devtmpfs */
-#define XUARTPS_NR_PORTS 2
-#define XUARTPS_FIFO_SIZE 64 /* FIFO size */
-#define XUARTPS_REGISTER_SPACE 0xFFF
+#define CDNS_UART_TTY_NAME "ttyPS"
+#define CDNS_UART_NAME "xuartps"
+#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
+#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 xuartps_readl(offset) ioread32(port->membase + offset)
-#define xuartps_writel(val, offset) iowrite32(val, port->membase + offset)
+#define cdns_uart_readl(offset) ioread32(port->membase + offset)
+#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset)
/* Rx Trigger level */
static int rx_trigger_level = 56;
@@ -49,77 +52,62 @@ static int rx_timeout = 10;
module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
-/********************************Register Map********************************/
-/** UART
- *
- * Register offsets for the UART.
- *
- */
-#define XUARTPS_CR_OFFSET 0x00 /* Control Register [8:0] */
-#define XUARTPS_MR_OFFSET 0x04 /* Mode Register [10:0] */
-#define XUARTPS_IER_OFFSET 0x08 /* Interrupt Enable [10:0] */
-#define XUARTPS_IDR_OFFSET 0x0C /* Interrupt Disable [10:0] */
-#define XUARTPS_IMR_OFFSET 0x10 /* Interrupt Mask [10:0] */
-#define XUARTPS_ISR_OFFSET 0x14 /* Interrupt Status [10:0]*/
-#define XUARTPS_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator [15:0] */
-#define XUARTPS_RXTOUT_OFFSET 0x1C /* RX Timeout [7:0] */
-#define XUARTPS_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level [5:0] */
-#define XUARTPS_MODEMCR_OFFSET 0x24 /* Modem Control [5:0] */
-#define XUARTPS_MODEMSR_OFFSET 0x28 /* Modem Status [8:0] */
-#define XUARTPS_SR_OFFSET 0x2C /* Channel Status [11:0] */
-#define XUARTPS_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */
-#define XUARTPS_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider [7:0] */
-#define XUARTPS_FLOWDEL_OFFSET 0x38 /* Flow Delay [15:0] */
-#define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C /* IR Minimum Received Pulse
- Width [15:0] */
-#define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse
- Width [7:0] */
-#define XUARTPS_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level [5:0] */
-
-/** Control Register
- *
- * The Control register (CR) controls the major functions of the device.
- *
- * Control Register Bit Definitions
- */
-#define XUARTPS_CR_STOPBRK 0x00000100 /* Stop TX break */
-#define XUARTPS_CR_STARTBRK 0x00000080 /* Set TX break */
-#define XUARTPS_CR_TX_DIS 0x00000020 /* TX disabled. */
-#define XUARTPS_CR_TX_EN 0x00000010 /* TX enabled */
-#define XUARTPS_CR_RX_DIS 0x00000008 /* RX disabled. */
-#define XUARTPS_CR_RX_EN 0x00000004 /* RX enabled */
-#define XUARTPS_CR_TXRST 0x00000002 /* TX logic reset */
-#define XUARTPS_CR_RXRST 0x00000001 /* RX logic reset */
-#define XUARTPS_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
-
-/** Mode Register
- *
+/* Register offsets for the UART. */
+#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
+#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
+#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
+#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
+#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
+#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
+#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
+#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
+#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
+#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
+#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
+#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
+#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
+#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
+#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
+#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
+#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
+#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
+
+/* Control Register Bit Definitions */
+#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
+#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */
+#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */
+#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */
+#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */
+#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */
+#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
+#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
+#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
+
+/*
+ * Mode Register:
* The mode register (MR) defines the mode of transfer as well as the data
* format. If this register is modified during transmission or reception,
* data validity cannot be guaranteed.
- *
- * Mode Register Bit Definitions
- *
*/
-#define XUARTPS_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
-#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
-#define XUARTPS_MR_CHMODE_NORM 0x00000000 /* Normal mode */
+#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
+#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
+#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */
-#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
-#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
+#define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
+#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
-#define XUARTPS_MR_PARITY_NONE 0x00000020 /* No parity mode */
-#define XUARTPS_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
-#define XUARTPS_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
-#define XUARTPS_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
-#define XUARTPS_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
+#define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
+#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
+#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
+#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
+#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
-#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
-#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
-#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
+#define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
+#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
+#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
-/** Interrupt Registers
- *
+/*
+ * Interrupt Registers:
* Interrupt control logic uses the interrupt enable register (IER) and the
* interrupt disable register (IDR) to set the value of the bits in the
* interrupt mask register (IMR). The IMR determines whether to pass an
@@ -127,65 +115,65 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an
* interrupt. IMR and ISR are read only, and IER and IDR are write only.
* Reading either IER or IDR returns 0x00.
- *
* All four registers have the same bit definitions.
*/
-#define XUARTPS_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
-#define XUARTPS_IXR_PARITY 0x00000080 /* Parity error interrupt */
-#define XUARTPS_IXR_FRAMING 0x00000040 /* Framing error interrupt */
-#define XUARTPS_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
-#define XUARTPS_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
-#define XUARTPS_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
-#define XUARTPS_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
-#define XUARTPS_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
-#define XUARTPS_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
-#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
-#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */
+#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
+#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */
+#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */
+#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
+#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
+#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
+#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
+#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
+#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
+#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
+#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
-#define XUARTPS_IXR_BRK 0x80000000
+#define CDNS_UART_IXR_BRK 0x80000000
-/** Channel Status Register
- *
+/*
+ * Channel Status Register:
* The channel status register (CSR) is provided to enable the control logic
* to monitor the status of bits in the channel interrupt status register,
* even if these are masked out by the interrupt mask register.
*/
-#define XUARTPS_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
-#define XUARTPS_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
-#define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */
-#define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */
+#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
+#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
+#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
+#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */
/* baud dividers min/max values */
-#define XUARTPS_BDIV_MIN 4
-#define XUARTPS_BDIV_MAX 255
-#define XUARTPS_CD_MAX 65535
+#define CDNS_UART_BDIV_MIN 4
+#define CDNS_UART_BDIV_MAX 255
+#define CDNS_UART_CD_MAX 65535
/**
- * struct xuartps - device data
- * @port Pointer to the UART port
- * @refclk Reference clock
- * @aperclk APB clock
- * @baud Current baud rate
- * @clk_rate_change_nb Notifier block for clock changes
+ * struct cdns_uart - device data
+ * @port: Pointer to the UART port
+ * @uartclk: Reference clock
+ * @pclk: APB clock
+ * @baud: Current baud rate
+ * @clk_rate_change_nb: Notifier block for clock changes
*/
-struct xuartps {
+struct cdns_uart {
struct uart_port *port;
- struct clk *refclk;
- struct clk *aperclk;
+ struct clk *uartclk;
+ struct clk *pclk;
unsigned int baud;
struct notifier_block clk_rate_change_nb;
};
-#define to_xuartps(_nb) container_of(_nb, struct xuartps, clk_rate_change_nb);
+#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
+ clk_rate_change_nb);
/**
- * xuartps_isr - Interrupt handler
+ * cdns_uart_isr - Interrupt handler
* @irq: Irq number
* @dev_id: Id of the port
*
- * Returns IRQHANDLED
- **/
-static irqreturn_t xuartps_isr(int irq, void *dev_id)
+ * Return: IRQHANDLED
+ */
+static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
{
struct uart_port *port = (struct uart_port *)dev_id;
unsigned long flags;
@@ -198,43 +186,42 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
/* Read the interrupt status register to determine which
* interrupt(s) is/are active.
*/
- isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);
+ isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET);
/*
* There is no hardware break detection, so we interpret framing
* error with all-zeros data as a break sequence. Most of the time,
* there's another non-zero byte at the end of the sequence.
*/
-
- if (isrstatus & XUARTPS_IXR_FRAMING) {
- while (!(xuartps_readl(XUARTPS_SR_OFFSET) &
- XUARTPS_SR_RXEMPTY)) {
- if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) {
- port->read_status_mask |= XUARTPS_IXR_BRK;
- isrstatus &= ~XUARTPS_IXR_FRAMING;
+ if (isrstatus & CDNS_UART_IXR_FRAMING) {
+ while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_RXEMPTY)) {
+ if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) {
+ port->read_status_mask |= CDNS_UART_IXR_BRK;
+ isrstatus &= ~CDNS_UART_IXR_FRAMING;
}
}
- xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET);
}
/* drop byte with parity error if IGNPAR specified */
- if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
- isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);
+ if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
+ isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);
isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask;
- if ((isrstatus & XUARTPS_IXR_TOUT) ||
- (isrstatus & XUARTPS_IXR_RXTRIG)) {
+ if ((isrstatus & CDNS_UART_IXR_TOUT) ||
+ (isrstatus & CDNS_UART_IXR_RXTRIG)) {
/* Receive Timeout Interrupt */
- while ((xuartps_readl(XUARTPS_SR_OFFSET) &
- XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
- data = xuartps_readl(XUARTPS_FIFO_OFFSET);
+ while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
+ data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
/* Non-NULL byte after BREAK is garbage (99%) */
if (data && (port->read_status_mask &
- XUARTPS_IXR_BRK)) {
- port->read_status_mask &= ~XUARTPS_IXR_BRK;
+ CDNS_UART_IXR_BRK)) {
+ port->read_status_mask &= ~CDNS_UART_IXR_BRK;
port->icount.brk++;
if (uart_handle_break(port))
continue;
@@ -258,16 +245,17 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
port->icount.rx++;
- if (isrstatus & XUARTPS_IXR_PARITY) {
+ if (isrstatus & CDNS_UART_IXR_PARITY) {
port->icount.parity++;
status = TTY_PARITY;
- } else if (isrstatus & XUARTPS_IXR_FRAMING) {
+ } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
port->icount.frame++;
status = TTY_FRAME;
- } else if (isrstatus & XUARTPS_IXR_OVERRUN)
+ } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
port->icount.overrun++;
+ }
- uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN,
+ uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
data, status);
}
spin_unlock(&port->lock);
@@ -276,10 +264,10 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
}
/* Dispatch an appropriate handler */
- if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) {
+ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
if (uart_circ_empty(&port->state->xmit)) {
- xuartps_writel(XUARTPS_IXR_TXEMPTY,
- XUARTPS_IDR_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_TXEMPTY,
+ CDNS_UART_IDR_OFFSET);
} else {
numbytes = port->fifosize;
/* Break if no more data available in the UART buffer */
@@ -287,12 +275,12 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
if (uart_circ_empty(&port->state->xmit))
break;
/* Get the data from the UART circular buffer
- * and write it to the xuartps's TX_FIFO
+ * and write it to the cdns_uart's TX_FIFO
* register.
*/
- xuartps_writel(
+ cdns_uart_writel(
port->state->xmit.buf[port->state->xmit.
- tail], XUARTPS_FIFO_OFFSET);
+ tail], CDNS_UART_FIFO_OFFSET);
port->icount.tx++;
@@ -300,7 +288,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
* the buffer if it reaches limit.
*/
port->state->xmit.tail =
- (port->state->xmit.tail + 1) & \
+ (port->state->xmit.tail + 1) &
(UART_XMIT_SIZE - 1);
}
@@ -310,7 +298,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
}
}
- xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET);
+ cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET);
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore(&port->lock, flags);
@@ -319,13 +307,13 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
}
/**
- * xuartps_calc_baud_divs - Calculate baud rate divisors
+ * cdns_uart_calc_baud_divs - Calculate baud rate divisors
* @clk: UART module input clock
* @baud: Desired baud rate
* @rbdiv: BDIV value (return value)
* @rcd: CD value (return value)
* @div8: Value for clk_sel bit in mod (return value)
- * Returns baud rate, requested baud when possible, or actual baud when there
+ * Return: baud rate, requested baud when possible, or actual baud when there
* was too much error, zero if no valid divisors are found.
*
* Formula to obtain baud rate is
@@ -338,8 +326,8 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
* baud rate generate register
* baud rate clock divisor register
*/
-static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud,
- u32 *rbdiv, u32 *rcd, int *div8)
+static unsigned int cdns_uart_calc_baud_divs(unsigned int clk,
+ unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8)
{
u32 cd, bdiv;
unsigned int calc_baud;
@@ -347,16 +335,16 @@ static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud,
unsigned int bauderror;
unsigned int besterror = ~0;
- if (baud < clk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX)) {
+ if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) {
*div8 = 1;
clk /= 8;
} else {
*div8 = 0;
}
- for (bdiv = XUARTPS_BDIV_MIN; bdiv <= XUARTPS_BDIV_MAX; bdiv++) {
+ for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) {
cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1));
- if (cd < 1 || cd > XUARTPS_CD_MAX)
+ if (cd < 1 || cd > CDNS_UART_CD_MAX)
continue;
calc_baud = clk / (cd * (bdiv + 1));
@@ -381,47 +369,47 @@ static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud,
}
/**
- * xuartps_set_baud_rate - Calculate and set the baud rate
+ * cdns_uart_set_baud_rate - Calculate and set the baud rate
* @port: Handle to the uart port structure
* @baud: Baud rate to set
- * Returns baud rate, requested baud when possible, or actual baud when there
+ * Return: baud rate, requested baud when possible, or actual baud when there
* was too much error, zero if no valid divisors are found.
*/
-static unsigned int xuartps_set_baud_rate(struct uart_port *port,
+static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
unsigned int baud)
{
unsigned int calc_baud;
u32 cd = 0, bdiv = 0;
u32 mreg;
int div8;
- struct xuartps *xuartps = port->private_data;
+ struct cdns_uart *cdns_uart = port->private_data;
- calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
+ calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
&div8);
/* Write new divisors to hardware */
- mreg = xuartps_readl(XUARTPS_MR_OFFSET);
+ mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET);
if (div8)
- mreg |= XUARTPS_MR_CLKSEL;
+ mreg |= CDNS_UART_MR_CLKSEL;
else
- mreg &= ~XUARTPS_MR_CLKSEL;
- xuartps_writel(mreg, XUARTPS_MR_OFFSET);
- xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET);
- xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET);
- xuartps->baud = baud;
+ 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);
+ cdns_uart->baud = baud;
return calc_baud;
}
#ifdef CONFIG_COMMON_CLK
/**
- * xuartps_clk_notitifer_cb - Clock notifier callback
+ * cdns_uart_clk_notitifer_cb - Clock notifier callback
* @nb: Notifier block
* @event: Notify event
* @data: Notifier data
- * Returns NOTIFY_OK on success, NOTIFY_BAD on error.
+ * Return: NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error.
*/
-static int xuartps_clk_notifier_cb(struct notifier_block *nb,
+static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
u32 ctrl_reg;
@@ -429,35 +417,36 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb,
int locked = 0;
struct clk_notifier_data *ndata = data;
unsigned long flags = 0;
- struct xuartps *xuartps = to_xuartps(nb);
+ struct cdns_uart *cdns_uart = to_cdns_uart(nb);
- port = xuartps->port;
+ port = cdns_uart->port;
if (port->suspended)
return NOTIFY_OK;
switch (event) {
case PRE_RATE_CHANGE:
{
- u32 bdiv;
- u32 cd;
+ u32 bdiv, cd;
int div8;
/*
* Find out if current baud-rate can be achieved with new clock
* frequency.
*/
- if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud,
- &bdiv, &cd, &div8))
+ if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud,
+ &bdiv, &cd, &div8)) {
+ dev_warn(port->dev, "clock rate change rejected\n");
return NOTIFY_BAD;
+ }
- spin_lock_irqsave(&xuartps->port->lock, flags);
+ spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Disable the TX and RX to set baud rate */
- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
- (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(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);
- spin_unlock_irqrestore(&xuartps->port->lock, flags);
+ spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
return NOTIFY_OK;
}
@@ -467,25 +456,25 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb,
* frequency.
*/
- spin_lock_irqsave(&xuartps->port->lock, flags);
+ spin_lock_irqsave(&cdns_uart->port->lock, flags);
locked = 1;
port->uartclk = ndata->new_rate;
- xuartps->baud = xuartps_set_baud_rate(xuartps->port,
- xuartps->baud);
+ cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port,
+ cdns_uart->baud);
/* fall through */
case ABORT_RATE_CHANGE:
if (!locked)
- spin_lock_irqsave(&xuartps->port->lock, flags);
+ spin_lock_irqsave(&cdns_uart->port->lock, flags);
/* Set TX/RX Reset */
- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
- (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
+ cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
- while (xuartps_readl(XUARTPS_CR_OFFSET) &
- (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST))
+ while (cdns_uart_readl(CDNS_UART_CR_OFFSET) &
+ (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/*
@@ -493,14 +482,13 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb,
* enable bit and RX enable bit to enable the transmitter and
* receiver.
*/
- xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
- ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
- xuartps_writel(
- (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
- (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
- XUARTPS_CR_OFFSET);
+ cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
+ ctrl_reg = cdns_uart_readl(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);
- spin_unlock_irqrestore(&xuartps->port->lock, flags);
+ spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
return NOTIFY_OK;
default:
@@ -509,40 +497,36 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb,
}
#endif
-/*----------------------Uart Operations---------------------------*/
-
/**
- * xuartps_start_tx - Start transmitting bytes
+ * cdns_uart_start_tx - Start transmitting bytes
* @port: Handle to the uart port structure
- *
- **/
-static void xuartps_start_tx(struct uart_port *port)
+ */
+static void cdns_uart_start_tx(struct uart_port *port)
{
unsigned int status, numbytes = port->fifosize;
if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
return;
- status = xuartps_readl(XUARTPS_CR_OFFSET);
+ status = cdns_uart_readl(CDNS_UART_CR_OFFSET);
/* Set the TX enable bit and clear the TX disable bit to enable the
* transmitter.
*/
- xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN,
- XUARTPS_CR_OFFSET);
-
- while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET)
- & XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) {
+ cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
+ CDNS_UART_CR_OFFSET);
+ while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
/* Break if no more data available in the UART buffer */
if (uart_circ_empty(&port->state->xmit))
break;
/* Get the data from the UART circular buffer and
- * write it to the xuartps's TX_FIFO register.
+ * write it to the cdns_uart's TX_FIFO register.
*/
- xuartps_writel(
+ cdns_uart_writel(
port->state->xmit.buf[port->state->xmit.tail],
- XUARTPS_FIFO_OFFSET);
+ CDNS_UART_FIFO_OFFSET);
port->icount.tx++;
/* Adjust the tail of the UART buffer and wrap
@@ -551,94 +535,90 @@ static void xuartps_start_tx(struct uart_port *port)
port->state->xmit.tail = (port->state->xmit.tail + 1) &
(UART_XMIT_SIZE - 1);
}
- xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_ISR_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET);
/* Enable the TX Empty interrupt */
- xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET);
if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
/**
- * xuartps_stop_tx - Stop TX
+ * cdns_uart_stop_tx - Stop TX
* @port: Handle to the uart port structure
- *
- **/
-static void xuartps_stop_tx(struct uart_port *port)
+ */
+static void cdns_uart_stop_tx(struct uart_port *port)
{
unsigned int regval;
- regval = xuartps_readl(XUARTPS_CR_OFFSET);
- regval |= XUARTPS_CR_TX_DIS;
+ regval = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ regval |= CDNS_UART_CR_TX_DIS;
/* Disable the transmitter */
- xuartps_writel(regval, XUARTPS_CR_OFFSET);
+ cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);
}
/**
- * xuartps_stop_rx - Stop RX
+ * cdns_uart_stop_rx - Stop RX
* @port: Handle to the uart port structure
- *
- **/
-static void xuartps_stop_rx(struct uart_port *port)
+ */
+static void cdns_uart_stop_rx(struct uart_port *port)
{
unsigned int regval;
- regval = xuartps_readl(XUARTPS_CR_OFFSET);
- regval |= XUARTPS_CR_RX_DIS;
+ regval = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ regval |= CDNS_UART_CR_RX_DIS;
/* Disable the receiver */
- xuartps_writel(regval, XUARTPS_CR_OFFSET);
+ cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);
}
/**
- * xuartps_tx_empty - Check whether TX is empty
+ * cdns_uart_tx_empty - Check whether TX is empty
* @port: Handle to the uart port structure
*
- * Returns TIOCSER_TEMT on success, 0 otherwise
- **/
-static unsigned int xuartps_tx_empty(struct uart_port *port)
+ * Return: TIOCSER_TEMT on success, 0 otherwise
+ */
+static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
- status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY;
+ status = cdns_uart_readl(CDNS_UART_ISR_OFFSET) & CDNS_UART_IXR_TXEMPTY;
return status ? TIOCSER_TEMT : 0;
}
/**
- * xuartps_break_ctl - Based on the input ctl we have to start or stop
+ * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
* transmitting char breaks
* @port: Handle to the uart port structure
* @ctl: Value based on which start or stop decision is taken
- *
- **/
-static void xuartps_break_ctl(struct uart_port *port, int ctl)
+ */
+static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
{
unsigned int status;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- status = xuartps_readl(XUARTPS_CR_OFFSET);
+ status = cdns_uart_readl(CDNS_UART_CR_OFFSET);
if (ctl == -1)
- xuartps_writel(XUARTPS_CR_STARTBRK | status,
- XUARTPS_CR_OFFSET);
+ cdns_uart_writel(CDNS_UART_CR_STARTBRK | status,
+ CDNS_UART_CR_OFFSET);
else {
- if ((status & XUARTPS_CR_STOPBRK) == 0)
- xuartps_writel(XUARTPS_CR_STOPBRK | status,
- XUARTPS_CR_OFFSET);
+ if ((status & CDNS_UART_CR_STOPBRK) == 0)
+ cdns_uart_writel(CDNS_UART_CR_STOPBRK | status,
+ CDNS_UART_CR_OFFSET);
}
spin_unlock_irqrestore(&port->lock, flags);
}
/**
- * xuartps_set_termios - termios operations, handling data length, parity,
+ * cdns_uart_set_termios - termios operations, handling data length, parity,
* stop bits, flow control, baud rate
* @port: Handle to the uart port structure
* @termios: Handle to the input termios structure
* @old: Values of the previously saved termios structure
- *
- **/
-static void xuartps_set_termios(struct uart_port *port,
+ */
+static void cdns_uart_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old)
{
unsigned int cval = 0;
@@ -649,81 +629,79 @@ static void xuartps_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while ((xuartps_readl(XUARTPS_SR_OFFSET) &
- XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
- xuartps_readl(XUARTPS_FIFO_OFFSET);
+ while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
+ cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
}
/* Disable the TX and RX to set baud rate */
- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
- (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(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);
/*
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
* min and max baud should be calculated here based on port->uartclk.
* this way we get a valid baud and can safely call set_baud()
*/
- minbaud = port->uartclk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX * 8);
- maxbaud = port->uartclk / (XUARTPS_BDIV_MIN + 1);
+ minbaud = port->uartclk /
+ ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8);
+ maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1);
baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud);
- baud = xuartps_set_baud_rate(port, baud);
+ baud = cdns_uart_set_baud_rate(port, baud);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
- /*
- * Update the per-port timeout.
- */
+ /* Update the per-port timeout. */
uart_update_timeout(port, termios->c_cflag, baud);
/* Set TX/RX Reset */
- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
- (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET);
+ ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
+ cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET);
- ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
-
- /* Clear the RX disable and TX disable bits and then set the TX enable
+ /*
+ * 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.
*/
- xuartps_writel(
- (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
- | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(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);
- xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
+ cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
- port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG |
- XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT;
+ port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
+ CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
port->ignore_status_mask = 0;
if (termios->c_iflag & INPCK)
- port->read_status_mask |= XUARTPS_IXR_PARITY |
- XUARTPS_IXR_FRAMING;
+ port->read_status_mask |= CDNS_UART_IXR_PARITY |
+ CDNS_UART_IXR_FRAMING;
if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= XUARTPS_IXR_PARITY |
- XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;
+ port->ignore_status_mask |= CDNS_UART_IXR_PARITY |
+ CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
/* ignore all characters if CREAD is not set */
if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= XUARTPS_IXR_RXTRIG |
- XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY |
- XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;
+ port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG |
+ CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
+ CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
- mode_reg = xuartps_readl(XUARTPS_MR_OFFSET);
+ mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET);
/* Handling Data Size */
switch (termios->c_cflag & CSIZE) {
case CS6:
- cval |= XUARTPS_MR_CHARLEN_6_BIT;
+ cval |= CDNS_UART_MR_CHARLEN_6_BIT;
break;
case CS7:
- cval |= XUARTPS_MR_CHARLEN_7_BIT;
+ cval |= CDNS_UART_MR_CHARLEN_7_BIT;
break;
default:
case CS8:
- cval |= XUARTPS_MR_CHARLEN_8_BIT;
+ cval |= CDNS_UART_MR_CHARLEN_8_BIT;
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
break;
@@ -731,134 +709,135 @@ static void xuartps_set_termios(struct uart_port *port,
/* Handling Parity and Stop Bits length */
if (termios->c_cflag & CSTOPB)
- cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */
+ cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */
else
- cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */
+ cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */
if (termios->c_cflag & PARENB) {
/* Mark or Space parity */
if (termios->c_cflag & CMSPAR) {
if (termios->c_cflag & PARODD)
- cval |= XUARTPS_MR_PARITY_MARK;
+ cval |= CDNS_UART_MR_PARITY_MARK;
else
- cval |= XUARTPS_MR_PARITY_SPACE;
+ cval |= CDNS_UART_MR_PARITY_SPACE;
} else {
if (termios->c_cflag & PARODD)
- cval |= XUARTPS_MR_PARITY_ODD;
+ cval |= CDNS_UART_MR_PARITY_ODD;
else
- cval |= XUARTPS_MR_PARITY_EVEN;
+ cval |= CDNS_UART_MR_PARITY_EVEN;
}
} else {
- cval |= XUARTPS_MR_PARITY_NONE;
+ cval |= CDNS_UART_MR_PARITY_NONE;
}
cval |= mode_reg & 1;
- xuartps_writel(cval, XUARTPS_MR_OFFSET);
+ cdns_uart_writel(cval, CDNS_UART_MR_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
/**
- * xuartps_startup - Called when an application opens a xuartps port
+ * cdns_uart_startup - Called when an application opens a cdns_uart port
* @port: Handle to the uart port structure
*
- * Returns 0 on success, negative error otherwise
- **/
-static int xuartps_startup(struct uart_port *port)
+ * Return: 0 on success, negative errno otherwise
+ */
+static int cdns_uart_startup(struct uart_port *port)
{
unsigned int retval = 0, status = 0;
- retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME,
+ retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,
(void *)port);
if (retval)
return retval;
/* Disable the TX and RX */
- xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
- XUARTPS_CR_OFFSET);
+ cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
+ CDNS_UART_CR_OFFSET);
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars.
*/
- xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST,
- XUARTPS_CR_OFFSET);
+ cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
+ CDNS_UART_CR_OFFSET);
- status = xuartps_readl(XUARTPS_CR_OFFSET);
+ status = cdns_uart_readl(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.
*/
- xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
- | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN |
- XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET);
+ cdns_uart_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);
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity.
*/
- xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT
- | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT,
- XUARTPS_MR_OFFSET);
+ cdns_uart_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);
/*
* Set the RX FIFO Trigger level to use most of the FIFO, but it
* can be tuned with a module parameter
*/
- xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET);
+ cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET);
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
- xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
+ cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
/* Clear out any pending interrupts before enabling them */
- xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET);
+ cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET),
+ CDNS_UART_ISR_OFFSET);
/* Set the Interrupt Registers with desired interrupts */
- xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
- XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
- XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
+ cdns_uart_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);
return retval;
}
/**
- * xuartps_shutdown - Called when an application closes a xuartps port
+ * cdns_uart_shutdown - Called when an application closes a cdns_uart port
* @port: Handle to the uart port structure
- *
- **/
-static void xuartps_shutdown(struct uart_port *port)
+ */
+static void cdns_uart_shutdown(struct uart_port *port)
{
int status;
/* Disable interrupts */
- status = xuartps_readl(XUARTPS_IMR_OFFSET);
- xuartps_writel(status, XUARTPS_IDR_OFFSET);
+ status = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
+ cdns_uart_writel(status, CDNS_UART_IDR_OFFSET);
/* Disable the TX and RX */
- xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
- XUARTPS_CR_OFFSET);
+ cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
+ CDNS_UART_CR_OFFSET);
free_irq(port->irq, port);
}
/**
- * xuartps_type - Set UART type to xuartps port
+ * cdns_uart_type - Set UART type to cdns_uart port
* @port: Handle to the uart port structure
*
- * Returns string on success, NULL otherwise
- **/
-static const char *xuartps_type(struct uart_port *port)
+ * Return: string on success, NULL otherwise
+ */
+static const char *cdns_uart_type(struct uart_port *port)
{
- return port->type == PORT_XUARTPS ? XUARTPS_NAME : NULL;
+ return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL;
}
/**
- * xuartps_verify_port - Verify the port params
+ * cdns_uart_verify_port - Verify the port params
* @port: Handle to the uart port structure
* @ser: Handle to the structure whose members are compared
*
- * Returns 0 if success otherwise -EINVAL
- **/
-static int xuartps_verify_port(struct uart_port *port,
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int cdns_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS)
@@ -875,187 +854,164 @@ static int xuartps_verify_port(struct uart_port *port,
}
/**
- * xuartps_request_port - Claim the memory region attached to xuartps port,
- * called when the driver adds a xuartps port via
+ * cdns_uart_request_port - Claim the memory region attached to cdns_uart port,
+ * called when the driver adds a cdns_uart port via
* uart_add_one_port()
* @port: Handle to the uart port structure
*
- * Returns 0, -ENOMEM if request fails
- **/
-static int xuartps_request_port(struct uart_port *port)
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int cdns_uart_request_port(struct uart_port *port)
{
- if (!request_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE,
- XUARTPS_NAME)) {
+ if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE,
+ CDNS_UART_NAME)) {
return -ENOMEM;
}
- port->membase = ioremap(port->mapbase, XUARTPS_REGISTER_SPACE);
+ port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE);
if (!port->membase) {
dev_err(port->dev, "Unable to map registers\n");
- release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE);
+ release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
return -ENOMEM;
}
return 0;
}
/**
- * xuartps_release_port - Release the memory region attached to a xuartps
- * port, called when the driver removes a xuartps
- * port via uart_remove_one_port().
+ * cdns_uart_release_port - Release UART port
* @port: Handle to the uart port structure
*
- **/
-static void xuartps_release_port(struct uart_port *port)
+ * Release the memory region attached to a cdns_uart port. Called when the
+ * driver removes a cdns_uart port via uart_remove_one_port().
+ */
+static void cdns_uart_release_port(struct uart_port *port)
{
- release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE);
+ release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
iounmap(port->membase);
port->membase = NULL;
}
/**
- * xuartps_config_port - Configure xuartps, called when the driver adds a
- * xuartps port
+ * cdns_uart_config_port - Configure UART port
* @port: Handle to the uart port structure
* @flags: If any
- *
- **/
-static void xuartps_config_port(struct uart_port *port, int flags)
+ */
+static void cdns_uart_config_port(struct uart_port *port, int flags)
{
- if (flags & UART_CONFIG_TYPE && xuartps_request_port(port) == 0)
+ if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0)
port->type = PORT_XUARTPS;
}
/**
- * xuartps_get_mctrl - Get the modem control state
- *
+ * cdns_uart_get_mctrl - Get the modem control state
* @port: Handle to the uart port structure
*
- * Returns the modem control state
- *
- **/
-static unsigned int xuartps_get_mctrl(struct uart_port *port)
+ * Return: the modem control state
+ */
+static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
-static void xuartps_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /* N/A */
-}
-
-static void xuartps_enable_ms(struct uart_port *port)
+static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* N/A */
}
#ifdef CONFIG_CONSOLE_POLL
-static int xuartps_poll_get_char(struct uart_port *port)
+static int cdns_uart_poll_get_char(struct uart_port *port)
{
u32 imr;
int c;
/* Disable all interrupts */
- imr = xuartps_readl(XUARTPS_IMR_OFFSET);
- xuartps_writel(imr, XUARTPS_IDR_OFFSET);
+ imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
+ cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET);
/* Check if FIFO is empty */
- if (xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)
+ if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
c = NO_POLL_CHAR;
else /* Read a character */
- c = (unsigned char) xuartps_readl(XUARTPS_FIFO_OFFSET);
+ c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
/* Enable interrupts */
- xuartps_writel(imr, XUARTPS_IER_OFFSET);
+ cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
return c;
}
-static void xuartps_poll_put_char(struct uart_port *port, unsigned char c)
+static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
u32 imr;
/* Disable all interrupts */
- imr = xuartps_readl(XUARTPS_IMR_OFFSET);
- xuartps_writel(imr, XUARTPS_IDR_OFFSET);
+ imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
+ cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET);
/* Wait until FIFO is empty */
- while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY))
+ while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Write a character */
- xuartps_writel(c, XUARTPS_FIFO_OFFSET);
+ cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET);
/* Wait until FIFO is empty */
- while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY))
+ while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY))
cpu_relax();
/* Enable interrupts */
- xuartps_writel(imr, XUARTPS_IER_OFFSET);
+ cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
return;
}
#endif
-/** The UART operations structure
- */
-static struct uart_ops xuartps_ops = {
- .set_mctrl = xuartps_set_mctrl,
- .get_mctrl = xuartps_get_mctrl,
- .enable_ms = xuartps_enable_ms,
-
- .start_tx = xuartps_start_tx, /* Start transmitting */
- .stop_tx = xuartps_stop_tx, /* Stop transmission */
- .stop_rx = xuartps_stop_rx, /* Stop reception */
- .tx_empty = xuartps_tx_empty, /* Transmitter busy? */
- .break_ctl = xuartps_break_ctl, /* Start/stop
- * transmitting break
- */
- .set_termios = xuartps_set_termios, /* Set termios */
- .startup = xuartps_startup, /* App opens xuartps */
- .shutdown = xuartps_shutdown, /* App closes xuartps */
- .type = xuartps_type, /* Set UART type */
- .verify_port = xuartps_verify_port, /* Verification of port
- * params
- */
- .request_port = xuartps_request_port, /* Claim resources
- * associated with a
- * xuartps port
- */
- .release_port = xuartps_release_port, /* Release resources
- * associated with a
- * xuartps port
- */
- .config_port = xuartps_config_port, /* Configure when driver
- * adds a xuartps port
- */
+static struct uart_ops cdns_uart_ops = {
+ .set_mctrl = cdns_uart_set_mctrl,
+ .get_mctrl = cdns_uart_get_mctrl,
+ .start_tx = cdns_uart_start_tx,
+ .stop_tx = cdns_uart_stop_tx,
+ .stop_rx = cdns_uart_stop_rx,
+ .tx_empty = cdns_uart_tx_empty,
+ .break_ctl = cdns_uart_break_ctl,
+ .set_termios = cdns_uart_set_termios,
+ .startup = cdns_uart_startup,
+ .shutdown = cdns_uart_shutdown,
+ .type = cdns_uart_type,
+ .verify_port = cdns_uart_verify_port,
+ .request_port = cdns_uart_request_port,
+ .release_port = cdns_uart_release_port,
+ .config_port = cdns_uart_config_port,
#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = xuartps_poll_get_char,
- .poll_put_char = xuartps_poll_put_char,
+ .poll_get_char = cdns_uart_poll_get_char,
+ .poll_put_char = cdns_uart_poll_put_char,
#endif
};
-static struct uart_port xuartps_port[2];
+static struct uart_port cdns_uart_port[2];
/**
- * xuartps_get_port - Configure the port from the platform device resource
- * info
+ * cdns_uart_get_port - Configure the port from platform device resource info
+ * @id: Port id
*
- * Returns a pointer to a uart_port or NULL for failure
- **/
-static struct uart_port *xuartps_get_port(void)
+ * Return: a pointer to a uart_port or NULL for failure
+ */
+static struct uart_port *cdns_uart_get_port(int id)
{
struct uart_port *port;
- int id;
- /* Find the next unused port */
- for (id = 0; id < XUARTPS_NR_PORTS; id++)
- if (xuartps_port[id].mapbase == 0)
- break;
+ /* Try the given port id if failed use default method */
+ if (cdns_uart_port[id].mapbase != 0) {
+ /* Find the next unused port */
+ for (id = 0; id < CDNS_UART_NR_PORTS; id++)
+ if (cdns_uart_port[id].mapbase == 0)
+ break;
+ }
- if (id >= XUARTPS_NR_PORTS)
+ if (id >= CDNS_UART_NR_PORTS)
return NULL;
- port = &xuartps_port[id];
+ port = &cdns_uart_port[id];
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
@@ -1065,50 +1021,46 @@ static struct uart_port *xuartps_get_port(void)
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
port->flags = UPF_BOOT_AUTOCONF;
- port->ops = &xuartps_ops;
- port->fifosize = XUARTPS_FIFO_SIZE;
+ port->ops = &cdns_uart_ops;
+ port->fifosize = CDNS_UART_FIFO_SIZE;
port->line = id;
port->dev = NULL;
return port;
}
-/*-----------------------Console driver operations--------------------------*/
-
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/**
- * xuartps_console_wait_tx - Wait for the TX to be full
+ * cdns_uart_console_wait_tx - Wait for the TX to be full
* @port: Handle to the uart port structure
- *
- **/
-static void xuartps_console_wait_tx(struct uart_port *port)
+ */
+static void cdns_uart_console_wait_tx(struct uart_port *port)
{
- while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)
- != XUARTPS_SR_TXEMPTY)
+ while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)
+ != CDNS_UART_SR_TXEMPTY)
barrier();
}
/**
- * xuartps_console_putchar - write the character to the FIFO buffer
+ * cdns_uart_console_putchar - write the character to the FIFO buffer
* @port: Handle to the uart port structure
* @ch: Character to be written
- *
- **/
-static void xuartps_console_putchar(struct uart_port *port, int ch)
+ */
+static void cdns_uart_console_putchar(struct uart_port *port, int ch)
{
- xuartps_console_wait_tx(port);
- xuartps_writel(ch, XUARTPS_FIFO_OFFSET);
+ cdns_uart_console_wait_tx(port);
+ cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET);
}
/**
- * xuartps_console_write - perform write operation
- * @port: Handle to the uart port structure
+ * cdns_uart_console_write - perform write operation
+ * @co: Console handle
* @s: Pointer to character array
* @count: No of characters
- **/
-static void xuartps_console_write(struct console *co, const char *s,
+ */
+static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &xuartps_port[co->index];
+ struct uart_port *port = &cdns_uart_port[co->index];
unsigned long flags;
unsigned int imr, ctrl;
int locked = 1;
@@ -1119,49 +1071,45 @@ static void xuartps_console_write(struct console *co, const char *s,
spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */
- imr = xuartps_readl(XUARTPS_IMR_OFFSET);
- xuartps_writel(imr, XUARTPS_IDR_OFFSET);
+ imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET);
+ cdns_uart_writel(imr, 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 = xuartps_readl(XUARTPS_CR_OFFSET);
- xuartps_writel((ctrl & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN,
- XUARTPS_CR_OFFSET);
+ 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);
- uart_console_write(port, s, count, xuartps_console_putchar);
- xuartps_console_wait_tx(port);
+ uart_console_write(port, s, count, cdns_uart_console_putchar);
+ cdns_uart_console_wait_tx(port);
- xuartps_writel(ctrl, XUARTPS_CR_OFFSET);
+ cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET);
- /* restore interrupt state, it seems like there may be a h/w bug
- * in that the interrupt enable register should not need to be
- * written based on the data sheet
- */
- xuartps_writel(~imr, XUARTPS_IDR_OFFSET);
- xuartps_writel(imr, XUARTPS_IER_OFFSET);
+ /* restore interrupt state */
+ cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
}
/**
- * xuartps_console_setup - Initialize the uart to default config
+ * cdns_uart_console_setup - Initialize the uart to default config
* @co: Console handle
* @options: Initial settings of uart
*
- * Returns 0, -ENODEV if no device
- **/
-static int __init xuartps_console_setup(struct console *co, char *options)
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int __init cdns_uart_console_setup(struct console *co, char *options)
{
- struct uart_port *port = &xuartps_port[co->index];
+ struct uart_port *port = &cdns_uart_port[co->index];
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
- if (co->index < 0 || co->index >= XUARTPS_NR_PORTS)
+ if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS)
return -EINVAL;
if (!port->mapbase) {
@@ -1175,55 +1123,53 @@ static int __init xuartps_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-static struct uart_driver xuartps_uart_driver;
+static struct uart_driver cdns_uart_uart_driver;
-static struct console xuartps_console = {
- .name = XUARTPS_TTY_NAME,
- .write = xuartps_console_write,
+static struct console cdns_uart_console = {
+ .name = CDNS_UART_TTY_NAME,
+ .write = cdns_uart_console_write,
.device = uart_console_device,
- .setup = xuartps_console_setup,
+ .setup = cdns_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
- .data = &xuartps_uart_driver,
+ .data = &cdns_uart_uart_driver,
};
/**
- * xuartps_console_init - Initialization call
+ * cdns_uart_console_init - Initialization call
*
- * Returns 0 on success, negative error otherwise
- **/
-static int __init xuartps_console_init(void)
+ * Return: 0 on success, negative errno otherwise
+ */
+static int __init cdns_uart_console_init(void)
{
- register_console(&xuartps_console);
+ register_console(&cdns_uart_console);
return 0;
}
-console_initcall(xuartps_console_init);
+console_initcall(cdns_uart_console_init);
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
-/** Structure Definitions
- */
-static struct uart_driver xuartps_uart_driver = {
- .owner = THIS_MODULE, /* Owner */
- .driver_name = XUARTPS_NAME, /* Driver name */
- .dev_name = XUARTPS_TTY_NAME, /* Node name */
- .major = XUARTPS_MAJOR, /* Major number */
- .minor = XUARTPS_MINOR, /* Minor number */
- .nr = XUARTPS_NR_PORTS, /* Number of UART ports */
+static struct uart_driver cdns_uart_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = CDNS_UART_NAME,
+ .dev_name = CDNS_UART_TTY_NAME,
+ .major = CDNS_UART_MAJOR,
+ .minor = CDNS_UART_MINOR,
+ .nr = CDNS_UART_NR_PORTS,
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
- .cons = &xuartps_console, /* Console */
+ .cons = &cdns_uart_console,
#endif
};
#ifdef CONFIG_PM_SLEEP
/**
- * xuartps_suspend - suspend event
+ * cdns_uart_suspend - suspend event
* @device: Pointer to the device structure
*
- * Returns 0
+ * Return: 0
*/
-static int xuartps_suspend(struct device *device)
+static int cdns_uart_suspend(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
struct tty_struct *tty;
@@ -1242,23 +1188,24 @@ static int xuartps_suspend(struct device *device)
* Call the API provided in serial_core.c file which handles
* the suspend.
*/
- uart_suspend_port(&xuartps_uart_driver, port);
+ uart_suspend_port(&cdns_uart_uart_driver, port);
if (console_suspend_enabled && !may_wake) {
- struct xuartps *xuartps = port->private_data;
+ struct cdns_uart *cdns_uart = port->private_data;
- clk_disable(xuartps->refclk);
- clk_disable(xuartps->aperclk);
+ clk_disable(cdns_uart->uartclk);
+ clk_disable(cdns_uart->pclk);
} else {
unsigned long flags = 0;
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
- while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY))
- xuartps_readl(XUARTPS_FIFO_OFFSET);
+ while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_RXEMPTY))
+ cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
/* set RX trigger level to 1 */
- xuartps_writel(1, XUARTPS_RXWM_OFFSET);
+ cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET);
/* disable RX timeout interrups */
- xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1266,12 +1213,12 @@ static int xuartps_suspend(struct device *device)
}
/**
- * xuartps_resume - Resume after a previous suspend
+ * cdns_uart_resume - Resume after a previous suspend
* @device: Pointer to the device structure
*
- * Returns 0
+ * Return: 0
*/
-static int xuartps_resume(struct device *device)
+static int cdns_uart_resume(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
unsigned long flags = 0;
@@ -1289,87 +1236,95 @@ static int xuartps_resume(struct device *device)
}
if (console_suspend_enabled && !may_wake) {
- struct xuartps *xuartps = port->private_data;
+ struct cdns_uart *cdns_uart = port->private_data;
- clk_enable(xuartps->aperclk);
- clk_enable(xuartps->refclk);
+ clk_enable(cdns_uart->pclk);
+ clk_enable(cdns_uart->uartclk);
spin_lock_irqsave(&port->lock, flags);
/* Set TX/RX Reset */
- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
- (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
- XUARTPS_CR_OFFSET);
- while (xuartps_readl(XUARTPS_CR_OFFSET) &
- (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST))
+ ctrl_reg = cdns_uart_readl(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) &
+ (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* restore rx timeout value */
- xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
+ cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);
/* Enable Tx/Rx */
- ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
- xuartps_writel(
- (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
- (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
- XUARTPS_CR_OFFSET);
+ ctrl_reg = cdns_uart_readl(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);
spin_unlock_irqrestore(&port->lock, flags);
} else {
spin_lock_irqsave(&port->lock, flags);
/* restore original rx trigger level */
- xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET);
+ cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET);
/* enable RX timeout interrupt */
- xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
+ cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET);
spin_unlock_irqrestore(&port->lock, flags);
}
- return uart_resume_port(&xuartps_uart_driver, port);
+ return uart_resume_port(&cdns_uart_uart_driver, port);
}
#endif /* ! CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(xuartps_dev_pm_ops, xuartps_suspend, xuartps_resume);
+static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
+ cdns_uart_resume);
-/* ---------------------------------------------------------------------
- * Platform bus binding
- */
/**
- * xuartps_probe - Platform driver probe
+ * cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
*
- * Returns 0 on success, negative error otherwise
- **/
-static int xuartps_probe(struct platform_device *pdev)
+ * Return: 0 on success, negative errno otherwise
+ */
+static int cdns_uart_probe(struct platform_device *pdev)
{
- int rc;
+ int rc, id;
struct uart_port *port;
struct resource *res, *res2;
- struct xuartps *xuartps_data;
+ struct cdns_uart *cdns_uart_data;
- xuartps_data = devm_kzalloc(&pdev->dev, sizeof(*xuartps_data),
+ cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL);
- if (!xuartps_data)
+ if (!cdns_uart_data)
return -ENOMEM;
- xuartps_data->aperclk = devm_clk_get(&pdev->dev, "aper_clk");
- if (IS_ERR(xuartps_data->aperclk)) {
- dev_err(&pdev->dev, "aper_clk clock not found.\n");
- return PTR_ERR(xuartps_data->aperclk);
+ cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(cdns_uart_data->pclk)) {
+ cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
+ if (!IS_ERR(cdns_uart_data->pclk))
+ dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n");
}
- xuartps_data->refclk = devm_clk_get(&pdev->dev, "ref_clk");
- if (IS_ERR(xuartps_data->refclk)) {
- dev_err(&pdev->dev, "ref_clk clock not found.\n");
- return PTR_ERR(xuartps_data->refclk);
+ if (IS_ERR(cdns_uart_data->pclk)) {
+ dev_err(&pdev->dev, "pclk clock not found.\n");
+ return PTR_ERR(cdns_uart_data->pclk);
}
- rc = clk_prepare_enable(xuartps_data->aperclk);
+ cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
+ if (IS_ERR(cdns_uart_data->uartclk)) {
+ cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (!IS_ERR(cdns_uart_data->uartclk))
+ dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
+ }
+ if (IS_ERR(cdns_uart_data->uartclk)) {
+ dev_err(&pdev->dev, "uart_clk clock not found.\n");
+ return PTR_ERR(cdns_uart_data->uartclk);
+ }
+
+ rc = clk_prepare_enable(cdns_uart_data->pclk);
if (rc) {
- dev_err(&pdev->dev, "Unable to enable APER clock.\n");
+ dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
return rc;
}
- rc = clk_prepare_enable(xuartps_data->refclk);
+ rc = clk_prepare_enable(cdns_uart_data->uartclk);
if (rc) {
dev_err(&pdev->dev, "Unable to enable device clock.\n");
- goto err_out_clk_dis_aper;
+ goto err_out_clk_dis_pclk;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1385,15 +1340,19 @@ static int xuartps_probe(struct platform_device *pdev)
}
#ifdef CONFIG_COMMON_CLK
- xuartps_data->clk_rate_change_nb.notifier_call =
- xuartps_clk_notifier_cb;
- if (clk_notifier_register(xuartps_data->refclk,
- &xuartps_data->clk_rate_change_nb))
+ cdns_uart_data->clk_rate_change_nb.notifier_call =
+ cdns_uart_clk_notifier_cb;
+ if (clk_notifier_register(cdns_uart_data->uartclk,
+ &cdns_uart_data->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
#endif
+ /* Look for a serialN alias */
+ id = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (id < 0)
+ id = 0;
/* Initialize the port structure */
- port = xuartps_get_port();
+ port = cdns_uart_get_port(id);
if (!port) {
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
@@ -1407,11 +1366,11 @@ static int xuartps_probe(struct platform_device *pdev)
port->mapbase = res->start;
port->irq = res2->start;
port->dev = &pdev->dev;
- port->uartclk = clk_get_rate(xuartps_data->refclk);
- port->private_data = xuartps_data;
- xuartps_data->port = port;
+ port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
+ port->private_data = cdns_uart_data;
+ cdns_uart_data->port = port;
platform_set_drvdata(pdev, port);
- rc = uart_add_one_port(&xuartps_uart_driver, port);
+ rc = uart_add_one_port(&cdns_uart_uart_driver, port);
if (rc) {
dev_err(&pdev->dev,
"uart_add_one_port() failed; err=%i\n", rc);
@@ -1422,103 +1381,89 @@ static int xuartps_probe(struct platform_device *pdev)
err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
- clk_notifier_unregister(xuartps_data->refclk,
- &xuartps_data->clk_rate_change_nb);
+ clk_notifier_unregister(cdns_uart_data->uartclk,
+ &cdns_uart_data->clk_rate_change_nb);
#endif
err_out_clk_disable:
- clk_disable_unprepare(xuartps_data->refclk);
-err_out_clk_dis_aper:
- clk_disable_unprepare(xuartps_data->aperclk);
+ clk_disable_unprepare(cdns_uart_data->uartclk);
+err_out_clk_dis_pclk:
+ clk_disable_unprepare(cdns_uart_data->pclk);
return rc;
}
/**
- * xuartps_remove - called when the platform driver is unregistered
+ * cdns_uart_remove - called when the platform driver is unregistered
* @pdev: Pointer to the platform device structure
*
- * Returns 0 on success, negative error otherwise
- **/
-static int xuartps_remove(struct platform_device *pdev)
+ * Return: 0 on success, negative errno otherwise
+ */
+static int cdns_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
- struct xuartps *xuartps_data = port->private_data;
+ struct cdns_uart *cdns_uart_data = port->private_data;
int rc;
- /* Remove the xuartps port from the serial core */
+ /* Remove the cdns_uart port from the serial core */
#ifdef CONFIG_COMMON_CLK
- clk_notifier_unregister(xuartps_data->refclk,
- &xuartps_data->clk_rate_change_nb);
+ clk_notifier_unregister(cdns_uart_data->uartclk,
+ &cdns_uart_data->clk_rate_change_nb);
#endif
- rc = uart_remove_one_port(&xuartps_uart_driver, port);
+ rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
port->mapbase = 0;
- clk_disable_unprepare(xuartps_data->refclk);
- clk_disable_unprepare(xuartps_data->aperclk);
+ clk_disable_unprepare(cdns_uart_data->uartclk);
+ clk_disable_unprepare(cdns_uart_data->pclk);
return rc;
}
/* Match table for of_platform binding */
-static struct of_device_id xuartps_of_match[] = {
+static struct of_device_id cdns_uart_of_match[] = {
{ .compatible = "xlnx,xuartps", },
+ { .compatible = "cdns,uart-r1p8", },
{}
};
-MODULE_DEVICE_TABLE(of, xuartps_of_match);
+MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
-static struct platform_driver xuartps_platform_driver = {
- .probe = xuartps_probe, /* Probe method */
- .remove = xuartps_remove, /* Detach method */
+static struct platform_driver cdns_uart_platform_driver = {
+ .probe = cdns_uart_probe,
+ .remove = cdns_uart_remove,
.driver = {
.owner = THIS_MODULE,
- .name = XUARTPS_NAME, /* Driver name */
- .of_match_table = xuartps_of_match,
- .pm = &xuartps_dev_pm_ops,
+ .name = CDNS_UART_NAME,
+ .of_match_table = cdns_uart_of_match,
+ .pm = &cdns_uart_dev_pm_ops,
},
};
-/* ---------------------------------------------------------------------
- * Module Init and Exit
- */
-/**
- * xuartps_init - Initial driver registration call
- *
- * Returns whether the registration was successful or not
- **/
-static int __init xuartps_init(void)
+static int __init cdns_uart_init(void)
{
int retval = 0;
- /* Register the xuartps driver with the serial core */
- retval = uart_register_driver(&xuartps_uart_driver);
+ /* Register the cdns_uart driver with the serial core */
+ retval = uart_register_driver(&cdns_uart_uart_driver);
if (retval)
return retval;
/* Register the platform driver */
- retval = platform_driver_register(&xuartps_platform_driver);
+ retval = platform_driver_register(&cdns_uart_platform_driver);
if (retval)
- uart_unregister_driver(&xuartps_uart_driver);
+ uart_unregister_driver(&cdns_uart_uart_driver);
return retval;
}
-/**
- * xuartps_exit - Driver unregistration call
- **/
-static void __exit xuartps_exit(void)
+static void __exit cdns_uart_exit(void)
{
- /* The order of unregistration is important. Unregister the
- * UART driver before the platform driver crashes the system.
- */
-
/* Unregister the platform driver */
- platform_driver_unregister(&xuartps_platform_driver);
+ platform_driver_unregister(&cdns_uart_platform_driver);
- /* Unregister the xuartps driver */
- uart_unregister_driver(&xuartps_uart_driver);
+ /* Unregister the cdns_uart driver */
+ uart_unregister_driver(&cdns_uart_uart_driver);
}
-module_init(xuartps_init);
-module_exit(xuartps_exit);
+module_init(cdns_uart_init);
+module_exit(cdns_uart_exit);
-MODULE_DESCRIPTION("Driver for PS UART");
+MODULE_DESCRIPTION("Driver for Cadence UART");
MODULE_AUTHOR("Xilinx Inc.");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 6a169877109b..2b65bb7ffb8a 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -923,7 +923,7 @@ static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
uport->read_status_mask = Rx_OVR;
if (termios->c_iflag & INPCK)
uport->read_status_mask |= FRM_ERR | PAR_ERR;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
uport->read_status_mask |= Rx_BRK;
uport->ignore_status_mask = 0;
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index d48e040cd8c5..b7991707ffc0 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3267,7 +3267,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
DECLARE_WAITQUEUE(wait, current);
int retval;
bool do_clocal = false;
- bool extra_count = false;
unsigned long flags;
int dcd;
struct tty_port *port = &info->port;
@@ -3300,10 +3299,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
__FILE__,__LINE__, tty->driver->name, port->count );
spin_lock_irqsave(&info->irq_spinlock, flags);
- if (!tty_hung_up_p(filp)) {
- extra_count = true;
- port->count--;
- }
+ port->count--;
spin_unlock_irqrestore(&info->irq_spinlock, flags);
port->blocked_open++;
@@ -3342,7 +3338,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
remove_wait_queue(&port->open_wait, &wait);
/* FIXME: Racy on hangup during close wait */
- if (extra_count)
+ if (!tty_hung_up_p(filp))
port->count++;
port->blocked_open--;
@@ -3403,7 +3399,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
__FILE__,__LINE__,tty->driver->name, info->port.count);
/* If port is closing, signal caller to try again */
- if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+ if (info->port.flags & ASYNC_CLOSING){
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index c359a91f7346..0e8c39b6ccd4 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -673,7 +673,7 @@ static int open(struct tty_struct *tty, struct file *filp)
DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count));
/* If port is closing, signal caller to try again */
- if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+ if (info->port.flags & ASYNC_CLOSING){
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
@@ -3273,7 +3273,6 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
DECLARE_WAITQUEUE(wait, current);
int retval;
bool do_clocal = false;
- bool extra_count = false;
unsigned long flags;
int cd;
struct tty_port *port = &info->port;
@@ -3300,10 +3299,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
add_wait_queue(&port->open_wait, &wait);
spin_lock_irqsave(&info->lock, flags);
- if (!tty_hung_up_p(filp)) {
- extra_count = true;
- port->count--;
- }
+ port->count--;
spin_unlock_irqrestore(&info->lock, flags);
port->blocked_open++;
@@ -3338,7 +3334,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
- if (extra_count)
+ if (!tty_hung_up_p(filp))
port->count++;
port->blocked_open--;
@@ -3387,12 +3383,11 @@ static int alloc_desc(struct slgt_info *info)
unsigned int pbufs;
/* allocate memory to hold descriptor lists */
- info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr);
+ info->bufs = pci_zalloc_consistent(info->pdev, DESC_LIST_SIZE,
+ &info->bufs_dma_addr);
if (info->bufs == NULL)
return -ENOMEM;
- memset(info->bufs, 0, DESC_LIST_SIZE);
-
info->rbufs = (struct slgt_desc*)info->bufs;
info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count;
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 53ba8537de8d..c3f90910fed9 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -753,7 +753,7 @@ static int open(struct tty_struct *tty, struct file *filp)
__FILE__,__LINE__,tty->driver->name, info->port.count);
/* If port is closing, signal caller to try again */
- if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+ if (info->port.flags & ASYNC_CLOSING){
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
@@ -3288,7 +3288,6 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
DECLARE_WAITQUEUE(wait, current);
int retval;
bool do_clocal = false;
- bool extra_count = false;
unsigned long flags;
int cd;
struct tty_port *port = &info->port;
@@ -3322,10 +3321,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
__FILE__,__LINE__, tty->driver->name, port->count );
spin_lock_irqsave(&info->lock, flags);
- if (!tty_hung_up_p(filp)) {
- extra_count = true;
- port->count--;
- }
+ port->count--;
spin_unlock_irqrestore(&info->lock, flags);
port->blocked_open++;
@@ -3362,8 +3358,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
-
- if (extra_count)
+ if (!tty_hung_up_p(filp))
port->count++;
port->blocked_open--;
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index ce396ecdf412..42bad18c66c9 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -46,6 +46,7 @@
#include <linux/jiffies.h>
#include <linux/syscalls.h>
#include <linux/of.h>
+#include <linux/rcupdate.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -88,7 +89,7 @@ static void sysrq_handle_loglevel(int key)
int i;
i = key - '0';
- console_loglevel = 7;
+ console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
printk("Loglevel set to %d\n", i);
console_loglevel = i;
}
@@ -343,7 +344,7 @@ static void send_sig_all(int sig)
static void sysrq_handle_term(int key)
{
send_sig_all(SIGTERM);
- console_loglevel = 8;
+ console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
static struct sysrq_key_op sysrq_term_op = {
.handler = sysrq_handle_term,
@@ -354,7 +355,7 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(struct work_struct *ignored)
{
- out_of_memory(node_zonelist(first_online_node, GFP_KERNEL), GFP_KERNEL,
+ out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), GFP_KERNEL,
0, NULL, true);
}
@@ -387,7 +388,7 @@ static struct sysrq_key_op sysrq_thaw_op = {
static void sysrq_handle_kill(int key)
{
send_sig_all(SIGKILL);
- console_loglevel = 8;
+ console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
static struct sysrq_key_op sysrq_kill_op = {
.handler = sysrq_handle_kill,
@@ -510,9 +511,9 @@ void __handle_sysrq(int key, bool check_mask)
struct sysrq_key_op *op_p;
int orig_log_level;
int i;
- unsigned long flags;
- spin_lock_irqsave(&sysrq_key_table_lock, flags);
+ rcu_sysrq_start();
+ rcu_read_lock();
/*
* Raise the apparent loglevel to maximum so that the sysrq header
* is shown to provide the user with positive feedback. We do not
@@ -520,7 +521,7 @@ void __handle_sysrq(int key, bool check_mask)
* routing in the consumers of /proc/kmsg.
*/
orig_log_level = console_loglevel;
- console_loglevel = 7;
+ console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
printk(KERN_INFO "SysRq : ");
op_p = __sysrq_get_key_op(key);
@@ -554,7 +555,8 @@ void __handle_sysrq(int key, bool check_mask)
printk("\n");
console_loglevel = orig_log_level;
}
- spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+ rcu_read_unlock();
+ rcu_sysrq_end();
}
void handle_sysrq(int key)
@@ -1043,16 +1045,23 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p)
{
int retval;
- unsigned long flags;
- spin_lock_irqsave(&sysrq_key_table_lock, flags);
+ spin_lock(&sysrq_key_table_lock);
if (__sysrq_get_key_op(key) == remove_op_p) {
__sysrq_put_key_op(key, insert_op_p);
retval = 0;
} else {
retval = -1;
}
- spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+ spin_unlock(&sysrq_key_table_lock);
+
+ /*
+ * A concurrent __handle_sysrq either got the old op or the new op.
+ * Wait for it to go away before returning, so the code for an old
+ * op is not freed (eg. on module unload) while it is in use.
+ */
+ synchronize_rcu();
+
return retval;
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 34110719fe03..8fbad3410c75 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -157,20 +157,6 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
/**
- * alloc_tty_struct - allocate a tty object
- *
- * Return a new empty tty structure. The data fields have not
- * been initialized in any way but has been zeroed
- *
- * Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
- return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
* free_tty_struct - free a disused tty
* @tty: tty struct to free
*
@@ -688,7 +674,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
for (n = 0; n < closecount; n++)
tty->ops->close(tty, cons_filp);
} else if (tty->ops->hangup)
- (tty->ops->hangup)(tty);
+ tty->ops->hangup(tty);
/*
* We don't want to have driver/ldisc interactions beyond
* the ones we did here. The driver layer expects no
@@ -1455,12 +1441,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
if (!try_module_get(driver->owner))
return ERR_PTR(-ENODEV);
- tty = alloc_tty_struct();
+ tty = alloc_tty_struct(driver, idx);
if (!tty) {
retval = -ENOMEM;
goto err_module_put;
}
- initialize_tty_struct(tty, driver, idx);
tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
@@ -3003,19 +2988,21 @@ static struct device *tty_get_device(struct tty_struct *tty)
/**
- * initialize_tty_struct
- * @tty: tty to initialize
+ * alloc_tty_struct
*
- * This subroutine initializes a tty structure that has been newly
- * allocated.
+ * This subroutine allocates and initializes a tty structure.
*
- * Locking: none - tty in question must not be exposed at this point
+ * Locking: none - tty in question is not exposed at this point
*/
-void initialize_tty_struct(struct tty_struct *tty,
- struct tty_driver *driver, int idx)
+struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
{
- memset(tty, 0, sizeof(struct tty_struct));
+ struct tty_struct *tty;
+
+ tty = kzalloc(sizeof(*tty), GFP_KERNEL);
+ if (!tty)
+ return NULL;
+
kref_init(&tty->kref);
tty->magic = TTY_MAGIC;
tty_ldisc_init(tty);
@@ -3039,6 +3026,8 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->index = idx;
tty_line_name(driver, idx, tty->name);
tty->dev = tty_get_device(tty);
+
+ return tty;
}
/**
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 3f746c8eb0dd..1b9335796da4 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -227,6 +227,8 @@ out:
*
* Perform port level tty hangup flag and count changes. Drop the tty
* reference.
+ *
+ * Caller holds tty lock.
*/
void tty_port_hangup(struct tty_port *port)
@@ -348,6 +350,11 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* do carrier detect and the dtr_rts method if it supports software
* management of these lines. Note that the dtr/rts raise is done each
* iteration as a hangup may have previously dropped them while we wait.
+ *
+ * Caller holds tty lock.
+ *
+ * NB: May drop and reacquire tty lock when blocking, so tty and tty_port
+ * may have changed state (eg., may have been hung up).
*/
int tty_port_block_til_ready(struct tty_port *port,
@@ -358,7 +365,7 @@ int tty_port_block_til_ready(struct tty_port *port,
DEFINE_WAIT(wait);
/* block if port is in the process of being closed */
- if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+ if (port->flags & ASYNC_CLOSING) {
wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
@@ -392,8 +399,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count--;
+ port->count--;
port->blocked_open++;
spin_unlock_irqrestore(&port->lock, flags);
@@ -458,6 +464,10 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
schedule_timeout_interruptible(timeout);
}
+/* Caller holds tty lock.
+ * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close())
+ * so tty and tty port may have changed state (but not hung up or reopened).
+ */
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
@@ -486,9 +496,10 @@ int tty_port_close_start(struct tty_port *port,
return 0;
}
set_bit(ASYNCB_CLOSING, &port->flags);
- tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
+ tty->closing = 1;
+
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
/* Don't block on a stalled port, just pull the chain */
if (tty->flow_stopped)
@@ -506,13 +517,15 @@ int tty_port_close_start(struct tty_port *port,
}
EXPORT_SYMBOL(tty_port_close_start);
+/* Caller holds tty lock */
void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
+ spin_lock_irqsave(&port->lock, flags);
+
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
if (port->close_delay) {
@@ -528,6 +541,15 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_port_close_end);
+/**
+ * tty_port_close
+ *
+ * Caller holds tty lock
+ *
+ * NB: may drop and reacquire tty lock (in tty_port_close_start()->
+ * tty_wait_until_sent_from_close()) so tty and tty_port may have changed
+ * state (but not hung up or reopened).
+ */
void tty_port_close(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
@@ -558,12 +580,19 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver,
}
EXPORT_SYMBOL_GPL(tty_port_install);
+/**
+ * tty_port_open
+ *
+ * Caller holds tty lock.
+ *
+ * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so
+ * tty and tty_port may have changed state (eg., may be hung up now)
+ */
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
spin_lock_irq(&port->lock);
- if (!tty_hung_up_p(filp))
- ++port->count;
+ ++port->count;
spin_unlock_irq(&port->lock);
tty_port_tty_set(port, tty);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 2978ca596a7f..610b720d3b91 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -179,7 +179,6 @@ struct uni_pagedir {
unsigned long sum;
unsigned char *inverse_translations[4];
u16 *inverse_trans_unicode;
- int readonly;
};
static struct uni_pagedir *dflt;
@@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
- else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+ else if (!(p = *conp->vc_uni_pagedir_loc))
return glyph;
else if (use_unicode) {
if (!p->inverse_trans_unicode)
@@ -287,7 +286,7 @@ static void update_user_maps(void)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ p = *vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(vc_cons[i].d, p);
@@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (!p)
return;
- *vc->vc_uni_pagedir_loc = 0;
+ *vc->vc_uni_pagedir_loc = NULL;
if (--p->refcount)
return;
con_release_unimap(p);
@@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ q = *vc_cons[i].d->vc_uni_pagedir_loc;
if (!q || q == p || q->sum != p->sum)
continue;
for (j = 0; j < 32; j++) {
@@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
}
if (j == 32) {
q->refcount++;
- *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ *conp->vc_uni_pagedir_loc = q;
con_release_unimap(p);
kfree(p);
return 1;
@@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p && p->readonly)
- return -EIO;
-
+ p = *vc->vc_uni_pagedir_loc;
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
@@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return -ENOMEM;
}
q->refcount=1;
- *vc->vc_uni_pagedir_loc = (unsigned long)q;
+ *vc->vc_uni_pagedir_loc = q;
} else {
if (p == dflt) dflt = NULL;
p->refcount++;
@@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i;
struct uni_pagedir *p, *q;
+ if (!ct)
+ return 0;
+
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p->readonly) {
- console_unlock();
- return -EIO;
- }
-
- if (!ct) {
- console_unlock();
- return 0;
- }
+ p = *vc->vc_uni_pagedir_loc;
if (p->refcount > 1) {
int j, k;
@@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
- q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ q = *vc->vc_uni_pagedir_loc;
/*
* uni_pgdir is a 32*32*64 table with rows allocated
@@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_insert_unipair(q, l, p2[k]);
if (err1) {
p->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)p;
+ *vc->vc_uni_pagedir_loc = p;
con_release_unimap(q);
kfree(q);
console_unlock();
@@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
struct uni_pagedir *p;
if (dflt) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
dflt->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+ *vc->vc_uni_pagedir_loc = dflt;
if (p && !--p->refcount) {
con_release_unimap(p);
kfree(p);
@@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
if (err)
return err;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
q = dfont_unitable;
for (i = 0; i < 256; i++)
@@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
}
if (con_unify_unimap(vc, p)) {
- dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ dflt = *vc->vc_uni_pagedir_loc;
return err;
}
@@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
return 0;
con_free_unimap(dst_vc);
- q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+ q = *src_vc->vc_uni_pagedir_loc;
q->refcount++;
- *dst_vc->vc_uni_pagedir_loc = (long)q;
+ *dst_vc->vc_uni_pagedir_loc = q;
return 0;
}
EXPORT_SYMBOL(con_copy_unimap);
@@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++)
@@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
if (!*conp->vc_uni_pagedir_loc)
return -3;
- p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ p = *conp->vc_uni_pagedir_loc;
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
(p2 = p1[(ucs >> 6) & 0x1f]) &&
(h = p2[ucs & 0x3f]) < MAX_GLYPH)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 3ad0b61e35b4..b33b00b386de 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
- vc->vc_uni_pagedir = 0;
+ vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
@@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
vc->vc_color = vc->vc_def_color;
}
+struct rgb { u8 r; u8 g; u8 b; };
+
+struct rgb rgb_from_256(int i)
+{
+ struct rgb c;
+ if (i < 8) { /* Standard colours. */
+ c.r = i&1 ? 0xaa : 0x00;
+ c.g = i&2 ? 0xaa : 0x00;
+ c.b = i&4 ? 0xaa : 0x00;
+ } else if (i < 16) {
+ c.r = i&1 ? 0xff : 0x55;
+ c.g = i&2 ? 0xff : 0x55;
+ c.b = i&4 ? 0xff : 0x55;
+ } else if (i < 232) { /* 6x6x6 colour cube. */
+ c.r = (i - 16) / 36 * 85 / 2;
+ c.g = (i - 16) / 6 % 6 * 85 / 2;
+ c.b = (i - 16) % 6 * 85 / 2;
+ } else /* Grayscale ramp. */
+ c.r = c.g = c.b = i * 10 - 2312;
+ return c;
+}
+
+static void rgb_foreground(struct vc_data *vc, struct rgb c)
+{
+ u8 hue, max = c.r;
+ if (c.g > max)
+ max = c.g;
+ if (c.b > max)
+ max = c.b;
+ hue = (c.r > max/2 ? 4 : 0)
+ | (c.g > max/2 ? 2 : 0)
+ | (c.b > max/2 ? 1 : 0);
+ if (hue == 7 && max <= 0x55)
+ hue = 0, vc->vc_intensity = 2;
+ else
+ vc->vc_intensity = (max > 0xaa) + 1;
+ vc->vc_color = (vc->vc_color & 0xf0) | hue;
+}
+
+static void rgb_background(struct vc_data *vc, struct rgb c)
+{
+ /* For backgrounds, err on the dark side. */
+ vc->vc_color = (vc->vc_color & 0x0f)
+ | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
+}
+
/* console_lock is held */
static void csi_m(struct vc_data *vc)
{
@@ -1302,8 +1348,7 @@ static void csi_m(struct vc_data *vc)
case 27:
vc->vc_reverse = 0;
break;
- case 38:
- case 48: /* ITU T.416
+ case 38: /* ITU T.416
* Higher colour modes.
* They break the usual properties of SGR codes
* and thus need to be detected and ignored by
@@ -1315,15 +1360,41 @@ static void csi_m(struct vc_data *vc)
i++;
if (i > vc->vc_npar)
break;
- if (vc->vc_par[i] == 5) /* 256 colours */
- i++; /* ubiquitous */
- else if (vc->vc_par[i] == 2) /* 24 bit colours */
- i += 3; /* extremely rare */
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) { /* ubiquitous */
+ i++;
+ rgb_foreground(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {/* extremely rare */
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_foreground(vc, c);
+ i += 3;
+ }
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
- * that detecting them is not worth the few extra
- * bytes of kernel's size.
+ * there's no point in supporting them.
*/
break;
+ case 48:
+ i++;
+ if (i > vc->vc_npar)
+ break;
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) {
+ i++;
+ rgb_background(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_background(vc, c);
+ i += 3;
+ }
+ break;
case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
break;
@@ -3155,8 +3226,7 @@ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_back = &registered_con_driver[i];
- if (con_back->con &&
- !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+ if (con_back->con && con_back->con != csw) {
defcsw = con_back->con;
retval = 0;
break;
@@ -3261,6 +3331,7 @@ static int vt_unbind(struct con_driver *con)
{
const struct consw *csw = NULL;
int i, more = 1, first = -1, last = -1, deflt = 0;
+ int ret;
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
con_is_graphics(con->con, con->first, con->last))
@@ -3286,8 +3357,10 @@ static int vt_unbind(struct con_driver *con)
if (first != -1) {
console_lock();
- do_unbind_con_driver(csw, first, last, deflt);
+ ret = do_unbind_con_driver(csw, first, last, deflt);
console_unlock();
+ if (ret != 0)
+ return ret;
}
first = -1;
@@ -3574,17 +3647,20 @@ err:
*/
int do_unregister_con_driver(const struct consw *csw)
{
- int i, retval = -ENODEV;
+ int i;
/* cannot unregister a bound driver */
if (con_is_bound(csw))
- goto err;
+ return -EBUSY;
+
+ if (csw == conswitchp)
+ return -EINVAL;
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
struct con_driver *con_driver = &registered_con_driver[i];
if (con_driver->con == csw &&
- con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ con_driver->flag & CON_DRIVER_FLAG_INIT) {
vtconsole_deinit_device(con_driver);
device_destroy(vtconsole_class,
MKDEV(0, con_driver->node));
@@ -3595,12 +3671,11 @@ int do_unregister_con_driver(const struct consw *csw)
con_driver->flag = 0;
con_driver->first = 0;
con_driver->last = 0;
- retval = 0;
- break;
+ return 0;
}
}
-err:
- return retval;
+
+ return -ENODEV;
}
EXPORT_SYMBOL_GPL(do_unregister_con_driver);