#undef DEBUG
#undef DEBUG_LOW
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
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;
}
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,
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) {
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 */
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) {
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",
/* 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,
/* 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 },
if (p->compatible &&
!device_is_compatible(np, p->compatible))
continue;
- if (p->quirks & pmac_i2c_quirk_skip)
- break;
callback(np, p->quirks);
break;
}
return 0;
i2c_inited = 1;
- if (!machine_is(powermac))
- return 0;
-
/* Probe keywest-i2c busses */
kw_i2c_probe();