aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-omap.c
diff options
context:
space:
mode:
authorGirish S G <girishsg@ti.com>2011-06-18 23:16:14 -0500
committerNishanth Menon <nm@ti.com>2011-06-21 19:36:31 -0500
commit59dcd7add4896aa82e23b1fb7a37843afb067c00 (patch)
tree441f9f37719e0348a3f3475c802de007e55760ac /drivers/i2c/busses/i2c-omap.c
parent6f25b5ac083a68a30fed8de22b84bdfd1573cb8b (diff)
downloadkernel_samsung_tuna-59dcd7add4896aa82e23b1fb7a37843afb067c00.zip
kernel_samsung_tuna-59dcd7add4896aa82e23b1fb7a37843afb067c00.tar.gz
kernel_samsung_tuna-59dcd7add4896aa82e23b1fb7a37843afb067c00.tar.bz2
OMAP: I2C: PM: Adapt to pm_qos framework for requesting mpu lat
This patch adapts PM_QoS infrastructure to request MPU latency. PM_QoS provides interface for drivers to register performance expectations such as in this case, MPU wakeup latency. The current I2C driver uses a wrapper around PM_QoS interface to request MPU latency. The resultant behavior was as follows: when ever any i2c transaction took place, every i2c request translates into individual i2c_xfers. Each i2c_xfer in the current I2C driver does the following: allocate memory for a pm_qos request request the qos latency do things that are time critical remove the qos request free the memory Instead, it is possible to make this efficient by: Allocating, adding the request on probe (with the default as disabled), removing the request and freeing the allocated memory on remove. In i2c_xfer, we can do: update the request with required latency do time critical operation update the request with default latency to disable the request. This allows the system to optimize the time critical i2c_xfer path which all drivers which use i2c will use. Acked-by: Todd Poyner <toddpoynor@google.com> Acked-by: Nishanth Menon <nm@ti.com> Signed-off-by: Girish S G <girishsg@ti.com>
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r--drivers/i2c/busses/i2c-omap.c47
1 files changed, 35 insertions, 12 deletions
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));