Marcello, my "old" version is from the linuxppc_2_4_devel CVS archive on www.denx.de:/cvsroot. The i2c-algo-8xx.c there has the revision number 1.5.
Regards Cajus --- ../../i2c-algo-8xx.c 2005-08-10 16:19:09.000000000 +0200 +++ drivers/i2c/i2c-algo-8xx.c 2005-08-10 08:03:46.000000000 +0200 @@ -19,12 +19,19 @@ * moved into proper i2c interface; separated out platform specific * parts into i2c-rpx.c * Brad Parker (brad at heeltoe.com) + * + * added define for BUSY_WAIT and INTERRUPTIBLE_SLEEP, added I2C_ALGO_8XX_DATE + ..VERSION + * fixed bug in cpm_iic_read and cpm_iic_write (timeout never detected if count < 16) + * added force_reinit(): in certain cases (disturbances on the I2C bus) a timeout will + * occur. After this a complete re-initialisation will be necessary, otherwise all + * following transmissions will have a timeout. + * Cajus Hahn, 09.08.2005 */ // XXX todo // timeout sleep? -/* $Id: i2c-algo-8xx.c,v 1.7 2002/08/03 22:48:18 ac9410 Exp $ */ +/* $Id: i2c-algo-8xx.c,v 1.2 2005/08/10 06:03:46 cajus Exp $ */ #include <linux/kernel.h> #include <linux/module.h> @@ -43,8 +50,16 @@ #include <linux/i2c.h> #include <linux/i2c-algo-8xx.h> +#define I2C_ALGO_8XX_DATE "20050809" +#define I2C_ALGO_8XX_VERSION "2.6.2" + #define CPM_MAX_READ 513 /* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */ +#define I2C_BUSY_WAIT /* Uncomment this if you want to do a busy wait in cpm_iic_read and + cpm_iic_write. In a timeout case the CPU load will be 99.9% ! */ +#define I2C_INTERRUPTIBLE_SLEEP /* Uncomment this if you want the waiting in cpm_iic_read and + cpm_iic_write being interruptable by signals */ + static wait_queue_head_t iic_wait; static ushort r_tbase, r_rbase; @@ -73,7 +88,11 @@ /* Get 'me going again. */ +#ifdef I2C_INTERRUPTIBLE_SLEEP wake_up_interruptible(&iic_wait); +#else + wake_up(&iic_wait); +#endif } static void @@ -201,20 +220,77 @@ static void force_close(struct i2c_algo_8xx_data *cpm) { volatile i2c8xx_t *i2c = cpm->i2c; + + if (cpm_debug) + printk(KERN_DEBUG "force_close()"); + if (cpm->reloc == 0) { /* micro code disabled */ volatile cpm8xx_t *cp = cpm->cp; - - if (cpm_debug) printk(KERN_DEBUG "force_close()\n"); cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); } + i2c->i2c_i2cmr = 0x00; /* Disable all interrupts */ i2c->i2c_i2cer = 0xff; } +static void force_reinit(struct i2c_algo_8xx_data *cpm) +{ + volatile iic_t *iip = cpm->iip; + volatile i2c8xx_t *i2c = cpm->i2c; + volatile cpm8xx_t *cp = cpm->cp; + unsigned char brg; + bd_t *bd = (bd_t *)__res; + + // Disable interrupts. + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + // Clear enable + i2c->i2c_i2mod &= ~1; + + // Initialize the parameter ram. + iip->iic_rstate = 0; + iip->iic_rdp = 0; + iip->iic_rbptr = 0; + iip->iic_rbc = 0; + iip->iic_rxtmp = 0; + iip->iic_tstate = 0; + iip->iic_tdp = 0; + iip->iic_tbptr = 0; + iip->iic_tbc = 0; + iip->iic_txtmp = 0; + iip->iic_tbase = r_tbase; + iip->iic_rbase = r_rbase; + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + iip->iic_mrblr = CPM_MAX_READ; + + if (cpm->reloc == 0) + { + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + else + { + iip->iic_rbptr = iip->iic_rbase; + iip->iic_tbptr = iip->iic_tbase; + iip->iic_rstate = 0; + iip->iic_tstate = 0; + } + + // Select an arbitrary address. Just make sure it is unique. + i2c->i2c_i2add = 0xfe; + + // Make clock run at 60 KHz. + brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3); + i2c->i2c_i2brg = brg; + + i2c->i2c_i2mod = 0x00; + i2c->i2c_i2com = 0x01; /* Master mode */ +} /* Read from IIC... * abyte = address byte, with r/w flag already set @@ -227,7 +303,7 @@ volatile cpm8xx_t *cp = cpm->cp; volatile cbd_t *tbdf, *rbdf; u_char *tb; - unsigned long flags, tmo; + unsigned long flags, tmo, timedout; if (count >= CPM_MAX_READ) return -EINVAL; @@ -269,7 +345,10 @@ rbdf->cbd_bufaddr = __pa(buf); rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT; + timedout = 0; +#ifdef I2C_BUSY_WAIT if(count > 16){ +#endif /* Chip bug, set enable here */ local_irq_save(flags); i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ @@ -278,23 +357,40 @@ i2c->i2c_i2com |= 0x80; /* Begin transmission */ /* Wait for IIC transfer */ +#ifdef I2C_INTERRUPTIBLE_SLEEP tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); +#else + tmo = sleep_on_timeout(&iic_wait,1*HZ); +#endif + if(tmo == 0) timedout=1; local_irq_restore(flags); +#ifdef I2C_BUSY_WAIT } else { /* busy wait for small transfers, its faster */ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ i2c->i2c_i2cer = 0xff; i2c->i2c_i2mod |= 1; /* Enable */ i2c->i2c_i2com |= 0x80; /* Begin transmission */ tmo = jiffies + 1*HZ; - while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ + while(!(i2c->i2c_i2cer & 0x11 || (timedout = time_after(jiffies, tmo)))); /* Busy wait, with a timeout */ } +#endif + if(timedout) + { + printk(KERN_DEBUG "cpm_iic_read: timeout!\n"); + force_reinit(cpm); + return -EIO; + } + +#ifdef I2C_INTERRUPTIBLE_SLEEP + if (signal_pending(current)) + { + force_close(cpm); + if (cpm_debug) + printk(KERN_DEBUG "cpm_iic_read: signal_pending! \n"); + return -EINTR; + } +#endif - if (signal_pending(current) || !tmo){ - force_close(cpm); - if(cpm_debug) - printk(KERN_DEBUG "IIC read: timeout!\n"); - return -EIO; - } #ifdef I2C_CHIP_ERRATA /* Chip errata, clear enable. This is not needed on rev D4 CPUs. Disabling I2C too early may cause too short stop condition */ @@ -359,7 +455,7 @@ volatile cpm8xx_t *cp = cpm->cp; volatile cbd_t *tbdf; u_char *tb; - unsigned long flags, tmo; + unsigned long flags, tmo, timedout; /* check for and use a microcode relocation patch */ if (cpm->reloc) { @@ -385,7 +481,10 @@ tbdf[1].cbd_datlen = count; tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP; + timedout = 0; +#ifdef I2C_BUSY_WAIT if(count > 16){ +#endif /* Chip bug, set enable here */ local_irq_save(flags); i2c->i2c_i2cmr = 0x13; /* Enable some interupts */ @@ -394,23 +493,39 @@ i2c->i2c_i2com |= 0x80; /* Begin transmission */ /* Wait for IIC transfer */ +#ifdef I2C_INTERRUPTIBLE_SLEEP tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); +#else + tmo = sleep_on_timeout(&iic_wait,1*HZ); +#endif + if(tmo == 0) timedout=1; local_irq_restore(flags); +#ifdef I2C_BUSY_WAIT } else { /* busy wait for small transfers, its faster */ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */ i2c->i2c_i2cer = 0xff; i2c->i2c_i2mod |= 1; /* Enable */ i2c->i2c_i2com |= 0x80; /* Begin transmission */ tmo = jiffies + 1*HZ; - while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */ - } - - if (signal_pending(current) || !tmo){ - force_close(cpm); - if(cpm_debug && !tmo) - printk(KERN_DEBUG "IIC write: timeout!\n"); - return -EIO; + while(!(i2c->i2c_i2cer & 0x12 || (timedout = time_after(jiffies, tmo)))); /* Busy wait, with a timeout */ } +#endif + if(timedout) + { + printk(KERN_DEBUG "cpm_iic_write: timeout!\n"); + force_reinit(cpm); + return -EIO; + } + +#ifdef I2C_INTERRUPTIBLE_SLEEP + if (signal_pending(current)) + { + force_close(cpm); + if (cpm_debug) + printk(KERN_DEBUG "cpm_iic_write: signal_pending! \n"); + return -EINTR; + } +#endif #if I2C_CHIP_ERRATA /* Chip errata, clear enable. This is not needed on rev D4 CPUs. @@ -495,7 +610,11 @@ if (cpm_debug > 1) printk(KERN_DEBUG "about to sleep\n"); /* wait for IIC transfer */ +#ifdef I2C_INTERRUPTIBLE_SLEEP tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ); +#else + tmo = sleep_on_timeout(&iic_wait,1*HZ); +#endif local_irq_restore(flags); #ifdef I2C_CHIP_ERRATA @@ -658,7 +777,7 @@ int __init i2c_algo_8xx_init (void) { - printk(KERN_INFO "i2c-algo-8xx.o: i2c mpc8xx algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE); + printk(KERN_INFO "i2c-algo-8xx.o: i2c mpc8xx algorithm module version %s (%s)\n", I2C_ALGO_8XX_VERSION, I2C_ALGO_8XX_DATE); return 0; }