Pull acpi_bus_register_driver into release branch
[pandora-kernel.git] / arch / powerpc / platforms / powermac / low_i2c.c
index 87eb6bb..c896ce8 100644 (file)
@@ -231,6 +231,14 @@ 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;
@@ -246,42 +254,36 @@ 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) {
-                       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);
+                       kw_i2c_do_stop(host, -EIO);
+                       return;
                }
+               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"); 
-                       host->result = -EIO;
-                       goto stop;
+                       kw_i2c_do_stop(host, -EIO);
                }
                if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                       host->result = -ENODEV;
-                       DBG_LOW("KW: NAK on address\n");
+                       host->result = -ENXIO;
                        host->state = state_stop;
-                       return;
+                       DBG_LOW("KW: NAK on address\n");
                } else {
-                       if (host->len == 0) {
-                               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-                               goto stop;
-                       }
-                       if (host->rw) {
+                       if (host->len == 0)
+                               kw_i2c_do_stop(host, 0);
+                       else if (host->rw) {
                                host->state = state_read;
                                if (host->len > 1)
                                        kw_write_reg(reg_control,
@@ -308,25 +310,19 @@ 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 = -EIO;
-                               goto stop;
+                               host->result = -EFBIG;
+                               host->state = state_stop;
                        } else if (host->len) {
                                kw_write_reg(reg_data, *(host->data++));
                                host->len--;
-                       } 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_i2c_do_stop(host, 0);
                } else {
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
                        WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (host->state != state_stop) {
-                               host->result = -EIO;
-                               goto stop;
-                       }
+                       if (host->state != state_stop)
+                               kw_i2c_do_stop(host, -EIO);
                }
+               kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
        }
 
        if (isr & KW_I2C_IRQ_STOP) {
@@ -340,14 +336,10 @@ 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 */
@@ -544,11 +536,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
                return NULL;
        }
 
-       /* Make sure IRA is disabled */
+       /* Make sure IRQ is disabled */
        kw_write_reg(reg_ier, 0);
 
        /* Request chip interrupt */
-       if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+       if (request_irq(host->irq, kw_i2c_irq, 0, "keywest i2c", host))
                host->irq = NO_IRQ;
 
        printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
@@ -1165,6 +1157,7 @@ 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,
@@ -1180,6 +1173,15 @@ 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 },
@@ -1206,6 +1208,8 @@ 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;
                        }
@@ -1457,6 +1461,9 @@ int __init pmac_i2c_init(void)
                return 0;
        i2c_inited = 1;
 
+       if (!machine_is(powermac))
+               return 0;
+
        /* Probe keywest-i2c busses */
        kw_i2c_probe();