diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac')
-rw-r--r-- | arch/powerpc/platforms/powermac/low_i2c.c | 90 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pci.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pfunc_core.c | 18 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 12 |
4 files changed, 71 insertions, 51 deletions
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index e14f9ac55cf4..c896ce83d412 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -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; } diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index f5d8d15d74fa..ea179afea632 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1097,7 +1097,7 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) * (iBook second controller) */ if (dev->vendor == PCI_VENDOR_ID_APPLE - && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) + && dev->class == PCI_CLASS_SERIAL_USB_OHCI && !node) { printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n", pci_name(dev)); diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index 4baa75b1d36f..f08173b0f065 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/module.h> +#include <linux/mutex.h> #include <asm/semaphore.h> #include <asm/prom.h> @@ -546,6 +547,7 @@ struct pmf_device { static LIST_HEAD(pmf_devices); static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_MUTEX(pmf_irq_mutex); static void pmf_release_device(struct kref *kref) { @@ -864,15 +866,17 @@ int pmf_register_irq_client(struct device_node *target, spin_lock_irqsave(&pmf_lock, flags); func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN); - if (func == NULL) { - spin_unlock_irqrestore(&pmf_lock, flags); + if (func) + func = pmf_get_function(func); + spin_unlock_irqrestore(&pmf_lock, flags); + if (func == NULL) return -ENODEV; - } + mutex_lock(&pmf_irq_mutex); if (list_empty(&func->irq_clients)) func->dev->handlers->irq_enable(func); list_add(&client->link, &func->irq_clients); client->func = func; - spin_unlock_irqrestore(&pmf_lock, flags); + mutex_unlock(&pmf_irq_mutex); return 0; } @@ -881,16 +885,16 @@ EXPORT_SYMBOL_GPL(pmf_register_irq_client); void pmf_unregister_irq_client(struct pmf_irq_client *client) { struct pmf_function *func = client->func; - unsigned long flags; BUG_ON(func == NULL); - spin_lock_irqsave(&pmf_lock, flags); + mutex_lock(&pmf_irq_mutex); client->func = NULL; list_del(&client->link); if (list_empty(&func->irq_clients)) func->dev->handlers->irq_disable(func); - spin_unlock_irqrestore(&pmf_lock, flags); + mutex_unlock(&pmf_irq_mutex); + pmf_put_function(func); } EXPORT_SYMBOL_GPL(pmf_unregister_irq_client); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 4d15e396655c..b9200fb07815 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -463,11 +463,23 @@ static int pmac_pm_finish(suspend_state_t state) return 0; } +static int pmac_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_DISK: + return 1; + /* can't do any other states via generic mechanism yet */ + default: + return 0; + } +} + static struct pm_ops pmac_pm_ops = { .pm_disk_mode = PM_DISK_SHUTDOWN, .prepare = pmac_pm_prepare, .enter = pmac_pm_enter, .finish = pmac_pm_finish, + .valid = pmac_pm_valid, }; #endif /* CONFIG_SOFTWARE_SUSPEND */ |