Merge branch 'merge'
[pandora-kernel.git] / drivers / serial / serial_cs.c
index eec05a0..cbf260b 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/serial_core.h>
+#include <linux/delay.h>
 #include <linux/major.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -102,6 +103,8 @@ struct serial_info {
        int                     multi;
        int                     slave;
        int                     manfid;
+       int                     prodid;
+       int                     c950ctrl;
        dev_node_t              node[4];
        int                     line[4];
 };
@@ -116,6 +119,33 @@ struct serial_cfg_mem {
 static int serial_config(struct pcmcia_device * link);
 
 
+static void wakeup_card(struct serial_info *info)
+{
+       int ctrl = info->c950ctrl;
+
+       if (info->manfid == MANFID_OXSEMI) {
+               outb(12, ctrl + 1);
+       } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
+               /* request_region? oxsemi branch does no request_region too... */
+               /* This sequence is needed to properly initialize MC45 attached to OXCF950.
+                * I tried decreasing these msleep()s, but it worked properly (survived
+                * 1000 stop/start operations) with these timeouts (or bigger). */
+               outb(0xA, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(300);
+               outb(0xC, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(200);
+               outb(0xF, ctrl + 1);
+               msleep(100);
+               outb(0xE, ctrl + 1);
+               msleep(100);
+               outb(0xC, ctrl + 1);
+       }
+}
+
 /*======================================================================
 
     After a card is removed, serial_remove() will unregister
@@ -155,12 +185,13 @@ static int serial_suspend(struct pcmcia_device *link)
 
 static int serial_resume(struct pcmcia_device *link)
 {
-       if (DEV_OK(link)) {
+       if (pcmcia_dev_present(link)) {
                struct serial_info *info = link->priv;
                int i;
 
                for (i = 0; i < info->ndev; i++)
                        serial8250_resume_port(info->line[i]);
+               wakeup_card(info);
        }
 
        return 0;
@@ -503,15 +534,23 @@ static int multi_config(struct pcmcia_device * link)
        }
 
        /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-          8 registers are for the UART, the others are extra registers */
-       if (info->manfid == MANFID_OXSEMI) {
+        * 8 registers are for the UART, the others are extra registers.
+        * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+        */
+       if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+                               info->prodid == PRODID_POSSIO_GCC)) {
+               int err;
+
                if (cf->index == 1 || cf->index == 3) {
-                       setup_serial(link, info, base2, link->irq.AssignedIRQ);
-                       outb(12, link->io.BasePort1 + 1);
+                       err = setup_serial(link, info, base2,
+                                       link->irq.AssignedIRQ);
+                       base2 = link->io.BasePort1;
                } else {
-                       setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
-                       outb(12, base2 + 1);
+                       err = setup_serial(link, info, link->io.BasePort1,
+                                       link->irq.AssignedIRQ);
                }
+               info->c950ctrl = base2;
+               wakeup_card(info);
                rc = 0;
                goto free_cfg_mem;
        }
@@ -583,6 +622,7 @@ static int serial_config(struct pcmcia_device * link)
        tuple->DesiredTuple = CISTPL_MANFID;
        if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
                info->manfid = parse->manfid.manf;
+               info->prodid = le16_to_cpu(buf[1]);
                for (i = 0; i < MULTI_COUNT; i++)
                        if ((info->manfid == multi_id[i].manfid) &&
                            (parse->manfid.card == multi_id[i].prodid))
@@ -746,6 +786,7 @@ static struct pcmcia_device_id serial_ids[] = {
        PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
        PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
        PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
+       PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"),
        /* too generic */
        /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
        /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */