/* sunzilog.c: Zilog serial driver for Sparc systems.
*
* Driver for Zilog serial chips found on Sun workstations and
* servers. This driver could actually be made more generic.
*
* This is based on the old drivers/sbus/char/zs.c code. A lot
* of code has been simply moved over directly from there but
* much has been rewritten. Credits therefore go out to Eddie
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there.
*
* Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/circ_buf.h>
#include <linux/serial.h>
#include <linux/sysrq.h>
#include <linux/console.h>
#include <linux/spinlock.h>
#ifdef CONFIG_SERIO
#include <linux/serio.h>
#endif
#include <linux/init.h>
#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#include "suncore.h"
#include "sunzilog.h"
/* On 32-bit sparcs we need to delay after register accesses
* to accommodate sun4 systems, but we do not need to flush writes.
* On 64-bit sparc we only need to flush single writes to ensure
* completion.
*/
#ifndef CONFIG_SPARC64
#define ZSDELAY() udelay(5)
#define ZSDELAY_LONG() udelay(20)
#define ZS_WSYNC(channel) do { } while (0)
#else
#define ZSDELAY()
#define ZSDELAY_LONG()
#define ZS_WSYNC(__channel) \
readb(&((__channel)->control))
#endif
#define ZS_CLOCK 4915200 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
/*
* We wrap our port structure around the generic uart_port.
*/
struct uart_sunzilog_port {
struct uart_port port;
/* IRQ servicing chain. */
struct uart_sunzilog_port *next;
/* Current values of Zilog write registers. */
unsigned char curregs[NUM_ZSREGS];
unsigned int flags;
#define SUNZILOG_FLAG_CONS_KEYB 0x00000001
#define SUNZILOG_FLAG_CONS_MOUSE 0x00000002
#define SUNZILOG_FLAG_IS_CONS 0x00000004
#define SUNZILOG_FLAG_IS_KGDB 0x00000008
#define SUNZILOG_FLAG_MODEM_STATUS 0x00000010
#define SUNZILOG_FLAG_IS_CHANNEL_A 0x00000020
#define SUNZILOG_FLAG_REGS_HELD 0x00000040
#define SUNZILOG_FLAG_TX_STOPPED 0x00000080
#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100
#define SUNZILOG_FLAG_ESCC 0x00000200
#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400
unsigned int cflag;
unsigned char parity_mask;
unsigned char prev_status;
#ifdef CONFIG_SERIO
struct serio serio;
int serio_open;
#endif
};
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase))
#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT))
#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB)
#define ZS_IS_MOUSE(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE)
#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS)
#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB)
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS)
#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A)
#define ZS_REGS_HELD(UP) ((UP)->flags & SUNZILOG_FLAG_REGS_HELD)
#define ZS_TX_STOPPED(UP) ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED)
#define ZS_TX_ACTIVE(UP) ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE)
/* Reading and writing Zilog8530 registers. The delays are to make this
* driver work on the Sun4 which needs a settling delay after each chip
* register access, other machines handle this in hardware via auxiliary
* flip-flops which implement the settle time we do in software.
*
* The port lock must be held and local IRQs must be disabled
* when {read,write}_zsreg is invoked.
*/
static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
unsigned char reg)
{
unsigned char retval;
writeb(reg, &channel->control);
ZSDELAY();
retval = readb(&channel->control);
ZSDELAY();
return retval;
}
static void write_zsreg(struct zilog_channel __iomem *channel,
unsigned char reg, unsigned char value)
{
writeb(reg, &channel->control);
ZSDELAY();
writeb(value, &channel->control);
ZSDELAY();
}
static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
{
int i;
for (i = 0; i < 32; i++) {
unsigned char regval;
regval = readb(&channel->control);
ZSDELAY();
if (regval & Rx_CH_AV)
break;
regval = read_zsreg(channel, R1);
readb(&channel->data);
|