All of lore.kernel.org
 help / color / mirror / Atom feed
From: trini@kernel.crashing.org (Tom Rini)
To: lm-sensors@vger.kernel.org
Subject: 8xx i2c refers to unspecified chip errata
Date: Thu, 19 May 2005 06:23:42 +0000	[thread overview]
Message-ID: <20021118194555.GD18374@opus.bloom.county> (raw)
In-Reply-To: <IGEFJKJNHJDCBKALBJLLEEEIFHAA.joakim.tjernlund@lumentis.se>

On Mon, Nov 18, 2002 at 02:04:21PM -0500, Mark D. Studebaker wrote:

> whatever your patch was against didn't match our tree very well. would
> you please
> resolve the differences and generate a new patch against our tree?
> thanks

Here's a patch vs current i2c CVS (HEAD, if that makes a difference),
which brings things back into line.

Let me know when you commit this, and I'll bring the linuxppc BK trees
back into line.

-- 
Tom Rini (TR1265)
http://gate.crashing.org/~trini/

Index: i2c-algo-8xx.c
=================================RCS file: /home/cvs/i2c/kernel/i2c-algo-8xx.c,v
retrieving revision 1.7
diff -u -r1.7 i2c-algo-8xx.c
--- i2c-algo-8xx.c	2002/08/03 22:48:18	1.7
+++ i2c-algo-8xx.c	2002/11/18 20:40:55
@@ -44,25 +44,25 @@
 #include <linux/i2c-algo-8xx.h>
 
 #define CPM_MAX_READ	513
-
+/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */
 static wait_queue_head_t iic_wait;
 static ushort r_tbase, r_rbase;
 
-int cpm_scan = 1;
+int cpm_scan = 0;
 int cpm_debug = 0;
 
-static void
-cpm_iic_interrupt(void *dev_id, void *regs)
+static  void
+cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
 {
 	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
-
 	if (cpm_debug > 1)
 		printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id);
-
-	/* Chip errata, clear enable.
-	*/
-	i2c->i2c_i2mod = 0;
-
+#if 0
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs */
+        /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */
+        /* Someone with a buggy CPU needs to confirm that */
+	i2c->i2c_i2mod &= ~1;
+#endif
 	/* Clear interrupt.
 	*/
 	i2c->i2c_i2cer = 0xff;
@@ -77,8 +77,10 @@
 {
 	volatile iic_t		*iip = cpm_adap->iip;
 	volatile i2c8xx_t	*i2c = cpm_adap->i2c;
+	unsigned char brg;
+	bd_t *bd = (bd_t *)__res;
 
-	if (cpm_debug) printk("cpm_iic_init() - iip=%p\n",iip);
+	if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n");
 
 	/* Initialize the parameter ram.
 	 * We need to make sure many things are initialized to zero,
@@ -115,15 +117,24 @@
 		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 = 0x34;
+	i2c->i2c_i2add = 0xfe;
 
-	/* Make clock run maximum slow.
+	/* Make clock run at 60 KHz.
 	*/
-	i2c->i2c_i2brg = 7;
+	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
+	i2c->i2c_i2brg = brg;
+
+	i2c->i2c_i2mod = 0x00; 
+	i2c->i2c_i2com = 0x01; /* Master mode */
 
 	/* Disable interrupts.
 	*/
@@ -149,7 +160,7 @@
 
 	/* Shut down IIC.
 	*/
-	i2c->i2c_i2mod = 0;
+	i2c->i2c_i2mod &= ~1;
 	i2c->i2c_i2cmr = 0;
 	i2c->i2c_i2cer = 0xff;
 
@@ -169,22 +180,24 @@
 
 	iip->iic_rstate = 0;
 	iip->iic_rdp = 0;
-	iip->iic_rbptr = r_rbase;
+	iip->iic_rbptr = iip->iic_rbase;
 	iip->iic_rbc = 0;
 	iip->iic_rxtmp = 0;
 	iip->iic_tstate = 0;
 	iip->iic_tdp = 0;
-	iip->iic_tbptr = r_tbase;
+	iip->iic_tbptr = iip->iic_tbase;
 	iip->iic_tbc = 0;
 	iip->iic_txtmp = 0;
 }
 
 #define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
 #define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
 
 static void force_close(struct i2c_algo_8xx_data *cpm)
 {
-	if (cpm->reloc = 0) {
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc = 0) { /* micro code disabled */
 		volatile cpm8xx_t *cp = cpm->cp;
 
 		if (cpm_debug) printk("force_close()\n");
@@ -194,6 +207,8 @@
 
 		while (cp->cp_cpcr & CPM_CR_FLG);
 	}
+	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
+	i2c->i2c_i2cer = 0xff; 
 }
 
 
@@ -208,7 +223,7 @@
 	volatile cpm8xx_t *cp = cpm->cp;
 	volatile cbd_t	*tbdf, *rbdf;
 	u_char *tb;
