aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powermac/low_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powermac/low_i2c.c')
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 345e2da5676..7553b6a77c6 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -33,7 +33,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/delay.h>
@@ -43,6 +43,7 @@
#include <linux/timer.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
+#include <linux/slab.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
@@ -365,11 +366,20 @@ static void kw_i2c_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * If the timer is pending, that means we raced with the
+ * irq, in which case we just return
+ */
+ if (timer_pending(&host->timeout_timer))
+ goto skip;
+
kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
if (host->state != state_idle) {
host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
add_timer(&host->timeout_timer);
}
+ skip:
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -442,7 +452,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
*/
if (use_irq) {
/* Clear completion */
- INIT_COMPLETION(host->complete);
+ reinit_completion(&host->complete);
/* Ack stale interrupts */
kw_write_reg(reg_isr, kw_read_reg(reg_isr));
/* Arm timeout */
@@ -541,11 +551,12 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
/* Make sure IRQ is disabled */
kw_write_reg(reg_ier, 0);
- /* Request chip interrupt. We set IRQF_TIMER because we don't
+ /* Request chip interrupt. We set IRQF_NO_SUSPEND because we don't
* want that interrupt disabled between the 2 passes of driver
* suspend or we'll have issues running the pfuncs
*/
- if (request_irq(host->irq, kw_i2c_irq, IRQF_TIMER, "keywest i2c", host))
+ if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND,
+ "keywest i2c", host))
host->irq = NO_IRQ;
printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
@@ -591,7 +602,7 @@ static void __init kw_i2c_probe(void)
/* Probe keywest-i2c busses */
for_each_compatible_node(np, "i2c","keywest-i2c") {
struct pmac_i2c_host_kw *host;
- int multibus, chans, i;
+ int multibus;
/* Found one, init a host structure */
host = kw_i2c_host_init(np);
@@ -613,6 +624,8 @@ static void __init kw_i2c_probe(void)
* parent type
*/
if (multibus) {
+ int chans, i;
+
parent = of_get_parent(np);
if (parent == NULL)
continue;
@@ -704,7 +717,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
return -EINVAL;
}
- INIT_COMPLETION(comp);
+ reinit_completion(&comp);
req->data[0] = PMU_I2C_CMD;
req->reply[0] = 0xff;
req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
@@ -735,7 +748,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
hdr->bus = PMU_I2C_BUS_STATUS;
- INIT_COMPLETION(comp);
+ reinit_completion(&comp);
req->data[0] = PMU_I2C_CMD;
req->reply[0] = 0xff;
req->nbytes = 2;
@@ -900,7 +913,7 @@ static void __init smu_i2c_probe(void)
printk(KERN_INFO "SMU i2c %s\n", controller->full_name);
/* Look for childs, note that they might not be of the right
- * type as older device trees mix i2c busses and other thigns
+ * type as older device trees mix i2c busses and other things
* at the same level
*/
for (busnode = NULL;
@@ -1257,8 +1270,7 @@ static void pmac_i2c_do_end(struct pmf_function *func, void *instdata)
if (inst == NULL)
return;
pmac_i2c_close(inst->bus);
- if (inst)
- kfree(inst);
+ kfree(inst);
}
static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len)
@@ -1491,6 +1503,7 @@ static int __init pmac_i2c_create_platform_devices(void)
if (bus->platform_dev == NULL)
return -ENOMEM;
bus->platform_dev->dev.platform_data = bus;
+ bus->platform_dev->dev.of_node = bus->busnode;
platform_device_add(bus->platform_dev);
}