Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / serial / sunzilog.c
index a1456d9..75de919 100644 (file)
@@ -68,9 +68,6 @@ static int num_sunzilog;
 #define NUM_SUNZILOG   num_sunzilog
 #define NUM_CHANNELS   (NUM_SUNZILOG * 2)
 
-#define KEYBOARD_LINE 0x2
-#define MOUSE_LINE    0x3
-
 #define ZS_CLOCK               4915200 /* Zilog input clock rate. */
 #define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
 
@@ -280,14 +277,13 @@ static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
 }
 
 static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
-                                        unsigned char ch, int is_break,
-                                        struct pt_regs *regs)
+                                        unsigned char ch, int is_break)
 {
        if (ZS_IS_KEYB(up)) {
                /* Stop-A is handled by drivers/char/keyboard.c now. */
 #ifdef CONFIG_SERIO
                if (up->serio_open)
-                       serio_interrupt(&up->serio, ch, 0, regs);
+                       serio_interrupt(&up->serio, ch, 0);
 #endif
        } else if (ZS_IS_MOUSE(up)) {
                int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -302,7 +298,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
                case 0:
 #ifdef CONFIG_SERIO
                        if (up->serio_open)
-                               serio_interrupt(&up->serio, ch, 0, regs);
+                               serio_interrupt(&up->serio, ch, 0);
 #endif
                        break;
                };
@@ -311,8 +307,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
 
 static struct tty_struct *
 sunzilog_receive_chars(struct uart_sunzilog_port *up,
-                      struct zilog_channel __iomem *channel,
-                      struct pt_regs *regs)
+                      struct zilog_channel __iomem *channel)
 {
        struct tty_struct *tty;
        unsigned char ch, r1, flag;
@@ -349,12 +344,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
                ch &= up->parity_mask;
 
                if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
-                       sunzilog_kbdms_receive_chars(up, ch, 0, regs);
+                       sunzilog_kbdms_receive_chars(up, ch, 0);
                        continue;
                }
 
                if (tty == NULL) {
-                       uart_handle_sysrq_char(&up->port, ch, regs);
+                       uart_handle_sysrq_char(&up->port, ch);
                        continue;
                }
 
@@ -382,7 +377,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
                        else if (r1 & CRC_ERR)
                                flag = TTY_FRAME;
                }
