summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 15:53:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 15:53:22 -0700
commit8c7febe83915332276cab49e89f6580bb963fb9a (patch)
treec6ffa5fbdef402f8c6e2d75b19dcce813fd21ded /drivers/tty
parent23908db413eccd77084b09c9b0a4451dfb0524c0 (diff)
parent71206b9f8120eb513c621d4f31906577bb658df3 (diff)
Merge tag 'tty-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH: "Here's the tty and serial driver patches for 4.2-rc1. A number of individual driver updates, some code cleanups, and other minor things, full details in the shortlog. All have been in linux-next for a while with no reported issues" * tag 'tty-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (152 commits) Doc: serial-rs485.txt: update RS485 driver interface Doc: tty.txt: remove mention of the BKL MAINTAINERS: tty: add serial docs directory serial: sprd: check for NULL after calling devm_clk_get serial: 8250_pci: Correct uartclk for xr17v35x expansion chips serial: 8250_pci: Add support for 12 port Exar boards serial: 8250_uniphier: add bindings document for UniPhier UART serial: core: cleanup in uart_get_baud_rate() serial: stm32-usart: Add STM32 USART Driver tty/serial: kill off set_irq_flags usage tty: move linux/gsmmux.h to uapi doc: dt: add documentation for nxp,lpc1850-uart serial: 8250: add LPC18xx/43xx UART driver serial: 8250_uniphier: add UniPhier serial driver serial: 8250_dw: support ACPI platforms with integrated DMA engine serial: of_serial: check the return value of clk_prepare_enable() serial: of_serial: use devm_clk_get() instead of clk_get() serial: earlycon: Add support for big-endian MMIO accesses serial: sirf: use hrtimer for data rx serial: sirf: correct the fifo empty_bit ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/amiserial.c11
-rw-r--r--drivers/tty/cyclades.c8
-rw-r--r--drivers/tty/hvc/Kconfig7
-rw-r--r--drivers/tty/hvc/Makefile1
-rw-r--r--drivers/tty/hvc/hvc_beat.c134
-rw-r--r--drivers/tty/hvc/hvc_console.c3
-rw-r--r--drivers/tty/hvc/hvcs.c4
-rw-r--r--drivers/tty/n_gsm.c5
-rw-r--r--drivers/tty/n_tty.c7
-rw-r--r--drivers/tty/nozomi.c8
-rw-r--r--drivers/tty/rocket.h2
-rw-r--r--drivers/tty/serial/68328serial.c3
-rw-r--r--drivers/tty/serial/8250/8250_core.c27
-rw-r--r--drivers/tty/serial/8250/8250_dw.c19
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c230
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c119
-rw-r--r--drivers/tty/serial/8250/8250_omap.c65
-rw-r--r--drivers/tty/serial/8250/8250_pci.c41
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c257
-rw-r--r--drivers/tty/serial/8250/Kconfig15
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/Kconfig72
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/altera_jtaguart.c2
-rw-r--r--drivers/tty/serial/altera_uart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c651
-rw-r--r--drivers/tty/serial/atmel_serial.c22
-rw-r--r--drivers/tty/serial/bfin_uart.c24
-rw-r--r--drivers/tty/serial/crisv10.c106
-rw-r--r--drivers/tty/serial/earlycon.c9
-rw-r--r--drivers/tty/serial/icom.c11
-rw-r--r--drivers/tty/serial/ifx6x60.c19
-rw-r--r--drivers/tty/serial/imx.c18
-rw-r--r--drivers/tty/serial/ioc3_serial.c3
-rw-r--r--drivers/tty/serial/ioc4_serial.c9
-rw-r--r--drivers/tty/serial/kgdb_nmi.c6
-rw-r--r--drivers/tty/serial/mcf.c2
-rw-r--r--drivers/tty/serial/meson_uart.c2
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c2
-rw-r--r--drivers/tty/serial/mpsc.c25
-rw-r--r--drivers/tty/serial/msm_smd_tty.c232
-rw-r--r--drivers/tty/serial/mxs-auart.c2
-rw-r--r--drivers/tty/serial/of_serial.c8
-rw-r--r--drivers/tty/serial/samsung.c4
-rw-r--r--drivers/tty/serial/sc16is7xx.c328
-rw-r--r--drivers/tty/serial/serial-tegra.c158
-rw-r--r--drivers/tty/serial/serial_core.c32
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c5
-rw-r--r--drivers/tty/serial/sh-sci.c96
-rw-r--r--drivers/tty/serial/sh-sci.h140
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c622
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h120
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/stm32-usart.c739
-rw-r--r--drivers/tty/serial/xilinx_uartps.c3
-rw-r--r--drivers/tty/synclink.c15
-rw-r--r--drivers/tty/synclink_gt.c15
-rw-r--r--drivers/tty/synclinkmp.c12
-rw-r--r--drivers/tty/tty_buffer.c3
-rw-r--r--drivers/tty/tty_io.c34
-rw-r--r--drivers/tty/tty_ioctl.c4
-rw-r--r--drivers/tty/tty_ldisc.c8
-rw-r--r--drivers/tty/tty_ldsem.c3
-rw-r--r--drivers/tty/vt/consolemap.c60
-rw-r--r--drivers/tty/vt/vt.c92
67 files changed, 3062 insertions, 1636 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index b2d760055952..e53d9a512c6d 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -966,9 +966,7 @@ static void rs_throttle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", tty_name(tty, buf),
+ printk("throttle %s: %d....\n", tty_name(tty),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -991,9 +989,7 @@ static void rs_unthrottle(struct tty_struct * tty)
struct serial_state *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+ printk("unthrottle %s: %d....\n", tty_name(tty),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -1786,7 +1782,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
struct serial_state *state = platform_get_drvdata(pdev);
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- if ((error = tty_unregister_driver(serial_driver)))
+ error = tty_unregister_driver(serial_driver);
+ if (error)
printk("SERIAL: failed to unregister serial driver (%d)\n",
error);
put_tty_driver(serial_driver);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index fd66f57390d0..87f6578c6f4a 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -2861,9 +2861,7 @@ static void cy_throttle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
-
- printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
+ printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty),
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
@@ -2902,10 +2900,8 @@ static void cy_unthrottle(struct tty_struct *tty)
unsigned long flags;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
-
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
+ tty_name(tty), tty_chars_in_buffer(tty), info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 8902f9b4df71..2509d057b99c 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -42,13 +42,6 @@ config HVC_RTAS
help
IBM Console device driver which makes use of RTAS
-config HVC_BEAT
- bool "Toshiba's Beat Hypervisor Console support"
- depends on PPC_CELLEB
- select HVC_DRIVER
- help
- Toshiba's Cell Reference Set Beat Console device driver
-
config HVC_IUCV
bool "z/VM IUCV Hypervisor console support (VM only)"
depends on S390
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
index 4ca3723b0a3a..6a2702be76d1 100644
--- a/drivers/tty/hvc/Makefile
+++ b/drivers/tty/hvc/Makefile
@@ -4,7 +4,6 @@ obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_TILE) += hvc_tile.o
obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
-obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c
deleted file mode 100644
index 1560d235449e..000000000000
--- a/drivers/tty/hvc/hvc_beat.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Beat hypervisor console driver
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on drivers/char/hvc_rtas.c:
- * (C) Copyright IBM Corporation 2001-2005
- * (C) Copyright Red Hat, Inc. 2005
- *
- * 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.
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/console.h>
-#include <asm/prom.h>
-#include <asm/hvconsole.h>
-#include <asm/firmware.h>
-
-#include "hvc_console.h"
-
-extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
-extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
-
-struct hvc_struct *hvc_beat_dev = NULL;
-
-/* bug: only one queue is available regardless of vtermno */
-static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
-{
- static unsigned char q[sizeof(unsigned long) * 2]
- __attribute__((aligned(sizeof(unsigned long))));
- static int qlen = 0;
- u64 got;
-
-again:
- if (qlen) {
- if (qlen > cnt) {
- memcpy(buf, q, cnt);
- qlen -= cnt;
- memmove(q + cnt, q, qlen);
- return cnt;
- } else { /* qlen <= cnt */
- int r;
-
- memcpy(buf, q, qlen);
- r = qlen;
- qlen = 0;
- return r;
- }
- }
- if (beat_get_term_char(vtermno, &got,
- ((u64 *)q), ((u64 *)q) + 1) == 0) {
- qlen = got;
- goto again;
- }
- return 0;
-}
-
-static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
-{
- unsigned long kb[2];
- int rest, nlen;
-
- for (rest = cnt; rest > 0; rest -= nlen) {
- nlen = (rest > 16) ? 16 : rest;
- memcpy(kb, buf, nlen);
- beat_put_term_char(vtermno, nlen, kb[0], kb[1]);
- buf += nlen;
- }
- return cnt;
-}
-
-static const struct hv_ops hvc_beat_get_put_ops = {
- .get_chars = hvc_beat_get_chars,
- .put_chars = hvc_beat_put_chars,
-};
-
-static int hvc_beat_useit = 1;
-
-static int hvc_beat_config(char *p)
-{
- hvc_beat_useit = simple_strtoul(p, NULL, 0);
- return 0;
-}
-
-static int __init hvc_beat_console_init(void)
-{
- if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
- hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
- }
- return 0;
-}
-
-/* temp */
-static int __init hvc_beat_init(void)
-{
- struct hvc_struct *hp;
-
- if (!firmware_has_feature(FW_FEATURE_BEAT))
- return -ENODEV;
-
- hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
- if (IS_ERR(hp))
- return PTR_ERR(hp);
- hvc_beat_dev = hp;
- return 0;
-}
-
-static void __exit hvc_beat_exit(void)
-{
- if (hvc_beat_dev)
- hvc_remove(hvc_beat_dev);
-}
-
-module_init(hvc_beat_init);
-module_exit(hvc_beat_exit);
-
-__setup("hvc_beat=", hvc_beat_config);
-
-console_initcall(hvc_beat_console_init);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 4fcec1d793a7..4e9c4cc9e1b5 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -319,7 +319,8 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
int rc;
/* Auto increments kref reference if found. */
- if (!(hp = hvc_get_by_index(tty->index)))
+ hp = hvc_get_by_index(tty->index);
+ if (!hp)
return -ENODEV;
tty->driver_data = hp;
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 81ff7e1bfb1a..f7ff97c0ad34 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1044,8 +1044,8 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
* It is possible that the vty-server was removed between the time that
* the conn was registered and now.
*/
- if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
- 0, "ibmhvcs", hvcsd))) {
+ rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd);
+ if (!rc) {
/*
* It is possible the vty-server was removed after the irq was
* requested but before we have time to enable interrupts.
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 2c34c3249972..382d3fcba6cc 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -161,7 +161,7 @@ struct gsm_dlci {
struct net_device *net; /* network interface, if created */
};
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
+/* DLCI 0, 62/63 are special or reserved see gsmtty_open */
#define NUM_DLCI 64
@@ -2274,7 +2274,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
const unsigned char *dp;
char *f;
int i;
- char buf[64];
char flags = TTY_NORMAL;
if (debug & 4)
@@ -2296,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
break;
default:
WARN_ONCE(1, "%s: unknown flag %d\n",
- tty_name(tty, buf), flags);
+ tty_name(tty), flags);
break;
}
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 396344cb011f..c9c27f69e101 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1190,13 +1190,12 @@ static void n_tty_receive_break(struct tty_struct *tty)
static void n_tty_receive_overrun(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- char buf[64];
ldata->num_overrun++;
if (time_after(jiffies, ldata->overrun_time + HZ) ||
time_after(ldata->overrun_time, jiffies)) {
printk(KERN_WARNING "%s: %d input overrun(s)\n",
- tty_name(tty, buf),
+ tty_name(tty),
ldata->num_overrun);
ldata->overrun_time = jiffies;
ldata->num_overrun = 0;
@@ -1471,8 +1470,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
static void
n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
{
- char buf[64];
-
switch (flag) {
case TTY_BREAK:
n_tty_receive_break(tty);
@@ -1486,7 +1483,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
break;
default:
printk(KERN_ERR "%s: unknown flag %d\n",
- tty_name(tty, buf), flag);
+ tty_name(tty), flag);
break;
}
}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 74885af8c7bd..80f9de907563 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -140,8 +140,8 @@ static int debug;
#define R_FCR 0x0000 /* Flow Control Register */
#define R_IER 0x0004 /* Interrupt Enable Register */
-#define CONFIG_MAGIC 0xEFEFFEFE
-#define TOGGLE_VALID 0x0000
+#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE
+#define TOGGLE_VALID 0x0000
/* Definition of interrupt tokens */
#define MDM_DL1 0x0001
@@ -660,9 +660,9 @@ static int nozomi_read_config_table(struct nozomi *dc)
read_mem32((u32 *) &dc->config_table, dc->base_addr + 0,
sizeof(struct config_table));
- if (dc->config_table.signature != CONFIG_MAGIC) {
+ if (dc->config_table.signature != NOZOMI_CONFIG_MAGIC) {
dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n",
- dc->config_table.signature, CONFIG_MAGIC);
+ dc->config_table.signature, NOZOMI_CONFIG_MAGIC);
return 0;
}
diff --git a/drivers/tty/rocket.h b/drivers/tty/rocket.h
index ec863f35f1a9..c11a9392f219 100644
--- a/drivers/tty/rocket.h
+++ b/drivers/tty/rocket.h
@@ -44,7 +44,7 @@ struct rocket_version {
#define ROCKET_HUP_NOTIFY 0x00000004
#define ROCKET_SPLIT_TERMIOS 0x00000008
#define ROCKET_SPD_MASK 0x00000070
-#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */
+#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */
#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */
#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */
#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 5dc9c4bfa66e..748c18f8c8cd 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
int i;
cflag = tty->termios.c_cflag;
- if (!(port = info->port))
+ port = info->port;
+ if (!port)
return;
ustcnt = uart->ustcnt;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 4506e405c8f3..37fff12dd4d0 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -85,19 +85,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_8250_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
-
-/*
- * HUB6 is always on. This will be removed once the header
- * files have been cleaned.
- */
-#define CONFIG_HUB6 1
-
#include <asm/serial.h>
/*
* SERIAL_PORT_DFNS tells us about built-in ports that have no
@@ -2019,8 +2006,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
if (port->set_mctrl)
- return port->set_mctrl(port, mctrl);
- return serial8250_do_set_mctrl(port, mctrl);
+ port->set_mctrl(port, mctrl);
+ else
+ serial8250_do_set_mctrl(port, mctrl);
}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
@@ -3548,6 +3536,9 @@ static struct console univ8250_console = {
static int __init univ8250_console_init(void)
{
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
register_console(&univ8250_console);
return 0;
@@ -3578,7 +3569,7 @@ int __init early_serial_setup(struct uart_port *port)
{
struct uart_port *p;
- if (port->line >= ARRAY_SIZE(serial8250_ports))
+ if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0)
return -ENODEV;
serial8250_isa_init_ports();
@@ -3850,7 +3841,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.mapbase = up->port.mapbase;
uart->port.mapsize = up->port.mapsize;
uart->port.private_data = up->port.private_data;
- uart->port.fifosize = up->port.fifosize;
uart->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities;
uart->port.throttle = up->port.throttle;
@@ -3945,6 +3935,9 @@ static int __init serial8250_init(void)
{
int ret;
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
printk(KERN_INFO "Serial: 8250/16550 driver, "
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 176f18f2e3ab..d48b50641e9a 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -377,6 +377,16 @@ static int dw8250_probe_of(struct uart_port *p,
return 0;
}
+static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
+{
+ struct device *dev = param;
+
+ if (dev != chan->device->dev->parent)
+ return false;
+
+ return true;
+}
+
static int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
@@ -389,8 +399,15 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
- up->dma = &data->dma;
+ /* Platforms with iDMA */
+ if (platform_get_resource_byname(to_platform_device(up->port.dev),
+ IORESOURCE_MEM, "lpss_priv")) {
+ data->dma.rx_param = up->port.dev->parent;
+ data->dma.tx_param = up->port.dev->parent;
+ data->dma.fn = dw8250_idma_filter;
+ }
+ up->dma = &data->dma;
up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 6c0fd8b9d1c3..771dda29a0f8 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -131,7 +131,7 @@ static void __init init_port(struct earlycon_device *device)
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
-static int __init early_serial8250_setup(struct earlycon_device *device,
+int __init early_serial8250_setup(struct earlycon_device *device,
const char *options)
{
if (!(device->port.membase || device->port.iobase))
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
new file mode 100644
index 000000000000..99cd478851ff
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -0,0 +1,230 @@
+/*
+ * Serial port driver for NXP LPC18xx/43xx UART
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Based on 8250_mtk.c:
+ * Copyright (c) 2014 MundoReader S.L.
+ * Matthias Brugger <matthias.bgg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+/* Additional LPC18xx/43xx 8250 registers and bits */
+#define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32))
+#define LPC18XX_UART_RS485CTRL_NMMEN BIT(0)
+#define LPC18XX_UART_RS485CTRL_DCTRL BIT(4)
+#define LPC18XX_UART_RS485CTRL_OINV BIT(5)
+#define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32))
+#define LPC18XX_UART_RS485DLY_MAX 255
+
+struct lpc18xx_uart_data {
+ struct uart_8250_dma dma;
+ struct clk *clk_uart;
+ struct clk *clk_reg;
+ int line;
+};
+
+static int lpc18xx_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u32 rs485_ctrl_reg = 0;
+ u32 rs485_dly_reg = 0;
+ unsigned baud_clk;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ memset(rs485->padding, 0, sizeof(rs485->padding));
+ else
+ memset(rs485, 0, sizeof(*rs485));
+
+ rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
+ LPC18XX_UART_RS485CTRL_DCTRL;
+
+ if (rs485->flags & SER_RS485_RTS_ON_SEND) {
+ rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
+ rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ } else {
+ rs485->flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+ }
+
+ if (rs485->delay_rts_after_send) {
+ baud_clk = port->uartclk / up->dl_read(up);
+ rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send
+ * baud_clk, MSEC_PER_SEC);
+
+ if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX)
+ rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX;
+
+ /* Calculate the resulting delay in ms */
+ rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC)
+ / baud_clk;
+ }
+
+ /* Delay RTS before send not supported */
+ rs485->delay_rts_before_send = 0;
+
+ serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
+ serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);
+
+ port->rs485 = *rs485;
+
+ return 0;
+}
+
+static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
+{
+ /*
+ * For DMA mode one must ensure that the UART_FCR_DMA_SELECT
+ * bit is set when FIFO is enabled. Even if DMA is not used
+ * setting this bit doesn't seem to affect anything.
+ */
+ if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO))
+ value |= UART_FCR_DMA_SELECT;
+
+ offset = offset << p->regshift;
+ writel(value, p->membase + offset);
+}
+
+static int lpc18xx_serial_probe(struct platform_device *pdev)
+{
+ struct lpc18xx_uart_data *data;
+ struct uart_8250_port uart;
+ struct resource *res;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "irq not found");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+
+ memset(&uart, 0, sizeof(uart));
+
+ uart.port.membase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->clk_uart = devm_clk_get(&pdev->dev, "uartclk");
+ if (IS_ERR(data->clk_uart)) {
+ dev_err(&pdev->dev, "uart clock not found\n");
+ return PTR_ERR(data->clk_uart);
+ }
+
+ data->clk_reg = devm_clk_get(&pdev->dev, "reg");
+ if (IS_ERR(data->clk_reg)) {
+ dev_err(&pdev->dev, "reg clock not found\n");
+ return PTR_ERR(data->clk_reg);
+ }
+
+ ret = clk_prepare_enable(data->clk_reg);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable reg clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk_uart);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock\n");
+ goto dis_clk_reg;
+ }
+
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ uart.port.line = ret;
+
+ data->dma.rx_param = data;
+ data->dma.tx_param = data;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = irq;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.mapbase = res->start;
+ uart.port.regshift = 2;
+ uart.port.type = PORT_16550A;
+ uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
+ uart.port.uartclk = clk_get_rate(data->clk_uart);
+ uart.port.private_data = data;
+ uart.port.rs485_config = lpc18xx_rs485_config;
+ uart.port.serial_out = lpc18xx_uart_serial_out;
+
+ uart.dma = &data->dma;
+ uart.dma->rxconf.src_maxburst = 1;
+ uart.dma->txconf.dst_maxburst = 1;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port\n");
+ goto dis_uart_clk;
+ }
+
+ data->line = ret;
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_uart_clk:
+ clk_disable_unprepare(data->clk_uart);
+dis_clk_reg:
+ clk_disable_unprepare(data->clk_reg);
+ return ret;
+}
+
+static int lpc18xx_serial_remove(struct platform_device *pdev)
+{
+ struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ clk_disable_unprepare(data->clk_uart);
+ clk_disable_unprepare(data->clk_reg);
+
+ return 0;
+}
+
+static const struct of_device_id lpc18xx_serial_match[] = {
+ { .compatible = "nxp,lpc1850-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_serial_match);
+
+static struct platform_driver lpc18xx_serial_driver = {
+ .probe = lpc18xx_serial_probe,
+ .remove = lpc18xx_serial_remove,
+ .driver = {
+ .name = "lpc18xx-uart",
+ .of_match_table = lpc18xx_serial_match,
+ },
+};
+module_platform_driver(lpc18xx_serial_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 7a11fac775c4..78883ca64ddd 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -34,6 +34,7 @@
struct mtk8250_data {
int line;
struct clk *uart_clk;
+ struct clk *bus_clk;
};
static void
@@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
tty_termios_encode_baud_rate(termios, baud, baud);
}
+static int mtk8250_runtime_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(data->uart_clk);
+ clk_disable_unprepare(data->bus_clk);
+
+ return 0;
+}
+
+static int mtk8250_runtime_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+ int err;
+
+ err = clk_prepare_enable(data->uart_clk);
+ if (err) {
+ dev_warn(dev, "Can't enable clock\n");
+ return err;
+ }
+
+ err = clk_prepare_enable(data->bus_clk);
+ if (err) {
+ dev_warn(dev, "Can't enable bus clock\n");
+ return err;
+ }
+
+ return 0;
+}
+
static void
mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
@@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
struct mtk8250_data *data)
{
- int err;
- struct device_node *np = pdev->dev.of_node;
-
- data->uart_clk = of_clk_get(np, 0);
+ data->uart_clk = devm_clk_get(&pdev->dev, "baud");
if (IS_ERR(data->uart_clk)) {
- dev_warn(&pdev->dev, "Can't get timer clock\n");
- return PTR_ERR(data->uart_clk);
+ /*
+ * For compatibility with older device trees try unnamed
+ * clk when no baud clk can be found.
+ */
+ data->uart_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->uart_clk)) {
+ dev_warn(&pdev->dev, "Can't get uart clock\n");
+ return PTR_ERR(data->uart_clk);
+ }
+
+ return 0;
}
- err = clk_prepare_enable(data->uart_clk);
- if (err) {
- dev_warn(&pdev->dev, "Can't prepare clock\n");
- clk_put(data->uart_clk);
- return err;
- }
- p->uartclk = clk_get_rate(data->uart_clk);
+ data->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(data->bus_clk))
+ return PTR_ERR(data->bus_clk);
return 0;
}
@@ -190,19 +223,24 @@ static int mtk8250_probe(struct platform_device *pdev)
uart.port.regshift = 2;
uart.port.private_data = data;
uart.port.set_termios = mtk8250_set_termios;
+ uart.port.uartclk = clk_get_rate(data->uart_clk);
/* Disable Rate Fix function */
writel(0x0, uart.port.membase +
(MTK_UART_RATE_FIX << uart.port.regshift));
- data->line = serial8250_register_8250_port(&uart);
- if (data->line < 0)
- return data->line;
-
platform_set_drvdata(pdev, data);
- pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ err = mtk8250_runtime_resume(&pdev->dev);
+ if (err)
+ return err;
+ }
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+ return data->line;
return 0;
}
@@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
serial8250_unregister_port(data->line);
- if (!IS_ERR(data->uart_clk)) {
- clk_disable_unprepare(data->uart_clk);
- clk_put(data->uart_clk);
- }
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
+
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mtk8250_runtime_suspend(&pdev->dev);
+
return 0;
}
@@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM
-static int mtk8250_runtime_suspend(struct device *dev)
-{
- struct mtk8250_data *data = dev_get_drvdata(dev);
-
- if (!IS_ERR(data->uart_clk))
- clk_disable_unprepare(data->uart_clk);
-
- return 0;
-}
-
-static int mtk8250_runtime_resume(struct device *dev)
-{
- struct mtk8250_data *data = dev_get_drvdata(dev);
-
- if (!IS_ERR(data->uart_clk))
- clk_prepare_enable(data->uart_clk);
-
- return 0;
-}
-#endif
-
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume,
@@ -289,6 +305,21 @@ static struct platform_driver mtk8250_platform_driver = {
};
module_platform_driver(mtk8250_platform_driver);
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init early_mtk8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.iotype = UPIO_MEM32;
+
+ return early_serial8250_setup(device, NULL);
+}
+
+OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
+#endif
+
MODULE_AUTHOR("Matthias Brugger");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index dce1a23706e8..978204333c94 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -98,6 +98,7 @@ struct omap8250_priv {
struct pm_qos_request pm_qos_request;
struct work_struct qos_work;
struct uart_8250_dma omap8250_dma;
+ spinlock_t rx_dma_lock;
};
static u32 uart_read(struct uart_8250_port *up, u32 reg)
@@ -726,14 +727,21 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
{
+ struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
struct tty_port *tty_port = &p->port.state->port;
struct dma_tx_state state;
int count;
+ unsigned long flags;
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
+ if (!dma->rx_running)
+ goto unlock;
+
dma->rx_running = 0;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
dmaengine_terminate_all(dma->rxchan);
@@ -742,6 +750,9 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
tty_insert_flip_string(tty_port, dma->rx_buf, count);
p->port.icount.rx += count;
+unlock:
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+
if (!error)
omap_8250_rx_dma(p, 0);
@@ -753,28 +764,45 @@ static void __dma_rx_complete(void *param)
__dma_rx_do_complete(param, false);
}
+static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
+{
+ struct omap8250_priv *priv = p->port.private_data;
+ struct uart_8250_dma *dma = p->dma;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
+ if (!dma->rx_running) {
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+ return;
+ }
+
+ dmaengine_pause(dma->rxchan);
+
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+
+ __dma_rx_do_complete(p, true);
+}
+
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
{
+ struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
+ int err = 0;
struct dma_async_tx_descriptor *desc;
+ unsigned long flags;
switch (iir & 0x3f) {
case UART_IIR_RLSI:
/* 8250_core handles errors and break interrupts */
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -EIO;
case UART_IIR_RX_TIMEOUT:
/*
* If RCVR FIFO trigger level was not reached, complete the
* transfer and let 8250_core copy the remaining data.
*/
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -ETIMEDOUT;
case UART_IIR_RDI:
/*
@@ -786,24 +814,25 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
* the DMA won't do anything soon so we have to cancel the DMA
* transfer and purge the FIFO manually.
*/
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -ETIMEDOUT;
default:
break;
}
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
if (dma->rx_running)
- return 0;
+ goto out;
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EBUSY;
+ if (!desc) {
+ err = -EBUSY;
+ goto out;
+ }
dma->rx_running = 1;
desc->callback = __dma_rx_complete;
@@ -815,7 +844,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
dma->rx_size, DMA_FROM_DEVICE);
dma_async_issue_pending(dma->rxchan);
- return 0;
+out:
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+ return err;
}
static int omap_8250_tx_dma(struct uart_8250_port *p);
@@ -1129,6 +1160,8 @@ static int omap8250_probe(struct platform_device *pdev)
priv->latency);
INIT_WORK(&priv->qos_work, omap8250_uart_qos_work);
+ spin_lock_init(&priv->rx_dma_lock);
+
device_init_wakeup(&pdev->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 46bcebba54b2..e55f18b93fe7 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1823,6 +1823,9 @@ static int pci_eg20t_init(struct pci_dev *dev)
#endif
}
+#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
+#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
+
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1832,6 +1835,15 @@ pci_xr17c154_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx);
}
+static inline int
+xr17v35x_has_slave(struct serial_private *priv)
+{
+ const int dev_id = priv->dev->device;
+
+ return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
+}
+
static int
pci_xr17v35x_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1846,6 +1858,13 @@ pci_xr17v35x_setup(struct serial_private *priv,
port->port.flags |= UPF_EXAR_EFR;
/*
+ * Setup the uart clock for the devices on expansion slot to
+ * half the clock speed of the main chip (which is 125MHz)
+ */
+ if (xr17v35x_has_slave(priv) && idx >= 8)
+ port->port.uartclk = (7812500 * 16 / 2);
+
+ /*
* Setup Multipurpose Input/Output pins.
*/
if (idx == 0) {
@@ -1998,8 +2017,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
-#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
-
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
@@ -2524,6 +2541,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
},
{
.vendor = PCI_VENDOR_ID_EXAR,
+ .device = PCI_DEVICE_ID_EXAR_XR17V4358,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_EXAR,
.device = PCI_DEVICE_ID_EXAR_XR17V8358,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
@@ -3008,6 +3032,7 @@ enum pci_board_num_t {
pbn_exar_XR17V352,
pbn_exar_XR17V354,
pbn_exar_XR17V358,
+ pbn_exar_XR17V4358,
pbn_exar_XR17V8358,
pbn_exar_ibm_saturn,
pbn_pasemi_1682M,
@@ -3695,6 +3720,14 @@ static struct pciserial_board pci_boards[] = {
.reg_shift = 0,
.first_offset = 0,
},
+ [pbn_exar_XR17V4358] = {
+ .flags = FL_BASE0,
+ .num_ports = 12,
+ .base_baud = 7812500,
+ .uart_offset = 0x400,
+ .reg_shift = 0,
+ .first_offset = 0,
+ },
[pbn_exar_XR17V8358] = {
.flags = FL_BASE0,
.num_ports = 16,
@@ -5112,6 +5145,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_exar_XR17V358 },
+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V4358,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V4358 },
{ PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358,
PCI_ANY_ID, PCI_ANY_ID,
0,
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
new file mode 100644
index 000000000000..7d79425c2b09
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
+#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
+
+#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */
+#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */
+#define UNIPHIER_UART_LCR_SHIFT 8
+#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */
+
+struct uniphier8250_priv {
+ int line;
+ struct clk *clk;
+ spinlock_t atomic_write_lock;
+};
+
+/*
+ * The register map is slightly different from that of 8250.
+ * IO callbacks must be overridden for correct access to FCR, LCR, and MCR.
+ */
+static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
+{
+ unsigned int valshift = 0;
+
+ switch (offset) {
+ case UART_LCR:
+ valshift = UNIPHIER_UART_LCR_SHIFT;
+ /* fall through */
+ case UART_MCR:
+ offset = UNIPHIER_UART_LCR_MCR;
+ break;
+ default:
+ break;
+ }
+
+ offset <<= p->regshift;
+
+ /*
+ * The return value must be masked with 0xff because LCR and MCR reside
+ * in the same register that must be accessed by 32-bit write/read.
+ * 8 or 16 bit access to this hardware result in unexpected behavior.
+ */
+ return (readl(p->membase + offset) >> valshift) & 0xff;
+}
+
+static void uniphier_serial_out(struct uart_port *p, int offset, int value)
+{
+ unsigned int valshift = 0;
+ bool normal = false;
+
+ switch (offset) {
+ case UART_FCR:
+ offset = UNIPHIER_UART_CHAR_FCR;
+ break;
+ case UART_LCR:
+ valshift = UNIPHIER_UART_LCR_SHIFT;
+ /* Divisor latch access bit does not exist. */
+ value &= ~(UART_LCR_DLAB << valshift);
+ /* fall through */
+ case UART_MCR:
+ offset = UNIPHIER_UART_LCR_MCR;
+ break;
+ default:
+ normal = true;
+ break;
+ }
+
+ offset <<= p->regshift;
+
+ if (normal) {
+ writel(value, p->membase + offset);
+ } else {
+ /*
+ * Special case: two registers share the same address that
+ * must be 32-bit accessed. As this is not longer atomic safe,
+ * take a lock just in case.
+ */
+ struct uniphier8250_priv *priv = p->private_data;
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&priv->atomic_write_lock, flags);
+ tmp = readl(p->membase + offset);
+ tmp &= ~(0xff << valshift);
+ tmp |= value << valshift;
+ writel(tmp, p->membase + offset);
+ spin_unlock_irqrestore(&priv->atomic_write_lock, flags);
+ }
+}
+
+/*
+ * This hardware does not have the divisor latch access bit.
+ * The divisor latch register exists at different address.
+ * Override dl_read/write callbacks.
+ */
+static int uniphier_serial_dl_read(struct uart_8250_port *up)
+{
+ return readl(up->port.membase + UNIPHIER_UART_DLR);
+}
+
+static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ writel(value, up->port.membase + UNIPHIER_UART_DLR);
+}
+
+static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
+ struct uniphier8250_priv *priv)
+{
+ int ret;
+ u32 prop;
+ struct device_node *np = dev->of_node;
+
+ ret = of_alias_get_id(np, "serial");
+ if (ret < 0) {
+ dev_err(dev, "failed to get alias id\n");
+ return ret;
+ }
+ port->line = priv->line = ret;
+
+ /* Get clk rate through clk driver */
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret < 0)
+ return ret;
+
+ port->uartclk = clk_get_rate(priv->clk);
+
+ /* Check for fifo size */
+ if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ port->fifosize = prop;
+ else
+ port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
+
+ return 0;
+}
+
+static int uniphier_uart_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port up;
+ struct uniphier8250_priv *priv;
+ struct resource *regs;
+ void __iomem *membase;
+ int irq;
+ int ret;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(dev, "failed to get memory resource");
+ return -EINVAL;
+ }
+
+ membase = devm_ioremap(dev, regs->start, resource_size(regs));
+ if (!membase)
+ return -ENOMEM;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number");
+ return irq;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ memset(&up, 0, sizeof(up));
+
+ ret = uniphier_of_serial_setup(dev, &up.port, priv);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_init(&priv->atomic_write_lock);
+
+ up.port.dev = dev;
+ up.port.private_data = priv;
+ up.port.mapbase = regs->start;
+ up.port.mapsize = resource_size(regs);
+ up.port.membase = membase;
+ up.port.irq = irq;
+
+ up.port.type = PORT_16550A;
+ up.port.iotype = UPIO_MEM32;
+ up.port.regshift = 2;
+ up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ up.capabilities = UART_CAP_FIFO;
+
+ up.port.serial_in = uniphier_serial_in;
+ up.port.serial_out = uniphier_serial_out;
+ up.dl_read = uniphier_serial_dl_read;
+ up.dl_write = uniphier_serial_dl_write;
+
+ ret = serial8250_register_8250_port(&up);
+ if (ret < 0) {
+ dev_err(dev, "failed to register 8250 port\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int uniphier_uart_remove(struct platform_device *pdev)
+{
+ struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_uart_match[] = {
+ { .compatible = "socionext,uniphier-uart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_uart_match);
+
+static struct platform_driver uniphier_uart_platform_driver = {
+ .probe = uniphier_uart_probe,
+ .remove = uniphier_uart_remove,
+ .driver = {
+ .name = "uniphier-uart",
+ .of_match_table = uniphier_uart_match,
+ },
+};
+module_platform_driver(uniphier_uart_platform_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c35070356528..a74a8e4717d4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -336,9 +336,24 @@ config SERIAL_8250_FINTEK
LPC to 4 UART. This device has some RS485 functionality not available
through the PNP driver. If unsure, say N.
+config SERIAL_8250_LPC18XX
+ bool "NXP LPC18xx/43xx serial port support"
+ depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
+ default ARCH_LPC18XX
+ help
+ If you have a LPC18xx/43xx based board and want to use the
+ serial port, say Y to this option. If unsure, say Y.
+
config SERIAL_8250_MT6577
bool "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
serial port, say Y to this option. If unsure, say N.
+
+config SERIAL_8250_UNIPHIER
+ tristate "Support for UniPhier on-chip UART"
+ depends on SERIAL_8250 && ARCH_UNIPHIER
+ help
+ If you have a UniPhier based board and want to use the on-chip
+ serial ports, say Y to this option. If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 31e7cdc6865c..6fa22ffad63d 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -22,4 +22,6 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
+obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index dea1eff6a92c..76e65b714471 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -241,7 +241,6 @@ config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
- select SERIAL_EARLYCON
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
@@ -277,6 +276,7 @@ config SERIAL_SAMSUNG_CONSOLE
bool "Support for console on Samsung SoC serial port"
depends on SERIAL_SAMSUNG=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
@@ -1179,15 +1179,42 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
+config SERIAL_SC16IS7XX_CORE
+ tristate
+
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.
+ tristate "SC16IS7xx serial support"
+ select SERIAL_CORE
+ depends on I2C || SPI_MASTER
+ help
+ This selects support for SC16IS7xx serial ports.
+ Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
+ SC16IS760 and SC16IS762. Select supported buses using options below.
+
+config SERIAL_SC16IS7XX_I2C
+ bool "SC16IS7xx for I2C interface"
+ depends on SERIAL_SC16IS7XX
+ depends on I2C
+ select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+ select REGMAP_I2C if I2C
+ default y
+ help
+ Enable SC16IS7xx driver on I2C bus,
+ If required say y, and say n to i2c if not required,
+ Enabled by default to support oldconfig.
+ You must select at least one bus for the driver to be built.
+
+config SERIAL_SC16IS7XX_SPI
+ bool "SC16IS7xx for spi interface"
+ depends on SERIAL_SC16IS7XX
+ depends on SPI_MASTER
+ select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+ select REGMAP_SPI if SPI_MASTER
+ help
+ Enable SC16IS7xx driver on SPI bus,
+ If required say y, and say n to spi if not required,
+ This is additional support to exsisting driver.
+ You must select at least one bus for the driver to be built.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
@@ -1349,7 +1376,7 @@ config SERIAL_ALTERA_UART_CONSOLE
config SERIAL_IFX6X60
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
- depends on GPIOLIB && SPI
+ depends on GPIOLIB && SPI && HAS_DMA
help
Support for the IFX6x60 modem devices on Intel MID platforms.
@@ -1378,14 +1405,6 @@ config SERIAL_PCH_UART_CONSOLE
(the system console is the device which receives all kernel messages and
warnings and which allows logins in single user mode).
-config SERIAL_MSM_SMD
- bool "Enable tty device interface for some SMD ports"
- default n
- depends on MSM_SMD
- help
- Enables userspace clients to read and write to some streaming SMD
- ports via tty device interface for MSM chipset.
-
config SERIAL_MXS_AUART
depends on ARCH_MXS
tristate "MXS AUART support"
@@ -1589,6 +1608,23 @@ config SERIAL_SPRD_CONSOLE
with "earlycon" on the kernel command line. The console is
enabled when early_param is processed.
+config SERIAL_STM32
+ tristate "STMicroelectronics STM32 serial port support"
+ select SERIAL_CORE
+ depends on ARM || COMPILE_TEST
+ help
+ This driver is for the on-chip Serial Controller on
+ STMicroelectronics STM32 MCUs.
+ USART supports Rx & Tx functionality.
+ It support all industry standard baud rates.
+
+ If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+ bool "Support for console on STM32"
+ depends on SERIAL_STM32=y
+ select SERIAL_CORE_CONSOLE
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index c3ac3d930b33..5ab41119b3dc 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -53,7 +53,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
-obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
+obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@@ -79,7 +79,6 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
-obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
@@ -93,6 +92,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
# 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 0fefdd8931a2..32df2a0cb060 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init);
#define ALTERA_JTAGUART_CONSOLE NULL
-#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
+#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index b2859fe07e14..fd87a6f574e3 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init);
#define ALTERA_UART_CONSOLE NULL
-#endif /* CONFIG_ALTERA_UART_CONSOLE */
+#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */
/*
* Define the altera_uart UART driver structure.
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 763eb20fe321..50cf5b10ceed 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,7 +58,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
#include <linux/io.h>
-#include <linux/workqueue.h>
+#include <linux/acpi.h>
#define UART_NR 14
@@ -79,6 +79,8 @@ struct vendor_data {
bool oversampling;
bool dma_threshold;
bool cts_event_workaround;
+ bool always_enabled;
+ bool fixed_options;
unsigned int (*get_fifosize)(struct amba_device *dev);
};
@@ -95,9 +97,19 @@ static struct vendor_data vendor_arm = {
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
+ .always_enabled = false,
+ .fixed_options = false,
.get_fifosize = get_fifosize_arm,
};
+static struct vendor_data vendor_sbsa = {
+ .oversampling = false,
+ .dma_threshold = false,
+ .cts_event_workaround = false,
+ .always_enabled = true,
+ .fixed_options = true,
+};
+
static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
@@ -110,6 +122,8 @@ static struct vendor_data vendor_st = {
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
+ .always_enabled = false,
+ .fixed_options = false,
.get_fifosize = get_fifosize_st,
};
@@ -157,9 +171,8 @@ struct uart_amba_port {
unsigned int lcrh_tx; /* vendor-specific */
unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
- struct delayed_work tx_softirq_work;
bool autorts;
- unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */
+ unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
@@ -1172,15 +1185,14 @@ static void pl011_stop_tx(struct uart_port *port)
pl011_dma_tx_stop(uap);
}
-static bool pl011_tx_chars(struct uart_amba_port *uap);
+static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
/* Start TX with programmed I/O only (no DMA) */
static void pl011_start_tx_pio(struct uart_amba_port *uap)
{
uap->im |= UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
- if (!uap->tx_irq_seen)
- pl011_tx_chars(uap);
+ pl011_tx_chars(uap, false);
}
static void pl011_start_tx(struct uart_port *port)
@@ -1247,15 +1259,11 @@ __acquires(&uap->port.lock)
spin_lock(&uap->port.lock);
}
-/*
- * Transmit a character
- *
- * Returns true if the character was successfully queued to the FIFO.
- * Returns false otherwise.
- */
-static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
+static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
+ bool from_irq)
{
- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ if (unlikely(!from_irq) &&
+ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
return false; /* unable to transmit character */
writew(c, uap->port.membase + UART01x_DR);
@@ -1264,70 +1272,41 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
return true;
}
-static bool pl011_tx_chars(struct uart_amba_port *uap)
+static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
{
struct circ_buf *xmit = &uap->port.state->xmit;
- int count;
-
- if (unlikely(uap->tx_irq_seen < 2))
- /*
- * Initial FIFO fill level unknown: we must check TXFF
- * after each write, so just try to fill up the FIFO.
- */
- count = uap->fifosize;
- else /* tx_irq_seen >= 2 */
- /*
- * FIFO initially at least half-empty, so we can simply
- * write half the FIFO without polling TXFF.
-
- * Note: the *first* TX IRQ can still race with
- * pl011_start_tx_pio(), which can result in the FIFO
- * being fuller than expected in that case.
- */
- count = uap->fifosize >> 1;
-
- /*
- * If the FIFO is full we're guaranteed a TX IRQ at some later point,
- * and can't transmit immediately in any case:
- */
- if (unlikely(uap->tx_irq_seen < 2 &&
- readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF))
- return false;
+ int count = uap->fifosize >> 1;
if (uap->port.x_char) {
- if (!pl011_tx_char(uap, uap->port.x_char))
- goto done;
+ if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
+ return;
uap->port.x_char = 0;
--count;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
pl011_stop_tx(&uap->port);
- goto done;
+ return;
}
/* If we are using DMA mode, try to send some characters. */
if (pl011_dma_tx_irq(uap))
- goto done;
+ return;
- while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) {
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- if (uart_circ_empty(xmit))
+ do {
+ if (likely(from_irq) && count-- == 0)
break;
- }
+
+ if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ break;
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ } while (!uart_circ_empty(xmit));
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
- if (uart_circ_empty(xmit)) {
+ if (uart_circ_empty(xmit))
pl011_stop_tx(&uap->port);
- goto done;
- }
-
- if (unlikely(!uap->tx_irq_seen))
- schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout);
-
-done:
- return false;
}
static void pl011_modem_status(struct uart_amba_port *uap)
@@ -1354,26 +1333,23 @@ static void pl011_modem_status(struct uart_amba_port *uap)
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
}
-static void pl011_tx_softirq(struct work_struct *work)
+static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
{
- struct delayed_work *dwork = to_delayed_work(work);
- struct uart_amba_port *uap =
- container_of(dwork, struct uart_amba_port, tx_softirq_work);
-
- spin_lock(&uap->port.lock);
- while (pl011_tx_chars(uap)) ;
- spin_unlock(&uap->port.lock);
-}
+ unsigned int dummy_read;
-static void pl011_tx_irq_seen(struct uart_amba_port *uap)
-{
- if (likely(uap->tx_irq_seen > 1))
+ if (!uap->vendor->cts_event_workaround)
return;
- uap->tx_irq_seen++;
- if (uap->tx_irq_seen < 2)
- /* first TX IRQ */
- cancel_delayed_work(&uap->tx_softirq_work);
+ /* workaround to make sure that all bits are unlocked.. */
+ writew(0x00, uap->port.membase + UART011_ICR);
+
+ /*
+ * WA: introduce 26ns(1 uart clk) delay before W1C;
+ * single apb access will incur 2 pclk(133.12Mhz) delay,
+ * so add 2 dummy reads
+ */
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = readw(uap->port.membase + UART011_ICR);
}
static irqreturn_t pl011_int(int irq, void *dev_id)
@@ -1381,25 +1357,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
struct uart_amba_port *uap = dev_id;
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+ u16 imsc;
int handled = 0;
- unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
- status = readw(uap->port.membase + UART011_MIS);
+ imsc = readw(uap->port.membase + UART011_IMSC);
+ status = readw(uap->port.membase + UART011_RIS) & imsc;
if (status) {
do {
- if (uap->vendor->cts_event_workaround) {
- /* workaround to make sure that all bits are unlocked.. */
- writew(0x00, uap->port.membase + UART011_ICR);
-
- /*
- * WA: introduce 26ns(1 uart clk) delay before W1C;
- * single apb access will incur 2 pclk(133.12Mhz) delay,
- * so add 2 dummy reads
- */
- dummy_read = readw(uap->port.membase + UART011_ICR);
- dummy_read = readw(uap->port.membase + UART011_ICR);
- }
+ check_apply_cts_event_workaround(uap);
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
@@ -1414,15 +1380,13 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
- if (status & UART011_TXIS) {
- pl011_tx_irq_seen(uap);
- pl011_tx_chars(uap);
- }
+ if (status & UART011_TXIS)
+ pl011_tx_chars(uap, true);
if (pass_counter-- == 0)
break;
- status = readw(uap->port.membase + UART011_MIS);
+ status = readw(uap->port.membase + UART011_RIS) & imsc;
} while (status != 0);
handled = 1;
}
@@ -1617,6 +1581,32 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
}
}
+static int pl011_allocate_irq(struct uart_amba_port *uap)
+{
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+}
+
+/*
+ * Enable interrupts, only timeouts when using DMA
+ * if initial RX DMA job failed, start in interrupt mode
+ * as well.
+ */
+static void pl011_enable_interrupts(struct uart_amba_port *uap)
+{
+ spin_lock_irq(&uap->port.lock);
+
+ /* Clear out any spuriously appearing RX interrupts */
+ writew(UART011_RTIS | UART011_RXIS,
+ uap->port.membase + UART011_ICR);
+ uap->im = UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ spin_unlock_irq(&uap->port.lock);
+}
+
static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1628,20 +1618,12 @@ static int pl011_startup(struct uart_port *port)
if (retval)
goto clk_dis;
- writew(uap->im, uap->port.membase + UART011_IMSC);
-
- /*
- * Allocate the IRQ
- */
- retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+ retval = pl011_allocate_irq(uap);
if (retval)
goto clk_dis;
writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
- /* Assume that TX IRQ doesn't work until we see one: */
- uap->tx_irq_seen = 0;
-
spin_lock_irq(&uap->port.lock);
/* restore RTS and DTR */
@@ -1659,20 +1641,7 @@ static int pl011_startup(struct uart_port *port)
/* Startup DMA */
pl011_dma_startup(uap);
- /*
- * Finally, enable interrupts, only timeouts when using DMA
- * if initial RX DMA job failed, start in interrupt mode
- * as well.
- */
- spin_lock_irq(&uap->port.lock);
- /* Clear out any spuriously appearing RX interrupts */
- writew(UART011_RTIS | UART011_RXIS,
- uap->port.membase + UART011_ICR);
- uap->im = UART011_RTIM;
- if (!pl011_dma_rx_running(uap))
- uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- spin_unlock_irq(&uap->port.lock);
+ pl011_enable_interrupts(uap);
return 0;
@@ -1681,6 +1650,28 @@ static int pl011_startup(struct uart_port *port)
return retval;
}
+static int sbsa_uart_startup(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ int retval;
+
+ retval = pl011_hwinit(port);
+ if (retval)
+ return retval;
+
+ retval = pl011_allocate_irq(uap);
+ if (retval)
+ return retval;
+
+ /* The SBSA UART does not support any modem status lines. */
+ uap->old_status = 0;
+
+ pl011_enable_interrupts(uap);
+
+ return 0;
+}
+
static void pl011_shutdown_channel(struct uart_amba_port *uap,
unsigned int lcrh)
{
@@ -1691,36 +1682,15 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
writew(val, uap->port.membase + lcrh);
}
-static void pl011_shutdown(struct uart_port *port)
+/*
+ * disable the port. It should not disable RTS and DTR.
+ * Also RTS and DTR state should be preserved to restore
+ * it during startup().
+ */
+static void pl011_disable_uart(struct uart_amba_port *uap)
{
- struct uart_amba_port *uap =
- container_of(port, struct uart_amba_port, port);
unsigned int cr;
- cancel_delayed_work_sync(&uap->tx_softirq_work);
-
- /*
- * disable all interrupts
- */
- spin_lock_irq(&uap->port.lock);
- uap->im = 0;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
- spin_unlock_irq(&uap->port.lock);
-
- pl011_dma_shutdown(uap);
-
- /*
- * Free the interrupt
- */
- free_irq(uap->port.irq, uap);
-
- /*
- * disable the port
- * disable the port. It should not disable RTS and DTR.
- * Also RTS and DTR state should be preserved to restore
- * it during startup().
- */
uap->autorts = false;
spin_lock_irq(&uap->port.lock);
cr = readw(uap->port.membase + UART011_CR);
@@ -1736,6 +1706,32 @@ static void pl011_shutdown(struct uart_port *port)
pl011_shutdown_channel(uap, uap->lcrh_rx);
if (uap->lcrh_rx != uap->lcrh_tx)
pl011_shutdown_channel(uap, uap->lcrh_tx);
+}
+
+static void pl011_disable_interrupts(struct uart_amba_port *uap)
+{
+ spin_lock_irq(&uap->port.lock);
+
+ /* mask all interrupts and clear all pending ones */
+ uap->im = 0;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ writew(0xffff, uap->port.membase + UART011_ICR);
+
+ spin_unlock_irq(&uap->port.lock);
+}
+
+static void pl011_shutdown(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ pl011_disable_interrupts(uap);
+
+ pl011_dma_shutdown(uap);
+
+ free_irq(uap->port.irq, uap);
+
+ pl011_disable_uart(uap);
/*
* Shut down the clock producer
@@ -1756,6 +1752,51 @@ static void pl011_shutdown(struct uart_port *port)
uap->port.ops->flush_buffer(port);
}
+static void sbsa_uart_shutdown(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ pl011_disable_interrupts(uap);
+
+ free_irq(uap->port.irq, uap);
+
+ if (uap->port.ops->flush_buffer)
+ uap->port.ops->flush_buffer(port);
+}
+
+static void
+pl011_setup_status_masks(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 & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= UART011_DR_BE;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= UART011_DR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART011_DR_OE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_DR_RX;
+}
+
static void
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
@@ -1820,33 +1861,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- 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 & (IGNBRK | BRKINT | PARMRK))
- port->read_status_mask |= UART011_DR_BE;
-
- /*
- * Characters to ignore
- */
- port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
- if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= UART011_DR_BE;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART011_DR_OE;
- }
-
- /*
- * Ignore all characters if CREAD is not set.
- */
- if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= UART_DUMMY_DR_RX;
+ pl011_setup_status_masks(port, termios);
if (UART_ENABLE_MS(port, termios->c_cflag))
pl011_enable_ms(port);
@@ -1901,6 +1916,27 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&port->lock, flags);
}
+static void
+sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ unsigned long flags;
+
+ tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
+
+ /* The SBSA UART only supports 8n1 without hardware flow control. */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+ termios->c_cflag |= CS8 | CLOCAL;
+
+ spin_lock_irqsave(&port->lock, flags);
+ uart_update_timeout(port, CS8, uap->fixed_baud);
+ pl011_setup_status_masks(port, termios);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
static const char *pl011_type(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1976,6 +2012,37 @@ static struct uart_ops amba_pl011_pops = {
#endif
};
+static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static const struct uart_ops sbsa_uart_pops = {
+ .tx_empty = pl011_tx_empty,
+ .set_mctrl = sbsa_uart_set_mctrl,
+ .get_mctrl = sbsa_uart_get_mctrl,
+ .stop_tx = pl011_stop_tx,
+ .start_tx = pl011_start_tx,
+ .stop_rx = pl011_stop_rx,
+ .startup = sbsa_uart_startup,
+ .shutdown = sbsa_uart_shutdown,
+ .set_termios = sbsa_uart_set_termios,
+ .type = pl011_type,
+ .release_port = pl011_release_port,
+ .request_port = pl011_request_port,
+ .config_port = pl011_config_port,
+ .verify_port = pl011_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = pl011_hwinit,
+ .poll_get_char = pl011_get_poll_char,
+ .poll_put_char = pl011_put_poll_char,
+#endif
+};
+
static struct uart_amba_port *amba_ports[UART_NR];
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
@@ -1994,7 +2061,7 @@ static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int status, old_cr, new_cr;
+ unsigned int status, old_cr = 0, new_cr;
unsigned long flags;
int locked = 1;
@@ -2011,10 +2078,12 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
/*
* First save the CR then disable the interrupts
*/
- old_cr = readw(uap->port.membase + UART011_CR);
- new_cr = old_cr & ~UART011_CR_CTSEN;
- new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(new_cr, uap->port.membase + UART011_CR);
+ if (!uap->vendor->always_enabled) {
+ old_cr = readw(uap->port.membase + UART011_CR);
+ new_cr = old_cr & ~UART011_CR_CTSEN;
+ new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+ writew(new_cr, uap->port.membase + UART011_CR);
+ }
uart_console_write(&uap->port, s, count, pl011_console_putchar);
@@ -2025,7 +2094,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
do {
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_BUSY);
- writew(old_cr, uap->port.membase + UART011_CR);
+ if (!uap->vendor->always_enabled)
+ writew(old_cr, uap->port.membase + UART011_CR);
if (locked)
spin_unlock(&uap->port.lock);
@@ -2106,10 +2176,15 @@ static int __init pl011_console_setup(struct console *co, char *options)
uap->port.uartclk = clk_get_rate(uap->clk);
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
- else
- pl011_console_get_options(uap, &baud, &parity, &bits);
+ if (uap->vendor->fixed_options) {
+ baud = uap->fixed_baud;
+ } else {
+ if (options)
+ uart_parse_options(options,
+ &baud, &parity, &bits, &flow);
+ else
+ pl011_console_get_options(uap, &baud, &parity, &bits);
+ }
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
@@ -2201,97 +2276,126 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
return ret;
}
-static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+/* unregisters the driver also if no more ports are left */
+static void pl011_unregister_port(struct uart_amba_port *uap)
{
- struct uart_amba_port *uap;
- struct vendor_data *vendor = id->data;
- void __iomem *base;
- int i, ret;
+ int i;
+ bool busy = false;
+
+ for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
+ if (amba_ports[i] == uap)
+ amba_ports[i] = NULL;
+ else if (amba_ports[i])
+ busy = true;
+ }
+ pl011_dma_remove(uap);
+ if (!busy)
+ uart_unregister_driver(&amba_reg);
+}
+
+static int pl011_find_free_port(void)
+{
+ int i;
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == NULL)
- break;
-
- if (i == ARRAY_SIZE(amba_ports))
- return -EBUSY;
+ return i;
- uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
- GFP_KERNEL);
- if (uap == NULL)
- return -ENOMEM;
+ return -EBUSY;
+}
- i = pl011_probe_dt_alias(i, &dev->dev);
+static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
+ struct resource *mmiobase, int index)
+{
+ void __iomem *base;
- base = devm_ioremap(&dev->dev, dev->res.start,
- resource_size(&dev->res));
+ base = devm_ioremap_resource(dev, mmiobase);
if (!base)
return -ENOMEM;
- uap->clk = devm_clk_get(&dev->dev, NULL);
- if (IS_ERR(uap->clk))
- return PTR_ERR(uap->clk);
+ index = pl011_probe_dt_alias(index, dev);
- uap->vendor = vendor;
- uap->lcrh_rx = vendor->lcrh_rx;
- uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
- uap->fifosize = vendor->get_fifosize(dev);
- uap->port.dev = &dev->dev;
- uap->port.mapbase = dev->res.start;
+ uap->port.dev = dev;
+ uap->port.mapbase = mmiobase->start;
uap->port.membase = base;
uap->port.iotype = UPIO_MEM;
- uap->port.irq = dev->irq[0];
uap->port.fifosize = uap->fifosize;
- uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
- uap->port.line = i;
- INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
+ uap->port.line = index;
- /* Ensure interrupts from this UART are masked and cleared */
- writew(0, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ amba_ports[index] = uap;
- snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+ return 0;
+}
- amba_ports[i] = uap;
+static int pl011_register_port(struct uart_amba_port *uap)
+{
+ int ret;
- amba_set_drvdata(dev, uap);
+ /* Ensure interrupts from this UART are masked and cleared */
+ writew(0, uap->port.membase + UART011_IMSC);
+ writew(0xffff, uap->port.membase + UART011_ICR);
if (!amba_reg.state) {
ret = uart_register_driver(&amba_reg);
if (ret < 0) {
- dev_err(&dev->dev,
+ dev_err(uap->port.dev,
"Failed to register AMBA-PL011 driver\n");
return ret;
}
}
ret = uart_add_one_port(&amba_reg, &uap->port);
- if (ret) {
- amba_ports[i] = NULL;
- uart_unregister_driver(&amba_reg);
- }
+ if (ret)
+ pl011_unregister_port(uap);
return ret;
}
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+{
+ struct uart_amba_port *uap;
+ struct vendor_data *vendor = id->data;
+ int portnr, ret;
+
+ portnr = pl011_find_free_port();
+ if (portnr < 0)
+ return portnr;
+
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
+ if (!uap)
+ return -ENOMEM;
+
+ uap->clk = devm_clk_get(&dev->dev, NULL);
+ if (IS_ERR(uap->clk))
+ return PTR_ERR(uap->clk);
+
+ uap->vendor = vendor;
+ uap->lcrh_rx = vendor->lcrh_rx;
+ uap->lcrh_tx = vendor->lcrh_tx;
+ uap->fifosize = vendor->get_fifosize(dev);
+ uap->port.irq = dev->irq[0];
+ uap->port.ops = &amba_pl011_pops;
+
+ snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+
+ ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
+ if (ret)
+ return ret;
+
+ amba_set_drvdata(dev, uap);
+
+ return pl011_register_port(uap);
+}
+
static int pl011_remove(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
- bool busy = false;
- int i;
uart_remove_one_port(&amba_reg, &uap->port);
-
- for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
- if (amba_ports[i] == uap)
- amba_ports[i] = NULL;
- else if (amba_ports[i])
- busy = true;
-
- pl011_dma_remove(uap);
- if (!busy)
- uart_unregister_driver(&amba_reg);
+ pl011_unregister_port(uap);
return 0;
}
@@ -2319,6 +2423,86 @@ static int pl011_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
+static int sbsa_uart_probe(struct platform_device *pdev)
+{
+ struct uart_amba_port *uap;
+ struct resource *r;
+ int portnr, ret;
+ int baudrate;
+
+ /*
+ * Check the mandatory baud rate parameter in the DT node early
+ * so that we can easily exit with the error.
+ */
+ if (pdev->dev.of_node) {
+ struct device_node *np = pdev->dev.of_node;
+
+ ret = of_property_read_u32(np, "current-speed", &baudrate);
+ if (ret)
+ return ret;
+ } else {
+ baudrate = 115200;
+ }
+
+ portnr = pl011_find_free_port();
+ if (portnr < 0)
+ return portnr;
+
+ uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
+ if (!uap)
+ return -ENOMEM;
+
+ uap->vendor = &vendor_sbsa;
+ uap->fifosize = 32;
+ uap->port.irq = platform_get_irq(pdev, 0);
+ uap->port.ops = &sbsa_uart_pops;
+ uap->fixed_baud = baudrate;
+
+ snprintf(uap->type, sizeof(uap->type), "SBSA");
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, uap);
+
+ return pl011_register_port(uap);
+}
+
+static int sbsa_uart_remove(struct platform_device *pdev)
+{
+ struct uart_amba_port *uap = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&amba_reg, &uap->port);
+ pl011_unregister_port(uap);
+ return 0;
+}
+
+static const struct of_device_id sbsa_uart_of_match[] = {
+ { .compatible = "arm,sbsa-uart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
+
+static const struct acpi_device_id sbsa_uart_acpi_match[] = {
+ { "ARMH0011", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
+
+static struct platform_driver arm_sbsa_uart_platform_driver = {
+ .probe = sbsa_uart_probe,
+ .remove = sbsa_uart_remove,
+ .driver = {
+ .name = "sbsa-uart",
+ .of_match_table = of_match_ptr(sbsa_uart_of_match),
+ .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
+ },
+};
+
static struct amba_id pl011_ids[] = {
{
.id = 0x00041011,
@@ -2349,11 +2533,14 @@ static int __init pl011_init(void)
{
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
+ if (platform_driver_register(&arm_sbsa_uart_platform_driver))
+ pr_warn("could not register SBSA UART platform driver\n");
return amba_driver_register(&pl011_driver);
}
static void __exit pl011_exit(void)
{
+ platform_driver_unregister(&arm_sbsa_uart_platform_driver);
amba_driver_unregister(&pl011_driver);
}
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 27dade29646b..2a8f528153e7 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -165,6 +165,7 @@ struct atmel_uart_port {
struct tasklet_struct tasklet;
unsigned int irq_status;
unsigned int irq_status_prev;
+ unsigned int status_change;
struct circ_buf rx_ring;
@@ -315,8 +316,7 @@ static int atmel_config_rs485(struct uart_port *port,
if (rs485conf->flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
- if ((rs485conf->delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
+ UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else {
dev_dbg(port->dev, "Setting UART to RS232\n");
@@ -354,8 +354,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
/* override mode to RS485 if needed, otherwise keep the current mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
- if ((port->rs485.delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode &= ~ATMEL_US_USMODE;
mode |= ATMEL_US_USMODE_RS485;
}
@@ -1177,6 +1176,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
| ATMEL_US_CTSIC)) {
atmel_port->irq_status = status;
+ atmel_port->status_change = atmel_port->irq_status ^
+ atmel_port->irq_status_prev;
+ atmel_port->irq_status_prev = status;
tasklet_schedule(&atmel_port->tasklet);
}
}
@@ -1523,17 +1525,14 @@ static void atmel_tasklet_func(unsigned long data)
{
struct uart_port *port = (struct uart_port *)data;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- unsigned int status;
- unsigned int status_change;
+ unsigned int status = atmel_port->irq_status;
+ unsigned int status_change = atmel_port->status_change;
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
atmel_port->schedule_tx(port);
- status = atmel_port->irq_status;
- status_change = status ^ atmel_port->irq_status_prev;
-
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
| ATMEL_US_DCD | ATMEL_US_CTS)) {
/* TODO: All reads to CSR will clear these interrupts! */
@@ -1548,7 +1547,7 @@ static void atmel_tasklet_func(unsigned long data)
wake_up_interruptible(&port->state->port.delta_msr_wait);
- atmel_port->irq_status_prev = status;
+ atmel_port->status_change = 0;
}
atmel_port->schedule_rx(port);
@@ -2061,8 +2060,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
/* mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
- if ((port->rs485.delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 155781ece050..ae3cf94b146b 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
static void bfin_serial_reset_irda(struct uart_port *port);
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id;
struct uart_port *uport = &uart->port;
unsigned int status = bfin_serial_get_mctrl(uport);
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
UART_CLEAR_SCTS(uart);
if (uport->hw_stopped) {
@@ -700,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port)
# endif
#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) {
if (request_irq(gpio_to_irq(uart->cts_pin),
bfin_serial_mctrl_cts_int,
@@ -718,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port)
gpio_direction_output(uart->rts_pin, 0);
}
#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0) {
if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
0, "BFIN_UART_MODEM_STATUS", uart)) {
@@ -766,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port)
free_irq(uart->tx_irq, uart);
#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0)
free_irq(gpio_to_irq(uart->cts_pin), uart);
if (uart->rts_pin >= 0)
gpio_free(uart->rts_pin);
#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0)
free_irq(uart->status_irq, uart);
#endif
@@ -788,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int ier, lcr = 0;
unsigned long timeout;
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (old == NULL && uart->cts_pin != -1)
termios->c_cflag |= CRTSCTS;
else if (uart->cts_pin == -1)
@@ -1110,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options)
int baud = 57600;
int bits = 8;
int parity = 'n';
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+# if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
int flow = 'r';
# else
int flow = 'n';
@@ -1322,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev)
init_timer(&(uart->rx_dma_timer));
#endif
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
uart->cts_pin = -1;
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 0c1825b0b41d..3e4470af5c50 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $";
#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
-#endif
-
/*
* All of the compatibilty code so we can compile serial.c against
* older kernels is hidden in serial_compat.h
@@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = {
static struct fast_timer fast_timers[NR_PORTS];
#endif
-#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
-#define PROCSTAT(x) x
-struct ser_statistics_type {
- int overrun_cnt;
- int early_errors_cnt;
- int ser_ints_ok_cnt;
- int errors_cnt;
- unsigned long int processing_flip;
- unsigned long processing_flip_still_room;
- unsigned long int timeout_flush_cnt;
- int rx_dma_ints;
- int tx_dma_ints;
- int rx_tot;
- int tx_tot;
-};
-
-static struct ser_statistics_type ser_stat[NR_PORTS];
-
-#else
-
-#define PROCSTAT(x)
-
-#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
-
/* RS-485 */
#if defined(CONFIG_ETRAX_RS485)
#ifdef CONFIG_ETRAX_FAST_TIMER
@@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS];
#if defined(CONFIG_ETRAX_RS485_ON_PA)
static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
-#endif
#endif
/* Info and macros needed for each ports extra control/status signals. */
@@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
-#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED
#endif
-#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED
/* The pins can be mixed on PA and PB */
#define CONTROL_PINS_PORT_NOT_USED(line) \
&dummy_ser[line], &dummy_ser[line], \
@@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
#endif
}
};
-#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
/* All pins are on either PA or PB for each serial port */
#define CONTROL_PINS_PORT_NOT_USED(line) \
@@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
#endif
}
};
-#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
#define E100_RTS_MASK 0x20
#define E100_CTS_MASK 0x40
@@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- rs485_port_g_bit, 1);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
-#endif
info->rs485 = *r;
@@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size)
{
struct etrax_recv_buffer *buffer;
- if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+ buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC);
+ if (!buffer)
return NULL;
buffer->next = NULL;
@@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl
{
struct etrax_recv_buffer *buffer;
if (info->uses_dma_in) {
- if (!(buffer = alloc_recv_buffer(4)))
+ buffer = alloc_recv_buffer(4);
+ if (!buffer)
return 0;
buffer->length = 1;
@@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info,
append_recv_buffer(info, buffer);
- if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
+ if (!buffer)
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr->buf = virt_to_phys(buffer->buffer);
@@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info)
*/
unsigned char data = info->ioport[REG_DATA];
- PROCSTAT(ser_stat[info->line].errors_cnt++);
DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
@@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info)
/* Set up the receiving descriptors */
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
- if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
+ if (!buffer)
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr[i].ctrl = d_int;
@@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id)
/* Read jiffies_usec first,
* we want this time to be as late as possible
*/
- PROCSTAT(ser_stat[info->line].tx_dma_ints++);
info->last_tx_active_usec = GET_JIFFIES_USEC();
info->last_tx_active = jiffies;
transmit_chars_dma(info);
@@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info)
*/
if (!info->forced_eop) {
info->forced_eop = 1;
- PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
FORCE_EOP(info);
}
@@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
DEBUG_LOG(info->line, "#iERR s d %04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
}
- PROCSTAT(ser_stat[info->line].early_errors_cnt++);
} else { /* It was a valid byte, now let the DMA do the rest */
unsigned long curr_time_u = GET_JIFFIES_USEC();
unsigned long curr_time = jiffies;
@@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
info->break_detected_cnt = 0;
- PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
}
/* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
@@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info)
*R_SERIAL_PRESCALE = divisor;
info->baud = SERIAL_PRESCALE_BASE/divisor;
}
-#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
- else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
- info->custom_divisor == 1) ||
- (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
- info->custom_divisor == 8)) {
- /* ext_clk selected */
- alt_source =
- IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
- IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
- DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
- info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
- }
-#endif
else
{
/* Bad baudbase, we don't support using timer0
@@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %lu....\n", tty_name(tty, buf),
+ printk("throttle %s: %lu....\n", tty_name(tty),
(unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
@@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+ printk("unthrottle %s: %lu....\n", tty_name(tty),
(unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
@@ -3725,16 +3666,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- rs485_port_g_bit, 0);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
-#endif
}
#endif
@@ -4263,15 +4194,6 @@ static int __init rs_init(void)
return -EBUSY;
}
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
- rs485_port_g_bit)) {
- printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
- "RS485 pin\n");
- put_tty_driver(driver);
- return -EBUSY;
- }
-#endif
#endif
/* Initialize the tty_driver structure */
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 6dc471e30e79..f09636083426 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -72,6 +72,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
switch (port->iotype) {
case UPIO_MEM32:
+ case UPIO_MEM32BE:
port->regshift = 2; /* fall-through */
case UPIO_MEM:
port->mapbase = addr;
@@ -90,9 +91,11 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32)
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 ||
+ port->iotype == UPIO_MEM32BE)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- (port->iotype == UPIO_MEM32) ? "32" : "",
+ (port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM32) ? "32" : "32be",
(unsigned long long)port->mapbase,
device->options);
else
@@ -133,7 +136,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
*
* Registers the earlycon console matching the earlycon specified
* in the param string @buf. Acceptable param strings are of the form
- * <name>,io|mmio|mmio32,<addr>,<options>
+ * <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
* <name>,0x<addr>,<options>
* <name>,<options>
* <name>
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 45fc323b95e6..ffc7cb2585a6 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev,
return retval;
}
- if ( (retval = pci_request_regions(dev, "icom"))) {
+ retval = pci_request_regions(dev, "icom");
+ if (retval) {
dev_err(&dev->dev, "pci_request_regions FAILED\n");
pci_disable_device(dev);
return retval;
@@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev,
pci_set_master(dev);
- if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
+ retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
+ if (retval) {
dev_err(&dev->dev, "PCI Config read FAILED\n");
return retval;
}
@@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev,
}
/* save off irq and request irq line */
- if ( (retval = request_irq(dev->irq, icom_interrupt,
- IRQF_SHARED, ICOM_DRIVER_NAME,
- (void *) icom_adapter))) {
+ retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
+ if (retval) {
goto probe_exit2;
}
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 590390970996..536a33b99be9 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
ifx_spi_reset_interrupt,
IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
- (void *)ifx_dev);
+ ifx_dev);
if (ret) {
dev_err(&spi->dev, "Unable to get irq %x\n",
gpio_to_irq(ifx_dev->gpio.reset_out));
@@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = ifx_spi_reset(ifx_dev);
ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
- ifx_spi_srdy_interrupt,
- IRQF_TRIGGER_RISING, DRVNAME,
- (void *)ifx_dev);
+ ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME,
+ ifx_dev);
if (ret) {
dev_err(&spi->dev, "Unable to get irq %x",
gpio_to_irq(ifx_dev->gpio.srdy));
@@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
return 0;
error_ret7:
- free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
error_ret6:
gpio_free(ifx_dev->gpio.srdy);
error_ret5:
@@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
/* stop activity */
tasklet_kill(&ifx_dev->io_work_tasklet);
/* free irq */
- free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
- free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
gpio_free(ifx_dev->gpio.srdy);
gpio_free(ifx_dev->gpio.mrdy);
@@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void)
/* unregister */
tty_unregister_driver(tty_drv);
put_tty_driver(tty_drv);
- spi_unregister_driver((void *)&ifx_spi_driver);
+ spi_unregister_driver(&ifx_spi_driver);
unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
}
@@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void)
goto err_free_tty;
}
- result = spi_register_driver((void *)&ifx_spi_driver);
+ result = spi_register_driver(&ifx_spi_driver);
if (result) {
pr_err("%s: spi_register_driver failed(%d)",
DRVNAME, result);
@@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void)
return 0;
err_unreg_spi:
- spi_unregister_driver((void *)&ifx_spi_driver);
+ spi_unregister_driver(&ifx_spi_driver);
err_unreg_tty:
tty_unregister_driver(tty_drv);
err_free_tty:
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 88250395b0ce..2c90dc31bfaa 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -239,7 +239,7 @@ static struct imx_uart_data imx_uart_devdata[] = {
},
};
-static struct platform_device_id imx_uart_devtype[] = {
+static const struct platform_device_id imx_uart_devtype[] = {
{
.name = "imx1-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
@@ -853,7 +853,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
#define TXTL 2 /* reset default */
#define RXTL 1 /* reset default */
-static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
{
unsigned int val;
@@ -861,7 +861,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
val |= TXTL << UFCR_TXTL_SHF | RXTL;
writel(val, sport->port.membase + UFCR);
- return 0;
}
#define RX_BUF_SIZE (PAGE_SIZE)
@@ -1122,6 +1121,12 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+ /* Can we enable the DMA support? */
+ if (is_imx6q_uart(sport) && !uart_console(port) &&
+ !sport->dma_is_inited)
+ imx_uart_dma_init(sport);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
/* Reset fifo's and state machines */
i = 100;
@@ -1132,13 +1137,6 @@ static int imx_startup(struct uart_port *port)
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
- /* Can we enable the DMA support? */
- if (is_imx6q_uart(sport) && !uart_console(port) &&
- !sport->dma_is_inited)
- imx_uart_dma_init(sport);
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
/*
* Finally, clear and enable interrupts
*/
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index abd7ea26ed9a..27b5fefac171 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
/* register port with the serial core */
- if ((ret = ioc3_serial_core_attach(is, idd)))
+ ret = ioc3_serial_core_attach(is, idd);
+ if (ret)
goto out4;
Num_of_ioc3_cards++;
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index aa28209f44c1..e5c42fef69d2 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
*/
for (xx = 0; xx < num_intrs; xx++) {
intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
- if ((this_mir = this_ir & intr_info->sd_bits)) {
+ this_mir = this_ir & intr_info->sd_bits;
+ if (this_mir) {
/* Disable owned interrupts, call handler */
handled++;
write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
@@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
/* register port with the serial core - 1 rs232, 1 rs422 */
- if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
+ ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232);
+ if (ret)
goto out4;
- if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+ ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422);
+ if (ret)
goto out5;
Num_of_ioc4_cards++;
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 129dc5be6028..117df151627d 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void)
bool kgdb_nmi_poll_knock(void)
{
if (kgdb_nmi_knock < 0)
- return 1;
+ return true;
while (1) {
int ret;
ret = kgdb_nmi_poll_one_knock();
if (ret == NO_POLL_CHAR)
- return 0;
+ return false;
else if (ret == 1)
break;
}
- return 1;
+ return true;
}
/*
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index a9b0ab38a68c..02eb32217685 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -597,7 +597,7 @@ console_initcall(mcf_console_init);
#define MCF_CONSOLE NULL
/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
+#endif /* CONFIG_SERIAL_MCF_CONSOLE */
/****************************************************************************/
/*
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 67c036702629..0fc83c962d10 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port,
static void meson_uart_release_port(struct uart_port *port)
{
if (port->flags & UPF_IOREMAP) {
- iounmap(port->membase);
+ devm_iounmap(port->dev, port->membase);
port->membase = NULL;
}
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 1589f17c1fca..6fc07eb9d74e 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -405,7 +405,7 @@ static struct psc_ops mpc5200b_psc_ops = {
.get_mr1 = mpc52xx_psc_get_mr1,
};
-#endif /* CONFIG_MPC52xx */
+#endif /* CONFIG_PPC_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index 856fd5a5fa3c..82bb6d1fe23b 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -913,7 +913,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi)
if (!pi->ready) {
mpsc_init_hw(pi);
- if ((rc = mpsc_alloc_ring_mem(pi)))
+ rc = mpsc_alloc_ring_mem(pi);
+ if (rc)
return rc;
mpsc_init_rings(pi);
pi->ready = 1;
@@ -1895,7 +1896,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev)
int rc = -ENODEV;
if (dev->id == 0) {
- if (!(rc = mpsc_shared_map_regs(dev))) {
+ rc = mpsc_shared_map_regs(dev);
+ if (!rc) {
pdata = (struct mpsc_shared_pdata *)
dev_get_platdata(&dev->dev);
@@ -2081,14 +2083,16 @@ static int mpsc_drv_probe(struct platform_device *dev)
if (dev->id < MPSC_NUM_CTLRS) {
pi = &mpsc_ports[dev->id];
- if (!(rc = mpsc_drv_map_regs(pi, dev))) {
+ rc = mpsc_drv_map_regs(pi, dev);
+ if (!rc) {
mpsc_drv_get_platform_data(pi, dev, dev->id);
pi->port.dev = &dev->dev;
- if (!(rc = mpsc_make_ready(pi))) {
+ rc = mpsc_make_ready(pi);
+ if (!rc) {
spin_lock_init(&pi->tx_lock);
- if (!(rc = uart_add_one_port(&mpsc_reg,
- &pi->port))) {
+ rc = uart_add_one_port(&mpsc_reg, &pi->port);
+ if (!rc) {
rc = 0;
} else {
mpsc_release_port((struct uart_port *)
@@ -2136,9 +2140,12 @@ static int __init mpsc_drv_init(void)
memset(mpsc_ports, 0, sizeof(mpsc_ports));
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
- if (!(rc = uart_register_driver(&mpsc_reg))) {
- if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
- if ((rc = platform_driver_register(&mpsc_driver))) {
+ rc = uart_register_driver(&mpsc_reg);
+ if (!rc) {
+ rc = platform_driver_register(&mpsc_shared_driver);
+ if (!rc) {
+ rc = platform_driver_register(&mpsc_driver);
+ if (rc) {
platform_driver_unregister(&mpsc_shared_driver);
uart_unregister_driver(&mpsc_reg);
}
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
deleted file mode 100644
index 1238ac370bff..000000000000
--- a/drivers/tty/serial/msm_smd_tty.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- * Author: Brian Swetland <swetland@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/module.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-
-#include <mach/msm_smd.h>
-
-#define MAX_SMD_TTYS 32
-
-struct smd_tty_info {
- struct tty_port port;
- smd_channel_t *ch;
-};
-
-struct smd_tty_channel_desc {
- int id;
- const char *name;
-};
-
-static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
-
-static const struct smd_tty_channel_desc smd_default_tty_channels[] = {
- { .id = 0, .name = "SMD_DS" },
- { .id = 27, .name = "SMD_GPSNMEA" },
-};
-
-static const struct smd_tty_channel_desc *smd_tty_channels =
- smd_default_tty_channels;
-static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels);
-
-static void smd_tty_notify(void *priv, unsigned event)
-{
- unsigned char *ptr;
- int avail;
- struct smd_tty_info *info = priv;
- struct tty_struct *tty;
-
- if (event != SMD_EVENT_DATA)
- return;
-
- tty = tty_port_tty_get(&info->port);
- if (!tty)
- return;
-
- for (;;) {
- if (test_bit(TTY_THROTTLED, &tty->flags))
- break;
- avail = smd_read_avail(info->ch);
- if (avail == 0)
- break;
-
- avail = tty_prepare_flip_string(&info->port, &ptr, avail);
-
- if (smd_read(info->ch, ptr, avail) != avail) {
- /* shouldn't be possible since we're in interrupt
- ** context here and nobody else could 'steal' our
- ** characters.
- */
- pr_err("OOPS - smd_tty_buffer mismatch?!");
- }
-
- tty_flip_buffer_push(&info->port);
- }
-
- /* XXX only when writable and necessary */
- tty_wakeup(tty);
- tty_kref_put(tty);
-}
-
-static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
-{
- struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
- port);
- int i, res = 0;
- const char *name = NULL;
-
- for (i = 0; i < smd_tty_channels_len; i++) {
- if (smd_tty_channels[i].id == tty->index) {
- name = smd_tty_channels[i].name;
- break;
- }
- }
- if (!name)
- return -ENODEV;
-
- if (info->ch)
- smd_kick(info->ch);
- else
- res = smd_open(name, &info->ch, info, smd_tty_notify);
-
- if (!res)
- tty->driver_data = info;
-
- return res;
-}
-
-static void smd_tty_port_shutdown(struct tty_port *tport)
-{
- struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
- port);
-
- if (info->ch) {
- smd_close(info->ch);
- info->ch = 0;
- }
-}
-
-static int smd_tty_open(struct tty_struct *tty, struct file *f)
-{
- struct smd_tty_info *info = smd_tty + tty->index;
-
- return tty_port_open(&info->port, tty, f);
-}
-
-static void smd_tty_close(struct tty_struct *tty, struct file *f)
-{
- struct smd_tty_info *info = tty->driver_data;
-
- tty_port_close(&info->port, tty, f);
-}
-
-static int smd_tty_write(struct tty_struct *tty,
- const unsigned char *buf, int len)
-{
- struct smd_tty_info *info = tty->driver_data;
- int avail;
-
- /* if we're writing to a packet channel we will
- ** never be able to write more data than there
- ** is currently space for
- */
- avail = smd_write_avail(info->ch);
- if (len > avail)
- len = avail;
-
- return smd_write(info->ch, buf, len);
-}
-
-static int smd_tty_write_room(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- return smd_write_avail(info->ch);
-}
-
-static int smd_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- return smd_read_avail(info->ch);
-}
-
-static void smd_tty_unthrottle(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- smd_kick(info->ch);
-}
-
-static const struct tty_port_operations smd_tty_port_ops = {
- .shutdown = smd_tty_port_shutdown,
- .activate = smd_tty_port_activate,
-};
-
-static const struct tty_operations smd_tty_ops = {
- .open = smd_tty_open,
- .close = smd_tty_close,
- .write = smd_tty_write,
- .write_room = smd_tty_write_room,
- .chars_in_buffer = smd_tty_chars_in_buffer,
- .unthrottle = smd_tty_unthrottle,
-};
-
-static struct tty_driver *smd_tty_driver;
-
-static int __init smd_tty_init(void)
-{
- int ret, i;
-
- smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
- if (smd_tty_driver == 0)
- return -ENOMEM;
-
- smd_tty_driver->driver_name = "smd_tty_driver";
- smd_tty_driver->name = "smd";
- smd_tty_driver->major = 0;
- smd_tty_driver->minor_start = 0;
- smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- smd_tty_driver->init_termios = tty_std_termios;
- smd_tty_driver->init_termios.c_iflag = 0;
- smd_tty_driver->init_termios.c_oflag = 0;
- smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
- smd_tty_driver->init_termios.c_lflag = 0;
- smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(smd_tty_driver, &smd_tty_ops);
-
- ret = tty_register_driver(smd_tty_driver);
- if (ret)
- return ret;
-
- for (i = 0; i < smd_tty_channels_len; i++) {
- struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
- tty_port_init(port);
- port->ops = &smd_tty_port_ops;
- tty_port_register_device(port, smd_tty_driver,
- smd_tty_channels[i].id, NULL);
- }
-
- return 0;
-}
-
-module_init(smd_tty_init);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index f7e5825b55ab..13cf7738fbdc 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -169,7 +169,7 @@ struct mxs_auart_port {
bool ms_irq_enabled;
};
-static struct platform_device_id mxs_auart_devtype[] = {
+static const struct platform_device_id mxs_auart_devtype[] = {
{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
{ /* sentinel */ }
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 137381e649e5..6823df99bd76 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -67,14 +67,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_property_read_u32(np, "clock-frequency", &clk)) {
/* Get clk rate through clk driver if present */
- info->clk = clk_get(&ofdev->dev, NULL);
+ info->clk = devm_clk_get(&ofdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_warn(&ofdev->dev,
"clk or clock-frequency not defined\n");
return PTR_ERR(info->clk);
}
- clk_prepare_enable(info->clk);
+ ret = clk_prepare_enable(info->clk);
+ if (ret < 0)
+ return ret;
+
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -188,7 +191,6 @@ 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)
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index a0ae942d9562..67d0c213b1c7 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -348,7 +348,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
s3c24xx_serial_start_tx_dma(ourport, count);
}
-void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct circ_buf *xmit = &port->state->xmit;
@@ -2337,7 +2337,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
#endif
-static struct platform_device_id s3c24xx_serial_driver_ids[] = {
+static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
{
.name = "s3c2410-uart",
.driver_data = S3C2410_SERIAL_DRV_DATA,
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 468354ef7baa..9e6576004a42 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -25,6 +25,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
#include <linux/uaccess.h>
#define SC16IS7XX_NAME "sc16is7xx"
@@ -300,25 +301,38 @@ struct sc16is7xx_devtype {
int nr_uart;
};
+#define SC16IS7XX_RECONF_MD (1 << 0)
+#define SC16IS7XX_RECONF_IER (1 << 1)
+#define SC16IS7XX_RECONF_RS485 (1 << 2)
+
+struct sc16is7xx_one_config {
+ unsigned int flags;
+ u8 ier_clear;
+};
+
struct sc16is7xx_one {
struct uart_port port;
- struct work_struct tx_work;
- struct work_struct md_work;
+ struct kthread_work tx_work;
+ struct kthread_work reg_work;
+ struct sc16is7xx_one_config config;
};
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 kthread_worker kworker;
+ struct task_struct *kworker_task;
+ struct kthread_work irq_work;
struct sc16is7xx_one p[0];
};
+#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e)))
#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
@@ -615,9 +629,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
!!(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,
@@ -628,81 +640,115 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
} while (1);
}
-static irqreturn_t sc16is7xx_ist(int irq, void *dev_id)
+static void sc16is7xx_ist(struct kthread_work *ws)
{
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+ struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
int i;
for (i = 0; i < s->uart.nr; ++i)
sc16is7xx_port_irq(s, i);
+}
+
+static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
+{
+ struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+
+ queue_kthread_work(&s->kworker, &s->irq_work);
return IRQ_HANDLED;
}
-static void sc16is7xx_wq_proc(struct work_struct *ws)
+static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work);
- struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
+ struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
+
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ (port->rs485.delay_rts_before_send > 0))
+ msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&s->mutex);
- sc16is7xx_handle_tx(&one->port);
- mutex_unlock(&s->mutex);
+ sc16is7xx_handle_tx(port);
}
-static void sc16is7xx_stop_tx(struct uart_port* port)
+static void sc16is7xx_reconf_rs485(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- struct circ_buf *xmit = &one->port.state->xmit;
-
- /* handle rs485 */
- if (port->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) &&
- (port->rs485.delay_rts_after_send > 0))
- mdelay(port->rs485.delay_rts_after_send);
+ const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
+ SC16IS7XX_EFCR_RTS_INVERT_BIT;
+ u32 efcr = 0;
+ struct serial_rs485 *rs485 = &port->rs485;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&port->lock, irqflags);
+ if (rs485->flags & SER_RS485_ENABLED) {
+ efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
+
+ if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+ efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
}
+ spin_unlock_irqrestore(&port->lock, irqflags);
- sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
- SC16IS7XX_IER_THRI_BIT,
- 0);
+ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
}
-static void sc16is7xx_stop_rx(struct uart_port* port)
+static void sc16is7xx_reg_proc(struct kthread_work *ws)
{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work);
+ struct sc16is7xx_one_config config;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&one->port.lock, irqflags);
+ config = one->config;
+ memset(&one->config, 0, sizeof(one->config));
+ spin_unlock_irqrestore(&one->port.lock, irqflags);
+
+ if (config.flags & SC16IS7XX_RECONF_MD)
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_LOOP_BIT,
+ (one->port.mctrl & TIOCM_LOOP) ?
+ SC16IS7XX_MCR_LOOP_BIT : 0);
+
+ if (config.flags & SC16IS7XX_RECONF_IER)
+ sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
+ config.ier_clear, 0);
+
+ if (config.flags & SC16IS7XX_RECONF_RS485)
+ sc16is7xx_reconf_rs485(&one->port);
+}
+
+static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
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);
+ one->config.flags |= SC16IS7XX_RECONF_IER;
+ one->config.ier_clear |= bit;
+ queue_kthread_work(&s->kworker, &one->reg_work);
+}
+
+static void sc16is7xx_stop_tx(struct uart_port *port)
+{
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT);
+}
+
+static void sc16is7xx_stop_rx(struct uart_port *port)
+{
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
}
static void sc16is7xx_start_tx(struct uart_port *port)
{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- /* handle rs485 */
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- (port->rs485.delay_rts_before_send > 0)) {
- mdelay(port->rs485.delay_rts_before_send);
- }
-
- if (!work_pending(&one->tx_work))
- schedule_work(&one->tx_work);
+ queue_kthread_work(&s->kworker, &one->tx_work);
}
static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
{
- unsigned int lvl, lsr;
+ unsigned int 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;
+ return (lsr & SC16IS7XX_LSR_TEMT_BIT) ? TIOCSER_TEMT : 0;
}
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
@@ -713,21 +759,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
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_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- schedule_work(&one->md_work);
+ one->config.flags |= SC16IS7XX_RECONF_MD;
+ queue_kthread_work(&s->kworker, &one->reg_work);
}
static void sc16is7xx_break_ctl(struct uart_port *port, int break_state)
@@ -831,9 +869,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
static int sc16is7xx_config_rs485(struct uart_port *port,
struct serial_rs485 *rs485)
{
- const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
- SC16IS7XX_EFCR_RTS_INVERT_BIT;
- u32 efcr = 0;
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
if (rs485->flags & SER_RS485_ENABLED) {
bool rts_during_rx, rts_during_tx;
@@ -841,21 +878,23 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND;
rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND;
- efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
-
- if (!rts_during_rx && rts_during_tx)
- /* default */;
- else if (rts_during_rx && !rts_during_tx)
- efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
- else
+ if (rts_during_rx == rts_during_tx)
dev_err(port->dev,
"unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n",
rts_during_tx, rts_during_rx);
- }
- sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
+ /*
+ * RTS signal is handled by HW, it's timing can't be influenced.
+ * However, it's sometimes useful to delay TX even without RTS
+ * control therefore we try to handle .delay_rts_before_send.
+ */
+ if (rs485->delay_rts_after_send)
+ return -EINVAL;
+ }
port->rs485 = *rs485;
+ one->config.flags |= SC16IS7XX_RECONF_RS485;
+ queue_kthread_work(&s->kworker, &one->reg_work);
return 0;
}
@@ -916,6 +955,8 @@ static int sc16is7xx_startup(struct uart_port *port)
static void sc16is7xx_shutdown(struct uart_port *port)
{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+
/* Disable all interrupts */
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
/* Disable TX/RX */
@@ -926,6 +967,8 @@ static void sc16is7xx_shutdown(struct uart_port *port)
SC16IS7XX_EFCR_TXDISABLE_BIT);
sc16is7xx_power(port, 0);
+
+ flush_kthread_worker(&s->kworker);
}
static const char *sc16is7xx_type(struct uart_port *port)
@@ -1043,6 +1086,7 @@ static int sc16is7xx_probe(struct device *dev,
struct sc16is7xx_devtype *devtype,
struct regmap *regmap, int irq, unsigned long flags)
{
+ struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
unsigned long freq, *pfreq = dev_get_platdata(dev);
int i, ret;
struct sc16is7xx_port *s;
@@ -1084,6 +1128,16 @@ static int sc16is7xx_probe(struct device *dev,
goto out_clk;
}
+ init_kthread_worker(&s->kworker);
+ init_kthread_work(&s->irq_work, sc16is7xx_ist);
+ s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
+ "sc16is7xx");
+ if (IS_ERR(s->kworker_task)) {
+ ret = PTR_ERR(s->kworker_task);
+ goto out_uart;
+ }
+ sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param);
+
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
@@ -1099,12 +1153,10 @@ static int sc16is7xx_probe(struct device *dev,
s->gpio.can_sleep = 1;
ret = gpiochip_add(&s->gpio);
if (ret)
- goto out_uart;
+ goto out_thread;
}
#endif
- mutex_init(&s->mutex);
-
for (i = 0; i < devtype->nr_uart; ++i) {
/* Initialize port data */
s->p[i].port.line = i;
@@ -1123,10 +1175,9 @@ static int sc16is7xx_probe(struct device *dev,
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);
+ /* Initialize kthread work structs */
+ init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
+ init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
/* Register port */
uart_add_one_port(&s->uart, &s->p[i].port);
/* Go to suspend mode */
@@ -1134,22 +1185,23 @@ static int sc16is7xx_probe(struct device *dev,
}
/* Setup interrupt */
- ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist,
- IRQF_ONESHOT | flags, dev_name(dev), s);
+ ret = devm_request_irq(dev, irq, sc16is7xx_irq,
+ IRQF_ONESHOT | flags, dev_name(dev), s);
if (!ret)
return 0;
for (i = 0; i < s->uart.nr; i++)
uart_remove_one_port(&s->uart, &s->p[i].port);
- mutex_destroy(&s->mutex);
-
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio)
gpiochip_remove(&s->gpio);
-out_uart:
+out_thread:
#endif
+ kthread_stop(s->kworker_task);
+
+out_uart:
uart_unregister_driver(&s->uart);
out_clk:
@@ -1170,13 +1222,13 @@ static int sc16is7xx_remove(struct device *dev)
#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);
+ flush_kthread_worker(&s->kworker);
+ kthread_stop(s->kworker_task);
+
uart_unregister_driver(&s->uart);
if (!IS_ERR(s->clk))
clk_disable_unprepare(s->clk);
@@ -1204,6 +1256,75 @@ static struct regmap_config regcfg = {
.precious_reg = sc16is7xx_regmap_precious,
};
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+static int sc16is7xx_spi_probe(struct spi_device *spi)
+{
+ struct sc16is7xx_devtype *devtype;
+ unsigned long flags = 0;
+ struct regmap *regmap;
+ int ret;
+
+ /* Setup SPI bus */
+ spi->bits_per_word = 8;
+ /* only supports mode 0 on SC16IS762 */
+ spi->mode = spi->mode ? : SPI_MODE_0;
+ spi->max_speed_hz = spi->max_speed_hz ? : 15000000;
+ ret = spi_setup(spi);
+ if (ret)
+ return ret;
+
+ if (spi->dev.of_node) {
+ const struct of_device_id *of_id =
+ of_match_device(sc16is7xx_dt_ids, &spi->dev);
+
+ devtype = (struct sc16is7xx_devtype *)of_id->data;
+ } else {
+ const struct spi_device_id *id_entry = spi_get_device_id(spi);
+
+ devtype = (struct sc16is7xx_devtype *)id_entry->driver_data;
+ flags = IRQF_TRIGGER_FALLING;
+ }
+
+ regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
+ (devtype->nr_uart - 1);
+ regmap = devm_regmap_init_spi(spi, &regcfg);
+
+ return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags);
+}
+
+static int sc16is7xx_spi_remove(struct spi_device *spi)
+{
+ return sc16is7xx_remove(&spi->dev);
+}
+
+static const struct spi_device_id sc16is7xx_spi_id_table[] = {
+ { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (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(spi, sc16is7xx_spi_id_table);
+
+static struct spi_driver sc16is7xx_spi_uart_driver = {
+ .driver = {
+ .name = SC16IS7XX_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sc16is7xx_dt_ids),
+ },
+ .probe = sc16is7xx_spi_probe,
+ .remove = sc16is7xx_spi_remove,
+ .id_table = sc16is7xx_spi_id_table,
+};
+
+MODULE_ALIAS("spi:sc16is7xx");
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1235,6 +1356,8 @@ static int sc16is7xx_i2c_remove(struct i2c_client *client)
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
@@ -1253,8 +1376,43 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
.remove = sc16is7xx_i2c_remove,
.id_table = sc16is7xx_i2c_id_table,
};
-module_i2c_driver(sc16is7xx_i2c_uart_driver);
+
MODULE_ALIAS("i2c:sc16is7xx");
+#endif
+
+static int __init sc16is7xx_init(void)
+{
+ int ret = 0;
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
+ ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
+ if (ret < 0) {
+ pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
+ return ret;
+ }
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+ ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
+ if (ret < 0) {
+ pr_err("failed to init sc16is7xx spi --> %d\n", ret);
+ return ret;
+ }
+#endif
+ return ret;
+}
+module_init(sc16is7xx_init);
+
+static void __exit sc16is7xx_exit(void)
+{
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
+ i2c_del_driver(&sc16is7xx_i2c_uart_driver);
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+ spi_unregister_driver(&sc16is7xx_spi_uart_driver);
+#endif
+}
+module_exit(sc16is7xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 1d5ea3964ee5..cf0133ae762d 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -131,8 +131,8 @@ struct tegra_uart_port {
struct dma_async_tx_descriptor *rx_dma_desc;
dma_cookie_t tx_cookie;
dma_cookie_t rx_cookie;
- int tx_bytes_requested;
- int rx_bytes_requested;
+ unsigned int tx_bytes_requested;
+ unsigned int rx_bytes_requested;
};
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup);
@@ -234,6 +234,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
tup->lcr_shadow = lcr;
}
+/**
+ * tegra_uart_wait_cycle_time: Wait for N UART clock periods
+ *
+ * @tup: Tegra serial port data structure.
+ * @cycles: Number of clock periods to wait.
+ *
+ * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART
+ * clock speed is 16X the current baud rate.
+ */
+static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup,
+ unsigned int cycles)
+{
+ if (tup->current_baud)
+ udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16));
+}
+
/* Wait for a symbol-time. */
static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup,
unsigned int syms)
@@ -263,8 +279,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits)
/* Dummy read to ensure the write is posted */
tegra_uart_read(tup, UART_SCR);
- /* Wait for the flush to propagate. */
- tegra_uart_wait_sym_time(tup, 1);
+ /*
+ * For all tegra devices (up to t210), there is a hardware issue that
+ * requires software to wait for 32 UART clock periods for the flush
+ * to propagate, otherwise data could be lost.
+ */
+ tegra_uart_wait_cycle_time(tup, 32);
}
static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud)
@@ -388,9 +408,9 @@ static void tegra_uart_tx_dma_complete(void *args)
struct circ_buf *xmit = &tup->uport.state->xmit;
struct dma_tx_state state;
unsigned long flags;
- int count;
+ unsigned int count;
- dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state);
+ dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
count = tup->tx_bytes_requested - state.residue;
async_tx_ack(tup->tx_dma_desc);
spin_lock_irqsave(&tup->uport.lock, flags);
@@ -480,7 +500,7 @@ static void tegra_uart_stop_tx(struct uart_port *u)
struct tegra_uart_port *tup = to_tegra_uport(u);
struct circ_buf *xmit = &tup->uport.state->xmit;
struct dma_tx_state state;
- int count;
+ unsigned int count;
if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
return;
@@ -530,10 +550,15 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
}
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
- struct tty_port *tty, int count)
+ struct tty_port *tty,
+ unsigned int count)
{
int copied;
+ /* If count is zero, then there is no data to be copied */
+ if (!count)
+ return;
+
tup->uport.icount.rx += count;
if (!tty) {
dev_err(tup->uport.dev, "No tty port\n");
@@ -555,21 +580,30 @@ static void tegra_uart_rx_dma_complete(void *args)
{
struct tegra_uart_port *tup = args;
struct uart_port *u = &tup->uport;
- int count = tup->rx_bytes_requested;
+ unsigned int count = tup->rx_bytes_requested;
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &u->state->port;
unsigned long flags;
+ struct dma_tx_state state;
+ enum dma_status status;
- async_tx_ack(tup->rx_dma_desc);
spin_lock_irqsave(&u->lock, flags);
+ status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+
+ if (status == DMA_IN_PROGRESS) {
+ dev_dbg(tup->uport.dev, "RX DMA is in progress\n");
+ goto done;
+ }
+
+ async_tx_ack(tup->rx_dma_desc);
+
/* Deactivate flow control to stop sender */
if (tup->rts_active)
set_rts(tup, false);
/* If we are here, DMA is stopped */
- if (count)
- tegra_uart_copy_rx_to_tty(tup, port, count);
+ tegra_uart_copy_rx_to_tty(tup, port, count);
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
@@ -584,6 +618,7 @@ static void tegra_uart_rx_dma_complete(void *args)
if (tup->rts_active)
set_rts(tup, true);
+done:
spin_unlock_irqrestore(&u->lock, flags);
}
@@ -594,7 +629,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
struct uart_port *u = &tup->uport;
- int count;
+ unsigned int count;
/* Deactivate flow control to stop sender */
if (tup->rts_active)
@@ -606,8 +641,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
count = tup->rx_bytes_requested - state.residue;
/* If we are here, DMA is stopped */
- if (count)
- tegra_uart_copy_rx_to_tty(tup, port, count);
+ tegra_uart_copy_rx_to_tty(tup, port, count);
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
@@ -865,6 +899,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
+ /* Dummy read to ensure the write is posted */
+ tegra_uart_read(tup, UART_SCR);
+
+ /*
+ * For all tegra devices (up to t210), there is a hardware issue that
+ * requires software to wait for 3 UART clock periods after enabling
+ * the TX fifo, otherwise data could be lost.
+ */
+ tegra_uart_wait_cycle_time(tup, 3);
+
/*
* Initialize the UART with default configuration
* (115200, N, 8, 1) so that the receive DMA buffer may be
@@ -905,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
return 0;
}
+static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
+ bool dma_to_memory)
+{
+ if (dma_to_memory) {
+ dmaengine_terminate_all(tup->rx_dma_chan);
+ dma_release_channel(tup->rx_dma_chan);
+ dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
+ tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
+ tup->rx_dma_chan = NULL;
+ tup->rx_dma_buf_phys = 0;
+ tup->rx_dma_buf_virt = NULL;
+ } else {
+ dmaengine_terminate_all(tup->tx_dma_chan);
+ dma_release_channel(tup->tx_dma_chan);
+ dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ tup->tx_dma_chan = NULL;
+ tup->tx_dma_buf_phys = 0;
+ tup->tx_dma_buf_virt = NULL;
+ }
+}
+
static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
bool dma_to_memory)
{
@@ -933,67 +999,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
dma_release_channel(dma_chan);
return -ENOMEM;
}
+ dma_sconfig.src_addr = tup->uport.mapbase;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.src_maxburst = 4;
+ tup->rx_dma_chan = dma_chan;
+ tup->rx_dma_buf_virt = dma_buf;
+ tup->rx_dma_buf_phys = dma_phys;
} else {
dma_phys = dma_map_single(tup->uport.dev,
tup->uport.state->xmit.buf, UART_XMIT_SIZE,
DMA_TO_DEVICE);
+ if (dma_mapping_error(tup->uport.dev, dma_phys)) {
+ dev_err(tup->uport.dev, "dma_map_single tx failed\n");
+ dma_release_channel(dma_chan);
+ return -ENOMEM;
+ }
dma_buf = tup->uport.state->xmit.buf;
- }
-
- if (dma_to_memory) {
- dma_sconfig.src_addr = tup->uport.mapbase;
- dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- dma_sconfig.src_maxburst = 4;
- } else {
dma_sconfig.dst_addr = tup->uport.mapbase;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_sconfig.dst_maxburst = 16;
+ tup->tx_dma_chan = dma_chan;
+ tup->tx_dma_buf_virt = dma_buf;
+ tup->tx_dma_buf_phys = dma_phys;
}
ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
if (ret < 0) {
dev_err(tup->uport.dev,
"Dma slave config failed, err = %d\n", ret);
- goto scrub;
+ tegra_uart_dma_channel_free(tup, dma_to_memory);
+ return ret;
}
- if (dma_to_memory) {
- tup->rx_dma_chan = dma_chan;
- tup->rx_dma_buf_virt = dma_buf;
- tup->rx_dma_buf_phys = dma_phys;
- } else {
- tup->tx_dma_chan = dma_chan;
- tup->tx_dma_buf_virt = dma_buf;
- tup->tx_dma_buf_phys = dma_phys;
- }
return 0;
-
-scrub:
- dma_release_channel(dma_chan);
- return ret;
-}
-
-static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
- bool dma_to_memory)
-{
- struct dma_chan *dma_chan;
-
- if (dma_to_memory) {
- dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
- tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
- dma_chan = tup->rx_dma_chan;
- tup->rx_dma_chan = NULL;
- tup->rx_dma_buf_phys = 0;
- tup->rx_dma_buf_virt = NULL;
- } else {
- dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
- dma_chan = tup->tx_dma_chan;
- tup->tx_dma_chan = NULL;
- tup->tx_dma_buf_phys = 0;
- tup->tx_dma_buf_virt = NULL;
- }
- dma_release_channel(dma_chan);
}
static int tegra_uart_startup(struct uart_port *u)
@@ -1060,8 +1098,6 @@ static void tegra_uart_shutdown(struct uart_port *u)
tegra_uart_dma_channel_free(tup, true);
tegra_uart_dma_channel_free(tup, false);
free_irq(u->irq, tup);
-
- tegra_uart_flush_buffer(u);
}
static void tegra_uart_enable_ms(struct uart_port *u)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 0b7bb12dfc68..7ae1592f7ec9 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -335,18 +335,29 @@ unsigned int
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
struct ktermios *old, unsigned int min, unsigned int max)
{
- unsigned int try, baud, altbaud = 38400;
+ unsigned int try;
+ unsigned int baud;
+ unsigned int altbaud;
int hung_up = 0;
upf_t flags = port->flags & UPF_SPD_MASK;
- if (flags == UPF_SPD_HI)
+ switch (flags) {
+ case UPF_SPD_HI:
altbaud = 57600;
- else if (flags == UPF_SPD_VHI)
+ break;
+ case UPF_SPD_VHI:
altbaud = 115200;
- else if (flags == UPF_SPD_SHI)
+ break;
+ case UPF_SPD_SHI:
altbaud = 230400;
- else if (flags == UPF_SPD_WARP)
+ break;
+ case UPF_SPD_WARP:
altbaud = 460800;
+ break;
+ default:
+ altbaud = 38400;
+ break;
+ }
for (try = 0; try < 2; try++) {
baud = tty_termios_baud_rate(termios);
@@ -894,12 +905,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
* need to rate-limit; it's CAP_SYS_ADMIN only.
*/
if (uport->flags & UPF_SPD_MASK) {
- char buf[64];
-
dev_notice(uport->dev,
"%s sets custom speed on %s. This is deprecated.\n",
current->comm,
- tty_name(port->tty, buf));
+ tty_name(port->tty));
}
uart_change_speed(tty, state, NULL);
}
@@ -1816,8 +1825,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* @options: ptr for <options> field; NULL if not present (out)
*
* Decodes earlycon kernel command line parameters of the form
- * earlycon=<name>,io|mmio|mmio32,<addr>,<options>
- * console=<name>,io|mmio|mmio32,<addr>,<options>
+ * earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
+ * console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
*
* The optional form
* earlycon=<name>,0x<addr>,<options>
@@ -1835,6 +1844,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
} else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
+ } else if (strncmp(p, "mmio32be,", 9) == 0) {
+ *iotype = UPIO_MEM32BE;
+ p += 9;
} else if (strncmp(p, "io,", 3) == 0) {
*iotype = UPIO_PORT;
p += 3;
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index 5c79bdab985d..b4decf8787de 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -328,7 +328,7 @@ static int ks8695uart_startup(struct uart_port *port)
{
int retval;
- set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(KS8695_IRQ_UART_TX, IRQ_NOREQUEST, IRQ_NOAUTOEN);
tx_enable(port, 0);
rx_enable(port, 1);
ms_enable(port, 1);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index d7b846d41630..402f7fb54133 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -49,8 +49,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
unsigned int count = 0;
for (i = 0; i < UART_GPIO_MAX; i++)
- if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
- mctrl_gpios_desc[i].dir_out) {
+ if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
desc_array[count] = gpios->gpio[i];
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
count++;
@@ -118,7 +117,7 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
enum mctrl_gpio_idx i;
for (i = 0; i < UART_GPIO_MAX; i++)
- if (!IS_ERR_OR_NULL(gpios->gpio[i]))
+ if (gpios->gpio[i])
devm_gpiod_put(dev, gpios->gpio[i]);
devm_kfree(dev, gpios);
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 95772cf4e7b0..1b2f894bdc9e 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -81,7 +81,8 @@ struct sci_port {
/* Platform configuration */
struct plat_sci_port *cfg;
- int overrun_bit;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
unsigned int error_mask;
unsigned int sampling_rate;
resource_size_t reg_size;
@@ -168,6 +169,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -188,6 +191,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -207,6 +212,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
@@ -226,6 +233,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
@@ -246,6 +255,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -265,6 +276,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -284,6 +297,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -303,6 +318,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = { 0x40, 16 },
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -323,6 +340,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -343,6 +362,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x24, 16 },
[SCLSR] = { 0x28, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -363,6 +384,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
};
@@ -781,7 +804,7 @@ static int sci_handle_errors(struct uart_port *port)
struct sci_port *s = to_sci_port(port);
/* Handle overruns */
- if (status & (1 << s->overrun_bit)) {
+ if (status & s->overrun_mask) {
port->icount.overrun++;
/* overrun error */
@@ -844,32 +867,17 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
struct plat_sci_reg *reg;
- int copied = 0, offset;
- u16 status, bit;
-
- switch (port->type) {
- case PORT_SCIF:
- case PORT_HSCIF:
- offset = SCLSR;
- break;
- case PORT_SCIFA:
- case PORT_SCIFB:
- offset = SCxSR;
- break;
- default:
- return 0;
- }
+ int copied = 0;
+ u16 status;
- reg = sci_getreg(port, offset);
+ reg = sci_getreg(port, s->overrun_reg);
if (!reg->size)
return 0;
- status = serial_port_in(port, offset);
- bit = 1 << s->overrun_bit;
-
- if (status & bit) {
- status &= ~bit;
- serial_port_out(port, offset, status);
+ status = serial_port_in(port, s->overrun_reg);
+ if (status & s->overrun_mask) {
+ status &= ~s->overrun_mask;
+ serial_port_out(port, s->overrun_reg, status);
port->icount.overrun++;
@@ -1021,15 +1029,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ssr_status = serial_port_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR);
- switch (port->type) {
- case PORT_SCIF:
- case PORT_HSCIF:
- orer_status = serial_port_in(port, SCLSR);
- break;
- case PORT_SCIFA:
- case PORT_SCIFB:
+ if (s->overrun_reg == SCxSR)
orer_status = ssr_status;
- break;
+ else {
+ if (sci_getreg(port, s->overrun_reg)->size)
+ orer_status = serial_port_in(port, s->overrun_reg);
}
err_enabled = scr_status & port_rx_irq_mask(port);
@@ -1059,7 +1063,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ret = sci_br_interrupt(irq, ptr);
/* Overrun Interrupt */
- if (orer_status & (1 << s->overrun_bit))
+ if (orer_status & s->overrun_mask)
sci_handle_fifo_overrun(port);
return ret;
@@ -2226,32 +2230,38 @@ static int sci_init_single(struct platform_device *dev,
switch (p->type) {
case PORT_SCIFB:
port->fifosize = 256;
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
break;
case PORT_HSCIF:
port->fifosize = 128;
sampling_rate = 0;
- sci_port->overrun_bit = 0;
+ sci_port->overrun_reg = SCLSR;
+ sci_port->overrun_mask = SCLSR_ORER;
break;
case PORT_SCIFA:
port->fifosize = 64;
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
break;
case PORT_SCIF:
port->fifosize = 16;
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
} else {
- sci_port->overrun_bit = 0;
+ sci_port->overrun_reg = SCLSR;
+ sci_port->overrun_mask = SCLSR_ORER;
sampling_rate = 32;
}
break;
default:
port->fifosize = 1;
- sci_port->overrun_bit = 5;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCI_ORER;
sampling_rate = 32;
break;
}
@@ -2297,15 +2307,11 @@ static int sci_init_single(struct platform_device *dev,
SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
/*
- * Establish sensible defaults for the overrun detection, unless
- * the part has explicitly disabled support for it.
- */
-
- /*
* Make the error mask inclusive of overrun detection, if
* supported.
*/
- sci_port->error_mask |= 1 << sci_port->overrun_bit;
+ if (sci_port->overrun_reg == SCxSR)
+ sci_port->error_mask |= sci_port->overrun_mask;
port->type = p->type;
port->flags = UPF_FIXED_PORT | p->flags;
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index d5db81a0a430..3393f67b4e84 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -1,7 +1,115 @@
+#include <linux/bitops.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#define SCI_MAJOR 204
+#define SCI_MINOR_START 8
+
+
+/*
+ * SCI register subset common for all port types.
+ * Not all registers will exist on all parts.
+ */
+enum {
+ SCSMR, /* Serial Mode Register */
+ SCBRR, /* Bit Rate Register */
+ SCSCR, /* Serial Control Register */
+ SCxSR, /* Serial Status Register */
+ SCFCR, /* FIFO Control Register */
+ SCFDR, /* FIFO Data Count Register */
+ SCxTDR, /* Transmit (FIFO) Data Register */
+ SCxRDR, /* Receive (FIFO) Data Register */
+ SCLSR, /* Line Status Register */
+ SCTFDR, /* Transmit FIFO Data Count Register */
+ SCRFDR, /* Receive FIFO Data Count Register */
+ SCSPTR, /* Serial Port Register */
+ HSSRR, /* Sampling Rate Register */
+ SCPCR, /* Serial Port Control Register */
+ SCPDR, /* Serial Port Data Register */
+
+ SCIx_NR_REGS,
+};
+
+
+/* SCSMR (Serial Mode Register) */
+#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
+#define SCSMR_PE BIT(5) /* Parity Enable */
+#define SCSMR_ODD BIT(4) /* Odd Parity */
+#define SCSMR_STOP BIT(3) /* Stop Bit Length */
+#define SCSMR_CKS 0x0003 /* Clock Select */
+
+/* Serial Control Register, SCIFA/SCIFB only bits */
+#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
+#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
+
+/* SCxSR (Serial Status Register) on SCI */
+#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */
+#define SCI_RDRF BIT(6) /* Receive Data Register Full */
+#define SCI_ORER BIT(5) /* Overrun Error */
+#define SCI_FER BIT(4) /* Framing Error */
+#define SCI_PER BIT(3) /* Parity Error */
+#define SCI_TEND BIT(2) /* Transmit End */
+#define SCI_RESERVED 0x03 /* All reserved bits */
+
+#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
+
+#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
+#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
+#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+
+/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
+#define SCIF_ER BIT(7) /* Receive Error */
+#define SCIF_TEND BIT(6) /* Transmission End */
+#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */
+#define SCIF_BRK BIT(4) /* Break Detect */
+#define SCIF_FER BIT(3) /* Framing Error */
+#define SCIF_PER BIT(2) /* Parity Error */
+#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */
+#define SCIF_DR BIT(0) /* Receive Data Ready */
+/* SCIF only (optional) */
+#define SCIF_PERC 0xf000 /* Number of Parity Errors */
+#define SCIF_FERC 0x0f00 /* Number of Framing Errors */
+/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */
+#define SCIFA_ORER BIT(9) /* Overrun Error */
+
+#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
+
+#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF)
+#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
+#define SCIF_TDxE_CLEAR ~(SCIF_TDFE)
+#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK)
+
+/* SCFCR (FIFO Control Register) */
+#define SCFCR_MCE BIT(3) /* Modem Control Enable */
+#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
+#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
+#define SCFCR_LOOP BIT(0) /* Loopback Test */
+
+/* SCLSR (Line Status Register) on (H)SCIF */
+#define SCLSR_ORER BIT(0) /* Overrun Error */
+
+/* SCSPTR (Serial Port Register), optional */
+#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */
+#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */
+#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */
+#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */
+#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
+#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
+
+/* HSSRR HSCIF */
+#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
+
+/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
+#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */
+#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */
+
+/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
+#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
+#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */
+
+
#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
@@ -15,24 +123,24 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH73A0) || \
- defined(CONFIG_ARCH_SH7372) || \
defined(CONFIG_ARCH_R8A7740)
-# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc)
-# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73)
-# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf)
-# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3)
+# define SCxSR_RDxF_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
+# define SCxSR_ERROR_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
+# define SCxSR_TDxE_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
+# define SCxSR_BREAK_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
#else
-# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
-# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
-# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
-# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+# define SCxSR_RDxF_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
+# define SCxSR_ERROR_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
+# define SCxSR_TDxE_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
+# define SCxSR_BREAK_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
#endif
-/* SCFCR */
-#define SCFCR_RFRST 0x0002
-#define SCFCR_TFRST 0x0004
-#define SCFCR_MCE 0x0008
-
-#define SCI_MAJOR 204
-#define SCI_MINOR_START 8
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 9de3eabe5737..653cdd5fb508 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -36,8 +36,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
static struct uart_driver sirfsoc_uart_drv;
static void sirfsoc_uart_tx_dma_complete_callback(void *param);
-static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
-static void sirfsoc_uart_rx_dma_complete_callback(void *param);
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{4000000, 2359296},
{3500000, 1310721},
@@ -59,50 +57,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{9600, 1114979},
};
-static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
- [0] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- },
- [1] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- },
- [2] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- },
- [3] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 3,
- },
- },
- [4] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 4,
- },
- },
- [5] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 5,
- },
- },
-};
+static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR];
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
{
@@ -116,8 +71,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
-
- return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
+ return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0;
}
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
@@ -152,6 +106,26 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
unsigned int current_val;
+ if (mctrl & TIOCM_LOOP) {
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
+ wr_regl(port, ureg->sirfsoc_line_ctrl,
+ rd_regl(port, ureg->sirfsoc_line_ctrl) |
+ SIRFUART_LOOP_BACK);
+ else
+ wr_regl(port, ureg->sirfsoc_mode1,
+ rd_regl(port, ureg->sirfsoc_mode1) |
+ SIRFSOC_USP_LOOP_BACK_CTRL);
+ } else {
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
+ wr_regl(port, ureg->sirfsoc_line_ctrl,
+ rd_regl(port, ureg->sirfsoc_line_ctrl) &
+ ~SIRFUART_LOOP_BACK);
+ else
+ wr_regl(port, ureg->sirfsoc_mode1,
+ rd_regl(port, ureg->sirfsoc_mode1) &
+ ~SIRFSOC_USP_LOOP_BACK_CTRL);
+ }
+
if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
return;
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
@@ -182,16 +156,19 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
}
} else {
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
+ ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
}
}
@@ -222,7 +199,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(uint_en->sirfsoc_txfifo_empty_en));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
/*
* DMA requires buffer address and buffer length are both aligned with
@@ -290,8 +267,11 @@ 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,
- SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
+ ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+ sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
@@ -314,21 +294,25 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
+ ~(SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type) |
uint_en->sirfsoc_rx_done_en));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- SIRFUART_RX_DMA_INT_EN(port, uint_en)|
- uint_en->sirfsoc_rx_done_en);
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type)|
+ uint_en->sirfsoc_rx_done_en);
dmaengine_terminate_all(sirfport->rx_dma_chan);
} else {
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
- ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
+ ~(SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type)));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
}
@@ -349,7 +333,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~uint_en->sirfsoc_cts_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_cts_en);
} else
disable_irq(gpio_to_irq(sirfport->cts_gpio));
@@ -379,7 +363,8 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) |
- SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
+ SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN |
+ SIRFUART_AFC_CTRL_RX_THD);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)
@@ -417,7 +402,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
if (!tty)
return -ENODEV;
while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
- ufifo_st->ff_empty(port->line))) {
+ ufifo_st->ff_empty(port))) {
ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
SIRFUART_DUMMY_READ;
if (unlikely(uart_handle_sysrq_char(port, ch)))
@@ -444,7 +429,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
unsigned int num_tx = 0;
while (!uart_circ_empty(xmit) &&
!(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
- ufifo_st->ff_full(port->line)) &&
+ ufifo_st->ff_full(port)) &&
count--) {
wr_regl(port, ureg->sirfsoc_tx_fifo_data,
xmit->buf[xmit->tail]);
@@ -478,139 +463,6 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
spin_unlock_irqrestore(&port->lock, flags);
}
-static void sirfsoc_uart_insert_rx_buf_to_tty(
- struct sirfsoc_uart_port *sirfport, int count)
-{
- struct uart_port *port = &sirfport->port;
- struct tty_port *tport = &port->state->port;
- int inserted;
-
- inserted = tty_insert_flip_string(tport,
- sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
- port->icount.rx += inserted;
-}
-
-static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
-{
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-
- sirfport->rx_dma_items[index].xmit.tail =
- sirfport->rx_dma_items[index].xmit.head = 0;
- sirfport->rx_dma_items[index].desc =
- dmaengine_prep_slave_single(sirfport->rx_dma_chan,
- sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
- if (!sirfport->rx_dma_items[index].desc) {
- dev_err(port->dev, "DMA slave single fail\n");
- return;
- }
- sirfport->rx_dma_items[index].desc->callback =
- sirfsoc_uart_rx_dma_complete_callback;
- sirfport->rx_dma_items[index].desc->callback_param = sirfport;
- sirfport->rx_dma_items[index].cookie =
- dmaengine_submit(sirfport->rx_dma_items[index].desc);
- dma_async_issue_pending(sirfport->rx_dma_chan);
-}
-
-static void sirfsoc_rx_tmo_process_tl(unsigned long param)
-{
- struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
- struct uart_port *port = &sirfport->port;
- struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
- struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
- struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
- unsigned int count;
- unsigned long flags;
- struct dma_tx_state tx_state;
-
- 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,
- SIRFSOC_RX_DMA_BUF_SIZE);
- sirfport->rx_completed++;
- sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
- }
- count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
- sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
- SIRFSOC_RX_DMA_BUF_SIZE);
- if (count > 0)
- sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
- wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
- rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
- SIRFUART_IO_MODE);
- sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
- if (sirfport->rx_io_count == 4) {
- sirfport->rx_io_count = 0;
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_done);
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_done_en);
- sirfsoc_uart_start_next_rx_dma(port);
- } else {
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_done);
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) |
- (uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- uint_en->sirfsoc_rx_done_en);
- }
- 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)
-{
- struct uart_port *port = &sirfport->port;
- 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;
- dmaengine_tx_status(sirfport->rx_dma_chan,
- sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
- dmaengine_terminate_all(sirfport->rx_dma_chan);
- sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
- SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_timeout_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_timeout_en);
- tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
-}
-
-static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
-{
- struct uart_port *port = &sirfport->port;
- struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
- struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
- struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
-
- sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
- if (sirfport->rx_io_count == 4) {
- sirfport->rx_io_count = 0;
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_done_en);
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_timeout);
- sirfsoc_uart_start_next_rx_dma(port);
- }
-}
-
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
unsigned long intr_status;
@@ -628,20 +480,25 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
- if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
+ if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
+ sirfport->uart_reg->uart_type)))) {
if (intr_status & uint_st->sirfsoc_rxd_brk) {
port->icount.brk++;
if (uart_handle_break(port))
goto recv_char;
}
- if (intr_status & uint_st->sirfsoc_rx_oflow)
+ if (intr_status & uint_st->sirfsoc_rx_oflow) {
port->icount.overrun++;
+ flag = TTY_OVERRUN;
+ }
if (intr_status & uint_st->sirfsoc_frm_err) {
port->icount.frame++;
flag = TTY_FRAME;
}
- if (intr_status & uint_st->sirfsoc_parity_err)
+ if (intr_status & uint_st->sirfsoc_parity_err) {
+ port->icount.parity++;
flag = TTY_PARITY;
+ }
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
@@ -662,15 +519,51 @@ recv_char:
uart_handle_cts_change(port, cts_status);
wake_up_interruptible(&state->port.delta_msr_wait);
}
- if (sirfport->rx_dma_chan) {
- if (intr_status & uint_st->sirfsoc_rx_timeout)
- sirfsoc_uart_handle_rx_tmo(sirfport);
- if (intr_status & uint_st->sirfsoc_rx_done)
- sirfsoc_uart_handle_rx_done(sirfport);
- } else {
- if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
- sirfsoc_uart_pio_rx_chars(port,
- SIRFSOC_UART_IO_RX_MAX_CNT);
+ if (!sirfport->rx_dma_chan &&
+ (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) {
+ /*
+ * chip will trigger continuous RX_TIMEOUT interrupt
+ * in RXFIFO empty and not trigger if RXFIFO recevice
+ * data in limit time, original method use RX_TIMEOUT
+ * will trigger lots of useless interrupt in RXFIFO
+ * empty.RXFIFO received one byte will trigger RX_DONE
+ * interrupt.use RX_DONE to wait for data received
+ * into RXFIFO, use RX_THD/RX_FULL for lots data receive
+ * and use RX_TIMEOUT for the last left data.
+ */
+ if (intr_status & uint_st->sirfsoc_rx_done) {
+ if (!sirfport->is_atlas7) {
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ & ~(uint_en->sirfsoc_rx_done_en));
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ | (uint_en->sirfsoc_rx_timeout_en));
+ } else {
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ uint_en->sirfsoc_rx_done_en);
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_rx_timeout_en);
+ }
+ } else {
+ if (intr_status & uint_st->sirfsoc_rx_timeout) {
+ if (!sirfport->is_atlas7) {
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ & ~(uint_en->sirfsoc_rx_timeout_en));
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ | (uint_en->sirfsoc_rx_done_en));
+ } else {
+ wr_regl(port,
+ ureg->sirfsoc_int_en_clr_reg,
+ uint_en->sirfsoc_rx_timeout_en);
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_rx_done_en);
+ }
+ }
+ sirfsoc_uart_pio_rx_chars(port, port->fifosize);
+ }
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&state->port);
@@ -684,10 +577,10 @@ recv_char:
return IRQ_HANDLED;
} else {
sirfsoc_uart_pio_tx_chars(sirfport,
- SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ port->fifosize);
if ((uart_circ_empty(xmit)) &&
(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
- ufifo_st->ff_empty(port->line)))
+ ufifo_st->ff_empty(port)))
sirfsoc_uart_stop_tx(port);
}
}
@@ -697,41 +590,8 @@ recv_char:
return IRQ_HANDLED;
}
-static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
-{
- struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
- struct uart_port *port = &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;
- struct dma_tx_state tx_state;
- 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,
- SIRFSOC_RX_DMA_BUF_SIZE);
- if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
- uint_en->sirfsoc_rx_timeout_en)
- sirfsoc_rx_submit_one_dma_desc(port,
- sirfport->rx_completed++);
- else
- sirfport->rx_completed++;
- sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
- }
- 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;
- unsigned long flags;
-
- spin_lock_irqsave(&sirfport->port.lock, flags);
- sirfport->rx_issued++;
- sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
- tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
- spin_unlock_irqrestore(&sirfport->port.lock, flags);
}
/* submit rx dma task into dmaengine */
@@ -740,21 +600,36 @@ 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;
- int i;
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);
- 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;
+ sirfport->rx_dma_items.xmit.tail =
+ sirfport->rx_dma_items.xmit.head = 0;
+ sirfport->rx_dma_items.desc =
+ dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
+ SIRFSOC_RX_DMA_BUF_SIZE / 2,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) {
+ dev_err(port->dev, "DMA slave single fail\n");
+ return;
+ }
+ sirfport->rx_dma_items.desc->callback =
+ sirfsoc_uart_rx_dma_complete_callback;
+ sirfport->rx_dma_items.desc->callback_param = sirfport;
+ sirfport->rx_dma_items.cookie =
+ dmaengine_submit(sirfport->rx_dma_items.desc);
+ dma_async_issue_pending(sirfport->rx_dma_chan);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
- SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
- SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
@@ -773,10 +648,12 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
}
@@ -789,7 +666,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate,
unsigned long ioclk_div = 0;
unsigned long temp_delta;
- for (sample_div = SIRF_MIN_SAMPLE_DIV;
+ for (sample_div = SIRF_USP_MIN_SAMPLE_DIV;
sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
temp_delta = ioclk_rate -
(ioclk_rate + (set_rate * sample_div) / 2)
@@ -910,10 +787,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
config_reg |= SIRFUART_STICK_BIT_MARK;
else
config_reg |= SIRFUART_STICK_BIT_SPACE;
- } else if (termios->c_cflag & PARODD) {
- config_reg |= SIRFUART_STICK_BIT_ODD;
} else {
- config_reg |= SIRFUART_STICK_BIT_EVEN;
+ if (termios->c_cflag & PARODD)
+ config_reg |= SIRFUART_STICK_BIT_ODD;
+ else
+ config_reg |= SIRFUART_STICK_BIT_EVEN;
}
}
} else {
@@ -976,7 +854,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
wr_regl(port, ureg->sirfsoc_tx_fifo_op,
(txfifo_op_reg & ~SIRFUART_FIFO_START));
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
- config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
+ config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out);
wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
} else {
/*tx frame ctrl*/
@@ -999,7 +877,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
/*async param*/
wr_regl(port, ureg->sirfsoc_async_param_reg,
- (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
+ (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) |
(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
SIRFSOC_USP_ASYNC_DIV2_OFFSET);
}
@@ -1011,6 +889,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
else
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
+ sirfport->rx_period_time = 20000000;
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
if (set_baud < 1000000)
threshold_div = 1;
@@ -1032,19 +911,10 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- if (!state) {
- if (sirfport->is_bt_uart) {
- clk_prepare_enable(sirfport->clk_noc);
- clk_prepare_enable(sirfport->clk_general);
- }
+ if (!state)
clk_prepare_enable(sirfport->clk);
- } else {
+ else
clk_disable_unprepare(sirfport->clk);
- if (sirfport->is_bt_uart) {
- clk_disable_unprepare(sirfport->clk_general);
- clk_disable_unprepare(sirfport->clk_noc);
- }
- }
}
static int sirfsoc_uart_startup(struct uart_port *port)
@@ -1053,7 +923,7 @@ static int sirfsoc_uart_startup(struct uart_port *port)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
unsigned int index = port->line;
int ret;
- set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
ret = request_irq(port->irq,
sirfsoc_uart_isr,
0,
@@ -1064,7 +934,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
index, port->irq);
goto irq_err;
}
-
/* initial hardware settings */
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
@@ -1072,6 +941,9 @@ static int sirfsoc_uart_startup(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+ ~SIRFUART_RX_DMA_FLUSH);
wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
@@ -1080,7 +952,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
SIRFSOC_USP_ENDIAN_CTRL_LSBF |
SIRFSOC_USP_EN);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
- wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
@@ -1100,8 +971,8 @@ static int sirfsoc_uart_startup(struct uart_port *port)
sirfport->ms_enabled = false;
if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
sirfport->hw_flow_ctrl) {
- set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
- IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(gpio_to_irq(sirfport->cts_gpio),
+ IRQ_NOREQUEST, IRQ_NOAUTOEN);
ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
@@ -1110,8 +981,16 @@ static int sirfsoc_uart_startup(struct uart_port *port)
goto init_rx_err;
}
}
-
enable_irq(port->irq);
+ if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) {
+ sirfport->is_hrt_enabled = true;
+ sirfport->rx_period_time = 20000000;
+ sirfport->rx_dma_items.xmit.tail =
+ sirfport->rx_dma_items.xmit.head = 0;
+ hrtimer_start(&sirfport->hrt,
+ ns_to_ktime(sirfport->rx_period_time),
+ HRTIMER_MODE_REL);
+ }
return 0;
init_rx_err:
@@ -1127,7 +1006,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
else
- wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL);
free_irq(port->irq, sirfport);
if (sirfport->ms_enabled)
@@ -1139,6 +1018,13 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
}
if (sirfport->tx_dma_chan)
sirfport->tx_dma_state = TX_DMA_IDLE;
+ if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) {
+ while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0)
+ ;
+ sirfport->is_hrt_enabled = false;
+ hrtimer_cancel(&sirfport->hrt);
+ }
}
static const char *sirfsoc_uart_type(struct uart_port *port)
@@ -1196,27 +1082,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options)
unsigned int bits = 8;
unsigned int parity = 'n';
unsigned int flow = 'n';
- struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_uart_port *sirfport;
+ struct sirfsoc_register *ureg;
if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
- return -EINVAL;
-
- if (!port->mapbase)
+ co->index = 1;
+ sirfport = sirf_ports[co->index];
+ if (!sirfport)
+ return -ENODEV;
+ ureg = &sirfport->uart_reg->uart_reg;
+ if (!sirfport->port.mapbase)
return -ENODEV;
/* enable usp in mode1 register */
if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
- wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
+ wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
SIRFSOC_USP_ENDIAN_CTRL_LSBF);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- port->cons = co;
+ sirfport->port.cons = co;
/* default console tx/rx transfer using io mode */
sirfport->rx_dma_chan = NULL;
sirfport->tx_dma_chan = NULL;
- return uart_set_options(port, co, baud, parity, bits, flow);
+ return uart_set_options(&sirfport->port, co, baud, parity, bits, flow);
}
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
@@ -1224,8 +1112,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
- while (rd_regl(port,
- ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
+ while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+ ufifo_st->ff_full(port))
cpu_relax();
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
}
@@ -1233,8 +1121,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
static void sirfsoc_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
- uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
+ struct sirfsoc_uart_port *sirfport = sirf_ports[co->index];
+
+ uart_console_write(&sirfport->port, s, count,
+ sirfsoc_uart_console_putchar);
}
static struct console sirfsoc_uart_console = {
@@ -1269,10 +1159,75 @@ static struct uart_driver sirfsoc_uart_drv = {
#endif
};
-static const struct of_device_id sirfsoc_uart_ids[] = {
+static enum hrtimer_restart
+ sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct sirfsoc_uart_port *sirfport;
+ struct uart_port *port;
+ int count, inserted;
+ struct dma_tx_state tx_state;
+ struct tty_struct *tty;
+ struct sirfsoc_register *ureg;
+ struct circ_buf *xmit;
+
+ sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt);
+ port = &sirfport->port;
+ inserted = 0;
+ tty = port->state->port.tty;
+ ureg = &sirfport->uart_reg->uart_reg;
+ xmit = &sirfport->rx_dma_items.xmit;
+ dmaengine_tx_status(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items.cookie, &tx_state);
+ xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ while (count > 0) {
+ inserted = tty_insert_flip_string(tty->port,
+ (const unsigned char *)&xmit->buf[xmit->tail], count);
+ if (!inserted)
+ goto next_hrt;
+ port->icount.rx += inserted;
+ xmit->tail = (xmit->tail + inserted) &
+ (SIRFSOC_RX_DMA_BUF_SIZE - 1);
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ tty_flip_buffer_push(tty->port);
+ }
+ /*
+ * if RX DMA buffer data have all push into tty buffer, and there is
+ * only little data(less than a dma transfer unit) left in rxfifo,
+ * fetch it out in pio mode and switch back to dma immediately
+ */
+ if (!inserted && !count &&
+ ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0)) {
+ /* switch to pio mode */
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+ SIRFUART_IO_MODE);
+ while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0) {
+ if (sirfsoc_uart_pio_rx_chars(port, 16) > 0)
+ tty_flip_buffer_push(tty->port);
+ }
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
+ /* switch back to dma mode */
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+ ~SIRFUART_IO_MODE);
+ }
+next_hrt:
+ hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time));
+ return HRTIMER_RESTART;
+}
+
+static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
+ { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp},
{}
};
MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
@@ -1283,7 +1238,6 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
struct uart_port *port;
struct resource *res;
int ret;
- int i, j;
struct dma_slave_config slv_cfg = {
.src_maxburst = 2,
};
@@ -1293,16 +1247,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
const struct of_device_id *match;
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
- if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
- dev_err(&pdev->dev,
- "Unable to find cell-index in uart node.\n");
- ret = -EFAULT;
+ sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
+ if (!sirfport) {
+ ret = -ENOMEM;
goto err;
}
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
- pdev->id += ((struct sirfsoc_uart_register *)
- match->data)->uart_param.register_uart_nr;
- sirfport = &sirfsoc_uart_ports[pdev->id];
+ sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
+ sirf_ports[sirfport->port.line] = sirfport;
+ sirfport->port.iotype = UPIO_MEM;
+ sirfport->port.flags = UPF_BOOT_AUTOCONF;
port = &sirfport->port;
port->dev = &pdev->dev;
port->private_data = sirfport;
@@ -1310,9 +1263,12 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
"sirf,uart-has-rtscts");
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") ||
+ of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "sirf,prima2-usp-uart") || of_device_is_compatible(
+ pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
sirfport->uart_reg->uart_type = SIRF_USP_UART;
if (!sirfport->hw_flow_ctrl)
goto usp_no_flow_control;
@@ -1350,7 +1306,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
gpio_direction_output(sirfport->rts_gpio, 1);
}
usp_no_flow_control:
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
+ of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
sirfport->is_atlas7 = true;
if (of_property_read_u32(pdev->dev.of_node,
@@ -1368,12 +1325,9 @@ usp_no_flow_control:
ret = -EFAULT;
goto err;
}
- tasklet_init(&sirfport->rx_dma_complete_tasklet,
- sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
- tasklet_init(&sirfport->rx_tmo_process_tasklet,
- sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
port->mapbase = res->start;
- port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ port->membase = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
if (!port->membase) {
dev_err(&pdev->dev, "Cannot remap resource.\n");
ret = -ENOMEM;
@@ -1393,20 +1347,6 @@ usp_no_flow_control:
goto err;
}
port->uartclk = clk_get_rate(sirfport->clk);
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
- sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
- if (IS_ERR(sirfport->clk_general)) {
- ret = PTR_ERR(sirfport->clk_general);
- goto err;
- }
- sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc");
- if (IS_ERR(sirfport->clk_noc)) {
- ret = PTR_ERR(sirfport->clk_noc);
- goto err;
- }
- sirfport->is_bt_uart = true;
- } else
- sirfport->is_bt_uart = false;
port->ops = &sirfsoc_uart_ops;
spin_lock_init(&port->lock);
@@ -1419,30 +1359,32 @@ usp_no_flow_control:
}
sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
- for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
- sirfport->rx_dma_items[i].xmit.buf =
- dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
- if (!sirfport->rx_dma_items[i].xmit.buf) {
- dev_err(port->dev, "Uart alloc bufa failed\n");
- ret = -ENOMEM;
- goto alloc_coherent_err;
- }
- sirfport->rx_dma_items[i].xmit.head =
- sirfport->rx_dma_items[i].xmit.tail = 0;
+ sirfport->rx_dma_items.xmit.buf =
+ dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ &sirfport->rx_dma_items.dma_addr, GFP_KERNEL);
+ if (!sirfport->rx_dma_items.xmit.buf) {
+ dev_err(port->dev, "Uart alloc bufa failed\n");
+ ret = -ENOMEM;
+ goto alloc_coherent_err;
}
+ sirfport->rx_dma_items.xmit.head =
+ sirfport->rx_dma_items.xmit.tail = 0;
if (sirfport->rx_dma_chan)
dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx");
if (sirfport->tx_dma_chan)
dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
+ if (sirfport->rx_dma_chan) {
+ hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback;
+ sirfport->is_hrt_enabled = false;
+ }
return 0;
alloc_coherent_err:
- for (j = 0; j < i; j++)
- dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- sirfport->rx_dma_items[j].xmit.buf,
- sirfport->rx_dma_items[j].dma_addr);
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items.xmit.buf,
+ sirfport->rx_dma_items.dma_addr);
dma_release_channel(sirfport->rx_dma_chan);
err:
return ret;
@@ -1454,13 +1396,11 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
struct uart_port *port = &sirfport->port;
uart_remove_one_port(&sirfsoc_uart_drv, port);
if (sirfport->rx_dma_chan) {
- int i;
dmaengine_terminate_all(sirfport->rx_dma_chan);
dma_release_channel(sirfport->rx_dma_chan);
- for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
- dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- sirfport->rx_dma_items[i].xmit.buf,
- sirfport->rx_dma_items[i].dma_addr);
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items.xmit.buf,
+ sirfport->rx_dma_items.dma_addr);
}
if (sirfport->tx_dma_chan) {
dmaengine_terminate_all(sirfport->tx_dma_chan);
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 727eb6b88fff..eb162b012eec 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -6,11 +6,11 @@
* Licensed under GPLv2 or later.
*/
#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/hrtimer.h>
struct sirfsoc_uart_param {
const char *uart_name;
const char *port_name;
- u32 uart_nr;
- u32 register_uart_nr;
};
struct sirfsoc_register {
@@ -21,6 +21,7 @@ struct sirfsoc_register {
u32 sirfsoc_tx_rx_en;
u32 sirfsoc_int_en_reg;
u32 sirfsoc_int_st_reg;
+ u32 sirfsoc_int_en_clr_reg;
u32 sirfsoc_tx_dma_io_ctrl;
u32 sirfsoc_tx_dma_io_len;
u32 sirfsoc_tx_fifo_ctrl;
@@ -45,8 +46,8 @@ struct sirfsoc_register {
u32 sirfsoc_async_param_reg;
};
-typedef u32 (*fifo_full_mask)(int line);
-typedef u32 (*fifo_empty_mask)(int line);
+typedef u32 (*fifo_full_mask)(struct uart_port *port);
+typedef u32 (*fifo_empty_mask)(struct uart_port *port);
struct sirfsoc_fifo_status {
fifo_full_mask ff_full;
@@ -105,21 +106,20 @@ struct sirfsoc_uart_register {
enum sirfsoc_uart_type uart_type;
};
-u32 usp_ff_full(int line)
+u32 uart_usp_ff_full_mask(struct uart_port *port)
{
- return 0x80;
-}
-u32 usp_ff_empty(int line)
-{
- return 0x100;
-}
-u32 uart_ff_full(int line)
-{
- return (line == 1) ? (0x20) : (0x80);
+ u32 full_bit;
+
+ full_bit = ilog2(port->fifosize);
+ return (1 << full_bit);
}
-u32 uart_ff_empty(int line)
+
+u32 uart_usp_ff_empty_mask(struct uart_port *port)
{
- return (line == 1) ? (0x40) : (0x100);
+ u32 empty_bit;
+
+ empty_bit = ilog2(port->fifosize) + 1;
+ return (1 << empty_bit);
}
struct sirfsoc_uart_register sirfsoc_usp = {
.uart_reg = {
@@ -145,6 +145,7 @@ struct sirfsoc_uart_register sirfsoc_usp = {
.sirfsoc_rx_fifo_op = 0x0130,
.sirfsoc_rx_fifo_status = 0x0134,
.sirfsoc_rx_fifo_data = 0x0138,
+ .sirfsoc_int_en_clr_reg = 0x140,
},
.uart_int_en = {
.sirfsoc_rx_done_en = BIT(0),
@@ -177,14 +178,12 @@ struct sirfsoc_uart_register sirfsoc_usp = {
.sirfsoc_rxd_brk = BIT(15),
},
.fifo_status = {
- .ff_full = usp_ff_full,
- .ff_empty = usp_ff_empty,
+ .ff_full = uart_usp_ff_full_mask,
+ .ff_empty = uart_usp_ff_empty_mask,
},
.uart_param = {
.uart_name = "ttySiRF",
.port_name = "sirfsoc-uart",
- .uart_nr = 2,
- .register_uart_nr = 3,
},
};
@@ -195,6 +194,7 @@ struct sirfsoc_uart_register sirfsoc_uart = {
.sirfsoc_divisor = 0x0050,
.sirfsoc_int_en_reg = 0x0054,
.sirfsoc_int_st_reg = 0x0058,
+ .sirfsoc_int_en_clr_reg = 0x0060,
.sirfsoc_tx_dma_io_ctrl = 0x0100,
.sirfsoc_tx_dma_io_len = 0x0104,
.sirfsoc_tx_fifo_ctrl = 0x0108,
@@ -249,14 +249,12 @@ struct sirfsoc_uart_register sirfsoc_uart = {
.sirfsoc_rts = BIT(15),
},
.fifo_status = {
- .ff_full = uart_ff_full,
- .ff_empty = uart_ff_empty,
+ .ff_full = uart_usp_ff_full_mask,
+ .ff_empty = uart_usp_ff_empty_mask,
},
.uart_param = {
.uart_name = "ttySiRF",
.port_name = "sirfsoc_uart",
- .uart_nr = 3,
- .register_uart_nr = 0,
},
};
/* uart io ctrl */
@@ -296,10 +294,10 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFUART_IO_MODE BIT(0)
#define SIRFUART_DMA_MODE 0x0
+#define SIRFUART_RX_DMA_FLUSH 0x4
-/* Macro Specific*/
-#define SIRFUART_INT_EN_CLR 0x0060
/* Baud Rate Calculation */
+#define SIRF_USP_MIN_SAMPLE_DIV 0x1
#define SIRF_MIN_SAMPLE_DIV 0xf
#define SIRF_MAX_SAMPLE_DIV 0x3f
#define SIRF_IOCLK_DIV_MAX 0xffff
@@ -326,55 +324,54 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24
#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f
#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16
-
+#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2)
/* USP-UART Common */
#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
#define SIRFUART_RECV_TIMEOUT_VALUE(x) \
(((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
-#define SIRFUART_RECV_TIMEOUT(port, x) \
- (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
+#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF)
+#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16)
-#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64)
-#define SIRFUART_ERR_INT_STAT(port, unit_st) \
+#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1)
+#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \
(uint_st->sirfsoc_rx_oflow | \
uint_st->sirfsoc_frm_err | \
uint_st->sirfsoc_rxd_brk | \
- ((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err))
-#define SIRFUART_RX_IO_INT_EN(port, uint_en) \
- (uint_en->sirfsoc_rx_timeout_en |\
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_st->sirfsoc_parity_err))
+#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \
+ (uint_en->sirfsoc_rx_done_en |\
uint_en->sirfsoc_rxfifo_thd_en |\
uint_en->sirfsoc_rxfifo_full_en |\
uint_en->sirfsoc_frm_err_en |\
uint_en->sirfsoc_rx_oflow_en |\
uint_en->sirfsoc_rxd_brk_en |\
- ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_en->sirfsoc_parity_err_en))
#define SIRFUART_RX_IO_INT_ST(uint_st) \
- (uint_st->sirfsoc_rx_timeout |\
- uint_st->sirfsoc_rxfifo_thd |\
- uint_st->sirfsoc_rxfifo_full)
+ (uint_st->sirfsoc_rxfifo_thd |\
+ uint_st->sirfsoc_rxfifo_full|\
+ uint_st->sirfsoc_rx_done |\
+ uint_st->sirfsoc_rx_timeout)
#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts)
-#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \
- (uint_en->sirfsoc_rx_timeout_en |\
- uint_en->sirfsoc_frm_err_en |\
+#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \
+ (uint_en->sirfsoc_frm_err_en |\
uint_en->sirfsoc_rx_oflow_en |\
uint_en->sirfsoc_rxd_brk_en |\
- ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_en->sirfsoc_parity_err_en))
/* Generic Definitions */
#define SIRFSOC_UART_NAME "ttySiRF"
#define SIRFSOC_UART_MAJOR 0
#define SIRFSOC_UART_MINOR 0
#define SIRFUART_PORT_NAME "sirfsoc-uart"
#define SIRFUART_MAP_SIZE 0x200
-#define SIRFSOC_UART_NR 6
+#define SIRFSOC_UART_NR 11
#define SIRFSOC_PORT_TYPE 0xa5
/* Uart Common Use Macro*/
-#define SIRFSOC_RX_DMA_BUF_SIZE 256
+#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32)
#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3)
-#define LOOP_DMA_BUFA_FILL 1
-#define LOOP_DMA_BUFB_FILL 2
-#define TX_TRAN_PIO 1
-#define TX_TRAN_DMA 2
/* Uart Fifo Level Chk */
#define SIRFUART_TX_FIFO_SC_OFFSET 0
#define SIRFUART_TX_FIFO_LC_OFFSET 10
@@ -389,8 +386,8 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
+#define SIRFUART_RX_FIFO_MASK 0x7f
/* Indicate how many buffers used */
-#define SIRFSOC_RX_LOOP_BUF_CNT 2
/* For Fast Baud Rate Calculation */
struct sirfsoc_baudrate_to_regv {
@@ -404,7 +401,7 @@ enum sirfsoc_tx_state {
TX_DMA_PAUSE,
};
-struct sirfsoc_loop_buffer {
+struct sirfsoc_rx_buffer {
struct circ_buf xmit;
dma_cookie_t cookie;
struct dma_async_tx_descriptor *desc;
@@ -417,10 +414,6 @@ struct sirfsoc_uart_port {
struct uart_port port;
struct clk *clk;
- /* UART6 for BT usage in A7DA platform need multi-clock source */
- bool is_bt_uart;
- struct clk *clk_general;
- struct clk *clk_noc;
/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
bool is_atlas7;
struct sirfsoc_uart_register *uart_reg;
@@ -428,17 +421,16 @@ struct sirfsoc_uart_port {
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
struct dma_async_tx_descriptor *tx_dma_desc;
- struct tasklet_struct rx_dma_complete_tasklet;
- struct tasklet_struct rx_tmo_process_tasklet;
unsigned int rx_io_count;
unsigned long transfer_size;
enum sirfsoc_tx_state tx_dma_state;
unsigned int cts_gpio;
unsigned int rts_gpio;
- struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT];
- int rx_completed;
- int rx_issued;
+ struct sirfsoc_rx_buffer rx_dma_items;
+ struct hrtimer hrt;
+ bool is_hrt_enabled;
+ unsigned long rx_period_time;
};
/* Register Access Control */
@@ -447,10 +439,6 @@ struct sirfsoc_uart_port {
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */
-#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f))
-#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80))
-#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100))
-
-/* I/O Mode */
-#define SIRFSOC_UART_IO_RX_MAX_CNT 256
-#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256
+#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF)
+#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF)
+#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 582d2729f700..3866516c2926 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -716,7 +716,7 @@ static int sprd_probe(struct platform_device *pdev)
up->flags = UPF_BOOT_AUTOCONF;
clk = devm_clk_get(&pdev->dev, NULL);
- if (!IS_ERR(clk))
+ if (!IS_ERR_OR_NULL(clk))
up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 000000000000..4a6eab6da63e
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR 0x00
+#define USART_DR 0x04
+#define USART_BRR 0x08
+#define USART_CR1 0x0c
+#define USART_CR2 0x10
+#define USART_CR3 0x14
+#define USART_GTPR 0x18
+
+/* USART_SR */
+#define USART_SR_PE BIT(0)
+#define USART_SR_FE BIT(1)
+#define USART_SR_NF BIT(2)
+#define USART_SR_ORE BIT(3)
+#define USART_SR_IDLE BIT(4)
+#define USART_SR_RXNE BIT(5)
+#define USART_SR_TC BIT(6)
+#define USART_SR_TXE BIT(7)
+#define USART_SR_LBD BIT(8)
+#define USART_SR_CTS BIT(9)
+#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
+ USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT 4
+
+/* USART_CR1 */
+#define USART_CR1_SBK BIT(0)
+#define USART_CR1_RWU BIT(1)
+#define USART_CR1_RE BIT(2)
+#define USART_CR1_TE BIT(3)
+#define USART_CR1_IDLEIE BIT(4)
+#define USART_CR1_RXNEIE BIT(5)
+#define USART_CR1_TCIE BIT(6)
+#define USART_CR1_TXEIE BIT(7)
+#define USART_CR1_PEIE BIT(8)
+#define USART_CR1_PS BIT(9)
+#define USART_CR1_PCE BIT(10)
+#define USART_CR1_WAKE BIT(11)
+#define USART_CR1_M BIT(12)
+#define USART_CR1_UE BIT(13)
+#define USART_CR1_OVER8 BIT(15)
+#define USART_CR1_IE_MASK GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK GENMASK(3, 0)
+#define USART_CR2_LBDL BIT(5)
+#define USART_CR2_LBDIE BIT(6)
+#define USART_CR2_LBCL BIT(8)
+#define USART_CR2_CPHA BIT(9)
+#define USART_CR2_CPOL BIT(10)
+#define USART_CR2_CLKEN BIT(11)
+#define USART_CR2_STOP_2B BIT(13)
+#define USART_CR2_STOP_MASK GENMASK(13, 12)
+#define USART_CR2_LINEN BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE BIT(0)
+#define USART_CR3_IREN BIT(1)
+#define USART_CR3_IRLP BIT(2)
+#define USART_CR3_HDSEL BIT(3)
+#define USART_CR3_NACK BIT(4)
+#define USART_CR3_SCEN BIT(5)
+#define USART_CR3_DMAR BIT(6)
+#define USART_CR3_DMAT BIT(7)
+#define USART_CR3_RTSE BIT(8)
+#define USART_CR3_CTSE BIT(9)
+#define USART_CR3_CTSIE BIT(10)
+#define USART_CR3_ONEBIT BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK GENMASK(7, 0)
+#define USART_GTPR_GT_MASK GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+ struct uart_port port;
+ struct clk *clk;
+ bool hw_flow_control;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static inline struct stm32_port *to_stm32_port(struct uart_port *port)
+{
+ return container_of(port, struct stm32_port, port);
+}
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val |= bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val &= ~bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned long c;
+ u32 sr;
+ char flag;
+
+ if (port->irq_wake)
+ pm_wakeup_event(tport->tty->dev, 0);
+
+ while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+ sr |= USART_SR_DUMMY_RX;
+ c = readl_relaxed(port->membase + USART_DR);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (sr & USART_SR_ERR_MASK) {
+ if (sr & USART_SR_LBD) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & USART_SR_ORE) {
+ port->icount.overrun++;
+ } else if (sr & USART_SR_PE) {
+ port->icount.parity++;
+ } else if (sr & USART_SR_FE) {
+ port->icount.frame++;
+ }
+
+ sr &= port->read_status_mask;
+
+ if (sr & USART_SR_LBD)
+ flag = TTY_BREAK;
+ else if (sr & USART_SR_PE)
+ flag = TTY_PARITY;
+ else if (sr & USART_SR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+ uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+ }
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (port->x_char) {
+ writel_relaxed(port->x_char, port->membase + USART_DR);
+ port->x_char = 0;
+ port->icount.tx++;
+ return;
+ }
+
+ if (uart_tx_stopped(port)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+ struct uart_port *port = ptr;
+ u32 sr;
+
+ spin_lock(&port->lock);
+
+ sr = readl_relaxed(port->membase + USART_SR);
+
+ if (sr & USART_SR_RXNE)
+ stm32_receive_chars(port);
+
+ if (sr & USART_SR_TXE)
+ stm32_transmit_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+ return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+ stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
+ else
+ stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+ /* This routine is used to get signals of: DCD, DSR, RI, and CTS */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (uart_circ_empty(xmit))
+ return;
+
+ stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Throttle the remote when input buffer is about to overflow. */
+static void stm32_throttle(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Unthrottle the remote, the input buffer can now accept data. */
+static void stm32_unthrottle(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+ const char *name = to_platform_device(port->dev)->name;
+ u32 val;
+ int ret;
+
+ ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+ name, port);
+ if (ret)
+ return ret;
+
+ val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+ u32 val;
+
+ val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ unsigned int baud;
+ u32 usartdiv, mantissa, fraction, oversampling;
+ tcflag_t cflag = termios->c_cflag;
+ u32 cr1, cr2, cr3;
+ unsigned long flags;
+
+ if (!stm32_port->hw_flow_control)
+ cflag &= ~CRTSCTS;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Stop serial port and reset value */
+ writel_relaxed(0, port->membase + USART_CR1);
+
+ cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+ cr2 = 0;
+ cr3 = 0;
+
+ if (cflag & CSTOPB)
+ cr2 |= USART_CR2_STOP_2B;
+
+ if (cflag & PARENB) {
+ cr1 |= USART_CR1_PCE;
+ if ((cflag & CSIZE) == CS8)
+ cr1 |= USART_CR1_M;
+ }
+
+ if (cflag & PARODD)
+ cr1 |= USART_CR1_PS;
+
+ port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
+ if (cflag & CRTSCTS) {
+ port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+ cr3 |= USART_CR3_CTSE;
+ }
+
+ usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+
+ /*
+ * The USART supports 16 or 8 times oversampling.
+ * By default we prefer 16 times oversampling, so that the receiver
+ * has a better tolerance to clock deviations.
+ * 8 times oversampling is only used to achieve higher speeds.
+ */
+ if (usartdiv < 16) {
+ oversampling = 8;
+ stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
+ } else {
+ oversampling = 16;
+ stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
+ }
+
+ mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
+ fraction = usartdiv % oversampling;
+ writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+ uart_update_timeout(port, cflag, baud);
+
+ port->read_status_mask = USART_SR_ORE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= USART_SR_LBD;
+
+ /* Characters to ignore */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= USART_SR_LBD;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= USART_SR_ORE;
+ }
+
+ /* Ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+ writel_relaxed(cr3, port->membase + USART_CR3);
+ writel_relaxed(cr2, port->membase + USART_CR2);
+ writel_relaxed(cr1, port->membase + USART_CR1);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+ return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* No user changeable parameters */
+ return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct stm32_port *stm32port = container_of(port,
+ struct stm32_port, port);
+ unsigned long flags = 0;
+
+ switch (state) {
+ case UART_PM_STATE_ON:
+ clk_prepare_enable(stm32port->clk);
+ break;
+ case UART_PM_STATE_OFF:
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+ spin_unlock_irqrestore(&port->lock, flags);
+ clk_disable_unprepare(stm32port->clk);
+ break;
+ }
+}
+
+static const struct uart_ops stm32_uart_ops = {
+ .tx_empty = stm32_tx_empty,
+ .set_mctrl = stm32_set_mctrl,
+ .get_mctrl = stm32_get_mctrl,
+ .stop_tx = stm32_stop_tx,
+ .start_tx = stm32_start_tx,
+ .throttle = stm32_throttle,
+ .unthrottle = stm32_unthrottle,
+ .stop_rx = stm32_stop_rx,
+ .break_ctl = stm32_break_ctl,
+ .startup = stm32_startup,
+ .shutdown = stm32_shutdown,
+ .set_termios = stm32_set_termios,
+ .pm = stm32_pm,
+ .type = stm32_type,
+ .release_port = stm32_release_port,
+ .request_port = stm32_request_port,
+ .config_port = stm32_config_port,
+ .verify_port = stm32_verify_port,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+ struct platform_device *pdev)
+{
+ struct uart_port *port = &stm32port->port;
+ struct resource *res;
+ int ret;
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &stm32_uart_ops;
+ port->dev = &pdev->dev;
+ port->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+ port->mapbase = res->start;
+
+ spin_lock_init(&port->lock);
+
+ stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(stm32port->clk))
+ return PTR_ERR(stm32port->clk);
+
+ /* Ensure that clk rate is correct by enabling the clk */
+ ret = clk_prepare_enable(stm32port->clk);
+ if (ret)
+ return ret;
+
+ stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+ if (!stm32port->port.uartclk)
+ ret = -EINVAL;
+
+ clk_disable_unprepare(stm32port->clk);
+
+ return ret;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int id;
+
+ if (!np)
+ return NULL;
+
+ id = of_alias_get_id(np, "serial");
+ if (id < 0)
+ id = 0;
+
+ if (WARN_ON(id >= STM32_MAX_PORTS))
+ return NULL;
+
+ stm32_ports[id].hw_flow_control = of_property_read_bool(np,
+ "auto-flow-control");
+ stm32_ports[id].port.line = id;
+ return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+ { .compatible = "st,stm32-usart", },
+ { .compatible = "st,stm32-uart", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct stm32_port *stm32port;
+
+ stm32port = stm32_of_get_stm32_port(pdev);
+ if (!stm32port)
+ return -ENODEV;
+
+ ret = stm32_init_port(stm32port, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, &stm32port->port);
+
+ return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+ cpu_relax();
+
+ writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+ struct uart_port *port = &stm32_ports[co->index].port;
+ unsigned long flags;
+ u32 old_cr1, new_cr1;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&port->lock);
+ else
+ spin_lock(&port->lock);
+
+ /* Save and disable interrupts */
+ old_cr1 = readl_relaxed(port->membase + USART_CR1);
+ new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+ writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+ uart_console_write(port, s, cnt, stm32_console_putchar);
+
+ /* Restore interrupt state */
+ writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+ struct stm32_port *stm32port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= STM32_MAX_PORTS)
+ return -ENODEV;
+
+ stm32port = &stm32_ports[co->index];
+
+ /*
+ * This driver does not support early console initialization
+ * (use ARM early printk support instead), so we only expect
+ * this to be called during the uart port registration when the
+ * driver gets probed and the port should be mapped at that point.
+ */
+ if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+ return -ENXIO;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+ .name = STM32_SERIAL_NAME,
+ .device = uart_console_device,
+ .write = stm32_console_write,
+ .setup = stm32_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+ .driver_name = DRIVER_NAME,
+ .dev_name = STM32_SERIAL_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = STM32_MAX_PORTS,
+ .cons = STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+ .probe = stm32_serial_probe,
+ .remove = stm32_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(stm32_match),
+ },
+};
+
+static int __init usart_init(void)
+{
+ static char banner[] __initdata = "STM32 USART driver initialized";
+ int ret;
+
+ pr_info("%s\n", banner);
+
+ ret = uart_register_driver(&stm32_usart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&stm32_serial_driver);
+ if (ret)
+ uart_unregister_driver(&stm32_usart_driver);
+
+ return ret;
+}
+
+static void __exit usart_exit(void)
+{
+ platform_driver_unregister(&stm32_serial_driver);
+ uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 3ddbac767db3..009e0dbc12d2 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1075,7 +1075,8 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
}
-static void cdns_early_write(struct console *con, const char *s, unsigned n)
+static void __init cdns_early_write(struct console *con, const char *s,
+ unsigned n)
{
struct earlycon_device *dev = con->data;
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index b7991707ffc0..2fac7123b274 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -4410,7 +4410,8 @@ static void synclink_cleanup(void)
printk("Unloading %s: %s\n", driver_name, driver_version);
if (serial_driver) {
- if ((rc = tty_unregister_driver(serial_driver)))
+ rc = tty_unregister_driver(serial_driver);
+ if (rc)
printk("%s(%d) failed to unregister tty driver err=%d\n",
__FILE__,__LINE__,rc);
put_tty_driver(serial_driver);
@@ -7751,7 +7752,8 @@ static int hdlcdev_open(struct net_device *dev)
printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
/* generic HDLC layer open processing */
- if ((rc = hdlc_open(dev)))
+ rc = hdlc_open(dev);
+ if (rc)
return rc;
/* arbitrate between network and tty opens */
@@ -8018,7 +8020,8 @@ static int hdlcdev_init(struct mgsl_struct *info)
/* allocate and initialize network and HDLC layer objects */
- if (!(dev = alloc_hdlcdev(info))) {
+ dev = alloc_hdlcdev(info);
+ if (!dev) {
printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
return -ENOMEM;
}
@@ -8039,7 +8042,8 @@ static int hdlcdev_init(struct mgsl_struct *info)
hdlc->xmit = hdlcdev_xmit;
/* register objects with HDLC layer */
- if ((rc = register_hdlc_device(dev))) {
+ rc = register_hdlc_device(dev);
+ if (rc) {
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
free_netdev(dev);
return rc;
@@ -8075,7 +8079,8 @@ static int synclink_init_one (struct pci_dev *dev,
return -EIO;
}
- if (!(info = mgsl_allocate_device())) {
+ info = mgsl_allocate_device();
+ if (!info) {
printk("can't allocate device instance data.\n");
return -EIO;
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 0e8c39b6ccd4..0ea8eee00178 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -1539,7 +1539,8 @@ static int hdlcdev_open(struct net_device *dev)
DBGINFO(("%s hdlcdev_open\n", dev->name));
/* generic HDLC layer open processing */
- if ((rc = hdlc_open(dev)))
+ rc = hdlc_open(dev);
+ if (rc)
return rc;
/* arbitrate between network and tty opens */
@@ -1803,7 +1804,8 @@ static int hdlcdev_init(struct slgt_info *info)
/* allocate and initialize network and HDLC layer objects */
- if (!(dev = alloc_hdlcdev(info))) {
+ dev = alloc_hdlcdev(info);
+ if (!dev) {
printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name);
return -ENOMEM;
}
@@ -1824,7 +1826,8 @@ static int hdlcdev_init(struct slgt_info *info)
hdlc->xmit = hdlcdev_xmit;
/* register objects with HDLC layer */
- if ((rc = register_hdlc_device(dev))) {
+ rc = register_hdlc_device(dev);
+ if (rc) {
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
free_netdev(dev);
return rc;
@@ -1879,7 +1882,8 @@ static void rx_async(struct slgt_info *info)
stat = 0;
- if ((status = *(p+1) & (BIT1 + BIT0))) {
+ status = *(p + 1) & (BIT1 + BIT0);
+ if (status) {
if (status & BIT1)
icount->parity++;
else if (status & BIT0)
@@ -3755,7 +3759,8 @@ static void slgt_cleanup(void)
if (serial_driver) {
for (info=slgt_device_list ; info != NULL ; info=info->next_device)
tty_unregister_device(serial_driver, info->line);
- if ((rc = tty_unregister_driver(serial_driver)))
+ rc = tty_unregister_driver(serial_driver);
+ if (rc)
DBGERR(("tty_unregister_driver error=%d\n", rc));
put_tty_driver(serial_driver);
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index c3f90910fed9..08633a8139ff 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -1655,7 +1655,8 @@ static int hdlcdev_open(struct net_device *dev)
printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
/* generic HDLC layer open processing */
- if ((rc = hdlc_open(dev)))
+ rc = hdlc_open(dev);
+ if (rc)
return rc;
/* arbitrate between network and tty opens */
@@ -1922,7 +1923,8 @@ static int hdlcdev_init(SLMP_INFO *info)
/* allocate and initialize network and HDLC layer objects */
- if (!(dev = alloc_hdlcdev(info))) {
+ dev = alloc_hdlcdev(info);
+ if (!dev) {
printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
return -ENOMEM;
}
@@ -1943,7 +1945,8 @@ static int hdlcdev_init(SLMP_INFO *info)
hdlc->xmit = hdlcdev_xmit;
/* register objects with HDLC layer */
- if ((rc = register_hdlc_device(dev))) {
+ rc = register_hdlc_device(dev);
+ if (rc) {
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
free_netdev(dev);
return rc;
@@ -3920,7 +3923,8 @@ static void synclinkmp_cleanup(void)
printk("Unloading %s %s\n", driver_name, driver_version);
if (serial_driver) {
- if ((rc = tty_unregister_driver(serial_driver)))
+ rc = tty_unregister_driver(serial_driver);
+ if (rc)
printk("%s(%d) failed to unregister tty driver err=%d\n",
__FILE__,__LINE__,rc);
put_tty_driver(serial_driver);
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 2f78b77f0f81..4cf263d7dffc 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -286,7 +286,8 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
if (change || left < size) {
/* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_alloc(port, size)) != NULL) {
+ n = tty_buffer_alloc(port, size);
+ if (n != NULL) {
n->flags = flags;
buf->tail = n;
b->commit = b->used;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e5695467598f..57fc6ee12332 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -235,7 +235,6 @@ static void tty_del_file(struct file *file)
/**
* tty_name - return tty naming
* @tty: tty structure
- * @buf: buffer for output
*
* Convert a tty structure into a name. The name reflects the kernel
* naming policy and if udev is in use may not reflect user space
@@ -243,13 +242,11 @@ static void tty_del_file(struct file *file)
* Locking: none
*/
-char *tty_name(struct tty_struct *tty, char *buf)
+const char *tty_name(const struct tty_struct *tty)
{
if (!tty) /* Hmm. NULL pointer. That's fun. */
- strcpy(buf, "NULL tty");
- else
- strcpy(buf, tty->name);
- return buf;
+ return "NULL tty";
+ return tty->name;
}
EXPORT_SYMBOL(tty_name);
@@ -770,8 +767,7 @@ static void do_tty_hangup(struct work_struct *work)
void tty_hangup(struct tty_struct *tty)
{
#ifdef TTY_DEBUG_HANGUP
- char buf[64];
- printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+ printk(KERN_DEBUG "%s hangup...\n", tty_name(tty));
#endif
schedule_work(&tty->hangup_work);
}
@@ -790,9 +786,7 @@ EXPORT_SYMBOL(tty_hangup);
void tty_vhangup(struct tty_struct *tty)
{
#ifdef TTY_DEBUG_HANGUP
- char buf[64];
-
- printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+ printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty));
#endif
__tty_hangup(tty, 0);
}
@@ -831,9 +825,7 @@ void tty_vhangup_self(void)
static void tty_vhangup_session(struct tty_struct *tty)
{
#ifdef TTY_DEBUG_HANGUP
- char buf[64];
-
- printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
+ printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty));
#endif
__tty_hangup(tty, 1);
}
@@ -1769,7 +1761,6 @@ int tty_release(struct inode *inode, struct file *filp)
struct tty_struct *o_tty = NULL;
int do_sleep, final;
int idx;
- char buf[64];
long timeout = 0;
int once = 1;
@@ -1793,7 +1784,7 @@ int tty_release(struct inode *inode, struct file *filp)
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__,
- tty_name(tty, buf), tty->count);
+ tty_name(tty), tty->count);
#endif
if (tty->ops->close)
@@ -1844,7 +1835,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (once) {
once = 0;
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
- __func__, tty_name(tty, buf));
+ __func__, tty_name(tty));
}
schedule_timeout_killable(timeout);
if (timeout < 120 * HZ)
@@ -1856,13 +1847,13 @@ int tty_release(struct inode *inode, struct file *filp)
if (o_tty) {
if (--o_tty->count < 0) {
printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
- __func__, o_tty->count, tty_name(o_tty, buf));
+ __func__, o_tty->count, tty_name(o_tty));
o_tty->count = 0;
}
}
if (--tty->count < 0) {
printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
- __func__, tty->count, tty_name(tty, buf));
+ __func__, tty->count, tty_name(tty));
tty->count = 0;
}
@@ -1905,7 +1896,7 @@ int tty_release(struct inode *inode, struct file *filp)
return 0;
#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
+ printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty));
#endif
/*
* Ask the line discipline code to release its structures
@@ -1916,7 +1907,8 @@ int tty_release(struct inode *inode, struct file *filp)
tty_flush_works(tty);
#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
+ printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__,
+ tty_name(tty));
#endif
/*
* The release_tty function takes care of the details of clearing
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 8e53fe469664..5232fb60b0b1 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -211,9 +211,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
void tty_wait_until_sent(struct tty_struct *tty, long timeout)
{
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
- char buf[64];
-
- printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
+ printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty));
#endif
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 3737f55272d2..c07fb5d9bcf9 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -22,9 +22,8 @@
#undef LDISC_DEBUG_HANGUP
#ifdef LDISC_DEBUG_HANGUP
-#define tty_ldisc_debug(tty, f, args...) ({ \
- char __b[64]; \
- printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
+#define tty_ldisc_debug(tty, f, args...) ({ \
+ printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty), ##args); \
})
#else
#define tty_ldisc_debug(tty, f, args...)
@@ -483,7 +482,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
{
- char buf[64];
struct tty_ldisc *new_ldisc;
int r;
@@ -504,7 +502,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
if (r < 0)
panic("Couldn't open N_TTY ldisc for "
"%s --- error %d.",
- tty_name(tty, buf), r);
+ tty_name(tty), r);
}
}
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index 0ffb0cbe2823..ad7eba5ca380 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -299,7 +299,8 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->wait_lock);
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((locked = writer_trylock(sem)))
+ locked = writer_trylock(sem);
+ if (locked)
break;
}
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 59b25e039968..c8c91f0476a2 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -261,19 +261,22 @@ 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 = *conp->vc_uni_pagedir_loc))
- return glyph;
- else if (use_unicode) {
- if (!p->inverse_trans_unicode)
+ else {
+ p = *conp->vc_uni_pagedir_loc;
+ if (!p)
return glyph;
- else
- return p->inverse_trans_unicode[glyph];
- } else {
- m = inv_translate[conp->vc_num];
- if (!p->inverse_translations[m])
- return glyph;
- else
- return p->inverse_translations[m][glyph];
+ else if (use_unicode) {
+ if (!p->inverse_trans_unicode)
+ return glyph;
+ else
+ return p->inverse_trans_unicode[glyph];
+ } else {
+ m = inv_translate[conp->vc_num];
+ if (!p->inverse_translations[m])
+ return glyph;
+ else
+ return p->inverse_translations[m][glyph];
+ }
}
}
EXPORT_SYMBOL_GPL(inverse_translate);
@@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p)
if (p == dflt) dflt = NULL;
for (i = 0; i < 32; i++) {
- if ((p1 = p->uni_pgdir[i]) != NULL) {
+ p1 = p->uni_pgdir[i];
+ if (p1 != NULL) {
for (j = 0; j < 32; j++)
kfree(p1[j]);
kfree(p1);
@@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
int i, n;
u16 **p1, *p2;
- if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+ p1 = p->uni_pgdir[n = unicode >> 11];
+ if (!p1) {
p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
if (!p1) return -ENOMEM;
for (i = 0; i < 32; i++)
p1[i] = NULL;
}
- if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+ p2 = p1[n = (unicode >> 6) & 0x1f];
+ if (!p2) {
p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
if (!p2) return -ENOMEM;
memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
@@ -569,10 +575,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* entries from "p" (old) to "q" (new).
*/
l = 0; /* unicode value */
- for (i = 0; i < 32; i++)
- if ((p1 = p->uni_pgdir[i]))
- for (j = 0; j < 32; j++)
- if ((p2 = p1[j])) {
+ for (i = 0; i < 32; i++) {
+ p1 = p->uni_pgdir[i];
+ if (p1)
+ for (j = 0; j < 32; j++) {
+ p2 = p1[j];
+ if (p2) {
for (k = 0; k < 64; k++, l++)
if (p2[k] != 0xffff) {
/*
@@ -593,9 +601,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/* Account for row of 64 empty entries */
l += 64;
}
+ }
else
/* Account for empty table */
l += 32 * 64;
+ }
/*
* Finished copying font table, set vc_uni_pagedir to new table
@@ -735,10 +745,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*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++)
- if ((p2 = *(p1++)))
+ for (i = 0; i < 32; i++) {
+ p1 = p->uni_pgdir[i];
+ if (p1)
+ for (j = 0; j < 32; j++) {
+ p2 = *(p1++);
+ if (p2)
for (k = 0; k < 64; k++) {
if (*p2 < MAX_GLYPH && ect++ < ct) {
__put_user((u_short)((i<<11)+(j<<6)+k),
@@ -749,6 +761,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
}
p2++;
}
+ }
+ }
}
__put_user(ect, uct);
console_unlock();
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 4a24eb2b0ede..8fe52989b380 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -108,6 +108,7 @@
#define CON_DRIVER_FLAG_MODULE 1
#define CON_DRIVER_FLAG_INIT 2
#define CON_DRIVER_FLAG_ATTR 4
+#define CON_DRIVER_FLAG_ZOMBIE 8
struct con_driver {
const struct consw *con;
@@ -135,6 +136,7 @@ const struct consw *conswitchp;
*/
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
+#define DEFAULT_CURSOR_BLINK_MS 200
struct vc vc_cons [MAX_NR_CONSOLES];
@@ -153,6 +155,7 @@ static int set_vesa_blanking(char __user *p);
static void set_cursor(struct vc_data *vc);
static void hide_cursor(struct vc_data *vc);
static void console_callback(struct work_struct *ignored);
+static void con_driver_unregister_callback(struct work_struct *ignored);
static void blank_screen_t(unsigned long dummy);
static void set_palette(struct vc_data *vc);
@@ -182,6 +185,7 @@ static int blankinterval = 10*60;
core_param(consoleblank, blankinterval, int, 0444);
static DECLARE_WORK(console_work, console_callback);
+static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback);
/*
* fg_console is the current virtual console,
@@ -1590,6 +1594,13 @@ static void setterm_command(struct vc_data *vc)
case 15: /* activate the previous console */
set_console(last_console);
break;
+ case 16: /* set cursor blink duration in msec */
+ if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
+ vc->vc_par[1] <= USHRT_MAX)
+ vc->vc_cur_blink_ms = vc->vc_par[1];
+ else
+ vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
+ break;
}
}
@@ -1717,6 +1728,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+ vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
gotoxy(vc, 0, 0);
save_cur(vc);
@@ -3192,22 +3204,6 @@ err:
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
- int i, retval = 0;
-
- for (i = first; i <= last; i++) {
- struct vc_data *vc = vc_cons[i].d;
-
- if (vc && vc->vc_mode == KD_GRAPHICS) {
- retval = 1;
- break;
- }
- }
-
- return retval;
-}
-
/* unlocked version of unbind_con_driver() */
int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
@@ -3293,8 +3289,7 @@ static int vt_bind(struct con_driver *con)
const struct consw *defcsw = NULL, *csw = NULL;
int i, more = 1, first = -1, last = -1, deflt = 0;
- if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
- con_is_graphics(con->con, con->first, con->last))
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
goto err;
csw = con->con;
@@ -3345,8 +3340,7 @@ static int vt_unbind(struct con_driver *con)
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))
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
goto err;
csw = con->con;
@@ -3596,7 +3590,8 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_driver = &registered_con_driver[i];
- if (con_driver->con == NULL) {
+ if (con_driver->con == NULL &&
+ !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) {
con_driver->con = csw;
con_driver->desc = desc;
con_driver->node = i;
@@ -3658,16 +3653,20 @@ int do_unregister_con_driver(const struct consw *csw)
struct con_driver *con_driver = &registered_con_driver[i];
if (con_driver->con == csw) {
- vtconsole_deinit_device(con_driver);
- device_destroy(vtconsole_class,
- MKDEV(0, con_driver->node));
+ /*
+ * Defer the removal of the sysfs entries since that
+ * will acquire the kernfs s_active lock and we can't
+ * acquire this lock while holding the console lock:
+ * the unbind sysfs entry imposes already the opposite
+ * order. Reset con already here to prevent any later
+ * lookup to succeed and mark this slot as zombie, so
+ * it won't get reused until we complete the removal
+ * in the deferred work.
+ */
con_driver->con = NULL;
- con_driver->desc = NULL;
- con_driver->dev = NULL;
- con_driver->node = 0;
- con_driver->flag = 0;
- con_driver->first = 0;
- con_driver->last = 0;
+ con_driver->flag = CON_DRIVER_FLAG_ZOMBIE;
+ schedule_work(&con_driver_unregister_work);
+
return 0;
}
}
@@ -3676,6 +3675,39 @@ int do_unregister_con_driver(const struct consw *csw)
}
EXPORT_SYMBOL_GPL(do_unregister_con_driver);
+static void con_driver_unregister_callback(struct work_struct *ignored)
+{
+ int i;
+
+ console_lock();
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = &registered_con_driver[i];
+
+ if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE))
+ continue;
+
+ console_unlock();
+
+ vtconsole_deinit_device(con_driver);
+ device_destroy(vtconsole_class, MKDEV(0, con_driver->node));
+
+ console_lock();
+
+ if (WARN_ON_ONCE(con_driver->con))
+ con_driver->con = NULL;
+ con_driver->desc = NULL;
+ con_driver->dev = NULL;
+ con_driver->node = 0;
+ WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE);
+ con_driver->flag = 0;
+ con_driver->first = 0;
+ con_driver->last = 0;
+ }
+
+ console_unlock();
+}
+
/*
* If we support more console drivers, this function is used
* when a driver wants to take over some existing consoles