-	unsigned long flags;
+	unsigned long flags, tmo;
 
 	if (count >= CPM_MAX_READ)
 		return -EINVAL;
@@ -225,9 +240,6 @@
 	 * All that is used is the first byte for address, the remainder
 	 * is just used for timing (and doesn't really have to exist).
 	 */
-	if (cpm->reloc) {
-		cpm_reset_iic_params(iip);
-	}
 	tb = cpm->temp;
 	tb = (u_char *)(((uint)tb + 15) & ~15);
 	tb[0] = abyte;		/* Device address byte w/rw flag */
@@ -239,56 +251,94 @@
 	tbdf->cbd_bufaddr = __pa(tb);
 	tbdf->cbd_datlen = count + 1;
 	tbdf->cbd_sc -		BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST |
+		BD_SC_READY | BD_SC_LAST |
 		BD_SC_WRAP | BD_IIC_START;
 
-	rbdf->cbd_datlen = 0;
-	rbdf->cbd_bufaddr = __pa(buf);
-	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	iip->iic_mrblr = count +1; /* prevent excessive read, +1
+				      is needed otherwise will the
+				      RXB interrupt come too early */
 
-	invalidate_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+	/* flush will invalidate too. */
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
 
-	/* Chip bug, set enable here */
-	local_irq_save(flags);
-	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
-	i2c->i2c_i2cer = 0xff;
-	i2c->i2c_i2mod = 1;	/* Enable */
-	i2c->i2c_i2com = 0x81;	/* Start master */
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} 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 */
+	}		
 
-	/* Wait for IIC transfer */
-	interruptible_sleep_on(&iic_wait);
-	local_irq_restore(flags);
-	if (signal_pending(current))
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug) 
+			printk("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 */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
 	if (cpm_debug) {
 		printk("tx sc %04x, rx sc %04x\n",
 		       tbdf->cbd_sc, rbdf->cbd_sc);
 	}
 
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk("IIC read; complete but tbuf ready\n");
+		force_close(cpm);
+		printk("tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
 	if (tbdf->cbd_sc & BD_SC_NAK) {
-		printk("IIC read; no ack\n");
-		return 0;
+		if (cpm_debug)
+			printk("IIC read; no ack\n");
+		return -EREMOTEIO;
 	}
 
 	if (rbdf->cbd_sc & BD_SC_EMPTY) {
-		printk("IIC read; complete but rbuf empty\n");
-		force_close(cpm);
-		printk("tx sc %04x, rx sc %04x\n",
-		       tbdf->cbd_sc, rbdf->cbd_sc);
+		/* force_close(cpm); */
+		if (cpm_debug){
+			printk("IIC read; complete but rbuf empty\n");
+			printk("tx sc %04x, rx sc %04x\n",
+			       tbdf->cbd_sc, rbdf->cbd_sc);
+		}
+		return -EREMOTEIO;
 	}
 
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		if (cpm_debug)
+			printk("IIC read; Overrun\n");
+		return -EREMOTEIO;;
+	}
+
 	if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen);
 
 	if (rbdf->cbd_datlen < count) {
-		printk("IIC read; short, wanted %d got %d\n",
-		       count, rbdf->cbd_datlen);
+		if (cpm_debug)
+			printk("IIC read; short, wanted %d got %d\n",
+			       count, rbdf->cbd_datlen);
 		return 0;
 	}
 
-
-	invalidate_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
-
 	return count;
 }
 
@@ -303,7 +353,7 @@
 	volatile cpm8xx_t *cp = cpm->cp;
 	volatile cbd_t	*tbdf;
 	u_char *tb;
-	unsigned long flags;
+	unsigned long flags, tmo;
 
 	/* check for and use a microcode relocation patch */
 	if (cpm->reloc) {
@@ -329,31 +379,53 @@
 	tbdf[1].cbd_datlen = count;
 	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
 
-	/* Chip bug, set enable here */
-	local_irq_save(flags);
-	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
-	i2c->i2c_i2cer = 0xff;
-	i2c->i2c_i2mod = 1;	/* Enable */
-	i2c->i2c_i2com = 0x81;	/* Start master */
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} 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 */
+	}		
 
-	/* Wait for IIC transfer */
-	interruptible_sleep_on(&iic_wait);
-	local_irq_restore(flags);
-	if (signal_pending(current))
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug && !tmo) 
+			printk("IIC write: timeout!\n");
 		return -EIO;
-
+	}
+	
+#if 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 */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
 	if (cpm_debug) {
 		printk("tx0 sc %04x, tx1 sc %04x\n",
 		       tbdf[0].cbd_sc, tbdf[1].cbd_sc);
 	}
 
 	if (tbdf->cbd_sc & BD_SC_NAK) {
-		printk("IIC write; no ack\n");
+		if (cpm_debug) 
+			printk("IIC write; no ack\n");
 		return 0;
 	}
 	  
 	if (tbdf->cbd_sc & BD_SC_READY) {
-		printk("IIC write; complete but tbuf ready\n");
+		if (cpm_debug)
+			printk("IIC write; complete but tbuf ready\n");
 		return 0;
 	}
 
