TTY/Serial updates for 4.14-rc1

Here is the big tty/serial driver update for 4.14-rc1.
 
 Well, not all that big, just a number of small serial driver fixes, and
 a new serial driver.  Also in here are some much needed goldfish tty
 driver (emulator) fixes to try to get that codebase under control.
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWa2A+A8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylNKACfWOuWb4PEGzPg2hF57V1g0cq8VXEAn0BtZT+n
 uuCBV53ylesoHhEhKf/D
 =g+za
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial updates from Greg KH:
 "Here is the big tty/serial driver update for 4.14-rc1.

  Well, not all that big, just a number of small serial driver fixes,
  and a new serial driver. Also in here are some much needed goldfish
  tty driver (emulator) fixes to try to get that codebase under control.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (94 commits)
  tty: goldfish: Implement support for kernel 'earlycon' parameter
  tty: goldfish: Use streaming DMA for r/w operations on Ranchu platforms
  tty: goldfish: Refactor constants to better reflect their nature
  serial: 8250_port: Remove useless NULL checks
  earlycon: initialise baud field of earlycon device structure
  tty: hvcs: make ktermios const
  pty: show associative slave of ptmx in fdinfo
  tty: n_gsm: Add compat_ioctl
  tty: hvcs: constify vio_device_id
  tty: hvc_vio: constify vio_device_id
  tty: mips_ejtag_fdc: constify mips_cdmm_device_id
  Introduce 8250_men_mcb
  mcb: introduce mcb_get_resource()
  serial: imx: Avoid post-PIO cleanup if TX DMA is started
  tty: serial: imx: disable irq after suspend
  serial: 8250_uniphier: add suspend/resume support
  serial: 8250_uniphier: use CHAR register for canary to detect power-off
  serial: 8250_uniphier: fix serial port index in private data
  serial: 8250: of: Add new port type for MediaTek BTIF controller on MT7622/23 SoC
  dt-bindings: serial: 8250: Add MediaTek BTIF controller bindings
  ...
This commit is contained in:
Linus Torvalds 2017-09-05 10:30:48 -07:00
commit e63a94f12b
74 changed files with 1628 additions and 306 deletions

View file

@ -14,6 +14,8 @@ Required properties:
tegra132, or tegra210. tegra132, or tegra210.
- "nxp,lpc3220-uart" - "nxp,lpc3220-uart"
- "ralink,rt2880-uart" - "ralink,rt2880-uart"
- For MediaTek BTIF, must contain '"mediatek,<chip>-btif",
"mediatek,mtk-btif"' where <chip> is mt7622, mt7623.
- "altr,16550-FIFO32" - "altr,16550-FIFO32"
- "altr,16550-FIFO64" - "altr,16550-FIFO64"
- "altr,16550-FIFO128" - "altr,16550-FIFO128"

View file

@ -41,6 +41,8 @@ Required properties:
- "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
- "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART. - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART.
- "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART. - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART.
- "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART.
- "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
- "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART, - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,

View file

@ -5,14 +5,13 @@ the built-in half-duplex mode.
The properties described hereafter shall be given to a half-duplex capable The properties described hereafter shall be given to a half-duplex capable
UART node. UART node.
Required properties: Optional properties:
- rs485-rts-delay: prop-encoded-array <a b> where: - rs485-rts-delay: prop-encoded-array <a b> where:
* a is the delay between rts signal and beginning of data sent in milliseconds. * a is the delay between rts signal and beginning of data sent in milliseconds.
it corresponds to the delay before sending data. it corresponds to the delay before sending data.
* b is the delay between end of data sent and rts signal in milliseconds * b is the delay between end of data sent and rts signal in milliseconds
it corresponds to the delay after sending data and actual release of the line. it corresponds to the delay after sending data and actual release of the line.
If this property is not specified, <0 0> is assumed.
Optional properties:
- linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
feature at boot time. It can be disabled later with proper ioctl. feature at boot time. It can be disabled later with proper ioctl.
- rs485-rx-during-tx: empty property that enables the receiving of data even - rs485-rx-during-tx: empty property that enables the receiving of data even

View file

@ -1,12 +1,19 @@
* STMicroelectronics STM32 USART * STMicroelectronics STM32 USART
Required properties: Required properties:
- compatible: Can be either "st,stm32-usart", "st,stm32-uart", - compatible: can be either:
"st,stm32f7-usart" or "st,stm32f7-uart" depending on whether - "st,stm32-usart",
the device supports synchronous mode and is compatible with - "st,stm32-uart",
stm32(f4) or stm32f7. - "st,stm32f7-usart",
- "st,stm32f7-uart",
- "st,stm32h7-usart"
- "st,stm32h7-uart".
depending on whether the device supports synchronous mode
and is compatible with stm32(f4), stm32f7 or stm32h7.
- reg: The address and length of the peripheral registers space - reg: The address and length of the peripheral registers space
- interrupts: The interrupt line of the USART instance - interrupts:
- The interrupt line for the USART instance,
- An optional wake-up interrupt.
- clocks: The input clock of the USART instance - clocks: The input clock of the USART instance
Optional properties: Optional properties:

View file

@ -417,6 +417,22 @@ void mcb_bus_add_devices(const struct mcb_bus *bus)
} }
EXPORT_SYMBOL_GPL(mcb_bus_add_devices); EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
/**
* mcb_get_resource() - get a resource for a mcb device
* @dev: the mcb device
* @type: the type of resource
*/
struct resource *mcb_get_resource(struct mcb_device *dev, unsigned int type)
{
if (type == IORESOURCE_MEM)
return &dev->mem;
else if (type == IORESOURCE_IRQ)
return &dev->irq;
else
return NULL;
}
EXPORT_SYMBOL_GPL(mcb_get_resource);
/** /**
* mcb_request_mem() - Request memory * mcb_request_mem() - Request memory
* @dev: The @mcb_device the memory is for * @dev: The @mcb_device the memory is for
@ -460,7 +476,9 @@ EXPORT_SYMBOL_GPL(mcb_release_mem);
static int __mcb_get_irq(struct mcb_device *dev) static int __mcb_get_irq(struct mcb_device *dev)
{ {
struct resource *irq = &dev->irq; struct resource *irq;
irq = mcb_get_resource(dev, IORESOURCE_IRQ);
return irq->start; return irq->start;
} }

View file

@ -392,6 +392,9 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
config GOLDFISH_TTY config GOLDFISH_TTY
tristate "Goldfish TTY Driver" tristate "Goldfish TTY Driver"
depends on GOLDFISH depends on GOLDFISH
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help help
Console and system TTY driver for the Goldfish virtual platform. Console and system TTY driver for the Goldfish virtual platform.

View file

@ -122,7 +122,7 @@ static int find_console_handle(void)
stdout_irq = irq_of_parse_and_map(np, 0); stdout_irq = irq_of_parse_and_map(np, 0);
if (stdout_irq == NO_IRQ) { if (stdout_irq == NO_IRQ) {
pr_err("ehv-bc: no 'interrupts' property in %s node\n", np->full_name); pr_err("ehv-bc: no 'interrupts' property in %pOF node\n", np);
return 0; return 0;
} }

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2007 Google, Inc. * Copyright (C) 2007 Google, Inc.
* Copyright (C) 2012 Intel, Inc. * Copyright (C) 2012 Intel, Inc.
* Copyright (C) 2017 Imagination Technologies Ltd.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
@ -22,21 +23,23 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/goldfish.h> #include <linux/goldfish.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/serial_core.h>
enum { /* Goldfish tty register's offsets */
GOLDFISH_TTY_PUT_CHAR = 0x00, #define GOLDFISH_TTY_REG_BYTES_READY 0x04
GOLDFISH_TTY_BYTES_READY = 0x04, #define GOLDFISH_TTY_REG_CMD 0x08
GOLDFISH_TTY_CMD = 0x08, #define GOLDFISH_TTY_REG_DATA_PTR 0x10
#define GOLDFISH_TTY_REG_DATA_LEN 0x14
#define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18
#define GOLDFISH_TTY_REG_VERSION 0x20
GOLDFISH_TTY_DATA_PTR = 0x10, /* Goldfish tty commands */
GOLDFISH_TTY_DATA_LEN = 0x14, #define GOLDFISH_TTY_CMD_INT_DISABLE 0
GOLDFISH_TTY_DATA_PTR_HIGH = 0x18, #define GOLDFISH_TTY_CMD_INT_ENABLE 1
#define GOLDFISH_TTY_CMD_WRITE_BUFFER 2
GOLDFISH_TTY_CMD_INT_DISABLE = 0, #define GOLDFISH_TTY_CMD_READ_BUFFER 3
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
GOLDFISH_TTY_CMD_WRITE_BUFFER = 2,
GOLDFISH_TTY_CMD_READ_BUFFER = 3,
};
struct goldfish_tty { struct goldfish_tty {
struct tty_port port; struct tty_port port;
@ -45,6 +48,8 @@ struct goldfish_tty {
u32 irq; u32 irq;
int opencount; int opencount;
struct console console; struct console console;
u32 version;
struct device *dev;
}; };
static DEFINE_MUTEX(goldfish_tty_lock); static DEFINE_MUTEX(goldfish_tty_lock);
@ -53,38 +58,107 @@ static u32 goldfish_tty_line_count = 8;
static u32 goldfish_tty_current_line_count; static u32 goldfish_tty_current_line_count;
static struct goldfish_tty *goldfish_ttys; static struct goldfish_tty *goldfish_ttys;
static void goldfish_tty_do_write(int line, const char *buf, unsigned count) static void do_rw_io(struct goldfish_tty *qtty,
unsigned long address,
unsigned int count,
int is_write)
{ {
unsigned long irq_flags; unsigned long irq_flags;
struct goldfish_tty *qtty = &goldfish_ttys[line];
void __iomem *base = qtty->base; void __iomem *base = qtty->base;
spin_lock_irqsave(&qtty->lock, irq_flags); spin_lock_irqsave(&qtty->lock, irq_flags);
gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR,
base + GOLDFISH_TTY_DATA_PTR_HIGH); base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
writel(count, base + GOLDFISH_TTY_DATA_LEN); writel(count, base + GOLDFISH_TTY_REG_DATA_LEN);
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
if (is_write)
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER,
base + GOLDFISH_TTY_REG_CMD);
else
writel(GOLDFISH_TTY_CMD_READ_BUFFER,
base + GOLDFISH_TTY_REG_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags); spin_unlock_irqrestore(&qtty->lock, irq_flags);
} }
static void goldfish_tty_rw(struct goldfish_tty *qtty,
unsigned long addr,
unsigned int count,
int is_write)
{
dma_addr_t dma_handle;
enum dma_data_direction dma_dir;
dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (qtty->version > 0) {
/*
* Goldfish TTY for Ranchu platform uses
* physical addresses and DMA for read/write operations
*/
unsigned long addr_end = addr + count;
while (addr < addr_end) {
unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE;
unsigned long next =
pg_end < addr_end ? pg_end : addr_end;
unsigned long avail = next - addr;
/*
* Map the buffer's virtual address to the DMA address
* so the buffer can be accessed by the device.
*/
dma_handle = dma_map_single(qtty->dev, (void *)addr,
avail, dma_dir);
if (dma_mapping_error(qtty->dev, dma_handle)) {
dev_err(qtty->dev, "tty: DMA mapping error.\n");
return;
}
do_rw_io(qtty, dma_handle, avail, is_write);
/*
* Unmap the previously mapped region after
* the completion of the read/write operation.
*/
dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir);
addr += avail;
}
} else {
/*
* Old style Goldfish TTY used on the Goldfish platform
* uses virtual addresses.
*/
do_rw_io(qtty, addr, count, is_write);
}
}
static void goldfish_tty_do_write(int line, const char *buf,
unsigned int count)
{
struct goldfish_tty *qtty = &goldfish_ttys[line];
unsigned long address = (unsigned long)(void *)buf;
goldfish_tty_rw(qtty, address, count, 1);
}
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
{ {
struct goldfish_tty *qtty = dev_id; struct goldfish_tty *qtty = dev_id;
void __iomem *base = qtty->base; void __iomem *base = qtty->base;
unsigned long irq_flags; unsigned long address;
unsigned char *buf; unsigned char *buf;
u32 count; u32 count;
count = readl(base + GOLDFISH_TTY_BYTES_READY); count = readl(base + GOLDFISH_TTY_REG_BYTES_READY);
if (count == 0) if (count == 0)
return IRQ_NONE; return IRQ_NONE;
count = tty_prepare_flip_string(&qtty->port, &buf, count); count = tty_prepare_flip_string(&qtty->port, &buf, count);
spin_lock_irqsave(&qtty->lock, irq_flags);
gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, address = (unsigned long)(void *)buf;
base + GOLDFISH_TTY_DATA_PTR_HIGH); goldfish_tty_rw(qtty, address, count, 0);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
tty_schedule_flip(&qtty->port); tty_schedule_flip(&qtty->port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -93,7 +167,7 @@ static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
{ {
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
port); port);
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD); writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
return 0; return 0;
} }
@ -101,7 +175,7 @@ static void goldfish_tty_shutdown(struct tty_port *port)
{ {
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
port); port);
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD); writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
} }
static int goldfish_tty_open(struct tty_struct *tty, struct file *filp) static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
@ -136,7 +210,7 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
{ {
struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
void __iomem *base = qtty->base; void __iomem *base = qtty->base;
return readl(base + GOLDFISH_TTY_BYTES_READY); return readl(base + GOLDFISH_TTY_REG_BYTES_READY);
} }
static void goldfish_tty_console_write(struct console *co, const char *b, static void goldfish_tty_console_write(struct console *co, const char *b,
@ -227,7 +301,7 @@ static void goldfish_tty_delete_driver(void)
static int goldfish_tty_probe(struct platform_device *pdev) static int goldfish_tty_probe(struct platform_device *pdev)
{ {
struct goldfish_tty *qtty; struct goldfish_tty *qtty;
int ret = -EINVAL; int ret = -ENODEV;
struct resource *r; struct resource *r;
struct device *ttydev; struct device *ttydev;
void __iomem *base; void __iomem *base;
@ -235,16 +309,22 @@ static int goldfish_tty_probe(struct platform_device *pdev)
unsigned int line; unsigned int line;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) if (!r) {
return -EINVAL; pr_err("goldfish_tty: No MEM resource available!\n");
return -ENOMEM;
}
base = ioremap(r->start, 0x1000); base = ioremap(r->start, 0x1000);
if (base == NULL) if (!base) {
pr_err("goldfish_tty: unable to remap base\n"); pr_err("goldfish_tty: Unable to ioremap base!\n");
return -ENOMEM;
}
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (r == NULL) if (!r) {
pr_err("goldfish_tty: No IRQ resource available!\n");
goto err_unmap; goto err_unmap;
}
irq = r->start; irq = r->start;
@ -255,13 +335,17 @@ static int goldfish_tty_probe(struct platform_device *pdev)
else else
line = pdev->id; line = pdev->id;
if (line >= goldfish_tty_line_count) if (line >= goldfish_tty_line_count) {
goto err_create_driver_failed; pr_err("goldfish_tty: Reached maximum tty number of %d.\n",
goldfish_tty_current_line_count);
ret = -ENOMEM;
goto err_unlock;
}
if (goldfish_tty_current_line_count == 0) { if (goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver(); ret = goldfish_tty_create_driver();
if (ret) if (ret)
goto err_create_driver_failed; goto err_unlock;
} }
goldfish_tty_current_line_count++; goldfish_tty_current_line_count++;
@ -271,17 +355,45 @@ static int goldfish_tty_probe(struct platform_device *pdev)
qtty->port.ops = &goldfish_port_ops; qtty->port.ops = &goldfish_port_ops;
qtty->base = base; qtty->base = base;
qtty->irq = irq; qtty->irq = irq;
qtty->dev = &pdev->dev;
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); /*
* Goldfish TTY device used by the Goldfish emulator
* should identify itself with 0, forcing the driver
* to use virtual addresses. Goldfish TTY device
* on Ranchu emulator (qemu2) returns 1 here and
* driver will use physical addresses.
*/
qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION);
/*
* Goldfish TTY device on Ranchu emulator (qemu2)
* will use DMA for read/write IO operations.
*/
if (qtty->version > 0) {
/*
* Initialize dma_mask to 32-bits.
*/
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(&pdev->dev, "No suitable DMA available.\n");
goto err_dec_line_count;
}
}
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD);
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
"goldfish_tty", qtty); "goldfish_tty", qtty);
if (ret) if (ret) {
goto err_request_irq_failed; pr_err("goldfish_tty: No IRQ available!\n");
goto err_dec_line_count;
}
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
line, &pdev->dev); line, &pdev->dev);
if (IS_ERR(ttydev)) { if (IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev); ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed; goto err_tty_register_device_failed;
@ -301,11 +413,11 @@ static int goldfish_tty_probe(struct platform_device *pdev)
err_tty_register_device_failed: err_tty_register_device_failed:
free_irq(irq, qtty); free_irq(irq, qtty);
err_request_irq_failed: err_dec_line_count:
goldfish_tty_current_line_count--; goldfish_tty_current_line_count--;
if (goldfish_tty_current_line_count == 0) if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver(); goldfish_tty_delete_driver();
err_create_driver_failed: err_unlock:
mutex_unlock(&goldfish_tty_lock); mutex_unlock(&goldfish_tty_lock);
err_unmap: err_unmap:
iounmap(base); iounmap(base);
@ -330,6 +442,30 @@ static int goldfish_tty_remove(struct platform_device *pdev)
return 0; return 0;
} }
static void gf_early_console_putchar(struct uart_port *port, int ch)
{
__raw_writel(ch, port->membase);
}
static void gf_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, gf_early_console_putchar);
}
static int __init gf_earlycon_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = gf_early_write;
return 0;
}
OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup);
static const struct of_device_id goldfish_tty_of_match[] = { static const struct of_device_id goldfish_tty_of_match[] = {
{ .compatible = "google,goldfish-tty", }, { .compatible = "google,goldfish-tty", },
{}, {},

View file

@ -179,8 +179,8 @@ static int hvc_opal_probe(struct platform_device *dev)
proto = HV_PROTOCOL_HVSI; proto = HV_PROTOCOL_HVSI;
ops = &hvc_opal_hvsi_ops; ops = &hvc_opal_hvsi_ops;
} else { } else {
pr_err("hvc_opal: Unknown protocol for %s\n", pr_err("hvc_opal: Unknown protocol for %pOF\n",
dev->dev.of_node->full_name); dev->dev.of_node);
return -ENXIO; return -ENXIO;
} }
@ -204,14 +204,14 @@ static int hvc_opal_probe(struct platform_device *dev)
/* Instanciate now to establish a mapping index==vtermno */ /* Instanciate now to establish a mapping index==vtermno */
hvc_instantiate(termno, termno, ops); hvc_instantiate(termno, termno, ops);
} else { } else {
pr_err("hvc_opal: Device %s has duplicate terminal number #%d\n", pr_err("hvc_opal: Device %pOF has duplicate terminal number #%d\n",
dev->dev.of_node->full_name, termno); dev->dev.of_node, termno);
return -ENXIO; return -ENXIO;
} }
pr_info("hvc%d: %s protocol on %s%s\n", termno, pr_info("hvc%d: %s protocol on %pOF%s\n", termno,
proto == HV_PROTOCOL_RAW ? "raw" : "hvsi", proto == HV_PROTOCOL_RAW ? "raw" : "hvsi",
dev->dev.of_node->full_name, dev->dev.of_node,
boot ? " (boot console)" : ""); boot ? " (boot console)" : "");
irq = irq_of_parse_and_map(dev->dev.of_node, 0); irq = irq_of_parse_and_map(dev->dev.of_node, 0);
@ -222,8 +222,8 @@ static int hvc_opal_probe(struct platform_device *dev)
} }
if (!irq) { if (!irq) {
pr_err("hvc_opal: Unable to map interrupt for device %s\n", pr_err("hvc_opal: Unable to map interrupt for device %pOF\n",
dev->dev.of_node->full_name); dev->dev.of_node);
return irq; return irq;
} }

