diff options
-rw-r--r-- | arch/arm/plat-omap/i2c.c | 13 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 47 | ||||
-rw-r--r-- | include/linux/i2c-omap.h | 2 |
3 files changed, 37 insertions, 25 deletions
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 5e76d49..f8dc82f 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -113,17 +113,6 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS -/* - * XXX This function is a temporary compatibility wrapper - only - * needed until the I2C driver can be converted to call - * omap_pm_set_max_dev_wakeup_lat() and handle a return code. - */ -static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) -{ - static struct pm_qos_request_list *qos_request; - omap_pm_set_max_mpu_wakeup_lat(&qos_request, t); -} - static struct omap_device_pm_latency omap_i2c_latency[] = { [0] = { .deactivate_func = omap_device_idle_hwmods, @@ -160,7 +149,7 @@ static inline int omap2_i2c_add_bus(int bus_id) * Only omap3 has support for constraints */ if (cpu_is_omap34xx() || cpu_is_omap44xx()) - pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; + pdata->needs_wakeup_latency = true; od = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), omap_i2c_latency, ARRAY_SIZE(omap_i2c_latency), 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ab9833b..da986f2 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -40,6 +40,7 @@ #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos_params.h> /* I2C controller revisions */ #define OMAP_I2C_REV_2 0x20 @@ -179,8 +180,7 @@ struct omap_i2c_dev { struct completion cmd_complete; struct resource *ioarea; u32 latency; /* maximum mpu wkup latency */ - void (*set_mpu_wkup_lat)(struct device *dev, - long latency); + struct pm_qos_request_list *pm_qos; u32 speed; /* Speed of bus in Khz */ u16 cmd_err; u8 *buf; @@ -648,8 +648,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + */ + if (dev->pm_qos) + pm_qos_update_request(dev->pm_qos, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -657,8 +663,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); + if (dev->pm_qos) + pm_qos_update_request(dev->pm_qos, PM_QOS_DEFAULT_VALUE); if (r == 0) r = num; @@ -1007,13 +1013,10 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - if (pdata != NULL) { + if (pdata) speed = pdata->clkrate; - dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - } else { + else speed = 100; /* Default speed */ - dev->set_mpu_wkup_lat = NULL; - } dev->speed = speed; dev->idle = 1; @@ -1025,6 +1028,17 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_mem; } + if (pdata && pdata->needs_wakeup_latency) { + dev->pm_qos = kzalloc(sizeof(struct pm_qos_request_list), + GFP_KERNEL); + if (!dev->pm_qos) { + r = -ENOMEM; + goto err_unmap; + } + pm_qos_add_request(dev->pm_qos, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + } + platform_set_drvdata(pdev, dev); if (cpu_is_omap7xx()) @@ -1067,7 +1081,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ } /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) + if (dev->pm_qos) dev->latency = (1000000 * dev->fifo_size) / (1000 * speed / 8); } @@ -1111,6 +1125,11 @@ err_free_irq: err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); omap_i2c_idle(dev); + if (dev->pm_qos) { + pm_qos_remove_request(dev->pm_qos); + kfree(dev->pm_qos); + } +err_unmap: iounmap(dev->base); err_free_mem: platform_set_drvdata(pdev, NULL); @@ -1133,6 +1152,10 @@ omap_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); iounmap(dev->base); + if (dev->pm_qos) { + pm_qos_remove_request(dev->pm_qos); + kfree(dev->pm_qos); + } kfree(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 7472449..3beb390 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -5,7 +5,7 @@ struct omap_i2c_bus_platform_data { u32 clkrate; - void (*set_mpu_wkup_lat)(struct device *dev, long set); + bool needs_wakeup_latency; int (*device_enable) (struct platform_device *pdev); int (*device_shutdown) (struct platform_device *pdev); int (*device_idle) (struct platform_device *pdev); |