Merge tag 'tty-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH: "Here is the big tty and serial driver update for 4.8-rc1. Lots of good cleanups from Jiri on a number of vt and other tty related things, and the normal driver updates. Full details are in the shortlog. All of these have been in linux-next for a while with no reported issues" * tag 'tty-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (90 commits) tty/serial: atmel: enforce tasklet init and termination sequences serial: sh-sci: Stop transfers in sci_shutdown() serial: 8250_ingenic: drop #if conditional surrounding earlycon code serial: 8250_mtk: drop !defined(MODULE) conditional serial: 8250_uniphier: drop !defined(MODULE) conditional earlycon: mark earlycon code as __used iif the caller is built-in tty/serial/8250: use mctrl_gpio helpers serial: mctrl_gpio: enable API usage only for initialized mctrl_gpios struct serial: mctrl_gpio: add modem control read routine tty/serial/8250: make UART_MCR register access consistent serial: 8250_mid: Read RX buffer on RX DMA timeout for DNV serial: 8250_dma: Export serial8250_rx_dma_flush() dmaengine: hsu: Export hsu_dma_get_status() tty: serial: 8250: add CON_CONSDEV to flags tty: serial: samsung: add byte-order aware bit functions tty: serial: samsung: fixup accessors for endian serial: sirf: make fifo functions static serial: mps2-uart: make driver explicitly non-modular serial: mvebu-uart: free the IRQ in ->shutdown() serial/bcm63xx_uart: use correct alias naming ...
This commit is contained in:
@@ -93,8 +93,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
|
||||
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
|
||||
#endif
|
||||
|
||||
#define STD_COM_FLAGS (0)
|
||||
|
||||
/* firmware stuff */
|
||||
#define ZL_MAX_BLOCKS 16
|
||||
#define DRIVER_VERSION 0x02010203
|
||||
@@ -2288,7 +2286,6 @@ static int cy_get_serial_info(struct cyclades_port *info,
|
||||
.closing_wait = info->port.closing_wait,
|
||||
.baud_base = info->baud,
|
||||
.custom_divisor = info->custom_divisor,
|
||||
.hub6 = 0, /*!!! */
|
||||
};
|
||||
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
|
||||
}
|
||||
@@ -3084,7 +3081,6 @@ static int cy_init_card(struct cyclades_card *cinfo)
|
||||
|
||||
info->port.closing_wait = CLOSING_WAIT_DELAY;
|
||||
info->port.close_delay = 5 * HZ / 10;
|
||||
info->port.flags = STD_COM_FLAGS;
|
||||
init_completion(&info->shutdown_wait);
|
||||
|
||||
if (cy_is_Z(cinfo)) {
|
||||
|
@@ -252,20 +252,11 @@ static int ipwireless_get_serial_info(struct ipw_tty *tty,
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
if (!retinfo)
|
||||
return (-EFAULT);
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tmp.type = PORT_UNKNOWN;
|
||||
tmp.line = tty->index;
|
||||
tmp.port = 0;
|
||||
tmp.irq = 0;
|
||||
tmp.flags = 0;
|
||||
tmp.baud_base = 115200;
|
||||
tmp.close_delay = 0;
|
||||
tmp.closing_wait = 0;
|
||||
tmp.custom_divisor = 0;
|
||||
tmp.hub6 = 0;
|
||||
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
|
@@ -1219,7 +1219,6 @@ static int mxser_get_serial_info(struct tty_struct *tty,
|
||||
.close_delay = info->port.close_delay,
|
||||
.closing_wait = info->port.closing_wait,
|
||||
.custom_divisor = info->custom_divisor,
|
||||
.hub6 = 0
|
||||
};
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
|
@@ -15,6 +15,8 @@
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include "../serial_mctrl_gpio.h"
|
||||
|
||||
struct uart_8250_dma {
|
||||
int (*tx_dma)(struct uart_8250_port *p);
|
||||
int (*rx_dma)(struct uart_8250_port *p);
|
||||
@@ -53,11 +55,9 @@ struct old_serial_port {
|
||||
unsigned int port;
|
||||
unsigned int irq;
|
||||
upf_t flags;
|
||||
unsigned char hub6;
|
||||
unsigned char io_type;
|
||||
unsigned char __iomem *iomem_base;
|
||||
unsigned short iomem_reg_shift;
|
||||
unsigned long irqflags;
|
||||
};
|
||||
|
||||
struct serial8250_config {
|
||||
@@ -131,6 +131,47 @@ void serial8250_rpm_put(struct uart_8250_port *p);
|
||||
int serial8250_em485_init(struct uart_8250_port *p);
|
||||
void serial8250_em485_destroy(struct uart_8250_port *p);
|
||||
|
||||
static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
|
||||
{
|
||||
int mctrl_gpio = 0;
|
||||
|
||||
serial_out(up, UART_MCR, value);
|
||||
|
||||
if (value & UART_MCR_RTS)
|
||||
mctrl_gpio |= TIOCM_RTS;
|
||||
if (value & UART_MCR_DTR)
|
||||
mctrl_gpio |= TIOCM_DTR;
|
||||
|
||||
mctrl_gpio_set(up->gpios, mctrl_gpio);
|
||||
}
|
||||
|
||||
static inline int serial8250_in_MCR(struct uart_8250_port *up)
|
||||
{
|
||||
int mctrl, mctrl_gpio = 0;
|
||||
|
||||
mctrl = serial_in(up, UART_MCR);
|
||||
|
||||
/* save current MCR values */
|
||||
if (mctrl & UART_MCR_RTS)
|
||||
mctrl_gpio |= TIOCM_RTS;
|
||||
if (mctrl & UART_MCR_DTR)
|
||||
mctrl_gpio |= TIOCM_DTR;
|
||||
|
||||
mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio);
|
||||
|
||||
if (mctrl_gpio & TIOCM_RTS)
|
||||
mctrl |= UART_MCR_RTS;
|
||||
else
|
||||
mctrl &= ~UART_MCR_RTS;
|
||||
|
||||
if (mctrl_gpio & TIOCM_DTR)
|
||||
mctrl |= UART_MCR_DTR;
|
||||
else
|
||||
mctrl &= ~UART_MCR_DTR;
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
/*
|
||||
* Digital did something really horribly wrong with the OUT1 and OUT2
|
||||
@@ -237,9 +278,3 @@ static inline int serial_index(struct uart_port *port)
|
||||
{
|
||||
return port->minor - 64;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define DEBUG_INTR(fmt...) printk(fmt)
|
||||
#else
|
||||
#define DEBUG_INTR(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
@@ -114,7 +114,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
||||
struct list_head *l, *end = NULL;
|
||||
int pass_counter = 0, handled = 0;
|
||||
|
||||
DEBUG_INTR("serial8250_interrupt(%d)...", irq);
|
||||
pr_debug("%s(%d): start\n", __func__, irq);
|
||||
|
||||
spin_lock(&i->lock);
|
||||
|
||||
@@ -144,7 +144,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
||||
|
||||
spin_unlock(&i->lock);
|
||||
|
||||
DEBUG_INTR("end.\n");
|
||||
pr_debug("%s(%d): end\n", __func__, irq);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
@@ -546,10 +546,10 @@ static void __init serial8250_isa_init_ports(void)
|
||||
|
||||
port->iobase = old_serial_port[i].port;
|
||||
port->irq = irq_canonicalize(old_serial_port[i].irq);
|
||||
port->irqflags = old_serial_port[i].irqflags;
|
||||
port->irqflags = 0;
|
||||
port->uartclk = old_serial_port[i].baud_base * 16;
|
||||
port->flags = old_serial_port[i].flags;
|
||||
port->hub6 = old_serial_port[i].hub6;
|
||||
port->hub6 = 0;
|
||||
port->membase = old_serial_port[i].iomem_base;
|
||||
port->iotype = old_serial_port[i].io_type;
|
||||
port->regshift = old_serial_port[i].iomem_reg_shift;
|
||||
@@ -675,7 +675,7 @@ static struct console univ8250_console = {
|
||||
.device = uart_console_device,
|
||||
.setup = univ8250_console_setup,
|
||||
.match = univ8250_console_match,
|
||||
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
||||
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV,
|
||||
.index = -1,
|
||||
.data = &serial8250_reg,
|
||||
};
|
||||
@@ -974,6 +974,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
|
||||
uart = serial8250_find_match_or_unused(&up->port);
|
||||
if (uart && uart->port.type != PORT_8250_CIR) {
|
||||
struct mctrl_gpios *gpios;
|
||||
|
||||
if (uart->port.dev)
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
|
||||
@@ -1011,6 +1013,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
if (up->port.flags & UPF_FIXED_TYPE)
|
||||
uart->port.type = up->port.type;
|
||||
|
||||
gpios = mctrl_gpio_init(&uart->port, 0);
|
||||
if (IS_ERR(gpios)) {
|
||||
if (PTR_ERR(gpios) != -ENOSYS)
|
||||
return PTR_ERR(gpios);
|
||||
} else
|
||||
uart->gpios = gpios;
|
||||
|
||||
serial8250_set_defaults(uart);
|
||||
|
||||
/* Possibly override default I/O functions. */
|
||||
|
@@ -145,6 +145,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
|
||||
|
||||
int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
|
@@ -150,6 +150,7 @@ EARLYCON_DECLARE(uart, early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_OMAP
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/irq.h>
|
||||
#include "8250.h"
|
||||
|
||||
#define ADDR_PORT 0
|
||||
@@ -30,6 +31,12 @@
|
||||
#define IO_ADDR2 0x60
|
||||
#define LDN 0x7
|
||||
|
||||
#define IRQ_MODE 0x70
|
||||
#define IRQ_SHARE BIT(4)
|
||||
#define IRQ_MODE_MASK (BIT(6) | BIT(5))
|
||||
#define IRQ_LEVEL_LOW 0
|
||||
#define IRQ_EDGE_HIGH BIT(5)
|
||||
|
||||
#define RS485 0xF0
|
||||
#define RTS_INVERT BIT(5)
|
||||
#define RS485_URA BIT(4)
|
||||
@@ -176,10 +183,37 @@ static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool level_mode)
|
||||
{
|
||||
int status;
|
||||
u8 tmp;
|
||||
|
||||
status = fintek_8250_enter_key(pdata->base_port, pdata->key);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
outb(LDN, pdata->base_port + ADDR_PORT);
|
||||
outb(pdata->index, pdata->base_port + DATA_PORT);
|
||||
|
||||
outb(IRQ_MODE, pdata->base_port + ADDR_PORT);
|
||||
tmp = inb(pdata->base_port + DATA_PORT);
|
||||
|
||||
tmp &= ~IRQ_MODE_MASK;
|
||||
tmp |= IRQ_SHARE;
|
||||
if (!level_mode)
|
||||
tmp |= IRQ_EDGE_HIGH;
|
||||
|
||||
outb(tmp, pdata->base_port + DATA_PORT);
|
||||
fintek_8250_exit_key(pdata->base_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fintek_8250_probe(struct uart_8250_port *uart)
|
||||
{
|
||||
struct fintek_8250 *pdata;
|
||||
struct fintek_8250 probe_data;
|
||||
struct irq_data *irq_data = irq_get_irq_data(uart->port.irq);
|
||||
bool level_mode = irqd_is_level_type(irq_data);
|
||||
|
||||
if (find_base_port(&probe_data, uart->port.iobase))
|
||||
return -ENODEV;
|
||||
@@ -192,5 +226,5 @@ int fintek_8250_probe(struct uart_8250_port *uart)
|
||||
uart->port.rs485_config = fintek_8250_rs485_config;
|
||||
uart->port.private_data = pdata;
|
||||
|
||||
return 0;
|
||||
return fintek_8250_set_irq_mode(pdata, level_mode);
|
||||
}
|
||||
|
@@ -48,7 +48,6 @@ static const struct of_device_id of_match[];
|
||||
#define UART_MCR_MDCE BIT(7)
|
||||
#define UART_MCR_FCM BIT(6)
|
||||
|
||||
#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
|
||||
static struct earlycon_device *early_device;
|
||||
|
||||
static uint8_t __init early_in(struct uart_port *port, int offset)
|
||||
@@ -141,7 +140,6 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
|
||||
EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
|
||||
ingenic_early_console_setup);
|
||||
#endif /* CONFIG_SERIAL_EARLYCON */
|
||||
|
||||
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
|
@@ -96,13 +96,27 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
static int dnv_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct mid8250 *mid = p->private_data;
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
|
||||
u32 status;
|
||||
int ret = IRQ_NONE;
|
||||
int err;
|
||||
|
||||
if (fisr & BIT(2))
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 1);
|
||||
if (fisr & BIT(1))
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 0);
|
||||
if (fisr & BIT(2)) {
|
||||
err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
|
||||
if (err > 0) {
|
||||
serial8250_rx_dma_flush(up);
|
||||
ret |= IRQ_HANDLED;
|
||||
} else if (err == 0)
|
||||
ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
|
||||
}
|
||||
if (fisr & BIT(1)) {
|
||||
err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
|
||||
if (err > 0)
|
||||
ret |= IRQ_HANDLED;
|
||||
else if (err == 0)
|
||||
ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
|
||||
}
|
||||
if (fisr & BIT(0))
|
||||
ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
|
||||
return ret;
|
||||
|
@@ -301,7 +301,7 @@ static struct platform_driver mtk8250_platform_driver = {
|
||||
};
|
||||
module_platform_driver(mtk8250_platform_driver);
|
||||
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init early_mtk8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
|
@@ -134,18 +134,21 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
|
||||
serial8250_do_set_mctrl(port, mctrl);
|
||||
|
||||
/*
|
||||
* Turn off autoRTS if RTS is lowered and restore autoRTS setting
|
||||
* if RTS is raised
|
||||
*/
|
||||
lcr = serial_in(up, UART_LCR);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
|
||||
priv->efr |= UART_EFR_RTS;
|
||||
else
|
||||
priv->efr &= ~UART_EFR_RTS;
|
||||
serial_out(up, UART_EFR, priv->efr);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios,
|
||||
UART_GPIO_RTS))) {
|
||||
/*
|
||||
* Turn off autoRTS if RTS is lowered and restore autoRTS
|
||||
* setting if RTS is raised
|
||||
*/
|
||||
lcr = serial_in(up, UART_LCR);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
|
||||
priv->efr |= UART_EFR_RTS;
|
||||
else
|
||||
priv->efr &= ~UART_EFR_RTS;
|
||||
serial_out(up, UART_EFR, priv->efr);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -280,7 +283,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
||||
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
serial_out(up, UART_MCR, UART_MCR_TCRTLR);
|
||||
serial8250_out_MCR(up, UART_MCR_TCRTLR);
|
||||
serial_out(up, UART_FCR, up->fcr);
|
||||
|
||||
omap8250_update_scr(up, priv);
|
||||
@@ -296,7 +299,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
/* drop TCR + TLR access, we setup XON/XOFF later */
|
||||
serial_out(up, UART_MCR, up->mcr);
|
||||
serial8250_out_MCR(up, up->mcr);
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
@@ -446,7 +449,9 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
priv->efr = 0;
|
||||
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
|
||||
|
||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
|
||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW
|
||||
&& IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios,
|
||||
UART_GPIO_RTS))) {
|
||||
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
|
||||
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
|
||||
priv->efr |= UART_EFR_CTS;
|
||||
|
@@ -1136,11 +1136,11 @@ static int pci_quatech_rqopr(struct uart_8250_port *port)
|
||||
static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val;
|
||||
u8 LCR;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
inb(base + UART_SCR);
|
||||
outb(qopr, base + UART_SCR);
|
||||
outb(LCR, base + UART_LCR);
|
||||
}
|
||||
@@ -1864,6 +1864,16 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_wch_ch355_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
port->port.flags |= UPF_FIXED_TYPE;
|
||||
port->port.type = PORT_16550A;
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_wch_ch38x_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
@@ -1915,6 +1925,7 @@ pci_wch_ch38x_setup(struct serial_private *priv,
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
|
||||
#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
|
||||
#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173
|
||||
#define PCI_VENDOR_ID_AGESTAR 0x5372
|
||||
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
|
||||
#define PCI_VENDOR_ID_ASIX 0x9710
|
||||
@@ -2618,6 +2629,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch353_setup,
|
||||
},
|
||||
/* WCH CH355 4S card (16550 clone) */
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_WCH,
|
||||
.device = PCI_DEVICE_ID_WCH_CH355_4S,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch355_setup,
|
||||
},
|
||||
/* WCH CH382 2S card (16850 clone) */
|
||||
{
|
||||
.vendor = PCIE_VENDOR_ID_WCH,
|
||||
@@ -3812,6 +3831,7 @@ static const struct pci_device_id blacklist[] = {
|
||||
/* multi-io cards handled by parport_serial */
|
||||
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x7173), }, /* WCH CH355 4S */
|
||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
|
||||
|
||||
@@ -5567,6 +5587,10 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0, pbn_b0_bt_2_115200 },
|
||||
|
||||
{ PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0, pbn_b0_bt_4_115200 },
|
||||
|
||||
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0, pbn_wch382_2 },
|
||||
|
@@ -527,13 +527,13 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
|
||||
|
||||
static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned char mcr = serial_in(p, UART_MCR);
|
||||
unsigned char mcr = serial8250_in_MCR(p);
|
||||
|
||||
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial_out(p, UART_MCR, mcr);
|
||||
serial8250_out_MCR(p, mcr);
|
||||
}
|
||||
|
||||
static void serial8250_em485_handle_start_tx(unsigned long arg);
|
||||
@@ -785,10 +785,10 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
old_lcr = serial_in(up, UART_LCR);
|
||||
serial_out(up, UART_LCR, 0);
|
||||
old_fcr = serial_in(up, UART_FCR);
|
||||
old_mcr = serial_in(up, UART_MCR);
|
||||
old_mcr = serial8250_in_MCR(up);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
||||
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||
serial_out(up, UART_MCR, UART_MCR_LOOP);
|
||||
serial8250_out_MCR(up, UART_MCR_LOOP);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
old_dl = serial_dl_read(up);
|
||||
serial_dl_write(up, 0x0001);
|
||||
@@ -800,7 +800,7 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
(count < 256); count++)
|
||||
serial_in(up, UART_RX);
|
||||
serial_out(up, UART_FCR, old_fcr);
|
||||
serial_out(up, UART_MCR, old_mcr);
|
||||
serial8250_out_MCR(up, old_mcr);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
serial_dl_write(up, old_dl);
|
||||
serial_out(up, UART_LCR, old_lcr);
|
||||
@@ -1040,17 +1040,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
|
||||
* it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
|
||||
*/
|
||||
serial_out(up, UART_LCR, 0);
|
||||
status1 = serial_in(up, UART_MCR);
|
||||
status1 = serial8250_in_MCR(up);
|
||||
serial_out(up, UART_LCR, 0xE0);
|
||||
status2 = serial_in(up, 0x02); /* EXCR1 */
|
||||
|
||||
if (!((status2 ^ status1) & UART_MCR_LOOP)) {
|
||||
serial_out(up, UART_LCR, 0);
|
||||
serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP);
|
||||
serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP);
|
||||
serial_out(up, UART_LCR, 0xE0);
|
||||
status2 = serial_in(up, 0x02); /* EXCR1 */
|
||||
serial_out(up, UART_LCR, 0);
|
||||
serial_out(up, UART_MCR, status1);
|
||||
serial8250_out_MCR(up, status1);
|
||||
|
||||
if ((status2 ^ status1) & UART_MCR_LOOP) {
|
||||
unsigned short quot;
|
||||
@@ -1224,7 +1224,7 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
}
|
||||
}
|
||||
|
||||
save_mcr = serial_in(up, UART_MCR);
|
||||
save_mcr = serial8250_in_MCR(up);
|
||||
save_lcr = serial_in(up, UART_LCR);
|
||||
|
||||
/*
|
||||
@@ -1237,9 +1237,9 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
* that conflicts with COM 1-4 --- we hope!
|
||||
*/
|
||||
if (!(port->flags & UPF_SKIP_TEST)) {
|
||||
serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
|
||||
serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
|
||||
status1 = serial_in(up, UART_MSR) & 0xF0;
|
||||
serial_out(up, UART_MCR, save_mcr);
|
||||
serial8250_out_MCR(up, save_mcr);
|
||||
if (status1 != 0x90) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
|
||||
@@ -1305,7 +1305,7 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
if (port->type == PORT_RSA)
|
||||
serial_out(up, UART_RSA_FRR, 0);
|
||||
#endif
|
||||
serial_out(up, UART_MCR, save_mcr);
|
||||
serial8250_out_MCR(up, save_mcr);
|
||||
serial8250_clear_fifos(up);
|
||||
serial_in(up, UART_RX);
|
||||
if (up->capabilities & UART_CAP_UUE)
|
||||
@@ -1353,19 +1353,18 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
|
||||
/* forget possible initially masked and pending IRQ */
|
||||
probe_irq_off(probe_irq_on());
|
||||
save_mcr = serial_in(up, UART_MCR);
|
||||
save_mcr = serial8250_in_MCR(up);
|
||||
save_ier = serial_in(up, UART_IER);
|
||||
serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
|
||||
serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2);
|
||||
|
||||
irqs = probe_irq_on();
|
||||
serial_out(up, UART_MCR, 0);
|
||||
serial8250_out_MCR(up, 0);
|
||||
udelay(10);
|
||||
if (port->flags & UPF_FOURPORT) {
|
||||
serial_out(up, UART_MCR,
|
||||
UART_MCR_DTR | UART_MCR_RTS);
|
||||
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
|
||||
} else {
|
||||
serial_out(up, UART_MCR,
|
||||
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
|
||||
serial8250_out_MCR(up,
|
||||
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
|
||||
}
|
||||
serial_out(up, UART_IER, 0x0f); /* enable all intrs */
|
||||
serial_in(up, UART_LSR);
|
||||
@@ -1376,7 +1375,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
udelay(20);
|
||||
irq = probe_irq_off(irqs);
|
||||
|
||||
serial_out(up, UART_MCR, save_mcr);
|
||||
serial8250_out_MCR(up, save_mcr);
|
||||
serial_out(up, UART_IER, save_ier);
|
||||
|
||||
if (port->flags & UPF_FOURPORT)
|
||||
@@ -1549,14 +1548,14 @@ static inline void start_tx_rs485(struct uart_port *port)
|
||||
del_timer(&em485->stop_tx_timer);
|
||||
em485->active_timer = NULL;
|
||||
|
||||
mcr = serial_in(up, UART_MCR);
|
||||
mcr = serial8250_in_MCR(up);
|
||||
if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
|
||||
!!(mcr & UART_MCR_RTS)) {
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial_out(up, UART_MCR, mcr);
|
||||
serial8250_out_MCR(up, mcr);
|
||||
|
||||
if (up->port.rs485.delay_rts_before_send > 0) {
|
||||
em485->active_timer = &em485->start_tx_timer;
|
||||
@@ -1619,6 +1618,8 @@ static void serial8250_disable_ms(struct uart_port *port)
|
||||
if (up->bugs & UART_BUG_NOMSR)
|
||||
return;
|
||||
|
||||
mctrl_gpio_disable_ms(up->gpios);
|
||||
|
||||
up->ier &= ~UART_IER_MSI;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
}
|
||||
@@ -1631,6 +1632,8 @@ static void serial8250_enable_ms(struct uart_port *port)
|
||||
if (up->bugs & UART_BUG_NOMSR)
|
||||
return;
|
||||
|
||||
mctrl_gpio_enable_ms(up->gpios);
|
||||
|
||||
up->ier |= UART_IER_MSI;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
@@ -1686,7 +1689,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||
lsr &= port->read_status_mask;
|
||||
|
||||
if (lsr & UART_LSR_BI) {
|
||||
DEBUG_INTR("handling break....");
|
||||
pr_debug("%s: handling break\n", __func__);
|
||||
flag = TTY_BREAK;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
@@ -1757,7 +1760,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
DEBUG_INTR("THRE...");
|
||||
pr_debug("%s: THRE\n", __func__);
|
||||
|
||||
/*
|
||||
* With RPM enabled, we have to wait until the FIFO is empty before the
|
||||
@@ -1823,7 +1826,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
|
||||
status = serial_port_in(port, UART_LSR);
|
||||
|
||||
DEBUG_INTR("status = %x...", status);
|
||||
pr_debug("%s: status = %x\n", __func__, status);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (!up->dma || handle_rx_dma(up, iir))
|
||||
@@ -1861,7 +1864,6 @@ static int serial8250_default_handle_irq(struct uart_port *port)
|
||||
*/
|
||||
static int exar_handle_irq(struct uart_port *port)
|
||||
{
|
||||
unsigned char int0, int1, int2, int3;
|
||||
unsigned int iir = serial_port_in(port, UART_IIR);
|
||||
int ret;
|
||||
|
||||
@@ -1869,10 +1871,10 @@ static int exar_handle_irq(struct uart_port *port)
|
||||
|
||||
if ((port->type == PORT_XR17V35X) ||
|
||||
(port->type == PORT_XR17D15X)) {
|
||||
int0 = serial_port_in(port, 0x80);
|
||||
int1 = serial_port_in(port, 0x81);
|
||||
int2 = serial_port_in(port, 0x82);
|
||||
int3 = serial_port_in(port, 0x83);
|
||||
serial_port_in(port, 0x80);
|
||||
serial_port_in(port, 0x81);
|
||||
serial_port_in(port, 0x82);
|
||||
serial_port_in(port, 0x83);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1915,7 +1917,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
|
||||
ret |= TIOCM_DSR;
|
||||
if (status & UART_MSR_CTS)
|
||||
ret |= TIOCM_CTS;
|
||||
return ret;
|
||||
|
||||
return mctrl_gpio_get(up->gpios, &ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
|
||||
|
||||
@@ -1944,7 +1947,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
|
||||
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
|
||||
|
||||
serial_port_out(port, UART_MCR, mcr);
|
||||
serial8250_out_MCR(up, mcr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
|
||||
|
||||
@@ -1994,8 +1997,6 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
unsigned int tmout;
|
||||
|
||||
for (tmout = 1000000; tmout; tmout--) {
|
||||
unsigned int msr = serial_in(up, UART_MSR);
|
||||
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
|
||||
@@ -3093,7 +3094,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
|
||||
|
||||
serial8250_set_divisor(port, baud, quot, frac);
|
||||
serial_port_out(port, UART_LCR, up->lcr);
|
||||
serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
|
||||
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -35,7 +35,7 @@ struct uniphier8250_priv {
|
||||
spinlock_t atomic_write_lock;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init uniphier_early_console_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
|
@@ -6,6 +6,7 @@
|
||||
config SERIAL_8250
|
||||
tristate "8250/16550 and compatible serial support"
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
---help---
|
||||
This selects whether you want to include the driver for the standard
|
||||
serial ports. The standard answer is Y. People who might say N
|
||||
@@ -387,7 +388,8 @@ config SERIAL_8250_MT6577
|
||||
|
||||
config SERIAL_8250_UNIPHIER
|
||||
tristate "Support for UniPhier on-chip UART"
|
||||
depends on SERIAL_8250 && ARCH_UNIPHIER
|
||||
depends on SERIAL_8250
|
||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||
help
|
||||
If you have a UniPhier based board and want to use the on-chip
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
@@ -395,7 +397,7 @@ config SERIAL_8250_UNIPHIER
|
||||
config SERIAL_8250_INGENIC
|
||||
tristate "Support for Ingenic SoC serial ports"
|
||||
depends on SERIAL_8250
|
||||
depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
|
||||
depends on OF_FLATTREE
|
||||
depends on MIPS || COMPILE_TEST
|
||||
help
|
||||
If you have a system using an Ingenic SoC and wish to make use of
|
||||
|
@@ -736,6 +736,7 @@ config SERIAL_SH_SCI
|
||||
tristate "SuperH SCI(F) serial port support"
|
||||
depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
|
||||
config SERIAL_SH_SCI_NR_UARTS
|
||||
int "Maximum number of SCI(F) serial ports"
|
||||
@@ -1477,7 +1478,7 @@ config SERIAL_MPS2_UART_CONSOLE
|
||||
|
||||
config SERIAL_MPS2_UART
|
||||
bool "MPS2 UART port"
|
||||
depends on ARM || COMPILE_TEST
|
||||
depends on ARCH_MPS2 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver support the UART ports on ARM MPS2.
|
||||
|
@@ -2553,11 +2553,17 @@ static int sbsa_uart_probe(struct platform_device *pdev)
|
||||
if (!uap)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||
return ret;
|
||||
}
|
||||
uap->port.irq = ret;
|
||||
|
||||
uap->reg_offset = vendor_sbsa.reg_offset;
|
||||
uap->vendor = &vendor_sbsa;
|
||||
uap->fifosize = 32;
|
||||
uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM;
|
||||
uap->port.irq = platform_get_irq(pdev, 0);
|
||||
uap->port.ops = &sbsa_uart_pops;
|
||||
uap->fixed_baud = baudrate;
|
||||
|
||||
|
@@ -108,6 +108,12 @@ struct atmel_uart_char {
|
||||
u16 ch;
|
||||
};
|
||||
|
||||
/*
|
||||
* Be careful, the real size of the ring buffer is
|
||||
* sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer
|
||||
* can contain up to 1024 characters in PIO mode and up to 4096 characters in
|
||||
* DMA mode.
|
||||
*/
|
||||
#define ATMEL_SERIAL_RINGSIZE 1024
|
||||
|
||||
/*
|
||||
@@ -145,10 +151,10 @@ struct atmel_uart_port {
|
||||
dma_cookie_t cookie_rx;
|
||||
struct scatterlist sg_tx;
|
||||
struct scatterlist sg_rx;
|
||||
struct tasklet_struct tasklet;
|
||||
unsigned int irq_status;
|
||||
struct tasklet_struct tasklet_rx;
|
||||
struct tasklet_struct tasklet_tx;
|
||||
atomic_t tasklet_shutdown;
|
||||
unsigned int irq_status_prev;
|
||||
unsigned int status_change;
|
||||
unsigned int tx_len;
|
||||
|
||||
struct circ_buf rx_ring;
|
||||
@@ -281,6 +287,13 @@ static bool atmel_use_fifo(struct uart_port *port)
|
||||
return atmel_port->fifo_size;
|
||||
}
|
||||
|
||||
static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
|
||||
struct tasklet_struct *t)
|
||||
{
|
||||
if (!atomic_read(&atmel_port->tasklet_shutdown))
|
||||
tasklet_schedule(t);
|
||||
}
|
||||
|
||||
static unsigned int atmel_get_lines_status(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
@@ -482,19 +495,21 @@ static void atmel_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port)) {
|
||||
if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN)
|
||||
/* The transmitter is already running. Yes, we
|
||||
really need this.*/
|
||||
return;
|
||||
if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
|
||||
& ATMEL_PDC_TXTEN))
|
||||
/* The transmitter is already running. Yes, we
|
||||
really need this.*/
|
||||
return;
|
||||
|
||||
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
atmel_stop_rx(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port))
|
||||
/* re-enable PDC transmit */
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
|
||||
}
|
||||
@@ -710,7 +725,7 @@ static void atmel_rx_chars(struct uart_port *port)
|
||||
status = atmel_uart_readl(port, ATMEL_US_CSR);
|
||||
}
|
||||
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -781,7 +796,7 @@ static void atmel_complete_tx_dma(void *arg)
|
||||
* remaining data from the beginning of xmit->buf to xmit->head.
|
||||
*/
|
||||
if (!uart_circ_empty(xmit))
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
@@ -966,7 +981,7 @@ static void atmel_complete_rx_dma(void *arg)
|
||||
struct uart_port *port = arg;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
|
||||
}
|
||||
|
||||
static void atmel_release_rx_dma(struct uart_port *port)
|
||||
@@ -1006,7 +1021,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
if (dmastat == DMA_ERROR) {
|
||||
dev_dbg(port->dev, "Get residue error, restart tasklet\n");
|
||||
atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1160,8 +1175,11 @@ static void atmel_uart_timer_callback(unsigned long data)
|
||||
struct uart_port *port = (void *)data;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
|
||||
if (!atomic_read(&atmel_port->tasklet_shutdown)) {
|
||||
tasklet_schedule(&atmel_port->tasklet_rx);
|
||||
mod_timer(&atmel_port->uart_timer,
|
||||
jiffies + uart_poll_timeout(port));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1183,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
|
||||
if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
|
||||
atmel_uart_writel(port, ATMEL_US_IDR,
|
||||
(ATMEL_US_ENDRX | ATMEL_US_TIMEOUT));
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port,
|
||||
&atmel_port->tasklet_rx);
|
||||
}
|
||||
|
||||
if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
|
||||
@@ -1195,7 +1214,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
|
||||
if (pending & ATMEL_US_TIMEOUT) {
|
||||
atmel_uart_writel(port, ATMEL_US_IDR,
|
||||
ATMEL_US_TIMEOUT);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port,
|
||||
&atmel_port->tasklet_rx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,7 +1245,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
|
||||
/* Either PDC or interrupt transmission */
|
||||
atmel_uart_writel(port, ATMEL_US_IDR,
|
||||
atmel_port->tx_done_mask);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1237,14 +1257,27 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
|
||||
unsigned int status)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status_change;
|
||||
|
||||
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;
|
||||
status_change = status ^ atmel_port->irq_status_prev;
|
||||
atmel_port->irq_status_prev = status;
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
|
||||
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
|
||||
| ATMEL_US_DCD | ATMEL_US_CTS)) {
|
||||
/* TODO: All reads to CSR will clear these interrupts! */
|
||||
if (status_change & ATMEL_US_RI)
|
||||
port->icount.rng++;
|
||||
if (status_change & ATMEL_US_DSR)
|
||||
port->icount.dsr++;
|
||||
if (status_change & ATMEL_US_DCD)
|
||||
uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
|
||||
if (status_change & ATMEL_US_CTS)
|
||||
uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1571,37 +1604,25 @@ static int atmel_prepare_rx_pdc(struct uart_port *port)
|
||||
/*
|
||||
* tasklet handling tty stuff outside the interrupt handler.
|
||||
*/
|
||||
static void atmel_tasklet_func(unsigned long data)
|
||||
static void atmel_tasklet_rx_func(unsigned long data)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status = 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);
|
||||
|
||||
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
|
||||
| ATMEL_US_DCD | ATMEL_US_CTS)) {
|
||||
/* TODO: All reads to CSR will clear these interrupts! */
|
||||
if (status_change & ATMEL_US_RI)
|
||||
port->icount.rng++;
|
||||
if (status_change & ATMEL_US_DSR)
|
||||
port->icount.dsr++;
|
||||
if (status_change & ATMEL_US_DCD)
|
||||
uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
|
||||
if (status_change & ATMEL_US_CTS)
|
||||
uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
|
||||
atmel_port->status_change = 0;
|
||||
}
|
||||
|
||||
atmel_port->schedule_rx(port);
|
||||
spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
static void atmel_tasklet_tx_func(unsigned long data)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
/* The interrupt handler does not take the lock */
|
||||
spin_lock(&port->lock);
|
||||
atmel_port->schedule_tx(port);
|
||||
spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
@@ -1785,7 +1806,11 @@ static int atmel_startup(struct uart_port *port)
|
||||
return retval;
|
||||
}
|
||||
|
||||
tasklet_enable(&atmel_port->tasklet);
|
||||
atomic_set(&atmel_port->tasklet_shutdown, 0);
|
||||
tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func,
|
||||
(unsigned long)port);
|
||||
tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func,
|
||||
(unsigned long)port);
|
||||
|
||||
/*
|
||||
* Initialize DMA (if necessary)
|
||||
@@ -1833,7 +1858,6 @@ static int atmel_startup(struct uart_port *port)
|
||||
|
||||
/* Save current CSR for comparison in atmel_tasklet_func() */
|
||||
atmel_port->irq_status_prev = atmel_get_lines_status(port);
|
||||
atmel_port->irq_status = atmel_port->irq_status_prev;
|
||||
|
||||
/*
|
||||
* Finally, enable the serial port
|
||||
@@ -1905,29 +1929,36 @@ static void atmel_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
/* Disable interrupts at device level */
|
||||
atmel_uart_writel(port, ATMEL_US_IDR, -1);
|
||||
|
||||
/* Prevent spurious interrupts from scheduling the tasklet */
|
||||
atomic_inc(&atmel_port->tasklet_shutdown);
|
||||
|
||||
/*
|
||||
* Prevent any tasklets being scheduled during
|
||||
* cleanup
|
||||
*/
|
||||
del_timer_sync(&atmel_port->uart_timer);
|
||||
|
||||
/* Make sure that no interrupt is on the fly */
|
||||
synchronize_irq(port->irq);
|
||||
|
||||
/*
|
||||
* Clear out any scheduled tasklets before
|
||||
* we destroy the buffers
|
||||
*/
|
||||
tasklet_disable(&atmel_port->tasklet);
|
||||
tasklet_kill(&atmel_port->tasklet);
|
||||
tasklet_kill(&atmel_port->tasklet_rx);
|
||||
tasklet_kill(&atmel_port->tasklet_tx);
|
||||
|
||||
/*
|
||||
* Ensure everything is stopped and
|
||||
* disable all interrupts, port and break condition.
|
||||
* disable port and break condition.
|
||||
*/
|
||||
atmel_stop_rx(port);
|
||||
atmel_stop_tx(port);
|
||||
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);
|
||||
atmel_uart_writel(port, ATMEL_US_IDR, -1);
|
||||
|
||||
|
||||
/*
|
||||
* Shut-down the DMA.
|
||||
@@ -2311,10 +2342,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
port->irq = pdev->resource[1].start;
|
||||
port->rs485_config = atmel_config_rs485;
|
||||
|
||||
tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
|
||||
(unsigned long)port);
|
||||
tasklet_disable(&atmel_port->tasklet);
|
||||
|
||||
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
|
||||
|
||||
if (pdata && pdata->regs) {
|
||||
@@ -2699,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
atmel_port->uart.line = ret;
|
||||
atmel_serial_probe_fifos(atmel_port, pdev);
|
||||
|
||||
atomic_set(&atmel_port->tasklet_shutdown, 0);
|
||||
spin_lock_init(&atmel_port->lock_suspended);
|
||||
|
||||
ret = atmel_init_port(atmel_port, pdev);
|
||||
@@ -2795,7 +2823,8 @@ static int atmel_serial_remove(struct platform_device *pdev)
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
int ret = 0;
|
||||
|
||||
tasklet_kill(&atmel_port->tasklet);
|
||||
tasklet_kill(&atmel_port->tasklet_rx);
|
||||
tasklet_kill(&atmel_port->tasklet_tx);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
|
@@ -813,8 +813,12 @@ static int bcm_uart_probe(struct platform_device *pdev)
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
|
||||
if (pdev->dev.of_node) {
|
||||
pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
|
||||
if (pdev->id < 0)
|
||||
pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
|
||||
}
|
||||
|
||||
if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
|
||||
return -EINVAL;
|
||||
|
@@ -1830,7 +1830,13 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->port.iotype = UPIO_MEM;
|
||||
sport->port.irq = platform_get_irq(pdev, 0);
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||
return ret;
|
||||
}
|
||||
sport->port.irq = ret;
|
||||
|
||||
if (sport->lpuart32)
|
||||
sport->port.ops = &lpuart32_pops;
|
||||
else
|
||||
|
@@ -30,7 +30,6 @@
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/ioport.h>
|
||||
@@ -51,9 +50,6 @@
|
||||
|
||||
#define PASS_LIMIT 256
|
||||
|
||||
/* Standard COM flags */
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
|
||||
|
||||
static const struct {
|
||||
unsigned int port;
|
||||
unsigned int irq;
|
||||
@@ -892,7 +888,7 @@ static void __init m32r_sio_init_ports(void)
|
||||
up->port.iobase = old_serial_port[i].port;
|
||||
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
|
||||
up->port.uartclk = BAUD_RATE * 16;
|
||||
up->port.flags = STD_COM_FLAGS;
|
||||
up->port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
|
||||
up->port.membase = 0;
|
||||
up->port.iotype = 0;
|
||||
up->port.regshift = 0;
|
||||
@@ -1060,19 +1056,4 @@ static int __init m32r_sio_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit m32r_sio_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < UART_NR; i++)
|
||||
uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
|
||||
|
||||
uart_unregister_driver(&m32r_sio_reg);
|
||||
}
|
||||
|
||||
module_init(m32r_sio_init);
|
||||
module_exit(m32r_sio_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Generic M32R SIO serial driver");
|
||||
device_initcall(m32r_sio_init);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
|
||||
*
|
||||
* Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
|
||||
* Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
|
||||
* Based on max3110.c, by Feng Tang <feng.tang@intel.com>
|
||||
@@ -32,6 +32,7 @@
|
||||
#define MAX310X_NAME "max310x"
|
||||
#define MAX310X_MAJOR 204
|
||||
#define MAX310X_MINOR 209
|
||||
#define MAX310X_UART_NRMAX 16
|
||||
|
||||
/* MAX310X register definitions */
|
||||
#define MAX310X_RHR_REG (0x00) /* RX FIFO */
|
||||
@@ -155,10 +156,6 @@
|
||||
#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
|
||||
#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
|
||||
#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
|
||||
#define MAX310X_LCR_WORD_LEN_5 (0x00)
|
||||
#define MAX310X_LCR_WORD_LEN_6 (0x01)
|
||||
#define MAX310X_LCR_WORD_LEN_7 (0x02)
|
||||
#define MAX310X_LCR_WORD_LEN_8 (0x03)
|
||||
|
||||
/* IRDA register bits */
|
||||
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
|
||||
@@ -262,10 +259,10 @@ struct max310x_one {
|
||||
struct uart_port port;
|
||||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
struct work_struct rs_work;
|
||||
};
|
||||
|
||||
struct max310x_port {
|
||||
struct uart_driver uart;
|
||||
struct max310x_devtype *devtype;
|
||||
struct regmap *regmap;
|
||||
struct mutex mutex;
|
||||
@@ -276,6 +273,17 @@ struct max310x_port {
|
||||
struct max310x_one p[0];
|
||||
};
|
||||
|
||||
static struct uart_driver max310x_uart = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = MAX310X_NAME,
|
||||
.dev_name = "ttyMAX",
|
||||
.major = MAX310X_MAJOR,
|
||||
.minor = MAX310X_MINOR,
|
||||
.nr = MAX310X_UART_NRMAX,
|
||||
};
|
||||
|
||||
static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX);
|
||||
|
||||
static u8 max310x_port_read(struct uart_port *port, u8 reg)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(port->dev);
|
||||
@@ -594,9 +602,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||
unsigned int sts, ch, flag;
|
||||
|
||||
if (unlikely(rxlen >= port->fifosize)) {
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"Port %i: Possible RX FIFO overrun\n",
|
||||
port->line);
|
||||
dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n");
|
||||
port->icount.buf_overrun++;
|
||||
/* Ensure sanity of RX level */
|
||||
rxlen = port->fifosize;
|
||||
@@ -715,13 +721,13 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
|
||||
{
|
||||
struct max310x_port *s = (struct max310x_port *)dev_id;
|
||||
|
||||
if (s->uart.nr > 1) {
|
||||
if (s->devtype->nr > 1) {
|
||||
do {
|
||||
unsigned int val = ~0;
|
||||
|
||||
WARN_ON_ONCE(regmap_read(s->regmap,
|
||||
MAX310X_GLOBALIRQ_REG, &val));
|
||||
val = ((1 << s->uart.nr) - 1) & ~val;
|
||||
val = ((1 << s->devtype->nr) - 1) & ~val;
|
||||
if (!val)
|
||||
break;
|
||||
max310x_port_irq(s, fls(val) - 1);
|
||||
@@ -796,7 +802,7 @@ static void max310x_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int lcr, flow = 0;
|
||||
unsigned int lcr = 0, flow = 0;
|
||||
int baud;
|
||||
|
||||
/* Mask termios capabilities we don't support */
|
||||
@@ -805,17 +811,16 @@ static void max310x_set_termios(struct uart_port *port,
|
||||
/* Word size */
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr = MAX310X_LCR_WORD_LEN_5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr = MAX310X_LCR_WORD_LEN_6;
|
||||
lcr = MAX310X_LCR_LENGTH0_BIT;
|
||||
break;
|
||||
case CS7:
|
||||
lcr = MAX310X_LCR_WORD_LEN_7;
|
||||
lcr = MAX310X_LCR_LENGTH1_BIT;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr = MAX310X_LCR_WORD_LEN_8;
|
||||
lcr = MAX310X_LCR_LENGTH1_BIT | MAX310X_LCR_LENGTH0_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -877,36 +882,45 @@ static void max310x_set_termios(struct uart_port *port,
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
}
|
||||
|
||||
static int max310x_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
static void max310x_rs_proc(struct work_struct *ws)
|
||||
{
|
||||
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
|
||||
unsigned int val;
|
||||
|
||||
if (rs485->delay_rts_before_send > 0x0f ||
|
||||
rs485->delay_rts_after_send > 0x0f)
|
||||
return -ERANGE;
|
||||
val = (one->port.rs485.delay_rts_before_send << 4) |
|
||||
one->port.rs485.delay_rts_after_send;
|
||||
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val);
|
||||
|
||||
val = (rs485->delay_rts_before_send << 4) |
|
||||
rs485->delay_rts_after_send;
|
||||
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
if (one->port.rs485.flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(&one->port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
} else {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
max310x_port_update(&one->port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int max310x_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct max310x_one *one = container_of(port, struct max310x_one, port);
|
||||
|
||||
if ((rs485->delay_rts_before_send > 0x0f) ||
|
||||
(rs485->delay_rts_after_send > 0x0f))
|
||||
return -ERANGE;
|
||||
|
||||
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
port->rs485 = *rs485;
|
||||
|
||||
schedule_work(&one->rs_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1009,8 +1023,8 @@ static int __maybe_unused max310x_suspend(struct device *dev)
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
uart_suspend_port(&s->uart, &s->p[i].port);
|
||||
for (i = 0; i < s->devtype->nr; i++) {
|
||||
uart_suspend_port(&max310x_uart, &s->p[i].port);
|
||||
s->devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
@@ -1022,9 +1036,9 @@ static int __maybe_unused max310x_resume(struct device *dev)
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
for (i = 0; i < s->devtype->nr; i++) {
|
||||
s->devtype->power(&s->p[i].port, 1);
|
||||
uart_resume_port(&s->uart, &s->p[i].port);
|
||||
uart_resume_port(&max310x_uart, &s->p[i].port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1159,18 +1173,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
uartclk = max310x_set_ref_clk(s, freq, xtal);
|
||||
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
|
||||
|
||||
/* Register UART driver */
|
||||
s->uart.owner = THIS_MODULE;
|
||||
s->uart.dev_name = "ttyMAX";
|
||||
s->uart.major = MAX310X_MAJOR;
|
||||
s->uart.minor = MAX310X_MINOR;
|
||||
s->uart.nr = devtype->nr;
|
||||
ret = uart_register_driver(&s->uart);
|
||||
if (ret) {
|
||||
dev_err(dev, "Registering UART driver failed\n");
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/* Setup GPIO cotroller */
|
||||
s->gpio.owner = THIS_MODULE;
|
||||
@@ -1183,16 +1185,24 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
s->gpio.base = -1;
|
||||
s->gpio.ngpio = devtype->nr * 4;
|
||||
s->gpio.can_sleep = 1;
|
||||
ret = gpiochip_add_data(&s->gpio, s);
|
||||
ret = devm_gpiochip_add_data(dev, &s->gpio, s);
|
||||
if (ret)
|
||||
goto out_uart;
|
||||
goto out_clk;
|
||||
#endif
|
||||
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
unsigned int line;
|
||||
|
||||
line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
|
||||
if (line == MAX310X_UART_NRMAX) {
|
||||
ret = -ERANGE;
|
||||
goto out_uart;
|
||||
}
|
||||
|
||||
/* Initialize port data */
|
||||
s->p[i].port.line = i;
|
||||
s->p[i].port.line = line;
|
||||
s->p[i].port.dev = dev;
|
||||
s->p[i].port.irq = irq;
|
||||
s->p[i].port.type = PORT_MAX310X;
|
||||
@@ -1214,10 +1224,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
MAX310X_MODE1_IRQSEL_BIT);
|
||||
/* Initialize queue for start TX */
|
||||
INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
|
||||
/* Initialize queue for changing mode */
|
||||
/* Initialize queue for changing LOOPBACK mode */
|
||||
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
|
||||
/* Initialize queue for changing RS485 mode */
|
||||
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
|
||||
|
||||
/* Register port */
|
||||
uart_add_one_port(&s->uart, &s->p[i].port);
|
||||
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
|
||||
if (ret) {
|
||||
s->p[i].port.dev = NULL;
|
||||
goto out_uart;
|
||||
}
|
||||
set_bit(line, max310x_lines);
|
||||
|
||||
/* Go to suspend mode */
|
||||
devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
@@ -1230,14 +1249,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
|
||||
dev_err(dev, "Unable to reguest IRQ %i\n", irq);
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
gpiochip_remove(&s->gpio);
|
||||
|
||||
out_uart:
|
||||
#endif
|
||||
uart_unregister_driver(&s->uart);
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
if (s->p[i].port.dev) {
|
||||
uart_remove_one_port(&max310x_uart, &s->p[i].port);
|
||||
clear_bit(s->p[i].port.line, max310x_lines);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
out_clk:
|
||||
clk_disable_unprepare(s->clk);
|
||||
@@ -1250,19 +1270,16 @@ static int max310x_remove(struct device *dev)
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
gpiochip_remove(&s->gpio);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
for (i = 0; i < s->devtype->nr; i++) {
|
||||
cancel_work_sync(&s->p[i].tx_work);
|
||||
cancel_work_sync(&s->p[i].md_work);
|
||||
uart_remove_one_port(&s->uart, &s->p[i].port);
|
||||
cancel_work_sync(&s->p[i].rs_work);
|
||||
uart_remove_one_port(&max310x_uart, &s->p[i].port);
|
||||
clear_bit(s->p[i].port.line, max310x_lines);
|
||||
s->devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
uart_unregister_driver(&s->uart);
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return 0;
|
||||
@@ -1335,7 +1352,7 @@ static const struct spi_device_id max310x_id_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max310x_id_table);
|
||||
|
||||
static struct spi_driver max310x_uart_driver = {
|
||||
static struct spi_driver max310x_spi_driver = {
|
||||
.driver = {
|
||||
.name = MAX310X_NAME,
|
||||
.of_match_table = of_match_ptr(max310x_dt_ids),
|
||||
@@ -1345,9 +1362,36 @@ static struct spi_driver max310x_uart_driver = {
|
||||
.remove = max310x_spi_remove,
|
||||
.id_table = max310x_id_table,
|
||||
};
|
||||
module_spi_driver(max310x_uart_driver);
|
||||
#endif
|
||||
|
||||
static int __init max310x_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bitmap_zero(max310x_lines, MAX310X_UART_NRMAX);
|
||||
|
||||
ret = uart_register_driver(&max310x_uart);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
spi_register_driver(&max310x_spi_driver);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(max310x_uart_init);
|
||||
|
||||
static void __exit max310x_uart_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
spi_unregister_driver(&max310x_spi_driver);
|
||||
#endif
|
||||
|
||||
uart_unregister_driver(&max310x_uart);
|
||||
}
|
||||
module_exit(max310x_uart_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
|
||||
MODULE_DESCRIPTION("MAX310X serial driver");
|
||||
|
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
* MPS2 UART driver
|
||||
*
|
||||
* Copyright (C) 2015 ARM Limited
|
||||
*
|
||||
* Author: Vladimir Murzin <vladimir.murzin@arm.com>
|
||||
@@ -17,7 +19,6 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -569,30 +570,20 @@ static int mps2_serial_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mps2_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&mps2_uart_driver, &mps_port->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id mps2_match[] = {
|
||||
{ .compatible = "arm,mps2-uart", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mps2_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver mps2_serial_driver = {
|
||||
.probe = mps2_serial_probe,
|
||||
.remove = mps2_serial_remove,
|
||||
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(mps2_match),
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -610,16 +601,4 @@ static int __init mps2_uart_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(mps2_uart_init);
|
||||
|
||||
static void __exit mps2_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mps2_serial_driver);
|
||||
uart_unregister_driver(&mps2_uart_driver);
|
||||
}
|
||||
module_exit(mps2_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Vladimir Murzin <vladimir.murzin@arm.com>");
|
||||
MODULE_DESCRIPTION("MPS2 UART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
arch_initcall(mps2_uart_init);
|
||||
|
@@ -19,33 +19,147 @@
|
||||
# define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "msm_serial.h"
|
||||
#define UART_MR1 0x0000
|
||||
|
||||
#define UARTDM_BURST_SIZE 16 /* in bytes */
|
||||
#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
|
||||
#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
|
||||
#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
|
||||
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
|
||||
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
|
||||
#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
|
||||
#define UART_MR1_RX_RDY_CTL BIT(7)
|
||||
#define UART_MR1_CTS_CTL BIT(6)
|
||||
|
||||
#define UART_MR2 0x0004
|
||||
#define UART_MR2_ERROR_MODE BIT(6)
|
||||
#define UART_MR2_BITS_PER_CHAR 0x30
|
||||
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
|
||||
#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
|
||||
#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
|
||||
#define UART_MR2_PARITY_MODE_NONE 0x0
|
||||
#define UART_MR2_PARITY_MODE_ODD 0x1
|
||||
#define UART_MR2_PARITY_MODE_EVEN 0x2
|
||||
#define UART_MR2_PARITY_MODE_SPACE 0x3
|
||||
#define UART_MR2_PARITY_MODE 0x3
|
||||
|
||||
#define UART_CSR 0x0008
|
||||
|
||||
#define UART_TF 0x000C
|
||||
#define UARTDM_TF 0x0070
|
||||
|
||||
#define UART_CR 0x0010
|
||||
#define UART_CR_CMD_NULL (0 << 4)
|
||||
#define UART_CR_CMD_RESET_RX (1 << 4)
|
||||
#define UART_CR_CMD_RESET_TX (2 << 4)
|
||||
#define UART_CR_CMD_RESET_ERR (3 << 4)
|
||||
#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
|
||||
#define UART_CR_CMD_START_BREAK (5 << 4)
|
||||
#define UART_CR_CMD_STOP_BREAK (6 << 4)
|
||||
#define UART_CR_CMD_RESET_CTS (7 << 4)
|
||||
#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
|
||||
#define UART_CR_CMD_PACKET_MODE (9 << 4)
|
||||
#define UART_CR_CMD_MODE_RESET (12 << 4)
|
||||
#define UART_CR_CMD_SET_RFR (13 << 4)
|
||||
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
||||
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
|
||||
#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
|
||||
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
|
||||
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
||||
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
||||
#define UART_CR_TX_DISABLE BIT(3)
|
||||
#define UART_CR_TX_ENABLE BIT(2)
|
||||
#define UART_CR_RX_DISABLE BIT(1)
|
||||
#define UART_CR_RX_ENABLE BIT(0)
|
||||
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
||||
|
||||
#define UART_IMR 0x0014
|
||||
#define UART_IMR_TXLEV BIT(0)
|
||||
#define UART_IMR_RXSTALE BIT(3)
|
||||
#define UART_IMR_RXLEV BIT(4)
|
||||
#define UART_IMR_DELTA_CTS BIT(5)
|
||||
#define UART_IMR_CURRENT_CTS BIT(6)
|
||||
#define UART_IMR_RXBREAK_START BIT(10)
|
||||
|
||||
#define UART_IPR_RXSTALE_LAST 0x20
|
||||
#define UART_IPR_STALE_LSB 0x1F
|
||||
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
|
||||
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
|
||||
|
||||
#define UART_IPR 0x0018
|
||||
#define UART_TFWR 0x001C
|
||||
#define UART_RFWR 0x0020
|
||||
#define UART_HCR 0x0024
|
||||
|
||||
#define UART_MREG 0x0028
|
||||
#define UART_NREG 0x002C
|
||||
#define UART_DREG 0x0030
|
||||
#define UART_MNDREG 0x0034
|
||||
#define UART_IRDA 0x0038
|
||||
#define UART_MISR_MODE 0x0040
|
||||
#define UART_MISR_RESET 0x0044
|
||||
#define UART_MISR_EXPORT 0x0048
|
||||
#define UART_MISR_VAL 0x004C
|
||||
#define UART_TEST_CTRL 0x0050
|
||||
|
||||
#define UART_SR 0x0008
|
||||
#define UART_SR_HUNT_CHAR BIT(7)
|
||||
#define UART_SR_RX_BREAK BIT(6)
|
||||
#define UART_SR_PAR_FRAME_ERR BIT(5)
|
||||
#define UART_SR_OVERRUN BIT(4)
|
||||
#define UART_SR_TX_EMPTY BIT(3)
|
||||
#define UART_SR_TX_READY BIT(2)
|
||||
#define UART_SR_RX_FULL BIT(1)
|
||||
#define UART_SR_RX_READY BIT(0)
|
||||
|
||||
#define UART_RF 0x000C
|
||||
#define UARTDM_RF 0x0070
|
||||
#define UART_MISR 0x0010
|
||||
#define UART_ISR 0x0014
|
||||
#define UART_ISR_TX_READY BIT(7)
|
||||
|
||||
#define UARTDM_RXFS 0x50
|
||||
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
||||
#define UARTDM_RXFS_BUF_MASK 0x7
|
||||
|
||||
#define UARTDM_DMEN 0x3C
|
||||
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
||||
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
|
||||
|
||||
#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMRX 0x34
|
||||
#define UARTDM_NCF_TX 0x40
|
||||
#define UARTDM_RX_TOTAL_SNAP 0x38
|
||||
|
||||
#define UARTDM_BURST_SIZE 16 /* in bytes */
|
||||
#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
|
||||
#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
|
||||
#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
|
||||
|
||||
enum {
|
||||
UARTDM_1P1 = 1,
|
||||
@@ -78,10 +192,65 @@ struct msm_port {
|
||||
struct msm_dma rx_dma;
|
||||
};
|
||||
|
||||
#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart)
|
||||
|
||||
static
|
||||
void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
|
||||
{
|
||||
writel_relaxed(val, port->membase + off);
|
||||
}
|
||||
|
||||
static
|
||||
unsigned int msm_read(struct uart_port *port, unsigned int off)
|
||||
{
|
||||
return readl_relaxed(port->membase + off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the MND registers to use the TCXO clock.
|
||||
*/
|
||||
static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
|
||||
{
|
||||
msm_write(port, 0x06, UART_MREG);
|
||||
msm_write(port, 0xF1, UART_NREG);
|
||||
msm_write(port, 0x0F, UART_DREG);
|
||||
msm_write(port, 0x1A, UART_MNDREG);
|
||||
port->uartclk = 1843200;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the MND registers to use the TCXO clock divided by 4.
|
||||
*/
|
||||
static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
|
||||
{
|
||||
msm_write(port, 0x18, UART_MREG);
|
||||
msm_write(port, 0xF6, UART_NREG);
|
||||
msm_write(port, 0x0F, UART_DREG);
|
||||
msm_write(port, 0x0A, UART_MNDREG);
|
||||
port->uartclk = 1843200;
|
||||
}
|
||||
|
||||
static void msm_serial_set_mnd_regs(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
/*
|
||||
* These registers don't exist so we change the clk input rate
|
||||
* on uartdm hardware instead
|
||||
*/
|
||||
if (msm_port->is_uartdm)
|
||||
return;
|
||||
|
||||
if (port->uartclk == 19200000)
|
||||
msm_serial_set_mnd_regs_tcxo(port);
|
||||
else if (port->uartclk == 4800000)
|
||||
msm_serial_set_mnd_regs_tcxoby4(port);
|
||||
}
|
||||
|
||||
static void msm_handle_tx(struct uart_port *port);
|
||||
static void msm_start_rx_dma(struct msm_port *msm_port);
|
||||
|
||||
void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
||||
static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
unsigned int mapped;
|
||||
@@ -388,10 +557,6 @@ static void msm_complete_rx_dma(void *args)
|
||||
val &= ~dma->enable_bit;
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
/* Restore interrupts */
|
||||
msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
@@ -726,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port)
|
||||
return;
|
||||
}
|
||||
|
||||
pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
dma_min = 1; /* Always DMA */
|
||||
|
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
* Author: Robert Love <rlove@google.com>
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
|
||||
#define __DRIVERS_SERIAL_MSM_SERIAL_H
|
||||
|
||||
#define UART_MR1 0x0000
|
||||
|
||||
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
|
||||
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
|
||||
#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
|
||||
#define UART_MR1_RX_RDY_CTL BIT(7)
|
||||
#define UART_MR1_CTS_CTL BIT(6)
|
||||
|
||||
#define UART_MR2 0x0004
|
||||
#define UART_MR2_ERROR_MODE BIT(6)
|
||||
#define UART_MR2_BITS_PER_CHAR 0x30
|
||||
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
|
||||
#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
|
||||
#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
|
||||
#define UART_MR2_PARITY_MODE_NONE 0x0
|
||||
#define UART_MR2_PARITY_MODE_ODD 0x1
|
||||
#define UART_MR2_PARITY_MODE_EVEN 0x2
|
||||
#define UART_MR2_PARITY_MODE_SPACE 0x3
|
||||
#define UART_MR2_PARITY_MODE 0x3
|
||||
|
||||
#define UART_CSR 0x0008
|
||||
|
||||
#define UART_TF 0x000C
|
||||
#define UARTDM_TF 0x0070
|
||||
|
||||
#define UART_CR 0x0010
|
||||
#define UART_CR_CMD_NULL (0 << 4)
|
||||
#define UART_CR_CMD_RESET_RX (1 << 4)
|
||||
#define UART_CR_CMD_RESET_TX (2 << 4)
|
||||
#define UART_CR_CMD_RESET_ERR (3 << 4)
|
||||
#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
|
||||
#define UART_CR_CMD_START_BREAK (5 << 4)
|
||||
#define UART_CR_CMD_STOP_BREAK (6 << 4)
|
||||
#define UART_CR_CMD_RESET_CTS (7 << 4)
|
||||
#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
|
||||
#define UART_CR_CMD_PACKET_MODE (9 << 4)
|
||||
#define UART_CR_CMD_MODE_RESET (12 << 4)
|
||||
#define UART_CR_CMD_SET_RFR (13 << 4)
|
||||
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
||||
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
|
||||
#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
|
||||
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
|
||||
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
||||
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
||||
#define UART_CR_TX_DISABLE BIT(3)
|
||||
#define UART_CR_TX_ENABLE BIT(2)
|
||||
#define UART_CR_RX_DISABLE BIT(1)
|
||||
#define UART_CR_RX_ENABLE BIT(0)
|
||||
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
||||
|
||||
#define UART_IMR 0x0014
|
||||
#define UART_IMR_TXLEV BIT(0)
|
||||
#define UART_IMR_RXSTALE BIT(3)
|
||||
#define UART_IMR_RXLEV BIT(4)
|
||||
#define UART_IMR_DELTA_CTS BIT(5)
|
||||
#define UART_IMR_CURRENT_CTS BIT(6)
|
||||
#define UART_IMR_RXBREAK_START BIT(10)
|
||||
|
||||
#define UART_IPR_RXSTALE_LAST 0x20
|
||||
#define UART_IPR_STALE_LSB 0x1F
|
||||
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
|
||||
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
|
||||
|
||||
#define UART_IPR 0x0018
|
||||
#define UART_TFWR 0x001C
|
||||
#define UART_RFWR 0x0020
|
||||
#define UART_HCR 0x0024
|
||||
|
||||
#define UART_MREG 0x0028
|
||||
#define UART_NREG 0x002C
|
||||
#define UART_DREG 0x0030
|
||||
#define UART_MNDREG 0x0034
|
||||
#define UART_IRDA 0x0038
|
||||
#define UART_MISR_MODE 0x0040
|
||||
#define UART_MISR_RESET 0x0044
|
||||
#define UART_MISR_EXPORT 0x0048
|
||||
#define UART_MISR_VAL 0x004C
|
||||
#define UART_TEST_CTRL 0x0050
|
||||
|
||||
#define UART_SR 0x0008
|
||||
#define UART_SR_HUNT_CHAR BIT(7)
|
||||
#define UART_SR_RX_BREAK BIT(6)
|
||||
#define UART_SR_PAR_FRAME_ERR BIT(5)
|
||||
#define UART_SR_OVERRUN BIT(4)
|
||||
#define UART_SR_TX_EMPTY BIT(3)
|
||||
#define UART_SR_TX_READY BIT(2)
|
||||
#define UART_SR_RX_FULL BIT(1)
|
||||
#define UART_SR_RX_READY BIT(0)
|
||||
|
||||
#define UART_RF 0x000C
|
||||
#define UARTDM_RF 0x0070
|
||||
#define UART_MISR 0x0010
|
||||
#define UART_ISR 0x0014
|
||||
#define UART_ISR_TX_READY BIT(7)
|
||||
|
||||
#define UARTDM_RXFS 0x50
|
||||
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
||||
#define UARTDM_RXFS_BUF_MASK 0x7
|
||||
|
||||
#define UARTDM_DMEN 0x3C
|
||||
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
||||
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
|
||||
|
||||
#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMRX 0x34
|
||||
#define UARTDM_NCF_TX 0x40
|
||||
#define UARTDM_RX_TOTAL_SNAP 0x38
|
||||
|
||||
#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
|
||||
|
||||
static inline
|
||||
void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
|
||||
{
|
||||
writel_relaxed(val, port->membase + off);
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned int msm_read(struct uart_port *port, unsigned int off)
|
||||
{
|
||||
return readl_relaxed(port->membase + off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the MND registers to use the TCXO clock.
|
||||
*/
|
||||
static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
|
||||
{
|
||||
msm_write(port, 0x06, UART_MREG);
|
||||
msm_write(port, 0xF1, UART_NREG);
|
||||
msm_write(port, 0x0F, UART_DREG);
|
||||
msm_write(port, 0x1A, UART_MNDREG);
|
||||
port->uartclk = 1843200;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the MND registers to use the TCXO clock divided by 4.
|
||||
*/
|
||||
static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
|
||||
{
|
||||
msm_write(port, 0x18, UART_MREG);
|
||||
msm_write(port, 0xF6, UART_NREG);
|
||||
msm_write(port, 0x0F, UART_DREG);
|
||||
msm_write(port, 0x0A, UART_MNDREG);
|
||||
port->uartclk = 1843200;
|
||||
}
|
||||
|
||||
static inline
|
||||
void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
|
||||
{
|
||||
if (port->uartclk == 19200000)
|
||||
msm_serial_set_mnd_regs_tcxo(port);
|
||||
else if (port->uartclk == 4800000)
|
||||
msm_serial_set_mnd_regs_tcxoby4(port);
|
||||
}
|
||||
|
||||
#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
|
||||
|
||||
#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
|
@@ -300,6 +300,8 @@ static int mvebu_uart_startup(struct uart_port *port)
|
||||
static void mvebu_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
writel(0, port->membase + UART_CTRL);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
static void mvebu_uart_set_termios(struct uart_port *port,
|
||||
|
@@ -445,7 +445,6 @@ static int pic32_uart_startup(struct uart_port *port)
|
||||
sport->idx);
|
||||
if (!sport->irq_rx_name) {
|
||||
dev_err(port->dev, "%s: kasprintf err!", __func__);
|
||||
kfree(sport->irq_fault_name);
|
||||
ret = -ENOMEM;
|
||||
goto out_f;
|
||||
}
|
||||
|
@@ -1720,7 +1720,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
|
||||
|
||||
r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(uap->pdev, 0);
|
||||
if (!r_ports || !irq)
|
||||
if (!r_ports || irq <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
uap->port.mapbase = r_ports->start;
|
||||
|
@@ -27,7 +27,6 @@
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
@@ -829,7 +828,6 @@ static const struct of_device_id serial_pxa_dt_ids[] = {
|
||||
{ .compatible = "mrvl,mmp-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
|
||||
|
||||
static int serial_pxa_probe_dt(struct platform_device *pdev,
|
||||
struct uart_pxa_port *sport)
|
||||
@@ -914,28 +912,15 @@ static int serial_pxa_probe(struct platform_device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int serial_pxa_remove(struct platform_device *dev)
|
||||
{
|
||||
struct uart_pxa_port *sport = platform_get_drvdata(dev);
|
||||
|
||||
uart_remove_one_port(&serial_pxa_reg, &sport->port);
|
||||
|
||||
clk_unprepare(sport->clk);
|
||||
clk_put(sport->clk);
|
||||
kfree(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver serial_pxa_driver = {
|
||||
.probe = serial_pxa_probe,
|
||||
.remove = serial_pxa_remove,
|
||||
|
||||
.driver = {
|
||||
.name = "pxa2xx-uart",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &serial_pxa_pm_ops,
|
||||
#endif
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = serial_pxa_dt_ids,
|
||||
},
|
||||
};
|
||||
@@ -954,15 +939,4 @@ static int __init serial_pxa_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit serial_pxa_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&serial_pxa_driver);
|
||||
uart_unregister_driver(&serial_pxa_reg);
|
||||
}
|
||||
|
||||
module_init(serial_pxa_init);
|
||||
module_exit(serial_pxa_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pxa2xx-uart");
|
||||
device_initcall(serial_pxa_init);
|
||||
|
@@ -169,8 +169,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
|
||||
return;
|
||||
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__set_bit(S3C64XX_UINTM_TXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
|
||||
else
|
||||
disable_irq_nosync(ourport->tx_irq);
|
||||
|
||||
@@ -235,8 +234,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
|
||||
|
||||
/* Mask Tx interrupt */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__set_bit(S3C64XX_UINTM_TXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
|
||||
else
|
||||
disable_irq_nosync(ourport->tx_irq);
|
||||
|
||||
@@ -269,8 +267,8 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
|
||||
|
||||
/* Unmask Tx interrupt */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__clear_bit(S3C64XX_UINTM_TXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
|
||||
S3C64XX_UINTM);
|
||||
else
|
||||
enable_irq(ourport->tx_irq);
|
||||
|
||||
@@ -397,8 +395,8 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
||||
if (rx_enabled(port)) {
|
||||
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__set_bit(S3C64XX_UINTM_RXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
|
||||
S3C64XX_UINTM);
|
||||
else
|
||||
disable_irq_nosync(ourport->rx_irq);
|
||||
rx_enabled(port) = 0;
|
||||
@@ -1069,7 +1067,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
/* Enable Rx Interrupt */
|
||||
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
|
||||
s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
|
||||
|
||||
dbg("s3c64xx_serial_startup ok\n");
|
||||
return ret;
|
||||
@@ -1684,7 +1682,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
return -ENODEV;
|
||||
|
||||
if (port->mapbase != 0)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
|
||||
/* setup info for port */
|
||||
port->dev = &platdev->dev;
|
||||
@@ -1738,22 +1736,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
ourport->dma = devm_kzalloc(port->dev,
|
||||
sizeof(*ourport->dma),
|
||||
GFP_KERNEL);
|
||||
if (!ourport->dma)
|
||||
return -ENOMEM;
|
||||
if (!ourport->dma) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ourport->clk = clk_get(&platdev->dev, "uart");
|
||||
if (IS_ERR(ourport->clk)) {
|
||||
pr_err("%s: Controller clock not found\n",
|
||||
dev_name(&platdev->dev));
|
||||
return PTR_ERR(ourport->clk);
|
||||
ret = PTR_ERR(ourport->clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ourport->clk);
|
||||
if (ret) {
|
||||
pr_err("uart: clock failed to prepare+enable: %d\n", ret);
|
||||
clk_put(ourport->clk);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Keep all interrupts masked and cleared */
|
||||
@@ -1769,7 +1770,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
|
||||
/* reset the fifos (and setup the uart) */
|
||||
s3c24xx_serial_resetport(port, cfg);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
port->mapbase = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Device driver serial port probe */
|
||||
@@ -1836,8 +1842,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
||||
ourport->min_dma_size = max_t(int, ourport->port.fifosize,
|
||||
dma_get_cache_alignment());
|
||||
|
||||
probe_index++;
|
||||
|
||||
dbg("%s: initialising port %p...\n", __func__, ourport);
|
||||
|
||||
ret = s3c24xx_serial_init_port(ourport, pdev);
|
||||
@@ -1867,6 +1871,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
|
||||
|
||||
probe_index++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -117,10 +117,38 @@ struct s3c24xx_uart_port {
|
||||
#define portaddrl(port, reg) \
|
||||
((unsigned long *)(unsigned long)((port)->membase + (reg)))
|
||||
|
||||
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
|
||||
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
|
||||
#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg)))
|
||||
#define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg)))
|
||||
|
||||
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg))
|
||||
|
||||
/* Byte-order aware bit setting/clearing functions. */
|
||||
|
||||
static inline void s3c24xx_set_bit(struct uart_port *port, int idx,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = rd_regl(port, reg);
|
||||
val |= (1 << idx);
|
||||
wr_regl(port, reg, val);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void s3c24xx_clear_bit(struct uart_port *port, int idx,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = rd_regl(port, reg);
|
||||
val &= ~(1 << idx);
|
||||
wr_regl(port, reg, val);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1317,7 +1317,12 @@ static int tegra_uart_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
u->iotype = UPIO_MEM32;
|
||||
u->irq = platform_get_irq(pdev, 0);
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't get IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
u->irq = ret;
|
||||
u->regshift = 2;
|
||||
ret = uart_add_one_port(&tegra_uart_driver, u);
|
||||
if (ret < 0) {
|
||||
|
@@ -887,7 +887,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
/*
|
||||
* Free and release old regions
|
||||
*/
|
||||
if (old_type != PORT_UNKNOWN)
|
||||
if (old_type != PORT_UNKNOWN && uport->ops->release_port)
|
||||
uport->ops->release_port(uport);
|
||||
|
||||
uport->iobase = new_port;
|
||||
@@ -900,7 +900,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
/*
|
||||
* Claim and map the new regions
|
||||
*/
|
||||
if (uport->type != PORT_UNKNOWN) {
|
||||
if (uport->type != PORT_UNKNOWN && uport->ops->request_port) {
|
||||
retval = uport->ops->request_port(uport);
|
||||
} else {
|
||||
/* Always success - Jean II */
|
||||
@@ -1125,7 +1125,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
|
||||
* If we already have a port type configured,
|
||||
* we must release its resources.
|
||||
*/
|
||||
if (uport->type != PORT_UNKNOWN)
|
||||
if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
|
||||
uport->ops->release_port(uport);
|
||||
|
||||
flags = UART_CONFIG_TYPE;
|
||||
@@ -2897,7 +2897,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
/*
|
||||
* Free the port IO and memory resources, if any.
|
||||
*/
|
||||
if (uport->type != PORT_UNKNOWN)
|
||||
if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
|
||||
uport->ops->release_port(uport);
|
||||
kfree(uport->tty_groups);
|
||||
|
||||
|
@@ -52,6 +52,9 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
int value_array[UART_GPIO_MAX];
|
||||
unsigned int count = 0;
|
||||
|
||||
if (gpios == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
|
||||
desc_array[count] = gpios->gpio[i];
|
||||
@@ -73,6 +76,9 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (gpios == NULL)
|
||||
return *mctrl;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) {
|
||||
if (gpiod_get_value(gpios->gpio[i]))
|
||||
@@ -86,6 +92,27 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
|
||||
|
||||
unsigned int
|
||||
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (gpios == NULL)
|
||||
return *mctrl;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
|
||||
if (gpiod_get_value(gpios->gpio[i]))
|
||||
*mctrl |= mctrl_gpios_desc[i].mctrl;
|
||||
else
|
||||
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
|
||||
}
|
||||
}
|
||||
|
||||
return *mctrl;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
|
||||
|
||||
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
|
||||
{
|
||||
struct mctrl_gpios *gpios;
|
||||
@@ -203,6 +230,9 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (gpios == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
if (gpios->irq[i])
|
||||
devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
|
||||
@@ -218,6 +248,9 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (gpios == NULL)
|
||||
return;
|
||||
|
||||
/* .enable_ms may be called multiple times */
|
||||
if (gpios->mctrl_on)
|
||||
return;
|
||||
@@ -240,6 +273,9 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (gpios == NULL)
|
||||
return;
|
||||
|
||||
if (!gpios->mctrl_on)
|
||||
return;
|
||||
|
||||
|
@@ -48,11 +48,18 @@ struct mctrl_gpios;
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
|
||||
|
||||
/*
|
||||
* Get state of the modem control output lines from GPIOs.
|
||||
* Get state of the modem control input lines from GPIOs.
|
||||
* The mctrl flags are updated and returned.
|
||||
*/
|
||||
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
|
||||
|
||||
/*
|
||||
* Get state of the modem control output lines from GPIOs.
|
||||
* The mctrl flags are updated and returned.
|
||||
*/
|
||||
unsigned int
|
||||
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl);
|
||||
|
||||
/*
|
||||
* Returns the associated struct gpio_desc to the modem line gidx
|
||||
*/
|
||||
@@ -107,6 +114,12 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
return *mctrl;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
return *mctrl;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx)
|
||||
|
@@ -57,6 +57,7 @@
|
||||
#include <asm/sh_bios.h>
|
||||
#endif
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
#include "sh-sci.h"
|
||||
|
||||
/* Offsets into the sci_port->irqs array */
|
||||
@@ -111,6 +112,7 @@ struct sci_port {
|
||||
unsigned int error_clear;
|
||||
unsigned int sampling_rate_mask;
|
||||
resource_size_t reg_size;
|
||||
struct mctrl_gpios *gpios;
|
||||
|
||||
/* Break timer */
|
||||
struct timer_list break_timer;
|
||||
@@ -139,6 +141,8 @@ struct sci_port {
|
||||
struct timer_list rx_timer;
|
||||
unsigned int rx_timeout;
|
||||
#endif
|
||||
|
||||
bool autorts;
|
||||
};
|
||||
|
||||
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
|
||||
@@ -701,7 +705,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
|
||||
|
||||
/*
|
||||
* Use port-specific handler if provided.
|
||||
@@ -711,21 +714,28 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the generic path SCSPTR is necessary. Bail out if that's
|
||||
* unavailable, too.
|
||||
*/
|
||||
if (!reg->size)
|
||||
return;
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
u16 ctrl = serial_port_in(port, SCPCR);
|
||||
|
||||
if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) &&
|
||||
((!(cflag & CRTSCTS)))) {
|
||||
unsigned short status;
|
||||
/* Enable RXD and TXD pin functions */
|
||||
ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
|
||||
if (to_sci_port(port)->cfg->capabilities & SCIx_HAVE_RTSCTS) {
|
||||
/* RTS# is output, driven 1 */
|
||||
ctrl |= SCPCR_RTSC;
|
||||
serial_port_out(port, SCPDR,
|
||||
serial_port_in(port, SCPDR) | SCPDR_RTSD);
|
||||
/* Enable CTS# pin function */
|
||||
ctrl &= ~SCPCR_CTSC;
|
||||
}
|
||||
serial_port_out(port, SCPCR, ctrl);
|
||||
} else if (sci_getreg(port, SCSPTR)->size) {
|
||||
u16 status = serial_port_in(port, SCSPTR);
|
||||
|
||||
status = serial_port_in(port, SCSPTR);
|
||||
status &= ~SCSPTR_CTSIO;
|
||||
status |= SCSPTR_RTSIO;
|
||||
serial_port_out(port, SCSPTR, status); /* Set RTS = 1 */
|
||||
/* RTS# is output, driven 1 */
|
||||
status |= SCSPTR_RTSIO | SCSPTR_RTSDT;
|
||||
/* CTS# and SCK are inputs */
|
||||
status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
|
||||
serial_port_out(port, SCSPTR, status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1803,6 +1813,46 @@ static unsigned int sci_tx_empty(struct uart_port *port)
|
||||
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static void sci_set_rts(struct uart_port *port, bool state)
|
||||
{
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
u16 data = serial_port_in(port, SCPDR);
|
||||
|
||||
/* Active low */
|
||||
if (state)
|
||||
data &= ~SCPDR_RTSD;
|
||||
else
|
||||
data |= SCPDR_RTSD;
|
||||
serial_port_out(port, SCPDR, data);
|
||||
|
||||
/* RTS# is output */
|
||||
serial_port_out(port, SCPCR,
|
||||
serial_port_in(port, SCPCR) | SCPCR_RTSC);
|
||||
} else if (sci_getreg(port, SCSPTR)->size) {
|
||||
u16 ctrl = serial_port_in(port, SCSPTR);
|
||||
|
||||
/* Active low */
|
||||
if (state)
|
||||
ctrl &= ~SCSPTR_RTSDT;
|
||||
else
|
||||
ctrl |= SCSPTR_RTSDT;
|
||||
serial_port_out(port, SCSPTR, ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sci_get_cts(struct uart_port *port)
|
||||
{
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
/* Active low */
|
||||
return !(serial_port_in(port, SCPDR) & SCPDR_CTSD);
|
||||
} else if (sci_getreg(port, SCSPTR)->size) {
|
||||
/* Active low */
|
||||
return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modem control is a bit of a mixed bag for SCI(F) ports. Generally
|
||||
* CTS/RTS is supported in hardware by at least one port and controlled
|
||||
@@ -1817,6 +1867,8 @@ static unsigned int sci_tx_empty(struct uart_port *port)
|
||||
*/
|
||||
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
if (mctrl & TIOCM_LOOP) {
|
||||
const struct plat_sci_reg *reg;
|
||||
|
||||
@@ -1829,25 +1881,72 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
serial_port_in(port, SCFCR) |
|
||||
SCFCR_LOOP);
|
||||
}
|
||||
|
||||
mctrl_gpio_set(s->gpios, mctrl);
|
||||
|
||||
if (!(s->cfg->capabilities & SCIx_HAVE_RTSCTS))
|
||||
return;
|
||||
|
||||
if (!(mctrl & TIOCM_RTS)) {
|
||||
/* Disable Auto RTS */
|
||||
serial_port_out(port, SCFCR,
|
||||
serial_port_in(port, SCFCR) & ~SCFCR_MCE);
|
||||
|
||||
/* Clear RTS */
|
||||
sci_set_rts(port, 0);
|
||||
} else if (s->autorts) {
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
/* Enable RTS# pin function */
|
||||
serial_port_out(port, SCPCR,
|
||||
serial_port_in(port, SCPCR) & ~SCPCR_RTSC);
|
||||
}
|
||||
|
||||
/* Enable Auto RTS */
|
||||
serial_port_out(port, SCFCR,
|
||||
serial_port_in(port, SCFCR) | SCFCR_MCE);
|
||||
} else {
|
||||
/* Set RTS */
|
||||
sci_set_rts(port, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int sci_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
struct mctrl_gpios *gpios = s->gpios;
|
||||
unsigned int mctrl = 0;
|
||||
|
||||
mctrl_gpio_get(gpios, &mctrl);
|
||||
|
||||
/*
|
||||
* CTS/RTS is handled in hardware when supported, while nothing
|
||||
* else is wired up. Keep it simple and simply assert DSR/CAR.
|
||||
* else is wired up.
|
||||
*/
|
||||
return TIOCM_DSR | TIOCM_CAR;
|
||||
if (s->autorts) {
|
||||
if (sci_get_cts(port))
|
||||
mctrl |= TIOCM_CTS;
|
||||
} else if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) {
|
||||
mctrl |= TIOCM_CTS;
|
||||
}
|
||||
if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR)))
|
||||
mctrl |= TIOCM_DSR;
|
||||
if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD)))
|
||||
mctrl |= TIOCM_CAR;
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
static void sci_enable_ms(struct uart_port *port)
|
||||
{
|
||||
mctrl_gpio_enable_ms(to_sci_port(port)->gpios);
|
||||
}
|
||||
|
||||
static void sci_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
|
||||
unsigned short scscr, scsptr;
|
||||
|
||||
/* check wheter the port has SCSPTR */
|
||||
if (!reg->size) {
|
||||
if (!sci_getreg(port, SCSPTR)->size) {
|
||||
/*
|
||||
* Not supported by hardware. Most parts couple break and rx
|
||||
* interrupts together, with break detection always enabled.
|
||||
@@ -1873,7 +1972,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
|
||||
static int sci_startup(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
||||
@@ -1884,11 +1982,6 @@ static int sci_startup(struct uart_port *port)
|
||||
|
||||
sci_request_dma(port);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sci_start_tx(port);
|
||||
sci_start_rx(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1896,12 +1989,19 @@ static void sci_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
unsigned long flags;
|
||||
u16 scr;
|
||||
|
||||
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
||||
|
||||
s->autorts = false;
|
||||
mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sci_stop_rx(port);
|
||||
sci_stop_tx(port);
|
||||
/* Stop RX and TX, disable related interrupts, keep clock source */
|
||||
scr = serial_port_in(port, SCSCR);
|
||||
serial_port_out(port, SCSCR, scr & (SCSCR_CKE1 | SCSCR_CKE0));
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
@@ -2056,6 +2156,15 @@ static void sci_reset(struct uart_port *port)
|
||||
reg = sci_getreg(port, SCFCR);
|
||||
if (reg->size)
|
||||
serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
|
||||
|
||||
sci_clear_SCxSR(port,
|
||||
SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
|
||||
SCxSR_BREAK_CLEAR(port));
|
||||
if (sci_getreg(port, SCLSR)->size) {
|
||||
status = serial_port_in(port, SCLSR);
|
||||
status &= ~(SCLSR_TO | SCLSR_ORER);
|
||||
serial_port_out(port, SCLSR, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
@@ -2218,15 +2327,18 @@ done:
|
||||
|
||||
sci_init_pins(port, termios->c_cflag);
|
||||
|
||||
port->status &= ~UPSTAT_AUTOCTS;
|
||||
s->autorts = false;
|
||||
reg = sci_getreg(port, SCFCR);
|
||||
if (reg->size) {
|
||||
unsigned short ctrl = serial_port_in(port, SCFCR);
|
||||
|
||||
if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) {
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
ctrl |= SCFCR_MCE;
|
||||
else
|
||||
ctrl &= ~SCFCR_MCE;
|
||||
if ((port->flags & UPF_HARD_FLOW) &&
|
||||
(termios->c_cflag & CRTSCTS)) {
|
||||
/* There is no CTS interrupt to restart the hardware */
|
||||
port->status |= UPSTAT_AUTOCTS;
|
||||
/* MCE is enabled when RTS is raised */
|
||||
s->autorts = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2300,6 +2412,9 @@ done:
|
||||
sci_start_rx(port);
|
||||
|
||||
sci_port_disable(s);
|
||||
|
||||
if (UART_ENABLE_MS(port, termios->c_cflag))
|
||||
sci_enable_ms(port);
|
||||
}
|
||||
|
||||
static void sci_pm(struct uart_port *port, unsigned int state,
|
||||
@@ -2425,6 +2540,7 @@ static struct uart_ops sci_uart_ops = {
|
||||
.start_tx = sci_start_tx,
|
||||
.stop_tx = sci_stop_tx,
|
||||
.stop_rx = sci_stop_rx,
|
||||
.enable_ms = sci_enable_ms,
|
||||
.break_ctl = sci_break_ctl,
|
||||
.startup = sci_startup,
|
||||
.shutdown = sci_shutdown,
|
||||
@@ -2890,6 +3006,9 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
|
||||
p->regtype = SCI_OF_REGTYPE(match->data);
|
||||
p->scscr = SCSCR_RE | SCSCR_TE;
|
||||
|
||||
if (of_find_property(np, "uart-has-rtscts", NULL))
|
||||
p->capabilities |= SCIx_HAVE_RTSCTS;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2912,6 +3031,21 @@ static int sci_probe_single(struct platform_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sciport->gpios = mctrl_gpio_init(&sciport->port, 0);
|
||||
if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS)
|
||||
return PTR_ERR(sciport->gpios);
|
||||
|
||||
if (p->capabilities & SCIx_HAVE_RTSCTS) {
|
||||
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios,
|
||||
UART_GPIO_CTS)) ||
|
||||
!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios,
|
||||
UART_GPIO_RTS))) {
|
||||
dev_err(&dev->dev, "Conflicting RTS/CTS config\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
sciport->port.flags |= UPF_HARD_FLOW;
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
|
||||
if (ret) {
|
||||
sci_cleanup_single(sciport);
|
||||
|
@@ -105,13 +105,16 @@ enum {
|
||||
#define SCFCR_LOOP BIT(0) /* Loopback Test */
|
||||
|
||||
/* SCLSR (Line Status Register) on (H)SCIF */
|
||||
#define SCLSR_TO BIT(2) /* Timeout */
|
||||
#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_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_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
|
||||
#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */
|
||||
#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
|
||||
#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
|
||||
|
||||
@@ -119,12 +122,18 @@ enum {
|
||||
#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 */
|
||||
#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */
|
||||
#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */
|
||||
#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
|
||||
#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
|
||||
#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output 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 SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */
|
||||
#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */
|
||||
#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
|
||||
#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
|
||||
#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
|
||||
|
||||
/*
|
||||
* BRG Clock Select Register (Some SCIF and HSCIF)
|
||||
|
@@ -106,7 +106,7 @@ struct sirfsoc_uart_register {
|
||||
enum sirfsoc_uart_type uart_type;
|
||||
};
|
||||
|
||||
u32 uart_usp_ff_full_mask(struct uart_port *port)
|
||||
static u32 uart_usp_ff_full_mask(struct uart_port *port)
|
||||
{
|
||||
u32 full_bit;
|
||||
|
||||
@@ -114,7 +114,7 @@ u32 uart_usp_ff_full_mask(struct uart_port *port)
|
||||
return (1 << full_bit);
|
||||
}
|
||||
|
||||
u32 uart_usp_ff_empty_mask(struct uart_port *port)
|
||||
static u32 uart_usp_ff_empty_mask(struct uart_port *port)
|
||||
{
|
||||
u32 empty_bit;
|
||||
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
@@ -730,22 +729,12 @@ static int vt8500_serial_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt8500_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(vt8500_port->clk);
|
||||
uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vt8500_platform_driver = {
|
||||
.probe = vt8500_serial_probe,
|
||||
.remove = vt8500_serial_remove,
|
||||
.driver = {
|
||||
.name = "vt8500_serial",
|
||||
.of_match_table = wmt_dt_ids,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -764,19 +753,4 @@ static int __init vt8500_serial_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vt8500_serial_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_VT8500_CONSOLE
|
||||
unregister_console(&vt8500_console);
|
||||
#endif
|
||||
platform_driver_unregister(&vt8500_platform_driver);
|
||||
uart_unregister_driver(&vt8500_uart_driver);
|
||||
}
|
||||
|
||||
module_init(vt8500_serial_init);
|
||||
module_exit(vt8500_serial_exit);
|
||||
|
||||
MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver for vt8500 serial device");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
device_initcall(vt8500_serial_init);
|
||||
|
@@ -976,6 +976,23 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cdns_uart_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
|
||||
switch (state) {
|
||||
case UART_PM_STATE_OFF:
|
||||
clk_disable(cdns_uart->uartclk);
|
||||
clk_disable(cdns_uart->pclk);
|
||||
break;
|
||||
default:
|
||||
clk_enable(cdns_uart->pclk);
|
||||
clk_enable(cdns_uart->uartclk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct uart_ops cdns_uart_ops = {
|
||||
.set_mctrl = cdns_uart_set_mctrl,
|
||||
.get_mctrl = cdns_uart_get_mctrl,
|
||||
@@ -987,6 +1004,7 @@ static struct uart_ops cdns_uart_ops = {
|
||||
.set_termios = cdns_uart_set_termios,
|
||||
.startup = cdns_uart_startup,
|
||||
.shutdown = cdns_uart_shutdown,
|
||||
.pm = cdns_uart_pm,
|
||||
.type = cdns_uart_type,
|
||||
.verify_port = cdns_uart_verify_port,
|
||||
.request_port = cdns_uart_request_port,
|
||||
@@ -1350,12 +1368,12 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(cdns_uart_data->uartclk);
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(cdns_uart_data->pclk);
|
||||
rc = clk_prepare(cdns_uart_data->pclk);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
|
||||
return rc;
|
||||
}
|
||||
rc = clk_prepare_enable(cdns_uart_data->uartclk);
|
||||
rc = clk_prepare(cdns_uart_data->uartclk);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Unable to enable device clock.\n");
|
||||
goto err_out_clk_dis_pclk;
|
||||
@@ -1422,9 +1440,9 @@ err_out_notif_unreg:
|
||||
&cdns_uart_data->clk_rate_change_nb);
|
||||
#endif
|
||||
err_out_clk_disable:
|
||||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||
clk_unprepare(cdns_uart_data->uartclk);
|
||||
err_out_clk_dis_pclk:
|
||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||
clk_unprepare(cdns_uart_data->pclk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1448,8 +1466,8 @@ static int cdns_uart_remove(struct platform_device *pdev)
|
||||
#endif
|
||||
rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
|
||||
port->mapbase = 0;
|
||||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||
clk_unprepare(cdns_uart_data->uartclk);
|
||||
clk_unprepare(cdns_uart_data->pclk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@@ -499,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ui is a leftover from using a hashtable, but might be used again
|
||||
Caller must hold the lock */
|
||||
static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
/* Caller must hold the lock */
|
||||
static int con_do_clear_unimap(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
@@ -524,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
int con_clear_unimap(struct vc_data *vc)
|
||||
{
|
||||
int ret;
|
||||
console_lock();
|
||||
ret = con_do_clear_unimap(vc, ui);
|
||||
ret = con_do_clear_unimap(vc);
|
||||
console_unlock();
|
||||
return ret;
|
||||
}
|
||||
@@ -556,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
int j, k;
|
||||
u16 **p1, *p2, l;
|
||||
|
||||
err1 = con_do_clear_unimap(vc, NULL);
|
||||
err1 = con_do_clear_unimap(vc);
|
||||
if (err1) {
|
||||
console_unlock();
|
||||
return err1;
|
||||
@@ -677,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
||||
|
||||
/* The default font is always 256 characters */
|
||||
|
||||
err = con_do_clear_unimap(vc, NULL);
|
||||
err = con_do_clear_unimap(vc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@@ -567,7 +567,7 @@ static void fn_scroll_forw(struct vc_data *vc)
|
||||
|
||||
static void fn_scroll_back(struct vc_data *vc)
|
||||
{
|
||||
scrollback(vc, 0);
|
||||
scrollback(vc);
|
||||
}
|
||||
|
||||
static void fn_show_mem(struct vc_data *vc)
|
||||
@@ -1733,16 +1733,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
buf = kmalloc(ct * sizeof(struct kbdiacruc),
|
||||
GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, a->kbdiacruc,
|
||||
ct * sizeof(struct kbdiacruc))) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
buf = memdup_user(a->kbdiacruc,
|
||||
ct * sizeof(struct kbdiacruc));
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
if (ct)
|
||||
|
@@ -277,13 +277,15 @@ static void notify_update(struct vc_data *vc)
|
||||
* Low-Level Functions
|
||||
*/
|
||||
|
||||
#define IS_FG(vc) ((vc)->vc_num == fg_console)
|
||||
static inline bool con_is_fg(const struct vc_data *vc)
|
||||
{
|
||||
return vc->vc_num == fg_console;
|
||||
}
|
||||
|
||||
#ifdef VT_BUF_VRAM_ONLY
|
||||
#define DO_UPDATE(vc) 0
|
||||
#else
|
||||
#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked)
|
||||
#endif
|
||||
static inline bool con_should_update(const struct vc_data *vc)
|
||||
{
|
||||
return con_is_visible(vc) && !console_blanked;
|
||||
}
|
||||
|
||||
static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
|
||||
{
|
||||
@@ -321,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
|
||||
nr = b - t - 1;
|
||||
if (b > vc->vc_rows || t >= b || nr < 1)
|
||||
return;
|
||||
if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
|
||||
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
|
||||
return;
|
||||
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
|
||||
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
|
||||
@@ -339,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
|
||||
nr = b - t - 1;
|
||||
if (b > vc->vc_rows || t >= b || nr < 1)
|
||||
return;
|
||||
if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
|
||||
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
|
||||
return;
|
||||
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
|
||||
step = vc->vc_cols * nr;
|
||||
@@ -349,7 +351,6 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
|
||||
|
||||
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
|
||||
{
|
||||
#ifndef VT_BUF_VRAM_ONLY
|
||||
unsigned int xx, yy, offset;
|
||||
u16 *p;
|
||||
|
||||
@@ -390,14 +391,13 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
|
||||
start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_region(struct vc_data *vc, unsigned long start, int count)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (DO_UPDATE(vc)) {
|
||||
if (con_should_update(vc)) {
|
||||
hide_cursor(vc);
|
||||
do_update_region(vc, start, count);
|
||||
set_cursor(vc);
|
||||
@@ -413,7 +413,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
|
||||
return vc->vc_sw->con_build_attr(vc, _color, _intensity,
|
||||
_blink, _underline, _reverse, _italic);
|
||||
|
||||
#ifndef VT_BUF_VRAM_ONLY
|
||||
/*
|
||||
* ++roman: I completely changed the attribute format for monochrome
|
||||
* mode (!can_do_color). The formerly used MDA (monochrome display
|
||||
@@ -448,9 +447,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
|
||||
a <<= 1;
|
||||
return a;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void update_attr(struct vc_data *vc)
|
||||
@@ -470,10 +466,9 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
|
||||
|
||||
count /= 2;
|
||||
p = screenpos(vc, offset, viewed);
|
||||
if (vc->vc_sw->con_invert_region)
|
||||
if (vc->vc_sw->con_invert_region) {
|
||||
vc->vc_sw->con_invert_region(vc, p, count);
|
||||
#ifndef VT_BUF_VRAM_ONLY
|
||||
else {
|
||||
} else {
|
||||
u16 *q = p;
|
||||
int cnt = count;
|
||||
u16 a;
|
||||
@@ -501,8 +496,8 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (DO_UPDATE(vc))
|
||||
|
||||
if (con_should_update(vc))
|
||||
do_update_region(vc, (unsigned long) p, count);
|
||||
notify_update(vc);
|
||||
}
|
||||
@@ -519,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset)
|
||||
if (old_offset != -1 && old_offset >= 0 &&
|
||||
old_offset < vc->vc_screenbuf_size) {
|
||||
scr_writew(old, screenpos(vc, old_offset, 1));
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
vc->vc_sw->con_putc(vc, old, oldy, oldx);
|
||||
notify_update(vc);
|
||||
}
|
||||
@@ -534,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset)
|
||||
old = scr_readw(p);
|
||||
new = old ^ vc->vc_complement_mask;
|
||||
scr_writew(new, p);
|
||||
if (DO_UPDATE(vc)) {
|
||||
if (con_should_update(vc)) {
|
||||
oldx = (offset >> 1) % vc->vc_cols;
|
||||
oldy = (offset >> 1) / vc->vc_cols;
|
||||
vc->vc_sw->con_putc(vc, new, oldy, oldx);
|
||||
@@ -550,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
|
||||
scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
|
||||
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
|
||||
vc->vc_need_wrap = 0;
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
do_update_region(vc, (unsigned long) p,
|
||||
vc->vc_cols - vc->vc_x);
|
||||
}
|
||||
@@ -563,7 +558,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
|
||||
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
|
||||
nr * 2);
|
||||
vc->vc_need_wrap = 0;
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
do_update_region(vc, (unsigned long) p,
|
||||
vc->vc_cols - vc->vc_x);
|
||||
}
|
||||
@@ -583,7 +578,7 @@ static void add_softcursor(struct vc_data *vc)
|
||||
if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
|
||||
if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
|
||||
scr_writew(i, (u16 *) vc->vc_pos);
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
|
||||
}
|
||||
|
||||
@@ -591,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc)
|
||||
{
|
||||
if (softcursor_original != -1) {
|
||||
scr_writew(softcursor_original, (u16 *)vc->vc_pos);
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
vc->vc_sw->con_putc(vc, softcursor_original,
|
||||
vc->vc_y, vc->vc_x);
|
||||
softcursor_original = -1;
|
||||
@@ -608,8 +603,7 @@ static void hide_cursor(struct vc_data *vc)
|
||||
|
||||
static void set_cursor(struct vc_data *vc)
|
||||
{
|
||||
if (!IS_FG(vc) || console_blanked ||
|
||||
vc->vc_mode == KD_GRAPHICS)
|
||||
if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
|
||||
return;
|
||||
if (vc->vc_deccm) {
|
||||
if (vc == sel_cons)
|
||||
@@ -625,7 +619,7 @@ static void set_origin(struct vc_data *vc)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (!CON_IS_VISIBLE(vc) ||
|
||||
if (!con_is_visible(vc) ||
|
||||
!vc->vc_sw->con_set_origin ||
|
||||
!vc->vc_sw->con_set_origin(vc))
|
||||
vc->vc_origin = (unsigned long)vc->vc_screenbuf;
|
||||
@@ -673,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch)
|
||||
struct vc_data *old_vc = vc_cons[fg_console].d;
|
||||
if (old_vc == vc)
|
||||
return;
|
||||
if (!CON_IS_VISIBLE(vc))
|
||||
if (!con_is_visible(vc))
|
||||
redraw = 1;
|
||||
*vc->vc_display_fg = vc;
|
||||
fg_console = vc->vc_num;
|
||||
hide_cursor(old_vc);
|
||||
if (!CON_IS_VISIBLE(old_vc)) {
|
||||
if (!con_is_visible(old_vc)) {
|
||||
save_screen(old_vc);
|
||||
set_origin(old_vc);
|
||||
}
|
||||
@@ -954,7 +948,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
|
||||
tty_do_resize(tty, &ws);
|
||||
}
|
||||
|
||||
if (CON_IS_VISIBLE(vc))
|
||||
if (con_is_visible(vc))
|
||||
update_screen(vc);
|
||||
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
|
||||
return err;
|
||||
@@ -1103,11 +1097,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y)
|
||||
gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
|
||||
}
|
||||
|
||||
void scrollback(struct vc_data *vc, int lines)
|
||||
void scrollback(struct vc_data *vc)
|
||||
{
|
||||
if (!lines)
|
||||
lines = vc->vc_rows / 2;
|
||||
scrolldelta(-lines);
|
||||
scrolldelta(-(vc->vc_rows / 2));
|
||||
}
|
||||
|
||||
void scrollfront(struct vc_data *vc, int lines)
|
||||
@@ -1186,7 +1178,7 @@ static void csi_J(struct vc_data *vc, int vpar)
|
||||
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
|
||||
vc->vc_screenbuf_size >> 1);
|
||||
set_origin(vc);
|
||||
if (CON_IS_VISIBLE(vc))
|
||||
if (con_is_visible(vc))
|
||||
update_screen(vc);
|
||||
/* fall through */
|
||||
case 2: /* erase whole display */
|
||||
@@ -1197,7 +1189,7 @@ static void csi_J(struct vc_data *vc, int vpar)
|
||||
return;
|
||||
}
|
||||
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
do_update_region(vc, (unsigned long) start, count);
|
||||
vc->vc_need_wrap = 0;
|
||||
}
|
||||
@@ -1225,7 +1217,7 @@ static void csi_K(struct vc_data *vc, int vpar)
|
||||
}
|
||||
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
|
||||
vc->vc_need_wrap = 0;
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
do_update_region(vc, (unsigned long) start, count);
|
||||
}
|
||||
|
||||
@@ -1238,7 +1230,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi
|
||||
count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
|
||||
|
||||
scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
|
||||
if (DO_UPDATE(vc))
|
||||
if (con_should_update(vc))
|
||||
vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
|
||||
vc->vc_need_wrap = 0;
|
||||
}
|
||||
@@ -1255,48 +1247,87 @@ static void default_attr(struct vc_data *vc)
|
||||
|
||||
struct rgb { u8 r; u8 g; u8 b; };
|
||||
|
||||
static struct rgb rgb_from_256(int i)
|
||||
static void rgb_from_256(int i, struct rgb *c)
|
||||
{
|
||||
struct rgb c;
|
||||
if (i < 8) { /* Standard colours. */
|
||||
c.r = i&1 ? 0xaa : 0x00;
|
||||
c.g = i&2 ? 0xaa : 0x00;
|
||||
c.b = i&4 ? 0xaa : 0x00;
|
||||
c->r = i&1 ? 0xaa : 0x00;
|
||||
c->g = i&2 ? 0xaa : 0x00;
|
||||
c->b = i&4 ? 0xaa : 0x00;
|
||||
} else if (i < 16) {
|
||||
c.r = i&1 ? 0xff : 0x55;
|
||||
c.g = i&2 ? 0xff : 0x55;
|
||||
c.b = i&4 ? 0xff : 0x55;
|
||||
c->r = i&1 ? 0xff : 0x55;
|
||||
c->g = i&2 ? 0xff : 0x55;
|
||||
c->b = i&4 ? 0xff : 0x55;
|
||||
} else if (i < 232) { /* 6x6x6 colour cube. */
|
||||
c.r = (i - 16) / 36 * 85 / 2;
|
||||
c.g = (i - 16) / 6 % 6 * 85 / 2;
|
||||
c.b = (i - 16) % 6 * 85 / 2;
|
||||
c->r = (i - 16) / 36 * 85 / 2;
|
||||
c->g = (i - 16) / 6 % 6 * 85 / 2;
|
||||
c->b = (i - 16) % 6 * 85 / 2;
|
||||
} else /* Grayscale ramp. */
|
||||
c.r = c.g = c.b = i * 10 - 2312;
|
||||
return c;
|
||||
c->r = c->g = c->b = i * 10 - 2312;
|
||||
}
|
||||
|
||||
static void rgb_foreground(struct vc_data *vc, struct rgb c)
|
||||
static void rgb_foreground(struct vc_data *vc, const struct rgb *c)
|
||||
{
|
||||
u8 hue, max = c.r;
|
||||
if (c.g > max)
|
||||
max = c.g;
|
||||
if (c.b > max)
|
||||
max = c.b;
|
||||
hue = (c.r > max/2 ? 4 : 0)
|
||||
| (c.g > max/2 ? 2 : 0)
|
||||
| (c.b > max/2 ? 1 : 0);
|
||||
if (hue == 7 && max <= 0x55)
|
||||
hue = 0, vc->vc_intensity = 2;
|
||||
u8 hue = 0, max = max3(c->r, c->g, c->b);
|
||||
|
||||
if (c->r > max / 2)
|
||||
hue |= 4;
|
||||
if (c->g > max / 2)
|
||||
hue |= 2;
|
||||
if (c->b > max / 2)
|
||||
hue |= 1;
|
||||
|
||||
if (hue == 7 && max <= 0x55) {
|
||||
hue = 0;
|
||||
vc->vc_intensity = 2;
|
||||
} else if (max > 0xaa)
|
||||
vc->vc_intensity = 2;
|
||||
else
|
||||
vc->vc_intensity = (max > 0xaa) + 1;
|
||||
vc->vc_intensity = 1;
|
||||
|
||||
vc->vc_color = (vc->vc_color & 0xf0) | hue;
|
||||
}
|
||||
|
||||
static void rgb_background(struct vc_data *vc, struct rgb c)
|
||||
static void rgb_background(struct vc_data *vc, const struct rgb *c)
|
||||
{
|
||||
/* For backgrounds, err on the dark side. */
|
||||
vc->vc_color = (vc->vc_color & 0x0f)
|
||||
| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
|
||||
| (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* ITU T.416 Higher colour modes. They break the usual properties of SGR codes
|
||||
* and thus need to be detected and ignored by hand. Strictly speaking, that
|
||||
* standard also wants : rather than ; as separators, contrary to ECMA-48, but
|
||||
* no one produces such codes and almost no one accepts them.
|
||||
*
|
||||
* Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in
|
||||
* supporting them.
|
||||
*/
|
||||
static int vc_t416_color(struct vc_data *vc, int i,
|
||||
void(*set_color)(struct vc_data *vc, const struct rgb *c))
|
||||
{
|
||||
struct rgb c;
|
||||
|
||||
i++;
|
||||
if (i > vc->vc_npar)
|
||||
return i;
|
||||
|
||||
if (vc->vc_par[i] == 5 && i < vc->vc_npar) {
|
||||
/* 256 colours -- ubiquitous */
|
||||
i++;
|
||||
rgb_from_256(vc->vc_par[i], &c);
|
||||
} else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) {
|
||||
/* 24 bit -- extremely rare */
|
||||
c.r = vc->vc_par[i + 1];
|
||||
c.g = vc->vc_par[i + 2];
|
||||
c.b = vc->vc_par[i + 3];
|
||||
i += 3;
|
||||
} else
|
||||
return i;
|
||||
|
||||
set_color(vc, &c);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* console_lock is held */
|
||||
@@ -1306,135 +1337,91 @@ static void csi_m(struct vc_data *vc)
|
||||
|
||||
for (i = 0; i <= vc->vc_npar; i++)
|
||||
switch (vc->vc_par[i]) {
|
||||
case 0: /* all attributes off */
|
||||
default_attr(vc);
|
||||
break;
|
||||
case 1:
|
||||
vc->vc_intensity = 2;
|
||||
break;
|
||||
case 2:
|
||||
vc->vc_intensity = 0;
|
||||
break;
|
||||
case 3:
|
||||
vc->vc_italic = 1;
|
||||
break;
|
||||
case 4:
|
||||
vc->vc_underline = 1;
|
||||
break;
|
||||
case 5:
|
||||
vc->vc_blink = 1;
|
||||
break;
|
||||
case 7:
|
||||
vc->vc_reverse = 1;
|
||||
break;
|
||||
case 10: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select primary font, don't display
|
||||
* control chars if defined, don't set
|
||||
* bit 8 on output.
|
||||
*/
|
||||
vc->vc_translate = set_translate(vc->vc_charset == 0
|
||||
? vc->vc_G0_charset
|
||||
: vc->vc_G1_charset, vc);
|
||||
vc->vc_disp_ctrl = 0;
|
||||
vc->vc_toggle_meta = 0;
|
||||
break;
|
||||
case 11: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select first alternate font, lets
|
||||
* chars < 32 be displayed as ROM chars.
|
||||
*/
|
||||
vc->vc_translate = set_translate(IBMPC_MAP, vc);
|
||||
vc->vc_disp_ctrl = 1;
|
||||
vc->vc_toggle_meta = 0;
|
||||
break;
|
||||
case 12: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select second alternate font, toggle
|
||||
* high bit before displaying as ROM char.
|
||||
*/
|
||||
vc->vc_translate = set_translate(IBMPC_MAP, vc);
|
||||
vc->vc_disp_ctrl = 1;
|
||||
vc->vc_toggle_meta = 1;
|
||||
break;
|
||||
case 21:
|
||||
case 22:
|
||||
vc->vc_intensity = 1;
|
||||
break;
|
||||
case 23:
|
||||
vc->vc_italic = 0;
|
||||
break;
|
||||
case 24:
|
||||
vc->vc_underline = 0;
|
||||
break;
|
||||
case 25:
|
||||
vc->vc_blink = 0;
|
||||
break;
|
||||
case 27:
|
||||
vc->vc_reverse = 0;
|
||||
break;
|
||||
case 38: /* ITU T.416
|
||||
* Higher colour modes.
|
||||
* They break the usual properties of SGR codes
|
||||
* and thus need to be detected and ignored by
|
||||
* hand. Strictly speaking, that standard also
|
||||
* wants : rather than ; as separators, contrary
|
||||
* to ECMA-48, but no one produces such codes
|
||||
* and almost no one accepts them.
|
||||
*/
|
||||
i++;
|
||||
if (i > vc->vc_npar)
|
||||
break;
|
||||
if (vc->vc_par[i] == 5 && /* 256 colours */
|
||||
i < vc->vc_npar) { /* ubiquitous */
|
||||
i++;
|
||||
rgb_foreground(vc,
|
||||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {/* extremely rare */
|
||||
struct rgb c = {
|
||||
.r = vc->vc_par[i + 1],
|
||||
.g = vc->vc_par[i + 2],
|
||||
.b = vc->vc_par[i + 3],
|
||||
};
|
||||
rgb_foreground(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
|
||||
* there's no point in supporting them.
|
||||
*/
|
||||
break;
|
||||
case 48:
|
||||
i++;
|
||||
if (i > vc->vc_npar)
|
||||
break;
|
||||
if (vc->vc_par[i] == 5 && /* 256 colours */
|
||||
i < vc->vc_npar) {
|
||||
i++;
|
||||
rgb_background(vc,
|
||||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {
|
||||
struct rgb c = {
|
||||
.r = vc->vc_par[i + 1],
|
||||
.g = vc->vc_par[i + 2],
|
||||
.b = vc->vc_par[i + 3],
|
||||
};
|
||||
rgb_background(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
break;
|
||||
case 39:
|
||||
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
|
||||
break;
|
||||
case 49:
|
||||
vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
|
||||
break;
|
||||
default:
|
||||
if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
|
||||
vc->vc_color = color_table[vc->vc_par[i] - 30]
|
||||
| (vc->vc_color & 0xf0);
|
||||
else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
|
||||
vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
|
||||
| (vc->vc_color & 0x0f);
|
||||
break;
|
||||
case 0: /* all attributes off */
|
||||
default_attr(vc);
|
||||
break;
|
||||
case 1:
|
||||
vc->vc_intensity = 2;
|
||||
break;
|
||||
case 2:
|
||||
vc->vc_intensity = 0;
|
||||
break;
|
||||
case 3:
|
||||
vc->vc_italic = 1;
|
||||
break;
|
||||
case 4:
|
||||
vc->vc_underline = 1;
|
||||
break;
|
||||
case 5:
|
||||
vc->vc_blink = 1;
|
||||
break;
|
||||
case 7:
|
||||
vc->vc_reverse = 1;
|
||||
break;
|
||||
case 10: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select primary font, don't display control chars if
|
||||
* defined, don't set bit 8 on output.
|
||||
*/
|
||||
vc->vc_translate = set_translate(vc->vc_charset == 0
|
||||
? vc->vc_G0_charset
|
||||
: vc->vc_G1_charset, vc);
|
||||
vc->vc_disp_ctrl = 0;
|
||||
vc->vc_toggle_meta = 0;
|
||||
break;
|
||||
case 11: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select first alternate font, lets chars < 32 be
|
||||
* displayed as ROM chars.
|
||||
*/
|
||||
vc->vc_translate = set_translate(IBMPC_MAP, vc);
|
||||
vc->vc_disp_ctrl = 1;
|
||||
vc->vc_toggle_meta = 0;
|
||||
break;
|
||||
case 12: /* ANSI X3.64-1979 (SCO-ish?)
|
||||
* Select second alternate font, toggle high bit
|
||||
* before displaying as ROM char.
|
||||
*/
|
||||
vc->vc_translate = set_translate(IBMPC_MAP, vc);
|
||||
vc->vc_disp_ctrl = 1;
|
||||
vc->vc_toggle_meta = 1;
|
||||
break;
|
||||
case 21:
|
||||
case 22:
|
||||
vc->vc_intensity = 1;
|
||||
break;
|
||||
case 23:
|
||||
vc->vc_italic = 0;
|
||||
break;
|
||||
case 24:
|
||||
vc->vc_underline = 0;
|
||||
break;
|
||||
case 25:
|
||||
vc->vc_blink = 0;
|
||||
break;
|
||||
case 27:
|
||||
vc->vc_reverse = 0;
|
||||
break;
|
||||
case 38:
|
||||
i = vc_t416_color(vc, i, rgb_foreground);
|
||||
break;
|
||||
case 48:
|
||||
i = vc_t416_color(vc, i, rgb_background);
|
||||
break;
|
||||
case 39:
|
||||
vc->vc_color = (vc->vc_def_color & 0x0f) |
|
||||
(vc->vc_color & 0xf0);
|
||||
break;
|
||||
case 49:
|
||||
vc->vc_color = (vc->vc_def_color & 0xf0) |
|
||||
(vc->vc_color & 0x0f);
|
||||
break;
|
||||
default:
|
||||
if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
|
||||
vc->vc_color = color_table[vc->vc_par[i] - 30]
|
||||
| (vc->vc_color & 0xf0);
|
||||
else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
|
||||
vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
|
||||
| (vc->vc_color & 0x0f);
|
||||
break;
|
||||
}
|
||||
update_attr(vc);
|
||||
}
|
||||
@@ -1496,7 +1483,6 @@ static void set_mode(struct vc_data *vc, int on_off)
|
||||
clr_kbd(vc, decckm);
|
||||
break;
|
||||
case 3: /* 80/132 mode switch unimplemented */
|
||||
vc->vc_deccolm = on_off;
|
||||
#if 0
|
||||
vc_resize(deccolm ? 132 : 80, vc->vc_rows);
|
||||
/* this alone does not suffice; some user mode
|
||||
@@ -2178,18 +2164,20 @@ static int is_double_width(uint32_t ucs)
|
||||
return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
|
||||
}
|
||||
|
||||
static void con_flush(struct vc_data *vc, unsigned long draw_from,
|
||||
unsigned long draw_to, int *draw_x)
|
||||
{
|
||||
if (*draw_x < 0)
|
||||
return;
|
||||
|
||||
vc->vc_sw->con_putcs(vc, (u16 *)draw_from,
|
||||
(u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x);
|
||||
*draw_x = -1;
|
||||
}
|
||||
|
||||
/* acquires console_lock */
|
||||
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
#ifdef VT_BUF_VRAM_ONLY
|
||||
#define FLUSH do { } while(0);
|
||||
#else
|
||||
#define FLUSH if (draw_x >= 0) { \
|
||||
vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
|
||||
draw_x = -1; \
|
||||
}
|
||||
#endif
|
||||
|
||||
int c, tc, ok, n = 0, draw_x = -1;
|
||||
unsigned int currcons;
|
||||
unsigned long draw_from = 0, draw_to = 0;
|
||||
@@ -2226,7 +2214,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
|
||||
charmask = himask ? 0x1ff : 0xff;
|
||||
|
||||
/* undraw cursor first */
|
||||
if (IS_FG(vc))
|
||||
if (con_is_fg(vc))
|
||||
hide_cursor(vc);
|
||||
|
||||
param.vc = vc;
|
||||
@@ -2381,12 +2369,13 @@ rescan_last_byte:
|
||||
} else {
|
||||
vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
|
||||
}
|
||||
FLUSH
|
||||
con_flush(vc, draw_from, draw_to, &draw_x);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (vc->vc_need_wrap || vc->vc_decim)
|
||||
FLUSH
|
||||
con_flush(vc, draw_from, draw_to,
|
||||
&draw_x);
|
||||
if (vc->vc_need_wrap) {
|
||||
cr(vc);
|
||||
lf(vc);
|
||||
@@ -2397,7 +2386,7 @@ rescan_last_byte:
|
||||
((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
|
||||
(vc_attr << 8) + tc,
|
||||
(u16 *) vc->vc_pos);
|
||||
if (DO_UPDATE(vc) && draw_x < 0) {
|
||||
if (con_should_update(vc) && draw_x < 0) {
|
||||
draw_x = vc->vc_x;
|
||||
draw_from = vc->vc_pos;
|
||||
}
|
||||
@@ -2416,9 +2405,8 @@ rescan_last_byte:
|
||||
}
|
||||
notify_write(vc, c);
|
||||
|
||||
if (inverse) {
|
||||
FLUSH
|
||||
}
|
||||
if (inverse)
|
||||
con_flush(vc, draw_from, draw_to, &draw_x);
|
||||
|
||||
if (rescan) {
|
||||
rescan = 0;
|
||||
@@ -2429,15 +2417,14 @@ rescan_last_byte:
|
||||
}
|
||||
continue;
|
||||
}
|
||||
FLUSH
|
||||
con_flush(vc, draw_from, draw_to, &draw_x);
|
||||
do_con_trol(tty, vc, orig);
|
||||
}
|
||||
FLUSH
|
||||
con_flush(vc, draw_from, draw_to, &draw_x);
|
||||
console_conditional_schedule();
|
||||
console_unlock();
|
||||
notify_update(vc);
|
||||
return n;
|
||||
#undef FLUSH
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2471,7 +2458,7 @@ static void console_callback(struct work_struct *ignored)
|
||||
if (scrollback_delta) {
|
||||
struct vc_data *vc = vc_cons[fg_console].d;
|
||||
clear_selection();
|
||||
if (vc->vc_mode == KD_TEXT)
|
||||
if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
|
||||
vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
|
||||
scrollback_delta = 0;
|
||||
}
|
||||
@@ -2583,7 +2570,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
|
||||
goto quit;
|
||||
|
||||
/* undraw cursor first */
|
||||
if (IS_FG(vc))
|
||||
if (con_is_fg(vc))
|
||||
hide_cursor(vc);
|
||||
|
||||
start = (ushort *)vc->vc_pos;
|
||||
@@ -2594,7 +2581,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
|
||||
c = *b++;
|
||||
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
|
||||
if (cnt > 0) {
|
||||
if (CON_IS_VISIBLE(vc))
|
||||
if (con_is_visible(vc))
|
||||
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
|
||||
vc->vc_x += cnt;
|
||||
if (vc->vc_need_wrap)
|
||||
@@ -2626,7 +2613,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
|
||||
myx++;
|
||||
}
|
||||
if (cnt > 0) {
|
||||
if (CON_IS_VISIBLE(vc))
|
||||
if (con_is_visible(vc))
|
||||
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
|
||||
vc->vc_x += cnt;
|
||||
if (vc->vc_x == vc->vc_cols) {
|
||||
@@ -3173,7 +3160,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
|
||||
|
||||
j = i;
|
||||
|
||||
if (CON_IS_VISIBLE(vc)) {
|
||||
if (con_is_visible(vc)) {
|
||||
k = i;
|
||||
save_screen(vc);
|
||||
}
|
||||
@@ -3981,7 +3968,7 @@ static void set_palette(struct vc_data *vc)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (vc->vc_mode != KD_GRAPHICS)
|
||||
if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette)
|
||||
vc->vc_sw->con_set_palette(vc, color_table);
|
||||
}
|
||||
|
||||
|
@@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty,
|
||||
break;
|
||||
|
||||
case PIO_UNIMAPCLR:
|
||||
{ struct unimapinit ui;
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
else
|
||||
con_clear_unimap(vc, &ui);
|
||||
con_clear_unimap(vc);
|
||||
break;
|
||||
}
|
||||
|
||||
case PIO_UNIMAP:
|
||||
case GIO_UNIMAP:
|
||||
|
Reference in New Issue
Block a user