pmac-zilog: cleanup
[safe/jmp/linux-2.6] / drivers / serial / pmac_zilog.c
index a3b99ca..1c8afd9 100644 (file)
@@ -88,6 +88,16 @@ MODULE_LICENSE("GPL");
 
 #define PWRDBG(fmt, arg...)    printk(KERN_DEBUG fmt , ## arg)
 
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR                TTY_MAJOR
+#define PMACZILOG_MINOR                64
+#define PMACZILOG_NAME         "ttyS"
+#else
+#define PMACZILOG_MAJOR                204
+#define PMACZILOG_MINOR                192
+#define PMACZILOG_NAME         "ttyPZ"
+#endif
+
 
 /*
  * For the sake of early serial console, we can do a pre-probe
@@ -99,9 +109,10 @@ static DEFINE_MUTEX(pmz_irq_mutex);
 
 static struct uart_driver pmz_uart_reg = {
        .owner          =       THIS_MODULE,
-       .driver_name    =       "ttyS",
-       .dev_name       =       "ttyS",
-       .major          =       TTY_MAJOR,
+       .driver_name    =       PMACZILOG_NAME,
+       .dev_name       =       PMACZILOG_NAME,
+       .major          =       PMACZILOG_MAJOR,
+       .minor          =       PMACZILOG_MINOR,
 };
 
 
@@ -142,8 +153,8 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
        write_zsreg(uap, R10, regs[R10]);
 
        /* Set TX/RX controls sans the enable bits.  */
-               write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
-               write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
+       write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
 
        /* now set R7 "prime" on ESCC */
        write_zsreg(uap, R15, regs[R15] | EN85C30);
@@ -194,7 +205,7 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
  */
 static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
 {
-               if (!ZS_REGS_HELD(uap)) {
+       if (!ZS_REGS_HELD(uap)) {
                if (ZS_TX_ACTIVE(uap)) {
                        uap->flags |= PMACZILOG_FLAG_REGS_HELD;
                } else {
@@ -204,8 +215,7 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
        }
 }
 
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
-                                           struct pt_regs *regs)
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
 {
        struct tty_struct *tty = NULL;
        unsigned char ch, r1, drop, error, flag;
@@ -232,12 +242,12 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
        }
 
        /* Sanity check, make sure the old bug is no longer happening */
-       if (uap->port.info == NULL || uap->port.info->tty == NULL) {
+       if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
                WARN_ON(1);
                (void)read_zsdata(uap);
                return NULL;
        }
-       tty = uap->port.info->tty;
+       tty = uap->port.state->port.tty;
 
        while (1) {
                error = 0;
@@ -267,11 +277,11 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
                if (uap->port.sysrq) {
                        int swallow;
                        spin_unlock(&uap->port.lock);
-                       swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
+                       swallow = uart_handle_sysrq_char(&uap->port, ch);
                        spin_lock(&uap->port.lock);
                        if (swallow)
                                goto next_char;
-               }
+               }
 #endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
 
                /* A real serial line, record the character and status.  */
@@ -307,7 +317,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
 
                if (uap->port.ignore_status_mask == 0xff ||
                    (r1 & uap->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
+                       tty_insert_flip_char(tty, ch, flag);
                }
                if (r1 & Rx_OVR)
                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -335,7 +345,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
        return tty;
 }
 
-static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
+static void pmz_status_handle(struct uart_pmac_port *uap)
 {
        unsigned char status;
 
@@ -359,7 +369,7 @@ static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
                        uart_handle_cts_change(&uap->port,
                                               !(status & CTS));
 
-               wake_up_interruptible(&uap->port.info->delta_msr_wait);
+               wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
        }
 
        if (status & BRK_ABRT)
@@ -401,6 +411,17 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
                goto ack_tx_int;
        }
 
+       /* Under some circumstances, we see interrupts reported for
+        * a closed channel. The interrupt mask in R1 is clear, but
+        * R3 still signals the interrupts and we see them when taking
+        * an interrupt for the other channel (this could be a qemu
+        * bug but since the ESCC doc doesn't specify precsiely whether
+        * R3 interrup status bits are masked by R1 interrupt enable
+        * bits, better safe than sorry). --BenH.
+        */
+       if (!ZS_IS_OPEN(uap))
+               goto ack_tx_int;
+
        if (uap->port.x_char) {
                uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
                write_zsdata(uap, uap->port.x_char);
@@ -410,9 +431,9 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
                return;
        }
 
-       if (uap->port.info == NULL)
+       if (uap->port.state == NULL)
                goto ack_tx_int;
