This resolves some tty driver merge issues.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- interrupts: A single interrupt specifier.
-- clocks: Clock driving the hardware.
+- clocks : Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names:
+ - "baud": The clock the baudrate is derived from
+ - "bus": The bus clock for register accesses (optional)
+
+For compatibility with older device trees an unnamed clock is used for the
+baud clock if the baudclk does not exist. Do not use this for new designs.
Example:
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
reg = <0x11006000 0x400>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&uart_clk>, <&bus_clk>;
+ clock-names = "baud", "bus";
};
Required properties:
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
- "sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
- uart located in BT module and used for BT.
+ "sirf,atlas7-uart" or "sirf,atlas7-usp-uart".
- reg : Offset and length of the register set for the device
- interrupts : Should contain uart interrupt
- fifosize : Should define hardware rx/tx fifo size
rts-gpios = <&gpio 15 0>;
cts-gpios = <&gpio 46 0>;
};
-
-for uart use in BT module,
-uart6: uart@11000000 {
- cell-index = <6>;
- compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
- reg = <0x11000000 0x1000>;
- interrupts = <0 100 0>;
- clocks = <&clks 138>, <&clks 140>, <&clks 141>;
- clock-names = "uart", "general", "noc";
- fifosize = <128>;
- status = "disabled";
-}
#define BASE_BAUD ( 1843200 / 16 )
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
edma_write_array(ctlr, EDMA_EMCR, j, mask);
+ /* clear possibly pending completion interrupt */
+ edma_shadow0_write_array(ctlr, SH_ICR, j, mask);
+
pr_debug("EDMA: EER%d %08x\n", j,
edma_shadow0_read_array(ctlr, SH_EER, j));
defined(CONFIG_BFIN_UART2_CTSRTS) || \
defined(CONFIG_BFIN_UART3_CTSRTS)
# if defined(BFIN_UART_BF54X_STYLE) || defined(BFIN_UART_BF60X_STYLE)
-# define CONFIG_SERIAL_BFIN_HARD_CTSRTS
+# define SERIAL_BFIN_HARD_CTSRTS
# else
-# define CONFIG_SERIAL_BFIN_CTSRTS
+# define SERIAL_BFIN_CTSRTS
# endif
#endif
#elif ANOMALY_05000363
unsigned int anomaly_threshold;
#endif
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
int cts_pin;
int rts_pin;
#endif
#define BASE_BAUD ( 1843200 / 16 )
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
#define _ASM_SERIAL_H
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
+#ifdef CONFIG_SERIAL_8250_MANY_PORTS
#define FOURPORT_FLAGS ASYNC_FOURPORT
#define ACCENT_FLAGS 0
#define BOCA_FLAGS 0
#define BASE_BAUD (1843200/16)
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | UPF_AUTO_IRQ)
#else
{
struct edma_chan *echan = to_edma_chan(chan);
- /* Pause/Resume only allowed with cyclic mode */
- if (!echan->edesc || !echan->edesc->cyclic)
+ if (!echan->edesc)
return -EINVAL;
edma_pause(echan->ch_num);
{
struct edma_chan *echan = to_edma_chan(chan);
- /* Pause/Resume only allowed with cyclic mode */
- if (!echan->edesc->cyclic)
- return -EINVAL;
-
edma_resume(echan->ch_num);
return 0;
}
{
struct serport *serport = (struct serport*) tty->disc_data;
struct serio *serio;
- char name[64];
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;
return -ENOMEM;
strlcpy(serio->name, "Serial port", sizeof(serio->name));
- snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
+ snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty));
serio->id = serport->id;
serio->id.type = SERIO_RS232;
serio->write = serport_serio_write;
serio->dev.parent = tty->dev;
serio_register_port(serport->serio);
- printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
+ printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty));
wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
serio_unregister_port(serport->serio);
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
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
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);
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
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"))
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
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
+++ /dev/null
-/*
- * 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);
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;
* 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.
const unsigned char *dp;
char *f;
int i;
- char buf[64];
char flags = TTY_NORMAL;
if (debug & 4)
break;
default:
WARN_ONCE(1, "%s: unknown flag %d\n",
- tty_name(tty, buf), flags);
+ tty_name(tty), flags);
break;
}
}
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;
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);
break;
default:
printk(KERN_ERR "%s: unknown flag %d\n",
- tty_name(tty, buf), flag);
+ tty_name(tty), flag);
break;
}
}
#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
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;
}
int i;
cflag = tty->termios.c_cflag;
- if (!(port = info->port))
+ port = info->port;
+ if (!port)
return;
ustcnt = uart->ustcnt;
#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
static int __init univ8250_console_init(void)
{
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
register_console(&univ8250_console);
return 0;
{
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();
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;
{
int ret;
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
printk(KERN_INFO "Serial: 8250/16550 driver, "
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))
struct mtk8250_data {
int line;
struct clk *uart_clk;
+ struct clk *bus_clk;
};
static void
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)
{
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;
}
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;
}
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;
}
}
#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,
};
module_platform_driver(mtk8250_platform_driver);
+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);
+
MODULE_AUTHOR("Matthias Brugger");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
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)
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);
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);
__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:
/*
* 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;
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);
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);
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.
(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"
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
#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,
#define ALTERA_UART_CONSOLE NULL
-#endif /* CONFIG_ALTERA_UART_CONSOLE */
+#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */
/*
* Define the altera_uart UART driver structure.
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
#include <linux/io.h>
-#include <linux/workqueue.h>
#define UART_NR 14
unsigned int lcrh_tx; /* vendor-specific */
unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
- struct delayed_work tx_softirq_work;
bool autorts;
- unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
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)
spin_lock(&uap->port.lock);
}
-/*
- * Transmit a character
- * There must be at least one free entry in the TX FIFO to accept the char.
- *
- * Returns true if the FIFO might have space in it afterwards;
- * returns false if the FIFO definitely became full.
- */
-static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
+static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
+ bool from_irq)
{
+ 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);
uap->port.icount.tx++;
- if (likely(uap->tx_irq_seen > 1))
- return true;
-
- return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF);
+ 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) {
- pl011_tx_char(uap, uap->port.x_char);
+ 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)
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
}
-static void pl011_tx_softirq(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct uart_amba_port *uap =
- container_of(dwork, struct uart_amba_port, tx_softirq_work);
-
- spin_lock(&uap->port.lock);
- while (pl011_tx_chars(uap)) ;
- spin_unlock(&uap->port.lock);
-}
-
-static void pl011_tx_irq_seen(struct uart_amba_port *uap)
-{
- if (likely(uap->tx_irq_seen > 1))
- return;
-
- uap->tx_irq_seen++;
- if (uap->tx_irq_seen < 2)
- /* first TX IRQ */
- cancel_delayed_work(&uap->tx_softirq_work);
-}
-
static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
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;
container_of(port, struct uart_amba_port, port);
unsigned int cr;
- cancel_delayed_work_sync(&uap->tx_softirq_work);
-
/*
* disable all interrupts
*/
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);
/* Ensure interrupts from this UART are masked and cleared */
writew(0, uap->port.membase + UART011_IMSC);
struct tasklet_struct tasklet;
unsigned int irq_status;
unsigned int irq_status_prev;
+ unsigned int status_change;
struct circ_buf rx_ring;
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);
}
}
{
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! */
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);
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;
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) {
# 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,
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)) {
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
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)
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';
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;
#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
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
#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. */
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], \
#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) \
#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
#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;
{
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;
{
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;
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);
*/
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);
/* 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;
/* 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);
*/
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);
}
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;
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);
*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
{
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)));
{
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)));
info->rs485.flags &= ~(SER_RS485_ENABLED);
#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
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 */
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;
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;
}
}
/* 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;
}
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));
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));
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:
/* 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);
/* 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);
}
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);
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:
},
};
-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],
#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;
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)
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;
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
*/
/* 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++;
*/
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,
/* 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++;
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;
}
/*
#define MCF_CONSOLE NULL
/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
+#endif /* CONFIG_SERIAL_MCF_CONSOLE */
/****************************************************************************/
/*
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;
}
}
.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))
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;
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);
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 *)
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);
}
+++ /dev/null
-/*
- * 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);
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 */ }
{
struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250));
- port.type = port_type;
port8250.port = port;
if (port.fifosize)
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;
#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,
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);
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)
/* 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)
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);
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;
}
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");
{
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) {
if (tup->rts_active)
set_rts(tup, true);
+done:
spin_unlock_irqrestore(&u->lock, flags);
}
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)
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) {
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
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)
{
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;
}
return 0;
scrub:
- dma_release_channel(dma_chan);
+ tegra_uart_dma_channel_free(tup, dma_to_memory);
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)
{
struct tegra_uart_port *tup = to_tegra_uport(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)
* 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);
}
/* 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;
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = { 0x40, 16 },
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = { 0x24, 16 },
[SCLSR] = { 0x28, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
};
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 */
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++;
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);
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;
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;
}
sci_port->error_mask = (p->type == PORT_SCI) ?
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;
+#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)
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
{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)
{
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)
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
else {
- sirfsoc_uart_pio_tx_chars(sirfport,
- SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ 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,
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)))
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]);
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);
+ sirfsoc_uart_pio_rx_chars(port, port->fifosize);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&state->port);
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);
}
}
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)
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)
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) |
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)
+ 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)
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);
}
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 = {
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;
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);
* Licensed under GPLv2 or later.
*/
#include <linux/bitops.h>
+#include <linux/log2.h>
struct sirfsoc_uart_param {
const char *uart_name;
const char *port_name;
- u32 uart_nr;
- u32 register_uart_nr;
};
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;
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);
+ return (1 << empty_bit);
}
struct sirfsoc_uart_register sirfsoc_usp = {
.uart_reg = {
.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,
},
};
.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 */
/* 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
#define SIRFUART_RECV_TIMEOUT(port, x) \
(((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
-#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64)
+#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1)
#define SIRFUART_ERR_INT_STAT(port, unit_st) \
(uint_st->sirfsoc_rx_oflow | \
uint_st->sirfsoc_frm_err | \
#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 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
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;
#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)
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;
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);
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 */
/* 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;
}
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;
return -EIO;
}
- if (!(info = mgsl_allocate_device())) {
+ info = mgsl_allocate_device();
+ if (!info) {
printk("can't allocate device instance data.\n");
return -EIO;
}
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 */
/* 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;
}
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;
stat = 0;
- if ((status = *(p+1) & (BIT1 + BIT0))) {
+ status = *(p + 1) & (BIT1 + BIT0);
+ if (status) {
if (status & BIT1)
icount->parity++;
else if (status & BIT0)
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);
}
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 */
/* 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;
}
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;
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);
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;
/**
* 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
* 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);
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);
}
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);
}
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);
}
struct tty_struct *o_tty = NULL;
int do_sleep, final;
int idx;
- char buf[64];
long timeout = 0;
int once = 1;
#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)
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)
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;
}
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
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
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;
#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...)
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
{
- char buf[64];
struct tty_ldisc *new_ldisc;
int r;
if (r < 0)
panic("Couldn't open N_TTY ldisc for "
"%s --- error %d.",
- tty_name(tty, buf), r);
+ tty_name(tty), r);
}
}
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;
}
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);
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);
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) */
* 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) {
/*
/* 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
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),
}
p2++;
}
+ }
+ }
}
__put_user(ect, uct);
console_unlock();
#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;
*/
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
+#define DEFAULT_CURSOR_BLINK_MS 200
struct vc vc_cons [MAX_NR_CONSOLES];
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);
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,
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;
}
}
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);
#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)
{
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;
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;
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_driver = ®istered_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;
struct con_driver *con_driver = ®istered_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;
}
}
}
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 = ®istered_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
struct fbcon_ops *ops = info->fbcon_par;
queue_work(system_power_efficient_wq, &info->queue);
- mod_timer(&ops->cursor_timer, jiffies + HZ/5);
+ mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
}
static void fbcon_add_cursor_timer(struct fb_info *info)
init_timer(&ops->cursor_timer);
ops->cursor_timer.function = cursor_timer_handler;
- ops->cursor_timer.expires = jiffies + HZ / 5;
+ ops->cursor_timer.expires = jiffies + ops->cur_blink_jiffies;
ops->cursor_timer.data = (unsigned long ) info;
add_timer(&ops->cursor_timer);
ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
return;
- if (vc->vc_cursor_type & 0x10)
- fbcon_del_cursor_timer(info);
- else
+ ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+ fbcon_del_cursor_timer(info);
+ if (!(vc->vc_cursor_type & 0x10))
fbcon_add_cursor_timer(info);
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
struct fb_cursor cursor_state;
struct display *p;
int currcon; /* Current VC. */
+ int cur_blink_jiffies;
int cursor_flash;
int cursor_reset;
int blank_state;
unsigned int vc_resize_user; /* resize request from user */
unsigned int vc_bell_pitch; /* Console bell pitch */
unsigned int vc_bell_duration; /* Console bell duration */
+ unsigned short vc_cur_blink_ms; /* Cursor blink duration */
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
struct uni_pagedir *vc_uni_pagedir;
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
extern unsigned int serial8250_early_in(struct uart_port *port, int offset);
extern void serial8250_early_out(struct uart_port *port, int offset, int value);
+extern int early_serial8250_setup(struct earlycon_device *device,
+ const char *options);
extern void serial8250_do_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old);
extern int serial8250_do_startup(struct uart_port *port);
#define uart_console(port) \
((port)->cons && (port)->cons->index == (port)->line)
#else
-#define uart_console(port) (0)
+#define uart_console(port) ({ (void)port; 0; })
#endif
struct uart_port;
#ifndef __LINUX_SERIAL_SCI_H
#define __LINUX_SERIAL_SCI_H
+#include <linux/bitops.h>
#include <linux/serial_core.h>
#include <linux/sh_dma.h>
#define SCIx_NOT_SUPPORTED (-1)
-/* SCSMR (Serial Mode Register) */
-#define SCSMR_CHR (1 << 6) /* 7-bit Character Length */
-#define SCSMR_PE (1 << 5) /* Parity Enable */
-#define SCSMR_ODD (1 << 4) /* Odd Parity */
-#define SCSMR_STOP (1 << 3) /* Stop Bit Length */
-#define SCSMR_CKS 0x0003 /* Clock Select */
-
/* Serial Control Register (@ = not supported by all parts) */
-#define SCSCR_TIE (1 << 7) /* Transmit Interrupt Enable */
-#define SCSCR_RIE (1 << 6) /* Receive Interrupt Enable */
-#define SCSCR_TE (1 << 5) /* Transmit Enable */
-#define SCSCR_RE (1 << 4) /* Receive Enable */
-#define SCSCR_REIE (1 << 3) /* Receive Error Interrupt Enable @ */
-#define SCSCR_TOIE (1 << 2) /* Timeout Interrupt Enable @ */
-#define SCSCR_CKE1 (1 << 1) /* Clock Enable 1 */
-#define SCSCR_CKE0 (1 << 0) /* Clock Enable 0 */
-/* SCIFA/SCIFB only */
-#define SCSCR_TDRQE (1 << 15) /* Tx Data Transfer Request Enable */
-#define SCSCR_RDRQE (1 << 14) /* Rx Data Transfer Request Enable */
-
-/* SCxSR (Serial Status Register) on SCI */
-#define SCI_TDRE 0x80 /* Transmit Data Register Empty */
-#define SCI_RDRF 0x40 /* Receive Data Register Full */
-#define SCI_ORER 0x20 /* Overrun Error */
-#define SCI_FER 0x10 /* Framing Error */
-#define SCI_PER 0x08 /* Parity Error */
-#define SCI_TEND 0x04 /* Transmit End */
-
-#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
-
-/* SCxSR (Serial Status Register) on SCIF, HSCIF */
-#define SCIF_ER 0x0080 /* Receive Error */
-#define SCIF_TEND 0x0040 /* Transmission End */
-#define SCIF_TDFE 0x0020 /* Transmit FIFO Data Empty */
-#define SCIF_BRK 0x0010 /* Break Detect */
-#define SCIF_FER 0x0008 /* Framing Error */
-#define SCIF_PER 0x0004 /* Parity Error */
-#define SCIF_RDF 0x0002 /* Receive FIFO Data Full */
-#define SCIF_DR 0x0001 /* Receive Data Ready */
-
-#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-
-/* SCFCR (FIFO Control Register) */
-#define SCFCR_LOOP (1 << 0) /* Loopback Test */
-
-/* SCSPTR (Serial Port Register), optional */
-#define SCSPTR_RTSIO (1 << 7) /* Serial Port RTS Pin Input/Output */
-#define SCSPTR_CTSIO (1 << 5) /* Serial Port CTS Pin Input/Output */
-#define SCSPTR_SPB2IO (1 << 1) /* Serial Port Break Input/Output */
-#define SCSPTR_SPB2DT (1 << 0) /* Serial Port Break Data */
-
-/* HSSRR HSCIF */
-#define HSCIF_SRE 0x8000 /* Sampling Rate Register Enable */
+#define SCSCR_TIE BIT(7) /* Transmit Interrupt Enable */
+#define SCSCR_RIE BIT(6) /* Receive Interrupt Enable */
+#define SCSCR_TE BIT(5) /* Transmit Enable */
+#define SCSCR_RE BIT(4) /* Receive Enable */
+#define SCSCR_REIE BIT(3) /* Receive Error Interrupt Enable @ */
+#define SCSCR_TOIE BIT(2) /* Timeout Interrupt Enable @ */
+#define SCSCR_CKE1 BIT(1) /* Clock Enable 1 */
+#define SCSCR_CKE0 BIT(0) /* Clock Enable 0 */
+
enum {
SCIx_PROBE_REGTYPE,
SCIx_NR_REGTYPES,
};
-/*
- * 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 */
-
- SCIx_NR_REGS,
-};
-
struct device;
struct plat_sci_port_ops {
/*
* Port-specific capabilities
*/
-#define SCIx_HAVE_RTSCTS (1 << 0)
+#define SCIx_HAVE_RTSCTS BIT(0)
/*
* Platform device specific platform_data struct
extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
const char *routine);
-extern char *tty_name(struct tty_struct *tty, char *buf);
+extern const char *tty_name(const struct tty_struct *tty);
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
extern int tty_check_change(struct tty_struct *tty);
extern void __stop_tty(struct tty_struct *tty);