View file

@ -53,7 +53,7 @@
static const char hvc_driver_name[] = "hvc_console"; static const char hvc_driver_name[] = "hvc_console";
static struct vio_device_id hvc_driver_table[] = { static const struct vio_device_id hvc_driver_table[] = {
{"serial", "hvterm1"}, {"serial", "hvterm1"},
#ifndef HVC_OLD_HVSI #ifndef HVC_OLD_HVSI
{"serial", "hvterm-protocol"}, {"serial", "hvterm-protocol"},
@ -312,12 +312,12 @@ static int hvc_vio_probe(struct vio_dev *vdev,
proto = HV_PROTOCOL_HVSI; proto = HV_PROTOCOL_HVSI;
ops = &hvterm_hvsi_ops; ops = &hvterm_hvsi_ops;
} else { } else {
pr_err("hvc_vio: Unknown protocol for %s\n", vdev->dev.of_node->full_name); pr_err("hvc_vio: Unknown protocol for %pOF\n", vdev->dev.of_node);
return -ENXIO; return -ENXIO;
} }
pr_devel("hvc_vio_probe() device %s, using %s protocol\n", pr_devel("hvc_vio_probe() device %pOF, using %s protocol\n",
vdev->dev.of_node->full_name, vdev->dev.of_node,
proto == HV_PROTOCOL_RAW ? "raw" : "hvsi"); proto == HV_PROTOCOL_RAW ? "raw" : "hvsi");
/* Is it our boot one ? */ /* Is it our boot one ? */

View file

@ -189,7 +189,7 @@ MODULE_VERSION(HVCS_DRIVER_VERSION);
* that will cause echoing or we'll go into recursive loop echoing chars back * that will cause echoing or we'll go into recursive loop echoing chars back
* and forth with the console drivers. * and forth with the console drivers.
*/ */
static struct ktermios hvcs_tty_termios = { static const struct ktermios hvcs_tty_termios = {
.c_iflag = IGNBRK | IGNPAR, .c_iflag = IGNBRK | IGNPAR,
.c_oflag = OPOST, .c_oflag = OPOST,
.c_cflag = B38400 | CS8 | CREAD | HUPCL, .c_cflag = B38400 | CS8 | CREAD | HUPCL,
@ -675,7 +675,7 @@ static int khvcsd(void *unused)
return 0; return 0;
} }
static struct vio_device_id hvcs_driver_table[] = { static const struct vio_device_id hvcs_driver_table[] = {
{"serial-server", "hvterm2"}, {"serial-server", "hvterm2"},
{ "", "" } { "", "" }
}; };

View file

@ -150,7 +150,7 @@
static int isicom_probe(struct pci_dev *, const struct pci_device_id *); static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
static void isicom_remove(struct pci_dev *); static void isicom_remove(struct pci_dev *);
static struct pci_device_id isicom_pci_tbl[] = { static const struct pci_device_id isicom_pci_tbl[] = {
{ PCI_DEVICE(VENDOR_ID, 0x2028) }, { PCI_DEVICE(VENDOR_ID, 0x2028) },
{ PCI_DEVICE(VENDOR_ID, 0x2051) }, { PCI_DEVICE(VENDOR_ID, 0x2051) },
{ PCI_DEVICE(VENDOR_ID, 0x2052) }, { PCI_DEVICE(VENDOR_ID, 0x2052) },

View file

@ -1110,7 +1110,7 @@ static int mips_ejtag_fdc_tty_cpu_up(struct mips_cdmm_device *dev)
return ret; return ret;
} }
static struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = { static const struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = {
{ .type = 0xfd }, { .type = 0xfd },
{ } { }
}; };

View file

@ -88,7 +88,7 @@ static char *moxa_brdname[] =
}; };
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static struct pci_device_id moxa_pcibrds[] = { static const struct pci_device_id moxa_pcibrds[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
.driver_data = MOXA_BOARD_C218_PCI }, .driver_data = MOXA_BOARD_C218_PCI },
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),

View file

@ -145,7 +145,7 @@ static const struct mxser_cardinfo mxser_cards[] = {
/* driver_data correspond to the lines in the structure above /* driver_data correspond to the lines in the structure above
see also ISA probe function before you change something */ see also ISA probe function before you change something */
static struct pci_device_id mxser_pcibrds[] = { static const struct pci_device_id mxser_pcibrds[] = {
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 },

View file

@ -2607,6 +2607,14 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
} }
} }
#ifdef CONFIG_COMPAT
static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
return gsmld_ioctl(tty, file, cmd, arg);
}
#endif
/* /*
* Network interface * Network interface
* *
@ -2818,6 +2826,9 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
.flush_buffer = gsmld_flush_buffer, .flush_buffer = gsmld_flush_buffer,
.read = gsmld_read, .read = gsmld_read,
.write = gsmld_write, .write = gsmld_write,
#ifdef CONFIG_COMPAT
.compat_ioctl = gsmld_compat_ioctl,
#endif
.ioctl = gsmld_ioctl, .ioctl = gsmld_ioctl,
.poll = gsmld_poll, .poll = gsmld_poll,
.receive_buf = gsmld_receive_buf, .receive_buf = gsmld_receive_buf,

View file

@ -742,6 +742,11 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
} }
} }
static void pty_show_fdinfo(struct tty_struct *tty, struct seq_file *m)
{
seq_printf(m, "tty-index:\t%d\n", tty->index);
}
static const struct tty_operations ptm_unix98_ops = { static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup, .lookup = ptm_unix98_lookup,
.install = pty_unix98_install, .install = pty_unix98_install,
@ -756,7 +761,8 @@ static const struct tty_operations ptm_unix98_ops = {
.ioctl = pty_unix98_ioctl, .ioctl = pty_unix98_ioctl,
.compat_ioctl = pty_unix98_compat_ioctl, .compat_ioctl = pty_unix98_compat_ioctl,
.resize = pty_resize, .resize = pty_resize,
.cleanup = pty_cleanup .cleanup = pty_cleanup,
.show_fdinfo = pty_show_fdinfo,
}; };
static const struct tty_operations pty_unix98_ops = { static const struct tty_operations pty_unix98_ops = {

View file

@ -363,7 +363,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
if (!of_get_property(node, "compatible", NULL)) if (!of_get_property(node, "compatible", NULL))
continue; continue;
dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name); dev_dbg(&ctrl->dev, "adding child %pOF\n", node);
serdev = serdev_device_alloc(ctrl); serdev = serdev_device_alloc(ctrl);
if (!serdev) if (!serdev)

View file

@ -334,7 +334,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
return ret; return ret;
} }
static struct uart_ops serial21285_ops = { static const struct uart_ops serial21285_ops = {
.tx_empty = serial21285_tx_empty, .tx_empty = serial21285_tx_empty,
.get_mctrl = serial21285_get_mctrl, .get_mctrl = serial21285_get_mctrl,
.set_mctrl = serial21285_set_mctrl, .set_mctrl = serial21285_set_mctrl,

View file

@ -223,12 +223,13 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
if (IS_ERR(vuart->clk)) { if (IS_ERR(vuart->clk)) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"clk or clock-frequency not defined\n"); "clk or clock-frequency not defined\n");
return PTR_ERR(vuart->clk); rc = PTR_ERR(vuart->clk);
goto err_sysfs_remove;
} }
rc = clk_prepare_enable(vuart->clk); rc = clk_prepare_enable(vuart->clk);
if (rc < 0) if (rc < 0)
return rc; goto err_sysfs_remove;
clk = clk_get_rate(vuart->clk); clk = clk_get_rate(vuart->clk);
} }
@ -286,6 +287,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
err_clk_disable: err_clk_disable:
clk_disable_unprepare(vuart->clk); clk_disable_unprepare(vuart->clk);
irq_dispose_mapping(port.port.irq); irq_dispose_mapping(port.port.irq);
err_sysfs_remove:
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
return rc; return rc;
} }

View file

@ -497,6 +497,11 @@ static void univ8250_rsa_support(struct uart_ops *ops)
#define univ8250_rsa_support(x) do { } while (0) #define univ8250_rsa_support(x) do { } while (0)
#endif /* CONFIG_SERIAL_8250_RSA */ #endif /* CONFIG_SERIAL_8250_RSA */
static inline void serial8250_apply_quirks(struct uart_8250_port *up)
{
up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0;
}
static void __init serial8250_isa_init_ports(void) static void __init serial8250_isa_init_ports(void)
{ {
struct uart_8250_port *up; struct uart_8250_port *up;
@ -577,9 +582,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
up->port.dev = dev; up->port.dev = dev;
if (skip_txen_test) serial8250_apply_quirks(up);
up->port.flags |= UPF_NO_TXEN_TEST;
uart_add_one_port(drv, &up->port); uart_add_one_port(drv, &up->port);
} }
} }
@ -1006,9 +1009,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.dev) if (up->port.dev)
uart->port.dev = up->port.dev; uart->port.dev = up->port.dev;
if (skip_txen_test)
uart->port.flags |= UPF_NO_TXEN_TEST;
if (up->port.flags & UPF_FIXED_TYPE) if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type; uart->port.type = up->port.type;
@ -1048,6 +1048,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
serial8250_isa_config(0, &uart->port, serial8250_isa_config(0, &uart->port,
&uart->capabilities); &uart->capabilities);
serial8250_apply_quirks(uart);
ret = uart_add_one_port(&serial8250_reg, ret = uart_add_one_port(&serial8250_reg,
&uart->port); &uart->port);
if (ret == 0) if (ret == 0)
@ -1092,11 +1093,10 @@ void serial8250_unregister_port(int line)
uart_remove_one_port(&serial8250_reg, &uart->port); uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) { if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF; uart->port.flags &= ~UPF_BOOT_AUTOCONF;
if (skip_txen_test)
uart->port.flags |= UPF_NO_TXEN_TEST;
uart->port.type = PORT_UNKNOWN; uart->port.type = PORT_UNKNOWN;
uart->port.dev = &serial8250_isa_devs->dev; uart->port.dev = &serial8250_isa_devs->dev;
uart->capabilities = 0; uart->capabilities = 0;
serial8250_apply_quirks(uart);
uart_add_one_port(&serial8250_reg, &uart->port); uart_add_one_port(&serial8250_reg, &uart->port);
} else { } else {
uart->port.dev = NULL; uart->port.dev = NULL;

View file

@ -529,7 +529,7 @@ static int dw8250_probe(struct platform_device *pdev)
} }
} }
data->rst = devm_reset_control_get_optional(dev, NULL); data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(data->rst)) { if (IS_ERR(data->rst)) {
err = PTR_ERR(data->rst); err = PTR_ERR(data->rst);
goto err_pclk; goto err_pclk;

View file

@ -37,7 +37,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/serial.h> #include <asm/serial.h>
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) static unsigned int serial8250_early_in(struct uart_port *port, int offset)
{ {
int reg_offset = offset; int reg_offset = offset;
offset <<= port->regshift; offset <<= port->regshift;
@ -60,7 +60,7 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
} }
} }
static void __init serial8250_early_out(struct uart_port *port, int offset, int value) static void serial8250_early_out(struct uart_port *port, int offset, int value)
{ {
int reg_offset = offset; int reg_offset = offset;
offset <<= port->regshift; offset <<= port->regshift;
@ -89,7 +89,7 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void __init serial_putc(struct uart_port *port, int c) static void serial_putc(struct uart_port *port, int c)
{ {
unsigned int status; unsigned int status;
@ -103,7 +103,7 @@ static void __init serial_putc(struct uart_port *port, int c)
} }
} }
static void __init early_serial8250_write(struct console *console, static void early_serial8250_write(struct console *console,
const char *s, unsigned int count) const char *s, unsigned int count)
{ {
struct earlycon_device *device = console->data; struct earlycon_device *device = console->data;

View file

@ -601,7 +601,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
(kernel_ulong_t)&bd \ (kernel_ulong_t)&bd \
} }
static struct pci_device_id exar_pci_tbl[] = { static const struct pci_device_id exar_pci_tbl[] = {
CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect),

View file

@ -50,17 +50,17 @@ static const struct of_device_id of_match[];
static struct earlycon_device *early_device; static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset) static uint8_t early_in(struct uart_port *port, int offset)
{ {
return readl(port->membase + (offset << 2)); return readl(port->membase + (offset << 2));
} }
static void __init early_out(struct uart_port *port, int offset, uint8_t value) static void early_out(struct uart_port *port, int offset, uint8_t value)
{ {
writel(value, port->membase + (offset << 2)); writel(value, port->membase + (offset << 2));
} }
static void __init ingenic_early_console_putc(struct uart_port *port, int c) static void ingenic_early_console_putc(struct uart_port *port, int c)
{ {
uint8_t lsr; uint8_t lsr;
@ -71,7 +71,7 @@ static void __init ingenic_early_console_putc(struct uart_port *port, int c)
early_out(port, UART_TX, c); early_out(port, UART_TX, c);
} }
static void __init ingenic_early_console_write(struct console *console, static void ingenic_early_console_write(struct console *console,
const char *s, unsigned int count) const char *s, unsigned int count)
{ {
uart_console_write(&early_device->port, s, count, uart_console_write(&early_device->port, s, count,

View file

@ -0,0 +1,118 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mcb.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <uapi/linux/serial_core.h>
struct serial_8250_men_mcb_data {
struct uart_8250_port uart;
int line;
};
/*
* The Z125 16550-compatible UART has no fixed base clock assigned
* So, depending on the board we're on, we need to adjust the
* parameter in order to really set the correct baudrate, and
* do so if possible without user interaction
*/
static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
{
/* use default value if board is not available below */
u32 clkval = 1041666;
dev_info(&mdev->dev, "%s on board %s\n",
dev_name(&mdev->dev),
mdev->bus->name);
if (strncmp(mdev->bus->name, "F075", 4) == 0)
clkval = 1041666;
else if (strncmp(mdev->bus->name, "F216", 4) == 0)
clkval = 1843200;
else if (strncmp(mdev->bus->name, "G215", 4) == 0)
clkval = 1843200;
else
dev_info(&mdev->dev,
"board not detected, using default uartclk\n");
clkval = clkval << 4;
return clkval;
}
static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
struct serial_8250_men_mcb_data *data;
struct resource *mem;
data = devm_kzalloc(&mdev->dev,
sizeof(struct serial_8250_men_mcb_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
mcb_set_drvdata(mdev, data);
data->uart.port.dev = mdev->dma_dev;
spin_lock_init(&data->uart.port.lock);
data->uart.port.type = PORT_16550;
data->uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
data->uart.port.iotype = UPIO_MEM;
data->uart.port.uartclk = men_z125_lookup_uartclk(mdev);
data->uart.port.regshift = 0;
data->uart.port.fifosize = 60;
mem = mcb_get_resource(mdev, IORESOURCE_MEM);
if (mem == NULL)
return -ENXIO;
data->uart.port.irq = mcb_get_irq(mdev);
data->uart.port.membase = devm_ioremap_resource(&mdev->dev, mem);
if (IS_ERR(data->uart.port.membase))
return PTR_ERR_OR_ZERO(data->uart.port.membase);
data->uart.port.mapbase = (unsigned long) mem->start;
data->uart.port.iobase = data->uart.port.mapbase;
/* ok, register the port */
data->line = serial8250_register_8250_port(&data->uart);
if (data->line < 0)
return data->line;
dev_info(&mdev->dev, "found 16Z125 UART: ttyS%d\n", data->line);
return 0;
}
static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
{
struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);
if (data)
serial8250_unregister_port(data->line);
}
static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
{ .device = 0x7d },
{ }
};
MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);
static struct mcb_driver mcb_driver = {
.driver = {
.name = "8250_men_mcb",
.owner = THIS_MODULE,
},
.probe = serial_8250_men_mcb_probe,
.remove = serial_8250_men_mcb_remove,
.id_table = serial_8250_men_mcb_ids,
};
module_mcb_driver(mcb_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z125 8250 UART driver");
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
MODULE_ALIAS("mcb:16z125");

View file

@ -171,10 +171,7 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
} }
data->bus_clk = devm_clk_get(&pdev->dev, "bus"); data->bus_clk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(data->bus_clk)) return PTR_ERR_OR_ZERO(data->bus_clk);
return PTR_ERR(data->bus_clk);
return 0;
} }
static int mtk8250_probe(struct platform_device *pdev) static int mtk8250_probe(struct platform_device *pdev)