-       xmit = &uap->port.info->xmit;
+       xmit = &uap->port.state->xmit;
        if (uart_circ_empty(xmit)) {
                uart_write_wakeup(&uap->port);
                goto ack_tx_int;
@@ -438,7 +459,7 @@ ack_tx_int:
 }
 
 /* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
 {
        struct uart_pmac_port *uap = dev_id;
        struct uart_pmac_port *uap_a;
@@ -449,47 +470,47 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        uap_a = pmz_get_port_A(uap);
        uap_b = uap_a->mate;
-       
-               spin_lock(&uap_a->port.lock);
+
+       spin_lock(&uap_a->port.lock);
        r3 = read_zsreg(uap_a, R3);
 
 #ifdef DEBUG_HARD
        pmz_debug("irq, r3: %x\n", r3);
 #endif
-               /* Channel A */
+       /* Channel A */
        tty = NULL;
-               if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+       if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
                write_zsreg(uap_a, R0, RES_H_IUS);
                zssync(uap_a);          
-                       if (r3 & CHAEXT)
-                               pmz_status_handle(uap_a, regs);
+               if (r3 & CHAEXT)
+                       pmz_status_handle(uap_a);
                if (r3 & CHARxIP)
-                       tty = pmz_receive_chars(uap_a, regs);
-                       if (r3 & CHATxIP)
-                               pmz_transmit_chars(uap_a);
-               rc = IRQ_HANDLED;
-               }
-               spin_unlock(&uap_a->port.lock);
+                       tty = pmz_receive_chars(uap_a);
+               if (r3 & CHATxIP)
+                       pmz_transmit_chars(uap_a);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_a->port.lock);
        if (tty != NULL)
                tty_flip_buffer_push(tty);
 
        if (uap_b->node == NULL)
                goto out;
 
-               spin_lock(&uap_b->port.lock);
+       spin_lock(&uap_b->port.lock);
        tty = NULL;
        if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
                write_zsreg(uap_b, R0, RES_H_IUS);
                zssync(uap_b);
-                       if (r3 & CHBEXT)
-                               pmz_status_handle(uap_b, regs);
-                       if (r3 & CHBRxIP)
-                               tty = pmz_receive_chars(uap_b, regs);
-                       if (r3 & CHBTxIP)
-                               pmz_transmit_chars(uap_b);
-               rc = IRQ_HANDLED;
-               }
-               spin_unlock(&uap_b->port.lock);
+               if (r3 & CHBEXT)
+                       pmz_status_handle(uap_b);
+               if (r3 & CHBRxIP)
+                       tty = pmz_receive_chars(uap_b);
+               if (r3 & CHBTxIP)
+                       pmz_transmit_chars(uap_b);
+               rc = IRQ_HANDLED;
+       }
+       spin_unlock(&uap_b->port.lock);
        if (tty != NULL)
                tty_flip_buffer_push(tty);
 
@@ -645,7 +666,7 @@ static void pmz_start_tx(struct uart_port *port)
                port->icount.tx++;
                port->x_char = 0;
        } else {
-               struct circ_buf *xmit = &port->info->xmit;
+               struct circ_buf *xmit = &port->state->xmit;
 
                write_zsdata(uap, xmit->buf[xmit->tail]);
                zssync(uap);
@@ -697,7 +718,7 @@ static void pmz_enable_ms(struct uart_port *port)
 
                if (ZS_IS_ASLEEP(uap))
                        return;
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               /* NOTE: Not subject to 'transmitter active' rule. */
                write_zsreg(uap, R15, uap->curregs[R15]);
        }
 }
@@ -727,7 +748,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
        if (new_reg != uap->curregs[R5]) {
                uap->curregs[R5] = new_reg;
 
-               /* NOTE: Not subject to 'transmitter active' rule.  */ 
+               /* NOTE: Not subject to 'transmitter active' rule. */
                if (ZS_IS_ASLEEP(uap))
                        return;
                write_zsreg(uap, R5, uap->curregs[R5]);
@@ -887,7 +908,6 @@ static int __pmz_startup(struct uart_pmac_port *uap)
        /* Remember status for DCD/CTS changes */
        uap->prev_status = read_zsreg(uap, R0);
 
-
        return pwr_delay;
 }
 
@@ -962,7 +982,7 @@ static int pmz_startup(struct uart_port *port)
        if (!ZS_IS_EXTCLK(uap))
                uap->curregs[R1] |= EXT_INT_ENAB;
        write_zsreg(uap, R1, uap->curregs[R1]);
-               spin_unlock_irqrestore(&port->lock, flags);
+       spin_unlock_irqrestore(&port->lock, flags);
 
        pmz_debug("pmz: startup() done.\n");
 
@@ -982,7 +1002,7 @@ static void pmz_shutdown(struct uart_port *port)
        mutex_lock(&pmz_irq_mutex);
 
        /* Release interrupt handler */
