V4L/DVB: tm6000: README - add vbi
[safe/jmp/linux-2.6] / drivers / serial / vr41xx_siu.c
index 1f98532..3beb6ab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for NEC VR4100 series Serial Interface Unit.
  *
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  Based on drivers/serial/8250.c, by Russell King.
  *
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/config.h>
 
 #if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
 
 #include <linux/console.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
+#include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
@@ -42,7 +41,6 @@
 #include <asm/vr41xx/siu.h>
 #include <asm/vr41xx/vr41xx.h>
 
-#define SIU_PORTS_MAX  2
 #define SIU_BAUD_BASE  1152000
 #define SIU_MAJOR      204
 #define SIU_MINOR_BASE 82
  #define IRUSESEL      0x02
  #define SIRSEL                0x01
 
-struct siu_port {
-       unsigned int type;
-       unsigned int irq;
-       unsigned long start;
-};
-
-static const struct siu_port siu_type1_ports[] = {
-       {       .type           = PORT_VR41XX_SIU,
-               .irq            = SIU_IRQ,
-               .start          = 0x0c000000UL,         },
+static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
+       [0 ... SIU_PORTS_MAX-1] = {
+               .lock   = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
+               .irq    = -1,
+       },
 };
 
-#define SIU_TYPE1_NR_PORTS     (sizeof(siu_type1_ports) / sizeof(struct siu_port))
-
-static const struct siu_port siu_type2_ports[] = {
-       {       .type           = PORT_VR41XX_SIU,
-               .irq            = SIU_IRQ,
-               .start          = 0x0f000800UL,         },
-       {       .type           = PORT_VR41XX_DSIU,
-               .irq            = DSIU_IRQ,
-               .start          = 0x0f000820UL,         },
-};
-
-#define SIU_TYPE2_NR_PORTS     (sizeof(siu_type2_ports) / sizeof(struct siu_port))
-
-static struct uart_port siu_uart_ports[SIU_PORTS_MAX];
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
 static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+#endif
 
 #define siu_read(port, offset)         readb((port)->membase + (offset))
 #define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
@@ -110,7 +91,6 @@ void vr41xx_select_siu_interface(siu_interface_t interface)
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
-
 EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
 
 void vr41xx_use_irda(irda_use_t use)
@@ -132,7 +112,6 @@ void vr41xx_use_irda(irda_use_t use)
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
-
 EXPORT_SYMBOL_GPL(vr41xx_use_irda);
 
 void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
@@ -166,7 +145,6 @@ void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
 
        spin_unlock_irqrestore(&port->lock, flags);
 }
-
 EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
 
 static inline void siu_clear_fifo(struct uart_port *port)
@@ -177,21 +155,6 @@ static inline void siu_clear_fifo(struct uart_port *port)
        siu_write(port, UART_FCR, 0);
 }
 
-static inline int siu_probe_ports(void)
-{
-       switch (current_cpu_data.cputype) {
-       case CPU_VR4111:
-       case CPU_VR4121:
-               return SIU_TYPE1_NR_PORTS;
-       case CPU_VR4122:
-       case CPU_VR4131:
-       case CPU_VR4133:
-               return SIU_TYPE2_NR_PORTS;
-       }
-
-       return 0;
-}
-
 static inline unsigned long siu_port_size(struct uart_port *port)
 {
        switch (port->type) {
@@ -206,21 +169,10 @@ static inline unsigned long siu_port_size(struct uart_port *port)
 
 static inline unsigned int siu_check_type(struct uart_port *port)
 {
-       switch (current_cpu_data.cputype) {
-       case CPU_VR4111:
-       case CPU_VR4121:
-               if (port->line == 0)
-                       return PORT_VR41XX_SIU;
-               break;
-       case CPU_VR4122:
-       case CPU_VR4131:
-       case CPU_VR4133:
-               if (port->line == 0)
-                       return PORT_VR41XX_SIU;
-               else if (port->line == 1)
-                       return PORT_VR41XX_DSIU;
-               break;
-       }
+       if (port->line == 0)
+               return PORT_VR41XX_SIU;
+       if (port->line == 1 && port->irq != -1)
+               return PORT_VR41XX_DSIU;
 
        return PORT_UNKNOWN;
 }
@@ -284,7 +236,7 @@ static unsigned int siu_get_mctrl(struct uart_port *port)
        return mctrl;
 }
 
-static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void siu_stop_tx(struct uart_port *port)
 {
        unsigned long flags;
        uint8_t ier;
@@ -298,7 +250,7 @@ static void siu_stop_tx(struct uart_port *port, unsigned int tty_stop)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void siu_start_tx(struct uart_port *port, unsigned int tty_start)
+static void siu_start_tx(struct uart_port *port)
 {
        unsigned long flags;
        uint8_t ier;
@@ -359,23 +311,17 @@ static void siu_break_ctl(struct uart_port *port, int ctl)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static inline void receive_chars(struct uart_port *port, uint8_t *status,
-                                 struct pt_regs *regs)
+static inline void receive_chars(struct uart_port *port, uint8_t *status)
 {
        struct tty_struct *tty;
        uint8_t lsr, ch;
        char flag;
        int max_count = RX_MAX_COUNT;
 
-       tty = port->info->tty;
+       tty = port->state->port.tty;
        lsr = *status;
 
        do {
-               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       if (tty->low_latency)
-                               tty_flip_buffer_push(tty);
-               }
-
                ch = siu_read(port, UART_RX);
                port->icount.rx++;
                flag = TTY_NORMAL;
@@ -410,7 +356,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status,
                                flag = TTY_PARITY;
                }
 
-               if (uart_handle_sysrq_char(port, ch, regs))
+               if (uart_handle_sysrq_char(port, ch))
                        goto ignore_char;
 
                uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
@@ -440,7 +386,7 @@ static inline void check_modem_status(struct uart_port *port)
        if (msr & UART_MSR_DCTS)
                uart_handle_cts_change(port, msr & UART_MSR_CTS);
 
-       wake_up_interruptible(&port->info->delta_msr_wait);
+       wake_up_interruptible(&port->state->port.delta_msr_wait);
 }
 
 static inline void transmit_chars(struct uart_port *port)
@@ -448,7 +394,7 @@ static inline void transmit_chars(struct uart_port *port)
        struct circ_buf *xmit;
        int max_count = TX_MAX_COUNT;
 
-       xmit = &port->info->xmit;
+       xmit = &port->state->xmit;
 
        if (port->x_char) {
                siu_write(port, UART_TX, port->x_char);
@@ -458,7 +404,7 @@ static inline void transmit_chars(struct uart_port *port)
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               siu_stop_tx(port, 0);
+               siu_stop_tx(port);
                return;
        }
 
@@ -474,10 +420,10 @@ static inline void transmit_chars(struct uart_port *port)
                uart_write_wakeup(port);
 
        if (uart_circ_empty(xmit))
-               siu_stop_tx(port, 0);
+               siu_stop_tx(port);
 }
 
-static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t siu_interrupt(int irq, void *dev_id)
 {
        struct uart_port *port;
        uint8_t iir, lsr;
@@ -490,7 +436,7 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        lsr = siu_read(port, UART_LSR);
        if (lsr & UART_LSR_DR)
-               receive_chars(port, &lsr, regs);
+               receive_chars(port, &lsr);
 
        check_modem_status(port);
 
@@ -568,8 +514,8 @@ static void siu_shutdown(struct uart_port *port)
        free_irq(port->irq, port);
 }
 
-static void siu_set_termios(struct uart_port *port, struct termios *new,
-                            struct termios *old)
+static void siu_set_termios(struct uart_port *port, struct ktermios *new,
+                            struct ktermios *old)
 {
        tcflag_t c_cflag, c_iflag;
        uint8_t lcr, fcr, ier;
@@ -757,44 +703,34 @@ static struct uart_ops siu_uart_ops = {
        .verify_port    = siu_verify_port,
 };
 
-static int siu_init_ports(void)
+static int siu_init_ports(struct platform_device *pdev)
 {
-       const struct siu_port *siu;
        struct uart_port *port;
-       int i, num;
+       struct resource *res;
+       int *type = pdev->dev.platform_data;
+       int i;
 
-       switch (current_cpu_data.cputype) {
-       case CPU_VR4111:
-       case CPU_VR4121:
-               siu = siu_type1_ports;
-               break;
-       case CPU_VR4122:
-       case CPU_VR4131:
-       case CPU_VR4133:
-               siu = siu_type2_ports;
-               break;
-       default:
+       if (!type)
                return 0;
-       }
 
        port = siu_uart_ports;
-       num = siu_probe_ports();
-       for (i = 0; i < num; i++) {
-               spin_lock_init(&port->lock);
-               port->irq = siu->irq;
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
+               port->type = type[i];
+               if (port->type == PORT_UNKNOWN)
+                       continue;
+               port->irq = platform_get_irq(pdev, i);
                port->uartclk = SIU_BAUD_BASE * 16;
                port->fifosize = 16;
                port->regshift = 0;
                port->iotype = UPIO_MEM;
                port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
-               port->type = siu->type;
                port->line = i;
-               port->mapbase = siu->start;
-               siu++;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               port->mapbase = res->start;
                port++;
        }
 
-       return num;
+       return i;
 }
 
 #ifdef CONFIG_SERIAL_VR41XX_CONSOLE
@@ -826,31 +762,29 @@ static void wait_for_xmitr(struct uart_port *port)
        }
 }
 
+static void siu_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmitr(port);
+       siu_write(port, UART_TX, ch);
+}
+
 static void siu_console_write(struct console *con, const char *s, unsigned count)
 {
        struct uart_port *port;
        uint8_t ier;
-       unsigned i;
 
        port = &siu_uart_ports[con->index];
 
        ier = siu_read(port, UART_IER);
        siu_write(port, UART_IER, 0);
 
-       for (i = 0; i < count && *s != '\0'; i++, s++) {
-               wait_for_xmitr(port);
-               siu_write(port, UART_TX, *s);
-               if (*s == '\n') {
-                       wait_for_xmitr(port);
-                       siu_write(port, UART_TX, '\r');
-               }
-       }
+       uart_console_write(port, s, count, siu_console_putchar);
 
        wait_for_xmitr(port);
        siu_write(port, UART_IER, ier);
 }
 
-static int siu_console_setup(struct console *con, char *options)
+static int __init siu_console_setup(struct console *con, char *options)
 {
        struct uart_port *port;
        int baud = 9600;
@@ -868,7 +802,8 @@ static int siu_console_setup(struct console *con, char *options)
                port->membase = ioremap(port->mapbase, siu_port_size(port));
        }
 
-       vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+       if (port->type == PORT_VR41XX_SIU)
+               vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
 
        if (options != NULL)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -891,13 +826,9 @@ static struct console siu_console = {
 static int __devinit siu_console_init(void)
 {
        struct uart_port *port;
-       int num, i;
-
-       num = siu_init_ports();
-       if (num <= 0)
-               return -ENODEV;
+       int i;
 
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < SIU_PORTS_MAX; i++) {
                port = &siu_uart_ports[i];
                port->ops = &siu_uart_ops;
        }
@@ -909,6 +840,19 @@ static int __devinit siu_console_init(void)
 
 console_initcall(siu_console_init);
 
+void __init vr41xx_siu_early_setup(struct uart_port *port)
+{
+       if (port->type == PORT_UNKNOWN)
+               return;
+
+       siu_uart_ports[port->line].line = port->line;
+       siu_uart_ports[port->line].type = port->type;
+       siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].mapbase = port->mapbase;
+       siu_uart_ports[port->line].ops = &siu_uart_ops;
+}
+
 #define SERIAL_VR41XX_CONSOLE  &siu_console
 #else
 #define SERIAL_VR41XX_CONSOLE  NULL