View file

@ -18,6 +18,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/reset.h> #include <linux/reset.h>
@ -65,6 +66,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
int ret; int ret;
memset(port, 0, sizeof *port); memset(port, 0, sizeof *port);
pm_runtime_enable(&ofdev->dev);
pm_runtime_get_sync(&ofdev->dev);
if (of_property_read_u32(np, "clock-frequency", &clk)) { if (of_property_read_u32(np, "clock-frequency", &clk)) {
/* Get clk rate through clk driver if present */ /* Get clk rate through clk driver if present */
@ -72,12 +77,13 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (IS_ERR(info->clk)) { if (IS_ERR(info->clk)) {
dev_warn(&ofdev->dev, dev_warn(&ofdev->dev,
"clk or clock-frequency not defined\n"); "clk or clock-frequency not defined\n");
return PTR_ERR(info->clk); ret = PTR_ERR(info->clk);
goto err_pmruntime;
} }
ret = clk_prepare_enable(info->clk); ret = clk_prepare_enable(info->clk);
if (ret < 0) if (ret < 0)
return ret; goto err_pmruntime;
clk = clk_get_rate(info->clk); clk = clk_get_rate(info->clk);
} }
@ -88,7 +94,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
ret = of_address_to_resource(np, 0, &resource); ret = of_address_to_resource(np, 0, &resource);
if (ret) { if (ret) {
dev_warn(&ofdev->dev, "invalid address\n"); dev_warn(&ofdev->dev, "invalid address\n");
goto out; goto err_unprepare;
} }
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
@ -130,23 +136,23 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop); prop);
ret = -EINVAL; ret = -EINVAL;
goto out; goto err_dispose;
} }
} }
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) if (IS_ERR(info->rst))
goto out; goto err_dispose;
ret = reset_control_deassert(info->rst); ret = reset_control_deassert(info->rst);
if (ret) if (ret)
goto out; goto err_dispose;
port->type = type; port->type = type;
port->uartclk = clk; port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE; | UPF_FIXED_PORT | UPF_FIXED_TYPE;
if (of_find_property(np, "no-loopback-test", NULL)) if (of_property_read_bool(np, "no-loopback-test"))
port->flags |= UPF_SKIP_TEST; port->flags |= UPF_SKIP_TEST;
port->dev = &ofdev->dev; port->dev = &ofdev->dev;
@ -167,9 +173,13 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->handle_irq = fsl8250_handle_irq; port->handle_irq = fsl8250_handle_irq;
return 0; return 0;
out: err_dispose:
if (info->clk) irq_dispose_mapping(port->irq);
clk_disable_unprepare(info->clk); err_unprepare:
clk_disable_unprepare(info->clk);
err_pmruntime:
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
return ret; return ret;
} }
@ -190,7 +200,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (!match) if (!match)
return -EINVAL; return -EINVAL;
if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) if (of_property_read_bool(ofdev->dev.of_node, "used-by-rtas"))
return -EBUSY; return -EBUSY;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
@ -201,7 +211,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
memset(&port8250, 0, sizeof(port8250)); memset(&port8250, 0, sizeof(port8250));
ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info); ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
if (ret) if (ret)
goto out; goto err_free;
if (port8250.port.fifosize) if (port8250.port.fifosize)
port8250.capabilities = UART_CAP_FIFO; port8250.capabilities = UART_CAP_FIFO;
@ -217,15 +227,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
ret = serial8250_register_8250_port(&port8250); ret = serial8250_register_8250_port(&port8250);
if (ret < 0) if (ret < 0)
goto out; goto err_dispose;
info->type = port_type; info->type = port_type;
info->line = ret; info->line = ret;
platform_set_drvdata(ofdev, info); platform_set_drvdata(ofdev, info);
return 0; return 0;
out: err_dispose:
kfree(info);
irq_dispose_mapping(port8250.port.irq); irq_dispose_mapping(port8250.port.irq);
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
clk_disable_unprepare(info->clk);
err_free:
kfree(info);
return ret; return ret;
} }
@ -239,8 +253,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
serial8250_unregister_port(info->line); serial8250_unregister_port(info->line);
reset_control_assert(info->rst); reset_control_assert(info->rst);
if (info->clk) pm_runtime_put_sync(&ofdev->dev);
clk_disable_unprepare(info->clk); pm_runtime_disable(&ofdev->dev);
clk_disable_unprepare(info->clk);
kfree(info); kfree(info);
return 0; return 0;
} }
@ -254,9 +269,10 @@ static int of_serial_suspend(struct device *dev)
serial8250_suspend_port(info->line); serial8250_suspend_port(info->line);
if (info->clk && (!uart_console(port) || console_suspend_enabled)) if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
clk_disable_unprepare(info->clk); clk_disable_unprepare(info->clk);
}
return 0; return 0;
} }
@ -266,8 +282,10 @@ static int of_serial_resume(struct device *dev)
struct uart_8250_port *port8250 = serial8250_get_port(info->line); struct uart_8250_port *port8250 = serial8250_get_port(info->line);
struct uart_port *port = &port8250->port; struct uart_port *port = &port8250->port;
if (info->clk && (!uart_console(port) || console_suspend_enabled)) if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_get_sync(dev);
clk_prepare_enable(info->clk); clk_prepare_enable(info->clk);
}
serial8250_resume_port(info->line); serial8250_resume_port(info->line);
@ -295,6 +313,8 @@ static const struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_ALTR_16550_F64, }, .data = (void *)PORT_ALTR_16550_F64, },
{ .compatible = "altr,16550-FIFO128", { .compatible = "altr,16550-FIFO128",
.data = (void *)PORT_ALTR_16550_F128, }, .data = (void *)PORT_ALTR_16550_F128, },
{ .compatible = "mediatek,mtk-btif",
.data = (void *)PORT_MTK_BTIF, },
{ .compatible = "mrvl,mmp-uart", { .compatible = "mrvl,mmp-uart",
.data = (void *)PORT_XSCALE, }, .data = (void *)PORT_XSCALE, },
{ .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },

View file

@ -1548,7 +1548,7 @@ static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
struct uart_8250_port *port, int idx) struct uart_8250_port *port, int idx)
{ {
port->port.flags |= UPF_NO_TXEN_TEST; port->port.quirks |= UPQ_NO_TXEN_TEST;
dev_dbg(&priv->dev->dev, dev_dbg(&priv->dev->dev,
"serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n",
priv->dev->vendor, priv->dev->device, priv->dev->vendor, priv->dev->device,
@ -3384,17 +3384,8 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
}; };
/* static int serial_pci_is_class_communication(struct pci_dev *dev)
* Given a complete unknown PCI device, try to use some heuristics to
* guess what the configuration might be, based on the pitiful PCI
* serial specs. Returns 0 on success, 1 on failure.
*/
static int
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{ {
const struct pci_device_id *bldev;
int num_iomem, num_port, first_port = -1, i;
/* /*
* If it is not a communications device or the programming * If it is not a communications device or the programming
* interface is greater than 6, give up. * interface is greater than 6, give up.
@ -3407,6 +3398,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
(dev->class & 0xff) > 6) (dev->class & 0xff) > 6)
return -ENODEV; return -ENODEV;
return 0;
}
static int serial_pci_is_blacklisted(struct pci_dev *dev)
{
const struct pci_device_id *bldev;
/* /*
* Do not access blacklisted devices that are known not to * Do not access blacklisted devices that are known not to
* feature serial ports or are handled by other modules. * feature serial ports or are handled by other modules.
@ -3419,6 +3417,19 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
return -ENODEV; return -ENODEV;
} }
return 0;
}
/*
* Given a complete unknown PCI device, try to use some heuristics to
* guess what the configuration might be, based on the pitiful PCI
* serial specs. Returns 0 on success, -ENODEV on failure.
*/
static int
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
int num_iomem, num_port, first_port = -1, i;
num_iomem = num_port = 0; num_iomem = num_port = 0;
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
if (pci_resource_flags(dev, i) & IORESOURCE_IO) { if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
@ -3639,6 +3650,14 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data]; board = &pci_boards[ent->driver_data];
rc = serial_pci_is_class_communication(dev);
if (rc)
return rc;
rc = serial_pci_is_blacklisted(dev);
if (rc)
return rc;
rc = pcim_enable_device(dev); rc = pcim_enable_device(dev);
pci_save_state(dev); pci_save_state(dev);
if (rc) if (rc)
@ -3723,7 +3742,7 @@ static int pciserial_resume_one(struct device *dev)
static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one,
pciserial_resume_one); pciserial_resume_one);
static struct pci_device_id serial_pci_tbl[] = { static const struct pci_device_id serial_pci_tbl[] = {
/* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,

View file

@ -37,7 +37,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/timer.h> #include <linux/ktime.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
@ -289,6 +289,14 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 4, 8, 14}, .rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO | UART_CAP_AFE, .flags = UART_CAP_FIFO | UART_CAP_AFE,
}, },
[PORT_MTK_BTIF] = {
.name = "MediaTek BTIF",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
.flags = UART_CAP_FIFO,
},
}; };
/* Uart divisor latch read */ /* Uart divisor latch read */
@ -553,8 +561,8 @@ static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
serial8250_out_MCR(p, mcr); serial8250_out_MCR(p, mcr);
} }
static void serial8250_em485_handle_start_tx(unsigned long arg); static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static void serial8250_em485_handle_stop_tx(unsigned long arg); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{ {
@ -609,12 +617,14 @@ int serial8250_em485_init(struct uart_8250_port *p)
if (!p->em485) if (!p->em485)
return -ENOMEM; return -ENOMEM;
setup_timer(&p->em485->stop_tx_timer, hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
serial8250_em485_handle_stop_tx, (unsigned long)p); HRTIMER_MODE_REL);
setup_timer(&p->em485->start_tx_timer, hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
serial8250_em485_handle_start_tx, (unsigned long)p); HRTIMER_MODE_REL);
p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
p->em485->port = p;
p->em485->active_timer = NULL; p->em485->active_timer = NULL;
serial8250_em485_rts_after_send(p); serial8250_em485_rts_after_send(p);
return 0; return 0;
@ -639,8 +649,8 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
if (!p->em485) if (!p->em485)
return; return;
del_timer(&p->em485->start_tx_timer); hrtimer_cancel(&p->em485->start_tx_timer);
del_timer(&p->em485->stop_tx_timer); hrtimer_cancel(&p->em485->stop_tx_timer);
kfree(p->em485); kfree(p->em485);
p->em485 = NULL; p->em485 = NULL;
@ -1435,22 +1445,33 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
serial_port_out(&p->port, UART_IER, p->ier); serial_port_out(&p->port, UART_IER, p->ier);
} }
} }
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
static void serial8250_em485_handle_stop_tx(unsigned long arg)
{ {
struct uart_8250_port *p = (struct uart_8250_port *)arg; struct uart_8250_em485 *em485;
struct uart_8250_em485 *em485 = p->em485; struct uart_8250_port *p;
unsigned long flags; unsigned long flags;
em485 = container_of(t, struct uart_8250_em485, stop_tx_timer);
p = em485->port;
serial8250_rpm_get(p); serial8250_rpm_get(p);
spin_lock_irqsave(&p->port.lock, flags); spin_lock_irqsave(&p->port.lock, flags);
if (em485 && if (em485->active_timer == &em485->stop_tx_timer) {
em485->active_timer == &em485->stop_tx_timer) {
__do_stop_tx_rs485(p); __do_stop_tx_rs485(p);
em485->active_timer = NULL; em485->active_timer = NULL;
} }
spin_unlock_irqrestore(&p->port.lock, flags); spin_unlock_irqrestore(&p->port.lock, flags);
serial8250_rpm_put(p); serial8250_rpm_put(p);
return HRTIMER_NORESTART;
}
static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
{
long sec = msec / 1000;
long nsec = (msec % 1000) * 1000000;
ktime_t t = ktime_set(sec, nsec);
hrtimer_start(hrt, t, HRTIMER_MODE_REL);
} }
static void __stop_tx_rs485(struct uart_8250_port *p) static void __stop_tx_rs485(struct uart_8250_port *p)
@ -1463,8 +1484,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
*/ */
if (p->port.rs485.delay_rts_after_send > 0) { if (p->port.rs485.delay_rts_after_send > 0) {
em485->active_timer = &em485->stop_tx_timer; em485->active_timer = &em485->stop_tx_timer;
mod_timer(&em485->stop_tx_timer, jiffies + start_hrtimer_ms(&em485->stop_tx_timer,
p->port.rs485.delay_rts_after_send * HZ / 1000); p->port.rs485.delay_rts_after_send);
} else { } else {
__do_stop_tx_rs485(p); __do_stop_tx_rs485(p);
} }
@ -1494,8 +1515,8 @@ static inline void __stop_tx(struct uart_8250_port *p)
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
return; return;
del_timer(&em485->start_tx_timer);
em485->active_timer = NULL; em485->active_timer = NULL;
hrtimer_cancel(&em485->start_tx_timer);
__stop_tx_rs485(p); __stop_tx_rs485(p);
} }
@ -1558,8 +1579,9 @@ static inline void start_tx_rs485(struct uart_port *port)
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
serial8250_stop_rx(&up->port); serial8250_stop_rx(&up->port);
del_timer(&em485->stop_tx_timer);
em485->active_timer = NULL; em485->active_timer = NULL;
if (hrtimer_is_queued(&em485->stop_tx_timer))
hrtimer_cancel(&em485->stop_tx_timer);
mcr = serial8250_in_MCR(up); mcr = serial8250_in_MCR(up);
if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
@ -1572,8 +1594,8 @@ static inline void start_tx_rs485(struct uart_port *port)
if (up->port.rs485.delay_rts_before_send > 0) { if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer; em485->active_timer = &em485->start_tx_timer;
mod_timer(&em485->start_tx_timer, jiffies + start_hrtimer_ms(&em485->start_tx_timer,
up->port.rs485.delay_rts_before_send * HZ / 1000); up->port.rs485.delay_rts_before_send);
return; return;
} }
} }
@ -1581,19 +1603,22 @@ static inline void start_tx_rs485(struct uart_port *port)
__start_tx(port); __start_tx(port);
} }
static void serial8250_em485_handle_start_tx(unsigned long arg) static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t)
{ {
struct uart_8250_port *p = (struct uart_8250_port *)arg; struct uart_8250_em485 *em485;
struct uart_8250_em485 *em485 = p->em485; struct uart_8250_port *p;
unsigned long flags; unsigned long flags;
em485 = container_of(t, struct uart_8250_em485, start_tx_timer);
p = em485->port;
spin_lock_irqsave(&p->port.lock, flags); spin_lock_irqsave(&p->port.lock, flags);
if (em485 && if (em485->active_timer == &em485->start_tx_timer) {
em485->active_timer == &em485->start_tx_timer) {
__start_tx(&p->port); __start_tx(&p->port);
em485->active_timer = NULL; em485->active_timer = NULL;
} }
spin_unlock_irqrestore(&p->port.lock, flags); spin_unlock_irqrestore(&p->port.lock, flags);
return HRTIMER_NORESTART;
} }
static void serial8250_start_tx(struct uart_port *port) static void serial8250_start_tx(struct uart_port *port)
@ -2304,7 +2329,7 @@ int serial8250_do_startup(struct uart_port *port)
* test if we receive TX irq. This way, we'll never enable * test if we receive TX irq. This way, we'll never enable
* UART_BUG_TXEN. * UART_BUG_TXEN.
*/ */
if (up->port.flags & UPF_NO_TXEN_TEST) if (up->port.quirks & UPQ_NO_TXEN_TEST)
goto dont_test_tx_en; goto dont_test_tx_en;
/* /*

View file

@ -29,12 +29,13 @@
* - MMIO32 (regshift = 2) * - MMIO32 (regshift = 2)
* - FCR is not at 2, but 3 * - FCR is not at 2, but 3
* - LCR and MCR are not at 3 and 4, they share 4 * - LCR and MCR are not at 3 and 4, they share 4
* - No SCR (Instead, CHAR can be used as a scratch register)
* - Divisor latch at 9, no divisor latch access bit * - Divisor latch at 9, no divisor latch access bit
*/ */
#define UNIPHIER_UART_REGSHIFT 2 #define UNIPHIER_UART_REGSHIFT 2
/* bit[15:8] = CHAR (not used), bit[7:0] = FCR */ /* bit[15:8] = CHAR, bit[7:0] = FCR */
#define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) #define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT))
/* bit[15:8] = LCR, bit[7:0] = MCR */ /* bit[15:8] = LCR, bit[7:0] = MCR */
#define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) #define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT))
@ -72,13 +73,18 @@ OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart",
/* /*
* The register map is slightly different from that of 8250. * The register map is slightly different from that of 8250.
* IO callbacks must be overridden for correct access to FCR, LCR, and MCR. * IO callbacks must be overridden for correct access to FCR, LCR, MCR and SCR.
*/ */
static unsigned int uniphier_serial_in(struct uart_port *p, int offset) static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
{ {
unsigned int valshift = 0; unsigned int valshift = 0;
switch (offset) { switch (offset) {
case UART_SCR:
/* No SCR for this hardware. Use CHAR as a scratch register */
valshift = 8;
offset = UNIPHIER_UART_CHAR_FCR;
break;
case UART_LCR: case UART_LCR:
valshift = 8; valshift = 8;
/* fall through */ /* fall through */
@ -91,8 +97,8 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
} }
/* /*
* The return value must be masked with 0xff because LCR and MCR reside * The return value must be masked with 0xff because some registers
* in the same register that must be accessed by 32-bit write/read. * share the same offset that must be accessed by 32-bit write/read.
* 8 or 16 bit access to this hardware result in unexpected behavior. * 8 or 16 bit access to this hardware result in unexpected behavior.
*/ */
return (readl(p->membase + offset) >> valshift) & 0xff; return (readl(p->membase + offset) >> valshift) & 0xff;
@ -101,9 +107,13 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
static void uniphier_serial_out(struct uart_port *p, int offset, int value) static void uniphier_serial_out(struct uart_port *p, int offset, int value)
{ {
unsigned int valshift = 0; unsigned int valshift = 0;
bool normal = true; bool normal = false;
switch (offset) { switch (offset) {
case UART_SCR:
/* No SCR for this hardware. Use CHAR as a scratch register */
valshift = 8;
/* fall through */
case UART_FCR: case UART_FCR:
offset = UNIPHIER_UART_CHAR_FCR; offset = UNIPHIER_UART_CHAR_FCR;
break; break;
@ -114,10 +124,10 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
/* fall through */ /* fall through */
case UART_MCR: case UART_MCR:
offset = UNIPHIER_UART_LCR_MCR; offset = UNIPHIER_UART_LCR_MCR;
normal = false;
break; break;
default: default:
offset <<= UNIPHIER_UART_REGSHIFT; offset <<= UNIPHIER_UART_REGSHIFT;
normal = true;
break; break;
} }
@ -169,7 +179,7 @@ static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
dev_err(dev, "failed to get alias id\n"); dev_err(dev, "failed to get alias id\n");
return ret; return ret;
} }
port->line = priv->line = ret; port->line = ret;
/* Get clk rate through clk driver */ /* Get clk rate through clk driver */
priv->clk = devm_clk_get(dev, NULL); priv->clk = devm_clk_get(dev, NULL);
@ -249,8 +259,8 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.dl_read = uniphier_serial_dl_read; up.dl_read = uniphier_serial_dl_read;
up.dl_write = uniphier_serial_dl_write; up.dl_write = uniphier_serial_dl_write;
ret = serial8250_register_8250_port(&up); priv->line = serial8250_register_8250_port(&up);
if (ret < 0) { if (priv->line < 0) {
dev_err(dev, "failed to register 8250 port\n"); dev_err(dev, "failed to register 8250 port\n");
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
return ret; return ret;
@ -271,6 +281,40 @@ static int uniphier_uart_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused uniphier_uart_suspend(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
serial8250_suspend_port(priv->line);
if (!uart_console(&up->port) || console_suspend_enabled)
clk_disable_unprepare(priv->clk);
return 0;
}
static int __maybe_unused uniphier_uart_resume(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
int ret;
if (!uart_console(&up->port) || console_suspend_enabled) {
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
}
serial8250_resume_port(priv->line);
return 0;
}
static const struct dev_pm_ops uniphier_uart_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(uniphier_uart_suspend, uniphier_uart_resume)
};
static const struct of_device_id uniphier_uart_match[] = { static const struct of_device_id uniphier_uart_match[] = {
{ .compatible = "socionext,uniphier-uart" }, { .compatible = "socionext,uniphier-uart" },
{ /* sentinel */ } { /* sentinel */ }
@ -283,6 +327,7 @@ static struct platform_driver uniphier_uart_platform_driver = {
.driver = { .driver = {
.name = "uniphier-uart", .name = "uniphier-uart",
.of_match_table = uniphier_uart_match, .of_match_table = uniphier_uart_match,
.pm = &uniphier_uart_pm_ops,
}, },
}; };
module_platform_driver(uniphier_uart_platform_driver); module_platform_driver(uniphier_uart_platform_driver);

View file

@ -155,6 +155,17 @@ config SERIAL_8250_CS
If unsure, say N. If unsure, say N.
config SERIAL_8250_MEN_MCB
tristate "MEN Z125 UART device support"
depends on MCB && SERIAL_8250
help
This enables support for FPGA based UARTs found on many MEN
boards. This driver enables support for the Z125 UARTs.
To compile this driver as a module, chose M here: the
module will be called 8250_men_mcb.
config SERIAL_8250_NR_UARTS config SERIAL_8250_NR_UARTS
int "Maximum number of 8250/16550 serial ports" int "Maximum number of 8250/16550 serial ports"
depends on SERIAL_8250 depends on SERIAL_8250

View file

@ -23,6 +23,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o

View file

@ -1689,7 +1689,7 @@ config SERIAL_MVEBU_CONSOLE
Otherwise, say 'N'. Otherwise, say 'N'.
config SERIAL_OWL config SERIAL_OWL
bool "Actions Semi Owl serial port support" tristate "Actions Semi Owl serial port support"
depends on ARCH_ACTIONS || COMPILE_TEST depends on ARCH_ACTIONS || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
help help
@ -1705,7 +1705,7 @@ config SERIAL_OWL_CONSOLE
default y default y
help help
Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
as the system console. Only earlycon is implemented currently. as the system console.
endmenu endmenu

View file

@ -814,7 +814,7 @@ static int pl010_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume); static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume);
static struct amba_id pl010_ids[] = { static const struct amba_id pl010_ids[] = {
{ {
.id = 0x00041010, .id = 0x00041010,
.mask = 0x000fffff, .mask = 0x000fffff,

View file

@ -128,7 +128,7 @@ static struct vendor_data vendor_arm = {
.get_fifosize = get_fifosize_arm, .get_fifosize = get_fifosize_arm,
}; };
static struct vendor_data vendor_sbsa = { static const struct vendor_data vendor_sbsa = {
.reg_offset = pl011_std_offsets, .reg_offset = pl011_std_offsets,
.fr_busy = UART01x_FR_BUSY, .fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR, .fr_dsr = UART01x_FR_DSR,
@ -143,7 +143,7 @@ static struct vendor_data vendor_sbsa = {
}; };
#ifdef CONFIG_ACPI_SPCR_TABLE #ifdef CONFIG_ACPI_SPCR_TABLE
static struct vendor_data vendor_qdt_qdf2400_e44 = { static const struct vendor_data vendor_qdt_qdf2400_e44 = {
.reg_offset = pl011_std_offsets, .reg_offset = pl011_std_offsets,
.fr_busy = UART011_FR_TXFE, .fr_busy = UART011_FR_TXFE,
.fr_dsr = UART01x_FR_DSR, .fr_dsr = UART01x_FR_DSR,
@ -2787,7 +2787,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
}, },
}; };
static struct amba_id pl011_ids[] = { static const struct amba_id pl011_ids[] = {
{ {
.id = 0x00041011, .id = 0x00041011,
.mask = 0x000fffff, .mask = 0x000fffff,

View file

@ -325,7 +325,7 @@ static int apbuart_verify_port(struct uart_port *port,
return ret; return ret;
} }
static struct uart_ops grlib_apbuart_ops = { static const struct uart_ops grlib_apbuart_ops = {
.tx_empty = apbuart_tx_empty, .tx_empty = apbuart_tx_empty,
.set_mctrl = apbuart_set_mctrl, .set_mctrl = apbuart_set_mctrl,
.get_mctrl = apbuart_get_mctrl, .get_mctrl = apbuart_get_mctrl,

View file

@ -549,8 +549,8 @@ static struct console arc_console = {
.data = &arc_uart_driver .data = &arc_uart_driver
}; };
static __init void arc_early_serial_write(struct console *con, const char *s, static void arc_early_serial_write(struct console *con, const char *s,
unsigned int n) unsigned int n)
{ {
struct earlycon_device *dev = con->data; struct earlycon_device *dev = con->data;

View file

@ -1123,7 +1123,7 @@ static void cpm_put_poll_char(struct uart_port *port,
} }
#endif /* CONFIG_CONSOLE_POLL */ #endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops cpm_uart_pops = { static const struct uart_ops cpm_uart_pops = {
.tx_empty = cpm_uart_tx_empty, .tx_empty = cpm_uart_tx_empty,
.set_mctrl = cpm_uart_set_mctrl, .set_mctrl = cpm_uart_set_mctrl,
.get_mctrl = cpm_uart_get_mctrl, .get_mctrl = cpm_uart_get_mctrl,

View file

@ -220,7 +220,7 @@ static int __init param_setup_earlycon(char *buf)
if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
earlycon_init_is_deferred = true; earlycon_init_is_deferred = true;
return 0; return 0;
} else { } else if (!buf) {
return early_init_dt_scan_chosen_stdout(); return early_init_dt_scan_chosen_stdout();
} }
} }
@ -282,7 +282,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
} }
} }
val = of_get_flat_dt_prop(node, "current-speed", NULL);
if (val)
early_console_dev.baud = be32_to_cpu(*val);
if (options) { if (options) {
early_console_dev.baud = simple_strtoul(options, NULL, 0);
strlcpy(early_console_dev.options, options, strlcpy(early_console_dev.options, options,
sizeof(early_console_dev.options)); sizeof(early_console_dev.options));
} }

View file

@ -117,7 +117,7 @@
#define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01 #define UARTSFIFO_RXUF 0x01
/* 32-bit register defination */ /* 32-bit register definition */
#define UARTBAUD 0x00 #define UARTBAUD 0x00
#define UARTSTAT 0x04 #define UARTSTAT 0x04
#define UARTCTRL 0x08 #define UARTCTRL 0x08
@ -521,6 +521,57 @@ static int lpuart_poll_get_char(struct uart_port *port)
return readb(port->membase + UARTDR); return readb(port->membase + UARTDR);
} }
static int lpuart32_poll_init(struct uart_port *port)
{
unsigned long flags;
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
u32 temp;
sport->port.fifosize = 0;
spin_lock_irqsave(&sport->port.lock, flags);
/* Disable Rx & Tx */
writel(0, sport->port.membase + UARTCTRL);
temp = readl(sport->port.membase + UARTFIFO);
/* Enable Rx and Tx FIFO */
writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE,
sport->port.membase + UARTFIFO);
/* flush Tx and Rx FIFO */
writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH,
sport->port.membase + UARTFIFO);
/* explicitly clear RDRF */
if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) {
readl(sport->port.membase + UARTDATA);
writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO);
}
/* Enable Rx and Tx */
writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL);
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c)
{
while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE))
barrier();
writel(c, port->membase + UARTDATA);
}
static int lpuart32_poll_get_char(struct uart_port *port)
{
if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF))
return NO_POLL_CHAR;
return readl(port->membase + UARTDATA);
}
#endif #endif
static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
@ -1025,6 +1076,11 @@ static int lpuart_config_rs485(struct uart_port *port,
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
writeb(modem, sport->port.membase + UARTMODEM); writeb(modem, sport->port.membase + UARTMODEM);
/* clear unsupported configurations */
rs485->delay_rts_before_send = 0;
rs485->delay_rts_after_send = 0;
rs485->flags &= ~SER_RS485_RX_DURING_TX;
if (rs485->flags & SER_RS485_ENABLED) { if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */ /* Enable auto RS-485 RTS mode */
modem |= UARTMODEM_TXRTSE; modem |= UARTMODEM_TXRTSE;
@ -1782,6 +1838,11 @@ static const struct uart_ops lpuart32_pops = {
.config_port = lpuart_config_port, .config_port = lpuart_config_port,
.verify_port = lpuart_verify_port, .verify_port = lpuart_verify_port,
.flush_buffer = lpuart_flush_buffer, .flush_buffer = lpuart_flush_buffer,
#if defined(CONFIG_CONSOLE_POLL)
.poll_init = lpuart32_poll_init,
.poll_get_char = lpuart32_poll_get_char,
.poll_put_char = lpuart32_poll_put_char,
#endif
}; };
static struct lpuart_port *lpuart_ports[UART_NR]; static struct lpuart_port *lpuart_ports[UART_NR];
@ -2203,6 +2264,7 @@ static int lpuart_suspend(struct device *dev)
{ {
struct lpuart_port *sport = dev_get_drvdata(dev); struct lpuart_port *sport = dev_get_drvdata(dev);
unsigned long temp; unsigned long temp;
bool irq_wake;
if (lpuart_is_32(sport)) { if (lpuart_is_32(sport)) {
/* disable Rx/Tx and interrupts */ /* disable Rx/Tx and interrupts */
@ -2218,6 +2280,9 @@ static int lpuart_suspend(struct device *dev)
uart_suspend_port(&lpuart_reg, &sport->port); uart_suspend_port(&lpuart_reg, &sport->port);
/* uart_suspend_port() might set wakeup flag */
irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
if (sport->lpuart_dma_rx_use) { if (sport->lpuart_dma_rx_use) {
/* /*
* EDMA driver during suspend will forcefully release any * EDMA driver during suspend will forcefully release any
@ -2226,7 +2291,7 @@ static int lpuart_suspend(struct device *dev)
* cannot resume as as expected, hence gracefully release the * cannot resume as as expected, hence gracefully release the
* Rx DMA path before suspend and start Rx DMA path on resume. * Rx DMA path before suspend and start Rx DMA path on resume.
*/ */
if (sport->port.irq_wake) { if (irq_wake) {
del_timer_sync(&sport->lpuart_timer); del_timer_sync(&sport->lpuart_timer);
lpuart_dma_rx_free(&sport->port); lpuart_dma_rx_free(&sport->port);
} }
@ -2241,7 +2306,7 @@ static int lpuart_suspend(struct device *dev)
dmaengine_terminate_all(sport->dma_tx_chan); dmaengine_terminate_all(sport->dma_tx_chan);
} }
if (sport->port.suspended && !sport->port.irq_wake) if (sport->port.suspended && !irq_wake)
clk_disable_unprepare(sport->clk); clk_disable_unprepare(sport->clk);
return 0; return 0;
@ -2250,9 +2315,10 @@ static int lpuart_suspend(struct device *dev)
static int lpuart_resume(struct device *dev) static int lpuart_resume(struct device *dev)
{ {
struct lpuart_port *sport = dev_get_drvdata(dev); struct lpuart_port *sport = dev_get_drvdata(dev);
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
unsigned long temp; unsigned long temp;
if (sport->port.suspended && !sport->port.irq_wake) if (sport->port.suspended && !irq_wake)
clk_prepare_enable(sport->clk); clk_prepare_enable(sport->clk);
if (lpuart_is_32(sport)) { if (lpuart_is_32(sport)) {
@ -2269,7 +2335,7 @@ static int lpuart_resume(struct device *dev)
} }
if (sport->lpuart_dma_rx_use) { if (sport->lpuart_dma_rx_use) {
if (sport->port.irq_wake) { if (irq_wake) {
if (!lpuart_start_rx_dma(sport)) if (!lpuart_start_rx_dma(sport))
rx_dma_timer_init(sport); rx_dma_timer_init(sport);
else else

View file

@ -226,7 +226,6 @@ struct imx_port {
dma_cookie_t rx_cookie; dma_cookie_t rx_cookie;
unsigned int tx_bytes; unsigned int tx_bytes;
unsigned int dma_tx_nents; unsigned int dma_tx_nents;
wait_queue_head_t dma_wait;
unsigned int saved_reg[10]; unsigned int saved_reg[10];
bool context_saved; bool context_saved;
}; };
@ -458,7 +457,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
} }
} }
while (!uart_circ_empty(xmit) && !sport->dma_is_txing && if (sport->dma_is_txing)
return;
while (!uart_circ_empty(xmit) &&
!(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) { !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail] /* send xmit->buf[xmit->tail]
* out the port here */ * out the port here */
@ -498,20 +500,12 @@ static void dma_tx_callback(void *data)
sport->dma_is_txing = 0; sport->dma_is_txing = 0;
spin_unlock_irqrestore(&sport->port.lock, flags);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port); uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
return;
}
spin_lock_irqsave(&sport->port.lock, flags);
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
imx_dma_tx(sport); imx_dma_tx(sport);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock_irqrestore(&sport->port.lock, flags);
} }
@ -1208,8 +1202,6 @@ static void imx_enable_dma(struct imx_port *sport)
{ {
unsigned long temp; unsigned long temp;
init_waitqueue_head(&sport->dma_wait);
/* set UCR1 */ /* set UCR1 */
temp = readl(sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
@ -2332,6 +2324,7 @@ static int imx_serial_port_suspend(struct device *dev)
serial_imx_enable_wakeup(sport, true); serial_imx_enable_wakeup(sport, true);
uart_suspend_port(&imx_reg, &sport->port); uart_suspend_port(&imx_reg, &sport->port);
disable_irq(sport->port.irq);
/* Needed to enable clock in suspend_noirq */ /* Needed to enable clock in suspend_noirq */
return clk_prepare(sport->clk_ipg); return clk_prepare(sport->clk_ipg);
@ -2346,6 +2339,7 @@ static int imx_serial_port_resume(struct device *dev)
serial_imx_enable_wakeup(sport, false); serial_imx_enable_wakeup(sport, false);
uart_resume_port(&imx_reg, &sport->port); uart_resume_port(&imx_reg, &sport->port);
enable_irq(sport->port.irq);
clk_unprepare(sport->clk_ipg); clk_unprepare(sport->clk_ipg);

View file

@ -304,7 +304,7 @@ static void jsm_remove_one(struct pci_dev *pdev)
kfree(brd); kfree(brd);
} }
static struct pci_device_id jsm_pci_tbl[] = { static const struct pci_device_id jsm_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },

View file

@ -854,7 +854,7 @@ m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0; return 0;
} }
static struct uart_ops m32r_sio_pops = { static const struct uart_ops m32r_sio_pops = {
.tx_empty = m32r_sio_tx_empty, .tx_empty = m32r_sio_tx_empty,
.set_mctrl = m32r_sio_set_mctrl, .set_mctrl = m32r_sio_set_mctrl,
.get_mctrl = m32r_sio_get_mctrl, .get_mctrl = m32r_sio_get_mctrl,

View file

@ -424,7 +424,7 @@ static void meson_uart_config_port(struct uart_port *port, int flags)
} }
} }
static struct uart_ops meson_uart_ops = { static const struct uart_ops meson_uart_ops = {
.set_mctrl = meson_uart_set_mctrl, .set_mctrl = meson_uart_set_mctrl,
.get_mctrl = meson_uart_get_mctrl, .get_mctrl = meson_uart_get_mctrl,
.tx_empty = meson_uart_tx_empty, .tx_empty = meson_uart_tx_empty,

View file

@ -1347,7 +1347,7 @@ mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
} }
static struct uart_ops mpc52xx_uart_ops = { static const struct uart_ops mpc52xx_uart_ops = {
.tx_empty = mpc52xx_uart_tx_empty, .tx_empty = mpc52xx_uart_tx_empty,
.set_mctrl = mpc52xx_uart_set_mctrl, .set_mctrl = mpc52xx_uart_set_mctrl,
.get_mctrl = mpc52xx_uart_get_mctrl, .get_mctrl = mpc52xx_uart_get_mctrl,
@ -1634,8 +1634,8 @@ mpc52xx_console_setup(struct console *co, char *options)
return -EINVAL; return -EINVAL;
} }
pr_debug("Console on ttyPSC%x is %s\n", pr_debug("Console on ttyPSC%x is %pOF\n",
co->index, mpc52xx_uart_nodes[co->index]->full_name); co->index, mpc52xx_uart_nodes[co->index]);
/* Fetch register locations */ /* Fetch register locations */
ret = of_address_to_resource(np, 0, &res); ret = of_address_to_resource(np, 0, &res);
@ -1755,8 +1755,8 @@ static int mpc52xx_uart_of_probe(struct platform_device *op)
break; break;
if (idx >= MPC52xx_PSC_MAXNUM) if (idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL; return -EINVAL;
pr_debug("Found %s assigned to ttyPSC%x\n", pr_debug("Found %pOF assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[idx]->full_name, idx); mpc52xx_uart_nodes[idx], idx);
/* set the uart clock to the input clock of the psc, the different /* set the uart clock to the input clock of the psc, the different
* prescalers are taken into account in the set_baudrate() methods * prescalers are taken into account in the set_baudrate() methods
@ -1881,8 +1881,8 @@ mpc52xx_uart_of_enumerate(void)
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
if (mpc52xx_uart_nodes[i]) if (mpc52xx_uart_nodes[i])
pr_debug("%s assigned to ttyPSC%x\n", pr_debug("%pOF assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[i]->full_name, i); mpc52xx_uart_nodes[i], i);
} }
} }

View file

@ -1175,11 +1175,6 @@ static int msm_startup(struct uart_port *port)
snprintf(msm_port->name, sizeof(msm_port->name), snprintf(msm_port->name, sizeof(msm_port->name),
"msm_serial%d", port->line); "msm_serial%d", port->line);
ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
msm_port->name, port);
if (unlikely(ret))
return ret;
msm_init_clock(port); msm_init_clock(port);
if (likely(port->fifosize > 12)) if (likely(port->fifosize > 12))
@ -1206,7 +1201,21 @@ static int msm_startup(struct uart_port *port)
msm_request_rx_dma(msm_port, msm_port->uart.mapbase); msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
} }
ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
msm_port->name, port);
if (unlikely(ret))
goto err_irq;
return 0; return 0;
err_irq:
if (msm_port->is_uartdm)
msm_release_dma(msm_port);
clk_disable_unprepare(msm_port->pclk);
clk_disable_unprepare(msm_port->clk);
return ret;
} }
static void msm_shutdown(struct uart_port *port) static void msm_shutdown(struct uart_port *port)

View file

@ -427,7 +427,7 @@ static struct console mux_console = {
#define MUX_CONSOLE NULL #define MUX_CONSOLE NULL
#endif #endif
static struct uart_ops mux_pops = { static const struct uart_ops mux_pops = {
.tx_empty = mux_tx_empty, .tx_empty = mux_tx_empty,
.set_mctrl = mux_set_mctrl, .set_mctrl = mux_set_mctrl,
.get_mctrl = mux_get_mctrl, .get_mctrl = mux_get_mctrl,

View file

@ -1235,21 +1235,20 @@ static int serial_omap_poll_get_char(struct uart_port *port)
#ifdef CONFIG_SERIAL_OMAP_CONSOLE #ifdef CONFIG_SERIAL_OMAP_CONSOLE
#ifdef CONFIG_SERIAL_EARLYCON #ifdef CONFIG_SERIAL_EARLYCON
static unsigned int __init omap_serial_early_in(struct uart_port *port, static unsigned int omap_serial_early_in(struct uart_port *port, int offset)
int offset)
{ {
offset <<= port->regshift; offset <<= port->regshift;
return readw(port->membase + offset); return readw(port->membase + offset);
} }
static void __init omap_serial_early_out(struct uart_port *port, int offset, static void omap_serial_early_out(struct uart_port *port, int offset,
int value) int value)
{ {
offset <<= port->regshift; offset <<= port->regshift;
writew(value, port->membase + offset); writew(value, port->membase + offset);
} }
static void __init omap_serial_early_putc(struct uart_port *port, int c) static void omap_serial_early_putc(struct uart_port *port, int c)
{ {
unsigned int status; unsigned int status;
@ -1262,8 +1261,8 @@ static void __init omap_serial_early_putc(struct uart_port *port, int c)
omap_serial_early_out(port, UART_TX, c); omap_serial_early_out(port, UART_TX, c);
} }
static void __init early_omap_serial_write(struct console *console, static void early_omap_serial_write(struct console *console, const char *s,
const char *s, unsigned int count) unsigned int count)
{ {
struct earlycon_device *device = console->data; struct earlycon_device *device = console->data;
struct uart_port *port = &device->port; struct uart_port *port = &device->port;

View file

@ -20,6 +20,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/clk.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
@ -28,22 +29,66 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#define OWL_UART_PORT_NUM 7
#define OWL_UART_DEV_NAME "ttyOWL"
#define OWL_UART_CTL 0x000 #define OWL_UART_CTL 0x000
#define OWL_UART_RXDAT 0x004
#define OWL_UART_TXDAT 0x008 #define OWL_UART_TXDAT 0x008
#define OWL_UART_STAT 0x00c #define OWL_UART_STAT 0x00c
#define OWL_UART_CTL_DWLS_MASK GENMASK(1, 0)
#define OWL_UART_CTL_DWLS_5BITS (0x0 << 0)
#define OWL_UART_CTL_DWLS_6BITS (0x1 << 0)
#define OWL_UART_CTL_DWLS_7BITS (0x2 << 0)
#define OWL_UART_CTL_DWLS_8BITS (0x3 << 0)
#define OWL_UART_CTL_STPS_2BITS BIT(2)
#define OWL_UART_CTL_PRS_MASK GENMASK(6, 4)
#define OWL_UART_CTL_PRS_NONE (0x0 << 4)
#define OWL_UART_CTL_PRS_ODD (0x4 << 4)
#define OWL_UART_CTL_PRS_MARK (0x5 << 4)
#define OWL_UART_CTL_PRS_EVEN (0x6 << 4)
#define OWL_UART_CTL_PRS_SPACE (0x7 << 4)
#define OWL_UART_CTL_AFE BIT(12)
#define OWL_UART_CTL_TRFS_TX BIT(14) #define OWL_UART_CTL_TRFS_TX BIT(14)
#define OWL_UART_CTL_EN BIT(15) #define OWL_UART_CTL_EN BIT(15)
#define OWL_UART_CTL_RXDE BIT(16)
#define OWL_UART_CTL_TXDE BIT(17)
#define OWL_UART_CTL_RXIE BIT(18) #define OWL_UART_CTL_RXIE BIT(18)
#define OWL_UART_CTL_TXIE BIT(19) #define OWL_UART_CTL_TXIE BIT(19)
#define OWL_UART_CTL_LBEN BIT(20)
#define OWL_UART_STAT_RIP BIT(0) #define OWL_UART_STAT_RIP BIT(0)
#define OWL_UART_STAT_TIP BIT(1) #define OWL_UART_STAT_TIP BIT(1)
#define OWL_UART_STAT_RXER BIT(2)
#define OWL_UART_STAT_TFER BIT(3)
#define OWL_UART_STAT_RXST BIT(4)
#define OWL_UART_STAT_RFEM BIT(5)
#define OWL_UART_STAT_TFFU BIT(6) #define OWL_UART_STAT_TFFU BIT(6)
#define OWL_UART_STAT_TRFL_MASK (0x1f << 11) #define OWL_UART_STAT_CTSS BIT(7)
#define OWL_UART_STAT_RTSS BIT(8)
#define OWL_UART_STAT_TFES BIT(10)
#define OWL_UART_STAT_TRFL_MASK GENMASK(16, 11)
#define OWL_UART_STAT_UTBB BIT(17) #define OWL_UART_STAT_UTBB BIT(17)
static struct uart_driver owl_uart_driver;
struct owl_uart_info {
unsigned int tx_fifosize;
};
struct owl_uart_port {
struct uart_port port;
struct clk *clk;
};
#define to_owl_uart_port(prt) container_of(prt, struct owl_uart_port, prt)
static struct owl_uart_port *owl_uart_ports[OWL_UART_PORT_NUM];
static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off) static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
{ {
writel(val, port->membase + off); writel(val, port->membase + off);
@ -54,6 +99,397 @@ static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
return readl(port->membase + off); return readl(port->membase + off);
} }
static void owl_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
u32 ctl;
ctl = owl_uart_read(port, OWL_UART_CTL);
if (mctrl & TIOCM_LOOP)
ctl |= OWL_UART_CTL_LBEN;
else
ctl &= ~OWL_UART_CTL_LBEN;
owl_uart_write(port, ctl, OWL_UART_CTL);
}
static unsigned int owl_uart_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = TIOCM_CAR | TIOCM_DSR;
u32 stat, ctl;
ctl = owl_uart_read(port, OWL_UART_CTL);
stat = owl_uart_read(port, OWL_UART_STAT);
if (stat & OWL_UART_STAT_RTSS)
mctrl |= TIOCM_RTS;
if ((stat & OWL_UART_STAT_CTSS) || !(ctl & OWL_UART_CTL_AFE))
mctrl |= TIOCM_CTS;
return mctrl;
}
static unsigned int owl_uart_tx_empty(struct uart_port *port)
{
unsigned long flags;
u32 val;
unsigned int ret;
spin_lock_irqsave(&port->lock, flags);
val = owl_uart_read(port, OWL_UART_STAT);
ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&port->lock, flags);
return ret;
}
static void owl_uart_stop_rx(struct uart_port *port)
{
u32 val;
val = owl_uart_read(port, OWL_UART_CTL);
val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_RXDE);
owl_uart_write(port, val, OWL_UART_CTL);
val = owl_uart_read(port, OWL_UART_STAT);
val |= OWL_UART_STAT_RIP;
owl_uart_write(port, val, OWL_UART_STAT);
}
static void owl_uart_stop_tx(struct uart_port *port)
{
u32 val;
val = owl_uart_read(port, OWL_UART_CTL);
val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_TXDE);
owl_uart_write(port, val, OWL_UART_CTL);
val = owl_uart_read(port, OWL_UART_STAT);
val |= OWL_UART_STAT_TIP;
owl_uart_write(port, val, OWL_UART_STAT);
}
static void owl_uart_start_tx(struct uart_port *port)
{
u32 val;
if (uart_tx_stopped(port)) {
owl_uart_stop_tx(port);
return;
}
val = owl_uart_read(port, OWL_UART_STAT);
val |= OWL_UART_STAT_TIP;
owl_uart_write(port, val, OWL_UART_STAT);
val = owl_uart_read(port, OWL_UART_CTL);
val |= OWL_UART_CTL_TXIE;
owl_uart_write(port, val, OWL_UART_CTL);
}
static void owl_uart_send_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned int ch;
if (uart_tx_stopped(port))
return;
if (port->x_char) {
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU))
cpu_relax();
owl_uart_write(port, port->x_char, OWL_UART_TXDAT);
port->icount.tx++;
port->x_char = 0;
}
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) {
if (uart_circ_empty(xmit))
break;
ch = xmit->buf[xmit->tail];
owl_uart_write(port, ch, OWL_UART_TXDAT);
xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
owl_uart_stop_tx(port);
}
static void owl_uart_receive_chars(struct uart_port *port)
{
u32 stat, val;
val = owl_uart_read(port, OWL_UART_CTL);
val &= ~OWL_UART_CTL_TRFS_TX;
owl_uart_write(port, val, OWL_UART_CTL);
stat = owl_uart_read(port, OWL_UART_STAT);
while (!(stat & OWL_UART_STAT_RFEM)) {
char flag = TTY_NORMAL;
if (stat & OWL_UART_STAT_RXER)
port->icount.overrun++;
if (stat & OWL_UART_STAT_RXST) {
/* We are not able to distinguish the error type. */
port->icount.brk++;
port->icount.frame++;
stat &= port->read_status_mask;
if (stat & OWL_UART_STAT_RXST)
flag = TTY_PARITY;
} else
port->icount.rx++;
val = owl_uart_read(port, OWL_UART_RXDAT);
val &= 0xff;
if ((stat & port->ignore_status_mask) == 0)
tty_insert_flip_char(&port->state->port, val, flag);
stat = owl_uart_read(port, OWL_UART_STAT);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
spin_lock(&port->lock);
}
static irqreturn_t owl_uart_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned long flags;
u32 stat;
spin_lock_irqsave(&port->lock, flags);
stat = owl_uart_read(port, OWL_UART_STAT);
if (stat & OWL_UART_STAT_RIP)
owl_uart_receive_chars(port);
if (stat & OWL_UART_STAT_TIP)
owl_uart_send_chars(port);
stat = owl_uart_read(port, OWL_UART_STAT);
stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP;
owl_uart_write(port, stat, OWL_UART_STAT);
spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
static void owl_uart_shutdown(struct uart_port *port)
{
u32 val;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
val = owl_uart_read(port, OWL_UART_CTL);
val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE
| OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN);
owl_uart_write(port, val, OWL_UART_CTL);
spin_unlock_irqrestore(&port->lock, flags);
free_irq(port->irq, port);
}
static int owl_uart_startup(struct uart_port *port)
{
u32 val;
unsigned long flags;
int ret;
ret = request_irq(port->irq, owl_uart_irq, IRQF_TRIGGER_HIGH,
"owl-uart", port);
if (ret)
return ret;
spin_lock_irqsave(&port->lock, flags);
val = owl_uart_read(port, OWL_UART_STAT);
val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP
| OWL_UART_STAT_RXER | OWL_UART_STAT_TFER | OWL_UART_STAT_RXST;
owl_uart_write(port, val, OWL_UART_STAT);
val = owl_uart_read(port, OWL_UART_CTL);
val |= OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE;
val |= OWL_UART_CTL_EN;
owl_uart_write(port, val, OWL_UART_CTL);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void owl_uart_change_baudrate(struct owl_uart_port *owl_port,
unsigned long baud)
{
clk_set_rate(owl_port->clk, baud * 8);
}
static void owl_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
struct owl_uart_port *owl_port = to_owl_uart_port(port);
unsigned int baud;
u32 ctl;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
ctl = owl_uart_read(port, OWL_UART_CTL);
ctl &= ~OWL_UART_CTL_DWLS_MASK;
switch (termios->c_cflag & CSIZE) {
case CS5:
ctl |= OWL_UART_CTL_DWLS_5BITS;
break;
case CS6:
ctl |= OWL_UART_CTL_DWLS_6BITS;
break;
case CS7:
ctl |= OWL_UART_CTL_DWLS_7BITS;
break;
case CS8:
default:
ctl |= OWL_UART_CTL_DWLS_8BITS;
break;
}
if (termios->c_cflag & CSTOPB)
ctl |= OWL_UART_CTL_STPS_2BITS;
else
ctl &= ~OWL_UART_CTL_STPS_2BITS;
ctl &= ~OWL_UART_CTL_PRS_MASK;
if (termios->c_cflag & PARENB) {
if (termios->c_cflag & CMSPAR) {
if (termios->c_cflag & PARODD)
ctl |= OWL_UART_CTL_PRS_MARK;
else
ctl |= OWL_UART_CTL_PRS_SPACE;
} else if (termios->c_cflag & PARODD)
ctl |= OWL_UART_CTL_PRS_ODD;
else
ctl |= OWL_UART_CTL_PRS_EVEN;
} else
ctl |= OWL_UART_CTL_PRS_NONE;
if (termios->c_cflag & CRTSCTS)
ctl |= OWL_UART_CTL_AFE;
else
ctl &= ~OWL_UART_CTL_AFE;
owl_uart_write(port, ctl, OWL_UART_CTL);
baud = uart_get_baud_rate(port, termios, old, 9600, 3200000);
owl_uart_change_baudrate(owl_port, baud);
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
port->read_status_mask |= OWL_UART_STAT_RXER;
if (termios->c_iflag & INPCK)
port->read_status_mask |= OWL_UART_STAT_RXST;
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock_irqrestore(&port->lock, flags);
}
static void owl_uart_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return;
if (port->flags & UPF_IOREMAP) {
devm_release_mem_region(port->dev, port->mapbase,
resource_size(res));
devm_iounmap(port->dev, port->membase);
port->membase = NULL;
}
}
static int owl_uart_request_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
if (!devm_request_mem_region(port->dev, port->mapbase,
resource_size(res), dev_name(port->dev)))
return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = devm_ioremap_nocache(port->dev, port->mapbase,
resource_size(res));
if (!port->membase)
return -EBUSY;
}
return 0;
}
static const char *owl_uart_type(struct uart_port *port)
{
return (port->type == PORT_OWL) ? "owl-uart" : NULL;
}
static int owl_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (port->type != PORT_OWL)
return -EINVAL;
if (port->irq != ser->irq)
return -EINVAL;
return 0;
}
static void owl_uart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_OWL;
owl_uart_request_port(port);
}
}
static const struct uart_ops owl_uart_ops = {
.set_mctrl = owl_uart_set_mctrl,
.get_mctrl = owl_uart_get_mctrl,
.tx_empty = owl_uart_tx_empty,
.start_tx = owl_uart_start_tx,
.stop_rx = owl_uart_stop_rx,
.stop_tx = owl_uart_stop_tx,
.startup = owl_uart_startup,
.shutdown = owl_uart_shutdown,
.set_termios = owl_uart_set_termios,
.type = owl_uart_type,
.config_port = owl_uart_config_port,
.request_port = owl_uart_request_port,
.release_port = owl_uart_release_port,
.verify_port = owl_uart_verify_port,
};
#ifdef CONFIG_SERIAL_OWL_CONSOLE #ifdef CONFIG_SERIAL_OWL_CONSOLE
static void owl_console_putchar(struct uart_port *port, int ch) static void owl_console_putchar(struct uart_port *port, int ch)
@ -110,6 +546,57 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
local_irq_restore(flags); local_irq_restore(flags);
} }
static void owl_uart_console_write(struct console *co, const char *s,
u_int count)
{
struct owl_uart_port *owl_port;
owl_port = owl_uart_ports[co->index];
if (!owl_port)
return;
owl_uart_port_write(&owl_port->port, s, count);
}
static int owl_uart_console_setup(struct console *co, char *options)
{
struct owl_uart_port *owl_port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= OWL_UART_PORT_NUM)
return -EINVAL;
owl_port = owl_uart_ports[co->index];
if (!owl_port || !owl_port->port.membase)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(&owl_port->port, co, baud, parity, bits, flow);
}
static struct console owl_uart_console = {
.name = OWL_UART_DEV_NAME,
.write = owl_uart_console_write,
.device = uart_console_device,
.setup = owl_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &owl_uart_driver,
};
static int __init owl_uart_console_init(void)
{
register_console(&owl_uart_console);
return 0;
}
console_initcall(owl_uart_console_init);
static void owl_uart_early_console_write(struct console *co, static void owl_uart_early_console_write(struct console *co,
const char *s, const char *s,
u_int count) u_int count)
@ -132,4 +619,148 @@ owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
OF_EARLYCON_DECLARE(owl, "actions,owl-uart", OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
owl_uart_early_console_setup); owl_uart_early_console_setup);
#endif /* CONFIG_SERIAL_OWL_CONSOLE */ #define OWL_UART_CONSOLE (&owl_uart_console)
#else
#define OWL_UART_CONSOLE NULL
#endif
static struct uart_driver owl_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "owl-uart",
.dev_name = OWL_UART_DEV_NAME,
.nr = OWL_UART_PORT_NUM,
.cons = OWL_UART_CONSOLE,
};
static const struct owl_uart_info owl_s500_info = {
.tx_fifosize = 16,
};
static const struct owl_uart_info owl_s900_info = {
.tx_fifosize = 32,
};
static const struct of_device_id owl_uart_dt_matches[] = {
{ .compatible = "actions,s500-uart", .data = &owl_s500_info },
{ .compatible = "actions,s900-uart", .data = &owl_s900_info },
{ }
};
MODULE_DEVICE_TABLE(of, owl_uart_dt_matches);
static int owl_uart_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct owl_uart_info *info = NULL;
struct resource *res_mem;
struct owl_uart_port *owl_port;
int ret, irq;
if (pdev->dev.of_node) {
pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
match = of_match_node(owl_uart_dt_matches, pdev->dev.of_node);
if (match)
info = match->data;
}
if (pdev->id < 0 || pdev->id >= OWL_UART_PORT_NUM) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
return -EINVAL;
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_mem) {
dev_err(&pdev->dev, "could not get mem\n");
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "could not get irq\n");
return irq;
}
if (owl_uart_ports[pdev->id]) {
dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
return -EBUSY;
}
owl_port = devm_kzalloc(&pdev->dev, sizeof(*owl_port), GFP_KERNEL);
if (!owl_port)
return -ENOMEM;
owl_port->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(owl_port->clk)) {
dev_err(&pdev->dev, "could not get clk\n");
return PTR_ERR(owl_port->clk);
}
owl_port->port.dev = &pdev->dev;
owl_port->port.line = pdev->id;
owl_port->port.type = PORT_OWL;
owl_port->port.iotype = UPIO_MEM;
owl_port->port.mapbase = res_mem->start;
owl_port->port.irq = irq;
owl_port->port.uartclk = clk_get_rate(owl_port->clk);
if (owl_port->port.uartclk == 0) {
dev_err(&pdev->dev, "clock rate is zero\n");
return -EINVAL;
}
owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
owl_port->port.x_char = 0;
owl_port->port.fifosize = (info) ? info->tx_fifosize : 16;
owl_port->port.ops = &owl_uart_ops;
owl_uart_ports[pdev->id] = owl_port;
platform_set_drvdata(pdev, owl_port);
ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
if (ret)
owl_uart_ports[pdev->id] = NULL;
return ret;
}
static int owl_uart_remove(struct platform_device *pdev)
{
struct owl_uart_port *owl_port = platform_get_drvdata(pdev);
uart_remove_one_port(&owl_uart_driver, &owl_port->port);
owl_uart_ports[pdev->id] = NULL;
return 0;
}
static struct platform_driver owl_uart_platform_driver = {
.probe = owl_uart_probe,
.remove = owl_uart_remove,
.driver = {
.name = "owl-uart",
.of_match_table = owl_uart_dt_matches,
},
};
static int __init owl_uart_init(void)
{
int ret;
ret = uart_register_driver(&owl_uart_driver);
if (ret)
return ret;
ret = platform_driver_register(&owl_uart_platform_driver);
if (ret)
uart_unregister_driver(&owl_uart_driver);
return ret;
}
static void __init owl_uart_exit(void)
{
platform_driver_unregister(&owl_uart_platform_driver);
uart_unregister_driver(&owl_uart_driver);
}
module_init(owl_uart_init);
module_exit(owl_uart_exit);
MODULE_LICENSE("GPL");