-               free_irq(uap->port.irq, uap);
+       free_irq(uap->port.irq, uap);
 
        spin_lock_irqsave(&port->lock, flags);
 
@@ -1030,7 +1050,6 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
 {
        int brg;
 
-
        /* Switch to external clocking for IrDA high clock rates. That
         * code could be re-used for Midi interfaces with different
         * multipliers
@@ -1202,12 +1221,12 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
        uap->curregs[R5] |= DTR;
        write_zsreg(uap, R5, uap->curregs[R5]);
        zssync(uap);
-               mdelay(1);
+       mdelay(1);
 
        /* Switch SCC to 19200 */
        pmz_convert_to_zs(uap, CS8, 0, 19200);          
        pmz_load_zsregs(uap, uap->curregs);
-               mdelay(1);
+       mdelay(1);
 
        /* Write get_version command byte */
        write_zsdata(uap, 1);
@@ -1263,8 +1282,8 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
 }
 
 
-static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
-                             struct termios *old)
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned long baud;
@@ -1274,7 +1293,7 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
        if (ZS_IS_ASLEEP(uap))
                return;
 
-       memcpy(&uap->termios_cache, termios, sizeof(struct termios));
+       memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
 
        /* XXX Check which revs of machines actually allow 1 and 4Mb speeds
         * on the IR dongle. Note that the IRTTY driver currently doesn't know
@@ -1314,8 +1333,8 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
 }
 
 /* The port lock is not held.  */
