tegra, serial8250: add ->handle_break() uart_port op
The "KT" serial port has another use case for a "received break" quirk, so before adding another special case to the 8250 core take this opportunity to push such quirks out of the core and into a uart_port op. Stephen says: "If the callback function is to no longer live in 8250.c itself, arch/arm/mach-tegra/devices.c isn't logically a good place to put it, and that file will be going away once we get rid of all the board files and move solely to device tree." ...so since 8250_pci.c houses all the quirks for pci serial devices this quirk is similarly housed in of_serial.c. Once the open firmware conversion completes the infrastructure details (include/linux/of_serial.h, and the export) can all be removed to make this self contained to of_serial.c. Cc: Nhan H Mai <nhan.h.mai@intel.com> Cc: Colin Cross <ccross@android.com> Cc: Olof Johansson <olof@lixom.net> [stephen: kill CONFIG_SERIAL_TEGRA in favor just using CONFIG_ARCH_TEGRA] Cc: Grant Likely <grant.likely@secretlab.ca> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Sudhakar Mamillapalli <sudhakar@fb.com> Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Acked-by: Stephen Warren <swarren@wwwdotorg.org> Tested-by: Stephen Warren <swarren@wwwdotorg.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7c77c8decf
commit
bf03f65b79
9 changed files with 61 additions and 31 deletions
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
|
#include <linux/of_serial.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/pda_power.h>
|
#include <linux/pda_power.h>
|
||||||
|
@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||||
.irq = INT_UARTD,
|
.irq = INT_UARTD,
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
.type = PORT_TEGRA,
|
.type = PORT_TEGRA,
|
||||||
|
.handle_break = tegra_serial_handle_break,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = 216000000,
|
.uartclk = 216000000,
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
|
#include <linux/of_serial.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/gpio_keys.h>
|
#include <linux/gpio_keys.h>
|
||||||
|
@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||||
.irq = INT_UARTA,
|
.irq = INT_UARTA,
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
.type = PORT_TEGRA,
|
.type = PORT_TEGRA,
|
||||||
|
.handle_break = tegra_serial_handle_break,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = 216000000,
|
.uartclk = 216000000,
|
||||||
|
@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||||
.irq = INT_UARTC,
|
.irq = INT_UARTC,
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
.type = PORT_TEGRA,
|
.type = PORT_TEGRA,
|
||||||
|
.handle_break = tegra_serial_handle_break,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = 216000000,
|
.uartclk = 216000000,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
|
#include <linux/of_serial.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||||
/* Memory and IRQ filled in before registration */
|
/* Memory and IRQ filled in before registration */
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
.type = PORT_TEGRA,
|
.type = PORT_TEGRA,
|
||||||
|
.handle_break = tegra_serial_handle_break,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = 216000000,
|
.uartclk = 216000000,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
|
#include <linux/of_serial.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||||
.irq = INT_UARTA,
|
.irq = INT_UARTA,
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
.type = PORT_TEGRA,
|
.type = PORT_TEGRA,
|
||||||
|
.handle_break = tegra_serial_handle_break,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = 216000000,
|
.uartclk = 216000000,
|
||||||
|
|
|
@ -1331,27 +1331,6 @@ static void serial8250_enable_ms(struct uart_port *port)
|
||||||
serial_port_out(port, UART_IER, up->ier);
|
serial_port_out(port, UART_IER, up->ier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear the Tegra rx fifo after a break
|
|
||||||
*
|
|
||||||
* FIXME: This needs to become a port specific callback once we have a
|
|
||||||
* framework for this
|
|
||||||
*/
|
|
||||||
static void clear_rx_fifo(struct uart_8250_port *up)
|
|
||||||
{
|
|
||||||
unsigned int status, tmout = 10000;
|
|
||||||
do {
|
|
||||||
status = serial_in(up, UART_LSR);
|
|
||||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
|
||||||
status = serial_in(up, UART_RX);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
if (--tmout == 0)
|
|
||||||
break;
|
|
||||||
udelay(1);
|
|
||||||
} while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* serial8250_rx_chars: processes according to the passed in LSR
|
* serial8250_rx_chars: processes according to the passed in LSR
|
||||||
* value, and returns the remaining LSR bits not handled
|
* value, and returns the remaining LSR bits not handled
|
||||||
|
@ -1386,19 +1365,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
||||||
up->lsr_saved_flags = 0;
|
up->lsr_saved_flags = 0;
|
||||||
|
|
||||||
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
|
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
|
||||||
/*
|
|
||||||
* For statistics only
|
|
||||||
*/
|
|
||||||
if (lsr & UART_LSR_BI) {
|
if (lsr & UART_LSR_BI) {
|
||||||
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
||||||
port->icount.brk++;
|
port->icount.brk++;
|
||||||
/*
|
|
||||||
* If tegra port then clear the rx fifo to
|
|
||||||
* accept another break/character.
|
|
||||||
*/
|
|
||||||
if (port->type == PORT_TEGRA)
|
|
||||||
clear_rx_fifo(up);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do the SysRQ and SAK checking
|
* We do the SysRQ and SAK checking
|
||||||
* here because otherwise the break
|
* here because otherwise the break
|
||||||
|
@ -3037,6 +3006,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
|
||||||
port.serial_in = p->serial_in;
|
port.serial_in = p->serial_in;
|
||||||
port.serial_out = p->serial_out;
|
port.serial_out = p->serial_out;
|
||||||
port.handle_irq = p->handle_irq;
|
port.handle_irq = p->handle_irq;
|
||||||
|
port.handle_break = p->handle_break;
|
||||||
port.set_termios = p->set_termios;
|
port.set_termios = p->set_termios;
|
||||||
port.pm = p->pm;
|
port.pm = p->pm;
|
||||||
port.dev = &dev->dev;
|
port.dev = &dev->dev;
|
||||||
|
@ -3209,6 +3179,8 @@ int serial8250_register_port(struct uart_port *port)
|
||||||
uart->port.set_termios = port->set_termios;
|
uart->port.set_termios = port->set_termios;
|
||||||
if (port->pm)
|
if (port->pm)
|
||||||
uart->port.pm = port->pm;
|
uart->port.pm = port->pm;
|
||||||
|
if (port->handle_break)
|
||||||
|
uart->port.handle_break = port->handle_break;
|
||||||
|
|
||||||
if (serial8250_isa_config != NULL)
|
if (serial8250_isa_config != NULL)
|
||||||
serial8250_isa_config(0, &uart->port,
|
serial8250_isa_config(0, &uart->port,
|
||||||
|
|
|
@ -12,10 +12,13 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
|
#include <linux/serial_reg.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/of_serial.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/nwpserial.h>
|
#include <linux/nwpserial.h>
|
||||||
|
|
||||||
|
@ -24,6 +27,26 @@ struct of_serial_info {
|
||||||
int line;
|
int line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_TEGRA
|
||||||
|
void tegra_serial_handle_break(struct uart_port *p)
|
||||||
|
{
|
||||||
|
unsigned int status, tmout = 10000;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = p->serial_in(p, UART_LSR);
|
||||||
|
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||||
|
status = p->serial_in(p, UART_RX);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (--tmout == 0)
|
||||||
|
break;
|
||||||
|
udelay(1);
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
/* FIXME remove this export when tegra finishes conversion to open firmware */
|
||||||
|
EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill a struct uart_port for a given device node
|
* Fill a struct uart_port for a given device node
|
||||||
*/
|
*/
|
||||||
|
@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
|
||||||
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||||
port->dev = &ofdev->dev;
|
port->dev = &ofdev->dev;
|
||||||
|
|
||||||
|
if (type == PORT_TEGRA)
|
||||||
|
port->handle_break = tegra_serial_handle_break;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
include/linux/of_serial.h
Normal file
17
include/linux/of_serial.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef __LINUX_OF_SERIAL_H
|
||||||
|
#define __LINUX_OF_SERIAL_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME remove this file when tegra finishes conversion to open firmware,
|
||||||
|
* expectation is that all quirks will then be self-contained in
|
||||||
|
* drivers/tty/serial/of_serial.c.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_ARCH_TEGRA
|
||||||
|
extern void tegra_serial_handle_break(struct uart_port *port);
|
||||||
|
#else
|
||||||
|
static inline void tegra_serial_handle_break(struct uart_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LINUX_OF_SERIAL */
|
|
@ -38,6 +38,7 @@ struct plat_serial8250_port {
|
||||||
int (*handle_irq)(struct uart_port *);
|
int (*handle_irq)(struct uart_port *);
|
||||||
void (*pm)(struct uart_port *, unsigned int state,
|
void (*pm)(struct uart_port *, unsigned int state,
|
||||||
unsigned old);
|
unsigned old);
|
||||||
|
void (*handle_break)(struct uart_port *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -310,6 +310,7 @@ struct uart_port {
|
||||||
int (*handle_irq)(struct uart_port *);
|
int (*handle_irq)(struct uart_port *);
|
||||||
void (*pm)(struct uart_port *, unsigned int state,
|
void (*pm)(struct uart_port *, unsigned int state,
|
||||||
unsigned int old);
|
unsigned int old);
|
||||||
|
void (*handle_break)(struct uart_port *);
|
||||||
unsigned int irq; /* irq number */
|
unsigned int irq; /* irq number */
|
||||||
unsigned long irqflags; /* irq flags */
|
unsigned long irqflags; /* irq flags */
|
||||||
unsigned int uartclk; /* base uart clock */
|
unsigned int uartclk; /* base uart clock */
|
||||||
|
@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||||
static inline int uart_handle_break(struct uart_port *port)
|
static inline int uart_handle_break(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_state *state = port->state;
|
struct uart_state *state = port->state;
|
||||||
|
|
||||||
|
if (port->handle_break)
|
||||||
|
port->handle_break(port);
|
||||||
|
|
||||||
#ifdef SUPPORT_SYSRQ
|
#ifdef SUPPORT_SYSRQ
|
||||||
if (port->cons && port->cons->index == port->line) {
|
if (port->cons && port->cons->index == port->line) {
|
||||||
if (!port->sysrq) {
|
if (!port->sysrq) {
|
||||||
|
|
Loading…
Reference in a new issue