linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / powerpc / platforms / powermac / low_i2c.c
index 8677f50..87eb6bb 100644 (file)
@@ -30,6 +30,7 @@
 #undef DEBUG
 #undef DEBUG_LOW
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -230,14 +231,6 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
        return isr;
 }
 
-static void kw_i2c_do_stop(struct pmac_i2c_host_kw *host, int result)
-{
-       kw_write_reg(reg_control, KW_I2C_CTL_STOP);
-       host->state = state_stop;
-       host->result = result;
-}
-
-
 static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
 {
        u8 ack;
@@ -253,36 +246,42 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
        }
 
        if (isr == 0) {
-               printk(KERN_WARNING "low_i2c: Timeout in i2c transfer"
-                      " on keywest !\n");
                if (host->state != state_stop) {
-                       kw_i2c_do_stop(host, -EIO);
-                       return;
+                       DBG_LOW("KW: Timeout !\n");
+                       host->result = -EIO;
+                       goto stop;
+               }
+               if (host->state == state_stop) {
+                       ack = kw_read_reg(reg_status);
+                       if (ack & KW_I2C_STAT_BUSY)
+                               kw_write_reg(reg_status, 0);
+                       host->state = state_idle;
+                       kw_write_reg(reg_ier, 0x00);
+                       if (!host->polled)
+                               complete(&host->complete);
                }
-               ack = kw_read_reg(reg_status);
-               if (ack & KW_I2C_STAT_BUSY)
-                       kw_write_reg(reg_status, 0);
-               host->state = state_idle;
-               kw_write_reg(reg_ier, 0x00);
-               if (!host->polled)
-                       complete(&host->complete);
                return;
        }
 
        if (isr & KW_I2C_IRQ_ADDR) {
                ack = kw_read_reg(reg_status);
                if (host->state != state_addr) {
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
                        WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-                       kw_i2c_do_stop(host, -EIO);
+                       host->result = -EIO;
+                       goto stop;
                }
                if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                       host->result = -ENXIO;
-                       host->state = state_stop;
+                       host->result = -ENODEV;
                        DBG_LOW("KW: NAK on address\n");
+                       host->state = state_stop;
+                       return;
                } else {
-                       if (host->len == 0)
-                               kw_i2c_do_stop(host, 0);
-                       else if (host->rw) {
+                       if (host->len == 0) {
+                               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+                               goto stop;
+                       }
+                       if (host->rw) {
                                host->state = state_read;
                                if (host->len > 1)
                                        kw_write_reg(reg_control,
@@ -309,19 +308,25 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
                        ack = kw_read_reg(reg_status);
                        if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
                                DBG_LOW("KW: nack on data write\n");
-                               host->result = -EFBIG;
-                               host->state = state_stop;
+                               host->result = -EIO;
+                               goto stop;
                        } else if (host->len) {
                                kw_write_reg(reg_data, *(host->data++));
                                host->len--;
-                       } else
-                               kw_i2c_do_stop(host, 0);
+                       } else {
+                               kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+                               host->state = state_stop;
+                               host->result = 0;
+                       }
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
                } else {
+                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
                        WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (host->state != state_stop)
-                               kw_i2c_do_stop(host, -EIO);
+                       if (host->state != state_stop) {
+                               host->result = -EIO;
+                               goto stop;
+                       }
                }
-               kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
        }
 
        if (isr & KW_I2C_IRQ_STOP) {
@@ -335,10 +340,14 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
                        complete(&host->complete);
        }
 
-       /* Below should only happen in manual mode which we don't use ... */
        if (isr & KW_I2C_IRQ_START)
                kw_write_reg(reg_isr, KW_I2C_IRQ_START);
 
+       return;
+ stop:
+       kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
+       host->state = state_stop;
+       return;
 }
 
 /* Interrupt handler */
@@ -522,11 +531,10 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
                host->speed = KW_I2C_MODE_25KHZ;
                break;
        }       
-       host->irq = irq_of_parse_and_map(np, 0);
-       if (host->irq == NO_IRQ)
-               printk(KERN_WARNING
-                      "low_i2c: Failed to map interrupt for %s\n",
-                      np->full_name);
+       if (np->n_intrs > 0)
+               host->irq = np->intrs[0].line;
+       else
+               host->irq = NO_IRQ;
 
        host->base = ioremap((*addrp), 0x1000);
        if (host->base == NULL) {
@@ -536,11 +544,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
                return NULL;
        }
 
-       /* Make sure IRQ is disabled */
+       /* Make sure IRA is disabled */
        kw_write_reg(reg_ier, 0);
 
        /* Request chip interrupt */
-       if (request_irq(host->irq, kw_i2c_irq, 0, "keywest i2c", host))
+       if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
                host->irq = NO_IRQ;
 
        printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
@@ -1157,7 +1165,6 @@ EXPORT_SYMBOL_GPL(pmac_i2c_xfer);
 /* some quirks for platform function decoding */
 enum {
        pmac_i2c_quirk_invmask = 0x00000001u,
-       pmac_i2c_quirk_skip = 0x00000002u,
 };
 
 static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
@@ -1173,15 +1180,6 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
                /* XXX Study device-tree's & apple drivers are get the quirks
                 * right !
                 */
-               /* Workaround: It seems that running the clockspreading
-                * properties on the eMac will cause lockups during boot.
-                * The machine seems to work fine without that. So for now,
-                * let's make sure i2c-hwclock doesn't match about "imic"
-                * clocks and we'll figure out if we really need to do
-                * something special about those later.
-                */
-               { "i2c-hwclock", "imic5002", pmac_i2c_quirk_skip },
-               { "i2c-hwclock", "imic5003", pmac_i2c_quirk_skip },
                { "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
                { "i2c-cpu-voltage", NULL, 0},
                {  "temp-monitor", NULL, 0 },
@@ -1208,8 +1206,6 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
                                if (p->compatible &&
                                    !device_is_compatible(np, p->compatible))
                                        continue;
-                               if (p->quirks & pmac_i2c_quirk_skip)
-                                       break;
                                callback(np, p->quirks);
                                break;
                        }
@@ -1461,9 +1457,6 @@ int __init pmac_i2c_init(void)
                return 0;
        i2c_inited = 1;
 
-       if (!machine_is(powermac))
-               return 0;
-
        /* Probe keywest-i2c busses */
        kw_i2c_probe();