@@ -371,7 +443,7 @@
 	volatile cpm8xx_t *cp = cpm->cp;
 	volatile cbd_t *tbdf, *rbdf;
 	u_char *tb;
-	unsigned long flags, len;
+	unsigned long flags, len, tmo;
 
 	if (cpm_debug > 1)
 		printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
@@ -396,31 +468,43 @@
 	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
 	len = 2;
 
-	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2));
 
 	tbdf->cbd_bufaddr = __pa(tb);
 	tbdf->cbd_datlen = len;
 	tbdf->cbd_sc -		BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST |
+		BD_SC_READY | BD_SC_LAST |
 		BD_SC_WRAP | BD_IIC_START;
 
 	rbdf->cbd_datlen = 0;
 	rbdf->cbd_bufaddr = __pa(tb+2);
-	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
 
 	local_irq_save(flags);
 	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
 	i2c->i2c_i2cer = 0xff;
-	i2c->i2c_i2mod = 1;	/* Enable */
-	i2c->i2c_i2com = 0x81;	/* Start master */
+	i2c->i2c_i2mod |= 1;	/* Enable */
+	i2c->i2c_i2com |= 0x80;	/* Begin transmission */
 
 	if (cpm_debug > 1) printk("about to sleep\n");
 
 	/* wait for IIC transfer */
-	interruptible_sleep_on(&iic_wait);
+	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
 	local_irq_restore(flags);
-	if (signal_pending(current))
+
+#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 */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug && !tmo) 
+			printk("IIC tryaddress: timeout!\n");
 		return -EIO;
+	}
 
 	if (cpm_debug > 1) printk("back from sleep\n");
 
@@ -450,8 +534,8 @@
 
 		if (cpm_debug)
 			printk("i2c-algo-8xx.o: "
-			       "#%d addr=0x%x flags=0x%x len=%d\n",
-			       i, pmsg->addr, pmsg->flags, pmsg->len);
+			       "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",
+			       i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf);
 
 		addr = pmsg->addr << 1;
 		if (pmsg->flags & I2C_M_RD )

  parent reply	other threads:[~2005-05-19  6:23 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-10-09 20:14 8xx i2c refers to unspecified chip errata Barker Michael-r43496
2002-10-10 10:35 ` Joakim Tjernlund
2002-10-10 16:18   ` Dan Malek
2002-10-10 16:35     ` Dr. Craig Hollabaugh
2002-10-11  7:28     ` Joakim Tjernlund
2002-10-11  7:50       ` bart
2002-10-11  9:12         ` Joakim Tjernlund
2002-10-11  9:56           ` bart
2002-10-11 12:02           ` Stephan Linke
2002-10-11 12:14             ` bart
2002-10-11 12:31               ` Stephan Linke
2002-10-11 12:46                 ` Joakim Tjernlund
2002-10-11 12:44             ` Joakim Tjernlund
2002-10-11 12:55               ` bart
2002-10-11 13:10                 ` Joakim Tjernlund
2002-10-15 16:57           ` Tom Rini
2002-10-22  9:15             ` Joakim Tjernlund
2005-05-19  6:23               ` Joakim Tjernlund
2002-10-24 16:10               ` Tom Rini
2005-05-19  6:23                 ` Tom Rini
2002-10-24 18:21                 ` Joakim Tjernlund
2005-05-19  6:23                   ` Joakim Tjernlund
2002-11-01 11:01                   ` Joakim Tjernlund
2002-11-01 19:19                     ` Tom Rini
2002-11-17 20:51                   ` Mark D. Studebaker
2005-05-19  6:23                     ` Mark D. Studebaker
2002-11-17 21:44                     ` Joakim Tjernlund
2002-11-18 14:10                       ` Tom Rini
2005-05-19  6:23                         ` Tom Rini
2002-11-18 19:04                         ` Mark D. Studebaker
2005-05-19  6:23                           ` Mark D. Studebaker
2002-11-18 19:24                           ` Joakim Tjernlund
2005-05-19  6:23                             ` Joakim Tjernlund
2002-11-18 19:31                             ` Tom Rini
2005-05-19  6:23                               ` Tom Rini
2002-11-18 19:42                             ` Jean Delvare
2005-05-19  6:23                               ` Jean Delvare
2002-11-18 19:46                               ` Tom Rini
2005-05-19  6:23                                 ` Tom Rini
2005-05-19  6:23               ` Joakim Tjernlund
2005-05-19  6:23               ` Tom Rini [this message]
2005-05-19  6:23               ` Mark D. Studebaker
  -- strict thread matches above, loose matches on Subject: below --
2002-10-10 17:01 Barker Michael-r43496

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20021118194555.GD18374@opus.bloom.county \
    --to=trini@kernel.crashing.org \
    --cc=lm-sensors@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.