i2c-omap patches for 2.6.35 merge window
Subsystems (6)
Tony Lindgren
maintainercover i2c-omap patches for 2.6.35 merge window
Hi all,
Here are the i2c-omap patches that we'd like to get in for 2.6.35.
I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.
I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.
Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.
Regards,
Tony
---
Alexander Shishkin (2):
omap: i2c: make errata 1.153 workaround a separate function
omap: i2c: add a timeout to the busy waiting
Kalle Jokiniemi (1):
i2c-omap: add mpu wake up latency constraint in i2c
Santosh Shilimkar (1):
omap: i2c: Add i2c support on omap4 platform
manjugk manjugk (2):
OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
OMAP3: I2C: Clean up Errata 1p153 handling
arch/arm/plat-omap/i2c.c | 39 ++++-- drivers/i2c/busses/i2c-omap.c | 265 ++++++++++++++++++++++++++++++++--------- include/linux/i2c-omap.h | 9 + 3 files changed, 246 insertions(+), 67 deletions(-) create mode 100644 include/linux/i2c-omap.h
Signature · 1 line
Signature
A message that is not in the archive (sent off-list or not yet received): 20100511182854.15596.56293.stgit-XB442sTQ5VIxQTnqJstS8Q@public.gmane.org
PATCH 1/6 omap: i2c: Add i2c support on omap4 platform
From: Santosh Shilimkar <[email protected]>
This patch is rebased version of earlier post to add I2C driver support to OMAP4 platform. On OMAP4, all I2C register address offsets are changed from OMAP1/2/3 I2C. In order to not have #ifdef's at various places in code, as well as to support multi-OMAP build, an array is created to hold the register addresses with it's offset.
This patch was submitted, reviewed and acked on mailing list already. For more details refer below link
http://www.mail-archive.com/[email protected]/msg02281.html
This updated verion has a depedancy on "Add support for 16-bit registers" posted on linux-omap. Below is the patch-works link for the same
http://patchwork.kernel.org/patch/72295/
--- drivers/i2c/busses/i2c-omap.c | 146 ++++++++++++++++++++++++++++++++--------- 1 files changed, 114 insertions(+), 32 deletions(-)
drivers/i2c/busses/i2c-omap.c +114 -32
@@ -45,29 +45,37 @@/* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36#define OMAP_I2C_REV_ON_3430 0x3C +#define OMAP_I2C_REV_ON_4430 0x40/* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) -#define OMAP_I2C_REV_REG 0x00 -#define OMAP_I2C_IE_REG 0x01 -#define OMAP_I2C_STAT_REG 0x02 -#define OMAP_I2C_IV_REG 0x03/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ -#define OMAP_I2C_WE_REG 0x03 -#define OMAP_I2C_SYSS_REG 0x04 -#define OMAP_I2C_BUF_REG 0x05 -#define OMAP_I2C_CNT_REG 0x06 -#define OMAP_I2C_DATA_REG 0x07 -#define OMAP_I2C_SYSC_REG 0x08 -#define OMAP_I2C_CON_REG 0x09 -#define OMAP_I2C_OA_REG 0x0a -#define OMAP_I2C_SA_REG 0x0b -#define OMAP_I2C_PSC_REG 0x0c -#define OMAP_I2C_SCLL_REG 0x0d -#define OMAP_I2C_SCLH_REG 0x0e -#define OMAP_I2C_SYSTEST_REG 0x0f -#define OMAP_I2C_BUFSTAT_REG 0x10 +enum { +OMAP_I2C_REV_REG =0 , +OMAP_I2C_IE_REG , +OMAP_I2C_STAT_REG , +OMAP_I2C_IV_REG , +OMAP_I2C_WE_REG , +OMAP_I2C_SYSS_REG , +OMAP_I2C_BUF_REG , +OMAP_I2C_CNT_REG , +OMAP_I2C_DATA_REG , +OMAP_I2C_SYSC_REG , +OMAP_I2C_CON_REG , +OMAP_I2C_OA_REG , +OMAP_I2C_SA_REG , +OMAP_I2C_PSC_REG , +OMAP_I2C_SCLL_REG , +OMAP_I2C_SCLH_REG , +OMAP_I2C_SYSTEST_REG , +OMAP_I2C_BUFSTAT_REG , +OMAP_I2C_REVNB_LO , +OMAP_I2C_REVNB_HI , +OMAP_I2C_IRQSTATUS_RAW , +OMAP_I2C_IRQENABLE_SET , +OMAP_I2C_IRQENABLE_CLR , +};/* I2C Interrupt Enable Register (OMAP_I2C_IE): */ #define OMAP_I2C_IE_XDR (1 << 14)/* TX Buffer drain int enable */
@@ -170,6 +178,7 @@ struct omap_i2c_dev {u32 speed;/* Speed of bus in Khz */ u16 cmd_err;u8 *buf; +u8 *regs;size_t buf_len;struct i2c_adapter adapter;u8 fifo_size;/* use as flag and value
@@ -188,15 +197,64 @@ struct omap_i2c_dev {u16 westate; }; +const static u8 reg_map[] = { + [OMAP_I2C_REV_REG ] =0x00 , + [OMAP_I2C_IE_REG ] =0x01 , + [OMAP_I2C_STAT_REG ] =0x02 , + [OMAP_I2C_IV_REG ] =0x03 , + [OMAP_I2C_WE_REG ] =0x03 , + [OMAP_I2C_SYSS_REG ] =0x04 , + [OMAP_I2C_BUF_REG ] =0x05 , + [OMAP_I2C_CNT_REG ] =0x06 , + [OMAP_I2C_DATA_REG ] =0x07 , + [OMAP_I2C_SYSC_REG ] =0x08 , + [OMAP_I2C_CON_REG ] =0x09 , + [OMAP_I2C_OA_REG ] =0x0a , + [OMAP_I2C_SA_REG ] =0x0b , + [OMAP_I2C_PSC_REG ] =0x0c , + [OMAP_I2C_SCLL_REG ] =0x0d , + [OMAP_I2C_SCLH_REG ] =0x0e , + [OMAP_I2C_SYSTEST_REG ] =0x0f , + [OMAP_I2C_BUFSTAT_REG ] =0x10 , +}; + +const static u8 omap4_reg_map[] = { + [OMAP_I2C_REV_REG ] =0x04 , + [OMAP_I2C_IE_REG ] =0x2c , + [OMAP_I2C_STAT_REG ] =0x28 , + [OMAP_I2C_IV_REG ] =0x34 , + [OMAP_I2C_WE_REG ] =0x34 , + [OMAP_I2C_SYSS_REG ] =0x90 , + [OMAP_I2C_BUF_REG ] =0x94 , + [OMAP_I2C_CNT_REG ] =0x98 , + [OMAP_I2C_DATA_REG ] =0x9c , + [OMAP_I2C_SYSC_REG ] =0x20 , + [OMAP_I2C_CON_REG ] =0xa4 , + [OMAP_I2C_OA_REG ] =0xa8 , + [OMAP_I2C_SA_REG ] =0xac , + [OMAP_I2C_PSC_REG ] =0xb0 , + [OMAP_I2C_SCLL_REG ] =0xb4 , + [OMAP_I2C_SCLH_REG ] =0xb8 , + [OMAP_I2C_SYSTEST_REG ] =0xbC , + [OMAP_I2C_BUFSTAT_REG ] =0xc0 , + [OMAP_I2C_REVNB_LO ] =0x00 , + [OMAP_I2C_REVNB_HI ] =0x04 , + [OMAP_I2C_IRQSTATUS_RAW ] =0x24 , + [OMAP_I2C_IRQENABLE_SET ] =0x2c , + [OMAP_I2C_IRQENABLE_CLR ] =0x30 , +}; +static inline void omap_i2c_write_reg (struct omap_i2c_dev *i2c_dev,int reg,u16 val) { -__raw_writew (val, i2c_dev->base + (reg << i2c_dev->reg_shift)); +__raw_writew (val, i2c_dev->base + + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); }static inline u16 omap_i2c_read_reg (struct omap_i2c_dev *i2c_dev,int reg) { -return __raw_readw (i2c_dev->base + (reg << i2c_dev->reg_shift)); +return __raw_readw (i2c_dev->base + + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); }static int __init omap_i2c_get_clocks (struct omap_i2c_dev *dev)
@@ -265,7 +323,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)WARN_ON (dev->idle); dev->iestate =omap_i2c_read_reg (dev,OMAP_I2C_IE_REG ); -omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 ); +if (dev->rev >=OMAP_I2C_REV_ON_4430 ) +omap_i2c_write_reg (dev,OMAP_I2C_IRQENABLE_CLR ,1 ); +else +omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 ); +if (dev->rev <OMAP_I2C_REV_2 ) { iv =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG );/* Read clears */ }else {
@@ -330,7 +392,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)* REVISIT: Some wkup sources might not be needed. */ dev->westate =OMAP_I2C_WE_ALL ; -omap_i2c_write_reg (dev,OMAP_I2C_WE_REG , dev->westate); +if (dev->rev <OMAP_I2C_REV_ON_4430 ) +omap_i2c_write_reg (dev,OMAP_I2C_WE_REG , + dev->westate); } }omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,0 );
@@ -357,7 +421,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate /12000000 ; } -if (cpu_is_omap2430 () ||cpu_is_omap34xx ()) { +if (!(cpu_class_is_omap1 () ||cpu_is_omap2420 ())) {/* * HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -747,9 +811,12 @@ complete:if (dev->buf_len) { *dev->buf++ = w; dev->buf_len--; -/* Data reg from 2430 is 8 bit wide */ -if (!cpu_is_omap2430 () && - !cpu_is_omap34xx ()) { +/* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ +if (cpu_class_is_omap1 () || +cpu_is_omap2420 ()) {if (dev->buf_len) { *dev->buf++ = w >>8 ; dev->buf_len--;
@@ -787,9 +854,12 @@ complete:if (dev->buf_len) { w = *dev->buf++; dev->buf_len--; -/* Data reg from 2430 is 8 bit wide */ -if (!cpu_is_omap2430 () && - !cpu_is_omap34xx ()) { +/* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ +if (cpu_class_is_omap1 () || +cpu_is_omap2420 ()) {if (dev->buf_len) { w |= *dev->buf++ <<8 ; dev->buf_len--;
@@ -905,17 +975,24 @@ omap_i2c_probe(struct platform_device *pdev)if (cpu_is_omap7xx ()) dev->reg_shift =1 ; +else if (cpu_is_omap44xx ()) + dev->reg_shift =0 ;else dev->reg_shift =2 ;if ((r =omap_i2c_get_clocks (dev)) !=0 ) goto err_iounmap; +if (cpu_is_omap44xx ()) + dev->regs = (u8 *) omap4_reg_map; +else + dev->regs = (u8 *) reg_map; +omap_i2c_unidle (dev); dev->rev =omap_i2c_read_reg (dev,OMAP_I2C_REV_REG ) &0xff ; -if (cpu_is_omap2430 () ||cpu_is_omap34xx ()) { +if (!(cpu_class_is_omap1 () ||cpu_is_omap2420 ())) {u16 s;/* Set up the fifo size - Get total size */
@@ -927,8 +1004,13 @@ omap_i2c_probe(struct platform_device *pdev)* size. This is to ensure that we can handle the status on int * call back latencies. */ - dev->fifo_size = (dev->fifo_size /2 ); - dev->b_hw =1 ;/* Enable hardware fixes */ +if (dev->rev >=OMAP_I2C_REV_ON_4430 ) { + dev->fifo_size =0 ; + dev->b_hw =0 ;/* Disable hardware fixes */ + }else { + dev->fifo_size = (dev->fifo_size /2 ); + dev->b_hw =1 ;/* Enable hardware fixes */ + } }/* reset ASAP, clearing any IRQs */
PATCH 2/6 i2c-omap: add mpu wake up latency constraint in i2c
In reply to a message not in the archiveFrom: Kalle Jokiniemi <[email protected]>
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.
--- arch/arm/plat-omap/i2c.c | 39 +++++++++++++++++++++++++++------------ drivers/i2c/busses/i2c-omap.c | 24 ++++++++++++++++++++---- include/linux/i2c-omap.h | 9 +++++++++ 3 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 include/linux/i2c-omap.h
arch/arm/plat-omap/i2c.c +27 -12
@@ -26,9 +26,12 @@#include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/i2c-omap.h> +#include <mach/irqs.h> #include <plat/mux.h> #include <plat/i2c.h> +#include <plat/omap-pm.h> #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); }
drivers/i2c/busses/i2c-omap.c +20 -4
@@ -38,6 +38,7 @@#include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/i2c-omap.h> /* I2C controller revisions */ #define OMAP_I2C_REV_2 0x20
@@ -175,6 +176,9 @@ struct omap_i2c_dev {struct clk *fclk;/* Functional clock */ struct completion cmd_complete;struct resource *ioarea; +u32 latency;/* maximum mpu wkup latency */ +void (*set_mpu_wkup_lat)(struct device *dev, +long latency);u32 speed;/* Speed of bus in Khz */ u16 cmd_err;u8 *buf;
@@ -603,8 +607,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,* REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ +if (dev->set_mpu_wkup_lat !=NULL ) + dev->set_mpu_wkup_lat (dev->dev, dev->latency); r =wait_for_completion_timeout (&dev->cmd_complete,OMAP_I2C_TIMEOUT ); +if (dev->set_mpu_wkup_lat !=NULL ) + dev->set_mpu_wkup_lat (dev->dev,-1 ); dev->buf_len =0 ;if (r <0 )return r;
@@ -927,6 +935,7 @@ omap_i2c_probe(struct platform_device *pdev)struct omap_i2c_dev *dev;struct i2c_adapter *adap;struct resource *mem, *irq, *ioarea; +struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;irq_handler_t isr;int r;u32 speed =0 ;
@@ -956,10 +965,13 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } -if (pdev->dev.platform_data !=NULL ) - speed = *(u32 *)pdev->dev.platform_data; -else - speed =100 ;/* Defualt speed */ +if (pdata !=NULL ) { + speed = pdata->clkrate; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + }else { + speed =100 ;/* Default speed */ + dev->set_mpu_wkup_lat =NULL ; + } dev->speed = speed; dev->idle =1 ;
@@ -1011,6 +1023,10 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size /2 ); dev->b_hw =1 ;/* Enable hardware fixes */ } +/* calculate wakeup latency constraint for MPU */ +if (dev->set_mpu_wkup_lat !=NULL ) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * speed /8 ); }/* reset ASAP, clearing any IRQs */
include/linux/i2c-omap.h new file +9 -0
@@ -0,0 +1,9 @@ +#ifndef __I2C_OMAP_H__ +#define __I2C_OMAP_H__ + +struct omap_i2c_bus_platform_data { +u32 clkrate; +void (*set_mpu_wkup_lat)(struct device *dev,long set); +}; + +#endif
PATCH 3/6 omap: i2c: make errata 1.153 workaround a separate function
In reply to a message not in the archiveFrom: Alexander Shishkin <[email protected]>
This is to avoid insanely long lines and levels of indentation.
--- drivers/i2c/busses/i2c-omap.c | 43 +++++++++++++++++++++++------------------ 1 files changed, 24 insertions(+), 19 deletions(-)
drivers/i2c/busses/i2c-omap.c +24 -19
@@ -756,6 +756,27 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)#define omap_i2c_rev1_isr NULL#endif +/* +* OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing +* data to DATA_REG. Otherwise some data bytes can be lost while transferring +* them from the memory to the I2C interface. +*/ +static int errata_omap3_1p153 (struct omap_i2c_dev *dev,u16 *stat,int *err) +{ +while (!(*stat &OMAP_I2C_STAT_XUDF )) { +if (*stat & (OMAP_I2C_STAT_NACK |OMAP_I2C_STAT_AL )) { +omap_i2c_ack_stat (dev, *stat & (OMAP_I2C_STAT_XRDY | +OMAP_I2C_STAT_XDR )); + *err |=OMAP_I2C_STAT_XUDF ; +return -ETIMEDOUT ; + } +cpu_relax (); + *stat =omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ); + } + +return 0 ; +} +static irqreturn_t omap_i2c_isr (int this_irq,void *dev_id) {
@@ -885,25 +906,9 @@ complete:break ; } -/* -* OMAP3430 Errata 1.153: When an XRDY/XDR -* is hit, wait for XUDF before writing data -* to DATA_REG. Otherwise some data bytes can -* be lost while transferring them from the -* memory to the I2C interface. -*/ - -if (dev->rev <=OMAP_I2C_REV_ON_3430 ) { -while (!(stat &OMAP_I2C_STAT_XUDF )) { -if (stat & (OMAP_I2C_STAT_NACK |OMAP_I2C_STAT_AL )) { -omap_i2c_ack_stat (dev, stat & (OMAP_I2C_STAT_XRDY |OMAP_I2C_STAT_XDR )); - err |=OMAP_I2C_STAT_XUDF ; - goto complete; - } -cpu_relax (); - stat =omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ); - } - } +if ((dev->rev <=OMAP_I2C_REV_ON_3430 ) && +errata_omap3_1p153 (dev, &stat, &err)) + goto complete;omap_i2c_write_reg (dev,OMAP_I2C_DATA_REG , w); }
PATCH 4/6 omap: i2c: add a timeout to the busy waiting
In reply to a message not in the archiveFrom: Alexander Shishkin <[email protected]>
The errata 1.153 workaround is busy waiting on XUDF bit in interrupt context, which may lead to kernel hangs. The problem can be reproduced by running the bus with wrong (too high) speed.
--- drivers/i2c/busses/i2c-omap.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-omap.c +9 -1
@@ -763,17 +763,25 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)*/ static int errata_omap3_1p153 (struct omap_i2c_dev *dev,u16 *stat,int *err) { -while (!(*stat &OMAP_I2C_STAT_XUDF )) { +unsigned long timeout =10000 ; + +while (--timeout && !(*stat &OMAP_I2C_STAT_XUDF )) {if (*stat & (OMAP_I2C_STAT_NACK |OMAP_I2C_STAT_AL )) {omap_i2c_ack_stat (dev, *stat & (OMAP_I2C_STAT_XRDY |OMAP_I2C_STAT_XDR )); *err |=OMAP_I2C_STAT_XUDF ;return -ETIMEDOUT ; } +cpu_relax (); *stat =omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ); } +if (!timeout) { +dev_err (dev->dev,"timeout waiting on XUDF bit\n" ); +return 0 ; + } +return 0 ; }
PATCH 5/6 OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
In reply to a message not in the archiveFrom: manjugk manjugk <[email protected]>
Under certain rare conditions, I2C_STAT[13].RDR bit may be set and the corresponding interrupt fire, even there is no data in the receive FIFO, or the I2C data transfer is still ongoing. These spurious RDR events must be ignored by the software.
This patch handles and ignores RDR spurious interrupts.
The below sequence is required in interrupt handler for handling this errata:
1. If RDR is set to 1, clear RDR
2. Read I2C status register and check for BusBusy bit. If BusBusy bit is set, skip remaining steps.
3. If BusBusy bit is not set, perform read operation on I2C status register.
4. If RDR is set, clear the same. Check RDR again and clear if it sets RDR bit again.
5. Perform I2C Data Read operation N number of times(where N is value read from the register BUFSTAT-RXSTAT bit fields).
Note:
This errata is not applicable for omap2420 and omap4. It is applicable for:
1. omap2430
2. omap34xx(including omap3630).
--- drivers/i2c/busses/i2c-omap.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 40 insertions(+), 0 deletions(-)
drivers/i2c/busses/i2c-omap.c +40 -0
@@ -166,6 +166,8 @@ enum {#define SYSC_IDLEMODE_SMART 0x2#define SYSC_CLOCKACTIVITY_FCLK 0x2 +/* Errata definitions */ +#define I2C_OMAP_ERRATA_I207 (1 << 0)struct omap_i2c_dev {struct device *dev;
@@ -199,6 +201,7 @@ struct omap_i2c_dev {u16 bufstate;u16 syscstate;u16 westate; +u16 errata; };const static u8 reg_map[] = {
@@ -498,6 +501,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)/* Take the I2C module out of reset: */ omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,OMAP_I2C_CON_EN ); + dev->errata =0 ; + +if (cpu_is_omap2430 () ||cpu_is_omap34xx ()) + dev->errata |=I2C_OMAP_ERRATA_I207 ; +/* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -695,6 +703,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)omap_i2c_write_reg (dev,OMAP_I2C_STAT_REG , stat); } +static inline void i2c_omap_errata_i207 (struct omap_i2c_dev *dev,u16 stat) +{ +/* +* I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8) +* Not applicable for OMAP4. +* Under certain rare conditions, RDR could be set again +* when the bus is busy, then ignore the interrupt and +* clear the interrupt. +*/ +if (stat &OMAP_I2C_STAT_RDR ) { +/* Step 1: If RDR is set, clear it */ +omap_i2c_ack_stat (dev,OMAP_I2C_STAT_RDR ); + +/* Step 2: */ +if (!(omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ) + &OMAP_I2C_STAT_BB )) { + +/* Step 3: */ +if (omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ) + &OMAP_I2C_STAT_RDR ) { +omap_i2c_ack_stat (dev,OMAP_I2C_STAT_RDR ); +dev_dbg (dev->dev,"RDR when bus is busy.\n" ); + } + + } + } +} +/* rev1 devices are apparently only on some 15xx */ #ifdef CONFIG_ARCH_OMAP15XX
@@ -834,6 +870,10 @@ complete: }if (stat & (OMAP_I2C_STAT_RRDY |OMAP_I2C_STAT_RDR )) {u8 num_bytes =1 ; + +if (dev->errata &I2C_OMAP_ERRATA_I207 ) +i2c_omap_errata_i207 (dev, stat); +if (dev->fifo_size) {if (stat &OMAP_I2C_STAT_RRDY ) num_bytes = dev->fifo_size;
Ben Dooks
AppliedQuoted 8 lines · Tony Lindgren
Hi all,
Here are the i2c-omap patches that we'd like to get in for 2.6.35.
I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.
Quoted 6 lines
I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.
Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.
I've applied these to for-2635/i2c-omap to get them into -next
please keep the start of each commit the same, I prefer i2c-omap:
thanks.
Quoted 33 lines
Regards,
Tony
---
Alexander Shishkin (2):
omap: i2c: make errata 1.153 workaround a separate function
omap: i2c: add a timeout to the busy waitingKalle Jokiniemi (1):
i2c-omap: add mpu wake up latency constraint in i2cSantosh Shilimkar (1):
omap: i2c: Add i2c support on omap4 platformmanjugk manjugk (2):
OMAP2/3: I2C: Errata ID i207: Clear wrong RDR interrupt
OMAP3: I2C: Clean up Errata 1p153 handlingarch/arm/plat-omap/i2c.c | 39 ++++-- drivers/i2c/busses/i2c-omap.c | 265 ++++++++++++++++++++++++++++++++--------- include/linux/i2c-omap.h | 9 + 3 files changed, 246 insertions(+), 67 deletions(-) create mode 100644 include/linux/i2c-omap.hSignature · 5 lines
Signature -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/) 'a smiley only costs 4 bytes'
Tony Lindgren
maintainerQuoted 9 lines · Ben Dooks
Quoted 8 lines · Tony Lindgren
Hi all,
Here are the i2c-omap patches that we'd like to get in for 2.6.35.
I believe all of these patches have been posted earlier already to the i2c list. They all have been merged into the linux-omap master branch for testing.
Quoted 8 lines
Quoted 6 lines
I've removed some duplicate Cc fields from the commit messages for the obvious mailings lists and the people who will be merging them.
Anyways, if no comments over the next few days, I'll reply to this message with a pull request for Ben.
I've applied these to for-2635/i2c-omap to get them into -next
OK, thanks!
Quoted 1 line
please keep the start of each commit the same, I prefer i2c-omap:
OK
Regards,
Tony
Tony Lindgren
maintainerPATCH 6/6 OMAP3: I2C: Clean up Errata 1p153 handling
In reply to Tony LindgrenFrom: manjugk manjugk <[email protected]>
Clean up existing Errata 1p153 handling to use generic errata handling mechanism through dev flag.
--- drivers/i2c/busses/i2c-omap.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-omap.c +5 -1
@@ -168,6 +168,7 @@ enum {/* Errata definitions */ #define I2C_OMAP_ERRATA_I207 (1 << 0) +#define I2C_OMAP3_1P153 (1 << 1)struct omap_i2c_dev {struct device *dev;
@@ -954,7 +955,7 @@ complete:break ; } -if ((dev->rev <=OMAP_I2C_REV_ON_3430 ) && +if ((dev->errata &I2C_OMAP3_1P153 ) &&errata_omap3_1p153 (dev, &stat, &err)) goto complete;
@@ -1057,6 +1058,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->rev =omap_i2c_read_reg (dev,OMAP_I2C_REV_REG ) &0xff ; +if (dev->rev <=OMAP_I2C_REV_ON_3430 ) + dev->errata |=I2C_OMAP3_1P153 ; +if (!(cpu_class_is_omap1 () ||cpu_is_omap2420 ())) {u16 s;