View file

@ -46,11 +46,6 @@ enum {
PCH_UART_HANDLED_LS_INT_SHIFT, PCH_UART_HANDLED_LS_INT_SHIFT,
}; };
enum {
PCH_UART_8LINE,
PCH_UART_2LINE,
};
#define PCH_UART_DRIVER_DEVICE "ttyPCH" #define PCH_UART_DRIVER_DEVICE "ttyPCH"
/* Set the max number of UART port /* Set the max number of UART port
@ -267,7 +262,7 @@ struct eg20t_port {
/** /**
* struct pch_uart_driver_data - private data structure for UART-DMA * struct pch_uart_driver_data - private data structure for UART-DMA
* @port_type: The number of DMA channel * @port_type: The type of UART port
* @line_no: UART port line number (0, 1, 2...) * @line_no: UART port line number (0, 1, 2...)
*/ */
struct pch_uart_driver_data { struct pch_uart_driver_data {
@ -290,17 +285,17 @@ enum pch_uart_num_t {
}; };
static struct pch_uart_driver_data drv_dat[] = { static struct pch_uart_driver_data drv_dat[] = {
[pch_et20t_uart0] = {PCH_UART_8LINE, 0}, [pch_et20t_uart0] = {PORT_PCH_8LINE, 0},
[pch_et20t_uart1] = {PCH_UART_2LINE, 1}, [pch_et20t_uart1] = {PORT_PCH_2LINE, 1},
[pch_et20t_uart2] = {PCH_UART_2LINE, 2}, [pch_et20t_uart2] = {PORT_PCH_2LINE, 2},
[pch_et20t_uart3] = {PCH_UART_2LINE, 3}, [pch_et20t_uart3] = {PORT_PCH_2LINE, 3},
[pch_ml7213_uart0] = {PCH_UART_8LINE, 0}, [pch_ml7213_uart0] = {PORT_PCH_8LINE, 0},
[pch_ml7213_uart1] = {PCH_UART_2LINE, 1}, [pch_ml7213_uart1] = {PORT_PCH_2LINE, 1},
[pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, [pch_ml7213_uart2] = {PORT_PCH_2LINE, 2},
[pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, [pch_ml7223_uart0] = {PORT_PCH_8LINE, 0},
[pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, [pch_ml7223_uart1] = {PORT_PCH_2LINE, 1},
[pch_ml7831_uart0] = {PCH_UART_8LINE, 0}, [pch_ml7831_uart0] = {PORT_PCH_8LINE, 0},
[pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, [pch_ml7831_uart1] = {PORT_PCH_2LINE, 1},
}; };
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
@ -1777,10 +1772,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
goto init_port_free_txbuf; goto init_port_free_txbuf;
switch (port_type) { switch (port_type) {
case PORT_UNKNOWN: case PORT_PCH_8LINE:
fifosize = 256; /* EG20T/ML7213: UART0 */ fifosize = 256; /* EG20T/ML7213: UART0 */
break; break;
case PORT_8250: case PORT_PCH_2LINE:
fifosize = 64; /* EG20T:UART1~3 ML7213: UART1~2*/ fifosize = 64; /* EG20T:UART1~3 ML7213: UART1~2*/
break; break;
default: default:
@ -1804,7 +1799,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->fifo_size = fifosize; priv->fifo_size = fifosize;
priv->uartclk = pch_uart_get_uartclk(); priv->uartclk = pch_uart_get_uartclk();
priv->port_type = PORT_MAX_8250 + port_type + 1; priv->port_type = port_type;
priv->port.dev = &pdev->dev; priv->port.dev = &pdev->dev;
priv->port.iobase = iobase; priv->port.iobase = iobase;
priv->port.membase = NULL; priv->port.membase = NULL;
@ -1862,8 +1857,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
{ {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
if (priv->debugfs) debugfs_remove(priv->debugfs);
debugfs_remove(priv->debugfs);
#endif #endif
uart_remove_one_port(&pch_uart_driver, &priv->port); uart_remove_one_port(&pch_uart_driver, &priv->port);
free_page((unsigned long)priv->rxbuf.buf); free_page((unsigned long)priv->rxbuf.buf);

View file

@ -1671,8 +1671,8 @@ static int __init pmz_probe(void)
if (!node_a && !node_b) { if (!node_a && !node_b) {
of_node_put(node_a); of_node_put(node_a);
of_node_put(node_b); of_node_put(node_b);
printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n", printk(KERN_ERR "pmac_zilog: missing node %c for escc %pOF\n",
(!node_a) ? 'a' : 'b', node_p->full_name); (!node_a) ? 'a' : 'b', node_p);
continue; continue;
} }

View file

@ -1310,7 +1310,7 @@ static int tegra_uart_probe(struct platform_device *pdev)
return PTR_ERR(tup->uart_clk); return PTR_ERR(tup->uart_clk);
} }
tup->rst = devm_reset_control_get(&pdev->dev, "serial"); tup->rst = devm_reset_control_get_exclusive(&pdev->dev, "serial");
if (IS_ERR(tup->rst)) { if (IS_ERR(tup->rst)) {
dev_err(&pdev->dev, "Couldn't get the reset\n"); dev_err(&pdev->dev, "Couldn't get the reset\n");
return PTR_ERR(tup->rst); return PTR_ERR(tup->rst);

View file

@ -36,7 +36,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/irq.h> #include <linux/irq.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
/* /*
@ -165,6 +165,27 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) #define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear)
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
{
int rs485_on = uport->rs485_config &&
(uport->rs485.flags & SER_RS485_ENABLED);
int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
if (raise) {
if (rs485_on && !RTS_after_send) {
uart_set_mctrl(uport, TIOCM_DTR);
uart_clear_mctrl(uport, TIOCM_RTS);
} else {
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
} else {
unsigned int clear = TIOCM_DTR;
clear |= (!rs485_on || !RTS_after_send) ? TIOCM_RTS : 0;
uart_clear_mctrl(uport, clear);
}
}
/* /*
* Startup the port. This will be called once per open. All calls * Startup the port. This will be called once per open. All calls
* will be serialised by the per-port mutex. * will be serialised by the per-port mutex.
@ -214,7 +235,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* port is open and ready to respond. * port is open and ready to respond.
*/ */
if (init_hw && C_BAUD(tty)) if (init_hw && C_BAUD(tty))
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); uart_port_dtr_rts(uport, 1);
} }
/* /*
@ -272,7 +293,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
uport->cons->cflag = tty->termios.c_cflag; uport->cons->cflag = tty->termios.c_cflag;
if (!tty || C_HUPCL(tty)) if (!tty || C_HUPCL(tty))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_port_dtr_rts(uport, 0);
uart_port_shutdown(port); uart_port_shutdown(port);
} }
@ -744,7 +765,7 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
if (HIGH_BITS_OFFSET) if (HIGH_BITS_OFFSET)
retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
retinfo->irq = uport->irq; retinfo->irq = uport->irq;
retinfo->flags = uport->flags; retinfo->flags = (__force int)uport->flags;
retinfo->xmit_fifo_size = uport->fifosize; retinfo->xmit_fifo_size = uport->fifosize;
retinfo->baud_base = uport->uartclk / 16; retinfo->baud_base = uport->uartclk / 16;
retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10; retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10;
@ -818,7 +839,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
new_info->type != uport->type); new_info->type != uport->type);
old_flags = uport->flags; old_flags = uport->flags;
new_flags = new_info->flags; new_flags = (__force upf_t)new_info->flags;
old_custom_divisor = uport->custom_divisor; old_custom_divisor = uport->custom_divisor;
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
@ -1658,7 +1679,7 @@ static int uart_carrier_raised(struct tty_port *port)
return 0; return 0;
} }
static void uart_dtr_rts(struct tty_port *port, int onoff) static void uart_dtr_rts(struct tty_port *port, int raise)
{ {
struct uart_state *state = container_of(port, struct uart_state, port); struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport; struct uart_port *uport;
@ -1666,12 +1687,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
uport = uart_port_ref(state); uport = uart_port_ref(state);
if (!uport) if (!uport)
return; return;
uart_port_dtr_rts(uport, raise);
if (onoff)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_deref(uport); uart_port_deref(uport);
} }
@ -2083,8 +2099,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
tty_dev = device_find_child(uport->dev, &match, serial_match_port); tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (tty_dev && device_may_wakeup(tty_dev)) { if (tty_dev && device_may_wakeup(tty_dev)) {
if (!enable_irq_wake(uport->irq)) enable_irq_wake(uport->irq);
uport->irq_wake = 1;
put_device(tty_dev); put_device(tty_dev);
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
return 0; return 0;
@ -2147,10 +2162,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
tty_dev = device_find_child(uport->dev, &match, serial_match_port); tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) { if (!uport->suspended && device_may_wakeup(tty_dev)) {
if (uport->irq_wake) { if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq))))
disable_irq_wake(uport->irq); disable_irq_wake(uport->irq);
uport->irq_wake = 0;
}
put_device(tty_dev); put_device(tty_dev);
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
return 0; return 0;

View file

@ -3073,8 +3073,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
p->type = SCI_OF_TYPE(match->data); p->type = SCI_OF_TYPE(match->data);
p->regtype = SCI_OF_REGTYPE(match->data); p->regtype = SCI_OF_REGTYPE(match->data);
if (of_find_property(np, "uart-has-rtscts", NULL)) sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
sp->has_rtscts = true;
return p; return p;
} }

View file

@ -63,6 +63,7 @@
/* interrupt clear register */ /* interrupt clear register */
#define SPRD_ICLR 0x0014 #define SPRD_ICLR 0x0014
#define SPRD_ICLR_TIMEOUT BIT(13)
/* line control register */ /* line control register */
#define SPRD_LCR 0x0018 #define SPRD_LCR 0x0018
@ -298,7 +299,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
} }
serial_out(port, SPRD_ICLR, ~0); if (ims & SPRD_IMSR_TIMEOUT)
serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
if (ims & (SPRD_IMSR_RX_FIFO_FULL | if (ims & (SPRD_IMSR_RX_FIFO_FULL |
SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT)) SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
@ -729,8 +731,8 @@ static int sprd_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "not provide irq resource\n"); dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
return -ENODEV; return irq;
} }
up->irq = irq; up->irq = irq;

View file

@ -310,7 +310,7 @@ static void asc_receive_chars(struct uart_port *port)
if (mode == ASC_CTL_MODE_8BIT || mode == ASC_CTL_MODE_8BIT_PAR) if (mode == ASC_CTL_MODE_8BIT || mode == ASC_CTL_MODE_8BIT_PAR)
ignore_pe = true; ignore_pe = true;
if (port->irq_wake) if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0); pm_wakeup_event(tport->tty->dev, 0);
while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) { while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) {

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (C) Maxime Coquelin 2015 * Copyright (C) Maxime Coquelin 2015
* Copyright (C) STMicroelectronics SA 2017
* Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com> * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* Gerald Baeza <gerald.baeza@st.com> * Gerald Baeza <gerald.baeza@st.com>
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
@ -25,6 +26,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -110,14 +112,13 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
unsigned long c; unsigned long c;
u32 sr; u32 sr;
char flag; char flag;
static int last_res = RX_BUF_L;
if (port->irq_wake) if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0); pm_wakeup_event(tport->tty->dev, 0);
while (stm32_pending_rx(port, &sr, &last_res, threaded)) { while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
sr |= USART_SR_DUMMY_RX; sr |= USART_SR_DUMMY_RX;
c = stm32_get_char(port, &sr, &last_res); c = stm32_get_char(port, &sr, &stm32_port->last_res);
flag = TTY_NORMAL; flag = TTY_NORMAL;
port->icount.rx++; port->icount.rx++;
@ -202,7 +203,7 @@ static void stm32_transmit_chars_pio(struct uart_port *port)
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
isr, isr,
(isr & USART_SR_TXE), (isr & USART_SR_TXE),
10, 100); 10, 100000);
if (ret) if (ret)
dev_err(port->dev, "tx empty not set\n"); dev_err(port->dev, "tx empty not set\n");
@ -326,6 +327,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
sr = readl_relaxed(port->membase + ofs->isr); sr = readl_relaxed(port->membase + ofs->isr);
if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
writel_relaxed(USART_ICR_WUCF,
port->membase + ofs->icr);
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_receive_chars(port, false); stm32_receive_chars(port, false);
@ -442,6 +447,7 @@ static int stm32_startup(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
const char *name = to_platform_device(port->dev)->name; const char *name = to_platform_device(port->dev)->name;
u32 val; u32 val;
int ret; int ret;
@ -452,7 +458,18 @@ static int stm32_startup(struct uart_port *port)
if (ret) if (ret)
return ret; return ret;
if (cfg->has_wakeup && stm32_port->wakeirq >= 0) {
ret = dev_pm_set_dedicated_wake_irq(port->dev,
stm32_port->wakeirq);
if (ret) {
free_irq(port->irq, port);
return ret;
}
}
val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_set_bits(port, ofs->cr1, val); stm32_set_bits(port, ofs->cr1, val);
return 0; return 0;
@ -467,8 +484,11 @@ static void stm32_shutdown(struct uart_port *port)
val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
val |= BIT(cfg->uart_enable_bit); val |= BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_clr_bits(port, ofs->cr1, val); stm32_clr_bits(port, ofs->cr1, val);
dev_pm_clear_wake_irq(port->dev);
free_irq(port->irq, port); free_irq(port->irq, port);
} }
@ -496,6 +516,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
cr1 |= BIT(cfg->uart_enable_bit); cr1 |= BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0; cr2 = 0;
cr3 = 0; cr3 = 0;
@ -518,7 +540,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
if (cflag & CRTSCTS) { if (cflag & CRTSCTS) {
port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
cr3 |= USART_CR3_CTSE; cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
} }
usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
@ -659,6 +681,8 @@ static int stm32_init_port(struct stm32_port *stm32port,
port->ops = &stm32_uart_ops; port->ops = &stm32_uart_ops;
port->dev = &pdev->dev; port->dev = &pdev->dev;
port->irq = platform_get_irq(pdev, 0); port->irq = platform_get_irq(pdev, 0);
stm32port->wakeirq = platform_get_irq(pdev, 1);
stm32port->fifoen = stm32port->info->cfg.has_fifo;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
port->membase = devm_ioremap_resource(&pdev->dev, res); port->membase = devm_ioremap_resource(&pdev->dev, res);
@ -678,8 +702,10 @@ static int stm32_init_port(struct stm32_port *stm32port,
return ret; return ret;
stm32port->port.uartclk = clk_get_rate(stm32port->clk); stm32port->port.uartclk = clk_get_rate(stm32port->clk);
if (!stm32port->port.uartclk) if (!stm32port->port.uartclk) {
clk_disable_unprepare(stm32port->clk);
ret = -EINVAL; ret = -EINVAL;
}
return ret; return ret;
} }
@ -693,8 +719,10 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
return NULL; return NULL;
id = of_alias_get_id(np, "serial"); id = of_alias_get_id(np, "serial");
if (id < 0) if (id < 0) {
id = 0; dev_err(&pdev->dev, "failed to get alias id, errno %d\n", id);
return NULL;
}
if (WARN_ON(id >= STM32_MAX_PORTS)) if (WARN_ON(id >= STM32_MAX_PORTS))
return NULL; return NULL;
@ -702,6 +730,7 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
stm32_ports[id].hw_flow_control = of_property_read_bool(np, stm32_ports[id].hw_flow_control = of_property_read_bool(np,
"st,hw-flow-ctrl"); "st,hw-flow-ctrl");
stm32_ports[id].port.line = id; stm32_ports[id].port.line = id;
stm32_ports[id].last_res = RX_BUF_L;
return &stm32_ports[id]; return &stm32_ports[id];
} }
@ -711,6 +740,8 @@ static const struct of_device_id stm32_match[] = {
{ .compatible = "st,stm32-uart", .data = &stm32f4_info}, { .compatible = "st,stm32-uart", .data = &stm32f4_info},
{ .compatible = "st,stm32f7-usart", .data = &stm32f7_info}, { .compatible = "st,stm32f7-usart", .data = &stm32f7_info},
{ .compatible = "st,stm32f7-uart", .data = &stm32f7_info}, { .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
{ .compatible = "st,stm32h7-usart", .data = &stm32h7_info},
{ .compatible = "st,stm32h7-uart", .data = &stm32h7_info},
{}, {},
}; };
@ -860,9 +891,15 @@ static int stm32_serial_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) {
ret = device_init_wakeup(&pdev->dev, true);
if (ret)
goto err_uninit;
}
ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
if (ret) if (ret)
return ret; goto err_nowup;
ret = stm32_of_dma_rx_probe(stm32port, pdev); ret = stm32_of_dma_rx_probe(stm32port, pdev);
if (ret) if (ret)
@ -875,6 +912,15 @@ static int stm32_serial_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &stm32port->port); platform_set_drvdata(pdev, &stm32port->port);
return 0; return 0;
err_nowup:
if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0)
device_init_wakeup(&pdev->dev, false);
err_uninit:
clk_disable_unprepare(stm32port->clk);
return ret;
} }
static int stm32_serial_remove(struct platform_device *pdev) static int stm32_serial_remove(struct platform_device *pdev)
@ -882,6 +928,7 @@ static int stm32_serial_remove(struct platform_device *pdev)
struct uart_port *port = platform_get_drvdata(pdev); struct uart_port *port = platform_get_drvdata(pdev);
struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
@ -903,6 +950,9 @@ static int stm32_serial_remove(struct platform_device *pdev)
TX_BUF_L, stm32_port->tx_buf, TX_BUF_L, stm32_port->tx_buf,
stm32_port->tx_dma_buf); stm32_port->tx_dma_buf);
if (cfg->has_wakeup && stm32_port->wakeirq >= 0)
device_init_wakeup(&pdev->dev, false);
clk_disable_unprepare(stm32_port->clk); clk_disable_unprepare(stm32_port->clk);
return uart_remove_one_port(&stm32_usart_driver, port); return uart_remove_one_port(&stm32_usart_driver, port);
@ -1008,11 +1058,66 @@ static struct uart_driver stm32_usart_driver = {
.cons = STM32_SERIAL_CONSOLE, .cons = STM32_SERIAL_CONSOLE,
}; };
#ifdef CONFIG_PM_SLEEP
static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
u32 val;
if (!cfg->has_wakeup || stm32_port->wakeirq < 0)
return;
if (enable) {
stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
stm32_set_bits(port, ofs->cr1, USART_CR1_UESM);
val = readl_relaxed(port->membase + ofs->cr3);
val &= ~USART_CR3_WUS_MASK;
/* Enable Wake up interrupt from low power on start bit */
val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE;
writel_relaxed(val, port->membase + ofs->cr3);
stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
} else {
stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM);
}
}
static int stm32_serial_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
uart_suspend_port(&stm32_usart_driver, port);
if (device_may_wakeup(dev))
stm32_serial_enable_wakeup(port, true);
else
stm32_serial_enable_wakeup(port, false);
return 0;
}
static int stm32_serial_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
stm32_serial_enable_wakeup(port, false);
return uart_resume_port(&stm32_usart_driver, port);
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops stm32_serial_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume)
};
static struct platform_driver stm32_serial_driver = { static struct platform_driver stm32_serial_driver = {
.probe = stm32_serial_probe, .probe = stm32_serial_probe,
.remove = stm32_serial_remove, .remove = stm32_serial_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.pm = &stm32_serial_pm_ops,
.of_match_table = of_match_ptr(stm32_match), .of_match_table = of_match_ptr(stm32_match),
}, },
}; };

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (C) Maxime Coquelin 2015 * Copyright (C) Maxime Coquelin 2015
* Copyright (C) STMicroelectronics SA 2017
* Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com> * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* Gerald Baeza <gerald_baeza@yahoo.fr> * Gerald Baeza <gerald_baeza@yahoo.fr>
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
@ -24,6 +25,8 @@ struct stm32_usart_offsets {
struct stm32_usart_config { struct stm32_usart_config {
u8 uart_enable_bit; /* USART_CR1_UE */ u8 uart_enable_bit; /* USART_CR1_UE */
bool has_7bits_data; bool has_7bits_data;
bool has_wakeup;
bool has_fifo;
}; };
struct stm32_usart_info { struct stm32_usart_info {
@ -74,6 +77,28 @@ struct stm32_usart_info stm32f7_info = {
} }
}; };
struct stm32_usart_info stm32h7_info = {
.ofs = {
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
},
.cfg = {
.uart_enable_bit = 0,
.has_7bits_data = true,
.has_wakeup = true,
.has_fifo = true,
}
};
/* USART_SR (F4) / USART_ISR (F7) */ /* USART_SR (F4) / USART_ISR (F7) */
#define USART_SR_PE BIT(0) #define USART_SR_PE BIT(0)
#define USART_SR_FE BIT(1) #define USART_SR_FE BIT(1)
@ -93,6 +118,7 @@ struct stm32_usart_info stm32f7_info = {
#define USART_SR_BUSY BIT(16) /* F7 */ #define USART_SR_BUSY BIT(16) /* F7 */
#define USART_SR_CMF BIT(17) /* F7 */ #define USART_SR_CMF BIT(17) /* F7 */
#define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_SBKF BIT(18) /* F7 */
#define USART_SR_WUF BIT(20) /* H7 */
#define USART_SR_TEACK BIT(21) /* F7 */ #define USART_SR_TEACK BIT(21) /* F7 */
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ #define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
USART_SR_FE | USART_SR_PE) USART_SR_FE | USART_SR_PE)
@ -113,6 +139,7 @@ struct stm32_usart_info stm32f7_info = {
/* USART_CR1 */ /* USART_CR1 */
#define USART_CR1_SBK BIT(0) #define USART_CR1_SBK BIT(0)
#define USART_CR1_RWU BIT(1) /* F4 */ #define USART_CR1_RWU BIT(1) /* F4 */
#define USART_CR1_UESM BIT(1) /* H7 */
#define USART_CR1_RE BIT(2) #define USART_CR1_RE BIT(2)
#define USART_CR1_TE BIT(3) #define USART_CR1_TE BIT(3)
#define USART_CR1_IDLEIE BIT(4) #define USART_CR1_IDLEIE BIT(4)
@ -134,6 +161,7 @@ struct stm32_usart_info stm32f7_info = {
#define USART_CR1_EOBIE BIT(27) /* F7 */ #define USART_CR1_EOBIE BIT(27) /* F7 */
#define USART_CR1_M1 BIT(28) /* F7 */ #define USART_CR1_M1 BIT(28) /* F7 */
#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) #define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
#define USART_CR1_FIFOEN BIT(29) /* H7 */
/* USART_CR2 */ /* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
@ -175,6 +203,9 @@ struct stm32_usart_info stm32f7_info = {
#define USART_CR3_DEM BIT(14) /* F7 */ #define USART_CR3_DEM BIT(14) /* F7 */
#define USART_CR3_DEP BIT(15) /* F7 */ #define USART_CR3_DEP BIT(15) /* F7 */
#define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */ #define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */
#define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */
#define USART_CR3_WUS_START_BIT BIT(21) /* H7 */
#define USART_CR3_WUFIE BIT(22) /* H7 */
/* USART_GTPR */ /* USART_GTPR */
#define USART_GTPR_PSC_MASK GENMASK(7, 0) #define USART_GTPR_PSC_MASK GENMASK(7, 0)
@ -203,9 +234,10 @@ struct stm32_usart_info stm32f7_info = {
#define USART_ICR_RTOCF BIT(11) /* F7 */ #define USART_ICR_RTOCF BIT(11) /* F7 */
#define USART_ICR_EOBCF BIT(12) /* F7 */ #define USART_ICR_EOBCF BIT(12) /* F7 */
#define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_CMCF BIT(17) /* F7 */
#define USART_ICR_WUCF BIT(20) /* H7 */
#define STM32_SERIAL_NAME "ttyS" #define STM32_SERIAL_NAME "ttyS"
#define STM32_MAX_PORTS 6 #define STM32_MAX_PORTS 8
#define RX_BUF_L 200 /* dma rx buffer length */ #define RX_BUF_L 200 /* dma rx buffer length */
#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ #define RX_BUF_P RX_BUF_L /* dma rx buffer period */
@ -221,8 +253,11 @@ struct stm32_port {
struct dma_chan *tx_ch; /* dma tx channel */ struct dma_chan *tx_ch; /* dma tx channel */
dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ dma_addr_t tx_dma_buf; /* dma tx buffer bus address */
unsigned char *tx_buf; /* dma tx buffer cpu address */ unsigned char *tx_buf; /* dma tx buffer cpu address */
int last_res;
bool tx_dma_busy; /* dma tx busy */ bool tx_dma_busy; /* dma tx busy */
bool hw_flow_control; bool hw_flow_control;
bool fifoen;
int wakeirq;
}; };
static struct stm32_port stm32_ports[STM32_MAX_PORTS]; static struct stm32_port stm32_ports[STM32_MAX_PORTS];

View file

@ -819,7 +819,7 @@ static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL; return -EINVAL;
} }
static struct uart_ops sunsab_pops = { static const struct uart_ops sunsab_pops = {
.tx_empty = sunsab_tx_empty, .tx_empty = sunsab_tx_empty,
.set_mctrl = sunsab_set_mctrl, .set_mctrl = sunsab_set_mctrl,
.get_mctrl = sunsab_get_mctrl, .get_mctrl = sunsab_get_mctrl,

View file

@ -958,7 +958,7 @@ sunsu_type(struct uart_port *port)
return uart_config[type].name; return uart_config[type].name;
} }
static struct uart_ops sunsu_pops = { static const struct uart_ops sunsu_pops = {
.tx_empty = sunsu_tx_empty, .tx_empty = sunsu_tx_empty,
.set_mctrl = sunsu_set_mctrl, .set_mctrl = sunsu_set_mctrl,
.get_mctrl = sunsu_get_mctrl, .get_mctrl = sunsu_get_mctrl,
@ -1212,8 +1212,8 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up)
if (up->port.type == PORT_UNKNOWN) if (up->port.type == PORT_UNKNOWN)
return -ENODEV; return -ENODEV;
printk("%s: %s port at %llx, irq %u\n", printk("%pOF: %s port at %llx, irq %u\n",
up->port.dev->of_node->full_name, up->port.dev->of_node,
(up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse", (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
(unsigned long long) up->port.mapbase, (unsigned long long) up->port.mapbase,
up->port.irq); up->port.irq);

View file

@ -1085,7 +1085,7 @@ static int qe_uart_verify_port(struct uart_port *port,
* *
* Details on these functions can be found in Documentation/serial/driver * Details on these functions can be found in Documentation/serial/driver
*/ */
static struct uart_ops qe_uart_pops = { static const struct uart_ops qe_uart_pops = {
.tx_empty = qe_uart_tx_empty, .tx_empty = qe_uart_tx_empty,
.set_mctrl = qe_uart_set_mctrl, .set_mctrl = qe_uart_set_mctrl,
.get_mctrl = qe_uart_get_mctrl, .get_mctrl = qe_uart_get_mctrl,

View file

@ -1163,7 +1163,7 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
writel(ch, port->membase + CDNS_UART_FIFO); writel(ch, port->membase + CDNS_UART_FIFO);
} }
static void __init cdns_early_write(struct console *con, const char *s, static void cdns_early_write(struct console *con, const char *s,
unsigned n) unsigned n)
{ {
struct earlycon_device *dev = con->data; struct earlycon_device *dev = con->data;

View file

@ -884,7 +884,7 @@ static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent); const struct pci_device_id *ent);
static void synclink_remove_one (struct pci_dev *dev); static void synclink_remove_one (struct pci_dev *dev);
static struct pci_device_id synclink_pci_tbl[] = { static const struct pci_device_id synclink_pci_tbl[] = {
{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }, /* terminate list */ { 0, }, /* terminate list */

View file

@ -95,7 +95,7 @@ MODULE_LICENSE("GPL");
#define MGSL_MAGIC 0x5401 #define MGSL_MAGIC 0x5401
#define MAX_DEVICES 32 #define MAX_DEVICES 32
static struct pci_device_id pci_table[] = { static const struct pci_device_id pci_table[] = {
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},

View file

@ -479,7 +479,7 @@ static char *driver_version = "$Revision: 4.38 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev); static void synclinkmp_remove_one(struct pci_dev *dev);
static struct pci_device_id synclinkmp_pci_tbl[] = { static const struct pci_device_id synclinkmp_pci_tbl[] = {
{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }, /* terminate list */ { 0, }, /* terminate list */
}; };

View file

@ -361,6 +361,32 @@ int tty_insert_flip_string_flags(struct tty_port *port,
} }
EXPORT_SYMBOL(tty_insert_flip_string_flags); EXPORT_SYMBOL(tty_insert_flip_string_flags);
/**
* __tty_insert_flip_char - Add one character to the tty buffer
* @port: tty port
* @ch: character
* @flag: flag byte
*
* Queue a single byte to the tty buffering, with an optional flag.
* This is the slow path of tty_insert_flip_char.
*/
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
{
struct tty_buffer *tb;
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
if (!__tty_buffer_request_room(port, 1, flags))
return 0;
tb = port->buf.tail;
if (~tb->flags & TTYB_NORMAL)
*flag_buf_ptr(tb, tb->used) = flag;
*char_buf_ptr(tb, tb->used++) = ch;
return 1;
}
EXPORT_SYMBOL(__tty_insert_flip_char);
/** /**
* tty_schedule_flip - push characters to ldisc * tty_schedule_flip - push characters to ldisc
* @port: tty port to push from * @port: tty port to push from

View file

@ -462,6 +462,14 @@ static int hung_up_tty_fasync(int fd, struct file *file, int on)
return -ENOTTY; return -ENOTTY;
} }
static void tty_show_fdinfo(struct seq_file *m, struct file *file)
{
struct tty_struct *tty = file_tty(file);
if (tty && tty->ops && tty->ops->show_fdinfo)
tty->ops->show_fdinfo(tty, m);
}
static const struct file_operations tty_fops = { static const struct file_operations tty_fops = {
.llseek = no_llseek, .llseek = no_llseek,
.read = tty_read, .read = tty_read,
@ -472,6 +480,7 @@ static const struct file_operations tty_fops = {
.open = tty_open, .open = tty_open,
.release = tty_release, .release = tty_release,
.fasync = tty_fasync, .fasync = tty_fasync,
.show_fdinfo = tty_show_fdinfo,
}; };
static const struct file_operations console_fops = { static const struct file_operations console_fops = {

View file

@ -136,5 +136,7 @@ extern struct resource *mcb_request_mem(struct mcb_device *dev,
const char *name); const char *name);
extern void mcb_release_mem(struct resource *mem); extern void mcb_release_mem(struct resource *mem);
extern int mcb_get_irq(struct mcb_device *dev); extern int mcb_get_irq(struct mcb_device *dev);
extern struct resource *mcb_get_resource(struct mcb_device *dev,
unsigned int type);
#endif /* _LINUX_MCB_H */ #endif /* _LINUX_MCB_H */

View file

@ -80,9 +80,10 @@ struct uart_8250_ops {
}; };
struct uart_8250_em485 { struct uart_8250_em485 {
struct timer_list start_tx_timer; /* "rs485 start tx" timer */ struct hrtimer start_tx_timer; /* "rs485 start tx" timer */
struct timer_list stop_tx_timer; /* "rs485 stop tx" timer */ struct hrtimer stop_tx_timer; /* "rs485 stop tx" timer */
struct timer_list *active_timer; /* pointer to active timer */ struct hrtimer *active_timer; /* pointer to active timer */
struct uart_8250_port *port; /* for hrtimer callbacks */
}; };
/* /*

View file

@ -20,7 +20,7 @@
#ifndef LINUX_SERIAL_CORE_H #ifndef LINUX_SERIAL_CORE_H
#define LINUX_SERIAL_CORE_H #define LINUX_SERIAL_CORE_H
#include <linux/bitops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/circ_buf.h> #include <linux/circ_buf.h>
@ -144,7 +144,7 @@ struct uart_port {
unsigned char x_char; /* xon/xoff char */ unsigned char x_char; /* xon/xoff char */
unsigned char regshift; /* reg offset shift */ unsigned char regshift; /* reg offset shift */
unsigned char iotype; /* io access style */ unsigned char iotype; /* io access style */
unsigned char unused1; unsigned char quirks; /* internal quirks */
#define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */ #define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */
#define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */ #define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */
@ -155,6 +155,9 @@ struct uart_port {
#define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
#define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */ #define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */
/* quirks must be updated while holding port mutex */
#define UPQ_NO_TXEN_TEST BIT(0)
unsigned int read_status_mask; /* driver specific */ unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */
struct uart_state *state; /* pointer to parent state */ struct uart_state *state; /* pointer to parent state */
@ -175,7 +178,6 @@ struct uart_port {
* [for bit definitions in the UPF_CHANGE_MASK] * [for bit definitions in the UPF_CHANGE_MASK]
* *
* Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable * Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable
* except bit 15 (UPF_NO_TXEN_TEST) which is masked off.
* The remaining bits are serial-core specific and not modifiable by * The remaining bits are serial-core specific and not modifiable by
* userspace. * userspace.
*/ */
@ -192,7 +194,6 @@ struct uart_port {
#define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ ) #define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ )
#define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ ) #define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ )
#define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ ) #define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ )
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ ) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
#define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19)) #define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19))
@ -246,7 +247,6 @@ struct uart_port {
struct device *dev; /* parent device */ struct device *dev; /* parent device */
unsigned char hub6; /* this should be in the 8250 driver */ unsigned char hub6; /* this should be in the 8250 driver */
unsigned char suspended; unsigned char suspended;
unsigned char irq_wake;
unsigned char unused[2]; unsigned char unused[2];
const char *name; /* port name */ const char *name; /* port name */
struct attribute_group *attr_group; /* port specific attributes */ struct attribute_group *attr_group; /* port specific attributes */

View file

@ -243,6 +243,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/termios.h> #include <linux/termios.h>
#include <linux/seq_file.h>
struct tty_struct; struct tty_struct;
struct tty_driver; struct tty_driver;
@ -285,6 +286,7 @@ struct tty_operations {
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
int (*get_icount)(struct tty_struct *tty, int (*get_icount)(struct tty_struct *tty,
struct serial_icounter_struct *icount); struct serial_icounter_struct *icount);
void (*show_fdinfo)(struct tty_struct *tty, struct seq_file *m);
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line); int (*poll_get_char)(struct tty_driver *driver, int line);

View file

@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struct tty_port *port,
unsigned char **chars, size_t size); unsigned char **chars, size_t size);
extern void tty_flip_buffer_push(struct tty_port *port); extern void tty_flip_buffer_push(struct tty_port *port);
void tty_schedule_flip(struct tty_port *port); void tty_schedule_flip(struct tty_port *port);
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
static inline int tty_insert_flip_char(struct tty_port *port, static inline int tty_insert_flip_char(struct tty_port *port,
unsigned char ch, char flag) unsigned char ch, char flag)
@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(struct tty_port *port,
*char_buf_ptr(tb, tb->used++) = ch; *char_buf_ptr(tb, tb->used++) = ch;
return 1; return 1;
} }
return tty_insert_flip_string_flags(port, &ch, &flag, 1); return __tty_insert_flip_char(port, ch, flag);
} }
static inline int tty_insert_flip_string(struct tty_port *port, static inline int tty_insert_flip_string(struct tty_port *port,

View file

@ -56,8 +56,6 @@
#define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */ #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
#define PORT_RT2880 29 /* Ralink RT2880 internal UART */ #define PORT_RT2880 29 /* Ralink RT2880 internal UART */
#define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */ #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
#define PORT_DA830 31 /* TI DA8xx/66AK2x */
#define PORT_MAX_8250 31 /* max port ID */
/* /*
* ARM specific type numbers. These are not currently guaranteed * ARM specific type numbers. These are not currently guaranteed
@ -70,12 +68,17 @@
#define PORT_CLPS711X 33 #define PORT_CLPS711X 33
#define PORT_SA1100 34 #define PORT_SA1100 34
#define PORT_UART00 35 #define PORT_UART00 35
#define PORT_OWL 36
#define PORT_21285 37 #define PORT_21285 37
/* Sparc type numbers. */ /* Sparc type numbers. */
#define PORT_SUNZILOG 38 #define PORT_SUNZILOG 38
#define PORT_SUNSAB 39 #define PORT_SUNSAB 39
/* Intel EG20 */
#define PORT_PCH_8LINE 44
#define PORT_PCH_2LINE 45
/* DEC */ /* DEC */
#define PORT_DZ 46 #define PORT_DZ 46
#define PORT_ZS 47 #define PORT_ZS 47
@ -205,8 +208,8 @@
/* MAX310X */ /* MAX310X */
#define PORT_MAX310X 94 #define PORT_MAX310X 94
/* High Speed UART for Medfield */ /* TI DA8xx/66AK2x */
#define PORT_MFD 95 #define PORT_DA830 95
/* TI OMAP-UART */ /* TI OMAP-UART */
#define PORT_OMAP 96 #define PORT_OMAP 96
@ -271,4 +274,7 @@
/* MPS2 UART */ /* MPS2 UART */
#define PORT_MPS2UART 116 #define PORT_MPS2UART 116
/* MediaTek BTIF */
#define PORT_MTK_BTIF 117
#endif /* _UAPILINUX_SERIAL_CORE_H */ #endif /* _UAPILINUX_SERIAL_CORE_H */