From 20c9d2c4ab8243a1c311248232954b2c1da3ba75 Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Tue, 11 May 2010 11:35:08 -0700 Subject: 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 Cc: Jarkko Nikula Cc: Paul Walmsley Cc: Nishanth Menon Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman Signed-off-by: Tony Lindgren Signed-off-by: Ben Dooks --- arch/arm/plat-omap/i2c.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'arch/arm/plat-omap') 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 @@ #include #include #include +#include + #include #include #include +#include #define OMAP_I2C_SIZE 0x3f #define OMAP1_I2C_BASE 0xfffb3800 @@ -70,14 +73,14 @@ static struct resource i2c_resources[][2] = { }, \ } -static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; +static struct omap_i2c_bus_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)]; static struct platform_device omap_i2c_devices[] = { - I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), + I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]), #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), + I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]), #endif #if defined(CONFIG_ARCH_OMAP3) - I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]), + I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]), #endif }; @@ -100,10 +103,12 @@ static int __init omap_i2c_nr_ports(void) static int __init omap_i2c_add_bus(int bus_id) { struct platform_device *pdev; + struct omap_i2c_bus_platform_data *pd; struct resource *res; resource_size_t base, irq; pdev = &omap_i2c_devices[bus_id - 1]; + pd = pdev->dev.platform_data; if (bus_id == 1) { res = pdev->resource; if (cpu_class_is_omap1()) { @@ -123,6 +128,15 @@ static int __init omap_i2c_add_bus(int bus_id) if (cpu_class_is_omap2()) omap2_i2c_mux_pins(bus_id); + /* + * 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 (cpu_is_omap34xx()) + pd->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat; + return platform_device_register(pdev); } @@ -146,8 +160,8 @@ static int __init omap_i2c_bus_setup(char *str) get_options(str, 3, ints); if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports) return 0; - i2c_rate[ints[1] - 1] = ints[2]; - i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP; + i2c_pdata[ints[1] - 1].clkrate = ints[2]; + i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP; return 1; } @@ -161,9 +175,9 @@ static int __init omap_register_i2c_bus_cmdline(void) { int i, err = 0; - for (i = 0; i < ARRAY_SIZE(i2c_rate); i++) - if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) { - i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP; + for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++) + if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) { + i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP; err = omap_i2c_add_bus(i + 1); if (err) goto out; @@ -197,9 +211,10 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate, return err; } - if (!i2c_rate[bus_id - 1]) - i2c_rate[bus_id - 1] = clkrate; - i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP; + if (!i2c_pdata[bus_id - 1].clkrate) + i2c_pdata[bus_id - 1].clkrate = clkrate; + + i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP; return omap_i2c_add_bus(bus_id); } -- cgit v1.2.3 From b32dd41ed645c22ac3ce4e25bcbd7eee30297292 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 20 May 2010 11:36:43 -0700 Subject: omap: Fix i2c platform init code for omap4 Add separate omap_i2c_add_bus functions for mach-omap1 and mach-omap2. Make the mach-omap2 init set the interrupt dynamically to support. This is needed to add support for omap4 in a way that works with multi-omap builds. This will eventually get fixed in a generic way with the omap hwmods. Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/i2c.c | 67 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 20 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index f044b5927508..78d1cea9118d 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -100,33 +100,44 @@ static int __init omap_i2c_nr_ports(void) return ports; } -static int __init omap_i2c_add_bus(int bus_id) +/* Shared between omap2 and 3 */ +static resource_size_t omap2_i2c_irq[3] __initdata = { + INT_24XX_I2C1_IRQ, + INT_24XX_I2C2_IRQ, + INT_34XX_I2C3_IRQ, +}; + +static inline int omap1_i2c_add_bus(struct platform_device *pdev, int bus_id) { - struct platform_device *pdev; struct omap_i2c_bus_platform_data *pd; struct resource *res; - resource_size_t base, irq; - pdev = &omap_i2c_devices[bus_id - 1]; pd = pdev->dev.platform_data; + res = pdev->resource; + res[0].start = OMAP1_I2C_BASE; + res[0].end = res[0].start + OMAP_I2C_SIZE; + res[1].start = INT_I2C; + omap1_i2c_mux_pins(bus_id); + + return platform_device_register(pdev); +} + +static inline int omap2_i2c_add_bus(struct platform_device *pdev, int bus_id) +{ + struct resource *res; + resource_size_t *irq; + + res = pdev->resource; + + irq = omap2_i2c_irq; + if (bus_id == 1) { - res = pdev->resource; - if (cpu_class_is_omap1()) { - base = OMAP1_I2C_BASE; - irq = INT_I2C; - } else { - base = OMAP2_I2C_BASE1; - irq = INT_24XX_I2C1_IRQ; - } - res[0].start = base; - res[0].end = base + OMAP_I2C_SIZE; - res[1].start = irq; + res[0].start = OMAP2_I2C_BASE1; + res[0].end = res[0].start + OMAP_I2C_SIZE; } - if (cpu_class_is_omap1()) - omap1_i2c_mux_pins(bus_id); - if (cpu_class_is_omap2()) - omap2_i2c_mux_pins(bus_id); + res[1].start = irq[bus_id - 1]; + omap2_i2c_mux_pins(bus_id); /* * When waiting for completion of a i2c transfer, we need to @@ -134,12 +145,28 @@ static int __init omap_i2c_add_bus(int bus_id) * ensure quick enough wakeup from idle, when transfer * completes. */ - if (cpu_is_omap34xx()) + if (cpu_is_omap34xx()) { + struct omap_i2c_bus_platform_data *pd; + + pd = pdev->dev.platform_data; pd->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat; + } return platform_device_register(pdev); } +static int __init omap_i2c_add_bus(int bus_id) +{ + struct platform_device *pdev; + + pdev = &omap_i2c_devices[bus_id - 1]; + + if (cpu_class_is_omap1()) + return omap1_i2c_add_bus(pdev, bus_id); + else + return omap2_i2c_add_bus(pdev, bus_id); +} + /** * omap_i2c_bus_setup - Process command line options for the I2C bus speed * @str: String of options -- cgit v1.2.3 From 6daa642d9b8ec762b3c5641cd5e5fa855a5405bf Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 20 May 2010 11:36:43 -0700 Subject: omap4: Add support for i2c init Add support for i2c init for omap4. This patch is based on and earlier patch by Santosh Shilimkar . Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/i2c.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 78d1cea9118d..eec2b4993c69 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -38,6 +38,7 @@ #define OMAP2_I2C_BASE1 0x48070000 #define OMAP2_I2C_BASE2 0x48072000 #define OMAP2_I2C_BASE3 0x48060000 +#define OMAP4_I2C_BASE4 0x48350000 static const char name[] = "i2c_omap"; @@ -54,11 +55,14 @@ static const char name[] = "i2c_omap"; static struct resource i2c_resources[][2] = { { I2C_RESOURCE_BUILDER(0, 0) }, -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) }, +#if defined(CONFIG_ARCH_OMAP2PLUS) + { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, 0) }, #endif -#if defined(CONFIG_ARCH_OMAP3) - { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) }, +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) + { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, 0) }, +#endif +#if defined(CONFIG_ARCH_OMAP4) + { I2C_RESOURCE_BUILDER(OMAP4_I2C_BASE4, 0) }, #endif }; @@ -76,12 +80,15 @@ static struct resource i2c_resources[][2] = { static struct omap_i2c_bus_platform_data i2c_pdata[ARRAY_SIZE(i2c_resources)]; static struct platform_device omap_i2c_devices[] = { I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]), -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) +#if defined(CONFIG_ARCH_OMAP2PLUS) I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]), #endif -#if defined(CONFIG_ARCH_OMAP3) +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]), #endif +#if defined(CONFIG_ARCH_OMAP4) + I2C_DEV_BUILDER(4, i2c_resources[3], &i2c_pdata[3]), +#endif }; #define OMAP_I2C_CMDLINE_SETUP (BIT(31)) @@ -96,6 +103,8 @@ static int __init omap_i2c_nr_ports(void) ports = 2; else if (cpu_is_omap34xx()) ports = 3; + else if (cpu_is_omap44xx()) + ports = 4; return ports; } @@ -107,6 +116,13 @@ static resource_size_t omap2_i2c_irq[3] __initdata = { INT_34XX_I2C3_IRQ, }; +static resource_size_t omap4_i2c_irq[4] __initdata = { + OMAP44XX_IRQ_I2C1, + OMAP44XX_IRQ_I2C2, + OMAP44XX_IRQ_I2C3, + OMAP44XX_IRQ_I2C4, +}; + static inline int omap1_i2c_add_bus(struct platform_device *pdev, int bus_id) { struct omap_i2c_bus_platform_data *pd; @@ -129,7 +145,10 @@ static inline int omap2_i2c_add_bus(struct platform_device *pdev, int bus_id) res = pdev->resource; - irq = omap2_i2c_irq; + if (!cpu_is_omap44xx()) + irq = omap2_i2c_irq; + else + irq = omap4_i2c_irq; if (bus_id == 1) { res[0].start = OMAP2_I2C_BASE1; -- cgit v1.2.3