-static void pmz_set_termios(struct uart_port *port, struct termios *termios,
-                           struct termios *old)
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
 {
        struct uart_pmac_port *uap = to_pmz(port);
        unsigned long flags;
@@ -1373,6 +1392,29 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
        return -EINVAL;
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+               udelay(5);
+       return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+       /* Wait for the transmit buffer to empty. */
+       while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(uap, c);
+}
+
+#endif
+
 static struct uart_ops pmz_pops = {
        .tx_empty       =       pmz_tx_empty,
        .set_mctrl      =       pmz_set_mctrl,
@@ -1390,6 +1432,10 @@ static struct uart_ops pmz_pops = {
        .request_port   =       pmz_request_port,
        .config_port    =       pmz_config_port,
        .verify_port    =       pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  =       pmz_poll_get_char,
+       .poll_put_char  =       pmz_poll_put_char,
+#endif
 };
 
 /*
@@ -1415,7 +1461,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
                return -ENODEV;
        uap->port.mapbase = r_ports.start;
        uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
-      
+
        uap->control_reg = uap->port.membase;
        uap->data_reg = uap->control_reg + 0x10;
        
@@ -1451,14 +1497,14 @@ no_dma:
        /*
         * Detect port type
         */
-       if (device_is_compatible(np, "cobalt"))
+       if (of_device_is_compatible(np, "cobalt"))
                uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-       conn = get_property(np, "AAPL,connector", &len);
+       conn = of_get_property(np, "AAPL,connector", &len);
        if (conn && (strcmp(conn, "infrared") == 0))
                uap->flags |= PMACZILOG_FLAG_IS_IRDA;
        uap->port_type = PMAC_SCC_ASYNC;
        /* 1999 Powerbook G3 has slot-names property instead */
-       slots = get_property(np, "slot-names", &len);
+       slots = of_get_property(np, "slot-names", &len);
        if (slots && slots->count > 0) {
                if (strcmp(slots->name, "IrDA") == 0)
                        uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1468,10 +1514,11 @@ no_dma:
        if (ZS_IS_IRDA(uap))
                uap->port_type = PMAC_SCC_IRDA;
        if (ZS_IS_INTMODEM(uap)) {
-               struct device_node* i2c_modem = find_devices("i2c-modem");
+               struct device_node* i2c_modem =
+                       of_find_node_by_name(NULL, "i2c-modem");
                if (i2c_modem) {
                        const char* mid =
-                               get_property(i2c_modem, "modem-id", NULL);
+                               of_get_property(i2c_modem, "modem-id", NULL);
                        if (mid) switch(*mid) {
                        case 0x04 :
                        case 0x05 :
@@ -1483,6 +1530,7 @@ no_dma:
                        }
                        printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
                                mid ? (*mid) : 0);
+                       of_node_put(i2c_modem);
                } else {
                        printk(KERN_INFO "pmac_zilog: serial modem detected\n");
                }
@@ -1499,6 +1547,21 @@ no_dma:
        uap->port.type = PORT_PMAC_ZILOG;
        uap->port.flags = 0;
 
+       /*
+        * Fixup for the port on Gatwick for which the device-tree has
+        * missing interrupts. Normally, the macio_dev would contain
+        * fixed up interrupt info, but we use the device-tree directly
+        * here due to early probing so we need the fixup too.
+        */
+       if (uap->port.irq == NO_IRQ &&
+           np->parent && np->parent->parent &&
+           of_device_is_compatible(np->parent->parent, "gatwick")) {
+               /* IRQs on gatwick are offset by 64 */
+               uap->port.irq = irq_create_mapping(NULL, 64 + 15);
+               uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
+               uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
+       }
+
        /* Setup some valid baud rate information in the register
         * shadows so we don't write crap there before baud rate is
         * first initialized.
@@ -1525,7 +1588,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
 }
 
 /*
- * Called upon match with an escc node in the devive-tree.
+ * Called upon match with an escc node in the device-tree.
  */
 static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
@@ -1586,12 +1649,12 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
        if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
                return 0;
 
-       pmz_debug("suspend, switching to state %d\n", pm_state);
+       pmz_debug("suspend, switching to state %d\n", pm_state.event);
 
        state = pmz_uart_reg.state + uap->port.line;
 
        mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->mutex);
+       mutex_lock(&state->port.mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
 
@@ -1622,7 +1685,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
        /* Shut the chip down */
        pmz_set_scc_power(uap, 0);
 
-       mutex_unlock(&state->mutex);
+       mutex_unlock(&state->port.mutex);
        mutex_unlock(&pmz_irq_mutex);
 
        pmz_debug("suspend, switching complete\n");
@@ -1651,7 +1714,7 @@ static int pmz_resume(struct macio_dev *mdev)
        state = pmz_uart_reg.state + uap->port.line;
 
        mutex_lock(&pmz_irq_mutex);
-       mutex_lock(&state->mutex);
+       mutex_lock(&state->port.mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
        if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
@@ -1683,7 +1746,7 @@ static int pmz_resume(struct macio_dev *mdev)
        }
 
  bail:
-       mutex_unlock(&state->mutex);
+       mutex_unlock(&state->port.mutex);
        mutex_unlock(&pmz_irq_mutex);
 
        /* Right now, we deal with delay by blocking here, I'll be
@@ -1747,7 +1810,7 @@ static int __init pmz_probe(void)
                pmz_ports[count].node           = node_a;
                pmz_ports[count+1].node         = node_b;
                pmz_ports[count].port.line      = count;
-               pmz_ports[count+1].port.line    = count+1;
+               pmz_ports[count+1].port.line    = count+1;
 
                /*
                 * Setup the ports for real
@@ -1777,7 +1840,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
 static int __init pmz_console_setup(struct console *co, char *options);
 
 static struct console pmz_console = {
-       .name   =       "ttyS",
+       .name   =       PMACZILOG_NAME,
        .write  =       pmz_console_write,
        .device =       uart_console_device,
        .setup  =       pmz_console_setup,
@@ -1801,7 +1864,6 @@ static int __init pmz_register(void)
        
        pmz_uart_reg.nr = pmz_ports_count;
        pmz_uart_reg.cons = PMACZILOG_CONSOLE;
-       pmz_uart_reg.minor = 64;
 
        /*
         * Register this driver with the serial core
@@ -1835,23 +1897,22 @@ err_out:
 static struct of_device_id pmz_match[] = 
 {
        {
-       .name           = "ch-a",
+       .name           = "ch-a",
        },
        {
-       .name           = "ch-b",
+       .name           = "ch-b",
        },
        {},
 };
 MODULE_DEVICE_TABLE (of, pmz_match);
 
-static struct macio_driver pmz_driver = 
-{
+static struct macio_driver pmz_driver = {
        .name           = "pmac_zilog",
        .match_table    = pmz_match,
        .probe          = pmz_attach,
        .remove         = pmz_detach,
        .suspend        = pmz_suspend,
-               .resume         = pmz_resume,
+       .resume         = pmz_resume,
 };
 
 static int __init init_pmz(void)
@@ -1888,7 +1949,7 @@ static int __init init_pmz(void)
                        pmz_dispose_port(&pmz_ports[i]);
                return rc;
        }
-       
+
        /*
         * Then we register the macio driver itself
         */
@@ -1967,10 +2028,10 @@ static int __init pmz_console_setup(struct console *co, char *options)
        /*
         * XServe's default to 57600 bps
         */
-       if (machine_is_compatible("RackMac1,1")
-           || machine_is_compatible("RackMac1,2")
-           || machine_is_compatible("MacRISC4"))
-               baud = 57600;
+       if (of_machine_is_compatible("RackMac1,1")
+           || of_machine_is_compatible("RackMac1,2")
+           || of_machine_is_compatible("MacRISC4"))
+               baud = 57600;
 
        /*
         * Check whether an invalid uart number has been specified, and