Commit 5566c10d authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-serial

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 0d61fc5e d6a03f19
...@@ -133,6 +133,7 @@ struct uart_8250_port { ...@@ -133,6 +133,7 @@ struct uart_8250_port {
unsigned char acr; unsigned char acr;
unsigned char ier; unsigned char ier;
unsigned char lcr; unsigned char lcr;
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */ unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */ unsigned char mcr_force; /* mask of forced bits */
unsigned char lsr_break_flag; unsigned char lsr_break_flag;
...@@ -177,11 +178,11 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) ...@@ -177,11 +178,11 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
offset <<= up->port.regshift; offset <<= up->port.regshift;
switch (up->port.iotype) { switch (up->port.iotype) {
case SERIAL_IO_HUB6: case UPIO_HUB6:
outb(up->port.hub6 - 1 + offset, up->port.iobase); outb(up->port.hub6 - 1 + offset, up->port.iobase);
return inb(up->port.iobase + 1); return inb(up->port.iobase + 1);
case SERIAL_IO_MEM: case UPIO_MEM:
return readb(up->port.membase + offset); return readb(up->port.membase + offset);
default: default:
...@@ -195,12 +196,12 @@ serial_out(struct uart_8250_port *up, int offset, int value) ...@@ -195,12 +196,12 @@ serial_out(struct uart_8250_port *up, int offset, int value)
offset <<= up->port.regshift; offset <<= up->port.regshift;
switch (up->port.iotype) { switch (up->port.iotype) {
case SERIAL_IO_HUB6: case UPIO_HUB6:
outb(up->port.hub6 - 1 + offset, up->port.iobase); outb(up->port.hub6 - 1 + offset, up->port.iobase);
outb(value, up->port.iobase + 1); outb(value, up->port.iobase + 1);
break; break;
case SERIAL_IO_MEM: case UPIO_MEM:
writeb(value, up->port.membase + offset); writeb(value, up->port.membase + offset);
break; break;
...@@ -574,7 +575,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) ...@@ -574,7 +575,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
if (!up->port.iobase && !up->port.mapbase && !up->port.membase) if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
return; return;
DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%08lx): ", DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
up->port.line, up->port.iobase, up->port.membase); up->port.line, up->port.iobase, up->port.membase);
/* /*
...@@ -1176,7 +1177,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -1176,7 +1177,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP) if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP; mcr |= UART_MCR_LOOP;
mcr = (mcr & up->mcr_mask) | up->mcr_force; mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
serial_out(up, UART_MCR, mcr); serial_out(up, UART_MCR, mcr);
} }
...@@ -1202,6 +1203,7 @@ static int serial8250_startup(struct uart_port *port) ...@@ -1202,6 +1203,7 @@ static int serial8250_startup(struct uart_port *port)
int retval; int retval;
up->capabilities = uart_config[up->port.type].flags; up->capabilities = uart_config[up->port.type].flags;
up->mcr = 0;
if (up->port.type == PORT_16C950) { if (up->port.type == PORT_16C950) {
/* Wake up and initialize UART */ /* Wake up and initialize UART */
...@@ -1451,8 +1453,19 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1451,8 +1453,19 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
else else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
} }
if (up->port.type == PORT_16750)
/*
* TI16C750: hardware flow control and 64 byte FIFOs. When AFE is
* enabled, RTS will be deasserted when the receive FIFO contains
* more characters than the trigger, or the MCR RTS bit is cleared.
*/
if (up->port.type == PORT_16750) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;
fcr |= UART_FCR7_64BYTE; fcr |= UART_FCR7_64BYTE;
}
/* /*
* Ok, we're now changing the port state. Do it with * Ok, we're now changing the port state. Do it with
...@@ -1514,10 +1527,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1514,10 +1527,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
} else { } else {
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
} }
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
* is written without DLAB set, this mode will be disabled.
*/
if (up->port.type == PORT_16750) if (up->port.type == PORT_16750)
serial_outp(up, UART_FCR, fcr); /* set fcr */ serial_outp(up, UART_FCR, fcr);
serial_outp(up, UART_LCR, cval); /* reset DLAB */ serial_outp(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */ up->lcr = cval; /* Save LCR */
if (up->port.type != PORT_16750) { if (up->port.type != PORT_16750) {
...@@ -1527,6 +1547,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, ...@@ -1527,6 +1547,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
} }
serial_outp(up, UART_FCR, fcr); /* set fcr */ serial_outp(up, UART_FCR, fcr); /* set fcr */
} }
serial8250_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
} }
...@@ -1613,7 +1634,7 @@ serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res ...@@ -1613,7 +1634,7 @@ serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res
int ret = 0; int ret = 0;
switch (up->port.iotype) { switch (up->port.iotype) {
case SERIAL_IO_MEM: case UPIO_MEM:
if (up->port.mapbase) { if (up->port.mapbase) {
*res = request_mem_region(up->port.mapbase, size, "serial"); *res = request_mem_region(up->port.mapbase, size, "serial");
if (!*res) if (!*res)
...@@ -1621,8 +1642,8 @@ serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res ...@@ -1621,8 +1642,8 @@ serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res
} }
break; break;
case SERIAL_IO_HUB6: case UPIO_HUB6:
case SERIAL_IO_PORT: case UPIO_PORT:
*res = request_region(up->port.iobase, size, "serial"); *res = request_region(up->port.iobase, size, "serial");
if (!*res) if (!*res)
ret = -EBUSY; ret = -EBUSY;
...@@ -1639,7 +1660,7 @@ serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res ...@@ -1639,7 +1660,7 @@ serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res
int ret = 0; int ret = 0;
switch (up->port.iotype) { switch (up->port.iotype) {
case SERIAL_IO_MEM: case UPIO_MEM:
if (up->port.mapbase) { if (up->port.mapbase) {
start = up->port.mapbase; start = up->port.mapbase;
start += UART_RSA_BASE << up->port.regshift; start += UART_RSA_BASE << up->port.regshift;
...@@ -1649,8 +1670,8 @@ serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res ...@@ -1649,8 +1670,8 @@ serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res
} }
break; break;
case SERIAL_IO_HUB6: case UPIO_HUB6:
case SERIAL_IO_PORT: case UPIO_PORT:
start = up->port.iobase; start = up->port.iobase;
start += UART_RSA_BASE << up->port.regshift; start += UART_RSA_BASE << up->port.regshift;
*res = request_region(start, size, "serial-rsa"); *res = request_region(start, size, "serial-rsa");
...@@ -1667,6 +1688,8 @@ static void serial8250_release_port(struct uart_port *port) ...@@ -1667,6 +1688,8 @@ static void serial8250_release_port(struct uart_port *port)
struct uart_8250_port *up = (struct uart_8250_port *)port; struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long start, offset = 0, size = 0; unsigned long start, offset = 0, size = 0;
if (!(up->port.flags & UPF_RESOURCES))
return;
if (up->port.type == PORT_RSA) { if (up->port.type == PORT_RSA) {
offset = UART_RSA_BASE << up->port.regshift; offset = UART_RSA_BASE << up->port.regshift;
size = 8; size = 8;
...@@ -1675,7 +1698,7 @@ static void serial8250_release_port(struct uart_port *port) ...@@ -1675,7 +1698,7 @@ static void serial8250_release_port(struct uart_port *port)
size <<= up->port.regshift; size <<= up->port.regshift;
switch (up->port.iotype) { switch (up->port.iotype) {
case SERIAL_IO_MEM: case UPIO_MEM:
if (up->port.mapbase) { if (up->port.mapbase) {
/* /*
* Unmap the area. * Unmap the area.
...@@ -1691,8 +1714,8 @@ static void serial8250_release_port(struct uart_port *port) ...@@ -1691,8 +1714,8 @@ static void serial8250_release_port(struct uart_port *port)
} }
break; break;
case SERIAL_IO_HUB6: case UPIO_HUB6:
case SERIAL_IO_PORT: case UPIO_PORT:
start = up->port.iobase; start = up->port.iobase;
if (size) if (size)
......
...@@ -17,15 +17,6 @@ ...@@ -17,15 +17,6 @@
#include <linux/config.h> #include <linux/config.h>
struct serial8250_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 serial8250_register_probe(struct serial8250_probe *probe);
void serial8250_unregister_probe(struct serial8250_probe *probe);
void serial8250_get_irq_map(unsigned int *map); void serial8250_get_irq_map(unsigned int *map);
void serial8250_suspend_port(int line); void serial8250_suspend_port(int line);
void serial8250_resume_port(int line); void serial8250_resume_port(int line);
......
...@@ -186,6 +186,8 @@ setup_serial_hcdp(void *tablep) ...@@ -186,6 +186,8 @@ setup_serial_hcdp(void *tablep)
port.irq = gsi; port.irq = gsi;
#endif #endif
port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES; port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES;
if (gsi)
port.flags |= UPF_AUTO_IRQ;
/* /*
* Note: the above memset() initializes port.line to 0, * Note: the above memset() initializes port.line to 0,
......
...@@ -224,6 +224,37 @@ config SERIAL_CLPS711X_CONSOLE ...@@ -224,6 +224,37 @@ config SERIAL_CLPS711X_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.) kernel at boot time.)
config SERIAL_S3C2410
tristate "Samsung S3C2410 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C2410X CPU,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
help
Allow selection of the S3C2410 on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySACx". (Try "man bootparam" or see the documentation of
your boot loader about how to pass options to the kernel at
boot time.)
config SERIAL_BAST_SIO
bool "Support for BAST SuperIO serial ports"
depends on ARCH_BAST && SERIAL_8250=y
help
Support for registerin the SuperIO chip on BAST board with
the 8250/16550 uart code.
config SERIAL_DZ config SERIAL_DZ
bool "DECstation DZ serial driver" bool "DECstation DZ serial driver"
depends on DECSTATION depends on DECSTATION
......
...@@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_AMBA) += amba.o ...@@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_AMBA) += amba.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_UART00) += uart00.o obj-$(CONFIG_SERIAL_UART00) += uart00.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
...@@ -36,3 +37,4 @@ obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o ...@@ -36,3 +37,4 @@ obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_BAST_SIO) += bast_sio.o
#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/serial.h>
#include <asm/mach-types.h>
#include <asm/arch/map.h>
#include <asm/arch/irqs.h>
#include <asm/arch/bast-map.h>
#include <asm/arch/bast-irq.h>
static int __init serial_bast_register(unsigned long port, unsigned int irq)
{
struct serial_struct serial_req;
#if 0
printk("BAST: SuperIO serial (%08lx,%d)\n", port, irq);
#endif
serial_req.flags = UPF_AUTOPROBE | UPF_RESOURCES | UPF_SHARE_IRQ;
serial_req.baud_base = BASE_BAUD;
serial_req.irq = irq;
serial_req.io_type = UPIO_MEM;
serial_req.iomap_base = port;
serial_req.iomem_base = ioremap(port, 0x10);
serial_req.iomem_reg_shift = 0;
return register_serial(&serial_req);
}
#define SERIAL_BASE (S3C2410_CS2 + BAST_PA_SUPERIO)
static int __init serial_bast_init(void)
{
if (machine_is_bast()) {
serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1);
serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2);
}
return 0;
}
static void __exit serial_bast_exit(void)
{
/* todo -> remove both our ports */
}
module_init(serial_bast_init);
module_exit(serial_bast_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks, ben@simtec.co.uk");
MODULE_DESCRIPTION("BAST Onboard Serial setup");
/*
* linux/drivers/char/s3c2410.c
*
* Driver for onboard UARTs on the Samsung S3C2410
*
* Based on drivers/char/serial.c and drivers/char/21285.c
*
* Ben Dooks, (c) 2003 Simtec Electronics
*
* Changelog:
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/arch/regs-serial.h>
#include <asm/mach-types.h>
#if 0
#include <asm/debug-ll.h>
#define dbg(x...) llprintk(x)
#else
#define dbg(x...)
#endif
#define SERIAL_S3C2410_NAME "ttySAC"
#define SERIAL_S3C2410_MAJOR 204
#define SERIAL_S3C2410_MINOR 4
/* we can support 3 uarts, but not always use them */
#define NR_PORTS (3)
static const char serial_s3c2410_name[] = "Samsung S3C2410 UART";
/* port irq numbers */
#define TX_IRQ(port) ((port)->irq + 1)
#define RX_IRQ(port) ((port)->irq)
#define tx_enabled(port) ((port)->unused[0])
#define rx_enabled(port) ((port)->unused[1])
/* flag to ignore all characters comming in */
#define RXSTAT_DUMMY_READ (0x10000000)
/* access functions */
#define portaddr(port, reg) ((void *)((port)->membase + (reg)))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
#define wr_regb(port, reg, val) \
do { __raw_writeb(val, portaddr(port, reg)); } while(0)
#define wr_regl(port, reg, val) \
do { __raw_writel(val, portaddr(port, reg)); } while(0)
/* code */
static void
serial_s3c2410_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
if (tx_enabled(port)) {
disable_irq(TX_IRQ(port));
tx_enabled(port) = 0;
}
}
static void
serial_s3c2410_start_tx(struct uart_port *port, unsigned int tty_start)
{
if (!tx_enabled(port)) {
enable_irq(TX_IRQ(port));
tx_enabled(port) = 1;
}
}
static void serial_s3c2410_stop_rx(struct uart_port *port)
{
if (rx_enabled(port)) {
dbg("serial_s3c2410_stop_rx: port=%p\n", port);
disable_irq(RX_IRQ(port));
rx_enabled(port) = 0;
}
}
static void serial_s3c2410_enable_ms(struct uart_port *port)
{
}
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
static irqreturn_t
serial_s3c2410_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = port->info->tty;
unsigned int ufcon, ch, rxs, ufstat;
int max_count = 256;
while (max_count-- > 0) {
ufcon = rd_regl(port, S3C2410_UFCON);
ufstat = rd_regl(port, S3C2410_UFSTAT);
if (S3C2410_UFCON_RXC(ufstat) == 0)
break;
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty->flip.work.func((void *)tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
printk(KERN_WARNING "TTY_DONT_FLIP set\n");
goto out;
}
}
ch = rd_regb(port, S3C2410_URXH);
*tty->flip.char_buf_ptr = ch;
*tty->flip.flag_buf_ptr = TTY_NORMAL;
port->icount.rx++;
rxs = rd_regb(port, S3C2410_UERSTAT) | RXSTAT_DUMMY_READ;
if (rxs & S3C2410_UERSTAT_ANY) {
if (rxs & S3C2410_UERSTAT_FRAME)
port->icount.frame++;
if (rxs & S3C2410_UERSTAT_OVERRUN)
port->icount.overrun++;
rxs &= port->read_status_mask;
if (rxs & S3C2410_UERSTAT_PARITY)
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (rxs & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
*tty->flip.flag_buf_ptr = TTY_FRAME;
}
if ((rxs & port->ignore_status_mask) == 0) {
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
}
if ((rxs & S3C2410_UERSTAT_OVERRUN) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
*tty->flip.char_buf_ptr++ = 0;
*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
tty->flip.count++;
}
}
tty_flip_buffer_push(tty);
out:
return IRQ_HANDLED;
}
static irqreturn_t
serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = (struct uart_port *)dev_id;
struct circ_buf *xmit = &port->info->xmit;
int count = 256;
if (port->x_char) {
wr_regb(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
port->x_char = 0;
goto out;
}
/* if there isnt anything more to transmit, or the uart is now
* stopped, disable the uart and exit
*/
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
serial_s3c2410_stop_tx(port, 0);
goto out;
}
/* try and drain the buffer... */
while (!uart_circ_empty(xmit) && count-- > 0) {
if (rd_regl(port, S3C2410_UFSTAT) & S3C2410_UFSTAT_TXFULL)
break;
wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
serial_s3c2410_stop_tx(port, 0);
out:
return IRQ_HANDLED;
}
static unsigned int
serial_s3c2410_tx_empty(struct uart_port *port)
{
unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
return (S3C2410_UFCON_TXC(ufcon) != 0) ? 0 : TIOCSER_TEMT;
}
/* no modem control lines */
static unsigned int
serial_s3c2410_get_mctrl(struct uart_port *port)
{
unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);
if (umstat & S3C2410_UMSTAT_CTS)
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
else
return TIOCM_CAR | TIOCM_DSR;
}
static void
serial_s3c2410_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* todo - possibly remove AFC and do manual CTS */
}
static void serial_s3c2410_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int ucon;
spin_lock_irqsave(&port->lock, flags);
ucon = rd_regl(port, S3C2410_UCON);
if (break_state)
ucon |= S3C2410_UCON_SBREAK;
else
ucon &= ~S3C2410_UCON_SBREAK;
wr_regl(port, S3C2410_UCON, ucon);
spin_unlock_irqrestore(&port->lock, flags);
}
static int serial_s3c2410_startup(struct uart_port *port)
{
int ret;
tx_enabled(port) = 1;
rx_enabled(port) = 1;
dbg("serial_s3c2410_startup: port=%p (%p)\n",
port, port->mapbase);
ret = request_irq(RX_IRQ(port), serial_s3c2410_rx_chars, 0,
serial_s3c2410_name, port);
if (ret != 0)
return ret;
ret = request_irq(TX_IRQ(port), serial_s3c2410_tx_chars, 0,
serial_s3c2410_name, port);
if (ret) {
free_irq(RX_IRQ(port), port);
return ret;
}
/* the port reset code should have done the correct
* register setup for the port controls */
return ret;
}
static void serial_s3c2410_shutdown(struct uart_port *port)
{
free_irq(TX_IRQ(port), port);
free_irq(RX_IRQ(port), port);
}
static void
serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int baud, quot;
unsigned int ulcon;
/*
* We don't support modem control lines.
*/
termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
termios->c_cflag |= CLOCAL;
/*
* We don't support BREAK character recognition.
*/
termios->c_iflag &= ~(IGNBRK | BRKINT);
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
dbg("config: 5bits/char\n");
ulcon = S3C2410_LCON_CS5;
break;
case CS6:
dbg("config: 6bits/char\n");
ulcon = S3C2410_LCON_CS6;
break;
case CS7:
dbg("config: 7bits/char\n");
ulcon = S3C2410_LCON_CS7;
break;
case CS8:
default:
dbg("config: 8bits/char\n");
ulcon = S3C2410_LCON_CS8;
break;
}
if (termios->c_cflag & CSTOPB)
ulcon |= S3C2410_LCON_STOPB;
if (termios->c_cflag & PARENB) {
if (!(termios->c_cflag & PARODD))
ulcon |= S3C2410_LCON_PODD;
else
ulcon |= S3C2410_LCON_PEVEN;
} else {
ulcon |= S3C2410_LCON_PNONE;
}
/*
if (port->fifosize)
enable_fifo()
*/
spin_lock_irqsave(&port->lock, flags);
dbg("setting ulcon to %08x\n", ulcon);
//dbg("<flushing output from serial>\n");
/* set the ulcon register */
wr_regl(port, S3C2410_ULCON, ulcon);
dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
rd_regl(port, S3C2410_ULCON),
rd_regl(port, S3C2410_UCON),
rd_regl(port, S3C2410_UFCON));
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/*
* Which character status flags are we interested in?
*/
port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
if (termios->c_iflag & INPCK)
port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
/*
* Which character status flags should we ignore?
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
/*
* Ignore all characters if CREAD is not set.
*/
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *serial_s3c2410_type(struct uart_port *port)
{
return port->type == PORT_S3C2410 ? "S3C2410" : NULL;
}
#define MAP_SIZE (0x100)
static void
serial_s3c2410_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, MAP_SIZE);
}
static int
serial_s3c2410_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, MAP_SIZE, serial_s3c2410_name)
!= NULL ? 0 : -EBUSY;
}
static void
serial_s3c2410_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE &&
serial_s3c2410_request_port(port) == 0)
port->type = PORT_S3C2410;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int
serial_s3c2410_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_S3C2410)
ret = -EINVAL;
return ret;
}
static struct uart_ops serial_s3c2410_ops = {
.tx_empty = serial_s3c2410_tx_empty,
.get_mctrl = serial_s3c2410_get_mctrl,
.set_mctrl = serial_s3c2410_set_mctrl,
.stop_tx = serial_s3c2410_stop_tx,
.start_tx = serial_s3c2410_start_tx,
.stop_rx = serial_s3c2410_stop_rx,
.enable_ms = serial_s3c2410_enable_ms,
.break_ctl = serial_s3c2410_break_ctl,
.startup = serial_s3c2410_startup,
.shutdown = serial_s3c2410_shutdown,
.set_termios = serial_s3c2410_set_termios,
.type = serial_s3c2410_type,
.release_port = serial_s3c2410_release_port,
.request_port = serial_s3c2410_request_port,
.config_port = serial_s3c2410_config_port,
.verify_port = serial_s3c2410_verify_port,
};
static struct uart_port serial_s3c2410_ports[NR_PORTS] = {
{
.membase = 0,
.mapbase = 0,
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = 0,
.fifosize = 16,
.ops = &serial_s3c2410_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
{
.membase = 0,
.mapbase = 0,
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &serial_s3c2410_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
}
#if NR_PORTS > 2
,
{
.membase = 0,
.mapbase = 0,
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
.fifosize = 16,
.ops = &serial_s3c2410_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
}
#endif
};
static int
serial_s3c2410_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
/* ensure registers are setup */
dbg("serial_s3c2410_resetport: port=%p (%08x), cfg=%p\n",
port, port->mapbase, cfg);
wr_regl(port, S3C2410_UCON, cfg->ucon);
wr_regl(port, S3C2410_ULCON, cfg->ulcon);
/* reset both fifos */
wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
wr_regl(port, S3C2410_UFCON, cfg->ufcon);
return 0;
}
/* serial_s3c2410_init_ports
*
* initialise the serial ports from the machine provided initialisation
* data.
*/
static int serial_s3c2410_init_ports(void)
{
struct uart_port *ptr = serial_s3c2410_ports;
struct s3c2410_uartcfg *cfg = s3c2410_uartcfgs;
static int inited = 0;
int i;
if (inited)
return 0;
inited = 1;
dbg("serial_s3c2410_init_ports: initialising ports...\n");
for (i = 0; i < NR_PORTS; i++, ptr++, cfg++) {
if (cfg->hwport > 3)
continue;
dbg("serial_s3c2410_init_ports: port %d (hw %d)...\n",
i, cfg->hwport);
if (cfg->clock != NULL)
ptr->uartclk = *cfg->clock;
switch (cfg->hwport) {
case 0:
ptr->mapbase = S3C2410_PA_UART0;
ptr->membase = (char *)S3C2410_VA_UART0;
ptr->irq = IRQ_S3CUART_RX0;
break;
case 1:
ptr->mapbase = S3C2410_PA_UART1;
ptr->membase = (char *)S3C2410_VA_UART1;
ptr->irq = IRQ_S3CUART_RX1;
break;
case 2:
ptr->mapbase = S3C2410_PA_UART2;
ptr->membase = (char *)S3C2410_VA_UART2;
ptr->irq = IRQ_S3CUART_RX2;
break;
}
if (ptr->mapbase == 0)
continue;
/* reset the fifos (and setup the uart */
serial_s3c2410_resetport(ptr, cfg);
}
return 0;
}
#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
static struct uart_port *cons_uart;
static int
serial_s3c2410_console_txrdy(struct uart_port *port, unsigned int ufcon)
{
unsigned long ufstat, utrstat;
if (ufcon & S3C2410_UFCON_FIFOMODE) {
/* fifo mode - check ammount of data in fifo registers... */
ufstat = rd_regl(port, S3C2410_UFSTAT);
return S3C2410_UFCON_TXC(ufstat) < 12;
}
/* in non-fifo mode, we go and use the tx buffer empty */
utrstat = rd_regl(port, S3C2410_UTRSTAT);
return (utrstat & S3C2410_UTRSTAT_TXFE) ? 1 : 0;
}
static void
serial_s3c2410_console_write(struct console *co, const char *s,
unsigned int count)
{
int i;
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
for (i = 0; i < count; i++) {
while (!serial_s3c2410_console_txrdy(cons_uart, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, s[i]);
if (s[i] == '\n') {
while (!serial_s3c2410_console_txrdy(cons_uart, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, '\r');
}
}
}
static void __init
serial_s3c2410_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
unsigned int ulcon, ucon, ubrdiv;
ulcon = rd_regl(port, S3C2410_ULCON);
ucon = rd_regl(port, S3C2410_UCON);
ubrdiv = rd_regl(port, S3C2410_UBRDIV);
dbg("serial_s3c2410_get_options: port=%p\n"
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
port, ulcon, ucon, ubrdiv);
if ((ucon & 0xf) != 0) {
/* consider the serial port configured if the tx/rx mode set */
switch (ulcon & S3C2410_LCON_CSMASK) {
case S3C2410_LCON_CS5:
*bits = 5;
break;
case S3C2410_LCON_CS6:
*bits = 6;
break;
case S3C2410_LCON_CS7:
*bits = 7;
break;
default:
case S3C2410_LCON_CS8:
*bits = 8;
break;
}
switch (ulcon & S3C2410_LCON_PMASK) {
case S3C2410_LCON_PEVEN:
*parity = 'e';
break;
case S3C2410_LCON_PODD:
*parity = 'o';
break;
default:
case S3C2410_LCON_PNONE:
/* nothing */
}
/* now calculate the baud rate */
*baud = port->uartclk / ( 16 * (ubrdiv + 1));
dbg("calculated baud %d\n", *baud);
}
}
static int __init
serial_s3c2410_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
/* is this a valid port */
if (co->index == -1 || co->index >= NR_PORTS)
co->index = 0;
port = &serial_s3c2410_ports[co->index];
/* is the port configured? */
if (port->mapbase == 0x0) {
co->index = 0;
port = &serial_s3c2410_ports[co->index];
}
cons_uart = port;
dbg("serial_s3c2410_console_setup: port=%p (%d)\n", port, co->index);
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
serial_s3c2410_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver s3c2410_uart_drv;
static struct console serial_s3c2410_console =
{
.name = SERIAL_S3C2410_NAME,
.write = serial_s3c2410_console_write,
.device = uart_console_device,
.setup = serial_s3c2410_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &s3c2410_uart_drv,
};
static int __init s3c2410_console_init(void)
{
dbg("s3c2410_console_init:\n");
serial_s3c2410_init_ports();
register_console(&serial_s3c2410_console);
return 0;
}
console_initcall(s3c2410_console_init);
#define SERIAL_S3C2410_CONSOLE &serial_s3c2410_console
#else
#define SERIAL_S3C2410_CONSOLE NULL
#endif
static struct uart_driver s3c2410_uart_drv = {
.owner = THIS_MODULE,
.driver_name = SERIAL_S3C2410_NAME,
.dev_name = SERIAL_S3C2410_NAME,
.major = SERIAL_S3C2410_MAJOR,
.minor = SERIAL_S3C2410_MINOR,
.nr = 3,
.cons = SERIAL_S3C2410_CONSOLE,
};
/* device driver */
static int s3c2410_serial_probe(struct device *_dev);
static int s3c2410_serial_remove(struct device *_dev);
static struct device_driver s3c2410_serial_drv = {
.name = "s3c2410-uart",
.bus = &platform_bus_type,
.probe = s3c2410_serial_probe,
.remove = s3c2410_serial_remove,
.suspend = NULL,
.resume = NULL,
};
#define s3c2410_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
static int s3c2410_serial_probe(struct device *_dev)
{
struct platform_device *dev = to_platform_device(_dev);
struct resource *res = dev->resource;
int i;
dbg("s3c2410_serial_probe: dev=%p, _dev=%p, res=%p\n", _dev, dev, res);
for (i = 0; i < dev->num_resources; i++, res++)
if (res->flags & IORESOURCE_MEM)
break;
if (i < dev->num_resources) {
struct uart_port *ptr = serial_s3c2410_ports;
for (i = 0; i < NR_PORTS; i++, ptr++) {
dbg("s3c2410_serial_probe: ptr=%p (%08x, %08x)\n",
ptr, ptr->mapbase, ptr->membase);
if (ptr->mapbase != res->start)
continue;
dbg("s3c2410_serial_probe: got device %p: port=%p\n",
_dev, ptr);
uart_add_one_port(&s3c2410_uart_drv, ptr);
dev_set_drvdata(_dev, ptr);
break;
}
}
return 0;
}
static int s3c2410_serial_remove(struct device *_dev)
{
struct uart_port *port = s3c2410_dev_to_port(_dev);
if (port)
uart_remove_one_port(&s3c2410_uart_drv, port);
return 0;
}
static int __init serial_s3c2410_init(void)
{
int ret;
printk(KERN_INFO "S3C2410X Serial, (c) 2003 Simtec Electronics\n");
ret = uart_register_driver(&s3c2410_uart_drv);
if (ret != 0)
return ret;
ret = driver_register(&s3c2410_serial_drv);
if (ret) {
uart_unregister_driver(&s3c2410_uart_drv);
}
return ret;
}
static void __exit serial_s3c2410_exit(void)
{
driver_unregister(&s3c2410_serial_drv);
uart_unregister_driver(&s3c2410_uart_drv);
}
module_init(serial_s3c2410_init);
module_exit(serial_s3c2410_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C2410X (S3C2410) Serial driver");
...@@ -894,6 +894,7 @@ static int sa1100_serial_probe(struct device *_dev) ...@@ -894,6 +894,7 @@ static int sa1100_serial_probe(struct device *_dev)
if (sa1100_ports[i].port.mapbase != res->start) if (sa1100_ports[i].port.mapbase != res->start)
continue; continue;
sa1100_ports[i].port.dev = _dev;
uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
dev_set_drvdata(_dev, &sa1100_ports[i]); dev_set_drvdata(_dev, &sa1100_ports[i]);
break; break;
......
...@@ -2227,7 +2227,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) ...@@ -2227,7 +2227,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
* Register the port whether it's detected or not. This allows * Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters. * setserial to be used to alter this ports parameters.
*/ */
tty_register_device(drv->tty_driver, port->line, NULL); tty_register_device(drv->tty_driver, port->line, port->dev);
out: out:
up(&port_sem); up(&port_sem);
......
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
#include <pcmcia/ds.h> #include <pcmcia/ds.h>
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include "8250.h"
#ifdef PCMCIA_DEBUG #ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG; static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i"); MODULE_PARM(pc_debug, "i");
...@@ -158,6 +160,38 @@ static void serial_remove(dev_link_t *link) ...@@ -158,6 +160,38 @@ static void serial_remove(dev_link_t *link)
} }
} }
static void serial_suspend(dev_link_t *link)
{
link->state |= DEV_SUSPEND;
if (link->state & DEV_CONFIG) {
struct serial_info *info = link->priv;
int i;
for (i = 0; i < info->ndev; i++)
serial8250_suspend_port(info->line[i]);
if (!info->slave)
pcmcia_release_configuration(link->handle);
}
}
static void serial_resume(dev_link_t *link)
{
link->state &= ~DEV_SUSPEND;
if (DEV_OK(link)) {
struct serial_info *info = link->priv;
int i;
if (!info->slave)
pcmcia_request_configuration(link->handle, &link->conf);
for (i = 0; i < info->ndev; i++)
serial8250_resume_port(info->line[i]);
}
}
/*====================================================================== /*======================================================================
serial_attach() creates an "instance" of the driver, allocating serial_attach() creates an "instance" of the driver, allocating
...@@ -674,16 +708,18 @@ serial_event(event_t event, int priority, event_callback_args_t * args) ...@@ -674,16 +708,18 @@ serial_event(event_t event, int priority, event_callback_args_t * args)
break; break;
case CS_EVENT_PM_SUSPEND: case CS_EVENT_PM_SUSPEND:
link->state |= DEV_SUSPEND; serial_suspend(link);
/* Fall through... */ break;
case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_RESET_PHYSICAL:
if ((link->state & DEV_CONFIG) && !info->slave) if ((link->state & DEV_CONFIG) && !info->slave)
pcmcia_release_configuration(link->handle); pcmcia_release_configuration(link->handle);
break; break;
case CS_EVENT_PM_RESUME: case CS_EVENT_PM_RESUME:
link->state &= ~DEV_SUSPEND; serial_resume(link);
/* Fall through... */ break;
case CS_EVENT_CARD_RESET: case CS_EVENT_CARD_RESET:
if (DEV_OK(link) && !info->slave) if (DEV_OK(link) && !info->slave)
pcmcia_request_configuration(link->handle, &link->conf); pcmcia_request_configuration(link->handle, &link->conf);
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: serial_core.h,v 1.49 2002/07/20 18:06:32 rmk Exp $
*/ */
/* /*
...@@ -83,6 +81,9 @@ ...@@ -83,6 +81,9 @@
#define PORT_SCIF 53 #define PORT_SCIF 53
#define PORT_IRDA 54 #define PORT_IRDA 54
/* Samsung S3C2410 SoC and derivatives thereof */
#define PORT_S3C2410 55
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/config.h> #include <linux/config.h>
...@@ -94,6 +95,7 @@ ...@@ -94,6 +95,7 @@
struct uart_port; struct uart_port;
struct uart_info; struct uart_info;
struct serial_struct; struct serial_struct;
struct device;
/* /*
* This structure describes all the operations that can be * This structure describes all the operations that can be
...@@ -182,7 +184,6 @@ struct uart_port { ...@@ -182,7 +184,6 @@ struct uart_port {
unsigned int flags; unsigned int flags;
#define UPF_HUP_NOTIFY (1 << 0)
#define UPF_FOURPORT (1 << 1) #define UPF_FOURPORT (1 << 1)
#define UPF_SAK (1 << 2) #define UPF_SAK (1 << 2)
#define UPF_SPD_MASK (0x1030) #define UPF_SPD_MASK (0x1030)
...@@ -215,6 +216,7 @@ struct uart_port { ...@@ -215,6 +216,7 @@ struct uart_port {
unsigned int custom_divisor; unsigned int custom_divisor;
unsigned int line; /* port index */ unsigned int line; /* port index */
unsigned long mapbase; /* for ioremap */ unsigned long mapbase; /* for ioremap */
struct device *dev; /* parent device */
unsigned char hub6; /* this should be in the 8250 driver */ unsigned char hub6; /* this should be in the 8250 driver */
unsigned char unused[3]; unsigned char unused[3];
}; };
......
...@@ -121,6 +121,7 @@ ...@@ -121,6 +121,7 @@
/* /*
* These are the definitions for the Modem Control Register * These are the definitions for the Modem Control Register
*/ */
#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */ #define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */ #define UART_MCR_OUT1 0x04 /* Out1 complement */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment