forked from Minki/linux
TTY/Serial patches for 4.6-rc1
Here's the big tty/serial driver pull request for 4.6-rc1. Lots of changes in here, Peter has been on a tear again, with lots of refactoring and bugs fixes, many thanks to the great work he has been doing. Lots of driver updates and fixes as well, full details in the shortlog. All have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlbp8z8ACgkQMUfUDdst+ym1vwCgnOOCORaZyeQ4QrcxPAK5pHFn VrMAoNHvDgNYtG+Hmzv25Lgp3HnysPin =MLRG -----END PGP SIGNATURE----- Merge tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial updates from Greg KH: "Here's the big tty/serial driver pull request for 4.6-rc1. Lots of changes in here, Peter has been on a tear again, with lots of refactoring and bugs fixes, many thanks to the great work he has been doing. Lots of driver updates and fixes as well, full details in the shortlog. All have been in linux-next for a while with no reported issues" * tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (220 commits) serial: 8250: describe CONFIG_SERIAL_8250_RSA serial: samsung: optimize UART rx fifo access routine serial: pl011: add mark/space parity support serial: sa1100: make sa1100_register_uart_fns a function tty: serial: 8250: add MOXA Smartio MUE boards support serial: 8250: convert drivers to use up_to_u8250p() serial: 8250/mediatek: fix building with SERIAL_8250=m serial: 8250/ingenic: fix building with SERIAL_8250=m serial: 8250/uniphier: fix modular build Revert "drivers/tty/serial: make 8250/8250_ingenic.c explicitly non-modular" Revert "drivers/tty/serial: make 8250/8250_mtk.c explicitly non-modular" serial: mvebu-uart: initial support for Armada-3700 serial port serial: mctrl_gpio: Add missing module license serial: ifx6x60: avoid uninitialized variable use tty/serial: at91: fix bad offset for UART timeout register tty/serial: at91: restore dynamic driver binding serial: 8250: Add hardware dependency to RT288X option TTY, devpts: document pty count limiting tty: goldfish: support platform_device with id -1 drivers: tty: goldfish: Add device tree bindings ...
This commit is contained in:
commit
96b9b1c956
17
Documentation/devicetree/bindings/goldfish/tty.txt
Normal file
17
Documentation/devicetree/bindings/goldfish/tty.txt
Normal file
@ -0,0 +1,17 @@
|
||||
Android Goldfish TTY
|
||||
|
||||
Android goldfish tty device generated by android emulator.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should contain "google,goldfish-tty" to match emulator
|
||||
- reg : <registers mapping>
|
||||
- interrupts : <interrupt mapping>
|
||||
|
||||
Example:
|
||||
|
||||
goldfish_tty@1f004000 {
|
||||
compatible = "google,goldfish-tty";
|
||||
reg = <0x1f004000 0x1000>;
|
||||
interrupts = <0xc>;
|
||||
};
|
@ -0,0 +1,18 @@
|
||||
* BCM2835 AUXILIAR UART
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "brcm,bcm2835-aux-uart"
|
||||
- reg: The base address of the UART register bank.
|
||||
- interrupts: A single interrupt specifier.
|
||||
- clocks: Clock driving the hardware; used to figure out the baud rate
|
||||
divisor.
|
||||
|
||||
Example:
|
||||
|
||||
uart1: serial@7e215040 {
|
||||
compatible = "brcm,bcm2835-aux-uart";
|
||||
reg = <0x7e215040 0x40>;
|
||||
interrupts = <1 29>;
|
||||
clocks = <&aux BCM2835_AUX_CLOCK_UART>;
|
||||
};
|
@ -19,6 +19,8 @@ Required properties:
|
||||
- "renesas,scifa-r8a7791" for R8A7791 (R-Car M2-W) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7791" for R8A7791 (R-Car M2-W) SCIFB compatible UART.
|
||||
- "renesas,hscif-r8a7791" for R8A7791 (R-Car M2-W) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7792" for R8A7792 (R-Car V2H) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a7792" for R8A7792 (R-Car V2H) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7793" for R8A7793 (R-Car M2-N) SCIF compatible UART.
|
||||
- "renesas,scifa-r8a7793" for R8A7793 (R-Car M2-N) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7793" for R8A7793 (R-Car M2-N) SCIFB compatible UART.
|
||||
|
13
Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt
Normal file
13
Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt
Normal file
@ -0,0 +1,13 @@
|
||||
* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700)
|
||||
|
||||
Required properties:
|
||||
- compatible: "marvell,armada-3700-uart"
|
||||
- reg: offset and length of the register set for the device.
|
||||
- interrupts: device interrupt
|
||||
|
||||
Example:
|
||||
serial@12000 {
|
||||
compatible = "marvell,armada-3700-uart";
|
||||
reg = <0x12000 0x400>;
|
||||
interrupts = <43>;
|
||||
};
|
@ -51,6 +51,15 @@ where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs
|
||||
/bin/bash in the child process. A pty created by the sshd is not visible in
|
||||
the original mount of /dev/pts.
|
||||
|
||||
Total count of pty pairs in all instances is limited by sysctls:
|
||||
kernel.pty.max = 4096 - global limit
|
||||
kernel.pty.reserve = 1024 - reserve for initial instance
|
||||
kernel.pty.nr - current count of ptys
|
||||
|
||||
Per-instance limit could be set by adding mount option "max=<count>".
|
||||
This feature was added in kernel 3.4 together with sysctl kernel.pty.reserve.
|
||||
In kernels older than 3.4 sysctl kernel.pty.max works as per-instance limit.
|
||||
|
||||
User-space changes
|
||||
------------------
|
||||
|
||||
|
@ -1064,6 +1064,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
A valid base address must be provided, and the serial
|
||||
port must already be setup and configured.
|
||||
|
||||
armada3700_uart,<addr>
|
||||
Start an early, polled-mode console on the
|
||||
Armada 3700 serial port at the specified
|
||||
address. The serial port must already be setup
|
||||
and configured. Options are not yet supported.
|
||||
|
||||
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
|
||||
earlyprintk=vga
|
||||
earlyprintk=efi
|
||||
|
@ -72,9 +72,6 @@ flush_buffer() - (optional) May be called at any point between
|
||||
open and close, and instructs the line discipline
|
||||
to empty its input buffer.
|
||||
|
||||
chars_in_buffer() - (optional) Report the number of bytes in the input
|
||||
buffer.
|
||||
|
||||
set_termios() - (optional) Called on termios structure changes.
|
||||
The caller passes the old termios data and the
|
||||
current data is in the tty. Called under the
|
||||
|
@ -66,6 +66,7 @@ show up in /proc/sys/kernel:
|
||||
- printk_delay
|
||||
- printk_ratelimit
|
||||
- printk_ratelimit_burst
|
||||
- pty ==> Documentation/filesystems/devpts.txt
|
||||
- randomize_va_space
|
||||
- real-root-dev ==> Documentation/initrd.txt
|
||||
- reboot-cmd [ SPARC only ]
|
||||
|
@ -6068,7 +6068,7 @@ S: Maintained
|
||||
F: drivers/media/platform/rcar_jpu.c
|
||||
|
||||
JSM Neo PCI based serial card
|
||||
M: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
|
||||
M: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
|
||||
L: linux-serial@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/tty/serial/jsm/
|
||||
|
@ -14,11 +14,11 @@
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
|
||||
#else
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
|
||||
#endif
|
||||
|
||||
#define SERIAL_PORT_DFNS \
|
||||
|
@ -252,7 +252,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
|
||||
info = omap_serial_default_info;
|
||||
|
||||
oh = uart->oh;
|
||||
name = DRIVER_NAME;
|
||||
name = OMAP_SERIAL_DRIVER_NAME;
|
||||
|
||||
omap_up.dma_enabled = info->dma_enabled;
|
||||
omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
|
||||
|
@ -13,6 +13,6 @@
|
||||
*/
|
||||
#define BASE_BAUD 0
|
||||
|
||||
#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#define STD_COM_FLAGS UPF_BOOT_AUTOCONF
|
||||
|
||||
#define SERIAL_PORT_DFNS
|
||||
|
@ -1336,8 +1336,11 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
|
||||
* Don't call tty_write_message() if we're in the kernel; we might
|
||||
* be holding locks...
|
||||
*/
|
||||
if (user_mode(regs))
|
||||
tty_write_message(current->signal->tty, buf);
|
||||
if (user_mode(regs)) {
|
||||
struct tty_struct *tty = get_current_tty();
|
||||
tty_write_message(tty, buf);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
buf[len-1] = '\0'; /* drop '\r' */
|
||||
/* watch for command names containing %s */
|
||||
printk(KERN_WARNING "%s", buf);
|
||||
|
@ -18,11 +18,11 @@
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
|
||||
#else
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ISA
|
||||
|
@ -110,7 +110,7 @@ void __init msp_serial_setup(void)
|
||||
up.uartclk = uartclk;
|
||||
up.regshift = 2;
|
||||
up.iotype = UPIO_MEM;
|
||||
up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
|
||||
up.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
|
||||
up.type = PORT_16550A;
|
||||
up.line = 0;
|
||||
up.serial_out = msp_serial_out;
|
||||
|
@ -14,15 +14,15 @@
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
|
||||
#else
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
|
||||
#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
|
||||
#define FOURPORT_FLAGS ASYNC_FOURPORT
|
||||
#define FOURPORT_FLAGS UPF_FOURPORT
|
||||
#define ACCENT_FLAGS 0
|
||||
#define BOCA_FLAGS 0
|
||||
#define HUB6_FLAGS 0
|
||||
|
@ -28,10 +28,6 @@
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#ifdef SERIAL_INLINE
|
||||
#define _INLINE_ inline
|
||||
#endif
|
||||
|
||||
#define SERIAL_MAX_NUM_LINES 1
|
||||
#define SERIAL_TIMER_VALUE (HZ / 10)
|
||||
|
||||
|
@ -113,7 +113,7 @@ void platform_heartbeat(void)
|
||||
}
|
||||
|
||||
//#define RS_TABLE_SIZE 2
|
||||
//#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
|
||||
//#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF|UPF_SKIP_TEST)
|
||||
|
||||
#define _SERIAL_PORT(_base,_irq) \
|
||||
{ \
|
||||
|
@ -1349,7 +1349,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
|
||||
/* TODO:disable interrupts instead of reset to preserve signal states */
|
||||
reset_device(info);
|
||||
|
||||
if (!tty || tty->termios.c_cflag & HUPCL) {
|
||||
if (!tty || C_HUPCL(tty)) {
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
set_signals(info);
|
||||
}
|
||||
@ -1390,7 +1390,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
|
||||
get_signals(info);
|
||||
|
||||
if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
|
||||
if (info->netcount || (tty && C_CREAD(tty)))
|
||||
rx_start(info);
|
||||
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
@ -1733,7 +1733,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
|
||||
if (I_IXOFF(tty))
|
||||
mgslpc_send_xchar(tty, STOP_CHAR(tty));
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
info->serial_signals &= ~SerialSignal_RTS;
|
||||
set_signals(info);
|
||||
@ -1762,7 +1762,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
|
||||
mgslpc_send_xchar(tty, START_CHAR(tty));
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
info->serial_signals |= SerialSignal_RTS;
|
||||
set_signals(info);
|
||||
@ -2306,8 +2306,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
|
||||
mgslpc_change_params(info, tty);
|
||||
|
||||
/* Handle transition to B0 status */
|
||||
if (old_termios->c_cflag & CBAUD &&
|
||||
!(tty->termios.c_cflag & CBAUD)) {
|
||||
if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
set_signals(info);
|
||||
@ -2315,21 +2314,17 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
|
||||
}
|
||||
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) &&
|
||||
tty->termios.c_cflag & CBAUD) {
|
||||
if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
|
||||
info->serial_signals |= SerialSignal_DTR;
|
||||
if (!(tty->termios.c_cflag & CRTSCTS) ||
|
||||
!test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
info->serial_signals |= SerialSignal_RTS;
|
||||
}
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
set_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
}
|
||||
|
||||
/* Handle turning off CRTSCTS */
|
||||
if (old_termios->c_cflag & CRTSCTS &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) {
|
||||
tty->hw_stopped = 0;
|
||||
tx_release(tty);
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ static const struct tty_operations ttyprintk_ops = {
|
||||
.ioctl = tpk_ioctl,
|
||||
};
|
||||
|
||||
static struct tty_port_operations null_ops = { };
|
||||
static const struct tty_port_operations null_ops = { };
|
||||
|
||||
static struct tty_driver *ttyprintk_driver;
|
||||
|
||||
|
@ -1572,7 +1572,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
port->flags |= ASYNC_CLOSING;
|
||||
info->closing = 1;
|
||||
|
||||
tty->closing = 1;
|
||||
/*
|
||||
@ -1603,6 +1603,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
info->ncarrier = 0;
|
||||
|
||||
tty_port_close_end(port, tty);
|
||||
info->closing = 0;
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
|
||||
#endif
|
||||
@ -2236,7 +2237,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
|
||||
l = strlen(msg);
|
||||
|
||||
spin_lock_irqsave(&info->readlock, flags);
|
||||
if (port->flags & ASYNC_CLOSING) {
|
||||
if (info->closing) {
|
||||
spin_unlock_irqrestore(&info->readlock, flags);
|
||||
return;
|
||||
}
|
||||
@ -2386,13 +2387,12 @@ isdn_tty_modem_result(int code, modem_info *info)
|
||||
case RESULT_NO_CARRIER:
|
||||
#ifdef ISDN_DEBUG_MODEM_HUP
|
||||
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
|
||||
(info->port.flags & ASYNC_CLOSING),
|
||||
(!info->port.tty));
|
||||
info->closing, !info->port.tty);
|
||||
#endif
|
||||
m->mdmreg[REG_RINGCNT] = 0;
|
||||
del_timer(&info->nc_timer);
|
||||
info->ncarrier = 0;
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
|
||||
if (info->closing || !info->port.tty)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
@ -2525,7 +2525,7 @@ isdn_tty_modem_result(int code, modem_info *info)
|
||||
}
|
||||
}
|
||||
if (code == RESULT_NO_CARRIER) {
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
|
||||
if (info->closing || (!info->port.tty))
|
||||
return;
|
||||
|
||||
if (info->port.flags & ASYNC_CHECK_CD)
|
||||
|
@ -493,7 +493,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||
if (status & UART_MSR_DCTS) {
|
||||
port->icount.cts++;
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && (tty->termios.c_cflag & CRTSCTS)) {
|
||||
if (tty && C_CRTSCTS(tty)) {
|
||||
int cts = (status & UART_MSR_CTS);
|
||||
if (tty->hw_stopped) {
|
||||
if (cts) {
|
||||
@ -648,10 +648,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||
|
||||
sdio_uart_change_speed(port, &tty->termios, NULL);
|
||||
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty))
|
||||
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
|
||||
tty->hw_stopped = 1;
|
||||
|
||||
@ -833,7 +833,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
|
||||
if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
|
||||
if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
|
||||
return;
|
||||
|
||||
if (sdio_uart_claim_func(port) != 0)
|
||||
@ -844,7 +844,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
|
||||
sdio_uart_start_tx(port);
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
sdio_uart_clear_mctrl(port, TIOCM_RTS);
|
||||
|
||||
sdio_uart_irq(port->func);
|
||||
@ -855,7 +855,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
|
||||
if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
|
||||
if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
|
||||
return;
|
||||
|
||||
if (sdio_uart_claim_func(port) != 0)
|
||||
@ -870,7 +870,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
|
||||
}
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
sdio_uart_set_mctrl(port, TIOCM_RTS);
|
||||
|
||||
sdio_uart_irq(port->func);
|
||||
|
@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)
|
||||
|
||||
/* Module stuff handled via irda_ldisc.owner - Jean II */
|
||||
|
||||
/* First make sure we're not already connected. */
|
||||
if (tty->disc_data != NULL) {
|
||||
priv = tty->disc_data;
|
||||
if (priv && priv->magic == IRTTY_MAGIC) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
tty->disc_data = NULL; /* ### */
|
||||
}
|
||||
|
||||
/* stop the underlying driver */
|
||||
irtty_stop_receiver(tty, TRUE);
|
||||
if (tty->ops->stop)
|
||||
|
@ -796,14 +796,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
|
||||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
extern struct of_device_id __earlycon_of_table[];
|
||||
|
||||
static int __init early_init_dt_scan_chosen_serial(void)
|
||||
{
|
||||
int offset;
|
||||
const char *p;
|
||||
const char *p, *q, *options = NULL;
|
||||
int l;
|
||||
const struct of_device_id *match = __earlycon_of_table;
|
||||
const struct earlycon_id *match;
|
||||
const void *fdt = initial_boot_params;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
@ -818,27 +817,26 @@ static int __init early_init_dt_scan_chosen_serial(void)
|
||||
if (!p || !l)
|
||||
return -ENOENT;
|
||||
|
||||
/* Remove console options if present */
|
||||
l = strchrnul(p, ':') - p;
|
||||
q = strchrnul(p, ':');
|
||||
if (*q != '\0')
|
||||
options = q + 1;
|
||||
l = q - p;
|
||||
|
||||
/* Get the node specified by stdout-path */
|
||||
offset = fdt_path_offset_namelen(fdt, p, l);
|
||||
if (offset < 0)
|
||||
return -ENODEV;
|
||||
if (offset < 0) {
|
||||
pr_warn("earlycon: stdout-path %.*s not found\n", l, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (match->compatible[0]) {
|
||||
u64 addr;
|
||||
|
||||
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
|
||||
match++;
|
||||
for (match = __earlycon_table; match < __earlycon_table_end; match++) {
|
||||
if (!match->compatible[0])
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = fdt_translate_address(fdt, offset);
|
||||
if (addr == OF_BAD_ADDR)
|
||||
return -ENXIO;
|
||||
if (fdt_node_check_compatible(fdt, offset, match->compatible))
|
||||
continue;
|
||||
|
||||
of_setup_earlycon(addr, match->data);
|
||||
of_setup_earlycon(match, offset, options);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
|
@ -161,7 +161,7 @@ static int __init fdt_translate_one(const void *blob, int parent,
|
||||
* that can be mapped to a cpu physical address). This is not really specified
|
||||
* that way, but this is traditionally the way IBM at least do things
|
||||
*/
|
||||
u64 __init fdt_translate_address(const void *blob, int node_offset)
|
||||
static u64 __init fdt_translate_address(const void *blob, int node_offset)
|
||||
{
|
||||
int parent, len;
|
||||
const struct of_bus *bus, *pbus;
|
||||
@ -239,3 +239,12 @@ u64 __init fdt_translate_address(const void *blob, int node_offset)
|
||||
bail:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_flat_dt_translate_address - translate DT addr into CPU phys addr
|
||||
* @node: node in the flat blob
|
||||
*/
|
||||
u64 __init of_flat_dt_translate_address(unsigned long node)
|
||||
{
|
||||
return fdt_translate_address(initial_boot_params, node);
|
||||
}
|
||||
|
@ -643,7 +643,6 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
||||
if ((raw->flags & RAW3215_WORKING) ||
|
||||
raw->queued_write != NULL ||
|
||||
raw->queued_read != NULL) {
|
||||
raw->port.flags |= ASYNC_CLOSING;
|
||||
add_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
@ -651,7 +650,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
remove_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
|
||||
raw->port.flags &= ~ASYNC_INITIALIZED;
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
}
|
||||
|
@ -1530,7 +1530,7 @@ static void dgap_input(struct channel_t *ch)
|
||||
if ((bd->state != BOARD_READY) || !tp ||
|
||||
(tp->magic != TTY_MAGIC) ||
|
||||
!(ch->ch_tun.un_flags & UN_ISOPEN) ||
|
||||
!(tp->termios.c_cflag & CREAD) ||
|
||||
!C_CREAD(tp) ||
|
||||
(ch->ch_tun.un_flags & UN_CLOSING)) {
|
||||
writew(head, &bs->rx_tail);
|
||||
writeb(1, &bs->idata);
|
||||
@ -1665,9 +1665,7 @@ static void dgap_input(struct channel_t *ch)
|
||||
}
|
||||
|
||||
static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
|
||||
struct un_t *un, u32 mask,
|
||||
unsigned long *irq_flags1,
|
||||
unsigned long *irq_flags2)
|
||||
struct un_t *un, u32 mask)
|
||||
{
|
||||
if (!(un->un_flags & mask))
|
||||
return;
|
||||
@ -1677,17 +1675,7 @@ static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
|
||||
if (!(un->un_flags & UN_ISOPEN))
|
||||
return;
|
||||
|
||||
if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
||||
un->un_tty->ldisc->ops->write_wakeup) {
|
||||
spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2);
|
||||
spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1);
|
||||
|
||||
(un->un_tty->ldisc->ops->write_wakeup)(un->un_tty);
|
||||
|
||||
spin_lock_irqsave(&bd->bd_lock, *irq_flags1);
|
||||
spin_lock_irqsave(&ch->ch_lock, *irq_flags2);
|
||||
}
|
||||
wake_up_interruptible(&un->un_tty->write_wait);
|
||||
tty_wakeup(un->un_tty);
|
||||
wake_up_interruptible(&un->un_flags_wait);
|
||||
}
|
||||
|
||||
@ -1952,10 +1940,8 @@ static int dgap_event(struct board_t *bd)
|
||||
* Process Transmit low.
|
||||
*/
|
||||
if (reason & IFTLW) {
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW,
|
||||
&lock_flags, &lock_flags2);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW,
|
||||
&lock_flags, &lock_flags2);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW);
|
||||
if (ch->ch_flags & CH_WLOW) {
|
||||
ch->ch_flags &= ~CH_WLOW;
|
||||
wake_up_interruptible(&ch->ch_flags_wait);
|
||||
@ -1966,10 +1952,8 @@ static int dgap_event(struct board_t *bd)
|
||||
* Process Transmit empty.
|
||||
*/
|
||||
if (reason & IFTEM) {
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY,
|
||||
&lock_flags, &lock_flags2);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY,
|
||||
&lock_flags, &lock_flags2);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY);
|
||||
dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY);
|
||||
if (ch->ch_flags & CH_WEMPTY) {
|
||||
ch->ch_flags &= ~CH_WEMPTY;
|
||||
wake_up_interruptible(&ch->ch_flags_wait);
|
||||
@ -3171,8 +3155,6 @@ static void dgap_tty_flush_buffer(struct tty_struct *tty)
|
||||
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
|
||||
spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
|
||||
if (waitqueue_active(&tty->write_wait))
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
|
||||
@ -4969,10 +4951,6 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||
ch->ch_pun.un_flags &= ~(UN_LOW | UN_EMPTY);
|
||||
wake_up_interruptible(&ch->ch_pun.un_flags_wait);
|
||||
}
|
||||
if (waitqueue_active(&tty->write_wait))
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
|
||||
/* Can't hold any locks when calling tty_wakeup! */
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
|
||||
spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
|
||||
tty_wakeup(tty);
|
||||
|
@ -541,7 +541,7 @@ void dgnc_input(struct channel_t *ch)
|
||||
*/
|
||||
if (!tp || (tp->magic != TTY_MAGIC) ||
|
||||
!(ch->ch_tun.un_flags & UN_ISOPEN) ||
|
||||
!(tp->termios.c_cflag & CREAD) ||
|
||||
!C_CREAD(tp) ||
|
||||
(ch->ch_tun.un_flags & UN_CLOSING)) {
|
||||
ch->ch_r_head = tail;
|
||||
|
||||
@ -933,14 +933,7 @@ void dgnc_wakeup_writes(struct channel_t *ch)
|
||||
}
|
||||
|
||||
if (ch->ch_tun.un_flags & UN_ISOPEN) {
|
||||
if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
||||
ch->ch_tun.un_tty->ldisc->ops->write_wakeup) {
|
||||
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
||||
ch->ch_tun.un_tty->ldisc->ops->write_wakeup(ch->ch_tun.un_tty);
|
||||
spin_lock_irqsave(&ch->ch_lock, flags);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
|
||||
tty_wakeup(ch->ch_tun.un_tty);
|
||||
|
||||
/*
|
||||
* If unit is set to wait until empty, check to make sure
|
||||
@ -975,14 +968,7 @@ void dgnc_wakeup_writes(struct channel_t *ch)
|
||||
}
|
||||
|
||||
if (ch->ch_pun.un_flags & UN_ISOPEN) {
|
||||
if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
||||
ch->ch_pun.un_tty->ldisc->ops->write_wakeup) {
|
||||
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
||||
ch->ch_pun.un_tty->ldisc->ops->write_wakeup(ch->ch_pun.un_tty);
|
||||
spin_lock_irqsave(&ch->ch_lock, flags);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
|
||||
tty_wakeup(ch->ch_pun.un_tty);
|
||||
|
||||
/*
|
||||
* If unit is set to wait until empty, check to make sure
|
||||
|
@ -226,7 +226,7 @@ config CYCLADES
|
||||
|
||||
config CYZ_INTR
|
||||
bool "Cyclades-Z interrupt mode operation"
|
||||
depends on CYCLADES
|
||||
depends on CYCLADES && PCI
|
||||
help
|
||||
The Cyclades-Z family of multiport cards allows 2 (two) driver op
|
||||
modes: polling and interrupt. In polling mode, the driver will check
|
||||
|
@ -639,7 +639,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
|
||||
custom.adkcon = AC_UARTBRK;
|
||||
mb();
|
||||
|
||||
if (tty->termios.c_cflag & HUPCL)
|
||||
if (C_HUPCL(tty))
|
||||
info->MCR &= ~(SER_DTR|SER_RTS);
|
||||
rtsdtr_ctrl(info->MCR);
|
||||
|
||||
@ -965,8 +965,7 @@ static void rs_throttle(struct tty_struct * tty)
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
printk("throttle %s: %d....\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
printk("throttle %s ....\n", tty_name(tty));
|
||||
#endif
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
|
||||
@ -975,7 +974,7 @@ static void rs_throttle(struct tty_struct * tty)
|
||||
if (I_IXOFF(tty))
|
||||
rs_send_xchar(tty, STOP_CHAR(tty));
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
info->MCR &= ~SER_RTS;
|
||||
|
||||
local_irq_save(flags);
|
||||
@ -988,8 +987,7 @@ static void rs_unthrottle(struct tty_struct * tty)
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
printk("unthrottle %s: %d....\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
printk("unthrottle %s ....\n", tty_name(tty));
|
||||
#endif
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
|
||||
@ -1001,7 +999,7 @@ static void rs_unthrottle(struct tty_struct * tty)
|
||||
else
|
||||
rs_send_xchar(tty, START_CHAR(tty));
|
||||
}
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
info->MCR |= SER_RTS;
|
||||
local_irq_save(flags);
|
||||
rtsdtr_ctrl(info->MCR);
|
||||
@ -1334,8 +1332,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
change_speed(tty, info, old_termios);
|
||||
|
||||
/* Handle transition to B0 status */
|
||||
if ((old_termios->c_cflag & CBAUD) &&
|
||||
!(cflag & CBAUD)) {
|
||||
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
|
||||
info->MCR &= ~(SER_DTR|SER_RTS);
|
||||
local_irq_save(flags);
|
||||
rtsdtr_ctrl(info->MCR);
|
||||
@ -1343,21 +1340,17 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
}
|
||||
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) &&
|
||||
(cflag & CBAUD)) {
|
||||
if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
|
||||
info->MCR |= SER_DTR;
|
||||
if (!(tty->termios.c_cflag & CRTSCTS) ||
|
||||
!test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
info->MCR |= SER_RTS;
|
||||
}
|
||||
local_irq_save(flags);
|
||||
rtsdtr_ctrl(info->MCR);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* Handle turning off CRTSCTS */
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
||||
tty->hw_stopped = 0;
|
||||
rs_start(tty);
|
||||
}
|
||||
@ -1369,8 +1362,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
* XXX It's not clear whether the current behavior is correct
|
||||
* or not. Hence, this may change.....
|
||||
*/
|
||||
if (!(old_termios->c_cflag & CLOCAL) &&
|
||||
(tty->termios.c_cflag & CLOCAL))
|
||||
if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
#endif
|
||||
}
|
||||
|
@ -1440,7 +1440,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
||||
info->port.xmit_buf = NULL;
|
||||
free_page((unsigned long)temp);
|
||||
}
|
||||
if (tty->termios.c_cflag & HUPCL)
|
||||
if (C_HUPCL(tty))
|
||||
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
|
||||
|
||||
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
|
||||
@ -1469,7 +1469,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
||||
free_page((unsigned long)temp);
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & HUPCL)
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(&info->port);
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
@ -2795,8 +2795,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
|
||||
cy_set_line_char(info, tty);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
||||
tty->hw_stopped = 0;
|
||||
cy_start(tty);
|
||||
}
|
||||
@ -2807,8 +2806,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
* XXX It's not clear whether the current behavior is correct
|
||||
* or not. Hence, this may change.....
|
||||
*/
|
||||
if (!(old_termios->c_cflag & CLOCAL) &&
|
||||
(tty->termios.c_cflag & CLOCAL))
|
||||
if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
#endif
|
||||
} /* cy_set_termios */
|
||||
@ -2852,8 +2850,8 @@ static void cy_throttle(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CY_DEBUG_THROTTLE
|
||||
printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty), info->line);
|
||||
printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
|
||||
info->line);
|
||||
#endif
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "cy_throttle"))
|
||||
@ -2868,7 +2866,7 @@ static void cy_throttle(struct tty_struct *tty)
|
||||
info->throttle = 1;
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
|
||||
@ -2891,8 +2889,8 @@ static void cy_unthrottle(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CY_DEBUG_THROTTLE
|
||||
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
|
||||
tty_name(tty), tty_chars_in_buffer(tty), info->line);
|
||||
printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
|
||||
tty_name(tty), info->line);
|
||||
#endif
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
|
||||
@ -2905,7 +2903,7 @@ static void cy_unthrottle(struct tty_struct *tty)
|
||||
cy_send_xchar(tty, START_CHAR(tty));
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
card = info->card;
|
||||
if (!cy_is_Z(card)) {
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
|
@ -23,7 +23,6 @@
|
||||
* byte channel used for the console is designated as the default tty.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
@ -719,19 +718,6 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ehv_bc_tty_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
tty_unregister_device(ehv_bc_driver, bc - bcs);
|
||||
|
||||
tty_port_destroy(&bc->port);
|
||||
irq_dispose_mapping(bc->tx_irq);
|
||||
irq_dispose_mapping(bc->rx_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ehv_bc_tty_of_ids[] = {
|
||||
{ .compatible = "epapr,hv-byte-channel" },
|
||||
{}
|
||||
@ -741,15 +727,15 @@ static struct platform_driver ehv_bc_tty_driver = {
|
||||
.driver = {
|
||||
.name = "ehv-bc",
|
||||
.of_match_table = ehv_bc_tty_of_ids,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = ehv_bc_tty_probe,
|
||||
.remove = ehv_bc_tty_remove,
|
||||
};
|
||||
|
||||
/**
|
||||
* ehv_bc_init - ePAPR hypervisor byte channel driver initialization
|
||||
*
|
||||
* This function is called when this module is loaded.
|
||||
* This function is called when this driver is loaded.
|
||||
*/
|
||||
static int __init ehv_bc_init(void)
|
||||
{
|
||||
@ -814,24 +800,4 @@ error:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ehv_bc_exit - ePAPR hypervisor byte channel driver termination
|
||||
*
|
||||
* This function is called when this driver is unloaded.
|
||||
*/
|
||||
static void __exit ehv_bc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ehv_bc_tty_driver);
|
||||
tty_unregister_driver(ehv_bc_driver);
|
||||
put_tty_driver(ehv_bc_driver);
|
||||
kfree(bcs);
|
||||
}
|
||||
|
||||
module_init(ehv_bc_init);
|
||||
module_exit(ehv_bc_exit);
|
||||
|
||||
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
|
||||
MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
device_initcall(ehv_bc_init);
|
||||
|
@ -68,8 +68,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
|
||||
|
||||
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
|
||||
struct goldfish_tty *qtty = dev_id;
|
||||
void __iomem *base = qtty->base;
|
||||
unsigned long irq_flags;
|
||||
unsigned char *buf;
|
||||
@ -162,7 +161,7 @@ static int goldfish_tty_console_setup(struct console *co, char *options)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tty_port_operations goldfish_port_ops = {
|
||||
static const struct tty_port_operations goldfish_port_ops = {
|
||||
.activate = goldfish_tty_activate,
|
||||
.shutdown = goldfish_tty_shutdown
|
||||
};
|
||||
@ -233,6 +232,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
struct device *ttydev;
|
||||
void __iomem *base;
|
||||
u32 irq;
|
||||
unsigned int line;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL)
|
||||
@ -248,10 +248,16 @@ static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
|
||||
irq = r->start;
|
||||
|
||||
if (pdev->id >= goldfish_tty_line_count)
|
||||
goto err_unmap;
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
|
||||
if (pdev->id == PLATFORM_DEVID_NONE)
|
||||
line = goldfish_tty_current_line_count;
|
||||
else
|
||||
line = pdev->id;
|
||||
|
||||
if (line >= goldfish_tty_line_count)
|
||||
goto err_create_driver_failed;
|
||||
|
||||
if (goldfish_tty_current_line_count == 0) {
|
||||
ret = goldfish_tty_create_driver();
|
||||
if (ret)
|
||||
@ -259,7 +265,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
}
|
||||
goldfish_tty_current_line_count++;
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
qtty = &goldfish_ttys[line];
|
||||
spin_lock_init(&qtty->lock);
|
||||
tty_port_init(&qtty->port);
|
||||
qtty->port.ops = &goldfish_port_ops;
|
||||
@ -269,13 +275,13 @@ static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
|
||||
|
||||
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
|
||||
"goldfish_tty", pdev);
|
||||
"goldfish_tty", qtty);
|
||||
if (ret)
|
||||
goto err_request_irq_failed;
|
||||
|
||||
|
||||
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
|
||||
pdev->id, &pdev->dev);
|
||||
line, &pdev->dev);
|
||||
if (IS_ERR(ttydev)) {
|
||||
ret = PTR_ERR(ttydev);
|
||||
goto err_tty_register_device_failed;
|
||||
@ -286,8 +292,9 @@ static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
qtty->console.device = goldfish_tty_console_device;
|
||||
qtty->console.setup = goldfish_tty_console_setup;
|
||||
qtty->console.flags = CON_PRINTBUFFER;
|
||||
qtty->console.index = pdev->id;
|
||||
qtty->console.index = line;
|
||||
register_console(&qtty->console);
|
||||
platform_set_drvdata(pdev, qtty);
|
||||
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
return 0;
|
||||
@ -307,13 +314,12 @@ err_unmap:
|
||||
|
||||
static int goldfish_tty_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_tty *qtty;
|
||||
struct goldfish_tty *qtty = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
unregister_console(&qtty->console);
|
||||
tty_unregister_device(goldfish_tty_driver, pdev->id);
|
||||
tty_unregister_device(goldfish_tty_driver, qtty->console.index);
|
||||
iounmap(qtty->base);
|
||||
qtty->base = NULL;
|
||||
free_irq(qtty->irq, pdev);
|
||||
@ -324,11 +330,19 @@ static int goldfish_tty_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id goldfish_tty_of_match[] = {
|
||||
{ .compatible = "google,goldfish-tty", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
|
||||
|
||||
static struct platform_driver goldfish_tty_platform_driver = {
|
||||
.probe = goldfish_tty_probe,
|
||||
.remove = goldfish_tty_remove,
|
||||
.driver = {
|
||||
.name = "goldfish_tty"
|
||||
.name = "goldfish_tty",
|
||||
.of_match_table = goldfish_tty_of_match,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/hvconsole.h>
|
||||
#include <asm/vio.h>
|
||||
@ -61,7 +60,6 @@ static struct vio_device_id hvc_driver_table[] = {
|
||||
#endif
|
||||
{ "", "" }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(vio, hvc_driver_table);
|
||||
|
||||
typedef enum hv_protocol {
|
||||
HV_PROTOCOL_RAW,
|
||||
@ -363,26 +361,13 @@ static int hvc_vio_probe(struct vio_dev *vdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hvc_vio_remove(struct vio_dev *vdev)
|
||||
{
|
||||
struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
|
||||
int rc, termno;
|
||||
|
||||
termno = hp->vtermno;
|
||||
rc = hvc_remove(hp);
|
||||
if (rc == 0) {
|
||||
if (hvterm_privs[termno] != &hvterm_priv0)
|
||||
kfree(hvterm_privs[termno]);
|
||||
hvterm_privs[termno] = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct vio_driver hvc_vio_driver = {
|
||||
.id_table = hvc_driver_table,
|
||||
.probe = hvc_vio_probe,
|
||||
.remove = hvc_vio_remove,
|
||||
.name = hvc_driver_name,
|
||||
.driver = {
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init hvc_vio_init(void)
|
||||
@ -394,13 +379,7 @@ static int __init hvc_vio_init(void)
|
||||
|
||||
return rc;
|
||||
}
|
||||
module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
|
||||
|
||||
static void __exit hvc_vio_exit(void)
|
||||
{
|
||||
vio_unregister_driver(&hvc_vio_driver);
|
||||
}
|
||||
module_exit(hvc_vio_exit);
|
||||
device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */
|
||||
|
||||
void __init hvc_vio_init_early(void)
|
||||
{
|
||||
|
@ -162,7 +162,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
|
||||
return recv;
|
||||
}
|
||||
|
||||
static struct hv_ops domU_hvc_ops = {
|
||||
static const struct hv_ops domU_hvc_ops = {
|
||||
.get_chars = domU_read_console,
|
||||
.put_chars = domU_write_console,
|
||||
.notifier_add = notifier_add_irq,
|
||||
@ -188,7 +188,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct hv_ops dom0_hvc_ops = {
|
||||
static const struct hv_ops dom0_hvc_ops = {
|
||||
.get_chars = dom0_read_console,
|
||||
.put_chars = dom0_write_console,
|
||||
.notifier_add = notifier_add_irq,
|
||||
@ -323,6 +323,7 @@ void xen_console_resume(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HVC_XEN_FRONTEND
|
||||
static void xencons_disconnect_backend(struct xencons_info *info)
|
||||
{
|
||||
if (info->irq > 0)
|
||||
@ -363,7 +364,6 @@ static int xen_console_remove(struct xencons_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HVC_XEN_FRONTEND
|
||||
static int xencons_remove(struct xenbus_device *dev)
|
||||
{
|
||||
return xen_console_remove(dev_get_drvdata(&dev->dev));
|
||||
|
@ -1204,8 +1204,7 @@ static void isicom_set_termios(struct tty_struct *tty,
|
||||
isicom_config_port(tty);
|
||||
spin_unlock_irqrestore(&port->card->card_lock, flags);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
||||
tty->hw_stopped = 0;
|
||||
isicom_start(tty);
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ struct mxser_port {
|
||||
int xmit_head;
|
||||
int xmit_tail;
|
||||
int xmit_cnt;
|
||||
int closing;
|
||||
|
||||
struct ktermios normal_termios;
|
||||
|
||||
@ -1081,6 +1082,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
||||
return;
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
info->closing = 1;
|
||||
mutex_lock(&port->mutex);
|
||||
mxser_close_port(port);
|
||||
mxser_flush_buffer(tty);
|
||||
@ -1091,6 +1093,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
||||
mxser_shutdown_port(port);
|
||||
clear_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
mutex_unlock(&port->mutex);
|
||||
info->closing = 0;
|
||||
/* Right now the tty_port set is done outside of the close_end helper
|
||||
as we don't yet have everyone using refcounts */
|
||||
tty_port_close_end(port, tty);
|
||||
@ -1864,7 +1867,7 @@ static void mxser_stoprx(struct tty_struct *tty)
|
||||
}
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
info->MCR &= ~UART_MCR_RTS;
|
||||
outb(info->MCR, info->ioaddr + UART_MCR);
|
||||
}
|
||||
@ -1901,7 +1904,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
|
||||
}
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
info->MCR |= UART_MCR_RTS;
|
||||
outb(info->MCR, info->ioaddr + UART_MCR);
|
||||
}
|
||||
@ -1949,15 +1952,13 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
|
||||
mxser_change_speed(tty, old_termios);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
||||
tty->hw_stopped = 0;
|
||||
mxser_start(tty);
|
||||
}
|
||||
|
||||
/* Handle sw stopped */
|
||||
if ((old_termios->c_iflag & IXON) &&
|
||||
!(tty->termios.c_iflag & IXON)) {
|
||||
if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
|
||||
tty->stopped = 0;
|
||||
|
||||
if (info->board->chip_flag) {
|
||||
@ -2255,10 +2256,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
|
||||
break;
|
||||
iir &= MOXA_MUST_IIR_MASK;
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty ||
|
||||
(port->port.flags & ASYNC_CLOSING) ||
|
||||
!(port->port.flags &
|
||||
ASYNC_INITIALIZED)) {
|
||||
if (!tty || port->closing ||
|
||||
!(port->port.flags & ASYNC_INITIALIZED)) {
|
||||
status = inb(port->ioaddr + UART_LSR);
|
||||
outb(0x27, port->ioaddr + UART_FCR);
|
||||
inb(port->ioaddr + UART_MSR);
|
||||
@ -2337,7 +2336,7 @@ static const struct tty_operations mxser_ops = {
|
||||
.get_icount = mxser_get_icount,
|
||||
};
|
||||
|
||||
static struct tty_port_operations mxser_port_ops = {
|
||||
static const struct tty_port_operations mxser_port_ops = {
|
||||
.carrier_raised = mxser_carrier_raised,
|
||||
.dtr_rts = mxser_dtr_rts,
|
||||
.activate = mxser_activate,
|
||||
|
@ -1066,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||||
/* Carrier drop -> hangup */
|
||||
if (tty) {
|
||||
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
|
||||
if (!(tty->termios.c_cflag & CLOCAL))
|
||||
if (!C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
}
|
||||
if (brk & 0x01)
|
||||
@ -2303,21 +2303,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
/* If clogged call tty_throttle(tty); */
|
||||
}
|
||||
|
||||
/**
|
||||
* gsmld_chars_in_buffer - report available bytes
|
||||
* @tty: tty device
|
||||
*
|
||||
* Report the number of characters buffered to be delivered to user
|
||||
* at this instant in time.
|
||||
*
|
||||
* Locking: gsm lock
|
||||
*/
|
||||
|
||||
static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsmld_flush_buffer - clean input queue
|
||||
* @tty: terminal device
|
||||
@ -2830,7 +2815,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
|
||||
.open = gsmld_open,
|
||||
.close = gsmld_close,
|
||||
.flush_buffer = gsmld_flush_buffer,
|
||||
.chars_in_buffer = gsmld_chars_in_buffer,
|
||||
.read = gsmld_read,
|
||||
.write = gsmld_write,
|
||||
.ioctl = gsmld_ioctl,
|
||||
@ -3132,7 +3116,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
dlci->modem_tx &= ~TIOCM_DTR;
|
||||
dlci->throttled = 1;
|
||||
/* Send an MSC with DTR cleared */
|
||||
@ -3144,7 +3128,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
dlci->modem_tx |= TIOCM_DTR;
|
||||
dlci->throttled = 0;
|
||||
/* Send an MSC with DTR set */
|
||||
|
@ -159,7 +159,6 @@ struct n_hdlc {
|
||||
/*
|
||||
* HDLC buffer list manipulation functions
|
||||
*/
|
||||
static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
|
||||
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
|
||||
struct n_hdlc_buf *buf);
|
||||
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
|
||||
@ -853,10 +852,10 @@ static struct n_hdlc *n_hdlc_alloc(void)
|
||||
if (!n_hdlc)
|
||||
return NULL;
|
||||
|
||||
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
|
||||
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
|
||||
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
|
||||
n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
|
||||
spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
|
||||
spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
|
||||
spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
|
||||
spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
|
||||
|
||||
/* allocate free rx buffer list */
|
||||
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
|
||||
@ -884,16 +883,6 @@ static struct n_hdlc *n_hdlc_alloc(void)
|
||||
|
||||
} /* end of n_hdlc_alloc() */
|
||||
|
||||
/**
|
||||
* n_hdlc_buf_list_init - initialize specified HDLC buffer list
|
||||
* @list - pointer to buffer list
|
||||
*/
|
||||
static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
|
||||
{
|
||||
memset(list, 0, sizeof(*list));
|
||||
spin_lock_init(&list->spinlock);
|
||||
} /* end of n_hdlc_buf_list_init() */
|
||||
|
||||
/**
|
||||
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
|
||||
* @list - pointer to buffer list
|
||||
|
@ -113,8 +113,6 @@ struct n_tty_data {
|
||||
DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
|
||||
unsigned char echo_buf[N_TTY_BUF_SIZE];
|
||||
|
||||
int minimum_to_wake;
|
||||
|
||||
/* consumer-published */
|
||||
size_t read_tail;
|
||||
size_t line_start;
|
||||
@ -153,15 +151,6 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
|
||||
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
|
||||
}
|
||||
|
||||
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
|
||||
unsigned char __user *ptr)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
|
||||
tty_audit_add_data(tty, &x, 1, ldata->icanon);
|
||||
return put_user(x, ptr);
|
||||
}
|
||||
|
||||
static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
|
||||
size_t tail, size_t n)
|
||||
{
|
||||
@ -171,7 +160,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
|
||||
int uncopied;
|
||||
|
||||
if (n > size) {
|
||||
tty_audit_add_data(tty, from, size, ldata->icanon);
|
||||
tty_audit_add_data(tty, from, size);
|
||||
uncopied = copy_to_user(to, from, size);
|
||||
if (uncopied)
|
||||
return uncopied;
|
||||
@ -180,7 +169,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
|
||||
from = ldata->read_buf;
|
||||
}
|
||||
|
||||
tty_audit_add_data(tty, from, n, ldata->icanon);
|
||||
tty_audit_add_data(tty, from, n);
|
||||
return copy_to_user(to, from, n);
|
||||
}
|
||||
|
||||
@ -239,8 +228,8 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
|
||||
|
||||
static void n_tty_write_wakeup(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
|
||||
}
|
||||
|
||||
static void n_tty_check_throttle(struct tty_struct *tty)
|
||||
@ -272,8 +261,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
|
||||
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
||||
return;
|
||||
if (!tty->count)
|
||||
return;
|
||||
n_tty_kick_worker(tty);
|
||||
tty_wakeup(tty->link);
|
||||
return;
|
||||
@ -292,8 +279,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
|
||||
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
||||
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
||||
break;
|
||||
if (!tty->count)
|
||||
break;
|
||||
n_tty_kick_worker(tty);
|
||||
unthrottled = tty_unthrottle_safe(tty);
|
||||
if (!unthrottled)
|
||||
@ -380,28 +365,6 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
up_write(&tty->termios_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_chars_in_buffer - report available bytes
|
||||
* @tty: tty device
|
||||
*
|
||||
* Report the number of characters buffered to be delivered to user
|
||||
* at this instant in time.
|
||||
*
|
||||
* Locking: exclusive termios_rwsem
|
||||
*/
|
||||
|
||||
static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__);
|
||||
|
||||
down_write(&tty->termios_rwsem);
|
||||
n = chars_in_buffer(tty);
|
||||
up_write(&tty->termios_rwsem);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_utf8_continuation - utf8 multibyte check
|
||||
* @c: byte to check
|
||||
@ -1561,8 +1524,6 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
|
||||
flag = *fp++;
|
||||
if (likely(flag == TTY_NORMAL))
|
||||
n_tty_receive_char_closing(tty, *cp++);
|
||||
else
|
||||
n_tty_receive_char_flagged(tty, *cp++, flag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1664,7 +1625,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
/* publish read_head to consumer */
|
||||
smp_store_release(&ldata->commit_head, ldata->read_head);
|
||||
|
||||
if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
|
||||
if (read_cnt(ldata)) {
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
}
|
||||
@ -1785,12 +1746,6 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
|
||||
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
|
||||
}
|
||||
|
||||
int is_ignored(int sig)
|
||||
{
|
||||
return (sigismember(¤t->blocked, sig) ||
|
||||
current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_set_termios - termios data changed
|
||||
* @tty: terminal
|
||||
@ -1937,7 +1892,6 @@ static int n_tty_open(struct tty_struct *tty)
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
ldata->column = 0;
|
||||
ldata->canon_column = 0;
|
||||
ldata->minimum_to_wake = 1;
|
||||
ldata->num_overrun = 0;
|
||||
ldata->no_room = 0;
|
||||
ldata->lnext = 0;
|
||||
@ -2015,7 +1969,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
||||
retval = copy_to_user(*b, from, n);
|
||||
n -= retval;
|
||||
is_eof = n == 1 && *from == EOF_CHAR(tty);
|
||||
tty_audit_add_data(tty, from, n, ldata->icanon);
|
||||
tty_audit_add_data(tty, from, n);
|
||||
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
|
||||
@ -2109,7 +2063,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
|
||||
ldata->line_start = ldata->read_tail;
|
||||
else
|
||||
ldata->push = 0;
|
||||
tty_audit_push(tty);
|
||||
tty_audit_push();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2200,14 +2154,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
minimum = MIN_CHAR(tty);
|
||||
if (minimum) {
|
||||
time = (HZ / 10) * TIME_CHAR(tty);
|
||||
if (time)
|
||||
ldata->minimum_to_wake = 1;
|
||||
else if (!waitqueue_active(&tty->read_wait) ||
|
||||
(ldata->minimum_to_wake > minimum))
|
||||
ldata->minimum_to_wake = minimum;
|
||||
} else {
|
||||
timeout = (HZ / 10) * TIME_CHAR(tty);
|
||||
ldata->minimum_to_wake = minimum = 1;
|
||||
minimum = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2225,19 +2174,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
cs = tty->link->ctrl_status;
|
||||
tty->link->ctrl_status = 0;
|
||||
spin_unlock_irq(&tty->link->ctrl_lock);
|
||||
if (tty_put_user(tty, cs, b++)) {
|
||||
if (put_user(cs, b)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
break;
|
||||
}
|
||||
b++;
|
||||
nr--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
|
||||
((minimum - (b - buf)) >= 1))
|
||||
ldata->minimum_to_wake = (minimum - (b - buf));
|
||||
|
||||
done = check_other_done(tty);
|
||||
|
||||
if (!input_available_p(tty, 0)) {
|
||||
@ -2275,11 +2220,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
|
||||
/* Deal with packet mode. */
|
||||
if (packet && b == buf) {
|
||||
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
|
||||
if (put_user(TIOCPKT_DATA, b)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
break;
|
||||
}
|
||||
b++;
|
||||
nr--;
|
||||
}
|
||||
|
||||
@ -2303,9 +2248,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
remove_wait_queue(&tty->read_wait, &wait);
|
||||
if (!waitqueue_active(&tty->read_wait))
|
||||
ldata->minimum_to_wake = minimum;
|
||||
|
||||
mutex_unlock(&ldata->atomic_read_lock);
|
||||
|
||||
if (b - buf)
|
||||
@ -2417,7 +2359,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
break_out:
|
||||
remove_wait_queue(&tty->write_wait, &wait);
|
||||
if (b - buf != nr && tty->fasync)
|
||||
if (nr && tty->fasync)
|
||||
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
up_read(&tty->termios_rwsem);
|
||||
return (b - buf) ? b - buf : retval;
|
||||
@ -2440,7 +2382,6 @@ break_out:
|
||||
static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned int mask = 0;
|
||||
|
||||
poll_wait(file, &tty->read_wait, wait);
|
||||
@ -2453,12 +2394,6 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
|
||||
mask |= POLLPRI | POLLIN | POLLRDNORM;
|
||||
if (tty_hung_up_p(file))
|
||||
mask |= POLLHUP;
|
||||
if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
|
||||
if (MIN_CHAR(tty) && !TIME_CHAR(tty))
|
||||
ldata->minimum_to_wake = MIN_CHAR(tty);
|
||||
else
|
||||
ldata->minimum_to_wake = 1;
|
||||
}
|
||||
if (tty->ops->write && !tty_is_writelocked(tty) &&
|
||||
tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
|
||||
tty_write_room(tty) > 0)
|
||||
@ -2507,25 +2442,12 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
}
|
||||
|
||||
static void n_tty_fasync(struct tty_struct *tty, int on)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
|
||||
if (!waitqueue_active(&tty->read_wait)) {
|
||||
if (on)
|
||||
ldata->minimum_to_wake = 1;
|
||||
else if (!tty->fasync)
|
||||
ldata->minimum_to_wake = N_TTY_BUF_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
struct tty_ldisc_ops tty_ldisc_N_TTY = {
|
||||
static struct tty_ldisc_ops n_tty_ops = {
|
||||
.magic = TTY_LDISC_MAGIC,
|
||||
.name = "n_tty",
|
||||
.open = n_tty_open,
|
||||
.close = n_tty_close,
|
||||
.flush_buffer = n_tty_flush_buffer,
|
||||
.chars_in_buffer = n_tty_chars_in_buffer,
|
||||
.read = n_tty_read,
|
||||
.write = n_tty_write,
|
||||
.ioctl = n_tty_ioctl,
|
||||
@ -2533,7 +2455,6 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
|
||||
.poll = n_tty_poll,
|
||||
.receive_buf = n_tty_receive_buf,
|
||||
.write_wakeup = n_tty_write_wakeup,
|
||||
.fasync = n_tty_fasync,
|
||||
.receive_buf2 = n_tty_receive_buf2,
|
||||
};
|
||||
|
||||
@ -2541,14 +2462,18 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
|
||||
* n_tty_inherit_ops - inherit N_TTY methods
|
||||
* @ops: struct tty_ldisc_ops where to save N_TTY methods
|
||||
*
|
||||
* Enables a 'subclass' line discipline to 'inherit' N_TTY
|
||||
* methods.
|
||||
* Enables a 'subclass' line discipline to 'inherit' N_TTY methods.
|
||||
*/
|
||||
|
||||
void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
|
||||
{
|
||||
*ops = tty_ldisc_N_TTY;
|
||||
*ops = n_tty_ops;
|
||||
ops->owner = NULL;
|
||||
ops->refcount = ops->flags = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
|
||||
|
||||
void __init n_tty_init(void)
|
||||
{
|
||||
tty_register_ldisc(N_TTY, &n_tty_ops);
|
||||
}
|
||||
|
@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
int i, ret;
|
||||
|
||||
read_mem32((u32 *) &size, addr, 4);
|
||||
size = __le32_to_cpu(readl(addr));
|
||||
/* DBG1( "%d bytes port: %d", size, index); */
|
||||
|
||||
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
|
@ -263,8 +263,7 @@ static void pty_set_termios(struct tty_struct *tty,
|
||||
{
|
||||
/* See if packet mode change of state. */
|
||||
if (tty->link && tty->link->packet) {
|
||||
int extproc = (old_termios->c_lflag & EXTPROC) |
|
||||
(tty->termios.c_lflag & EXTPROC);
|
||||
int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
|
||||
int old_flow = ((old_termios->c_iflag & IXON) &&
|
||||
(old_termios->c_cc[VSTOP] == '\023') &&
|
||||
(old_termios->c_cc[VSTART] == '\021'));
|
||||
@ -406,13 +405,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
||||
if (legacy) {
|
||||
/* We always use new tty termios data so we can do this
|
||||
the easy way .. */
|
||||
retval = tty_init_termios(tty);
|
||||
if (retval)
|
||||
goto err_deinit_tty;
|
||||
|
||||
retval = tty_init_termios(o_tty);
|
||||
if (retval)
|
||||
goto err_free_termios;
|
||||
tty_init_termios(tty);
|
||||
tty_init_termios(o_tty);
|
||||
|
||||
driver->other->ttys[idx] = o_tty;
|
||||
driver->ttys[idx] = tty;
|
||||
@ -444,12 +438,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
||||
tty->count++;
|
||||
o_tty->count++;
|
||||
return 0;
|
||||
err_free_termios:
|
||||
if (legacy)
|
||||
tty_free_termios(tty);
|
||||
err_deinit_tty:
|
||||
deinitialize_tty_struct(o_tty);
|
||||
free_tty_struct(o_tty);
|
||||
|
||||
err_put_module:
|
||||
module_put(driver->other->owner);
|
||||
err:
|
||||
@ -666,20 +655,13 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
||||
return tty;
|
||||
}
|
||||
|
||||
/* We have no need to install and remove our tty objects as devpts does all
|
||||
the work for us */
|
||||
|
||||
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
return pty_common_install(driver, tty, false);
|
||||
}
|
||||
|
||||
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
}
|
||||
|
||||
/* this is called once with whichever end is closed last */
|
||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
struct inode *ptmx_inode;
|
||||
|
||||
@ -704,7 +686,6 @@ static const struct tty_operations ptm_unix98_ops = {
|
||||
.unthrottle = pty_unthrottle,
|
||||
.ioctl = pty_unix98_ioctl,
|
||||
.resize = pty_resize,
|
||||
.shutdown = pty_unix98_shutdown,
|
||||
.cleanup = pty_cleanup
|
||||
};
|
||||
|
||||
@ -722,7 +703,6 @@ static const struct tty_operations pty_unix98_ops = {
|
||||
.set_termios = pty_set_termios,
|
||||
.start = pty_start,
|
||||
.stop = pty_stop,
|
||||
.shutdown = pty_unix98_shutdown,
|
||||
.cleanup = pty_cleanup,
|
||||
};
|
||||
|
||||
|
@ -643,7 +643,6 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
|
||||
info->chan = chan;
|
||||
tty_port_init(&info->port);
|
||||
info->port.ops = &rocket_port_ops;
|
||||
init_completion(&info->close_wait);
|
||||
info->flags &= ~ROCKET_MODE_MASK;
|
||||
switch (pc104[board][line]) {
|
||||
case 422:
|
||||
@ -960,7 +959,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
configure_r_port(tty, info, NULL);
|
||||
if (tty->termios.c_cflag & CBAUD) {
|
||||
if (C_BAUD(tty)) {
|
||||
sSetDTR(cp);
|
||||
sSetRTS(cp);
|
||||
}
|
||||
@ -1043,13 +1042,12 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
|
||||
}
|
||||
}
|
||||
spin_lock_irq(&port->lock);
|
||||
info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
|
||||
info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
|
||||
tty->closing = 0;
|
||||
spin_unlock_irq(&port->lock);
|
||||
mutex_unlock(&port->mutex);
|
||||
tty_port_tty_set(port, NULL);
|
||||
|
||||
complete_all(&info->close_wait);
|
||||
atomic_dec(&rp_num_ports_open);
|
||||
|
||||
#ifdef ROCKET_DEBUG_OPEN
|
||||
@ -1086,18 +1084,18 @@ static void rp_set_termios(struct tty_struct *tty,
|
||||
cp = &info->channel;
|
||||
|
||||
/* Handle transition to B0 status */
|
||||
if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
|
||||
if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
|
||||
sClrDTR(cp);
|
||||
sClrRTS(cp);
|
||||
}
|
||||
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
|
||||
if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
|
||||
sSetRTS(cp);
|
||||
sSetDTR(cp);
|
||||
}
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
|
||||
rp_start(tty);
|
||||
}
|
||||
|
||||
@ -1360,8 +1358,7 @@ static void rp_throttle(struct tty_struct *tty)
|
||||
struct r_port *info = tty->driver_data;
|
||||
|
||||
#ifdef ROCKET_DEBUG_THROTTLE
|
||||
printk(KERN_INFO "throttle %s: %d....\n", tty->name,
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
printk(KERN_INFO "throttle %s ....\n", tty->name);
|
||||
#endif
|
||||
|
||||
if (rocket_paranoia_check(info, "rp_throttle"))
|
||||
@ -1377,8 +1374,7 @@ static void rp_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct r_port *info = tty->driver_data;
|
||||
#ifdef ROCKET_DEBUG_THROTTLE
|
||||
printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
printk(KERN_INFO "unthrottle %s ....\n", tty->name);
|
||||
#endif
|
||||
|
||||
if (rocket_paranoia_check(info, "rp_unthrottle"))
|
||||
|
@ -1144,7 +1144,6 @@ struct r_port {
|
||||
int read_status_mask;
|
||||
int cps;
|
||||
|
||||
struct completion close_wait; /* Not yet matching the core */
|
||||
spinlock_t slock;
|
||||
struct mutex write_mtx;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -92,6 +92,18 @@ struct serial8250_config {
|
||||
#define SERIAL8250_SHARE_IRQS 0
|
||||
#endif
|
||||
|
||||
#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.irq = _irq, \
|
||||
.uartclk = 1843200, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF | (_flags), \
|
||||
}
|
||||
|
||||
#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
|
||||
|
||||
|
||||
static inline int serial_in(struct uart_8250_port *up, int offset)
|
||||
{
|
||||
return up->port.serial_in(&up->port, offset);
|
||||
@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
struct uart_8250_port *serial8250_get_port(int line);
|
||||
void serial8250_rpm_get(struct uart_8250_port *p);
|
||||
void serial8250_rpm_put(struct uart_8250_port *p);
|
||||
int serial8250_em485_init(struct uart_8250_port *p);
|
||||
void serial8250_em485_destroy(struct uart_8250_port *p);
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
/*
|
||||
|
@ -10,18 +10,11 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define PORT(_base,_irq) \
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.irq = _irq, \
|
||||
.uartclk = 1843200, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF, \
|
||||
}
|
||||
#include "8250.h"
|
||||
|
||||
static struct plat_serial8250_port accent_data[] = {
|
||||
PORT(0x330, 4),
|
||||
PORT(0x338, 4),
|
||||
SERIAL8250_PORT(0x330, 4),
|
||||
SERIAL8250_PORT(0x338, 4),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
|
||||
uart.port.regshift = 2;
|
||||
uart.port.dev = &ec->dev;
|
||||
|
||||
for (i = 0; i < info->num_ports; i ++) {
|
||||
for (i = 0; i < info->num_ports; i++) {
|
||||
uart.port.membase = info->vaddr + type->offset[i];
|
||||
uart.port.mapbase = bus_addr + type->offset[i];
|
||||
|
||||
|
146
drivers/tty/serial/8250/8250_bcm2835aux.c
Normal file
146
drivers/tty/serial/8250/8250_bcm2835aux.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Serial port driver for BCM2835AUX UART
|
||||
*
|
||||
* Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
|
||||
*
|
||||
* Based on 8250_lpc18xx.c:
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
struct bcm2835aux_data {
|
||||
struct uart_8250_port uart;
|
||||
struct clk *clk;
|
||||
int line;
|
||||
};
|
||||
|
||||
static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835aux_data *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
/* allocate the custom structure */
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* initialize data */
|
||||
spin_lock_init(&data->uart.port.lock);
|
||||
data->uart.capabilities = UART_CAP_FIFO;
|
||||
data->uart.port.dev = &pdev->dev;
|
||||
data->uart.port.regshift = 2;
|
||||
data->uart.port.type = PORT_16550;
|
||||
data->uart.port.iotype = UPIO_MEM;
|
||||
data->uart.port.fifosize = 8;
|
||||
data->uart.port.flags = UPF_SHARE_IRQ |
|
||||
UPF_FIXED_PORT |
|
||||
UPF_FIXED_TYPE |
|
||||
UPF_SKIP_TEST;
|
||||
|
||||
/* get the clock - this also enables the HW */
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
ret = PTR_ERR_OR_ZERO(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "could not get clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get the interrupt */
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "irq not found - %i", ret);
|
||||
return ret;
|
||||
}
|
||||
data->uart.port.irq = ret;
|
||||
|
||||
/* map the main registers */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "memory resource not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check for a fixed line number */
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (ret >= 0)
|
||||
data->uart.port.line = ret;
|
||||
|
||||
/* enable the clock as a last step */
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* the HW-clock divider for bcm2835aux is 8,
|
||||
* but 8250 expects a divider of 16,
|
||||
* so we have to multiply the actual clock by 2
|
||||
* to get identical baudrates.
|
||||
*/
|
||||
data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
|
||||
|
||||
/* register the port */
|
||||
ret = serial8250_register_8250_port(&data->uart);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
|
||||
ret);
|
||||
goto dis_clk;
|
||||
}
|
||||
data->line = ret;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clk:
|
||||
clk_disable_unprepare(data->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bcm2835aux_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835aux_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
serial8250_unregister_port(data->uart.port.line);
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm2835aux_serial_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-aux-uart" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
|
||||
|
||||
static struct platform_driver bcm2835aux_serial_driver = {
|
||||
.driver = {
|
||||
.name = "bcm2835-aux-uart",
|
||||
.of_match_table = bcm2835aux_serial_match,
|
||||
},
|
||||
.probe = bcm2835aux_serial_probe,
|
||||
.remove = bcm2835aux_serial_remove,
|
||||
};
|
||||
module_platform_driver(bcm2835aux_serial_driver);
|
||||
|
||||
MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
|
||||
MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -10,32 +10,25 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define PORT(_base,_irq) \
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.irq = _irq, \
|
||||
.uartclk = 1843200, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF, \
|
||||
}
|
||||
#include "8250.h"
|
||||
|
||||
static struct plat_serial8250_port boca_data[] = {
|
||||
PORT(0x100, 12),
|
||||
PORT(0x108, 12),
|
||||
PORT(0x110, 12),
|
||||
PORT(0x118, 12),
|
||||
PORT(0x120, 12),
|
||||
PORT(0x128, 12),
|
||||
PORT(0x130, 12),
|
||||
PORT(0x138, 12),
|
||||
PORT(0x140, 12),
|
||||
PORT(0x148, 12),
|
||||
PORT(0x150, 12),
|
||||
PORT(0x158, 12),
|
||||
PORT(0x160, 12),
|
||||
PORT(0x168, 12),
|
||||
PORT(0x170, 12),
|
||||
PORT(0x178, 12),
|
||||
SERIAL8250_PORT(0x100, 12),
|
||||
SERIAL8250_PORT(0x108, 12),
|
||||
SERIAL8250_PORT(0x110, 12),
|
||||
SERIAL8250_PORT(0x118, 12),
|
||||
SERIAL8250_PORT(0x120, 12),
|
||||
SERIAL8250_PORT(0x128, 12),
|
||||
SERIAL8250_PORT(0x130, 12),
|
||||
SERIAL8250_PORT(0x138, 12),
|
||||
SERIAL8250_PORT(0x140, 12),
|
||||
SERIAL8250_PORT(0x148, 12),
|
||||
SERIAL8250_PORT(0x150, 12),
|
||||
SERIAL8250_PORT(0x158, 12),
|
||||
SERIAL8250_PORT(0x160, 12),
|
||||
SERIAL8250_PORT(0x168, 12),
|
||||
SERIAL8250_PORT(0x170, 12),
|
||||
SERIAL8250_PORT(0x178, 12),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s,
|
||||
static int univ8250_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* Check whether an invalid uart number has been specified, and
|
||||
@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options)
|
||||
/* link port to console */
|
||||
port->cons = co;
|
||||
|
||||
return serial8250_console_setup(port, options, false);
|
||||
retval = serial8250_console_setup(port, options, false);
|
||||
if (retval != 0)
|
||||
port->cons = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -687,7 +691,7 @@ static int __init univ8250_console_init(void)
|
||||
}
|
||||
console_initcall(univ8250_console_init);
|
||||
|
||||
#define SERIAL8250_CONSOLE &univ8250_console
|
||||
#define SERIAL8250_CONSOLE (&univ8250_console)
|
||||
#else
|
||||
#define SERIAL8250_CONSOLE NULL
|
||||
#endif
|
||||
@ -764,6 +768,7 @@ void serial8250_suspend_port(int line)
|
||||
|
||||
uart_suspend_port(&serial8250_reg, port);
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_suspend_port);
|
||||
|
||||
/**
|
||||
* serial8250_resume_port - resume one serial port
|
||||
@ -789,6 +794,7 @@ void serial8250_resume_port(int line)
|
||||
}
|
||||
uart_resume_port(&serial8250_reg, port);
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_resume_port);
|
||||
|
||||
/*
|
||||
* Register a set of serial devices attached to a platform device. The
|
||||
@ -1068,6 +1074,15 @@ void serial8250_unregister_port(int line)
|
||||
struct uart_8250_port *uart = &serial8250_ports[line];
|
||||
|
||||
mutex_lock(&serial_mutex);
|
||||
|
||||
if (uart->em485) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&uart->port.lock, flags);
|
||||
serial8250_em485_destroy(uart);
|
||||
spin_unlock_irqrestore(&uart->port.lock, flags);
|
||||
}
|
||||
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
if (serial8250_isa_devs) {
|
||||
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
|
||||
@ -1093,9 +1108,8 @@ static int __init serial8250_init(void)
|
||||
|
||||
serial8250_isa_init_ports();
|
||||
|
||||
printk(KERN_INFO "Serial: 8250/16550 driver, "
|
||||
"%d ports, IRQ sharing %sabled\n", nr_uarts,
|
||||
share_irqs ? "en" : "dis");
|
||||
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
|
||||
nr_uarts, share_irqs ? "en" : "dis");
|
||||
|
||||
#ifdef CONFIG_SPARC
|
||||
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
|
||||
@ -1168,15 +1182,11 @@ static void __exit serial8250_exit(void)
|
||||
module_init(serial8250_init);
|
||||
module_exit(serial8250_exit);
|
||||
|
||||
EXPORT_SYMBOL(serial8250_suspend_port);
|
||||
EXPORT_SYMBOL(serial8250_resume_port);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
|
||||
|
||||
module_param(share_irqs, uint, 0644);
|
||||
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
|
||||
" (unsafe)");
|
||||
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
|
||||
|
||||
module_param(nr_uarts, uint, 0644);
|
||||
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
|
||||
|
@ -68,12 +68,6 @@ struct dw8250_data {
|
||||
unsigned int uart_16550_compatible:1;
|
||||
};
|
||||
|
||||
#define BYT_PRV_CLK 0x800
|
||||
#define BYT_PRV_CLK_EN (1 << 0)
|
||||
#define BYT_PRV_CLK_M_VAL_SHIFT 1
|
||||
#define BYT_PRV_CLK_N_VAL_SHIFT 16
|
||||
#define BYT_PRV_CLK_UPDATE (1 << 31)
|
||||
|
||||
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p)
|
||||
(void)p->serial_in(p, UART_RX);
|
||||
}
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
static void dw8250_check_lcr(struct uart_port *p, int value)
|
||||
{
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
void __iomem *offset = p->membase + (UART_LCR << p->regshift);
|
||||
int tries = 1000;
|
||||
|
||||
/* Make sure LCR write wasn't ignored */
|
||||
if (offset == UART_LCR) {
|
||||
int tries = 1000;
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
dw8250_force_idle(p);
|
||||
writeb(value, p->membase + (UART_LCR << p->regshift));
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
|
||||
*/
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
|
||||
dw8250_force_idle(p);
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__raw_writeq(value & 0xff, offset);
|
||||
#else
|
||||
if (p->iotype == UPIO_MEM32)
|
||||
writel(value, offset);
|
||||
else if (p->iotype == UPIO_MEM32BE)
|
||||
iowrite32be(value, offset);
|
||||
else
|
||||
writeb(value, offset);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
|
||||
*/
|
||||
}
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
|
||||
@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
|
||||
|
||||
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
value &= 0xff;
|
||||
__raw_writeq(value, p->membase + (offset << p->regshift));
|
||||
/* Read back to ensure register write ordering. */
|
||||
__raw_readq(p->membase + (UART_LCR << p->regshift));
|
||||
|
||||
/* Make sure LCR write wasn't ignored */
|
||||
if (offset == UART_LCR) {
|
||||
int tries = 1000;
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
dw8250_force_idle(p);
|
||||
__raw_writeq(value & 0xff,
|
||||
p->membase + (UART_LCR << p->regshift));
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
|
||||
*/
|
||||
}
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
writel(value, p->membase + (offset << p->regshift));
|
||||
|
||||
/* Make sure LCR write wasn't ignored */
|
||||
if (offset == UART_LCR) {
|
||||
int tries = 1000;
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
dw8250_force_idle(p);
|
||||
writel(value, p->membase + (UART_LCR << p->regshift));
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
|
||||
*/
|
||||
}
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
return dw8250_modify_msr(p, offset, value);
|
||||
}
|
||||
|
||||
static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
iowrite32be(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
|
||||
{
|
||||
unsigned int value = ioread32be(p->membase + (offset << p->regshift));
|
||||
|
||||
return dw8250_modify_msr(p, offset, value);
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
if (serial8250_handle_irq(p, iir))
|
||||
return 1;
|
||||
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
||||
|
||||
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
||||
/* Clear the USR */
|
||||
(void)p->serial_in(p, d->usr_reg);
|
||||
|
||||
@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||
data->skip_autocfg = true;
|
||||
}
|
||||
#endif
|
||||
if (of_device_is_big_endian(p->dev->of_node)) {
|
||||
p->iotype = UPIO_MEM32BE;
|
||||
p->serial_in = dw8250_serial_in32be;
|
||||
p->serial_out = dw8250_serial_out32be;
|
||||
}
|
||||
} else if (has_acpi_companion(p->dev)) {
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->regshift = 2;
|
||||
@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p)
|
||||
* If the Component Version Register returns zero, we know that
|
||||
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
||||
*/
|
||||
reg = readl(p->membase + DW_UART_UCV);
|
||||
if (p->iotype == UPIO_MEM32BE)
|
||||
reg = ioread32be(p->membase + DW_UART_UCV);
|
||||
else
|
||||
reg = readl(p->membase + DW_UART_UCV);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
|
||||
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
||||
|
||||
reg = readl(p->membase + DW_UART_CPR);
|
||||
if (p->iotype == UPIO_MEM32BE)
|
||||
reg = ioread32be(p->membase + DW_UART_CPR);
|
||||
else
|
||||
reg = readl(p->membase + DW_UART_CPR);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
dw8250_quirks(p, data);
|
||||
|
||||
/* If the Busy Functionality is not implemented, don't handle it */
|
||||
if (data->uart_16550_compatible) {
|
||||
p->serial_out = NULL;
|
||||
if (data->uart_16550_compatible)
|
||||
p->handle_irq = NULL;
|
||||
}
|
||||
|
||||
if (!data->skip_autocfg)
|
||||
dw8250_setup_port(p);
|
||||
|
@ -39,15 +39,17 @@
|
||||
|
||||
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
|
||||
{
|
||||
offset <<= port->regshift;
|
||||
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM:
|
||||
return readb(port->membase + offset);
|
||||
case UPIO_MEM16:
|
||||
return readw(port->membase + (offset << 1));
|
||||
return readw(port->membase + offset);
|
||||
case UPIO_MEM32:
|
||||
return readl(port->membase + (offset << 2));
|
||||
return readl(port->membase + offset);
|
||||
case UPIO_MEM32BE:
|
||||
return ioread32be(port->membase + (offset << 2));
|
||||
return ioread32be(port->membase + offset);
|
||||
case UPIO_PORT:
|
||||
return inb(port->iobase + offset);
|
||||
default:
|
||||
@ -57,18 +59,20 @@ 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)
|
||||
{
|
||||
offset <<= port->regshift;
|
||||
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM:
|
||||
writeb(value, port->membase + offset);
|
||||
break;
|
||||
case UPIO_MEM16:
|
||||
writew(value, port->membase + (offset << 1));
|
||||
writew(value, port->membase + offset);
|
||||
break;
|
||||
case UPIO_MEM32:
|
||||
writel(value, port->membase + (offset << 2));
|
||||
writel(value, port->membase + offset);
|
||||
break;
|
||||
case UPIO_MEM32BE:
|
||||
iowrite32be(value, port->membase + (offset << 2));
|
||||
iowrite32be(value, port->membase + offset);
|
||||
break;
|
||||
case UPIO_PORT:
|
||||
outb(value, port->iobase + offset);
|
||||
@ -145,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
|
||||
EARLYCON_DECLARE(uart, early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_OMAP
|
||||
|
||||
static int __init early_omap8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
|
||||
if (!(device->port.membase || device->port.iobase))
|
||||
return -ENODEV;
|
||||
|
||||
port->regshift = 2;
|
||||
device->con->write = early_serial8250_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
|
||||
OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
|
||||
OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
|
||||
|
||||
#endif
|
||||
|
@ -13,20 +13,13 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define PORT(_base,_irq) \
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.irq = _irq, \
|
||||
.uartclk = 1843200, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF, \
|
||||
}
|
||||
#include "8250.h"
|
||||
|
||||
static struct plat_serial8250_port exar_data[] = {
|
||||
PORT(0x100, 5),
|
||||
PORT(0x108, 5),
|
||||
PORT(0x110, 5),
|
||||
PORT(0x118, 5),
|
||||
SERIAL8250_PORT(0x100, 5),
|
||||
SERIAL8250_PORT(0x108, 5),
|
||||
SERIAL8250_PORT(0x110, 5),
|
||||
SERIAL8250_PORT(0x118, 5),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -10,24 +10,20 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define PORT(_base,_irq) \
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.irq = _irq, \
|
||||
.uartclk = 1843200, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
|
||||
}
|
||||
#include "8250.h"
|
||||
|
||||
#define SERIAL8250_FOURPORT(_base, _irq) \
|
||||
SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT)
|
||||
|
||||
static struct plat_serial8250_port fourport_data[] = {
|
||||
PORT(0x1a0, 9),
|
||||
PORT(0x1a8, 9),
|
||||
PORT(0x1b0, 9),
|
||||
PORT(0x1b8, 9),
|
||||
PORT(0x2a0, 5),
|
||||
PORT(0x2a8, 5),
|
||||
PORT(0x2b0, 5),
|
||||
PORT(0x2b8, 5),
|
||||
SERIAL8250_FOURPORT(0x1a0, 9),
|
||||
SERIAL8250_FOURPORT(0x1a8, 9),
|
||||
SERIAL8250_FOURPORT(0x1b0, 9),
|
||||
SERIAL8250_FOURPORT(0x1b8, 9),
|
||||
SERIAL8250_FOURPORT(0x2a0, 5),
|
||||
SERIAL8250_FOURPORT(0x2a8, 5),
|
||||
SERIAL8250_FOURPORT(0x2b0, 5),
|
||||
SERIAL8250_FOURPORT(0x2b8, 5),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
|
||||
* the user what they're missing.
|
||||
*/
|
||||
if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
|
||||
printk(KERN_INFO
|
||||
dev_info(&dev->dev,
|
||||
"Serial: device 0x%llx not configured.\n"
|
||||
"Enable support for Wax, Lasi, Asp or Dino.\n",
|
||||
(unsigned long long)dev->hpa.start);
|
||||
@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev)
|
||||
|
||||
err = serial8250_register_8250_port(&uart);
|
||||
if (err < 0) {
|
||||
printk(KERN_WARNING
|
||||
"serial8250_register_8250_port returned error %d\n", err);
|
||||
dev_warn(&dev->dev,
|
||||
"serial8250_register_8250_port returned error %d\n",
|
||||
err);
|
||||
iounmap(uart.port.membase);
|
||||
return err;
|
||||
}
|
||||
|
@ -24,8 +24,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HPAPCI
|
||||
struct hp300_port
|
||||
{
|
||||
struct hp300_port {
|
||||
struct hp300_port *next; /* next port */
|
||||
int line; /* line (tty) number */
|
||||
};
|
||||
@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void)
|
||||
/* Check for APCI console */
|
||||
if (scode == 256) {
|
||||
#ifdef CONFIG_HPAPCI
|
||||
printk(KERN_INFO "Serial console is HP APCI 1\n");
|
||||
pr_info("Serial console is HP APCI 1\n");
|
||||
|
||||
port.uartclk = HPAPCI_BAUD_BASE * 16;
|
||||
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
|
||||
@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void)
|
||||
port.regshift = 2;
|
||||
add_preferred_console("ttyS", port.line, "9600n8");
|
||||
#else
|
||||
printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
|
||||
pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void)
|
||||
if (!pa)
|
||||
return 0;
|
||||
|
||||
printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
|
||||
pr_info("Serial console is HP DCA at select code %d\n", scode);
|
||||
|
||||
port.uartclk = HPDCA_BAUD_BASE * 16;
|
||||
port.mapbase = (pa + UART_OFFSET);
|
||||
@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void)
|
||||
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
|
||||
add_preferred_console("ttyS", port.line, "9600n8");
|
||||
#else
|
||||
printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
|
||||
pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (early_serial_setup(&port) < 0)
|
||||
printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
|
||||
pr_warn("%s: early_serial_setup() failed.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SERIAL_8250_CONSOLE */
|
||||
@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d,
|
||||
line = serial8250_register_8250_port(&uart);
|
||||
|
||||
if (line < 0) {
|
||||
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
|
||||
" irq %d failed\n", d->scode, uart.port.irq);
|
||||
dev_notice(&d->dev,
|
||||
"8250_hp300: register_serial() DCA scode %d irq %d failed\n",
|
||||
d->scode, uart.port.irq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -249,8 +249,8 @@ static int __init hp300_8250_init(void)
|
||||
|
||||
/* Memory mapped I/O */
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
|
||||
| UPF_BOOT_AUTOCONF;
|
||||
uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
|
||||
| UPF_BOOT_AUTOCONF;
|
||||
/* XXX - no interrupt support yet */
|
||||
uart.port.irq = 0;
|
||||
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
|
||||
@ -261,8 +261,9 @@ static int __init hp300_8250_init(void)
|
||||
line = serial8250_register_8250_port(&uart);
|
||||
|
||||
if (line < 0) {
|
||||
printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
|
||||
" %d irq %d failed\n", i, uart.port.irq);
|
||||
dev_notice(uart.port.dev,
|
||||
"8250_hp300: register_serial() APCI %d irq %d failed\n",
|
||||
i, uart.port.irq);
|
||||
kfree(port);
|
||||
continue;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define HUB6(card,port) \
|
||||
#define HUB6(card, port) \
|
||||
{ \
|
||||
.iobase = 0x302, \
|
||||
.irq = 3, \
|
||||
|
@ -48,7 +48,7 @@ static const struct of_device_id of_match[];
|
||||
#define UART_MCR_MDCE BIT(7)
|
||||
#define UART_MCR_FCM BIT(6)
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
|
||||
static struct earlycon_device *early_device;
|
||||
|
||||
static uint8_t __init early_in(struct uart_port *port, int offset)
|
||||
@ -154,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
break;
|
||||
|
||||
case UART_IER:
|
||||
/* Enable receive timeout interrupt with the
|
||||
* receive line status interrupt */
|
||||
/*
|
||||
* Enable receive timeout interrupt with the receive line
|
||||
* status interrupt.
|
||||
*/
|
||||
value |= (value & 0x4) << 2;
|
||||
break;
|
||||
|
||||
case UART_MCR:
|
||||
/* If we have enabled modem status IRQs we should enable modem
|
||||
* mode. */
|
||||
/*
|
||||
* If we have enabled modem status IRQs we should enable
|
||||
* modem mode.
|
||||
*/
|
||||
ier = p->serial_in(p, UART_IER);
|
||||
|
||||
if (ier & UART_IER_MSI)
|
||||
|
157
drivers/tty/serial/8250/8250_moxa.c
Normal file
157
drivers/tty/serial/8250/8250_moxa.c
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver.
|
||||
*
|
||||
* Author: Mathieu OTHACEHE <m.othacehe@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
|
||||
#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
|
||||
#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
|
||||
#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
|
||||
#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
|
||||
#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
|
||||
#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
|
||||
#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
|
||||
#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
|
||||
#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
|
||||
#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
|
||||
#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
|
||||
|
||||
#define MOXA_BASE_BAUD 921600
|
||||
#define MOXA_UART_OFFSET 0x200
|
||||
#define MOXA_BASE_BAR 1
|
||||
|
||||
struct moxa8250_board {
|
||||
unsigned int num_ports;
|
||||
int line[0];
|
||||
};
|
||||
|
||||
enum {
|
||||
moxa8250_2p = 0,
|
||||
moxa8250_4p,
|
||||
moxa8250_8p
|
||||
};
|
||||
|
||||
static struct moxa8250_board moxa8250_boards[] = {
|
||||
[moxa8250_2p] = { .num_ports = 2},
|
||||
[moxa8250_4p] = { .num_ports = 4},
|
||||
[moxa8250_8p] = { .num_ports = 8},
|
||||
};
|
||||
|
||||
static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
struct moxa8250_board *brd;
|
||||
void __iomem *ioaddr;
|
||||
resource_size_t baseaddr;
|
||||
unsigned int i, nr_ports;
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
|
||||
brd = &moxa8250_boards[id->driver_data];
|
||||
nr_ports = brd->num_ports;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) +
|
||||
sizeof(unsigned int) * nr_ports, GFP_KERNEL);
|
||||
if (!brd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&uart, 0, sizeof(struct uart_8250_port));
|
||||
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.irq = pdev->irq;
|
||||
uart.port.uartclk = MOXA_BASE_BAUD * 16;
|
||||
uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
||||
|
||||
baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR);
|
||||
ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0);
|
||||
if (!ioaddr)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nr_ports; i++) {
|
||||
|
||||
/*
|
||||
* MOXA Smartio MUE boards with 4 ports have
|
||||
* a different offset for port #3
|
||||
*/
|
||||
if (nr_ports == 4 && i == 3)
|
||||
offset = 7 * MOXA_UART_OFFSET;
|
||||
else
|
||||
offset = i * MOXA_UART_OFFSET;
|
||||
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.iobase = 0;
|
||||
uart.port.mapbase = baseaddr + offset;
|
||||
uart.port.membase = ioaddr + offset;
|
||||
uart.port.regshift = 0;
|
||||
|
||||
dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
|
||||
uart.port.iobase, uart.port.irq, uart.port.iotype);
|
||||
|
||||
brd->line[i] = serial8250_register_8250_port(&uart);
|
||||
if (brd->line[i] < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
|
||||
uart.port.iobase, uart.port.irq,
|
||||
uart.port.iotype, brd->line[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, brd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void moxa8250_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct moxa8250_board *brd = pci_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < brd->num_ports; i++)
|
||||
serial8250_unregister_port(brd->line[i]);
|
||||
}
|
||||
|
||||
#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data }
|
||||
|
||||
static const struct pci_device_id pci_ids[] = {
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p),
|
||||
MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p),
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
static struct pci_driver moxa8250_pci_driver = {
|
||||
.name = "8250_moxa",
|
||||
.id_table = pci_ids,
|
||||
.probe = moxa8250_probe,
|
||||
.remove = moxa8250_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(moxa8250_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Mathieu OTHACEHE");
|
||||
MODULE_DESCRIPTION("MOXA SmartIO MUE driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -41,12 +41,10 @@ static void
|
||||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
|
||||
serial8250_do_set_termios(port, termios, old);
|
||||
|
||||
/*
|
||||
@ -116,7 +114,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
}
|
||||
|
||||
static int mtk8250_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
@ -245,8 +243,24 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mtk8250_suspend(struct device *dev)
|
||||
static int mtk8250_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk8250_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
mtk8250_runtime_suspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk8250_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
@ -255,7 +269,7 @@ static int mtk8250_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_resume(struct device *dev)
|
||||
static int __maybe_unused mtk8250_resume(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
@ -263,7 +277,6 @@ static int mtk8250_resume(struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops mtk8250_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
|
||||
@ -275,20 +288,20 @@ static const struct of_device_id mtk8250_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6577-uart" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk8250_of_match);
|
||||
|
||||
static struct platform_driver mtk8250_platform_driver = {
|
||||
.driver = {
|
||||
.name = "mt6577-uart",
|
||||
.pm = &mtk8250_pm_ops,
|
||||
.of_match_table = mtk8250_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
|
||||
.name = "mt6577-uart",
|
||||
.pm = &mtk8250_pm_ops,
|
||||
.of_match_table = mtk8250_of_match,
|
||||
},
|
||||
.probe = mtk8250_probe,
|
||||
.remove = mtk8250_remove,
|
||||
};
|
||||
builtin_platform_driver(mtk8250_platform_driver);
|
||||
module_platform_driver(mtk8250_platform_driver);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
|
||||
static int __init early_mtk8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
@ -302,3 +315,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device,
|
||||
|
||||
OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Matthias Brugger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
|
||||
|
@ -335,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = {
|
||||
.driver = {
|
||||
.name = "of_serial",
|
||||
.of_match_table = of_platform_serial_table,
|
||||
.pm = &of_serial_pm_ops,
|
||||
},
|
||||
.probe = of_platform_serial_probe,
|
||||
.remove = of_platform_serial_remove,
|
||||
|
@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct omap8250_priv *priv = up->port.private_data;
|
||||
unsigned char cval = 0;
|
||||
unsigned int baud;
|
||||
@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
|
||||
static void omap_8250_throttle(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port)
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static int omap_8250_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* Clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init and serial8250_em485_destroy
|
||||
* are idempotent
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
int ret = serial8250_em485_init(up);
|
||||
|
||||
if (ret) {
|
||||
rs485->flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial8250_em485_destroy(up);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_8250_unthrottle(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
up.port.shutdown = omap_8250_shutdown;
|
||||
up.port.throttle = omap_8250_throttle;
|
||||
up.port.unthrottle = omap_8250_unthrottle;
|
||||
up.port.rs485_config = omap_8250_rs485_config;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *id;
|
||||
|
@ -55,7 +55,6 @@ struct pci_serial_quirk {
|
||||
struct serial_private {
|
||||
struct pci_dev *dev;
|
||||
unsigned int nr;
|
||||
void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
|
||||
struct pci_serial_quirk *quirk;
|
||||
int line[0];
|
||||
};
|
||||
@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
|
||||
return -EINVAL;
|
||||
|
||||
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
|
||||
if (!priv->remapped_bar[bar])
|
||||
priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
|
||||
if (!priv->remapped_bar[bar])
|
||||
if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
|
||||
return -ENOMEM;
|
||||
|
||||
port->port.iotype = UPIO_MEM;
|
||||
port->port.iobase = 0;
|
||||
port->port.mapbase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.membase = priv->remapped_bar[bar] + offset;
|
||||
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
|
||||
port->port.regshift = regshift;
|
||||
} else {
|
||||
port->port.iotype = UPIO_PORT;
|
||||
@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
|
||||
*/
|
||||
pcibios_resource_to_bus(dev->bus, ®ion, &dev->resource[bar]);
|
||||
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
|
||||
| MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
|
||||
| MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
|
||||
writel(device_window, p + MITE_IOWBSR1);
|
||||
|
||||
/* Set window access to go to RAMSEL IO address space */
|
||||
@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
|
||||
unsigned int pi;
|
||||
unsigned short sub_serports;
|
||||
|
||||
pi = (c & 0xff);
|
||||
pi = c & 0xff;
|
||||
|
||||
if (pi == 2) {
|
||||
if (pi == 2)
|
||||
return 1;
|
||||
} else if ((pi == 0) &&
|
||||
(dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
|
||||
|
||||
if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
|
||||
/* two possibilities: 0x30ps encodes number of parallel and
|
||||
* serial ports, or 0x1000 indicates *something*. This is not
|
||||
* immediately obvious, since the 2s1p+4s configuration seems
|
||||
@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
|
||||
* advertising the same function 3 as the 4s+2s1p config.
|
||||
*/
|
||||
sub_serports = dev->subsystem_device & 0xf;
|
||||
if (sub_serports > 0) {
|
||||
if (sub_serports > 0)
|
||||
return sub_serports;
|
||||
} else {
|
||||
dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(&dev->dev,
|
||||
"NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
moan_device("unknown NetMos/Mostech program interface", dev);
|
||||
@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev)
|
||||
return 0;
|
||||
|
||||
switch (dev->device) { /* FALLTHROUGH on all */
|
||||
case PCI_DEVICE_ID_NETMOS_9904:
|
||||
case PCI_DEVICE_ID_NETMOS_9912:
|
||||
case PCI_DEVICE_ID_NETMOS_9922:
|
||||
case PCI_DEVICE_ID_NETMOS_9900:
|
||||
num_serial = pci_netmos_9900_numports(dev);
|
||||
break;
|
||||
case PCI_DEVICE_ID_NETMOS_9904:
|
||||
case PCI_DEVICE_ID_NETMOS_9912:
|
||||
case PCI_DEVICE_ID_NETMOS_9922:
|
||||
case PCI_DEVICE_ID_NETMOS_9900:
|
||||
num_serial = pci_netmos_9900_numports(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (num_serial == 0 ) {
|
||||
moan_device("unknown NetMos/Mostech device", dev);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_serial == 0)
|
||||
if (num_serial == 0) {
|
||||
moan_device("unknown NetMos/Mostech device", dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return num_serial;
|
||||
}
|
||||
@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port)
|
||||
|
||||
static int pci_quatech_test(struct uart_8250_port *port)
|
||||
{
|
||||
u8 reg;
|
||||
u8 qopr = pci_quatech_rqopr(port);
|
||||
u8 reg, qopr;
|
||||
|
||||
qopr = pci_quatech_rqopr(port);
|
||||
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
|
||||
reg = pci_quatech_rqopr(port) & 0xC0;
|
||||
if (reg != QPCR_TEST_GET1)
|
||||
@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev)
|
||||
unsigned long base = pci_resource_start(dev, 0);
|
||||
if (base) {
|
||||
u32 tmp;
|
||||
|
||||
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
|
||||
tmp = inl(base + 0x3c);
|
||||
outl(tmp | 0x01000000, base + 0x3c);
|
||||
@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv,
|
||||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
|
||||
static int pci_pericom_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
unsigned int bar, offset = board->first_offset, maxnr;
|
||||
|
||||
bar = FL_GET_BASE(board->flags);
|
||||
if (board->flags & FL_BASE_BARS)
|
||||
bar += idx;
|
||||
else
|
||||
offset += idx * board->uart_offset;
|
||||
|
||||
maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
|
||||
(board->reg_shift + 3);
|
||||
|
||||
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
|
||||
return 1;
|
||||
|
||||
port->port.uartclk = 14745600;
|
||||
|
||||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
|
||||
static int
|
||||
ce4100_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
@ -1541,10 +1517,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
|
||||
static int pci_fintek_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(port->dev);
|
||||
u8 setting;
|
||||
u8 *index = (u8 *) port->private_data;
|
||||
struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
|
||||
dev);
|
||||
|
||||
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
|
||||
|
||||
@ -1766,7 +1741,7 @@ xr17v35x_has_slave(struct serial_private *priv)
|
||||
const int dev_id = priv->dev->device;
|
||||
|
||||
return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
|
||||
(dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
|
||||
(dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1866,8 +1841,8 @@ pci_fastcom335_setup(struct serial_private *priv,
|
||||
|
||||
static int
|
||||
pci_wch_ch353_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
port->port.flags |= UPF_FIXED_TYPE;
|
||||
port->port.type = PORT_16550A;
|
||||
@ -1876,8 +1851,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
||||
|
||||
static int
|
||||
pci_wch_ch38x_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
port->port.flags |= UPF_FIXED_TYPE;
|
||||
port->port.type = PORT_16850;
|
||||
@ -2245,16 +2220,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.setup = pci_default_setup,
|
||||
.exit = pci_plx9050_exit,
|
||||
},
|
||||
/*
|
||||
* Pericom
|
||||
*/
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_PERICOM,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
},
|
||||
/*
|
||||
* PLX
|
||||
*/
|
||||
@ -3733,15 +3698,10 @@ static struct pciserial_board pci_boards[] = {
|
||||
.base_baud = 921600,
|
||||
.reg_shift = 2,
|
||||
},
|
||||
/*
|
||||
* Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
|
||||
* but is overridden by byt_set_termios.
|
||||
*/
|
||||
[pbn_byt] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 1,
|
||||
.base_baud = 2764800,
|
||||
.uart_offset = 0x80,
|
||||
.reg_shift = 2,
|
||||
},
|
||||
[pbn_qrk] = {
|
||||
@ -3840,6 +3800,20 @@ static const struct pci_device_id blacklist[] = {
|
||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
|
||||
|
||||
/* Moxa Smartio MUE boards handled by 8250_moxa */
|
||||
{ PCI_VDEVICE(MOXA, 0x1024), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1025), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1045), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1144), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1160), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1161), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1182), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1183), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1322), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1342), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1381), },
|
||||
{ PCI_VDEVICE(MOXA, 0x1683), },
|
||||
|
||||
/* Intel platforms with MID UART */
|
||||
{ PCI_VDEVICE(INTEL, 0x081b), },
|
||||
{ PCI_VDEVICE(INTEL, 0x081c), },
|
||||
@ -4027,12 +4001,6 @@ void pciserial_remove_ports(struct serial_private *priv)
|
||||
for (i = 0; i < priv->nr; i++)
|
||||
serial8250_unregister_port(priv->line[i]);
|
||||
|
||||
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
|
||||
if (priv->remapped_bar[i])
|
||||
iounmap(priv->remapped_bar[i]);
|
||||
priv->remapped_bar[i] = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the exit quirks.
|
||||
*/
|
||||
@ -4104,7 +4072,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
|
||||
board = &pci_boards[ent->driver_data];
|
||||
|
||||
rc = pci_enable_device(dev);
|
||||
rc = pcim_enable_device(dev);
|
||||
pci_save_state(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -4123,7 +4091,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
*/
|
||||
rc = serial_pci_guess_board(dev, &tmp);
|
||||
if (rc)
|
||||
goto disable;
|
||||
return rc;
|
||||
} else {
|
||||
/*
|
||||
* We matched an explicit entry. If we are able to
|
||||
@ -4139,16 +4107,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||
}
|
||||
|
||||
priv = pciserial_init_ports(dev, board);
|
||||
if (!IS_ERR(priv)) {
|
||||
pci_set_drvdata(dev, priv);
|
||||
return 0;
|
||||
}
|
||||
if (IS_ERR(priv))
|
||||
return PTR_ERR(priv);
|
||||
|
||||
rc = PTR_ERR(priv);
|
||||
|
||||
disable:
|
||||
pci_disable_device(dev);
|
||||
return rc;
|
||||
pci_set_drvdata(dev, priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pciserial_remove_one(struct pci_dev *dev)
|
||||
@ -4156,8 +4119,6 @@ static void pciserial_remove_one(struct pci_dev *dev)
|
||||
struct serial_private *priv = pci_get_drvdata(dev);
|
||||
|
||||
pciserial_remove_ports(priv);
|
||||
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -4538,7 +4499,7 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b0_bt_2_921600 },
|
||||
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
|
||||
PCI_ANY_ID , PCI_ANY_ID, 0, 0,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_8_1152000 },
|
||||
|
||||
/*
|
||||
|
@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
||||
/* Fujitsu Wacom 1FGT Tablet PC device */
|
||||
{ "FUJ02E9", 0 },
|
||||
/*
|
||||
* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
|
||||
* disguise)
|
||||
* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
|
||||
* in disguise).
|
||||
*/
|
||||
{ "LTS0001", 0 },
|
||||
/* Rockwell's (PORALiNK) 33600 INT PNP */
|
||||
@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
||||
{ "PNPCXXX", UNKNOWN_DEV },
|
||||
/* More unknown PnP modems */
|
||||
{ "PNPDXXX", UNKNOWN_DEV },
|
||||
/* Winbond CIR port, should not be probed. We should keep track
|
||||
of it to prevent the legacy serial driver from probing it */
|
||||
/*
|
||||
* Winbond CIR port, should not be probed. We should keep track of
|
||||
* it to prevent the legacy serial driver from probing it.
|
||||
*/
|
||||
{ "WEC1022", CIR_PORT },
|
||||
/*
|
||||
* SMSC IrCC SIR/FIR port, should not be probed by serial driver
|
||||
* as well so its own driver can bind to it.
|
||||
* SMSC IrCC SIR/FIR port, should not be probed by serial driver as
|
||||
* well so its own driver can bind to it.
|
||||
*/
|
||||
{ "SMCF010", CIR_PORT },
|
||||
{ "", 0 }
|
||||
@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
|
||||
|
||||
static char *modem_names[] = {
|
||||
static const char *modem_names[] = {
|
||||
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
|
||||
"56K", "56k", "K56", "33.6", "28.8", "14.4",
|
||||
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
|
||||
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
|
||||
};
|
||||
|
||||
static int check_name(char *name)
|
||||
static bool check_name(const char *name)
|
||||
{
|
||||
char **tmp;
|
||||
const char **tmp;
|
||||
|
||||
for (tmp = modem_names; *tmp; tmp++)
|
||||
if (strstr(name, *tmp))
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int check_resources(struct pnp_dev *dev)
|
||||
static bool check_resources(struct pnp_dev *dev)
|
||||
{
|
||||
resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
|
||||
int i;
|
||||
static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(base); i++) {
|
||||
if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev)
|
||||
static int serial_pnp_guess_board(struct pnp_dev *dev)
|
||||
{
|
||||
if (!(check_name(pnp_dev_name(dev)) ||
|
||||
(dev->card && check_name(dev->card->name))))
|
||||
return -ENODEV;
|
||||
(dev->card && check_name(dev->card->name))))
|
||||
return -ENODEV;
|
||||
|
||||
if (check_resources(dev))
|
||||
return 0;
|
||||
@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef SERIAL_DEBUG_PNP
|
||||
printk(KERN_DEBUG
|
||||
"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
|
||||
uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
|
||||
#endif
|
||||
dev_dbg(&dev->dev,
|
||||
"Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
|
||||
uart.port.iobase, &uart.port.mapbase,
|
||||
uart.port.irq, uart.port.iotype);
|
||||
|
||||
if (flags & CIR_PORT) {
|
||||
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
uart.port.type = PORT_8250_CIR;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
@ -52,7 +53,7 @@
|
||||
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
/*
|
||||
* Here we define the default xmit fifo size used for each type of UART.
|
||||
@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = {
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||
.flags = UART_CAP_FIFO | UART_CAP_AFE,
|
||||
},
|
||||
/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
|
||||
workaround of errata A-008006 which states that tx_loadsz should be
|
||||
configured less than Maximum supported fifo bytes */
|
||||
/*
|
||||
* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
|
||||
* workaround of errata A-008006 which states that tx_loadsz should
|
||||
* be configured less than Maximum supported fifo bytes.
|
||||
*/
|
||||
[PORT_16550A_FSL64] = {
|
||||
.name = "16550A_FSL64",
|
||||
.fifo_size = 64,
|
||||
@ -522,6 +525,20 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned char mcr = serial_in(p, UART_MCR);
|
||||
|
||||
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial_out(p, UART_MCR, mcr);
|
||||
}
|
||||
|
||||
static void serial8250_em485_handle_start_tx(unsigned long arg);
|
||||
static void serial8250_em485_handle_stop_tx(unsigned long arg);
|
||||
|
||||
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
|
||||
{
|
||||
serial8250_clear_fifos(p);
|
||||
@ -546,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
|
||||
|
||||
/**
|
||||
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
|
||||
* @p: uart_8250_port port instance
|
||||
*
|
||||
* The function is used to start rs485 software emulating on the
|
||||
* &struct uart_8250_port* @p. Namely, RTS is switched before/after
|
||||
* transmission. The function is idempotent, so it is safe to call it
|
||||
* multiple times.
|
||||
*
|
||||
* The caller MUST enable interrupt on empty shift register before
|
||||
* calling serial8250_em485_init(). This interrupt is not a part of
|
||||
* 8250 standard, but implementation defined.
|
||||
*
|
||||
* The function is supposed to be called from .rs485_config callback
|
||||
* or from any other callback protected with p->port.lock spinlock.
|
||||
*
|
||||
* See also serial8250_em485_destroy()
|
||||
*
|
||||
* Return 0 - success, -errno - otherwise
|
||||
*/
|
||||
int serial8250_em485_init(struct uart_8250_port *p)
|
||||
{
|
||||
if (p->em485 != NULL)
|
||||
return 0;
|
||||
|
||||
p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
|
||||
if (p->em485 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
setup_timer(&p->em485->stop_tx_timer,
|
||||
serial8250_em485_handle_stop_tx, (unsigned long)p);
|
||||
setup_timer(&p->em485->start_tx_timer,
|
||||
serial8250_em485_handle_start_tx, (unsigned long)p);
|
||||
p->em485->active_timer = NULL;
|
||||
|
||||
serial8250_em485_rts_after_send(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_init);
|
||||
|
||||
/**
|
||||
* serial8250_em485_destroy() - put uart_8250_port into normal state
|
||||
* @p: uart_8250_port port instance
|
||||
*
|
||||
* The function is used to stop rs485 software emulating on the
|
||||
* &struct uart_8250_port* @p. The function is idempotent, so it is safe to
|
||||
* call it multiple times.
|
||||
*
|
||||
* The function is supposed to be called from .rs485_config callback
|
||||
* or from any other callback protected with p->port.lock spinlock.
|
||||
*
|
||||
* See also serial8250_em485_init()
|
||||
*/
|
||||
void serial8250_em485_destroy(struct uart_8250_port *p)
|
||||
{
|
||||
if (p->em485 == NULL)
|
||||
return;
|
||||
|
||||
del_timer(&p->em485->start_tx_timer);
|
||||
del_timer(&p->em485->stop_tx_timer);
|
||||
|
||||
kfree(p->em485);
|
||||
p->em485 = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
|
||||
|
||||
/*
|
||||
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
|
||||
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
|
||||
@ -731,22 +815,16 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
*/
|
||||
static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned char old_dll, old_dlm, old_lcr;
|
||||
unsigned int id;
|
||||
unsigned char old_lcr;
|
||||
unsigned int id, old_dl;
|
||||
|
||||
old_lcr = serial_in(p, UART_LCR);
|
||||
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
old_dl = serial_dl_read(p);
|
||||
serial_dl_write(p, 0);
|
||||
id = serial_dl_read(p);
|
||||
serial_dl_write(p, old_dl);
|
||||
|
||||
old_dll = serial_in(p, UART_DLL);
|
||||
old_dlm = serial_in(p, UART_DLM);
|
||||
|
||||
serial_out(p, UART_DLL, 0);
|
||||
serial_out(p, UART_DLM, 0);
|
||||
|
||||
id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
|
||||
|
||||
serial_out(p, UART_DLL, old_dll);
|
||||
serial_out(p, UART_DLM, old_dlm);
|
||||
serial_out(p, UART_LCR, old_lcr);
|
||||
|
||||
return id;
|
||||
@ -1238,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
out_lock:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (up->capabilities != old_capabilities) {
|
||||
printk(KERN_WARNING
|
||||
"ttyS%d: detected caps %08x should be %08x\n",
|
||||
pr_warn("ttyS%d: detected caps %08x should be %08x\n",
|
||||
serial_index(port), old_capabilities,
|
||||
up->capabilities);
|
||||
}
|
||||
@ -1304,7 +1381,69 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
port->irq = (irq > 0) ? irq : 0;
|
||||
}
|
||||
|
||||
static inline void __stop_tx(struct uart_8250_port *p)
|
||||
static void serial8250_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
up->port.read_status_mask &= ~UART_LSR_DR;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void __do_stop_tx_rs485(struct uart_8250_port *p)
|
||||
{
|
||||
if (!p->em485)
|
||||
return;
|
||||
|
||||
serial8250_em485_rts_after_send(p);
|
||||
/*
|
||||
* Empty the RX FIFO, we are not interested in anything
|
||||
* received during the half-duplex transmission.
|
||||
*/
|
||||
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
serial8250_clear_fifos(p);
|
||||
}
|
||||
|
||||
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 = p->em485;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
if (em485 &&
|
||||
em485->active_timer == &em485->stop_tx_timer) {
|
||||
__do_stop_tx_rs485(p);
|
||||
em485->active_timer = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
static void __stop_tx_rs485(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_em485 *em485 = p->em485;
|
||||
|
||||
if (!em485)
|
||||
return;
|
||||
|
||||
/*
|
||||
* __do_stop_tx_rs485 is going to set RTS according to config
|
||||
* AND flush RX FIFO if required.
|
||||
*/
|
||||
if (p->port.rs485.delay_rts_after_send > 0) {
|
||||
em485->active_timer = &em485->stop_tx_timer;
|
||||
mod_timer(&em485->stop_tx_timer, jiffies +
|
||||
p->port.rs485.delay_rts_after_send * HZ / 1000);
|
||||
} else {
|
||||
__do_stop_tx_rs485(p);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __do_stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
@ -1313,6 +1452,28 @@ static inline void __stop_tx(struct uart_8250_port *p)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_em485 *em485 = p->em485;
|
||||
|
||||
if (em485) {
|
||||
unsigned char lsr = serial_in(p, UART_LSR);
|
||||
/*
|
||||
* To provide required timeing and allow FIFO transfer,
|
||||
* __stop_tx_rs485 must be called only when both FIFO and
|
||||
* shift register are empty. It is for device driver to enable
|
||||
* interrupt on TEMT.
|
||||
*/
|
||||
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
return;
|
||||
|
||||
del_timer(&em485->start_tx_timer);
|
||||
em485->active_timer = NULL;
|
||||
}
|
||||
__do_stop_tx(p);
|
||||
__stop_tx_rs485(p);
|
||||
}
|
||||
|
||||
static void serial8250_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
@ -1330,12 +1491,10 @@ static void serial8250_stop_tx(struct uart_port *port)
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void serial8250_start_tx(struct uart_port *port)
|
||||
static inline void __start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
serial8250_rpm_get_tx(up);
|
||||
|
||||
if (up->dma && !up->dma->tx_dma(up))
|
||||
return;
|
||||
|
||||
@ -1345,6 +1504,7 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
|
||||
if (up->bugs & UART_BUG_TXEN) {
|
||||
unsigned char lsr;
|
||||
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
if (lsr & UART_LSR_THRE)
|
||||
@ -1361,6 +1521,70 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void start_tx_rs485(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
unsigned char mcr;
|
||||
|
||||
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
serial8250_stop_rx(&up->port);
|
||||
|
||||
del_timer(&em485->stop_tx_timer);
|
||||
em485->active_timer = NULL;
|
||||
|
||||
mcr = serial_in(up, UART_MCR);
|
||||
if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
|
||||
!!(mcr & UART_MCR_RTS)) {
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial_out(up, UART_MCR, mcr);
|
||||
|
||||
if (up->port.rs485.delay_rts_before_send > 0) {
|
||||
em485->active_timer = &em485->start_tx_timer;
|
||||
mod_timer(&em485->start_tx_timer, jiffies +
|
||||
up->port.rs485.delay_rts_before_send * HZ / 1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__start_tx(port);
|
||||
}
|
||||
|
||||
static void serial8250_em485_handle_start_tx(unsigned long arg)
|
||||
{
|
||||
struct uart_8250_port *p = (struct uart_8250_port *)arg;
|
||||
struct uart_8250_em485 *em485 = p->em485;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
if (em485 &&
|
||||
em485->active_timer == &em485->start_tx_timer) {
|
||||
__start_tx(&p->port);
|
||||
em485->active_timer = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
static void serial8250_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
|
||||
serial8250_rpm_get_tx(up);
|
||||
|
||||
if (em485 &&
|
||||
em485->active_timer == &em485->start_tx_timer)
|
||||
return;
|
||||
|
||||
if (em485)
|
||||
start_tx_rs485(port);
|
||||
else
|
||||
__start_tx(port);
|
||||
}
|
||||
|
||||
static void serial8250_throttle(struct uart_port *port)
|
||||
{
|
||||
port->throttle(port);
|
||||
@ -1371,23 +1595,9 @@ static void serial8250_unthrottle(struct uart_port *port)
|
||||
port->unthrottle(port);
|
||||
}
|
||||
|
||||
static void serial8250_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
up->port.read_status_mask &= ~UART_LSR_DR;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void serial8250_disable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* no MSR capabilities */
|
||||
if (up->bugs & UART_BUG_NOMSR)
|
||||
@ -1412,81 +1622,85 @@ static void serial8250_enable_ms(struct uart_port *port)
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned char ch;
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
if (likely(lsr & UART_LSR_DR))
|
||||
ch = serial_in(up, UART_RX);
|
||||
else
|
||||
/*
|
||||
* Intel 82571 has a Serial Over Lan device that will
|
||||
* set UART_LSR_BI without setting UART_LSR_DR when
|
||||
* it receives a break. To avoid reading from the
|
||||
* receive buffer without UART_LSR_DR bit set, we
|
||||
* just force the read character to be 0
|
||||
*/
|
||||
ch = 0;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
lsr |= up->lsr_saved_flags;
|
||||
up->lsr_saved_flags = 0;
|
||||
|
||||
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
|
||||
if (lsr & UART_LSR_BI) {
|
||||
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
||||
port->icount.brk++;
|
||||
/*
|
||||
* We do the SysRQ and SAK checking
|
||||
* here because otherwise the break
|
||||
* may get masked by ignore_status_mask
|
||||
* or read_status_mask.
|
||||
*/
|
||||
if (uart_handle_break(port))
|
||||
return;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
port->icount.parity++;
|
||||
else if (lsr & UART_LSR_FE)
|
||||
port->icount.frame++;
|
||||
if (lsr & UART_LSR_OE)
|
||||
port->icount.overrun++;
|
||||
|
||||
/*
|
||||
* Mask off conditions which should be ignored.
|
||||
*/
|
||||
lsr &= port->read_status_mask;
|
||||
|
||||
if (lsr & UART_LSR_BI) {
|
||||
DEBUG_INTR("handling break....");
|
||||
flag = TTY_BREAK;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
else if (lsr & UART_LSR_FE)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
return;
|
||||
|
||||
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
|
||||
}
|
||||
|
||||
/*
|
||||
* serial8250_rx_chars: processes according to the passed in LSR
|
||||
* value, and returns the remaining LSR bits not handled
|
||||
* by this Rx routine.
|
||||
*/
|
||||
unsigned char
|
||||
serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
||||
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned char ch;
|
||||
int max_count = 256;
|
||||
char flag;
|
||||
|
||||
do {
|
||||
if (likely(lsr & UART_LSR_DR))
|
||||
ch = serial_in(up, UART_RX);
|
||||
else
|
||||
/*
|
||||
* Intel 82571 has a Serial Over Lan device that will
|
||||
* set UART_LSR_BI without setting UART_LSR_DR when
|
||||
* it receives a break. To avoid reading from the
|
||||
* receive buffer without UART_LSR_DR bit set, we
|
||||
* just force the read character to be 0
|
||||
*/
|
||||
ch = 0;
|
||||
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
lsr |= up->lsr_saved_flags;
|
||||
up->lsr_saved_flags = 0;
|
||||
|
||||
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
|
||||
if (lsr & UART_LSR_BI) {
|
||||
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
||||
port->icount.brk++;
|
||||
/*
|
||||
* We do the SysRQ and SAK checking
|
||||
* here because otherwise the break
|
||||
* may get masked by ignore_status_mask
|
||||
* or read_status_mask.
|
||||
*/
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
port->icount.parity++;
|
||||
else if (lsr & UART_LSR_FE)
|
||||
port->icount.frame++;
|
||||
if (lsr & UART_LSR_OE)
|
||||
port->icount.overrun++;
|
||||
|
||||
/*
|
||||
* Mask off conditions which should be ignored.
|
||||
*/
|
||||
lsr &= port->read_status_mask;
|
||||
|
||||
if (lsr & UART_LSR_BI) {
|
||||
DEBUG_INTR("handling break....");
|
||||
flag = TTY_BREAK;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
else if (lsr & UART_LSR_FE)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
|
||||
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
|
||||
|
||||
ignore_char:
|
||||
serial8250_read_char(up, lsr);
|
||||
if (--max_count == 0)
|
||||
break;
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
|
||||
spin_unlock(&port->lock);
|
||||
} while (lsr & (UART_LSR_DR | UART_LSR_BI));
|
||||
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
return lsr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
|
||||
@ -1519,11 +1733,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
if (up->capabilities & UART_CAP_HFIFO) {
|
||||
if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
|
||||
BOTH_EMPTY)
|
||||
break;
|
||||
}
|
||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||
(serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
@ -1752,6 +1964,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
unsigned int tmout;
|
||||
|
||||
for (tmout = 1000000; tmout; tmout--) {
|
||||
unsigned int msr = serial_in(up, UART_MSR);
|
||||
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
|
||||
@ -1985,23 +2198,23 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
|
||||
serial8250_set_mctrl(port, port->mctrl);
|
||||
|
||||
/* Serial over Lan (SoL) hack:
|
||||
Intel 8257x Gigabit ethernet chips have a
|
||||
16550 emulation, to be used for Serial Over Lan.
|
||||
Those chips take a longer time than a normal
|
||||
serial device to signalize that a transmission
|
||||
data was queued. Due to that, the above test generally
|
||||
fails. One solution would be to delay the reading of
|
||||
iir. However, this is not reliable, since the timeout
|
||||
is variable. So, let's just don't test if we receive
|
||||
TX irq. This way, we'll never enable UART_BUG_TXEN.
|
||||
/*
|
||||
* Serial over Lan (SoL) hack:
|
||||
* Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
|
||||
* used for Serial Over Lan. Those chips take a longer time than a
|
||||
* normal serial device to signalize that a transmission data was
|
||||
* queued. Due to that, the above test generally fails. One solution
|
||||
* would be to delay the reading of iir. However, this is not
|
||||
* reliable, since the timeout is variable. So, let's just don't
|
||||
* test if we receive TX irq. This way, we'll never enable
|
||||
* UART_BUG_TXEN.
|
||||
*/
|
||||
if (up->port.flags & UPF_NO_TXEN_TEST)
|
||||
goto dont_test_tx_en;
|
||||
|
||||
/*
|
||||
* Do a quick test to see if we receive an
|
||||
* interrupt when we enable the TX irq.
|
||||
* Do a quick test to see if we receive an interrupt when we enable
|
||||
* the TX irq.
|
||||
*/
|
||||
serial_port_out(port, UART_IER, UART_IER_THRI);
|
||||
lsr = serial_port_in(port, UART_LSR);
|
||||
@ -2084,8 +2297,12 @@ void serial8250_do_shutdown(struct uart_port *port)
|
||||
/*
|
||||
* Disable interrupts from this port
|
||||
*/
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
up->ier = 0;
|
||||
serial_port_out(port, UART_IER, 0);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
synchronize_irq(port->irq);
|
||||
|
||||
if (up->dma)
|
||||
serial8250_release_dma(up);
|
||||
@ -2251,9 +2468,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
serial_port_out(port, 0x2, quot_frac);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
static unsigned int serial8250_get_baud_rate(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int tolerance = port->uartclk / 100;
|
||||
|
||||
@ -2270,7 +2487,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
void
|
||||
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned char cval;
|
||||
@ -2583,8 +2800,7 @@ static int do_get_rxtrig(struct tty_port *port)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport = state->uart_port;
|
||||
struct uart_8250_port *up =
|
||||
container_of(uport, struct uart_8250_port, port);
|
||||
struct uart_8250_port *up = up_to_u8250p(uport);
|
||||
|
||||
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
|
||||
return -EINVAL;
|
||||
@ -2620,8 +2836,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport = state->uart_port;
|
||||
struct uart_8250_port *up =
|
||||
container_of(uport, struct uart_8250_port, port);
|
||||
struct uart_8250_port *up = up_to_u8250p(uport);
|
||||
int rxtrig;
|
||||
|
||||
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
|
||||
@ -2745,8 +2960,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
serial8250_type(struct uart_port *port)
|
||||
static const char *serial8250_type(struct uart_port *port)
|
||||
{
|
||||
int type = port->type;
|
||||
|
||||
|
@ -35,7 +35,7 @@ struct uniphier8250_priv {
|
||||
spinlock_t atomic_write_lock;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
|
||||
static int __init uniphier_early_console_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
|
@ -262,7 +262,12 @@ config SERIAL_8250_RSA
|
||||
bool "Support RSA serial ports"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
::: To be written :::
|
||||
Say Y here if you have a IODATA RSA-DV II/S ISA card and
|
||||
would like to use its >115kbps speeds.
|
||||
You will need to provide module parameter "probe_rsa", or boot-time
|
||||
parameter 8250.probe_rsa with I/O addresses of this card then.
|
||||
|
||||
If you don't have such card, or if unsure, say N.
|
||||
|
||||
config SERIAL_8250_ACORN
|
||||
tristate "Acorn expansion card serial port support"
|
||||
@ -272,6 +277,30 @@ config SERIAL_8250_ACORN
|
||||
system, say Y to this option. The driver can handle 1, 2, or 3 port
|
||||
cards. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_BCM2835AUX
|
||||
tristate "BCM2835 auxiliar mini UART support"
|
||||
depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
|
||||
help
|
||||
Support for the BCM2835 auxiliar mini UART.
|
||||
|
||||
Features and limitations of the UART are
|
||||
Registers are similar to 16650 registers,
|
||||
set bits in the control registers that are unsupported
|
||||
are ignored and read back as 0
|
||||
7/8 bit operation with 1 start and 1 stop bit
|
||||
8 symbols deep fifo for rx and tx
|
||||
SW controlled RTS and SW readable CTS
|
||||
Clock rate derived from system clock
|
||||
Uses 8 times oversampling (compared to 16 times for 16650)
|
||||
Missing break detection (but break generation)
|
||||
Missing framing error detection
|
||||
Missing parity bit
|
||||
Missing receive time-out interrupt
|
||||
Missing DCD, DSR, DTR and RI signals
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_FSL
|
||||
bool
|
||||
depends on SERIAL_8250_CONSOLE
|
||||
@ -295,6 +324,7 @@ config SERIAL_8250_EM
|
||||
config SERIAL_8250_RT288X
|
||||
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
|
||||
depends on SERIAL_8250
|
||||
depends on MIPS || COMPILE_TEST
|
||||
default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
|
||||
help
|
||||
Selecting this option will add support for the alternate register
|
||||
@ -346,7 +376,7 @@ config SERIAL_8250_LPC18XX
|
||||
serial port, say Y to this option. If unsure, say Y.
|
||||
|
||||
config SERIAL_8250_MT6577
|
||||
bool "Mediatek serial port support"
|
||||
tristate "Mediatek serial port support"
|
||||
depends on SERIAL_8250 && ARCH_MEDIATEK
|
||||
help
|
||||
If you have a Mediatek based board and want to use the
|
||||
@ -360,9 +390,10 @@ config SERIAL_8250_UNIPHIER
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_INGENIC
|
||||
bool "Support for Ingenic SoC serial ports"
|
||||
depends on OF_FLATTREE
|
||||
select LIBFDT
|
||||
tristate "Support for Ingenic SoC serial ports"
|
||||
depends on SERIAL_8250
|
||||
depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
|
||||
depends on MIPS || COMPILE_TEST
|
||||
help
|
||||
If you have a system using an Ingenic SoC and wish to make use of
|
||||
its UARTs, say Y to this option. If unsure, say N.
|
||||
@ -378,6 +409,16 @@ config SERIAL_8250_MID
|
||||
present on the UART found on Intel Medfield SOC and various other
|
||||
Intel platforms.
|
||||
|
||||
config SERIAL_8250_MOXA
|
||||
tristate "MOXA SmartIO MUE support"
|
||||
depends on SERIAL_8250 && PCI
|
||||
help
|
||||
Say Y here if you have a Moxa SmartIO MUE multiport serial card.
|
||||
If unsure, say N.
|
||||
|
||||
This driver can also be built as a module. The module will be called
|
||||
8250_moxa. If you want to do that, say M here.
|
||||
|
||||
config SERIAL_OF_PLATFORM
|
||||
tristate "Devicetree based probing for 8250 ports"
|
||||
depends on SERIAL_8250 && OF
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
|
||||
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
||||
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
|
||||
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
|
||||
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
|
||||
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
|
||||
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
|
||||
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
|
||||
@ -28,6 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
||||
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
|
||||
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
|
||||
obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
|
||||
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
|
||||
|
||||
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
|
||||
|
@ -28,7 +28,7 @@
|
||||
and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this
|
||||
file under either the MPL or the GPL.
|
||||
|
||||
|
||||
======================================================================*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = {
|
||||
};
|
||||
|
||||
|
||||
static int serial_config(struct pcmcia_device * link);
|
||||
static int serial_config(struct pcmcia_device *link);
|
||||
|
||||
|
||||
static void serial_remove(struct pcmcia_device *link)
|
||||
@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link)
|
||||
dev_dbg(&link->dev, "serial_attach()\n");
|
||||
|
||||
/* Create new serial device */
|
||||
info = kzalloc(sizeof (*info), GFP_KERNEL);
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->p_dev = link;
|
||||
@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link)
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
|
||||
static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
|
||||
unsigned int iobase, int irq)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link)
|
||||
struct serial_info *info = link->priv;
|
||||
int i = -ENODEV, try;
|
||||
|
||||
/* First pass: look for a config entry that looks normal.
|
||||
* Two tries: without IO aliases, then with aliases */
|
||||
/*
|
||||
* First pass: look for a config entry that looks normal.
|
||||
* Two tries: without IO aliases, then with aliases.
|
||||
*/
|
||||
link->config_flags |= CONF_AUTO_SET_VPP;
|
||||
for (try = 0; try < 4; try++)
|
||||
if (!pcmcia_loop_config(link, simple_config_check, &try))
|
||||
goto found_port;
|
||||
|
||||
/* Second pass: try to find an entry that isn't picky about
|
||||
its base address, then try to grab any standard serial port
|
||||
address, and finally try to get any free port. */
|
||||
/*
|
||||
* Second pass: try to find an entry that isn't picky about
|
||||
* its base address, then try to grab any standard serial port
|
||||
* address, and finally try to get any free port.
|
||||
*/
|
||||
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
|
||||
goto found_port;
|
||||
|
||||
@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
|
||||
if (p_dev->resource[1]->end)
|
||||
return -EINVAL;
|
||||
|
||||
/* The quad port cards have bad CIS's, so just look for a
|
||||
window larger than 8 ports and assume it will be right */
|
||||
/*
|
||||
* The quad port cards have bad CIS's, so just look for a
|
||||
* window larger than 8 ports and assume it will be right.
|
||||
*/
|
||||
if (p_dev->resource[0]->end <= 8)
|
||||
return -EINVAL;
|
||||
|
||||
@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link)
|
||||
info->multi = 2;
|
||||
if (pcmcia_loop_config(link, multi_config_check_notpicky,
|
||||
&base2)) {
|
||||
dev_warn(&link->dev, "no usable port range "
|
||||
"found, giving up\n");
|
||||
dev_warn(&link->dev,
|
||||
"no usable port range found, giving up\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
|
||||
}
|
||||
|
||||
|
||||
static int serial_config(struct pcmcia_device * link)
|
||||
static int serial_config(struct pcmcia_device *link)
|
||||
{
|
||||
struct serial_info *info = link->priv;
|
||||
int i;
|
||||
@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Another check for dual-serial cards: look for either serial or
|
||||
multifunction cards that ask for appropriate IO port ranges */
|
||||
/*
|
||||
* Another check for dual-serial cards: look for either serial or
|
||||
* multifunction cards that ask for appropriate IO port ranges.
|
||||
*/
|
||||
if ((info->multi == 0) &&
|
||||
(link->has_func_id) &&
|
||||
(link->socket->pcmcia_pfc == 0) &&
|
||||
@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = {
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
|
||||
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
|
||||
@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = {
|
||||
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
|
||||
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
|
||||
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
|
||||
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
|
||||
PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
|
||||
/* too generic */
|
||||
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
|
||||
|
@ -610,6 +610,7 @@ config SERIAL_UARTLITE_CONSOLE
|
||||
bool "Support for console on Xilinx uartlite serial port"
|
||||
depends on SERIAL_UARTLITE=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Say Y here if you wish to use a Xilinx uartlite as the system
|
||||
console (the system console is the device which receives all kernel
|
||||
@ -732,7 +733,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
|
||||
|
||||
config SERIAL_SH_SCI
|
||||
tristate "SuperH SCI(F) serial port support"
|
||||
depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
|
||||
depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
|
||||
config SERIAL_SH_SCI_NR_UARTS
|
||||
@ -745,6 +746,12 @@ config SERIAL_SH_SCI_CONSOLE
|
||||
depends on SERIAL_SH_SCI=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
config SERIAL_SH_SCI_EARLYCON
|
||||
bool "Support for early console on SuperH SCI(F)"
|
||||
depends on SERIAL_SH_SCI=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
|
||||
config SERIAL_SH_SCI_DMA
|
||||
bool "DMA support"
|
||||
depends on SERIAL_SH_SCI && DMA_ENGINE
|
||||
@ -793,17 +800,6 @@ config SERIAL_CORE_CONSOLE
|
||||
config CONSOLE_POLL
|
||||
bool
|
||||
|
||||
config SERIAL_68328
|
||||
bool "68328 serial support"
|
||||
depends on M68328 || M68EZ328 || M68VZ328
|
||||
help
|
||||
This driver supports the built-in serial port of the Motorola 68328
|
||||
(standard, EZ and VZ varieties).
|
||||
|
||||
config SERIAL_68328_RTS_CTS
|
||||
bool "Support RTS/CTS on 68328 serial port"
|
||||
depends on SERIAL_68328
|
||||
|
||||
config SERIAL_MCF
|
||||
bool "Coldfire serial support"
|
||||
depends on COLDFIRE
|
||||
@ -1606,6 +1602,28 @@ config SERIAL_STM32_CONSOLE
|
||||
depends on SERIAL_STM32=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
config SERIAL_MVEBU_UART
|
||||
bool "Marvell EBU serial port support"
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for Marvell EBU SoC's UART. If you have a machine
|
||||
based on the Armada-3700 SoC and wish to use the on-board serial
|
||||
port,
|
||||
say 'Y' here.
|
||||
Otherwise, say 'N'.
|
||||
|
||||
config SERIAL_MVEBU_CONSOLE
|
||||
bool "Console on Marvell EBU serial port"
|
||||
depends on SERIAL_MVEBU_UART
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
default y
|
||||
help
|
||||
Say 'Y' here if you wish to use Armada-3700 UART as the system console.
|
||||
(the system console is the device which receives all kernel messages
|
||||
and warnings and which allows logins in single user mode)
|
||||
Otherwise, say 'N'.
|
||||
|
||||
endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
|
@ -34,7 +34,6 @@ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
|
||||
obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
|
||||
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
|
||||
obj-$(CONFIG_SERIAL_MUX) += mux.o
|
||||
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
|
||||
obj-$(CONFIG_SERIAL_MCF) += mcf.o
|
||||
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
|
||||
obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
|
||||
@ -91,6 +90,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
|
||||
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
|
||||
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
|
||||
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
|
||||
obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
@ -187,7 +187,7 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
|
||||
[REG_DMACR] = ZX_UART011_DMACR,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_zte = {
|
||||
static struct vendor_data vendor_zte __maybe_unused = {
|
||||
.reg_offset = pl011_zte_offsets,
|
||||
.access_32b = true,
|
||||
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
|
||||
@ -420,7 +420,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
/* Optionally make use of an RX channel as well */
|
||||
chan = dma_request_slave_channel(dev, "rx");
|
||||
|
||||
if (!chan && plat->dma_rx_param) {
|
||||
if (!chan && plat && plat->dma_rx_param) {
|
||||
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
|
||||
|
||||
if (!chan) {
|
||||
@ -1167,7 +1167,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
||||
|
||||
/* Disable RX and TX DMA */
|
||||
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
|
||||
barrier();
|
||||
cpu_relax();
|
||||
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
|
||||
@ -1611,7 +1611,7 @@ static void pl011_put_poll_char(struct uart_port *port,
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
|
||||
barrier();
|
||||
cpu_relax();
|
||||
|
||||
pl011_write(ch, uap, REG_DR);
|
||||
}
|
||||
@ -1947,6 +1947,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
lcr_h |= UART01x_LCRH_PEN;
|
||||
if (!(termios->c_cflag & PARODD))
|
||||
lcr_h |= UART01x_LCRH_EPS;
|
||||
if (termios->c_cflag & CMSPAR)
|
||||
lcr_h |= UART011_LCRH_SPS;
|
||||
}
|
||||
if (uap->fifosize > 1)
|
||||
lcr_h |= UART01x_LCRH_FEN;
|
||||
@ -2150,7 +2152,7 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
|
||||
barrier();
|
||||
cpu_relax();
|
||||
pl011_write(ch, uap, REG_DR);
|
||||
}
|
||||
|
||||
@ -2158,7 +2160,7 @@ static void
|
||||
pl011_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_ports[co->index];
|
||||
unsigned int status, old_cr = 0, new_cr;
|
||||
unsigned int old_cr = 0, new_cr;
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
@ -2188,9 +2190,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the TCR
|
||||
*/
|
||||
do {
|
||||
status = pl011_read(uap, REG_FR);
|
||||
} while (status & UART01x_FR_BUSY);
|
||||
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY)
|
||||
cpu_relax();
|
||||
if (!uap->vendor->always_enabled)
|
||||
pl011_write(old_cr, uap, REG_CR);
|
||||
|
||||
@ -2302,13 +2303,13 @@ static struct console amba_console = {
|
||||
static void pl011_putc(struct uart_port *port, int c)
|
||||
{
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
;
|
||||
cpu_relax();
|
||||
if (port->iotype == UPIO_MEM32)
|
||||
writel(c, port->membase + UART01x_DR);
|
||||
else
|
||||
writeb(c, port->membase + UART01x_DR);
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
|
||||
;
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static void pl011_early_write(struct console *con, const char *s, unsigned n)
|
||||
@ -2327,7 +2328,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
|
||||
device->con->write = pl011_early_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
|
||||
|
||||
#else
|
||||
|
@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
|
||||
dev->con->write = arc_early_serial_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(arc_uart, arc_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
|
||||
|
||||
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
|
||||
|
@ -159,8 +159,9 @@ struct atmel_uart_port {
|
||||
u32 rts_high;
|
||||
u32 rts_low;
|
||||
bool ms_irq_enabled;
|
||||
bool is_usart; /* usart or uart */
|
||||
struct timer_list uart_timer; /* uart timer */
|
||||
u32 rtor; /* address of receiver timeout register if it exists */
|
||||
bool has_hw_timer;
|
||||
struct timer_list uart_timer;
|
||||
|
||||
bool suspended;
|
||||
unsigned int pending;
|
||||
@ -1710,19 +1711,24 @@ static void atmel_get_ip_name(struct uart_port *port)
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
int name = atmel_uart_readl(port, ATMEL_US_NAME);
|
||||
u32 version;
|
||||
int usart, uart;
|
||||
/* usart and uart ascii */
|
||||
usart = 0x55534152;
|
||||
uart = 0x44424755;
|
||||
u32 usart, dbgu_uart, new_uart;
|
||||
/* ASCII decoding for IP version */
|
||||
usart = 0x55534152; /* USAR(T) */
|
||||
dbgu_uart = 0x44424755; /* DBGU */
|
||||
new_uart = 0x55415254; /* UART */
|
||||
|
||||
atmel_port->is_usart = false;
|
||||
atmel_port->has_hw_timer = false;
|
||||
|
||||
if (name == usart) {
|
||||
dev_dbg(port->dev, "This is usart\n");
|
||||
atmel_port->is_usart = true;
|
||||
} else if (name == uart) {
|
||||
dev_dbg(port->dev, "This is uart\n");
|
||||
atmel_port->is_usart = false;
|
||||
if (name == new_uart) {
|
||||
dev_dbg(port->dev, "Uart with hw timer");
|
||||
atmel_port->has_hw_timer = true;
|
||||
atmel_port->rtor = ATMEL_UA_RTOR;
|
||||
} else if (name == usart) {
|
||||
dev_dbg(port->dev, "Usart\n");
|
||||
atmel_port->has_hw_timer = true;
|
||||
atmel_port->rtor = ATMEL_US_RTOR;
|
||||
} else if (name == dbgu_uart) {
|
||||
dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
|
||||
} else {
|
||||
/* fallback for older SoCs: use version field */
|
||||
version = atmel_uart_readl(port, ATMEL_US_VERSION);
|
||||
@ -1730,12 +1736,12 @@ static void atmel_get_ip_name(struct uart_port *port)
|
||||
case 0x302:
|
||||
case 0x10213:
|
||||
dev_dbg(port->dev, "This version is usart\n");
|
||||
atmel_port->is_usart = true;
|
||||
atmel_port->has_hw_timer = true;
|
||||
atmel_port->rtor = ATMEL_US_RTOR;
|
||||
break;
|
||||
case 0x203:
|
||||
case 0x10202:
|
||||
dev_dbg(port->dev, "This version is uart\n");
|
||||
atmel_port->is_usart = false;
|
||||
break;
|
||||
default:
|
||||
dev_err(port->dev, "Not supported ip name nor version, set to uart\n");
|
||||
@ -1835,12 +1841,13 @@ static int atmel_startup(struct uart_port *port)
|
||||
|
||||
if (atmel_use_pdc_rx(port)) {
|
||||
/* set UART timeout */
|
||||
if (!atmel_port->is_usart) {
|
||||
if (!atmel_port->has_hw_timer) {
|
||||
mod_timer(&atmel_port->uart_timer,
|
||||
jiffies + uart_poll_timeout(port));
|
||||
/* set USART timeout */
|
||||
} else {
|
||||
atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
|
||||
atmel_uart_writel(port, atmel_port->rtor,
|
||||
PDC_RX_TIMEOUT);
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
|
||||
|
||||
atmel_uart_writel(port, ATMEL_US_IER,
|
||||
@ -1850,12 +1857,13 @@ static int atmel_startup(struct uart_port *port)
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
|
||||
} else if (atmel_use_dma_rx(port)) {
|
||||
/* set UART timeout */
|
||||
if (!atmel_port->is_usart) {
|
||||
if (!atmel_port->has_hw_timer) {
|
||||
mod_timer(&atmel_port->uart_timer,
|
||||
jiffies + uart_poll_timeout(port));
|
||||
/* set USART timeout */
|
||||
} else {
|
||||
atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT);
|
||||
atmel_uart_writel(port, atmel_port->rtor,
|
||||
PDC_RX_TIMEOUT);
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO);
|
||||
|
||||
atmel_uart_writel(port, ATMEL_US_IER,
|
||||
@ -2478,13 +2486,13 @@ static int __init atmel_console_init(void)
|
||||
struct atmel_uart_data *pdata =
|
||||
dev_get_platdata(&atmel_default_console_device->dev);
|
||||
int id = pdata->num;
|
||||
struct atmel_uart_port *port = &atmel_ports[id];
|
||||
struct atmel_uart_port *atmel_port = &atmel_ports[id];
|
||||
|
||||
port->backup_imr = 0;
|
||||
port->uart.line = id;
|
||||
atmel_port->backup_imr = 0;
|
||||
atmel_port->uart.line = id;
|
||||
|
||||
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
|
||||
ret = atmel_init_port(port, atmel_default_console_device);
|
||||
ret = atmel_init_port(atmel_port, atmel_default_console_device);
|
||||
if (ret)
|
||||
return ret;
|
||||
register_console(&atmel_console);
|
||||
@ -2599,23 +2607,23 @@ static int atmel_serial_resume(struct platform_device *pdev)
|
||||
#define atmel_serial_resume NULL
|
||||
#endif
|
||||
|
||||
static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
|
||||
static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
port->fifo_size = 0;
|
||||
port->rts_low = 0;
|
||||
port->rts_high = 0;
|
||||
atmel_port->fifo_size = 0;
|
||||
atmel_port->rts_low = 0;
|
||||
atmel_port->rts_high = 0;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"atmel,fifo-size",
|
||||
&port->fifo_size))
|
||||
&atmel_port->fifo_size))
|
||||
return;
|
||||
|
||||
if (!port->fifo_size)
|
||||
if (!atmel_port->fifo_size)
|
||||
return;
|
||||
|
||||
if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
|
||||
port->fifo_size = 0;
|
||||
if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) {
|
||||
atmel_port->fifo_size = 0;
|
||||
dev_err(&pdev->dev, "Invalid FIFO size\n");
|
||||
return;
|
||||
}
|
||||
@ -2628,22 +2636,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *port,
|
||||
* Threshold to a reasonably high value respecting this 16 data
|
||||
* empirical rule when possible.
|
||||
*/
|
||||
port->rts_high = max_t(int, port->fifo_size >> 1,
|
||||
port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
|
||||
port->rts_low = max_t(int, port->fifo_size >> 2,
|
||||
port->fifo_size - ATMEL_RTS_LOW_OFFSET);
|
||||
atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1,
|
||||
atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET);
|
||||
atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2,
|
||||
atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET);
|
||||
|
||||
dev_info(&pdev->dev, "Using FIFO (%u data)\n",
|
||||
port->fifo_size);
|
||||
atmel_port->fifo_size);
|
||||
dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n",
|
||||
port->rts_high);
|
||||
atmel_port->rts_high);
|
||||
dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n",
|
||||
port->rts_low);
|
||||
atmel_port->rts_low);
|
||||
}
|
||||
|
||||
static int atmel_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_uart_port *port;
|
||||
struct atmel_uart_port *atmel_port;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
void *data;
|
||||
@ -2674,99 +2682,133 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
port = &atmel_ports[ret];
|
||||
port->backup_imr = 0;
|
||||
port->uart.line = ret;
|
||||
atmel_serial_probe_fifos(port, pdev);
|
||||
atmel_port = &atmel_ports[ret];
|
||||
atmel_port->backup_imr = 0;
|
||||
atmel_port->uart.line = ret;
|
||||
atmel_serial_probe_fifos(atmel_port, pdev);
|
||||
|
||||
spin_lock_init(&port->lock_suspended);
|
||||
spin_lock_init(&atmel_port->lock_suspended);
|
||||
|
||||
ret = atmel_init_port(port, pdev);
|
||||
ret = atmel_init_port(atmel_port, pdev);
|
||||
if (ret)
|
||||
goto err_clear_bit;
|
||||
|
||||
port->gpios = mctrl_gpio_init(&port->uart, 0);
|
||||
if (IS_ERR(port->gpios)) {
|
||||
ret = PTR_ERR(port->gpios);
|
||||
atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0);
|
||||
if (IS_ERR(atmel_port->gpios)) {
|
||||
ret = PTR_ERR(atmel_port->gpios);
|
||||
goto err_clear_bit;
|
||||
}
|
||||
|
||||
if (!atmel_use_pdc_rx(&port->uart)) {
|
||||
if (!atmel_use_pdc_rx(&atmel_port->uart)) {
|
||||
ret = -ENOMEM;
|
||||
data = kmalloc(sizeof(struct atmel_uart_char)
|
||||
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
|
||||
if (!data)
|
||||
goto err_alloc_ring;
|
||||
port->rx_ring.buf = data;
|
||||
atmel_port->rx_ring.buf = data;
|
||||
}
|
||||
|
||||
rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
|
||||
rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED;
|
||||
|
||||
ret = uart_add_one_port(&atmel_uart, &port->uart);
|
||||
ret = uart_add_one_port(&atmel_uart, &atmel_port->uart);
|
||||
if (ret)
|
||||
goto err_add_port;
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||
if (atmel_is_console_port(&port->uart)
|
||||
if (atmel_is_console_port(&atmel_port->uart)
|
||||
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
|
||||
/*
|
||||
* The serial core enabled the clock for us, so undo
|
||||
* the clk_prepare_enable() in atmel_console_setup()
|
||||
*/
|
||||
clk_disable_unprepare(port->clk);
|
||||
clk_disable_unprepare(atmel_port->clk);
|
||||
}
|
||||
#endif
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
platform_set_drvdata(pdev, port);
|
||||
platform_set_drvdata(pdev, atmel_port);
|
||||
|
||||
/*
|
||||
* The peripheral clock has been disabled by atmel_init_port():
|
||||
* enable it before accessing I/O registers
|
||||
*/
|
||||
clk_prepare_enable(port->clk);
|
||||
clk_prepare_enable(atmel_port->clk);
|
||||
|
||||
if (rs485_enabled) {
|
||||
atmel_uart_writel(&port->uart, ATMEL_US_MR,
|
||||
atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR,
|
||||
ATMEL_US_USMODE_NORMAL);
|
||||
atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN);
|
||||
atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR,
|
||||
ATMEL_US_RTSEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get port name of usart or uart
|
||||
*/
|
||||
atmel_get_ip_name(&port->uart);
|
||||
atmel_get_ip_name(&atmel_port->uart);
|
||||
|
||||
/*
|
||||
* The peripheral clock can now safely be disabled till the port
|
||||
* is used
|
||||
*/
|
||||
clk_disable_unprepare(port->clk);
|
||||
clk_disable_unprepare(atmel_port->clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_port:
|
||||
kfree(port->rx_ring.buf);
|
||||
port->rx_ring.buf = NULL;
|
||||
kfree(atmel_port->rx_ring.buf);
|
||||
atmel_port->rx_ring.buf = NULL;
|
||||
err_alloc_ring:
|
||||
if (!atmel_is_console_port(&port->uart)) {
|
||||
clk_put(port->clk);
|
||||
port->clk = NULL;
|
||||
if (!atmel_is_console_port(&atmel_port->uart)) {
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
}
|
||||
err_clear_bit:
|
||||
clear_bit(port->uart.line, atmel_ports_in_use);
|
||||
clear_bit(atmel_port->uart.line, atmel_ports_in_use);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Even if the driver is not modular, it makes sense to be able to
|
||||
* unbind a device: there can be many bound devices, and there are
|
||||
* situations where dynamic binding and unbinding can be useful.
|
||||
*
|
||||
* For example, a connected device can require a specific firmware update
|
||||
* protocol that needs bitbanging on IO lines, but use the regular serial
|
||||
* port in the normal case.
|
||||
*/
|
||||
static int atmel_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
int ret = 0;
|
||||
|
||||
tasklet_kill(&atmel_port->tasklet);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
ret = uart_remove_one_port(&atmel_uart, port);
|
||||
|
||||
kfree(atmel_port->rx_ring.buf);
|
||||
|
||||
/* "port" is allocated statically, so we shouldn't free it */
|
||||
|
||||
clear_bit(port->line, atmel_ports_in_use);
|
||||
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver atmel_serial_driver = {
|
||||
.probe = atmel_serial_probe,
|
||||
.remove = atmel_serial_remove,
|
||||
.suspend = atmel_serial_suspend,
|
||||
.resume = atmel_serial_resume,
|
||||
.driver = {
|
||||
.name = "atmel_usart",
|
||||
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -450,6 +450,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
|
||||
struct clps711x_port *s;
|
||||
struct resource *res;
|
||||
struct clk *uart_clk;
|
||||
int irq;
|
||||
|
||||
if (index < 0 || index >= UART_CLPS711X_NR)
|
||||
return -EINVAL;
|
||||
@ -467,12 +468,13 @@ static int uart_clps711x_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(s->port.membase))
|
||||
return PTR_ERR(s->port.membase);
|
||||
|
||||
s->port.irq = platform_get_irq(pdev, 0);
|
||||
if (IS_ERR_VALUE(s->port.irq))
|
||||
return s->port.irq;
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
s->port.irq = irq;
|
||||
|
||||
s->rx_irq = platform_get_irq(pdev, 1);
|
||||
if (IS_ERR_VALUE(s->rx_irq))
|
||||
if (s->rx_irq < 0)
|
||||
return s->rx_irq;
|
||||
|
||||
if (!np) {
|
||||
|
@ -1413,9 +1413,8 @@ rs_stop(struct tty_struct *tty)
|
||||
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
|
||||
STOP_CHAR(info->port.tty));
|
||||
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
|
||||
if (tty->termios.c_iflag & IXON ) {
|
||||
if (I_IXON(tty))
|
||||
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
|
||||
}
|
||||
|
||||
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
|
||||
local_irq_restore(flags);
|
||||
@ -1436,9 +1435,8 @@ rs_start(struct tty_struct *tty)
|
||||
info->xmit.tail,SERIAL_XMIT_SIZE)));
|
||||
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
|
||||
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
|
||||
if (tty->termios.c_iflag & IXON ) {
|
||||
if (I_IXON(tty))
|
||||
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
|
||||
}
|
||||
|
||||
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
|
||||
if (!info->uses_dma_out &&
|
||||
@ -2968,7 +2966,7 @@ static int rs_raw_write(struct tty_struct *tty,
|
||||
|
||||
local_save_flags(flags);
|
||||
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
|
||||
DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
DFLOW(DEBUG_LOG(info->line, "ldisc\n"));
|
||||
|
||||
|
||||
/* The local_irq_disable/restore_flags pairs below are needed
|
||||
@ -3161,13 +3159,12 @@ rs_throttle(struct tty_struct * tty)
|
||||
{
|
||||
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
printk("throttle %s: %lu....\n", tty_name(tty),
|
||||
(unsigned long)tty->ldisc.chars_in_buffer(tty));
|
||||
printk("throttle %s ....\n", tty_name(tty));
|
||||
#endif
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_throttle\n"));
|
||||
|
||||
/* Do RTS before XOFF since XOFF might take some time */
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
/* Turn off RTS line */
|
||||
e100_rts(info, 0);
|
||||
}
|
||||
@ -3181,13 +3178,12 @@ rs_unthrottle(struct tty_struct * tty)
|
||||
{
|
||||
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
printk("unthrottle %s: %lu....\n", tty_name(tty),
|
||||
(unsigned long)tty->ldisc.chars_in_buffer(tty));
|
||||
printk("unthrottle %s ....\n", tty_name(tty));
|
||||
#endif
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc\n"));
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
|
||||
/* Do RTS before XOFF since XOFF might take some time */
|
||||
if (tty->termios.c_cflag & CRTSCTS) {
|
||||
if (C_CRTSCTS(tty)) {
|
||||
/* Assert RTS line */
|
||||
e100_rts(info, 1);
|
||||
}
|
||||
@ -3555,8 +3551,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
change_speed(info);
|
||||
|
||||
/* Handle turning off CRTSCTS */
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
|
||||
rs_start(tty);
|
||||
|
||||
}
|
||||
@ -3615,7 +3610,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
info->port.flags |= ASYNC_CLOSING;
|
||||
/*
|
||||
* Now we wait for the transmit buffer to clear; and we notify
|
||||
* the line discipline to only process XON/XOFF characters.
|
||||
@ -3654,7 +3648,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
schedule_timeout_interruptible(info->port.close_delay);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* port closed */
|
||||
@ -3767,9 +3761,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tty->termios.c_cflag & CLOCAL) {
|
||||
do_clocal = 1;
|
||||
}
|
||||
if (C_CLOCAL(tty))
|
||||
do_clocal = 1;
|
||||
|
||||
/*
|
||||
* Block waiting for the carrier detect and the line to become
|
||||
|
@ -453,7 +453,7 @@ static struct uart_driver digicolor_uart = {
|
||||
static int digicolor_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret, index;
|
||||
int irq, ret, index;
|
||||
struct digicolor_port *dp;
|
||||
struct resource *res;
|
||||
struct clk *uart_clk;
|
||||
@ -481,9 +481,10 @@ static int digicolor_uart_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(dp->port.membase))
|
||||
return PTR_ERR(dp->port.membase);
|
||||
|
||||
dp->port.irq = platform_get_irq(pdev, 0);
|
||||
if (IS_ERR_VALUE(dp->port.irq))
|
||||
return dp->port.irq;
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
dp->port.irq = irq;
|
||||
|
||||
dp->port.iotype = UPIO_MEM;
|
||||
dp->port.uartclk = clk_get_rate(uart_clk);
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||||
#include <asm/fixmap.h>
|
||||
@ -28,22 +29,15 @@
|
||||
#include <asm/serial.h>
|
||||
|
||||
static struct console early_con = {
|
||||
.name = "uart", /* 8250 console switch requires this name */
|
||||
.name = "uart", /* fixed up at earlycon registration */
|
||||
.flags = CON_PRINTBUFFER | CON_BOOT,
|
||||
.index = -1,
|
||||
.index = 0,
|
||||
};
|
||||
|
||||
static struct earlycon_device early_console_dev = {
|
||||
.con = &early_con,
|
||||
};
|
||||
|
||||
extern struct earlycon_id __earlycon_table[];
|
||||
static const struct earlycon_id __earlycon_table_sentinel
|
||||
__used __section(__earlycon_table_end);
|
||||
|
||||
static const struct of_device_id __earlycon_of_table_sentinel
|
||||
__used __section(__earlycon_of_table_end);
|
||||
|
||||
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
|
||||
{
|
||||
void __iomem *base;
|
||||
@ -61,6 +55,39 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
|
||||
return base;
|
||||
}
|
||||
|
||||
static void __init earlycon_init(struct earlycon_device *device,
|
||||
const char *name)
|
||||
{
|
||||
struct console *earlycon = device->con;
|
||||
struct uart_port *port = &device->port;
|
||||
const char *s;
|
||||
size_t len;
|
||||
|
||||
/* scan backwards from end of string for first non-numeral */
|
||||
for (s = name + strlen(name);
|
||||
s > name && s[-1] >= '0' && s[-1] <= '9';
|
||||
s--)
|
||||
;
|
||||
if (*s)
|
||||
earlycon->index = simple_strtoul(s, NULL, 10);
|
||||
len = s - name;
|
||||
strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
|
||||
earlycon->data = &early_console_dev;
|
||||
|
||||
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
|
||||
port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
|
||||
pr_info("%s%d at MMIO%s %pa (options '%s')\n",
|
||||
earlycon->name, earlycon->index,
|
||||
(port->iotype == UPIO_MEM) ? "" :
|
||||
(port->iotype == UPIO_MEM16) ? "16" :
|
||||
(port->iotype == UPIO_MEM32) ? "32" : "32be",
|
||||
&port->mapbase, device->options);
|
||||
else
|
||||
pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
|
||||
earlycon->name, earlycon->index,
|
||||
port->iobase, device->options);
|
||||
}
|
||||
|
||||
static int __init parse_options(struct earlycon_device *device, char *options)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
@ -97,19 +124,6 @@ static int __init parse_options(struct earlycon_device *device, char *options)
|
||||
strlcpy(device->options, options, length);
|
||||
}
|
||||
|
||||
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
|
||||
port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
|
||||
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
|
||||
(port->iotype == UPIO_MEM) ? "" :
|
||||
(port->iotype == UPIO_MEM16) ? "16" :
|
||||
(port->iotype == UPIO_MEM32) ? "32" : "32be",
|
||||
(unsigned long long)port->mapbase,
|
||||
device->options);
|
||||
else
|
||||
pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
|
||||
port->iobase,
|
||||
device->options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -127,7 +141,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
|
||||
if (port->mapbase)
|
||||
port->membase = earlycon_map(port->mapbase, 64);
|
||||
|
||||
early_console_dev.con->data = &early_console_dev;
|
||||
earlycon_init(&early_console_dev, match->name);
|
||||
err = match->setup(&early_console_dev, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -166,7 +180,7 @@ int __init setup_earlycon(char *buf)
|
||||
if (early_con.flags & CON_ENABLED)
|
||||
return -EALREADY;
|
||||
|
||||
for (match = __earlycon_table; match->name[0]; match++) {
|
||||
for (match = __earlycon_table; match < __earlycon_table_end; match++) {
|
||||
size_t len = strlen(match->name);
|
||||
|
||||
if (strncmp(buf, match->name, len))
|
||||
@ -204,20 +218,62 @@ static int __init param_setup_earlycon(char *buf)
|
||||
}
|
||||
early_param("earlycon", param_setup_earlycon);
|
||||
|
||||
int __init of_setup_earlycon(unsigned long addr,
|
||||
int (*setup)(struct earlycon_device *, const char *))
|
||||
#ifdef CONFIG_OF_EARLY_FLATTREE
|
||||
|
||||
int __init of_setup_earlycon(const struct earlycon_id *match,
|
||||
unsigned long node,
|
||||
const char *options)
|
||||
{
|
||||
int err;
|
||||
struct uart_port *port = &early_console_dev.port;
|
||||
const __be32 *val;
|
||||
bool big_endian;
|
||||
u64 addr;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->iotype = UPIO_MEM;
|
||||
addr = of_flat_dt_translate_address(node);
|
||||
if (addr == OF_BAD_ADDR) {
|
||||
pr_warn("[%s] bad address\n", match->name);
|
||||
return -ENXIO;
|
||||
}
|
||||
port->mapbase = addr;
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
port->membase = earlycon_map(addr, SZ_4K);
|
||||
port->membase = earlycon_map(port->mapbase, SZ_4K);
|
||||
|
||||
early_console_dev.con->data = &early_console_dev;
|
||||
err = setup(&early_console_dev, NULL);
|
||||
val = of_get_flat_dt_prop(node, "reg-offset", NULL);
|
||||
if (val)
|
||||
port->mapbase += be32_to_cpu(*val);
|
||||
val = of_get_flat_dt_prop(node, "reg-shift", NULL);
|
||||
if (val)
|
||||
port->regshift = be32_to_cpu(*val);
|
||||
big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
|
||||
(IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
|
||||
of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
|
||||
val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
|
||||
if (val) {
|
||||
switch (be32_to_cpu(*val)) {
|
||||
case 1:
|
||||
port->iotype = UPIO_MEM;
|
||||
break;
|
||||
case 2:
|
||||
port->iotype = UPIO_MEM16;
|
||||
break;
|
||||
case 4:
|
||||
port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
|
||||
break;
|
||||
default:
|
||||
pr_warn("[%s] unsupported reg-io-width\n", match->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (options) {
|
||||
strlcpy(early_console_dev.options, options,
|
||||
sizeof(early_console_dev.options));
|
||||
}
|
||||
earlycon_init(&early_console_dev, match->name);
|
||||
err = match->setup(&early_console_dev, options);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!early_console_dev.con->write)
|
||||
@ -227,3 +283,5 @@ int __init of_setup_earlycon(unsigned long addr,
|
||||
register_console(early_console_dev.con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF_EARLY_FLATTREE */
|
||||
|
@ -395,8 +395,10 @@ static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
|
||||
|
||||
if (h1 == 0 && h2 == 0) {
|
||||
*received_cts = 0;
|
||||
*more = 0;
|
||||
return IFX_SPI_HEADER_0;
|
||||
} else if (h1 == 0xffff && h2 == 0xffff) {
|
||||
*more = 0;
|
||||
/* spi_slave_cts remains as it was */
|
||||
return IFX_SPI_HEADER_F;
|
||||
}
|
||||
@ -688,6 +690,7 @@ static void ifx_spi_complete(void *ctx)
|
||||
ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
|
||||
(size_t)actual_length);
|
||||
} else {
|
||||
more = 0;
|
||||
dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
|
||||
ifx_dev->spi_msg.status);
|
||||
}
|
||||
|
@ -2166,7 +2166,8 @@ static int imx_serial_port_suspend(struct device *dev)
|
||||
|
||||
uart_suspend_port(&imx_reg, &sport->port);
|
||||
|
||||
return 0;
|
||||
/* Needed to enable clock in suspend_noirq */
|
||||
return clk_prepare(sport->clk_ipg);
|
||||
}
|
||||
|
||||
static int imx_serial_port_resume(struct device *dev)
|
||||
@ -2179,6 +2180,8 @@ static int imx_serial_port_resume(struct device *dev)
|
||||
|
||||
uart_resume_port(&imx_reg, &sport->port);
|
||||
|
||||
clk_unprepare(sport->clk_ipg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -529,7 +529,6 @@ void jsm_input(struct jsm_channel *ch)
|
||||
int data_len;
|
||||
unsigned long lock_flags;
|
||||
int len = 0;
|
||||
int n = 0;
|
||||
int s = 0;
|
||||
int i = 0;
|
||||
|
||||
@ -569,8 +568,7 @@ void jsm_input(struct jsm_channel *ch)
|
||||
*If the device is not open, or CREAD is off, flush
|
||||
*input data and return immediately.
|
||||
*/
|
||||
if (!tp ||
|
||||
!(tp->termios.c_cflag & CREAD) ) {
|
||||
if (!tp || !C_CREAD(tp)) {
|
||||
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev,
|
||||
"input. dropping %d bytes on port %d...\n",
|
||||
@ -598,16 +596,15 @@ void jsm_input(struct jsm_channel *ch)
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
|
||||
|
||||
len = tty_buffer_request_room(port, data_len);
|
||||
n = len;
|
||||
|
||||
/*
|
||||
* n now contains the most amount of data we can copy,
|
||||
* len now contains the most amount of data we can copy,
|
||||
* bounded either by the flip buffer size or the amount
|
||||
* of data the card actually has pending...
|
||||
*/
|
||||
while (n) {
|
||||
while (len) {
|
||||
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
|
||||
s = min(s, n);
|
||||
s = min(s, len);
|
||||
|
||||
if (s <= 0)
|
||||
break;
|
||||
@ -638,7 +635,7 @@ void jsm_input(struct jsm_channel *ch)
|
||||
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
|
||||
}
|
||||
tail += s;
|
||||
n -= s;
|
||||
len -= s;
|
||||
/* Flip queue if needed */
|
||||
tail &= rmask;
|
||||
}
|
||||
|
@ -47,59 +47,26 @@
|
||||
#define BAUD_RATE 115200
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
#include "m32r_sio.h"
|
||||
#include "m32r_sio_reg.h"
|
||||
|
||||
/*
|
||||
* Debugging.
|
||||
*/
|
||||
#if 0
|
||||
#define DEBUG_AUTOCONF(fmt...) printk(fmt)
|
||||
#else
|
||||
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define DEBUG_INTR(fmt...) printk(fmt)
|
||||
#else
|
||||
#define DEBUG_INTR(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define PASS_LIMIT 256
|
||||
|
||||
#define BASE_BAUD 115200
|
||||
|
||||
/* Standard COM flags */
|
||||
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
|
||||
|
||||
/*
|
||||
* SERIAL_PORT_DFNS tells us about built-in ports that have no
|
||||
* standard enumeration mechanism. Platforms that can find all
|
||||
* serial ports via mechanisms like ACPI or PCI need not supply it.
|
||||
*/
|
||||
static const struct {
|
||||
unsigned int port;
|
||||
unsigned int irq;
|
||||
} old_serial_port[] = {
|
||||
#if defined(CONFIG_PLAT_USRV)
|
||||
|
||||
#define SERIAL_PORT_DFNS \
|
||||
/* UART CLK PORT IRQ FLAGS */ \
|
||||
{ 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \
|
||||
{ 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */
|
||||
|
||||
#else /* !CONFIG_PLAT_USRV */
|
||||
|
||||
#if defined(CONFIG_SERIAL_M32R_PLDSIO)
|
||||
#define SERIAL_PORT_DFNS \
|
||||
{ 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \
|
||||
STD_COM_FLAGS }, /* ttyS0 */
|
||||
/* PORT IRQ FLAGS */
|
||||
{ 0x3F8, PLD_IRQ_UART0 }, /* ttyS0 */
|
||||
{ 0x2F8, PLD_IRQ_UART1 }, /* ttyS1 */
|
||||
#elif defined(CONFIG_SERIAL_M32R_PLDSIO)
|
||||
{ ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV }, /* ttyS0 */
|
||||
#else
|
||||
#define SERIAL_PORT_DFNS \
|
||||
{ 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \
|
||||
STD_COM_FLAGS }, /* ttyS0 */
|
||||
{ M32R_SIO_OFFSET, M32R_IRQ_SIO0_R }, /* ttyS0 */
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_PLAT_USRV */
|
||||
|
||||
static struct old_serial_port old_serial_port[] = {
|
||||
SERIAL_PORT_DFNS
|
||||
};
|
||||
|
||||
#define UART_NR ARRAY_SIZE(old_serial_port)
|
||||
@ -108,19 +75,7 @@ struct uart_sio_port {
|
||||
struct uart_port port;
|
||||
struct timer_list timer; /* "no irq" timer */
|
||||
struct list_head list; /* ports on this IRQ */
|
||||
unsigned short rev;
|
||||
unsigned char acr;
|
||||
unsigned char ier;
|
||||
unsigned char lcr;
|
||||
unsigned char mcr_mask; /* mask of user bits */
|
||||
unsigned char mcr_force; /* mask of forced bits */
|
||||
unsigned char lsr_break_flag;
|
||||
|
||||
/*
|
||||
* We provide a per-port pm hook.
|
||||
*/
|
||||
void (*pm)(struct uart_port *port,
|
||||
unsigned int state, unsigned int old);
|
||||
};
|
||||
|
||||
struct irq_info {
|
||||
@ -345,14 +300,8 @@ static void receive_chars(struct uart_sio_port *up, int *status)
|
||||
*/
|
||||
*status &= up->port.read_status_mask;
|
||||
|
||||
if (up->port.line == up->port.cons->index) {
|
||||
/* Recover the break flag from console xmit */
|
||||
*status |= up->lsr_break_flag;
|
||||
up->lsr_break_flag = 0;
|
||||
}
|
||||
|
||||
if (*status & UART_LSR_BI) {
|
||||
DEBUG_INTR("handling break....");
|
||||
pr_debug("handling break....\n");
|
||||
flag = TTY_BREAK;
|
||||
} else if (*status & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
@ -413,7 +362,7 @@ static void transmit_chars(struct uart_sio_port *up)
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
DEBUG_INTR("THRE...");
|
||||
pr_debug("THRE...\n");
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
m32r_sio_stop_tx(&up->port);
|
||||
@ -425,7 +374,7 @@ static void transmit_chars(struct uart_sio_port *up)
|
||||
static inline void m32r_sio_handle_port(struct uart_sio_port *up,
|
||||
unsigned int status)
|
||||
{
|
||||
DEBUG_INTR("status = %x...", status);
|
||||
pr_debug("status = %x...\n", status);
|
||||
|
||||
if (status & 0x04)
|
||||
receive_chars(up, &status);
|
||||
@ -453,7 +402,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
|
||||
struct list_head *l, *end = NULL;
|
||||
int pass_counter = 0;
|
||||
|
||||
DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
|
||||
pr_debug("m32r_sio_interrupt(%d)...\n", irq);
|
||||
|
||||
#ifdef CONFIG_SERIAL_M32R_PLDSIO
|
||||
// if (irq == PLD_IRQ_SIO0_SND)
|
||||
@ -493,7 +442,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
|
||||
|
||||
spin_unlock(&i->lock);
|
||||
|
||||
DEBUG_INTR("end.\n");
|
||||
pr_debug("end.\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -782,20 +731,9 @@ static void m32r_sio_set_termios(struct uart_port *port,
|
||||
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
|
||||
up->lcr = cval; /* Save LCR */
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
}
|
||||
|
||||
static void m32r_sio_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
if (up->pm)
|
||||
up->pm(port, state, oldstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resource handling. This is complicated by the fact that resources
|
||||
* depend on the port type. Maybe we should be claiming the standard
|
||||
@ -932,7 +870,6 @@ static struct uart_ops m32r_sio_pops = {
|
||||
.startup = m32r_sio_startup,
|
||||
.shutdown = m32r_sio_shutdown,
|
||||
.set_termios = m32r_sio_set_termios,
|
||||
.pm = m32r_sio_pm,
|
||||
.release_port = m32r_sio_release_port,
|
||||
.request_port = m32r_sio_request_port,
|
||||
.config_port = m32r_sio_config_port,
|
||||
@ -951,15 +888,14 @@ static void __init m32r_sio_init_ports(void)
|
||||
return;
|
||||
first = 0;
|
||||
|
||||
for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
|
||||
i++, up++) {
|
||||
for (i = 0, up = m32r_sio_ports; i < UART_NR; i++, up++) {
|
||||
up->port.iobase = old_serial_port[i].port;
|
||||
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
|
||||
up->port.uartclk = old_serial_port[i].baud_base * 16;
|
||||
up->port.flags = old_serial_port[i].flags;
|
||||
up->port.membase = old_serial_port[i].iomem_base;
|
||||
up->port.iotype = old_serial_port[i].io_type;
|
||||
up->port.regshift = old_serial_port[i].iomem_reg_shift;
|
||||
up->port.uartclk = BAUD_RATE * 16;
|
||||
up->port.flags = STD_COM_FLAGS;
|
||||
up->port.membase = 0;
|
||||
up->port.iotype = 0;
|
||||
up->port.regshift = 0;
|
||||
up->port.ops = &m32r_sio_pops;
|
||||
}
|
||||
}
|
||||
@ -978,9 +914,6 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
|
||||
init_timer(&up->timer);
|
||||
up->timer.function = m32r_sio_timeout;
|
||||
|
||||
up->mcr_mask = ~0;
|
||||
up->mcr_force = 0;
|
||||
|
||||
uart_add_one_port(drv, &up->port);
|
||||
}
|
||||
}
|
||||
@ -1112,28 +1045,6 @@ static struct uart_driver m32r_sio_reg = {
|
||||
.cons = M32R_SIO_CONSOLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* m32r_sio_suspend_port - suspend one serial port
|
||||
* @line: serial line number
|
||||
*
|
||||
* Suspend one serial port.
|
||||
*/
|
||||
void m32r_sio_suspend_port(int line)
|
||||
{
|
||||
uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
|
||||
}
|
||||
|
||||
/**
|
||||
* m32r_sio_resume_port - resume one serial port
|
||||
* @line: serial line number
|
||||
*
|
||||
* Resume one serial port.
|
||||
*/
|
||||
void m32r_sio_resume_port(int line)
|
||||
{
|
||||
uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
|
||||
}
|
||||
|
||||
static int __init m32r_sio_init(void)
|
||||
{
|
||||
int ret, i;
|
||||
@ -1163,8 +1074,5 @@ static void __exit m32r_sio_exit(void)
|
||||
module_init(m32r_sio_init);
|
||||
module_exit(m32r_sio_exit);
|
||||
|
||||
EXPORT_SYMBOL(m32r_sio_suspend_port);
|
||||
EXPORT_SYMBOL(m32r_sio_resume_port);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Generic M32R SIO serial driver");
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* m32r_sio.h
|
||||
*
|
||||
* Driver for M32R serial ports
|
||||
*
|
||||
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
|
||||
* Based on drivers/serial/8250.h.
|
||||
*
|
||||
* Copyright (C) 2001 Russell King.
|
||||
* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct m32r_sio_probe {
|
||||
struct module *owner;
|
||||
int (*pci_init_one)(struct pci_dev *dev);
|
||||
void (*pci_remove_one)(struct pci_dev *dev);
|
||||
void (*pnp_init)(void);
|
||||
};
|
||||
|
||||
int m32r_sio_register_probe(struct m32r_sio_probe *probe);
|
||||
void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
|
||||
void m32r_sio_get_irq_map(unsigned int *map);
|
||||
void m32r_sio_suspend_port(int line);
|
||||
void m32r_sio_resume_port(int line);
|
||||
|
||||
struct old_serial_port {
|
||||
unsigned int uart;
|
||||
unsigned int baud_base;
|
||||
unsigned int port;
|
||||
unsigned int irq;
|
||||
unsigned int flags;
|
||||
unsigned char io_type;
|
||||
unsigned char __iomem *iomem_base;
|
||||
unsigned short iomem_reg_shift;
|
||||
};
|
||||
|
||||
#define _INLINE_ inline
|
||||
|
||||
#define PROBE_RSA (1 << 0)
|
||||
#define PROBE_ANY (~0)
|
||||
|
||||
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
|
@ -78,6 +78,7 @@
|
||||
/* AML_UART_REG5 bits */
|
||||
#define AML_UART_BAUD_MASK 0x7fffff
|
||||
#define AML_UART_BAUD_USE BIT(23)
|
||||
#define AML_UART_BAUD_XTAL BIT(24)
|
||||
|
||||
#define AML_UART_PORT_NUM 6
|
||||
#define AML_UART_DEV_NAME "ttyAML"
|
||||
@ -299,7 +300,12 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
|
||||
|
||||
val = readl(port->membase + AML_UART_REG5);
|
||||
val &= ~AML_UART_BAUD_MASK;
|
||||
val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
|
||||
if (port->uartclk == 24000000) {
|
||||
val = ((port->uartclk / 3) / baud) - 1;
|
||||
val |= AML_UART_BAUD_XTAL;
|
||||
} else {
|
||||
val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
|
||||
}
|
||||
val |= AML_UART_BAUD_USE;
|
||||
writel(val, port->membase + AML_UART_REG5);
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
|
||||
return mpc5xxx_uart_process_int(port);
|
||||
}
|
||||
|
||||
static struct psc_ops mpc52xx_psc_ops = {
|
||||
static const struct psc_ops mpc52xx_psc_ops = {
|
||||
.fifo_init = mpc52xx_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
|
||||
@ -376,7 +376,7 @@ static struct psc_ops mpc52xx_psc_ops = {
|
||||
.get_mr1 = mpc52xx_psc_get_mr1,
|
||||
};
|
||||
|
||||
static struct psc_ops mpc5200b_psc_ops = {
|
||||
static const struct psc_ops mpc5200b_psc_ops = {
|
||||
.fifo_init = mpc52xx_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
|
||||
@ -969,7 +969,7 @@ static u8 mpc5125_psc_get_mr1(struct uart_port *port)
|
||||
return in_8(&PSC_5125(port)->mr1);
|
||||
}
|
||||
|
||||
static struct psc_ops mpc5125_psc_ops = {
|
||||
static const struct psc_ops mpc5125_psc_ops = {
|
||||
.fifo_init = mpc5125_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
|
||||
@ -1004,7 +1004,7 @@ static struct psc_ops mpc5125_psc_ops = {
|
||||
.get_mr1 = mpc5125_psc_get_mr1,
|
||||
};
|
||||
|
||||
static struct psc_ops mpc512x_psc_ops = {
|
||||
static const struct psc_ops mpc512x_psc_ops = {
|
||||
.fifo_init = mpc512x_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
|
||||
|
@ -137,8 +137,6 @@ struct mpsc_port_info {
|
||||
/* Internal driver state for this ctlr */
|
||||
u8 ready;
|
||||
u8 rcv_data;
|
||||
tcflag_t c_iflag; /* save termios->c_iflag */
|
||||
tcflag_t c_cflag; /* save termios->c_cflag */
|
||||
|
||||
/* Info passed in from platform */
|
||||
u8 mirror_regs; /* Need to mirror regs? */
|
||||
@ -1407,9 +1405,6 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
ulong flags;
|
||||
u32 chr_bits, stop_bits, par;
|
||||
|
||||
pi->c_iflag = termios->c_iflag;
|
||||
pi->c_cflag = termios->c_cflag;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
chr_bits = MPSC_MPCR_CL_5;
|
||||
@ -1870,12 +1865,12 @@ static int mpsc_shared_map_regs(struct platform_device *pd)
|
||||
|
||||
static void mpsc_shared_unmap_regs(void)
|
||||
{
|
||||
if (!mpsc_shared_regs.mpsc_routing_base) {
|
||||
if (mpsc_shared_regs.mpsc_routing_base) {
|
||||
iounmap(mpsc_shared_regs.mpsc_routing_base);
|
||||
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
|
||||
MPSC_ROUTING_REG_BLOCK_SIZE);
|
||||
}
|
||||
if (!mpsc_shared_regs.sdma_intr_base) {
|
||||
if (mpsc_shared_regs.sdma_intr_base) {
|
||||
iounmap(mpsc_shared_regs.sdma_intr_base);
|
||||
release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
|
||||
MPSC_SDMA_INTR_REG_BLOCK_SIZE);
|
||||
@ -1891,44 +1886,39 @@ static void mpsc_shared_unmap_regs(void)
|
||||
static int mpsc_shared_drv_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mpsc_shared_pdata *pdata;
|
||||
int rc = -ENODEV;
|
||||
int rc;
|
||||
|
||||
if (dev->id == 0) {
|
||||
rc = mpsc_shared_map_regs(dev);
|
||||
if (!rc) {
|
||||
pdata = (struct mpsc_shared_pdata *)
|
||||
dev_get_platdata(&dev->dev);
|
||||
if (dev->id != 0)
|
||||
return -ENODEV;
|
||||
|
||||
mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
|
||||
mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
|
||||
mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
|
||||
mpsc_shared_regs.SDMA_INTR_CAUSE_m =
|
||||
pdata->intr_cause_val;
|
||||
mpsc_shared_regs.SDMA_INTR_MASK_m =
|
||||
pdata->intr_mask_val;
|
||||
rc = mpsc_shared_map_regs(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
pdata = dev_get_platdata(&dev->dev);
|
||||
|
||||
return rc;
|
||||
mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
|
||||
mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
|
||||
mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
|
||||
mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
|
||||
mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpsc_shared_drv_remove(struct platform_device *dev)
|
||||
{
|
||||
int rc = -ENODEV;
|
||||
if (dev->id != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (dev->id == 0) {
|
||||
mpsc_shared_unmap_regs();
|
||||
mpsc_shared_regs.MPSC_MRR_m = 0;
|
||||
mpsc_shared_regs.MPSC_RCRR_m = 0;
|
||||
mpsc_shared_regs.MPSC_TCRR_m = 0;
|
||||
mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
|
||||
mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
|
||||
rc = 0;
|
||||
}
|
||||
mpsc_shared_unmap_regs();
|
||||
mpsc_shared_regs.MPSC_MRR_m = 0;
|
||||
mpsc_shared_regs.MPSC_RCRR_m = 0;
|
||||
mpsc_shared_regs.MPSC_TCRR_m = 0;
|
||||
mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
|
||||
mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mpsc_shared_driver = {
|
||||
@ -1979,10 +1969,6 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
|
||||
pi->sdma_base_p = r->start;
|
||||
} else {
|
||||
mpsc_resource_err("SDMA base");
|
||||
if (pi->mpsc_base) {
|
||||
iounmap(pi->mpsc_base);
|
||||
pi->mpsc_base = NULL;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1993,33 +1979,33 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
|
||||
pi->brg_base_p = r->start;
|
||||
} else {
|
||||
mpsc_resource_err("BRG base");
|
||||
if (pi->mpsc_base) {
|
||||
iounmap(pi->mpsc_base);
|
||||
pi->mpsc_base = NULL;
|
||||
}
|
||||
if (pi->sdma_base) {
|
||||
iounmap(pi->sdma_base);
|
||||
pi->sdma_base = NULL;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (pi->sdma_base) {
|
||||
iounmap(pi->sdma_base);
|
||||
pi->sdma_base = NULL;
|
||||
}
|
||||
if (pi->mpsc_base) {
|
||||
iounmap(pi->mpsc_base);
|
||||
pi->mpsc_base = NULL;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
|
||||
{
|
||||
if (!pi->mpsc_base) {
|
||||
if (pi->mpsc_base) {
|
||||
iounmap(pi->mpsc_base);
|
||||
release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
|
||||
}
|
||||
if (!pi->sdma_base) {
|
||||
if (pi->sdma_base) {
|
||||
iounmap(pi->sdma_base);
|
||||
release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
|
||||
}
|
||||
if (!pi->brg_base) {
|
||||
if (pi->brg_base) {
|
||||
iounmap(pi->brg_base);
|
||||
release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
|
||||
}
|
||||
@ -2073,36 +2059,37 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
|
||||
|
||||
static int mpsc_drv_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mpsc_port_info *pi;
|
||||
int rc = -ENODEV;
|
||||
struct mpsc_port_info *pi;
|
||||
int rc;
|
||||
|
||||
pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
|
||||
dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
|
||||
|
||||
if (dev->id < MPSC_NUM_CTLRS) {
|
||||
pi = &mpsc_ports[dev->id];
|
||||
if (dev->id >= MPSC_NUM_CTLRS)
|
||||
return -ENODEV;
|
||||
|
||||
rc = mpsc_drv_map_regs(pi, dev);
|
||||
if (!rc) {
|
||||
mpsc_drv_get_platform_data(pi, dev, dev->id);
|
||||
pi->port.dev = &dev->dev;
|
||||
pi = &mpsc_ports[dev->id];
|
||||
|
||||
rc = mpsc_make_ready(pi);
|
||||
if (!rc) {
|
||||
spin_lock_init(&pi->tx_lock);
|
||||
rc = uart_add_one_port(&mpsc_reg, &pi->port);
|
||||
if (!rc) {
|
||||
rc = 0;
|
||||
} else {
|
||||
mpsc_release_port((struct uart_port *)
|
||||
pi);
|
||||
mpsc_drv_unmap_regs(pi);
|
||||
}
|
||||
} else {
|
||||
mpsc_drv_unmap_regs(pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = mpsc_drv_map_regs(pi, dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
mpsc_drv_get_platform_data(pi, dev, dev->id);
|
||||
pi->port.dev = &dev->dev;
|
||||
|
||||
rc = mpsc_make_ready(pi);
|
||||
if (rc)
|
||||
goto err_unmap;
|
||||
|
||||
spin_lock_init(&pi->tx_lock);
|
||||
rc = uart_add_one_port(&mpsc_reg, &pi->port);
|
||||
if (rc)
|
||||
goto err_relport;
|
||||
|
||||
return 0;
|
||||
err_relport:
|
||||
mpsc_release_port(&pi->port);
|
||||
err_unmap:
|
||||
mpsc_drv_unmap_regs(pi);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2124,19 +2111,22 @@ static int __init mpsc_drv_init(void)
|
||||
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
|
||||
|
||||
rc = uart_register_driver(&mpsc_reg);
|
||||
if (!rc) {
|
||||
rc = platform_driver_register(&mpsc_shared_driver);
|
||||
if (!rc) {
|
||||
rc = platform_driver_register(&mpsc_driver);
|
||||
if (rc) {
|
||||
platform_driver_unregister(&mpsc_shared_driver);
|
||||
uart_unregister_driver(&mpsc_reg);
|
||||
}
|
||||
} else {
|
||||
uart_unregister_driver(&mpsc_reg);
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = platform_driver_register(&mpsc_shared_driver);
|
||||
if (rc)
|
||||
goto err_unreg_uart;
|
||||
|
||||
rc = platform_driver_register(&mpsc_driver);
|
||||
if (rc)
|
||||
goto err_unreg_plat;
|
||||
|
||||
return 0;
|
||||
err_unreg_plat:
|
||||
platform_driver_unregister(&mpsc_shared_driver);
|
||||
err_unreg_uart:
|
||||
uart_unregister_driver(&mpsc_reg);
|
||||
return rc;
|
||||
}
|
||||
device_initcall(mpsc_drv_init);
|
||||
|
@ -1478,7 +1478,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
|
||||
device->con->write = msm_serial_early_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
|
||||
msm_serial_early_console_setup);
|
||||
|
||||
@ -1500,7 +1499,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
|
||||
device->con->write = msm_serial_early_write_dm;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
|
||||
OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
|
||||
msm_serial_early_console_setup_dm);
|
||||
|
||||
|
650
drivers/tty/serial/mvebu-uart.c
Normal file
650
drivers/tty/serial/mvebu-uart.c
Normal file
@ -0,0 +1,650 @@
|
||||
/*
|
||||
* ***************************************************************************
|
||||
* Copyright (C) 2015 Marvell International Ltd.
|
||||
* ***************************************************************************
|
||||
* 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 any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ***************************************************************************
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
/* Register Map */
|
||||
#define UART_RBR 0x00
|
||||
#define RBR_BRK_DET BIT(15)
|
||||
#define RBR_FRM_ERR_DET BIT(14)
|
||||
#define RBR_PAR_ERR_DET BIT(13)
|
||||
#define RBR_OVR_ERR_DET BIT(12)
|
||||
|
||||
#define UART_TSH 0x04
|
||||
|
||||
#define UART_CTRL 0x08
|
||||
#define CTRL_SOFT_RST BIT(31)
|
||||
#define CTRL_TXFIFO_RST BIT(15)
|
||||
#define CTRL_RXFIFO_RST BIT(14)
|
||||
#define CTRL_ST_MIRR_EN BIT(13)
|
||||
#define CTRL_LPBK_EN BIT(12)
|
||||
#define CTRL_SND_BRK_SEQ BIT(11)
|
||||
#define CTRL_PAR_EN BIT(10)
|
||||
#define CTRL_TWO_STOP BIT(9)
|
||||
#define CTRL_TX_HFL_INT BIT(8)
|
||||
#define CTRL_RX_HFL_INT BIT(7)
|
||||
#define CTRL_TX_EMP_INT BIT(6)
|
||||
#define CTRL_TX_RDY_INT BIT(5)
|
||||
#define CTRL_RX_RDY_INT BIT(4)
|
||||
#define CTRL_BRK_DET_INT BIT(3)
|
||||
#define CTRL_FRM_ERR_INT BIT(2)
|
||||
#define CTRL_PAR_ERR_INT BIT(1)
|
||||
#define CTRL_OVR_ERR_INT BIT(0)
|
||||
#define CTRL_RX_INT (CTRL_RX_RDY_INT | CTRL_BRK_DET_INT |\
|
||||
CTRL_FRM_ERR_INT | CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
|
||||
|
||||
#define UART_STAT 0x0c
|
||||
#define STAT_TX_FIFO_EMP BIT(13)
|
||||
#define STAT_RX_FIFO_EMP BIT(12)
|
||||
#define STAT_TX_FIFO_FUL BIT(11)
|
||||
#define STAT_TX_FIFO_HFL BIT(10)
|
||||
#define STAT_RX_TOGL BIT(9)
|
||||
#define STAT_RX_FIFO_FUL BIT(8)
|
||||
#define STAT_RX_FIFO_HFL BIT(7)
|
||||
#define STAT_TX_EMP BIT(6)
|
||||
#define STAT_TX_RDY BIT(5)
|
||||
#define STAT_RX_RDY BIT(4)
|
||||
#define STAT_BRK_DET BIT(3)
|
||||
#define STAT_FRM_ERR BIT(2)
|
||||
#define STAT_PAR_ERR BIT(1)
|
||||
#define STAT_OVR_ERR BIT(0)
|
||||
#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\
|
||||
| STAT_PAR_ERR | STAT_OVR_ERR)
|
||||
|
||||
#define UART_BRDV 0x10
|
||||
|
||||
#define MVEBU_NR_UARTS 1
|
||||
|
||||
#define MVEBU_UART_TYPE "mvebu-uart"
|
||||
|
||||
static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
|
||||
|
||||
struct mvebu_uart_data {
|
||||
struct uart_port *port;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* Core UART Driver Operations */
|
||||
static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int st;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
st = readl(port->membase + UART_STAT);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static unsigned int mvebu_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void mvebu_uart_set_mctrl(struct uart_port *port,
|
||||
unsigned int mctrl)
|
||||
{
|
||||
/*
|
||||
* Even if we do not support configuring the modem control lines, this
|
||||
* function must be proided to the serial core
|
||||
*/
|
||||
}
|
||||
|
||||
static void mvebu_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ctl = readl(port->membase + UART_CTRL);
|
||||
|
||||
ctl &= ~CTRL_TX_RDY_INT;
|
||||
writel(ctl, port->membase + UART_CTRL);
|
||||
}
|
||||
|
||||
static void mvebu_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ctl = readl(port->membase + UART_CTRL);
|
||||
|
||||
ctl |= CTRL_TX_RDY_INT;
|
||||
writel(ctl, port->membase + UART_CTRL);
|
||||
}
|
||||
|
||||
static void mvebu_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ctl = readl(port->membase + UART_CTRL);
|
||||
|
||||
ctl &= ~CTRL_RX_INT;
|
||||
writel(ctl, port->membase + UART_CTRL);
|
||||
}
|
||||
|
||||
static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
|
||||
{
|
||||
unsigned int ctl;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ctl = readl(port->membase + UART_CTRL);
|
||||
if (brk == -1)
|
||||
ctl |= CTRL_SND_BRK_SEQ;
|
||||
else
|
||||
ctl &= ~CTRL_SND_BRK_SEQ;
|
||||
writel(ctl, port->membase + UART_CTRL);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch = 0;
|
||||
char flag = 0;
|
||||
|
||||
do {
|
||||
if (status & STAT_RX_RDY) {
|
||||
ch = readl(port->membase + UART_RBR);
|
||||
ch &= 0xff;
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
if (status & STAT_PAR_ERR)
|
||||
port->icount.parity++;
|
||||
}
|
||||
|
||||
if (status & STAT_BRK_DET) {
|
||||
port->icount.brk++;
|
||||
status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
}
|
||||
|
||||
if (status & STAT_OVR_ERR)
|
||||
port->icount.overrun++;
|
||||
|
||||
if (status & STAT_FRM_ERR)
|
||||
port->icount.frame++;
|
||||
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
|
||||
if (status & port->ignore_status_mask & STAT_PAR_ERR)
|
||||
status &= ~STAT_RX_RDY;
|
||||
|
||||
status &= port->read_status_mask;
|
||||
|
||||
if (status & STAT_PAR_ERR)
|
||||
flag = TTY_PARITY;
|
||||
|
||||
status &= ~port->ignore_status_mask;
|
||||
|
||||
if (status & STAT_RX_RDY)
|
||||
tty_insert_flip_char(tport, ch, flag);
|
||||
|
||||
if (status & STAT_BRK_DET)
|
||||
tty_insert_flip_char(tport, 0, TTY_BREAK);
|
||||
|
||||
if (status & STAT_FRM_ERR)
|
||||
tty_insert_flip_char(tport, 0, TTY_FRAME);
|
||||
|
||||
if (status & STAT_OVR_ERR)
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
|
||||
ignore_char:
|
||||
status = readl(port->membase + UART_STAT);
|
||||
} while (status & (STAT_RX_RDY | STAT_BRK_DET));
|
||||
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int count;
|
||||
unsigned int st;
|
||||
|
||||
if (port->x_char) {
|
||||
writel(port->x_char, port->membase + UART_TSH);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
mvebu_uart_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
for (count = 0; count < port->fifosize; count++) {
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART_TSH);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
st = readl(port->membase + UART_STAT);
|
||||
if (st & STAT_TX_FIFO_FUL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mvebu_uart_stop_tx(port);
|
||||
}
|
||||
|
||||
static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)dev_id;
|
||||
unsigned int st = readl(port->membase + UART_STAT);
|
||||
|
||||
if (st & (STAT_RX_RDY | STAT_OVR_ERR | STAT_FRM_ERR | STAT_BRK_DET))
|
||||
mvebu_uart_rx_chars(port, st);
|
||||
|
||||
if (st & STAT_TX_RDY)
|
||||
mvebu_uart_tx_chars(port, st);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mvebu_uart_startup(struct uart_port *port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST,
|
||||
port->membase + UART_CTRL);
|
||||
udelay(1);
|
||||
writel(CTRL_RX_INT, port->membase + UART_CTRL);
|
||||
|
||||
ret = request_irq(port->irq, mvebu_uart_isr, port->irqflags, "serial",
|
||||
port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "failed to request irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mvebu_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
writel(0, port->membase + UART_CTRL);
|
||||
}
|
||||
|
||||
static void mvebu_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int baud;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
port->read_status_mask = STAT_RX_RDY | STAT_OVR_ERR |
|
||||
STAT_TX_RDY | STAT_TX_FIFO_FUL;
|
||||
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |=
|
||||
STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR;
|
||||
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR;
|
||||
|
||||
if (old)
|
||||
tty_termios_copy_hw(termios, old);
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, 460800);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *mvebu_uart_type(struct uart_port *port)
|
||||
{
|
||||
return MVEBU_UART_TYPE;
|
||||
}
|
||||
|
||||
static void mvebu_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
static int mvebu_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int mvebu_uart_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
unsigned int st = readl(port->membase + UART_STAT);
|
||||
|
||||
if (!(st & STAT_RX_RDY))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return readl(port->membase + UART_RBR);
|
||||
}
|
||||
|
||||
static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int st;
|
||||
|
||||
for (;;) {
|
||||
st = readl(port->membase + UART_STAT);
|
||||
|
||||
if (!(st & STAT_TX_FIFO_FUL))
|
||||
break;
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
writel(c, port->membase + UART_TSH);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct uart_ops mvebu_uart_ops = {
|
||||
.tx_empty = mvebu_uart_tx_empty,
|
||||
.set_mctrl = mvebu_uart_set_mctrl,
|
||||
.get_mctrl = mvebu_uart_get_mctrl,
|
||||
.stop_tx = mvebu_uart_stop_tx,
|
||||
.start_tx = mvebu_uart_start_tx,
|
||||
.stop_rx = mvebu_uart_stop_rx,
|
||||
.break_ctl = mvebu_uart_break_ctl,
|
||||
.startup = mvebu_uart_startup,
|
||||
.shutdown = mvebu_uart_shutdown,
|
||||
.set_termios = mvebu_uart_set_termios,
|
||||
.type = mvebu_uart_type,
|
||||
.release_port = mvebu_uart_release_port,
|
||||
.request_port = mvebu_uart_request_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = mvebu_uart_get_poll_char,
|
||||
.poll_put_char = mvebu_uart_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Console Driver Operations */
|
||||
|
||||
#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
|
||||
/* Early Console */
|
||||
static void mvebu_uart_putc(struct uart_port *port, int c)
|
||||
{
|
||||
unsigned int st;
|
||||
|
||||
for (;;) {
|
||||
st = readl(port->membase + UART_STAT);
|
||||
if (!(st & STAT_TX_FIFO_FUL))
|
||||
break;
|
||||
}
|
||||
|
||||
writel(c, port->membase + UART_TSH);
|
||||
|
||||
for (;;) {
|
||||
st = readl(port->membase + UART_STAT);
|
||||
if (st & STAT_TX_FIFO_EMP)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mvebu_uart_putc_early_write(struct console *con,
|
||||
const char *s,
|
||||
unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, mvebu_uart_putc);
|
||||
}
|
||||
|
||||
static int __init
|
||||
mvebu_uart_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = mvebu_uart_putc_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart",
|
||||
mvebu_uart_early_console_setup);
|
||||
|
||||
static void wait_for_xmitr(struct uart_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
readl_poll_timeout_atomic(port->membase + UART_STAT, val,
|
||||
(val & STAT_TX_EMP), 1, 10000);
|
||||
}
|
||||
|
||||
static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
writel(ch, port->membase + UART_TSH);
|
||||
}
|
||||
|
||||
static void mvebu_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &mvebu_uart_ports[co->index];
|
||||
unsigned long flags;
|
||||
unsigned int ier;
|
||||
int locked = 1;
|
||||
|
||||
if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
ier = readl(port->membase + UART_CTRL) &
|
||||
(CTRL_RX_INT | CTRL_TX_RDY_INT);
|
||||
writel(0, port->membase + UART_CTRL);
|
||||
|
||||
uart_console_write(port, s, count, mvebu_uart_console_putchar);
|
||||
|
||||
wait_for_xmitr(port);
|
||||
|
||||
if (ier)
|
||||
writel(ier, port->membase + UART_CTRL);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int baud = 9600;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
if (co->index < 0 || co->index >= MVEBU_NR_UARTS)
|
||||
return -EINVAL;
|
||||
|
||||
port = &mvebu_uart_ports[co->index];
|
||||
|
||||
if (!port->mapbase || !port->membase) {
|
||||
pr_debug("console on ttyMV%i not present\n", co->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver mvebu_uart_driver;
|
||||
|
||||
static struct console mvebu_uart_console = {
|
||||
.name = "ttyMV",
|
||||
.write = mvebu_uart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = mvebu_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &mvebu_uart_driver,
|
||||
};
|
||||
|
||||
static int __init mvebu_uart_console_init(void)
|
||||
{
|
||||
register_console(&mvebu_uart_console);
|
||||
return 0;
|
||||
}
|
||||
|
||||
console_initcall(mvebu_uart_console_init);
|
||||
|
||||
|
||||
#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */
|
||||
|
||||
static struct uart_driver mvebu_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "mvebu_serial",
|
||||
.dev_name = "ttyMV",
|
||||
.nr = MVEBU_NR_UARTS,
|
||||
#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
|
||||
.cons = &mvebu_uart_console,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mvebu_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct uart_port *port;
|
||||
struct mvebu_uart_data *data;
|
||||
int ret;
|
||||
|
||||
if (!reg || !irq) {
|
||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port = &mvebu_uart_ports[0];
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
port->dev = &pdev->dev;
|
||||
port->type = PORT_MVEBU;
|
||||
port->ops = &mvebu_uart_ops;
|
||||
port->regshift = 0;
|
||||
|
||||
port->fifosize = 32;
|
||||
port->iotype = UPIO_MEM32;
|
||||
port->flags = UPF_FIXED_PORT;
|
||||
port->line = 0; /* single port: force line number to 0 */
|
||||
|
||||
port->irq = irq->start;
|
||||
port->irqflags = 0;
|
||||
port->mapbase = reg->start;
|
||||
|
||||
port->membase = devm_ioremap_resource(&pdev->dev, reg);
|
||||
if (IS_ERR(port->membase))
|
||||
return -PTR_ERR(port->membase);
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->port = port;
|
||||
|
||||
port->private_data = data;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
ret = uart_add_one_port(&mvebu_uart_driver, port);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mvebu_uart_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&mvebu_uart_driver, data->port);
|
||||
data->port->private_data = NULL;
|
||||
data->port->mapbase = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id mvebu_uart_of_match[] = {
|
||||
{ .compatible = "marvell,armada-3700-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
|
||||
|
||||
static struct platform_driver mvebu_uart_platform_driver = {
|
||||
.probe = mvebu_uart_probe,
|
||||
.remove = mvebu_uart_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mvebu-uart",
|
||||
.of_match_table = of_match_ptr(mvebu_uart_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mvebu_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&mvebu_uart_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&mvebu_uart_platform_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&mvebu_uart_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit mvebu_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mvebu_uart_platform_driver);
|
||||
uart_unregister_driver(&mvebu_uart_driver);
|
||||
}
|
||||
|
||||
arch_initcall(mvebu_uart_init);
|
||||
module_exit(mvebu_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>");
|
||||
MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -1870,7 +1870,7 @@ static struct platform_driver serial_omap_driver = {
|
||||
.probe = serial_omap_probe,
|
||||
.remove = serial_omap_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = OMAP_SERIAL_DRIVER_NAME,
|
||||
.pm = &serial_omap_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(omap_serial_of_match),
|
||||
},
|
||||
|
@ -601,14 +601,21 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
||||
unsigned int fifocnt = 0;
|
||||
int max_count = port->fifosize;
|
||||
|
||||
while (max_count-- > 0) {
|
||||
ufcon = rd_regl(port, S3C2410_UFCON);
|
||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
|
||||
if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
|
||||
break;
|
||||
/*
|
||||
* Receive all characters known to be in FIFO
|
||||
* before reading FIFO level again
|
||||
*/
|
||||
if (fifocnt == 0) {
|
||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
|
||||
if (fifocnt == 0)
|
||||
break;
|
||||
}
|
||||
fifocnt--;
|
||||
|
||||
uerstat = rd_regl(port, S3C2410_UERSTAT);
|
||||
ch = rd_regb(port, S3C2410_URXH);
|
||||
@ -623,6 +630,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
|
||||
}
|
||||
} else {
|
||||
if (txe) {
|
||||
ufcon = rd_regl(port, S3C2410_UFCON);
|
||||
ufcon |= S3C2410_UFCON_RESETRX;
|
||||
wr_regl(port, S3C2410_UFCON, ufcon);
|
||||
rx_enabled(port) = 1;
|
||||
@ -2451,7 +2459,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
|
||||
}
|
||||
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
|
||||
s3c2410_early_console_setup);
|
||||
EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
|
||||
|
||||
/* S3C2412, S3C2440, S3C64xx */
|
||||
static struct samsung_early_console_data s3c2440_early_console_data = {
|
||||
@ -2470,9 +2477,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
|
||||
s3c2440_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
|
||||
s3c2440_early_console_setup);
|
||||
EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
|
||||
EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
|
||||
EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
|
||||
|
||||
/* S5PV210, EXYNOS */
|
||||
static struct samsung_early_console_data s5pv210_early_console_data = {
|
||||
@ -2489,8 +2493,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
|
||||
s5pv210_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
|
||||
s5pv210_early_console_setup);
|
||||
EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
|
||||
EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
|
||||
#endif
|
||||
|
||||
MODULE_ALIAS("platform:samsung-uart");
|
||||
|
@ -196,14 +196,14 @@
|
||||
* or (IO6)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */
|
||||
#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4)
|
||||
#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
|
||||
#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7)
|
||||
#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6)
|
||||
#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
|
||||
@ -240,7 +240,7 @@
|
||||
|
||||
/* IOControl register bits (Only 750/760) */
|
||||
#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
|
||||
#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */
|
||||
#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */
|
||||
#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
|
||||
|
||||
/* EFCR register bits */
|
||||
@ -687,7 +687,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
case SC16IS7XX_IIR_CTSRTS_SRC:
|
||||
msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
|
||||
uart_handle_cts_change(port,
|
||||
!!(msr & SC16IS7XX_MSR_CTS_BIT));
|
||||
!!(msr & SC16IS7XX_MSR_DCTS_BIT));
|
||||
break;
|
||||
case SC16IS7XX_IIR_THRI_SRC:
|
||||
sc16is7xx_handle_tx(port);
|
||||
@ -761,12 +761,20 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
|
||||
memset(&one->config, 0, sizeof(one->config));
|
||||
spin_unlock_irqrestore(&one->port.lock, irqflags);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_MD)
|
||||
if (config.flags & SC16IS7XX_RECONF_MD) {
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_LOOP_BIT,
|
||||
(one->port.mctrl & TIOCM_LOOP) ?
|
||||
SC16IS7XX_MCR_LOOP_BIT : 0);
|
||||
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_RTS_BIT,
|
||||
(one->port.mctrl & TIOCM_RTS) ?
|
||||
SC16IS7XX_MCR_RTS_BIT : 0);
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_DTR_BIT,
|
||||
(one->port.mctrl & TIOCM_DTR) ?
|
||||
SC16IS7XX_MCR_DTR_BIT : 0);
|
||||
}
|
||||
if (config.flags & SC16IS7XX_RECONF_IER)
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
|
||||
config.ier_clear, 0);
|
||||
|
@ -171,14 +171,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
*/
|
||||
uart_change_speed(tty, state, NULL);
|
||||
|
||||
if (init_hw) {
|
||||
/*
|
||||
* Setup the RTS and DTR signals once the
|
||||
* port is open and ready to respond.
|
||||
*/
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
|
||||
}
|
||||
/*
|
||||
* Setup the RTS and DTR signals once the
|
||||
* port is open and ready to respond.
|
||||
*/
|
||||
if (init_hw && C_BAUD(tty))
|
||||
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -240,7 +238,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
if (uart_console(uport) && tty)
|
||||
uport->cons->cflag = tty->termios.c_cflag;
|
||||
|
||||
if (!tty || (tty->termios.c_cflag & HUPCL))
|
||||
if (!tty || C_HUPCL(tty))
|
||||
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
|
||||
|
||||
uart_port_shutdown(port);
|
||||
@ -485,12 +483,15 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
|
||||
spin_unlock_irq(&uport->lock);
|
||||
}
|
||||
|
||||
static inline int __uart_put_char(struct uart_port *port,
|
||||
struct circ_buf *circ, unsigned char c)
|
||||
static int uart_put_char(struct tty_struct *tty, unsigned char c)
|
||||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port = state->uart_port;
|
||||
struct circ_buf *circ;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
circ = &state->xmit;
|
||||
if (!circ->buf)
|
||||
return 0;
|
||||
|
||||
@ -504,13 +505,6 @@ static inline int __uart_put_char(struct uart_port *port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uart_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
|
||||
return __uart_put_char(state->uart_port, &state->xmit, ch);
|
||||
}
|
||||
|
||||
static void uart_flush_chars(struct tty_struct *tty)
|
||||
{
|
||||
uart_start(tty);
|
||||
@ -639,7 +633,7 @@ static void uart_throttle(struct tty_struct *tty)
|
||||
|
||||
if (I_IXOFF(tty))
|
||||
mask |= UPSTAT_AUTOXOFF;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
mask |= UPSTAT_AUTORTS;
|
||||
|
||||
if (port->status & mask) {
|
||||
@ -647,11 +641,11 @@ static void uart_throttle(struct tty_struct *tty)
|
||||
mask &= ~port->status;
|
||||
}
|
||||
|
||||
if (mask & UPSTAT_AUTOXOFF)
|
||||
uart_send_xchar(tty, STOP_CHAR(tty));
|
||||
|
||||
if (mask & UPSTAT_AUTORTS)
|
||||
uart_clear_mctrl(port, TIOCM_RTS);
|
||||
|
||||
if (mask & UPSTAT_AUTOXOFF)
|
||||
uart_send_xchar(tty, STOP_CHAR(tty));
|
||||
}
|
||||
|
||||
static void uart_unthrottle(struct tty_struct *tty)
|
||||
@ -662,7 +656,7 @@ static void uart_unthrottle(struct tty_struct *tty)
|
||||
|
||||
if (I_IXOFF(tty))
|
||||
mask |= UPSTAT_AUTOXOFF;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
if (C_CRTSCTS(tty))
|
||||
mask |= UPSTAT_AUTORTS;
|
||||
|
||||
if (port->status & mask) {
|
||||
@ -670,21 +664,25 @@ static void uart_unthrottle(struct tty_struct *tty)
|
||||
mask &= ~port->status;
|
||||
}
|
||||
|
||||
if (mask & UPSTAT_AUTOXOFF)
|
||||
uart_send_xchar(tty, START_CHAR(tty));
|
||||
|
||||
if (mask & UPSTAT_AUTORTS)
|
||||
uart_set_mctrl(port, TIOCM_RTS);
|
||||
|
||||
if (mask & UPSTAT_AUTOXOFF)
|
||||
uart_send_xchar(tty, START_CHAR(tty));
|
||||
}
|
||||
|
||||
static void do_uart_get_info(struct tty_port *port,
|
||||
struct serial_struct *retinfo)
|
||||
static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport = state->uart_port;
|
||||
|
||||
memset(retinfo, 0, sizeof(*retinfo));
|
||||
|
||||
/*
|
||||
* Ensure the state we copy is consistent and no hardware changes
|
||||
* occur as we go
|
||||
*/
|
||||
mutex_lock(&port->mutex);
|
||||
retinfo->type = uport->type;
|
||||
retinfo->line = uport->line;
|
||||
retinfo->port = uport->iobase;
|
||||
@ -703,15 +701,6 @@ static void do_uart_get_info(struct tty_port *port,
|
||||
retinfo->io_type = uport->iotype;
|
||||
retinfo->iomem_reg_shift = uport->regshift;
|
||||
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
|
||||
}
|
||||
|
||||
static void uart_get_info(struct tty_port *port,
|
||||
struct serial_struct *retinfo)
|
||||
{
|
||||
/* Ensure the state we copy is consistent and no hardware changes
|
||||
occur as we go */
|
||||
mutex_lock(&port->mutex);
|
||||
do_uart_get_info(port, retinfo);
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
||||
@ -719,6 +708,7 @@ static int uart_get_info_user(struct tty_port *port,
|
||||
struct serial_struct __user *retinfo)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
|
||||
uart_get_info(port, &tmp);
|
||||
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
@ -1391,8 +1381,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
uport = state->uart_port;
|
||||
port = &state->port;
|
||||
|
||||
pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
|
||||
pr_debug("uart_close(%d) called\n", tty->index);
|
||||
|
||||
if (!port->count || tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
@ -1434,7 +1423,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
* Wake up anyone trying to open this port.
|
||||
*/
|
||||
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
|
||||
clear_bit(ASYNCB_CLOSING, &port->flags);
|
||||
spin_unlock_irq(&port->lock);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
|
||||
@ -1510,7 +1498,7 @@ static void uart_hangup(struct tty_struct *tty)
|
||||
struct tty_port *port = &state->port;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("uart_hangup(%d)\n", state->uart_port->line);
|
||||
pr_debug("uart_hangup(%d)\n", tty->index);
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
if (port->flags & ASYNC_NORMAL_ACTIVE) {
|
||||
@ -1591,7 +1579,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
|
||||
*/
|
||||
static int uart_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
|
||||
struct uart_driver *drv = tty->driver->driver_state;
|
||||
int retval, line = tty->index;
|
||||
struct uart_state *state = drv->state + line;
|
||||
struct tty_port *port = &state->port;
|
||||
@ -1633,15 +1621,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
||||
/*
|
||||
* If we succeeded, wait until the port is ready.
|
||||
*/
|
||||
err_unlock:
|
||||
mutex_unlock(&port->mutex);
|
||||
if (retval == 0)
|
||||
retval = tty_port_block_til_ready(port, tty, filp);
|
||||
|
||||
end:
|
||||
return retval;
|
||||
err_unlock:
|
||||
mutex_unlock(&port->mutex);
|
||||
goto end;
|
||||
}
|
||||
|
||||
static const char *uart_type(struct uart_port *port)
|
||||
@ -1700,17 +1685,13 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
seq_printf(m, " tx:%d rx:%d",
|
||||
uport->icount.tx, uport->icount.rx);
|
||||
if (uport->icount.frame)
|
||||
seq_printf(m, " fe:%d",
|
||||
uport->icount.frame);
|
||||
seq_printf(m, " fe:%d", uport->icount.frame);
|
||||
if (uport->icount.parity)
|
||||
seq_printf(m, " pe:%d",
|
||||
uport->icount.parity);
|
||||
seq_printf(m, " pe:%d", uport->icount.parity);
|
||||
if (uport->icount.brk)
|
||||
seq_printf(m, " brk:%d",
|
||||
uport->icount.brk);
|
||||
seq_printf(m, " brk:%d", uport->icount.brk);
|
||||
if (uport->icount.overrun)
|
||||
seq_printf(m, " oe:%d",
|
||||
uport->icount.overrun);
|
||||
seq_printf(m, " oe:%d", uport->icount.overrun);
|
||||
|
||||
#define INFOBIT(bit, str) \
|
||||
if (uport->mctrl & (bit)) \
|
||||
@ -1745,8 +1726,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
|
||||
struct uart_driver *drv = ttydrv->driver_state;
|
||||
int i;
|
||||
|
||||
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
|
||||
"", "", "");
|
||||
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
|
||||
for (i = 0; i < drv->nr; i++)
|
||||
uart_line_info(m, drv, i);
|
||||
return 0;
|
||||
@ -1895,26 +1875,6 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_parse_options);
|
||||
|
||||
struct baud_rates {
|
||||
unsigned int rate;
|
||||
unsigned int cflag;
|
||||
};
|
||||
|
||||
static const struct baud_rates baud_rates[] = {
|
||||
{ 921600, B921600 },
|
||||
{ 460800, B460800 },
|
||||
{ 230400, B230400 },
|
||||
{ 115200, B115200 },
|
||||
{ 57600, B57600 },
|
||||
{ 38400, B38400 },
|
||||
{ 19200, B19200 },
|
||||
{ 9600, B9600 },
|
||||
{ 4800, B4800 },
|
||||
{ 2400, B2400 },
|
||||
{ 1200, B1200 },
|
||||
{ 0, B38400 }
|
||||
};
|
||||
|
||||
/**
|
||||
* uart_set_options - setup the serial console parameters
|
||||
* @port: pointer to the serial ports uart_port structure
|
||||
@ -1930,7 +1890,6 @@ uart_set_options(struct uart_port *port, struct console *co,
|
||||
{
|
||||
struct ktermios termios;
|
||||
static struct ktermios dummy;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Ensure that the serial console lock is initialised
|
||||
@ -1945,16 +1904,8 @@ uart_set_options(struct uart_port *port, struct console *co,
|
||||
|
||||
memset(&termios, 0, sizeof(struct ktermios));
|
||||
|
||||
termios.c_cflag = CREAD | HUPCL | CLOCAL;
|
||||
|
||||
/*
|
||||
* Construct a cflag setting.
|
||||
*/
|
||||
for (i = 0; baud_rates[i].rate; i++)
|
||||
if (baud_rates[i].rate <= baud)
|
||||
break;
|
||||
|
||||
termios.c_cflag |= baud_rates[i].cflag;
|
||||
termios.c_cflag |= CREAD | HUPCL | CLOCAL;
|
||||
tty_termios_encode_baud_rate(&termios, baud, baud);
|
||||
|
||||
if (bits == 7)
|
||||
termios.c_cflag |= CS7;
|
||||
|
@ -554,7 +554,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
|
||||
.uartclk = KS8695_CLOCK_RATE * 16,
|
||||
.fifosize = 16,
|
||||
.ops = &ks8695uart_pops,
|
||||
.flags = ASYNC_BOOT_AUTOCONF,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 0,
|
||||
}
|
||||
};
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
@ -249,3 +250,5 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -84,6 +84,22 @@ enum SCI_CLKS {
|
||||
SCI_NUM_CLKS
|
||||
};
|
||||
|
||||
/* Bit x set means sampling rate x + 1 is supported */
|
||||
#define SCI_SR(x) BIT((x) - 1)
|
||||
#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
|
||||
|
||||
#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
|
||||
SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
|
||||
SCI_SR(19) | SCI_SR(27)
|
||||
|
||||
#define min_sr(_port) ffs((_port)->sampling_rate_mask)
|
||||
#define max_sr(_port) fls((_port)->sampling_rate_mask)
|
||||
|
||||
/* Iterate over all supported sampling rates, from high to low */
|
||||
#define for_each_sr(_sr, _port) \
|
||||
for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
|
||||
if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
|
||||
|
||||
struct sci_port {
|
||||
struct uart_port port;
|
||||
|
||||
@ -93,7 +109,7 @@ struct sci_port {
|
||||
unsigned int overrun_mask;
|
||||
unsigned int error_mask;
|
||||
unsigned int error_clear;
|
||||
unsigned int sampling_rate;
|
||||
unsigned int sampling_rate_mask;
|
||||
resource_size_t reg_size;
|
||||
|
||||
/* Break timer */
|
||||
@ -637,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
|
||||
#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
|
||||
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int sci_poll_get_char(struct uart_port *port)
|
||||
@ -678,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
serial_port_out(port, SCxTDR, c);
|
||||
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
|
||||
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
|
||||
CONFIG_SERIAL_SH_SCI_EARLYCON */
|
||||
|
||||
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
|
||||
{
|
||||
@ -1902,19 +1920,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
|
||||
unsigned int *srr)
|
||||
{
|
||||
unsigned long freq = s->clk_rates[SCI_SCK];
|
||||
unsigned int min_sr, max_sr, sr;
|
||||
int err, min_err = INT_MAX;
|
||||
unsigned int sr;
|
||||
|
||||
if (s->sampling_rate) {
|
||||
/* SCI(F) has a fixed sampling rate */
|
||||
min_sr = max_sr = s->sampling_rate / 2;
|
||||
} else {
|
||||
/* HSCIF has a variable 1/(8..32) sampling rate */
|
||||
min_sr = 8;
|
||||
max_sr = 32;
|
||||
}
|
||||
if (s->port.type != PORT_HSCIF)
|
||||
freq *= 2;
|
||||
|
||||
for (sr = max_sr; sr >= min_sr; sr--) {
|
||||
for_each_sr(sr, s) {
|
||||
err = DIV_ROUND_CLOSEST(freq, sr) - bps;
|
||||
if (abs(err) >= abs(min_err))
|
||||
continue;
|
||||
@ -1935,19 +1947,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
|
||||
unsigned long freq, unsigned int *dlr,
|
||||
unsigned int *srr)
|
||||
{
|
||||
unsigned int min_sr, max_sr, sr, dl;
|
||||
int err, min_err = INT_MAX;
|
||||
unsigned int sr, dl;
|
||||
|
||||
if (s->sampling_rate) {
|
||||
/* SCIF has a fixed sampling rate */
|
||||
min_sr = max_sr = s->sampling_rate / 2;
|
||||
} else {
|
||||
/* HSCIF has a variable 1/(8..32) sampling rate */
|
||||
min_sr = 8;
|
||||
max_sr = 32;
|
||||
}
|
||||
if (s->port.type != PORT_HSCIF)
|
||||
freq *= 2;
|
||||
|
||||
for (sr = max_sr; sr >= min_sr; sr--) {
|
||||
for_each_sr(sr, s) {
|
||||
dl = DIV_ROUND_CLOSEST(freq, sr * bps);
|
||||
dl = clamp(dl, 1U, 65535U);
|
||||
|
||||
@ -1973,19 +1979,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
|
||||
unsigned int *brr, unsigned int *srr,
|
||||
unsigned int *cks)
|
||||
{
|
||||
unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
|
||||
unsigned long freq = s->clk_rates[SCI_FCK];
|
||||
unsigned int sr, br, prediv, scrate, c;
|
||||
int err, min_err = INT_MAX;
|
||||
|
||||
if (s->sampling_rate) {
|
||||
min_sr = max_sr = s->sampling_rate;
|
||||
shift = 0;
|
||||
} else {
|
||||
/* HSCIF has a variable sample rate */
|
||||
min_sr = 8;
|
||||
max_sr = 32;
|
||||
shift = 1;
|
||||
}
|
||||
if (s->port.type != PORT_HSCIF)
|
||||
freq *= 2;
|
||||
|
||||
/*
|
||||
* Find the combination of sample rate and clock select with the
|
||||
@ -2002,10 +2001,10 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
|
||||
* (|D - 0.5| / N * (1 + F))|
|
||||
* NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
|
||||
*/
|
||||
for (sr = max_sr; sr >= min_sr; sr--) {
|
||||
for_each_sr(sr, s) {
|
||||
for (c = 0; c <= 3; c++) {
|
||||
/* integerized formulas from HSCIF documentation */
|
||||
prediv = sr * (1 << (2 * c + shift));
|
||||
prediv = sr * (1 << (2 * c + 1));
|
||||
|
||||
/*
|
||||
* We need to calculate:
|
||||
@ -2062,7 +2061,7 @@ static void sci_reset(struct uart_port *port)
|
||||
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud, smr_val = 0, scr_val = 0, i;
|
||||
unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i;
|
||||
unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
|
||||
unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
@ -2096,8 +2095,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
for (i = 0; i < SCI_NUM_CLKS; i++)
|
||||
max_freq = max(max_freq, s->clk_rates[i]);
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0,
|
||||
max_freq / max(s->sampling_rate, 8U));
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
|
||||
if (!baud)
|
||||
goto done;
|
||||
|
||||
@ -2185,6 +2183,17 @@ done:
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
if (best_clk >= 0) {
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
switch (srr + 1) {
|
||||
case 5: smr_val |= SCSMR_SRC_5; break;
|
||||
case 7: smr_val |= SCSMR_SRC_7; break;
|
||||
case 11: smr_val |= SCSMR_SRC_11; break;
|
||||
case 13: smr_val |= SCSMR_SRC_13; break;
|
||||
case 16: smr_val |= SCSMR_SRC_16; break;
|
||||
case 17: smr_val |= SCSMR_SRC_17; break;
|
||||
case 19: smr_val |= SCSMR_SRC_19; break;
|
||||
case 27: smr_val |= SCSMR_SRC_27; break;
|
||||
}
|
||||
smr_val |= cks;
|
||||
dev_dbg(port->dev,
|
||||
"SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
|
||||
@ -2200,7 +2209,8 @@ done:
|
||||
} else {
|
||||
/* Don't touch the bit rate configuration */
|
||||
scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
|
||||
smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
|
||||
smr_val |= serial_port_in(port, SCSMR) &
|
||||
(SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
|
||||
dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
|
||||
serial_port_out(port, SCSCR, scr_val);
|
||||
serial_port_out(port, SCSMR, smr_val);
|
||||
@ -2232,6 +2242,16 @@ done:
|
||||
scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
|
||||
dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
|
||||
serial_port_out(port, SCSCR, scr_val);
|
||||
if ((srr + 1 == 5) &&
|
||||
(port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
|
||||
/*
|
||||
* In asynchronous mode, when the sampling rate is 1/5, first
|
||||
* received data may become invalid on some SCIFA and SCIFB.
|
||||
* To avoid this problem wait more than 1 serial data time (1
|
||||
* bit time x serial data number) after setting SCSCR.RE = 1.
|
||||
*/
|
||||
udelay(DIV_ROUND_UP(10 * 1000000, baud));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
/*
|
||||
@ -2528,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev,
|
||||
port->fifosize = 256;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sci_port->sampling_rate = 16;
|
||||
sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
|
||||
break;
|
||||
case PORT_HSCIF:
|
||||
port->fifosize = 128;
|
||||
sci_port->overrun_reg = SCLSR;
|
||||
sci_port->overrun_mask = SCLSR_ORER;
|
||||
sci_port->sampling_rate = 0;
|
||||
sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
|
||||
break;
|
||||
case PORT_SCIFA:
|
||||
port->fifosize = 64;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sci_port->sampling_rate = 16;
|
||||
sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
|
||||
break;
|
||||
case PORT_SCIF:
|
||||
port->fifosize = 16;
|
||||
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sci_port->sampling_rate = 16;
|
||||
sci_port->sampling_rate_mask = SCI_SR(16);
|
||||
} else {
|
||||
sci_port->overrun_reg = SCLSR;
|
||||
sci_port->overrun_mask = SCLSR_ORER;
|
||||
sci_port->sampling_rate = 32;
|
||||
sci_port->sampling_rate_mask = SCI_SR(32);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
port->fifosize = 1;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCI_ORER;
|
||||
sci_port->sampling_rate = 32;
|
||||
sci_port->sampling_rate_mask = SCI_SR(32);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2567,7 +2587,7 @@ static int sci_init_single(struct platform_device *dev,
|
||||
* data override the sampling rate for now.
|
||||
*/
|
||||
if (p->sampling_rate)
|
||||
sci_port->sampling_rate = p->sampling_rate;
|
||||
sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
|
||||
|
||||
if (!early) {
|
||||
ret = sci_init_clocks(sci_port, &dev->dev);
|
||||
@ -2632,7 +2652,8 @@ static void sci_cleanup_single(struct sci_port *port)
|
||||
pm_runtime_disable(port->port.dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
||||
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
|
||||
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
|
||||
static void serial_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
sci_poll_put_char(port, ch);
|
||||
@ -2652,9 +2673,12 @@ static void serial_console_write(struct console *co, const char *s,
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
#if defined(SUPPORT_SYSRQ)
|
||||
if (port->sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
else
|
||||
#endif
|
||||
if (oops_in_progress)
|
||||
locked = spin_trylock(&port->lock);
|
||||
else
|
||||
spin_lock(&port->lock);
|
||||
@ -2764,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
|
||||
|
||||
#define SCI_CONSOLE NULL
|
||||
|
||||
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
|
||||
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
|
||||
|
||||
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
|
||||
|
||||
@ -2998,6 +3022,62 @@ static void __exit sci_exit(void)
|
||||
early_platform_init_buffer("earlyprintk", &sci_driver,
|
||||
early_serial_buf, ARRAY_SIZE(early_serial_buf));
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
|
||||
static struct __init plat_sci_port port_cfg;
|
||||
|
||||
static int __init early_console_setup(struct earlycon_device *device,
|
||||
int type)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.serial_in = sci_serial_in;
|
||||
device->port.serial_out = sci_serial_out;
|
||||
device->port.type = type;
|
||||
memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
|
||||
sci_ports[0].cfg = &port_cfg;
|
||||
sci_ports[0].cfg->type = type;
|
||||
sci_probe_regmap(sci_ports[0].cfg);
|
||||
port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) |
|
||||
SCSCR_RE | SCSCR_TE;
|
||||
sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr);
|
||||
|
||||
device->con->write = serial_console_write;
|
||||
return 0;
|
||||
}
|
||||
static int __init sci_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return early_console_setup(device, PORT_SCI);
|
||||
}
|
||||
static int __init scif_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return early_console_setup(device, PORT_SCIF);
|
||||
}
|
||||
static int __init scifa_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return early_console_setup(device, PORT_SCIFA);
|
||||
}
|
||||
static int __init scifb_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return early_console_setup(device, PORT_SCIFB);
|
||||
}
|
||||
static int __init hscif_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return early_console_setup(device, PORT_HSCIF);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
|
||||
#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
|
||||
|
||||
module_init(sci_init);
|
||||
module_exit(sci_exit);
|
||||
|
||||
|
@ -35,12 +35,27 @@ enum {
|
||||
|
||||
|
||||
/* SCSMR (Serial Mode Register) */
|
||||
#define SCSMR_C_A BIT(7) /* Communication Mode */
|
||||
#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
|
||||
#define SCSMR_ASYNC 0 /* - Asynchronous mode */
|
||||
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
|
||||
#define SCSMR_PE BIT(5) /* Parity Enable */
|
||||
#define SCSMR_ODD BIT(4) /* Odd Parity */
|
||||
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
|
||||
#define SCSMR_CKS 0x0003 /* Clock Select */
|
||||
|
||||
/* Serial Mode Register, SCIFA/SCIFB only bits */
|
||||
#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
|
||||
#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
|
||||
#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
|
||||
#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
|
||||
#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
|
||||
#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
|
||||
#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
|
||||
#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
|
||||
#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
|
||||
#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
|
||||
|
||||
/* Serial Control Register, SCIFA/SCIFB only bits */
|
||||
#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
|
||||
#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
|
||||
|
@ -624,8 +624,6 @@ static int __init sprd_early_console_setup(
|
||||
device->con->write = sprd_early_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
|
||||
sprd_early_console_setup);
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define ULITE_NAME "ttyUL"
|
||||
#define ULITE_MAJOR 204
|
||||
#define ULITE_MINOR 187
|
||||
#define ULITE_NR_UARTS 4
|
||||
#define ULITE_NR_UARTS 16
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Register definitions
|
||||
@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr)
|
||||
iowrite32be(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_be = {
|
||||
static const struct uartlite_reg_ops uartlite_be = {
|
||||
.in = uartlite_inbe32,
|
||||
.out = uartlite_outbe32,
|
||||
};
|
||||
@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr)
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_le = {
|
||||
static const struct uartlite_reg_ops uartlite_le = {
|
||||
.in = uartlite_inle32,
|
||||
.out = uartlite_outle32,
|
||||
};
|
||||
|
||||
static inline u32 uart_in32(u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
const struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
return reg_ops->in(port->membase + offset);
|
||||
}
|
||||
|
||||
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
const struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
reg_ops->out(val, port->membase + offset);
|
||||
}
|
||||
@ -193,12 +193,15 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
||||
static irqreturn_t ulite_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
int busy, n = 0;
|
||||
int stat, busy, n = 0;
|
||||
unsigned long flags;
|
||||
|
||||
do {
|
||||
int stat = uart_in32(ULITE_STATUS, port);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
stat = uart_in32(ULITE_STATUS, port);
|
||||
busy = ulite_receive(port, stat);
|
||||
busy |= ulite_transmit(port, stat);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
n++;
|
||||
} while (busy);
|
||||
|
||||
@ -259,7 +262,8 @@ static int ulite_startup(struct uart_port *port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port);
|
||||
ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING,
|
||||
"uartlite", port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -519,6 +523,47 @@ static int __init ulite_console_init(void)
|
||||
|
||||
console_initcall(ulite_console_init);
|
||||
|
||||
static void early_uartlite_putc(struct uart_port *port, int c)
|
||||
{
|
||||
/*
|
||||
* Limit how many times we'll spin waiting for TX FIFO status.
|
||||
* This will prevent lockups if the base address is incorrectly
|
||||
* set, or any other issue on the UARTLITE.
|
||||
* This limit is pretty arbitrary, unless we are at about 10 baud
|
||||
* we'll never timeout on a working UART.
|
||||
*/
|
||||
|
||||
unsigned retries = 1000000;
|
||||
/* read status bit - 0x8 offset */
|
||||
while (--retries && (readl(port->membase + 8) & (1 << 3)))
|
||||
;
|
||||
|
||||
/* Only attempt the iowrite if we didn't timeout */
|
||||
/* write to TX_FIFO - 0x4 offset */
|
||||
if (retries)
|
||||
writel(c & 0xff, port->membase + 4);
|
||||
}
|
||||
|
||||
static void early_uartlite_write(struct console *console,
|
||||
const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *device = console->data;
|
||||
uart_console_write(&device->port, s, n, early_uartlite_putc);
|
||||
}
|
||||
|
||||
static int __init early_uartlite_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = early_uartlite_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(uartlite, early_uartlite_setup);
|
||||
OF_EARLYCON_DECLARE(uartlite_b, "xlnx,opb-uartlite-1.00.b", early_uartlite_setup);
|
||||
OF_EARLYCON_DECLARE(uartlite_a, "xlnx,xps-uartlite-1.00.a", early_uartlite_setup);
|
||||
|
||||
#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
|
||||
|
||||
static struct uart_driver ulite_uart_driver = {
|
||||
|
@ -50,24 +50,24 @@ module_param(rx_timeout, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
|
||||
/* Register offsets for the UART. */
|
||||
#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
|
||||
#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
|
||||
#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
|
||||
#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
|
||||
#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
|
||||
#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
|
||||
#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
|
||||
#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
|
||||
#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
|
||||
#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
|
||||
#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
|
||||
#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
|
||||
#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
|
||||
#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
|
||||
#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
|
||||
#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
|
||||
#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
|
||||
#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
|
||||
#define CDNS_UART_CR 0x00 /* Control Register */
|
||||
#define CDNS_UART_MR 0x04 /* Mode Register */
|
||||
#define CDNS_UART_IER 0x08 /* Interrupt Enable */
|
||||
#define CDNS_UART_IDR 0x0C /* Interrupt Disable */
|
||||
#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
|
||||
#define CDNS_UART_ISR 0x14 /* Interrupt Status */
|
||||
#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
|
||||
#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
|
||||
#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
|
||||
#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
|
||||
#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
|
||||
#define CDNS_UART_SR 0x2C /* Channel Status */
|
||||
#define CDNS_UART_FIFO 0x30 /* FIFO */
|
||||
#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
|
||||
#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
|
||||
#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
|
||||
#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
|
||||
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
|
||||
|
||||
/* Control Register Bit Definitions */
|
||||
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
|
||||
@ -126,6 +126,10 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
|
||||
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
|
||||
|
||||
#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
|
||||
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
|
||||
CDNS_UART_IXR_TOUT)
|
||||
|
||||
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
|
||||
#define CDNS_UART_IXR_BRK 0x80000000
|
||||
|
||||
@ -172,6 +176,104 @@ struct cdns_uart {
|
||||
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
|
||||
clk_rate_change_nb);
|
||||
|
||||
static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
||||
{
|
||||
/*
|
||||
* There is no hardware break detection, so we interpret framing
|
||||
* error with all-zeros data as a break sequence. Most of the time,
|
||||
* there's another non-zero byte at the end of the sequence.
|
||||
*/
|
||||
if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_RXEMPTY)) {
|
||||
if (!readl(port->membase + CDNS_UART_FIFO)) {
|
||||
port->read_status_mask |= CDNS_UART_IXR_BRK;
|
||||
isrstatus &= ~CDNS_UART_IXR_FRAMING;
|
||||
}
|
||||
}
|
||||
writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR);
|
||||
}
|
||||
|
||||
/* drop byte with parity error if IGNPAR specified */
|
||||
if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
|
||||
isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);
|
||||
|
||||
isrstatus &= port->read_status_mask;
|
||||
isrstatus &= ~port->ignore_status_mask;
|
||||
|
||||
if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
|
||||
return;
|
||||
|
||||
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
|
||||
u32 data;
|
||||
char status = TTY_NORMAL;
|
||||
|
||||
data = readl(port->membase + CDNS_UART_FIFO);
|
||||
|
||||
/* Non-NULL byte after BREAK is garbage (99%) */
|
||||
if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
|
||||
port->read_status_mask &= ~CDNS_UART_IXR_BRK;
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(port, data))
|
||||
continue;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if (isrstatus & CDNS_UART_IXR_PARITY) {
|
||||
port->icount.parity++;
|
||||
status = TTY_PARITY;
|
||||
} else if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
port->icount.frame++;
|
||||
status = TTY_FRAME;
|
||||
} else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
|
||||
port->icount.overrun++;
|
||||
}
|
||||
|
||||
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
|
||||
data, status);
|
||||
}
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void cdns_uart_handle_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int numbytes;
|
||||
|
||||
if (uart_circ_empty(&port->state->xmit)) {
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
|
||||
return;
|
||||
}
|
||||
|
||||
numbytes = port->fifosize;
|
||||
while (numbytes && !uart_circ_empty(&port->state->xmit) &&
|
||||
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
|
||||
/*
|
||||
* Get the data from the UART circular buffer
|
||||
* and write it to the cdns_uart's TX_FIFO
|
||||
* register.
|
||||
*/
|
||||
writel(port->state->xmit.buf[port->state->xmit.tail],
|
||||
port->membase + CDNS_UART_FIFO);
|
||||
port->icount.tx++;
|
||||
|
||||
/*
|
||||
* Adjust the tail of the UART buffer and wrap
|
||||
* the buffer if it reaches limit.
|
||||
*/
|
||||
port->state->xmit.tail =
|
||||
(port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
numbytes--;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_uart_isr - Interrupt handler
|
||||
* @irq: Irq number
|
||||
@ -183,129 +285,22 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)dev_id;
|
||||
unsigned long flags;
|
||||
unsigned int isrstatus, numbytes;
|
||||
unsigned int data;
|
||||
char status = TTY_NORMAL;
|
||||
unsigned int isrstatus;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Read the interrupt status register to determine which
|
||||
* interrupt(s) is/are active.
|
||||
*/
|
||||
isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
|
||||
isrstatus = readl(port->membase + CDNS_UART_ISR);
|
||||
|
||||
/*
|
||||
* There is no hardware break detection, so we interpret framing
|
||||
* error with all-zeros data as a break sequence. Most of the time,
|
||||
* there's another non-zero byte at the end of the sequence.
|
||||
*/
|
||||
if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_RXEMPTY)) {
|
||||
if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
|
||||
port->read_status_mask |= CDNS_UART_IXR_BRK;
|
||||
isrstatus &= ~CDNS_UART_IXR_FRAMING;
|
||||
}
|
||||
}
|
||||
writel(CDNS_UART_IXR_FRAMING,
|
||||
port->membase + CDNS_UART_ISR_OFFSET);
|
||||
}
|
||||
if (isrstatus & CDNS_UART_RX_IRQS)
|
||||
cdns_uart_handle_rx(port, isrstatus);
|
||||
|
||||
/* drop byte with parity error if IGNPAR specified */
|
||||
if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
|
||||
isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);
|
||||
if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
|
||||
cdns_uart_handle_tx(port);
|
||||
|
||||
isrstatus &= port->read_status_mask;
|
||||
isrstatus &= ~port->ignore_status_mask;
|
||||
|
||||
if ((isrstatus & CDNS_UART_IXR_TOUT) ||
|
||||
(isrstatus & CDNS_UART_IXR_RXTRIG)) {
|
||||
/* Receive Timeout Interrupt */
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_RXEMPTY)) {
|
||||
data = readl(port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
|
||||
/* Non-NULL byte after BREAK is garbage (99%) */
|
||||
if (data && (port->read_status_mask &
|
||||
CDNS_UART_IXR_BRK)) {
|
||||
port->read_status_mask &= ~CDNS_UART_IXR_BRK;
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
/*
|
||||
* uart_handle_sysrq_char() doesn't work if
|
||||
* spinlocked, for some reason
|
||||
*/
|
||||
if (port->sysrq) {
|
||||
spin_unlock(&port->lock);
|
||||
if (uart_handle_sysrq_char(port,
|
||||
(unsigned char)data)) {
|
||||
spin_lock(&port->lock);
|
||||
continue;
|
||||
}
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if (isrstatus & CDNS_UART_IXR_PARITY) {
|
||||
port->icount.parity++;
|
||||
status = TTY_PARITY;
|
||||
} else if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
port->icount.frame++;
|
||||
status = TTY_FRAME;
|
||||
} else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
|
||||
port->icount.overrun++;
|
||||
}
|
||||
|
||||
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
|
||||
data, status);
|
||||
}
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
|
||||
/* Dispatch an appropriate handler */
|
||||
if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
|
||||
if (uart_circ_empty(&port->state->xmit)) {
|
||||
writel(CDNS_UART_IXR_TXEMPTY,
|
||||
port->membase + CDNS_UART_IDR_OFFSET);
|
||||
} else {
|
||||
numbytes = port->fifosize;
|
||||
/* Break if no more data available in the UART buffer */
|
||||
while (numbytes--) {
|
||||
if (uart_circ_empty(&port->state->xmit))
|
||||
break;
|
||||
/* Get the data from the UART circular buffer
|
||||
* and write it to the cdns_uart's TX_FIFO
|
||||
* register.
|
||||
*/
|
||||
writel(port->state->xmit.buf[
|
||||
port->state->xmit.tail],
|
||||
port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
|
||||
port->icount.tx++;
|
||||
|
||||
/* Adjust the tail of the UART buffer and wrap
|
||||
* the buffer if it reaches limit.
|
||||
*/
|
||||
port->state->xmit.tail =
|
||||
(port->state->xmit.tail + 1) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(
|
||||
&port->state->xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
}
|
||||
|
||||
writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
|
||||
writel(isrstatus, port->membase + CDNS_UART_ISR);
|
||||
|
||||
/* be sure to release the lock and tty before leaving */
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@ -395,14 +390,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
|
||||
&div8);
|
||||
|
||||
/* Write new divisors to hardware */
|
||||
mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
|
||||
mreg = readl(port->membase + CDNS_UART_MR);
|
||||
if (div8)
|
||||
mreg |= CDNS_UART_MR_CLKSEL;
|
||||
else
|
||||
mreg &= ~CDNS_UART_MR_CLKSEL;
|
||||
writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
|
||||
writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
|
||||
writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
|
||||
writel(mreg, port->membase + CDNS_UART_MR);
|
||||
writel(cd, port->membase + CDNS_UART_BAUDGEN);
|
||||
writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
|
||||
cdns_uart->baud = baud;
|
||||
|
||||
return calc_baud;
|
||||
@ -449,9 +444,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
||||
spin_lock_irqsave(&cdns_uart->port->lock, flags);
|
||||
|
||||
/* Disable the TX and RX to set baud rate */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
|
||||
|
||||
@ -476,11 +471,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
||||
spin_lock_irqsave(&cdns_uart->port->lock, flags);
|
||||
|
||||
/* Set TX/RX Reset */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
while (readl(port->membase + CDNS_UART_CR_OFFSET) &
|
||||
while (readl(port->membase + CDNS_UART_CR) &
|
||||
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
|
||||
cpu_relax();
|
||||
|
||||
@ -489,11 +484,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
||||
* enable bit and RX enable bit to enable the transmitter and
|
||||
* receiver.
|
||||
*/
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
|
||||
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
|
||||
|
||||
@ -510,43 +505,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
||||
*/
|
||||
static void cdns_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int status, numbytes = port->fifosize;
|
||||
unsigned int status;
|
||||
|
||||
if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
|
||||
if (uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
status = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
/* Set the TX enable bit and clear the TX disable bit to enable the
|
||||
/*
|
||||
* Set the TX enable bit and clear the TX disable bit to enable the
|
||||
* transmitter.
|
||||
*/
|
||||
writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
status = readl(port->membase + CDNS_UART_CR);
|
||||
status &= ~CDNS_UART_CR_TX_DIS;
|
||||
status |= CDNS_UART_CR_TX_EN;
|
||||
writel(status, port->membase + CDNS_UART_CR);
|
||||
|
||||
while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
|
||||
/* Break if no more data available in the UART buffer */
|
||||
if (uart_circ_empty(&port->state->xmit))
|
||||
break;
|
||||
if (uart_circ_empty(&port->state->xmit))
|
||||
return;
|
||||
|
||||
/* Get the data from the UART circular buffer and
|
||||
* write it to the cdns_uart's TX_FIFO register.
|
||||
*/
|
||||
writel(port->state->xmit.buf[port->state->xmit.tail],
|
||||
port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
port->icount.tx++;
|
||||
cdns_uart_handle_tx(port);
|
||||
|
||||
/* Adjust the tail of the UART buffer and wrap
|
||||
* the buffer if it reaches limit.
|
||||
*/
|
||||
port->state->xmit.tail = (port->state->xmit.tail + 1) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
}
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
|
||||
/* Enable the TX Empty interrupt */
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET);
|
||||
|
||||
if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -557,10 +537,10 @@ static void cdns_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int regval;
|
||||
|
||||
regval = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
regval = readl(port->membase + CDNS_UART_CR);
|
||||
regval |= CDNS_UART_CR_TX_DIS;
|
||||
/* Disable the transmitter */
|
||||
writel(regval, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(regval, port->membase + CDNS_UART_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -571,10 +551,13 @@ static void cdns_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned int regval;
|
||||
|
||||
regval = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
regval |= CDNS_UART_CR_RX_DIS;
|
||||
/* Disable RX IRQs */
|
||||
writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR);
|
||||
|
||||
/* Disable the receiver */
|
||||
writel(regval, port->membase + CDNS_UART_CR_OFFSET);
|
||||
regval = readl(port->membase + CDNS_UART_CR);
|
||||
regval |= CDNS_UART_CR_RX_DIS;
|
||||
writel(regval, port->membase + CDNS_UART_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -587,7 +570,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
status = readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
status = readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_TXEMPTY;
|
||||
return status ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
@ -605,15 +588,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
status = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
status = readl(port->membase + CDNS_UART_CR);
|
||||
|
||||
if (ctl == -1)
|
||||
writel(CDNS_UART_CR_STARTBRK | status,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
port->membase + CDNS_UART_CR);
|
||||
else {
|
||||
if ((status & CDNS_UART_CR_STOPBRK) == 0)
|
||||
writel(CDNS_UART_CR_STOPBRK | status,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
port->membase + CDNS_UART_CR);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
@ -636,18 +619,18 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Wait for the transmit FIFO to empty before making changes */
|
||||
if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
|
||||
if (!(readl(port->membase + CDNS_UART_CR) &
|
||||
CDNS_UART_CR_TX_DIS)) {
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_TXEMPTY)) {
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the TX and RX to set baud rate */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
/*
|
||||
* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
|
||||
@ -666,20 +649,20 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
/* Set TX/RX Reset */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
/*
|
||||
* Clear the RX disable and TX disable bits and then set the TX enable
|
||||
* bit and RX enable bit to enable the transmitter and receiver.
|
||||
*/
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
|
||||
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
|
||||
|
||||
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
|
||||
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
|
||||
@ -699,7 +682,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
|
||||
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
|
||||
|
||||
mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
|
||||
mode_reg = readl(port->membase + CDNS_UART_MR);
|
||||
|
||||
/* Handling Data Size */
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
@ -740,7 +723,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
cval |= CDNS_UART_MR_PARITY_NONE;
|
||||
}
|
||||
cval |= mode_reg & 1;
|
||||
writel(cval, port->membase + CDNS_UART_MR_OFFSET);
|
||||
writel(cval, port->membase + CDNS_UART_MR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
@ -753,63 +736,67 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
*/
|
||||
static int cdns_uart_startup(struct uart_port *port)
|
||||
{
|
||||
unsigned int retval = 0, status = 0;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned int status = 0;
|
||||
|
||||
retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,
|
||||
(void *)port);
|
||||
if (retval)
|
||||
return retval;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable the TX and RX */
|
||||
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
port->membase + CDNS_UART_CR);
|
||||
|
||||
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
|
||||
* no break chars.
|
||||
*/
|
||||
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
port->membase + CDNS_UART_CR);
|
||||
|
||||
status = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
|
||||
/* Clear the RX disable and TX disable bits and then set the TX enable
|
||||
* bit and RX enable bit to enable the transmitter and receiver.
|
||||
/*
|
||||
* Clear the RX disable bit and then set the RX enable bit to enable
|
||||
* the receiver.
|
||||
*/
|
||||
writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS))
|
||||
| (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN |
|
||||
CDNS_UART_CR_STOPBRK),
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
status = readl(port->membase + CDNS_UART_CR);
|
||||
status &= CDNS_UART_CR_RX_DIS;
|
||||
status |= CDNS_UART_CR_RX_EN;
|
||||
writel(status, port->membase + CDNS_UART_CR);
|
||||
|
||||
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
|
||||
* no parity.
|
||||
*/
|
||||
writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
|
||||
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
|
||||
port->membase + CDNS_UART_MR_OFFSET);
|
||||
port->membase + CDNS_UART_MR);
|
||||
|
||||
/*
|
||||
* Set the RX FIFO Trigger level to use most of the FIFO, but it
|
||||
* can be tuned with a module parameter
|
||||
*/
|
||||
writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
|
||||
writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
|
||||
|
||||
/*
|
||||
* Receive Timeout register is enabled but it
|
||||
* can be tuned with a module parameter
|
||||
*/
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
|
||||
|
||||
/* Clear out any pending interrupts before enabling them */
|
||||
writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
|
||||
port->membase + CDNS_UART_ISR_OFFSET);
|
||||
writel(readl(port->membase + CDNS_UART_ISR),
|
||||
port->membase + CDNS_UART_ISR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "request_irq '%d' failed with %d\n",
|
||||
port->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the Interrupt Registers with desired interrupts */
|
||||
writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY |
|
||||
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN |
|
||||
CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT,
|
||||
port->membase + CDNS_UART_IER_OFFSET);
|
||||
writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
|
||||
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -819,14 +806,21 @@ static int cdns_uart_startup(struct uart_port *port)
|
||||
static void cdns_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable interrupts */
|
||||
status = readl(port->membase + CDNS_UART_IMR_OFFSET);
|
||||
writel(status, port->membase + CDNS_UART_IDR_OFFSET);
|
||||
status = readl(port->membase + CDNS_UART_IMR);
|
||||
writel(status, port->membase + CDNS_UART_IDR);
|
||||
writel(0xffffffff, port->membase + CDNS_UART_ISR);
|
||||
|
||||
/* Disable the TX and RX */
|
||||
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
port->membase + CDNS_UART_CR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
@ -928,7 +922,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
|
||||
val = readl(port->membase + CDNS_UART_MODEMCR);
|
||||
|
||||
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
|
||||
|
||||
@ -937,55 +931,46 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
if (mctrl & TIOCM_DTR)
|
||||
val |= CDNS_UART_MODEMCR_DTR;
|
||||
|
||||
writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
|
||||
writel(val, port->membase + CDNS_UART_MODEMCR);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int cdns_uart_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
u32 imr;
|
||||
int c;
|
||||
unsigned long flags;
|
||||
|
||||
/* Disable all interrupts */
|
||||
imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
|
||||
writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Check if FIFO is empty */
|
||||
if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
|
||||
if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
|
||||
c = NO_POLL_CHAR;
|
||||
else /* Read a character */
|
||||
c = (unsigned char) readl(
|
||||
port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(imr, port->membase + CDNS_UART_IER_OFFSET);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
u32 imr;
|
||||
unsigned long flags;
|
||||
|
||||
/* Disable all interrupts */
|
||||
imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
|
||||
writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Wait until FIFO is empty */
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_TXEMPTY))
|
||||
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
|
||||
cpu_relax();
|
||||
|
||||
/* Write a character */
|
||||
writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
writel(c, port->membase + CDNS_UART_FIFO);
|
||||
|
||||
/* Wait until FIFO is empty */
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_TXEMPTY))
|
||||
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
|
||||
cpu_relax();
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(imr, port->membase + CDNS_UART_IER_OFFSET);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1059,8 +1044,7 @@ static struct uart_port *cdns_uart_get_port(int id)
|
||||
*/
|
||||
static void cdns_uart_console_wait_tx(struct uart_port *port)
|
||||
{
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
CDNS_UART_SR_TXEMPTY))
|
||||
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
|
||||
barrier();
|
||||
}
|
||||
|
||||
@ -1072,7 +1056,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port)
|
||||
static void cdns_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
cdns_uart_console_wait_tx(port);
|
||||
writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
writel(ch, port->membase + CDNS_UART_FIFO);
|
||||
}
|
||||
|
||||
static void __init cdns_early_write(struct console *con, const char *s,
|
||||
@ -1093,7 +1077,9 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(cdns, cdns_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
|
||||
|
||||
/**
|
||||
* cdns_uart_console_write - perform write operation
|
||||
@ -1109,30 +1095,33 @@ static void cdns_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int imr, ctrl;
|
||||
int locked = 1;
|
||||
|
||||
if (oops_in_progress)
|
||||
if (port->sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* save and disable interrupt */
|
||||
imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
|
||||
writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
|
||||
imr = readl(port->membase + CDNS_UART_IMR);
|
||||
writel(imr, port->membase + CDNS_UART_IDR);
|
||||
|
||||
/*
|
||||
* Make sure that the tx part is enabled. Set the TX enable bit and
|
||||
* clear the TX disable bit to enable the transmitter.
|
||||
*/
|
||||
ctrl = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN,
|
||||
port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl &= ~CDNS_UART_CR_TX_DIS;
|
||||
ctrl |= CDNS_UART_CR_TX_EN;
|
||||
writel(ctrl, port->membase + CDNS_UART_CR);
|
||||
|
||||
uart_console_write(port, s, count, cdns_uart_console_putchar);
|
||||
cdns_uart_console_wait_tx(port);
|
||||
|
||||
writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl, port->membase + CDNS_UART_CR);
|
||||
|
||||
/* restore interrupt state */
|
||||
writel(imr, port->membase + CDNS_UART_IER_OFFSET);
|
||||
writel(imr, port->membase + CDNS_UART_IER);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@ -1244,14 +1233,13 @@ static int cdns_uart_suspend(struct device *device)
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* Empty the receive FIFO 1st before making changes */
|
||||
while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
|
||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_RXEMPTY))
|
||||
readl(port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
readl(port->membase + CDNS_UART_FIFO);
|
||||
/* set RX trigger level to 1 */
|
||||
writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
|
||||
writel(1, port->membase + CDNS_UART_RXWM);
|
||||
/* disable RX timeout interrups */
|
||||
writel(CDNS_UART_IXR_TOUT,
|
||||
port->membase + CDNS_UART_IDR_OFFSET);
|
||||
writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
@ -1290,30 +1278,28 @@ static int cdns_uart_resume(struct device *device)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Set TX/RX Reset */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
while (readl(port->membase + CDNS_UART_CR_OFFSET) &
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
while (readl(port->membase + CDNS_UART_CR) &
|
||||
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
|
||||
cpu_relax();
|
||||
|
||||
/* restore rx timeout value */
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
|
||||
writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
|
||||
/* Enable Tx/Rx */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
|
||||
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
|
||||
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
} else {
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* restore original rx trigger level */
|
||||
writel(rx_trigger_level,
|
||||
port->membase + CDNS_UART_RXWM_OFFSET);
|
||||
writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
|
||||
/* enable RX timeout interrupt */
|
||||
writel(CDNS_UART_IXR_TOUT,
|
||||
port->membase + CDNS_UART_IER_OFFSET);
|
||||
writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
@ -1406,27 +1392,30 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out_notif_unreg;
|
||||
} else {
|
||||
/* Register the port.
|
||||
* This function also registers this device with the tty layer
|
||||
* and triggers invocation of the config_port() entry point.
|
||||
*/
|
||||
port->mapbase = res->start;
|
||||
port->irq = irq;
|
||||
port->dev = &pdev->dev;
|
||||
port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
|
||||
port->private_data = cdns_uart_data;
|
||||
cdns_uart_data->port = port;
|
||||
platform_set_drvdata(pdev, port);
|
||||
rc = uart_add_one_port(&cdns_uart_uart_driver, port);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"uart_add_one_port() failed; err=%i\n", rc);
|
||||
goto err_out_notif_unreg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the port.
|
||||
* This function also registers this device with the tty layer
|
||||
* and triggers invocation of the config_port() entry point.
|
||||
*/
|
||||
port->mapbase = res->start;
|
||||
port->irq = irq;
|
||||
port->dev = &pdev->dev;
|
||||
port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
|
||||
port->private_data = cdns_uart_data;
|
||||
cdns_uart_data->port = port;
|
||||
platform_set_drvdata(pdev, port);
|
||||
|
||||
rc = uart_add_one_port(&cdns_uart_uart_driver, port);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"uart_add_one_port() failed; err=%i\n", rc);
|
||||
goto err_out_notif_unreg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_notif_unreg:
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
clk_notifier_unregister(cdns_uart_data->uartclk,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user