aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Jokiniemi <kalle.jokiniemi@digia.com>2010-05-11 14:35:08 -0400
committerBen Dooks <ben-linux@fluff.org>2010-05-19 19:18:59 -0400
commit20c9d2c4ab8243a1c311248232954b2c1da3ba75 (patch)
treee035de70d7b89618bb0e6923272849df7d1acb9a
parentf38e66e0077659e5d2ca3858fdb26fc9b1765b9f (diff)
i2c-omap: add mpu wake up latency constraint in i2c
While waiting for completion of the i2c transfer, the MPU could hit OFF mode and cause several msecs of delay that made i2c transfers fail more often. The extra delays and subsequent re-trys cause i2c clocks to be active more often. This has also an negative effect on power consumption. Created a mechanism for passing and using the constraint setting function in driver code. The used mpu wake up latency constraints are now set individually per bus, and they are calculated based on clock rate and fifo size. Thanks to Jarkko Nikula, Moiz Sonasath, Paul Walmsley, and Nishanth Menon for tuning out the details of this patch. Updates by Kevin as requested by Tony: - Remove omap_set_i2c_constraint_func() in favor of conditionally adding the flag in omap_i2c_add_bus() in order to keep all the OMAP conditional checking in a single location. - Update set_mpu_wkup_lat prototypes to match OMAP PM layer so OMAP PM function can be used directly in pdata. Cc: Moiz Sonasath <m-sonasath@ti.com> Cc: Jarkko Nikula <jhnikula@gmail.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Nishanth Menon <nm@ti.com> Signed-off-by: Kalle Jokiniemi <kalle.jokiniemi@digia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
-rw-r--r--arch/arm/plat-omap/i2c.c39
-rw-r--r--drivers/i2c/busses/i2c-omap.c24
-rw-r--r--include/linux/i2c-omap.h9
3 files changed, 56 insertions, 16 deletions
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 624e26298faa..f044b5927508 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -26,9 +26,12 @@
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/i2c.h> 28#include <linux/i2c.h>
29#include <linux/i2c-omap.h>
30
29#include <mach/irqs.h> 31#include <mach/irqs.h>
30#include <plat/mux.h> 32#include <plat/mux.h>
31#include <plat/i2c.h> 33#include <plat/i2c.h>
34#include <plat/omap-pm.h>
32 35
33#define OMAP_I2C_SIZE 0x3f 36#define OMAP_I2C_SIZE 0x3f
34#define OMAP1_I2C_BASE 0xfffb3800 37#define OMAP1_I2C_BASE 0xfffb3800
@@ -70,14 +73,14 @@ static struct resource i2c_resources[][2] = {
70 }, \ 73 }, \
71 } 74 }
72 75
73static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; 76static struct omap_i2c_bus_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)];
74static struct platform_device omap_i2c_devices[] = { 77static struct platform_device omap_i2c_devices[] = {
75 I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), 78 I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
76#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) 79#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
77 I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), 80 I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
78#endif 81#endif
79#if defined(CONFIG_ARCH_OMAP3) 82#if defined(CONFIG_ARCH_OMAP3)
80 I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]), 83 I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]),
81#endif 84#endif
82}; 85};
83 86
@@ -100,10 +103,12 @@ static int __init omap_i2c_nr_ports(void)
100static int __init omap_i2c_add_bus(int bus_id) 103static int __init omap_i2c_add_bus(int bus_id)
101{ 104{
102 struct platform_device *pdev; 105 struct platform_device *pdev;
106 struct omap_i2c_bus_platform_data *pd;
103 struct resource *res; 107 struct resource *res;
104 resource_size_t base, irq; 108 resource_size_t base, irq;
105 109
106 pdev = &omap_i2c_devices[bus_id - 1]; 110 pdev = &omap_i2c_devices[bus_id - 1];
111 pd = pdev->dev.platform_data;
107 if (bus_id == 1) { 112 if (bus_id == 1) {
108 res = pdev->resource; 113 res = pdev->resource;
109 if (cpu_class_is_omap1()) { 114 if (cpu_class_is_omap1()) {
@@ -123,6 +128,15 @@ static int __init omap_i2c_add_bus(int bus_id)
123 if (cpu_class_is_omap2()) 128 if (cpu_class_is_omap2())
124 omap2_i2c_mux_pins(bus_id); 129 omap2_i2c_mux_pins(bus_id);
125 130
131 /*
132 * When waiting for completion of a i2c transfer, we need to
133 * set a wake up latency constraint for the MPU. This is to
134 * ensure quick enough wakeup from idle, when transfer
135 * completes.
136 */
137 if (cpu_is_omap34xx())
138 pd->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat;
139
126 return platform_device_register(pdev); 140 return platform_device_register(pdev);
127} 141}
128 142
@@ -146,8 +160,8 @@ static int __init omap_i2c_bus_setup(char *str)
146 get_options(str, 3, ints); 160 get_options(str, 3, ints);
147 if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports) 161 if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
148 return 0; 162 return 0;
149 i2c_rate[ints[1] - 1] = ints[2]; 163 i2c_pdata[ints[1] - 1].clkrate = ints[2];
150 i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP; 164 i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
151 165
152 return 1; 166 return 1;
153} 167}
@@ -161,9 +175,9 @@ static int __init omap_register_i2c_bus_cmdline(void)
161{ 175{
162 int i, err = 0; 176 int i, err = 0;
163 177
164 for (i = 0; i < ARRAY_SIZE(i2c_rate); i++) 178 for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
165 if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) { 179 if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
166 i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP; 180 i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
167 err = omap_i2c_add_bus(i + 1); 181 err = omap_i2c_add_bus(i + 1);
168 if (err) 182 if (err)
169 goto out; 183 goto out;
@@ -197,9 +211,10 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
197 return err; 211 return err;
198 } 212 }
199 213
200 if (!i2c_rate[bus_id - 1]) 214 if (!i2c_pdata[bus_id - 1].clkrate)
201 i2c_rate[bus_id - 1] = clkrate; 215 i2c_pdata[bus_id - 1].clkrate = clkrate;
202 i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP; 216
217 i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
203 218
204 return omap_i2c_add_bus(bus_id); 219 return omap_i2c_add_bus(bus_id);
205} 220}
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 46111ff18133..42c0b9108c7f 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -38,6 +38,7 @@
38#include <linux/clk.h> 38#include <linux/clk.h>
39#include <linux/io.h> 39#include <linux/io.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41#include <linux/i2c-omap.h>
41 42
42/* I2C controller revisions */ 43/* I2C controller revisions */
43#define OMAP_I2C_REV_2 0x20 44#define OMAP_I2C_REV_2 0x20
@@ -175,6 +176,9 @@ struct omap_i2c_dev {
175 struct clk *fclk; /* Functional clock */ 176 struct clk *fclk; /* Functional clock */
176 struct completion cmd_complete; 177 struct completion cmd_complete;
177 struct resource *ioarea; 178 struct resource *ioarea;
179 u32 latency; /* maximum mpu wkup latency */
180 void (*set_mpu_wkup_lat)(struct device *dev,
181 long latency);
178 u32 speed; /* Speed of bus in Khz */ 182 u32 speed; /* Speed of bus in Khz */
179 u16 cmd_err; 183 u16 cmd_err;
180 u8 *buf; 184 u8 *buf;
@@ -603,8 +607,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
603 * REVISIT: We should abort the transfer on signals, but the bus goes 607 * REVISIT: We should abort the transfer on signals, but the bus goes
604 * into arbitration and we're currently unable to recover from it. 608 * into arbitration and we're currently unable to recover from it.
605 */ 609 */
610 if (dev->set_mpu_wkup_lat != NULL)
611 dev->set_mpu_wkup_lat(dev->dev, dev->latency);
606 r = wait_for_completion_timeout(&dev->cmd_complete, 612 r = wait_for_completion_timeout(&dev->cmd_complete,
607 OMAP_I2C_TIMEOUT); 613 OMAP_I2C_TIMEOUT);
614 if (dev->set_mpu_wkup_lat != NULL)
615 dev->set_mpu_wkup_lat(dev->dev, -1);
608 dev->buf_len = 0; 616 dev->buf_len = 0;
609 if (r < 0) 617 if (r < 0)
610 return r; 618 return r;
@@ -927,6 +935,7 @@ omap_i2c_probe(struct platform_device *pdev)
927 struct omap_i2c_dev *dev; 935 struct omap_i2c_dev *dev;
928 struct i2c_adapter *adap; 936 struct i2c_adapter *adap;
929 struct resource *mem, *irq, *ioarea; 937 struct resource *mem, *irq, *ioarea;
938 struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
930 irq_handler_t isr; 939 irq_handler_t isr;
931 int r; 940 int r;
932 u32 speed = 0; 941 u32 speed = 0;
@@ -956,10 +965,13 @@ omap_i2c_probe(struct platform_device *pdev)
956 goto err_release_region; 965 goto err_release_region;
957 } 966 }
958 967
959 if (pdev->dev.platform_data != NULL) 968 if (pdata != NULL) {
960 speed = *(u32 *)pdev->dev.platform_data; 969 speed = pdata->clkrate;
961 else 970 dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
962 speed = 100; /* Defualt speed */ 971 } else {
972 speed = 100; /* Default speed */
973 dev->set_mpu_wkup_lat = NULL;
974 }
963 975
964 dev->speed = speed; 976 dev->speed = speed;
965 dev->idle = 1; 977 dev->idle = 1;
@@ -1011,6 +1023,10 @@ omap_i2c_probe(struct platform_device *pdev)
1011 dev->fifo_size = (dev->fifo_size / 2); 1023 dev->fifo_size = (dev->fifo_size / 2);
1012 dev->b_hw = 1; /* Enable hardware fixes */ 1024 dev->b_hw = 1; /* Enable hardware fixes */
1013 } 1025 }
1026 /* calculate wakeup latency constraint for MPU */
1027 if (dev->set_mpu_wkup_lat != NULL)
1028 dev->latency = (1000000 * dev->fifo_size) /
1029 (1000 * speed / 8);
1014 } 1030 }
1015 1031
1016 /* reset ASAP, clearing any IRQs */ 1032 /* reset ASAP, clearing any IRQs */
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
new file mode 100644
index 000000000000..78ebf507ce56
--- /dev/null
+++ b/include/linux/i2c-omap.h
@@ -0,0 +1,9 @@
1#ifndef __I2C_OMAP_H__
2#define __I2C_OMAP_H__
3
4struct omap_i2c_bus_platform_data {
5 u32 clkrate;
6 void (*set_mpu_wkup_lat)(struct device *dev, long set);
7};
8
9#endif