*/
#include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/serial_reg.h>
#include <linux/circ_buf.h>
-#include <linux/serial.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
+#include <asm/arch/pxa-regs.h>
struct uart_pxa_port {
receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
{
struct tty_struct *tty = up->port.info->tty;
- unsigned char ch;
+ unsigned int ch, flag;
int max_count = 256;
do {
if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+ if (tty->low_latency)
+ tty_flip_buffer_push(tty);
/*
- * FIXME: Deadlock can happen here if we're a
- * low-latency port. We're holding the per-port
- * spinlock, and we call flush_to_ldisc->
- * n_tty_receive_buf->n_tty_receive_char->
- * opost->uart_put_char.
+ * If this failed then we will throw away the
+ * bytes but must do so to clear interrupts
*/
- tty->flip.work.func((void *)tty);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- return; // if TTY_DONT_FLIP is set
}
ch = serial_in(up, UART_RX);
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ flag = TTY_NORMAL;
up->port.icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
}
#endif
if (*status & UART_LSR_BI) {
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (*status & UART_LSR_FE)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0) {
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, ch, flag);
}
if ((*status & UART_LSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
* immediately, and doesn't affect the current
* character.
*/
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char:
*status = serial_in(up, UART_LSR);
if (retval)
return retval;
- CKEN |= up->cken;
- udelay(1);
-
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
-
- CKEN &= ~up->cken;
}
static void
serial_pxa_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- if (state) {
- /* sleep */
- } else {
- /* wake */
- }
+ struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+ pxa_set_cken(up->cken, !state);
+ if (!state)
+ udelay(1);
}
static void serial_pxa_release_port(struct uart_port *port)
.cken = CKEN6_FFUART,
.port = {
.type = PORT_PXA,
- .iotype = SERIAL_IO_MEM,
+ .iotype = UPIO_MEM,
.membase = (void *)&FFUART,
.mapbase = __PREG(FFUART),
.irq = IRQ_FFUART,
.uartclk = 921600 * 16,
.fifosize = 64,
- .flags = ASYNC_SKIP_TEST,
.ops = &serial_pxa_pops,
.line = 0,
},
.cken = CKEN7_BTUART,
.port = {
.type = PORT_PXA,
- .iotype = SERIAL_IO_MEM,
+ .iotype = UPIO_MEM,
.membase = (void *)&BTUART,
.mapbase = __PREG(BTUART),
.irq = IRQ_BTUART,
.uartclk = 921600 * 16,
.fifosize = 64,
- .flags = ASYNC_SKIP_TEST,
.ops = &serial_pxa_pops,
.line = 1,
},
.cken = CKEN5_STUART,
.port = {
.type = PORT_PXA,
- .iotype = SERIAL_IO_MEM,
+ .iotype = UPIO_MEM,
.membase = (void *)&STUART,
.mapbase = __PREG(STUART),
.irq = IRQ_STUART,
.uartclk = 921600 * 16,
.fifosize = 64,
- .flags = ASYNC_SKIP_TEST,
.ops = &serial_pxa_pops,
.line = 2,
},
.cons = PXA_CONSOLE,
};
-static int __init serial_pxa_init(void)
+static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level)
+{
+ struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+ if (sport && level == SUSPEND_DISABLE)
+ uart_suspend_port(&serial_pxa_reg, &sport->port);
+
+ return 0;
+}
+
+static int serial_pxa_resume(struct device *_dev, u32 level)
+{
+ struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+ if (sport && level == RESUME_ENABLE)
+ uart_resume_port(&serial_pxa_reg, &sport->port);
+
+ return 0;
+}
+
+static int serial_pxa_probe(struct device *_dev)
+{
+ struct platform_device *dev = to_platform_device(_dev);
+
+ serial_pxa_ports[dev->id].port.dev = _dev;
+ uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
+ dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);
+ return 0;
+}
+
+static int serial_pxa_remove(struct device *_dev)
+{
+ struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+ dev_set_drvdata(_dev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&serial_pxa_reg, &sport->port);
+
+ return 0;
+}
+
+static struct device_driver serial_pxa_driver = {
+ .name = "pxa2xx-uart",
+ .bus = &platform_bus_type,
+ .probe = serial_pxa_probe,
+ .remove = serial_pxa_remove,
+
+ .suspend = serial_pxa_suspend,
+ .resume = serial_pxa_resume,
+};
+
+int __init serial_pxa_init(void)
{
- int i, ret;
+ int ret;
ret = uart_register_driver(&serial_pxa_reg);
- if (ret)
+ if (ret != 0)
return ret;
- for (i = 0; i < ARRAY_SIZE(serial_pxa_ports); i++)
- uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[i].port);
+ ret = driver_register(&serial_pxa_driver);
+ if (ret != 0)
+ uart_unregister_driver(&serial_pxa_reg);
- return 0;
+ return ret;
}
-static void __exit serial_pxa_exit(void)
+void __exit serial_pxa_exit(void)
{
+ driver_unregister(&serial_pxa_driver);
uart_unregister_driver(&serial_pxa_reg);
}