-               if (uart_handle_sysrq_char(&up->port, ch, regs))
+               if (uart_handle_sysrq_char(&up->port, ch))
                        continue;
 
                if (up->port.ignore_status_mask == 0xff ||
@@ -397,8 +392,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
 }
 
 static void sunzilog_status_handle(struct uart_sunzilog_port *up,
-                                  struct zilog_channel __iomem *channel,
-                                  struct pt_regs *regs)
+                                  struct zilog_channel __iomem *channel)
 {
        unsigned char status;
 
@@ -411,7 +405,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
 
        if (status & BRK_ABRT) {
                if (ZS_IS_MOUSE(up))
-                       sunzilog_kbdms_receive_chars(up, 0, 1, regs);
+                       sunzilog_kbdms_receive_chars(up, 0, 1);
                if (ZS_IS_CONS(up)) {
                        /* Wait for BREAK to deassert to avoid potentially
                         * confusing the PROM.
@@ -520,7 +514,7 @@ ack_tx_int:
        ZS_WSYNC(channel);
 }
 
-static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
 {
        struct uart_sunzilog_port *up = dev_id;
 
@@ -541,9 +535,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
                        ZS_WSYNC(channel);
 
                        if (r3 & CHARxIP)
-                               tty = sunzilog_receive_chars(up, channel, regs);
+                               tty = sunzilog_receive_chars(up, channel);
                        if (r3 & CHAEXT)
-                               sunzilog_status_handle(up, channel, regs);
+                               sunzilog_status_handle(up, channel);
                        if (r3 & CHATxIP)
                                sunzilog_transmit_chars(up, channel);
                }
@@ -564,9 +558,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
                        ZS_WSYNC(channel);
 
                        if (r3 & CHBRxIP)
-                               tty = sunzilog_receive_chars(up, channel, regs);
+                               tty = sunzilog_receive_chars(up, channel);
                        if (r3 & CHBEXT)
-                               sunzilog_status_handle(up, channel, regs);
+                               sunzilog_status_handle(up, channel);
                        if (r3 & CHBTxIP)
                                sunzilog_transmit_chars(up, channel);
                }
@@ -928,8 +922,8 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
 
 /* The port lock is not held.  */
 static void
-sunzilog_set_termios(struct uart_port *port, struct termios *termios,
-                    struct termios *old)
+sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
 {
        struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
        unsigned long flags;
@@ -1063,7 +1057,7 @@ static void sunzilog_free_tables(void)
 
 static void sunzilog_putchar(struct uart_port *port, int ch)
 {
-       struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+       struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
        int loops = ZS_PUT_CHAR_MAX_DELAY;
 
        /* This is a timed polling loop so do not switch the explicit
@@ -1149,6 +1143,9 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
        unsigned long flags;
        int baud, brg;
 
+       if (up->port.type != PORT_SUNZILOG)
+               return -1;
+
        printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
               (sunzilog_reg.minor - 64) + con->index, con->index);
 
@@ -1185,7 +1182,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
        return 0;
 }
 
-static struct console sunzilog_console = {
+static struct console sunzilog_console_ops = {
        .name   =       "ttyS",
        .write  =       sunzilog_console_write,
        .device =       uart_console_device,
@@ -1211,10 +1208,10 @@ static inline struct console *SUNZILOG_CONSOLE(void)
        if (i == NUM_CHANNELS)
                return NULL;
 
-       sunzilog_console.index = i;
+       sunzilog_console_ops.index = i;
        sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
 
-       return &sunzilog_console;
+       return &sunzilog_console_ops;
 }
 
 #else
@@ -1225,12 +1222,10 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
 {
        int baud, brg;
 
-       if (channel == KEYBOARD_LINE) {
-               up->flags |= SUNZILOG_FLAG_CONS_KEYB;
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
                up->cflag = B1200 | CS8 | CLOCAL | CREAD;
                baud = 1200;
        } else {
-               up->flags |= SUNZILOG_FLAG_CONS_MOUSE;
                up->cflag = B4800 | CS8 | CLOCAL | CREAD;
                baud = 4800;
        }
@@ -1243,14 +1238,14 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
 }
 
 #ifdef CONFIG_SERIO
-static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel)
+static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
 {
        struct serio *serio = &up->serio;
 
        serio->port_data = up;
 
        serio->id.type = SERIO_RS232;
-       if (channel == KEYBOARD_LINE) {
+       if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
                serio->id.proto = SERIO_SUNKBD;
                strlcpy(serio->name, "zskbd", sizeof(serio->name));
        } else {
@@ -1259,7 +1254,8 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int ch
                strlcpy(serio->name, "zsms", sizeof(serio->name));
        }
        strlcpy(serio->phys,
-               (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"),
+               ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
+                "zs/serio0" : "zs/serio1"),
                sizeof(serio->phys));
 
        serio->write = sunzilog_serio_write;
@@ -1271,7 +1267,7 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int ch
 }
 #endif
 
-static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
+static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 {
        struct zilog_channel __iomem *channel;
        unsigned long flags;
@@ -1286,8 +1282,8 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
                (void) read_zsreg(channel, R0);
        }
 
-       if (up->port.line == KEYBOARD_LINE ||
-           up->port.line == MOUSE_LINE) {
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE)) {
                sunzilog_init_kbdms(up, up->port.line);
                up->curregs[R9] |= (NV | MIE);
                write_zsreg(channel, R9, up->curregs[R9]);
@@ -1313,37 +1309,26 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
        spin_unlock_irqrestore(&up->port.lock, flags);
 
 #ifdef CONFIG_SERIO
-       if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE)
-               sunzilog_register_serio(up, up->port.line);
+       if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+                        SUNZILOG_FLAG_CONS_MOUSE))
+               sunzilog_register_serio(up);
 #endif
 }
 
-static int __devinit zs_get_instance(struct device_node *dp)
-{
-       int ret;
-
-       ret = of_getintprop_default(dp, "slave", -1);
-       if (ret != -1)
-               return ret;
-
-       if (of_find_property(dp, "keyboard", NULL))
-               ret = 1;
-       else
-               ret = 0;
-
-       return ret;
-}
-
 static int zilog_irq = -1;
 
-static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct of_device *op = to_of_device(&dev->dev);
+       static int inst;
        struct uart_sunzilog_port *up;
        struct zilog_layout __iomem *rp;
-       int inst = zs_get_instance(dev->node);
+       int keyboard_mouse;
        int err;
 
+       keyboard_mouse = 0;
+       if (of_find_property(op->node, "keyboard", NULL))
+               keyboard_mouse = 1;
+
        sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
                                              sizeof(struct zilog_layout),
                                              "zs");
@@ -1352,16 +1337,8 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
 
        rp = sunzilog_chip_regs[inst];
 
-       if (zilog_irq == -1) {
+       if (zilog_irq == -1)
                zilog_irq = op->irqs[0];
-               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
-                                 "zs", sunzilog_irq_chain);
-               if (err) {
-                       of_iounmap(rp, sizeof(struct zilog_layout));
-
-                       return err;
-               }
-       }
 
        up = &sunzilog_port_table[inst * 2];
 
@@ -1378,7 +1355,7 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
        up[0].port.line = (inst * 2) + 0;
        up[0].port.dev = &op->dev;
        up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
-       if (inst == 1)
+       if (keyboard_mouse)
                up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
        sunzilog_init_hw(&up[0]);
 
@@ -1395,11 +1372,11 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
        up[1].port.line = (inst * 2) + 1;
        up[1].port.dev = &op->dev;
        up[1].flags |= 0;
-       if (inst == 1)
+       if (keyboard_mouse)
                up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
        sunzilog_init_hw(&up[1]);
 
-       if (inst != 1) {
+       if (!keyboard_mouse) {
                err = uart_add_one_port(&sunzilog_reg, &up[0].port);
                if (err) {
                        of_iounmap(rp, sizeof(struct zilog_layout));
@@ -1411,9 +1388,18 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
                        of_iounmap(rp, sizeof(struct zilog_layout));
                        return err;
                }
+       } else {
+               printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
+                      "is a zs\n",
+                      op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
+               printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
+                      "is a zs\n",
+                      op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
        }
 
-       dev_set_drvdata(&dev->dev, &up[0]);
+       dev_set_drvdata(&op->dev, &up[0]);
+
+       inst++;
 
        return 0;
 }
@@ -1462,36 +1448,65 @@ static struct of_platform_driver zs_driver = {
 static int __init sunzilog_init(void)
 {
        struct device_node *dp;
-       int err;
+       int err, uart_count;
+       int num_keybms;
 
        NUM_SUNZILOG = 0;
-       for_each_node_by_name(dp, "zs")
+       num_keybms = 0;
+       for_each_node_by_name(dp, "zs") {
                NUM_SUNZILOG++;
+               if (of_find_property(dp, "keyboard", NULL))
+                       num_keybms++;
+       }
 
+       uart_count = 0;
        if (NUM_SUNZILOG) {
                int uart_count;
 
                err = sunzilog_alloc_tables();
                if (err)
-                       return err;
+                       goto out;
 
-               /* Subtract 1 for keyboard, 1 for mouse.  */
-               uart_count = (NUM_SUNZILOG * 2) - 2;
+               uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
 
                sunzilog_reg.nr = uart_count;
                sunzilog_reg.minor = sunserial_current_minor;
                err = uart_register_driver(&sunzilog_reg);
-               if (err) {
-                       sunzilog_free_tables();
-                       return err;
-               }
+               if (err)
+                       goto out_free_tables;
+
                sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
                sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
                sunserial_current_minor += uart_count;
        }
 
-       return of_register_driver(&zs_driver, &of_bus_type);
+       err = of_register_driver(&zs_driver, &of_bus_type);
+       if (err)
+               goto out_unregister_uart;
+
+       if (zilog_irq != -1) {
+               err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
+                                 "zs", sunzilog_irq_chain);
+               if (err)
+                       goto out_unregister_driver;
+       }
+
+out:
+       return err;
+
+out_unregister_driver:
+       of_unregister_driver(&zs_driver);
+
+out_unregister_uart:
+       if (NUM_SUNZILOG) {
+               uart_unregister_driver(&sunzilog_reg);
+               sunzilog_reg.cons = NULL;
+       }
+
+out_free_tables:
+       sunzilog_free_tables();
+       goto out;
 }
 
 static void __exit sunzilog_exit(void)