@@ -918,18 +862,17 @@ static struct uart_driver siu_uart_driver = {
        .owner          = THIS_MODULE,
        .driver_name    = "SIU",
        .dev_name       = "ttyVR",
-       .devfs_name     = "ttvr/",
        .major          = SIU_MAJOR,
        .minor          = SIU_MINOR_BASE,
        .cons           = SERIAL_VR41XX_CONSOLE,
 };
 
-static int siu_probe(struct device *dev)
+static int __devinit siu_probe(struct platform_device *dev)
 {
        struct uart_port *port;
        int num, i, retval;
 
-       num = siu_init_ports();
+       num = siu_init_ports(dev);
        if (num <= 0)
                return -ENODEV;
 
@@ -941,7 +884,7 @@ static int siu_probe(struct device *dev)
        for (i = 0; i < num; i++) {
                port = &siu_uart_ports[i];
                port->ops = &siu_uart_ops;
-               port->dev = dev;
+               port->dev = &dev->dev;
 
                retval = uart_add_one_port(&siu_uart_driver, port);
                if (retval < 0) {
@@ -958,14 +901,14 @@ static int siu_probe(struct device *dev)
        return 0;
 }
 
-static int siu_remove(struct device *dev)
+static int __devexit siu_remove(struct platform_device *dev)
 {
        struct uart_port *port;
        int i;
 
        for (i = 0; i < siu_uart_driver.nr; i++) {
                port = &siu_uart_ports[i];
-               if (port->dev == dev) {
+               if (port->dev == &dev->dev) {
                        uart_remove_one_port(&siu_uart_driver, port);
                        port->dev = NULL;
                }
@@ -976,18 +919,15 @@ static int siu_remove(struct device *dev)
        return 0;
 }
 
-static int siu_suspend(struct device *dev, pm_message_t state, u32 level)
+static int siu_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct uart_port *port;
        int i;
 
-       if (level != SUSPEND_DISABLE)
-               return 0;
-
        for (i = 0; i < siu_uart_driver.nr; i++) {
                port = &siu_uart_ports[i];
                if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
                        uart_suspend_port(&siu_uart_driver, port);
 
        }
@@ -995,56 +935,44 @@ static int siu_suspend(struct device *dev, pm_message_t state, u32 level)
        return 0;
 }
 
-static int siu_resume(struct device *dev, u32 level)
+static int siu_resume(struct platform_device *dev)
 {
        struct uart_port *port;
        int i;
 
-       if (level != RESUME_ENABLE)
-               return 0;
-
        for (i = 0; i < siu_uart_driver.nr; i++) {
                port = &siu_uart_ports[i];
                if ((port->type == PORT_VR41XX_SIU ||
-                    port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+                    port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
                        uart_resume_port(&siu_uart_driver, port);
        }
 
        return 0;
 }
 
-static struct platform_device *siu_platform_device;
-
-static struct device_driver siu_device_driver = {
-       .name           = "SIU",
-       .bus            = &platform_bus_type,
+static struct platform_driver siu_device_driver = {
        .probe          = siu_probe,
-       .remove         = siu_remove,
+       .remove         = __devexit_p(siu_remove),
        .suspend        = siu_suspend,
        .resume         = siu_resume,
+       .driver         = {
+               .name   = "SIU",
+               .owner  = THIS_MODULE,
+       },
 };
 
-static int __devinit vr41xx_siu_init(void)
+static int __init vr41xx_siu_init(void)
 {
-       int retval;
-
-       siu_platform_device = platform_device_register_simple("SIU", -1, NULL, 0);
-       if (IS_ERR(siu_platform_device))
-               return PTR_ERR(siu_platform_device);
-
-       retval = driver_register(&siu_device_driver);
-       if (retval < 0)
-               platform_device_unregister(siu_platform_device);
-
-       return retval;
+       return platform_driver_register(&siu_device_driver);
 }
 
-static void __devexit vr41xx_siu_exit(void)
+static void __exit vr41xx_siu_exit(void)
 {
-       driver_unregister(&siu_device_driver);
-
-       platform_device_unregister(siu_platform_device);
+       platform_driver_unregister(&siu_device_driver);
 }
 
 module_init(vr41xx_siu_init);
 module_exit(vr41xx_siu_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:SIU");