tty: serial8250: add helpers for the DesignWare 8250
The Synopsys DesignWare 8250 is an 8250 that has an extra interrupt that gets raised when writing to the LCR when busy. To handle this we need special serial_out, serial_in and handle_irq methods. Add a new function serial8250_use_designware_io() that configures a uart_port with these accessors. Cc: Alan Cox <alan@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jamie Iles <jamie@jamieiles.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
4834d02897
Коммит
6b1a98d1c4
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Synopsys DesignWare specific 8250 operations.
|
||||
*
|
||||
* Copyright 2011 Picochip, Jamie Iles.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
|
||||
* LCR is written whilst busy. If it is, then a busy detect interrupt is
|
||||
* raised, the LCR needs to be rewritten and the uart status register read.
|
||||
*/
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct dw8250_data {
|
||||
int last_lcr;
|
||||
};
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
if (offset == UART_LCR)
|
||||
d->last_lcr = value;
|
||||
|
||||
offset <<= p->regshift;
|
||||
writeb(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset <<= p->regshift;
|
||||
|
||||
return readb(p->membase + offset);
|
||||
}
|
||||
|
||||
static void dw8250_serial_out32(struct uart_port *p, int offset,
|
||||
int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
if (offset == UART_LCR)
|
||||
d->last_lcr = value;
|
||||
|
||||
offset <<= p->regshift;
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
{
|
||||
offset <<= p->regshift;
|
||||
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
/* Offset for the DesignWare's UART Status Register. */
|
||||
#define UART_USR 0x1f
|
||||
|
||||
static int dw8250_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
unsigned int iir = p->serial_in(p, UART_IIR);
|
||||
|
||||
if (serial8250_handle_irq(p, iir)) {
|
||||
return 1;
|
||||
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
||||
/* Clear the USR and write the LCR again. */
|
||||
(void)p->serial_in(p, UART_USR);
|
||||
p->serial_out(p, d->last_lcr, UART_LCR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial8250_use_designware_io(struct uart_port *up)
|
||||
{
|
||||
up->private_data = kzalloc(sizeof(struct dw8250_data), GFP_KERNEL);
|
||||
if (!up->private_data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (up->iotype == UPIO_MEM32) {
|
||||
up->serial_out = dw8250_serial_out32;
|
||||
up->serial_in = dw8250_serial_in32;
|
||||
} else {
|
||||
up->serial_out = dw8250_serial_out;
|
||||
up->serial_in = dw8250_serial_in;
|
||||
}
|
||||
up->handle_irq = dw8250_handle_irq;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -267,6 +267,13 @@ config SERIAL_8250_RM9K
|
|||
port hardware found on MIPS RM9122 and similar processors.
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_DW
|
||||
bool "Support for Synopsys DesignWare 8250 quirks"
|
||||
depends on SERIAL_8250
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present in the Synopsys DesignWare APB UART.
|
||||
|
||||
comment "Non-8250 serial port support"
|
||||
|
||||
config SERIAL_AMBA_PL010
|
||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
|
|||
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
|
||||
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
|
||||
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
|
||||
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
|
||||
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
|
||||
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
|
||||
|
|
|
@ -86,5 +86,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
|
|||
extern void serial8250_set_isa_configurator(void (*v)
|
||||
(int port, struct uart_port *up,
|
||||
unsigned short *capabilities));
|
||||
#ifndef SERIAL_8250_DW
|
||||
extern int serial8250_use_designware_io(struct uart_port *up);
|
||||
#else
|
||||
static inline int serial8250_use_designware_io(struct uart_port *up)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче