diff options
author | Girish S G <girishsg@ti.com> | 2011-06-18 23:16:14 -0500 |
---|---|---|
committer | Nishanth Menon <nm@ti.com> | 2011-06-21 19:36:31 -0500 |
commit | 59dcd7add4896aa82e23b1fb7a37843afb067c00 (patch) | |
tree | 441f9f37719e0348a3f3475c802de007e55760ac /drivers/i2c/busses/i2c-omap.c | |
parent | 6f25b5ac083a68a30fed8de22b84bdfd1573cb8b (diff) | |
download | kernel_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.c | 47 |
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)); |