linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* Re: 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-12  5:11 Debora Liu
  0 siblings, 0 replies; 13+ messages in thread
From: Debora Liu @ 2005-08-12  5:11 UTC (permalink / raw)
  To: Tjernlund; +Cc: Linuxppc-embedded

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 628 bytes --]

Hello, Tjernlund

In message <2005-08-12 01:50:45 tjernlund@tjernlund.se> you wrote:

>Try changing all
>  i2c->i2c_i2com |= 0x80;	/* Begin transmission */
>to
>  i2c->i2c_i2com |= 0x80 | 0x01;	/* Begin transmission */
>
>That should remove the need to do force_reinit(cpm) I hope.
>See http://ozlabs.org/pipermail/linuxppc-embedded/2005-August/019600.html for a litte more info.
>
>Also, I think you should remove the busy wait code. Its not needed IMHO.

update i2c_algo_8xx.c as same

= = = = = = = = = = = = = = = = = = = =
				 
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Debora Liu
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡deboralh@fel.com.cn
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡2005-08-12

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-15  5:59 cajus.hahn
  2005-08-15  8:08 ` Joakim Tjernlund
  0 siblings, 1 reply; 13+ messages in thread
From: cajus.hahn @ 2005-08-15  5:59 UTC (permalink / raw)
  To: linuxppc-embedded





Hi Jocke,

I changed the force_reinit() to

// Disable interrupts.
i2c->i2c_i2cmr = 0;
i2c->i2c_i2cer = 0xff;
// Clear enable
i2c->i2c_i2mod &= ~1;
// Reset internal state
iip->iic_rstate = 0;
iip->iic_tstate = 0;

This seems to work and is less code than my old force_reinit().
On the other hand: This kind of CPM timeout will only occur on heavy I2C
bus conflicts. They should not appear at all. The code will not be executed
if a slave device does not answer! The original driver is from the year
2001 and nobody has mentioned problems of this kind before. Without
detailed knowledge of the CPM internals I feel much safer using my old
force_reinit(), which does a complete re-init.

Cajus

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-13 15:13 Joakim Tjernlund
  0 siblings, 0 replies; 13+ messages in thread
From: Joakim Tjernlund @ 2005-08-13 15:13 UTC (permalink / raw)
  To: linuxppc-embedded

> My description seems to be a little misleading.
> WITHOUT the force_reinit() my SPI driver reports transmission errors if the
> I2C bus has longer disturbances.
> WITH the force_reinit() my SPI driver works fine.
> This sounds like the I2C allocates a new buffer for every timed-out
> transmision. If all I2C buffers are full, the SPI buffers get overwritten
> !?
> I did not really trace back the problem, this is only my suspicion.
> Because the  force_reinit() resets all the buffer pointer to their init
> values the problem with the SPI does not occur.
> 
> Cajus

I think the problem is that the CPM is still waiting on the SCL long after the timeout has happen.
A complete reinit will reset the I2C part of the CPM.

I think you should be able to get away with less, maybe it will enough to disable
I2C (i2c->i2c_i2mod &= ~1) and/or clear internal state (iip->iic_rstate   = 0; iip->iic_tstate   = 0;)
after a timeout?

 Jocke

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-12  7:49 cajus.hahn
  2005-08-12  8:01 ` Wolfgang Denk
  0 siblings, 1 reply; 13+ messages in thread
From: cajus.hahn @ 2005-08-12  7:49 UTC (permalink / raw)
  To: linuxppc-embedded





Hello Tjernlund, Hello Debora

>Try changing all
>  i2c->i2c_i2com |= 0x80;           /* Begin transmission */
>to
>  i2c->i2c_i2com |= 0x80 | 0x01;          /* Begin transmission */
>
>That should remove the need to do force_reinit(cpm) I hope.

This is NOT working in every case!

It will work, on short bus-disturbances on the SCL line.
I suggest adding the "| 0x01" even this will not help on every transmission
problem.

If you have longer disturbances on SCL or SDA, something in  the CPM will
prevent the I2C bus to continue working after the disturbances are gone.
Perhaps there is a problem with the buffer allocation.
I changed the i2c-algo-8xx.c to work with your patch and without the
force_reinit() code.
Then I set the SCL line to ground to simulate a longer bus disturbance.
After some timeouts my SPI bus, yes the SPI bus, reportet transmission
errors. Both bus-interfaces use the CPM. It looks like the SPI buffer gets
garbaged by the I2C interface.
With the force_reinit() this problem did not occur.

Cajus

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-11 17:50 Tjernlund
  0 siblings, 0 replies; 13+ messages in thread
From: Tjernlund @ 2005-08-11 17:50 UTC (permalink / raw)
  To: linuxppc-embedded

Try changing all
  i2c->i2c_i2com |= 0x80;	/* Begin transmission */
to
  i2c->i2c_i2com |= 0x80 | 0x01;	/* Begin transmission */

That should remove the need to do force_reinit(cpm) I hope.
See http://ozlabs.org/pipermail/linuxppc-embedded/2005-August/019600.html for a litte more info.

Also, I think you should remove the busy wait code. Its not needed IMHO.

 Jocke

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-11  7:42 Cajus Hahn
  0 siblings, 0 replies; 13+ messages in thread
From: Cajus Hahn @ 2005-08-11  7:42 UTC (permalink / raw)
  To: linuxppc-embedded, cajus.hahn

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@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;
 }
 

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-10  9:37 Debora Liu
  2005-08-10  9:48 ` Wolfgang Denk
  0 siblings, 1 reply; 13+ messages in thread
From: Debora Liu @ 2005-08-10  9:37 UTC (permalink / raw)
  To: cajus.hahn@de.abb.com; +Cc: Linuxppc-embedded

Hello, cajus.hahn

In message <2005-08-10 15:27:57 cajus.hahn@de.abb.com> you wrote:

>Hi all,
>
>I had some problems on my MPC855M based board when I tried to access the
>i2c bus.

Try update i2c-algo-8xx.c

= = = = = = = = = = = = = = = = = = = =
				 
        Debora Liu
        deboralh@fel.com.cn
          2005-08-10

begin 600 i2c_algo_8xx-port_to_2_6.patch
M.'AX.B!P;W)T(&DR8RUA;&=O7SAX>"!T;R`R+C8-"@T*0F%S960@;VX@5&]M
M(%)I;FDG<R!A;F0@2F]A:VEM(%1J97)N;'5N9"=S('=O<FL-"@T*4VEG;F5D
M+6]F9BUB>3H@07)I<W1E=2!397)G:6\@4F]Z86YS:VD@1FEL:&\@/&%R:7-`
M8V%T:&5D<F%L;&%B<RYO<F<^#0H-"DEN9&5X.B`R+C8M.'AX+V1R:79E<G,O
M:3)C+V%L9V]S+VDR8RUA;&=O+3AX>"YC#0H]/3T]/3T]/3T]/3T]/3T]/3T]
M/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]
M/3T]#0HM+2T@+V1E=B]N=6QL"3$Y-S`M,#$M,#$@,#`Z,#`Z,#`N,#`P,#`P
M,#`P("LP,#`P#0HK*RL@,BXV+3AX>"]D<FEV97)S+VDR8R]A;&=O<R]I,F,M
M86QG;RTX>'@N8PDR,#`U+3`X+3`X(#`Y.C4U.C,P+C`P,#`P,#`P,"`M,#,P
M,`T*0$`@+3`L,"`K,2PV,3<@0$`-"BLO*@T**R`J(&DR8RUA;&=O+3AX>"YC
M(&DR>"!D<FEV97(@86QG;W)I=&AM<R!F;W(@35!#.%A8($-030T**R`J($-O
M<'ER:6=H="`H8RD@,3DY.2!$86X@36%L96L@*&1M86QE:T!J;&,N;F5T*2X-
M"BL@*@T**R`@("!4:&ES('!R;V=R86T@:7,@9G)E92!S;V9T=V%R93L@>6]U
M(&-A;B!R961I<W1R:6)U=&4@:70@86YD+V]R(&UO9&EF>0T**R`@("!I="!U
M;F1E<B!T:&4@=&5R;7,@;V8@=&AE($=.52!'96YE<F%L(%!U8FQI8R!,:6-E
M;G-E(&%S('!U8FQI<VAE9"!B>0T**R`@("!T:&4@1G)E92!3;V9T=V%R92!&
M;W5N9&%T:6]N.R!E:71H97(@=F5R<VEO;B`R(&]F('1H92!,:6-E;G-E+"!O
M<@T**R`@("`H870@>6]U<B!O<'1I;VXI(&%N>2!L871E<B!V97)S:6]N+@T*
M*PT**R`@("!4:&ES('!R;V=R86T@:7,@9&ES=')I8G5T960@:6X@=&AE(&AO
M<&4@=&AA="!I="!W:6QL(&)E('5S969U;"P-"BL@("`@8G5T(%=)5$A/550@
M04Y9(%=!4E)!3E19.R!W:71H;W5T(&5V96X@=&AE(&EM<&QI960@=V%R<F%N
M='D@;V8-"BL@("`@34520TA!3E1!0DE,2519(&]R($9)5$Y%4U,@1D]2($$@
M4$%25$E#54Q!4B!055)03U-%+B`@4V5E('1H90T**R`@("!'3E4@1V5N97)A
M;"!0=6)L:6,@3&EC96YS92!F;W(@;6]R92!D971A:6QS+@T**PT**R`@("!9
M;W4@<VAO=6QD(&AA=F4@<F5C96EV960@82!C;W!Y(&]F('1H92!'3E4@1V5N
M97)A;"!0=6)L:6,@3&EC96YS90T**R`@("!A;&]N9R!W:71H('1H:7,@<')O
M9W)A;3L@:68@;F]T+"!W<FET92!T;R!T:&4@1G)E92!3;V9T=V%R90T**R`@
M("!&;W5N9&%T:6]N+"!);F,N+"`V-S4@36%S<R!!=F4L($-A;6)R:61G92P@
M34$@,#(Q,SDL(%5302X-"BL@*@T**R`J(&UO=F5D(&EN=&\@<')O<&5R(&DR
M8R!I;G1E<F9A8V4[('-E<&%R871E9"!O=70@<&QA=&9O<FT@<W!E8VEF:6,-
M"BL@*B!P87)T<R!I;G1O(&DR8RUR<'@N8PT**R`J($)R860@4&%R:V5R("AB
M<F%D0&AE96QT;V4N8V]M*0T**R`J+PT**PT**R\O(%A86"!T;V1O#0HK+R\@
M=&EM96]U="!S;&5E<#\-"BL-"BLO*B`D260Z(&DR8RUA;&=O+3AX>"YC+'8@
M,2XW(#(P,#(O,#@O,#,@,C(Z-#@Z,3@@86,Y-#$P($5X<"`D("HO#0HK#0HK
M(VEN8VQU9&4@/&QI;G5X+VME<FYE;"YH/@T**R-I;F-L=61E(#QL:6YU>"]M
M;V1U;&4N:#X-"BLC:6YC;'5D92`\;&EN=7@O9&5L87DN:#X-"BLC:6YC;'5D
M92`\;&EN=7@O<VQA8BYH/@T**R-I;F-L=61E(#QL:6YU>"]V97)S:6]N+F@^
M#0HK(VEN8VQU9&4@/&QI;G5X+VEN:70N:#X-"BLC:6YC;'5D92`\87-M+W5A
M8V-E<W,N:#X-"BLC:6YC;'5D92`\;&EN=7@O:6]P;W)T+F@^#0HK(VEN8VQU
M9&4@/&QI;G5X+V5R<FYO+F@^#0HK(VEN8VQU9&4@/&QI;G5X+W-C:&5D+F@^
M#0HK#0HK(VEN8VQU9&4@/&%S;2]M<&,X>'@N:#X-"BLC:6YC;'5D92`\87-M
M+V-O;6UP<F]C+F@^#0HK#0HK(VEN8VQU9&4@/&QI;G5X+VDR8RYH/@T**R-I
M;F-L=61E(#QL:6YU>"]I,F,M86QG;RTX>'@N:#X-"BL-"BLC9&5F:6YE($-0
M35]-05A?4D5!1`DU,3,-"BLO*B!4<GD@=6YC;VUM96YT('1H:7,@:68@>6]U
M(&AA=F4@86X@;VQD97(@0U!5*&5A<FQI97(@=&AA;B!R978@1#0I("HO#0HK
M+RH@(V1E9FEN92!),D-?0TA)4%]%4E)!5$$@*B\-"BL-"BMS=&%T:6,@8VAA
M<B`J;6]D=6QE7VYA;64@/2`B:3)C7V%L9V]?.'AX(CL-"BLC9&5F:6YE($1%
M0E5'4"AL979E;"P@>"P@>2XN+BD@9&\@>R!<#0HK"0D)"6EF("AC<&U?9&5B
M=6<@/CT@;&5V96PI(%P-"BL)"0D)"7!R:6YT:RA+15).7T1%0E5'("(E<SH@
M(B!X+"!<#0HK"0D)"0D@("`@("`@;6]D=6QE7VYA;64L(",C('DI.R!<#0HK
M"0D)"7T@=VAI;&4H,"D-"BL-"BMS=&%T:6,@=V%I=%]Q=65U95]H96%D7W0@
M:6EC7W=A:70[#0HK<W1A=&EC('5S:&]R="!R7W1B87-E+"!R7W)B87-E.PT*
M*PT**VEN="!C<&U?<V-A;B`](#`[#0HK:6YT(&-P;5]D96)U9R`](#`[#0HK
M#0HK<W1A=&EC("!V;VED#0HK8W!M7VEI8U]I;G1E<G)U<'0H=F]I9"`J9&5V
M7VED+"!S=')U8W0@<'1?<F5G<R`J<F5G<RD-"BM[#0HK"79O;&%T:6QE(&DR
M8SAX>%]T("II,F,@/2`H:3)C.'AX7W0@*BED979?:60[#0HK#0HK"41%0E5'
M4"@R+"`B8W!M7VEI8U]I;G1E<G)U<'0H9&5V7VED/25P*5QN(BP@9&5V7VED
M*3L-"BL-"BLC:69D968@23)#7T-(25!?15)2051!#0HK"2\J($-H:7`@97)R
M871A+"!C;&5A<B!E;F%B;&4N#0HK"2`J(%1H:7,@<V5E;7,@=&\@;F]T(&)E
M(&YE961E9"!O;B!R978@1#0@;W(@;F5W97(@0U!5<RX-"BL)("H@4V]M96]N
M92!W:71H(&%N(&]L9&5R($-052!N965D<R!T;R!V97)I9GD@=&AI<RX-"BL)
M("HO#0HK"6DR8RT^:3)C7VDR;6]D("8]('XQ.PT**R-E;F1I9@T**PT**PDO
M*B!#;&5A<B!I;G1E<G)U<'0N#0HK"2HO#0HK"6DR8RT^:3)C7VDR8V5R(#T@
M,'AF9CL-"BL-"BL)+RH@1V5T("=M92!G;VEN9R!A9V%I;BX-"BL)*B\-"BL)
M=V%K95]U<%]I;G1E<G)U<'1I8FQE*"9I:6-?=V%I="D[#0HK?0T**PT**W-T
M871I8R!V;VED#0HK8W!M7VEI8U]I;FET*'-T<G5C="!I,F-?86QG;U\X>'A?
M9&%T82`J8W!M7V%D87`I#0HK>PT**PEV;VQA=&EL92!I:6-?=`D)*FEI<"`]
M(&-P;5]A9&%P+3YI:7`[#0HK"79O;&%T:6QE(&DR8SAX>%]T"2II,F,@/2!C
M<&U?861A<"T^:3)C.PT**PEU;G-I9VYE9"!C:&%R(&)R9SL-"BL)8F1?="`J
M8F0@/2`H8F1?="`J*5]?<F5S.PT**PT**PE$14)51U`H,2P@(F-P;5]I:6-?
M:6YI="@I("T@:6EP/25P7&XB+"!I:7`I.PT**PT**PDO*B!);FET:6%L:7IE
M('1H92!P87)A;65T97(@<F%M+@T**PD@*B!792!N965D('1O(&UA:V4@<W5R
M92!M86YY('1H:6YG<R!A<F4@:6YI=&EA;&EZ960@=&\@>F5R;RP-"BL)("H@
M97-P96-I86QL>2!I;B!T:&4@8V%S92!O9B!A(&UI8W)O8V]D92!P871C:"X-
M"BL)("HO#0HK"6EI<"T^:6EC7W)S=&%T92`](#`[#0HK"6EI<"T^:6EC7W)D
M<"`](#`[#0HK"6EI<"T^:6EC7W)B<'1R(#T@,#L-"BL):6EP+3YI:6-?<F)C
M(#T@,#L-"BL):6EP+3YI:6-?<GAT;7`@/2`P.PT**PEI:7`M/FEI8U]T<W1A
M=&4@/2`P.PT**PEI:7`M/FEI8U]T9'`@/2`P.PT**PEI:7`M/FEI8U]T8G!T
M<B`](#`[#0HK"6EI<"T^:6EC7W1B8R`](#`[#0HK"6EI<"T^:6EC7W1X=&UP
M(#T@,#L-"BL-"BL)+RH@4V5T('5P('1H92!)24,@<&%R86UE=&5R<R!I;B!T
M:&4@<&%R86UE=&5R(')A;2X-"BL)*B\-"BL):6EP+3YI:6-?=&)A<V4@/2!R
M7W1B87-E(#T@8W!M7V%D87`M/F1P7V%D9'([#0HK"6EI<"T^:6EC7W)B87-E
M(#T@<E]R8F%S92`](&-P;5]A9&%P+3YD<%]A9&1R("L@<VEZ96]F*&-B9%]T
M*2`J(#([#0HK#0HK"6EI<"T^:6EC7W1F8W(@/2!334-?14([#0HK"6EI<"T^
M:6EC7W)F8W(@/2!334-?14([#0HK#0HK"2\J(%-E="!M87AI;75M(')E8V5I
M=F4@<VEZ92X-"BL)*B\-"BL):6EP+3YI:6-?;7)B;'(@/2!#4$U?34%87U)%
M040[#0HK#0HK"2\J($EN:71I86QI>F4@5'@O4G@@<&%R86UE=&5R<RX-"BL)
M*B\-"BL):68@*&-P;5]A9&%P+3YR96QO8R`]/2`P*2![#0HK"0EV;VQA=&EL
M92!C<&TX>'A?="`J8W`@/2!C<&U?861A<"T^8W`[#0HK#0HK"0EC<"T^8W!?
M8W!C<B`]#0HK"0D);6M?8W)?8VUD*$-035]#4E]#2%]),D,L($-035]#4E])
M3DE47U126"D@?"!#4$U?0U)?1DQ'.PT**PD)=VAI;&4@*&-P+3YC<%]C<&-R
M("8@0U!-7T-27T9,1RD[#0HK"7T@96QS92![#0HK"0EI:7`M/FEI8U]R8G!T
M<B`](&EI<"T^:6EC7W)B87-E.PT**PD):6EP+3YI:6-?=&)P='(@/2!I:7`M
M/FEI8U]T8F%S93L-"BL)"6EI<"T^:6EC7W)S=&%T90D](#`[#0HK"0EI:7`M
M/FEI8U]T<W1A=&4)/2`P.PT**PE]#0HK#0HK"2\J(%-E;&5C="!A;B!A<F)I
M=')A<GD@861D<F5S<RX@($IU<W0@;6%K92!S=7)E(&ET(&ES('5N:7%U92X-
M"BL)*B\-"BL):3)C+3YI,F-?:3)A9&0@/2`P>&9E.PT**PT**PDO*B!-86ME
M(&-L;V-K(')U;B!A="`V,"!+2'HN#0HK"2HO#0HK"6)R9R`]("AU;G-I9VYE
M9"!C:&%R*2`H8F0M/F)I7VEN=&9R97$O*#,R*C(J-C`P,#`I("TS*3L-"BL)
M:3)C+3YI,F-?:3)B<F<@/2!B<F<[#0HK#0HK"6DR8RT^:3)C7VDR;6]D(#T@
M,'@P,#L-"BL):3)C+3YI,F-?:3)C;VT@/2`P>#`Q.R`O*B!-87-T97(@;6]D
M92`J+PT**PT**PDO*B!$:7-A8FQE(&EN=&5R<G5P=',N#0HK"2HO#0HK"6DR
M8RT^:3)C7VDR8VUR(#T@,#L-"BL):3)C+3YI,F-?:3)C97(@/2`P>&9F.PT*
M*PT**PEI;FET7W=A:71Q=65U95]H96%D*"9I:6-?=V%I="D[#0HK#0HK"2\J
M($EN<W1A;&P@:6YT97)R=7!T(&AA;F1L97(N#0HK"2HO#0HK"41%0E5'4"@Q
M+"`B26YS=&%L;"!)4U(@9F]R($E242`E9%QN(BP@0U!-5D5#7TDR0RD[#0HK
M"6-P;5]I;G-T86QL7VAA;F1L97(H0U!-5D5#7TDR0RP@8W!M7VEI8U]I;G1E
M<G)U<'0L("AV;VED("HI:3)C*3L-"BM]#0HK#0HK#0HK<W1A=&EC(&EN=`T*
M*V-P;5]I:6-?<VAU=&1O=VXH<W1R=6-T(&DR8U]A;&=O7SAX>%]D871A("IC
M<&U?861A<"D-"BM[#0HK"79O;&%T:6QE(&DR8SAX>%]T("II,F,@/2!C<&U?
M861A<"T^:3)C.PT**PT**PDO*B!3:'5T(&1O=VX@24E#+@T**PDJ+PT**PEI
M,F,M/FDR8U]I,FUO9"`F/2!^,3L-"BL):3)C+3YI,F-?:3)C;7(@/2`P.PT*
M*PEI,F,M/FDR8U]I,F-E<B`](#!X9F8[#0HK#0HK"7)E='5R;B`P.PT**WT-
M"BL-"BMS=&%T:6,@=F]I9`T**V-P;5]R97-E=%]I:6-?<&%R86US*'9O;&%T
M:6QE(&EI8U]T("II:7`I#0HK>PT**PEI:7`M/FEI8U]T8F%S92`](')?=&)A
M<V4[#0HK"6EI<"T^:6EC7W)B87-E(#T@<E]R8F%S93L-"BL-"BL):6EP+3YI
M:6-?=&9C<B`](%--0U]%0CL-"BL):6EP+3YI:6-?<F9C<B`](%--0U]%0CL-
M"BL-"BL):6EP+3YI:6-?;7)B;'(@/2!#4$U?34%87U)%040[#0HK#0HK"6EI
M<"T^:6EC7W)S=&%T92`](#`[#0HK"6EI<"T^:6EC7W)D<"`](#`[#0HK"6EI
M<"T^:6EC7W)B<'1R(#T@:6EP+3YI:6-?<F)A<V4[#0HK"6EI<"T^:6EC7W)B
M8R`](#`[#0HK"6EI<"T^:6EC7W)X=&UP(#T@,#L-"BL):6EP+3YI:6-?='-T
M871E(#T@,#L-"BL):6EP+3YI:6-?=&1P(#T@,#L-"BL):6EP+3YI:6-?=&)P
M='(@/2!I:7`M/FEI8U]T8F%S93L-"BL):6EP+3YI:6-?=&)C(#T@,#L-"BL)
M:6EP+3YI:6-?='AT;7`@/2`P.PT**WT-"BL-"BLC9&5F:6YE($)$7U-#7TY!
M2PD)*"AU<VAO<G0I,'@P,#`T*2`O*B!.04L@+2!D:60@;F]T(')E<W!O;F0@
M*B\-"BLC9&5F:6YE($)$7U-#7T]6"0DH*'5S:&]R="DP>#`P,#(I("\J($]6
M("T@<F5C96EV92!O=F5R<G5N("HO#0HK(V1E9FEN92!#4$U?0U)?0TQ/4T5?
M4EA"1`DH*'5S:&]R="DP>#`P,#<I#0HK#0HK<W1A=&EC('9O:60@9F]R8V5?
M8VQO<V4H<W1R=6-T(&DR8U]A;&=O7SAX>%]D871A("IC<&TI#0HK>PT**PEV
M;VQA=&EL92!I,F,X>'A?="`J:3)C(#T@8W!M+3YI,F,[#0HK"6EF("AC<&TM
M/G)E;&]C(#T](#`I('L@+RH@;6EC<F\@8V]D92!D:7-A8FQE9"`J+PT**PD)
M=F]L871I;&4@8W!M.'AX7W0@*F-P(#T@8W!M+3YC<#L-"BL-"BL)"41%0E5'
M4"@Q+"`B9F]R8V5?8VQO<V4H*5QN(BD[#0HK"0EC<"T^8W!?8W!C<B`]#0HK
M"0D);6M?8W)?8VUD*$-035]#4E]#2%]),D,L($-035]#4E]#3$]315]26$)$
M*2!\#0HK"0D)0U!-7T-27T9,1SL-"BL-"BL)"7=H:6QE("AC<"T^8W!?8W!C
M<B`F($-035]#4E]&3$<I.PT**PE]#0HK"6DR8RT^:3)C7VDR8VUR(#T@,'@P
M,#L)+RH@1&ES86)L92!A;&P@:6YT97)R=7!T<R`J+PT**PEI,F,M/FDR8U]I
M,F-E<B`](#!X9F8[#0HK?0T**PT**PT**R\J(%)E860@9G)O;2!)24,N+BX-
M"BL@*B!A8GET92`](&%D9')E<W,@8GET92P@=VET:"!R+W<@9FQA9R!A;')E
M861Y('-E=`T**R`J+PT**W-T871I8R!I;G0-"BMC<&U?:6EC7W)E860H<W1R
M=6-T(&DR8U]A;&=O7SAX>%]D871A("IC<&TL('5?8VAA<B!A8GET92P@8VAA
M<B`J8G5F+"!I;G0@8V]U;G0I#0HK>PT**PEV;VQA=&EL92!I:6-?="`J:6EP
M(#T@8W!M+3YI:7`[#0HK"79O;&%T:6QE(&DR8SAX>%]T("II,F,@/2!C<&TM
M/FDR8SL-"BL)=F]L871I;&4@8W!M.'AX7W0@*F-P(#T@8W!M+3YC<#L-"BL)
M=F]L871I;&4@8V)D7W0)*G1B9&8L("IR8F1F.PT**PEU7V-H87(@*G1B.PT*
M*PEU;G-I9VYE9"!L;VYG(&9L86=S+"!T;6\[#0HK#0HK"6EF("AC;W5N="`^
M/2!#4$U?34%87U)%040I#0HK"0ER971U<FX@+45)3E9!3#L-"BL-"BL)+RH@
M8VAE8VL@9F]R(&%N9"!U<V4@82!M:6-R;V-O9&4@<F5L;V-A=&EO;B!P871C
M:"`J+PT**PEI9B`H8W!M+3YR96QO8RD-"BL)"6-P;5]R97-E=%]I:6-?<&%R
M86US*&EI<"D[#0HK#0HK"71B9&8@/2`H8V)D7W0@*BDF8W`M/F-P7V1P;65M
M6VEI<"T^:6EC7W1B87-E73L-"BL)<F)D9B`]("AC8F1?="`J*29C<"T^8W!?
M9'!M96U;:6EP+3YI:6-?<F)A<V5=.PT**PT**PDO*B!4;R!R96%D+"!W92!N
M965D(&%N(&5M<'1Y(&)U9F9E<B!O9B!T:&4@<')O<&5R(&QE;F=T:"X-"BL)
M("H@06QL('1H870@:7,@=7-E9"!I<R!T:&4@9FER<W0@8GET92!F;W(@861D
M<F5S<RP@=&AE(')E;6%I;F1E<@T**PD@*B!I<R!J=7-T('5S960@9F]R('1I
M;6EN9R`H86YD(&1O97-N)W0@<F5A;&QY(&AA=F4@=&\@97AI<W0I+@T**PD@
M*B\-"BL)=&(@/2!C<&TM/G1E;7`[#0HK"71B(#T@*'5?8VAA<B`J*2@H*'5I
M;G0I=&(@*R`Q-2D@)B!^,34I.PT**PET8ELP72`](&%B>71E.PD)+RH@1&5V
M:6-E(&%D9')E<W,@8GET92!W+W)W(&9L86<@*B\-"BL-"BL)9FQU<VA?9&-A
M8VAE7W)A;F=E*"AU;G-I9VYE9"!L;VYG*2!T8BP@*'5N<VEG;F5D(&QO;F<I
M("AT8B`K(#$I*3L-"BL-"BL)1$5"54=0*#$L(")C<&U?:6EC7W)E860H86)Y
M=&4],'@E>"E<;B(L(&%B>71E*3L-"BL-"BL)=&)D9BT^8V)D7V)U9F%D9'(@
M/2!?7W!A*'1B*3L-"BL)=&)D9BT^8V)D7V1A=&QE;B`](&-O=6YT("L@,3L-
M"BL)=&)D9BT^8V)D7W-C(#T-"BL)"4)$7U-#7U)%0419('P@0D1?4T-?3$%3
M5"!\#0HK"0E"1%]30U]74D%0('P@0D1?24E#7U-405)4.PT**PT**PEI:7`M
M/FEI8U]M<F)L<B`](&-O=6YT("L@,3L@+RH@<')E=F5N="!E>&-E<W-I=F4@
M<F5A9"P@*S$-"BL)"0D)("`@("`@:7,@;F5E9&5D(&]T:&5R=VES92!W:6QL
M('1H90T**PD)"0D@("`@("!26$(@:6YT97)R=7!T(&-O;64@=&]O(&5A<FQY
M("HO#0HK#0HK"2\J(&9L=7-H('=I;&P@:6YV86QI9&%T92!T;V\N("HO#0HK
M"69L=7-H7V1C86-H95]R86YG92@H=6YS:6=N960@;&]N9RD@8G5F+"`H=6YS
M:6=N960@;&]N9RD@*&)U9BMC;W5N="DI.PT**PT**PER8F1F+3YC8F1?9&%T
M;&5N(#T@,#L-"BL)<F)D9BT^8V)D7V)U9F%D9'(@/2!?7W!A*&)U9BD[#0HK
M#0HK"7)B9&8M/F-B9%]S8R`]($)$7U-#7T5-4%19('P@0D1?4T-?5U)!4'P@
M0D1?4T-?24Y44E!4.PT**PT**PDO*B!#:&EP(&)U9RP@<V5T(&5N86)L92!H
M97)E("HO#0HK"6QO8V%L7VER<5]S879E*&9L86=S*3L-"BL):3)C+3YI,F-?
M:3)C;7(@/2`P>#$S.PDO*B!%;F%B;&4@<V]M92!I;G1E<G5P=',@*B\-"BL)
M:3)C+3YI,F-?:3)C97(@/2`P>&9F.PT**PEI,F,M/FDR8U]I,FUO9"!\/2`Q
M.PDO*B!%;F%B;&4@*B\-"BL)+RH-"BL)("H@0F5G:6X@=')A;G-M:7-S:6]N
M(&%N9"!F;W)C92!M87-T97(N#0HK"2`J(%-O;64@97)R;W)S*$-,*2!C;&5A
M<G,@=&AE($TO4R!B:70-"BL)("HO#0HK"6DR8RT^:3)C7VDR8V]M('P](#!X
M.#`@?"`P>#`Q.PT**PT**PDO*B!786ET(&9O<B!)24,@=')A;G-F97(@*B\-
M"BL)=&UO(#T@:6YT97)R=7!T:6)L95]S;&5E<%]O;E]T:6UE;W5T*"9I:6-?
M=V%I="PQ*DA:*3L-"BL);&]C86Q?:7)Q7W)E<W1O<F4H9FQA9W,I.PT**PT*
M*PEI9B`H<VEG;F%L7W!E;F1I;F<H8W5R<F5N="D@?'P@(71M;RE[#0HK"0EF
M;W)C95]C;&]S92AC<&TI.PT**PD)1$5"54=0*#$L("))24,@<F5A9#H@=&EM
M96]U="%<;B(I.PT**PD)<F5T=7)N("U%24\[#0HK"7T-"BLC:69D968@23)#
M7T-(25!?15)2051!#0HK"2\J($-H:7`@97)R871A+"!C;&5A<B!E;F%B;&4N
M(%1H:7,@:7,@;F]T(&YE961E9"!O;B!R978@1#0@0U!5<RX-"BL)($1I<V%B
M;&EN9R!),D,@=&]O(&5A<FQY(&UA>2!C875S92!T;V\@<VAO<G0@<W1O<"!C
M;VYD:71I;VX@*B\-"BL)=61E;&%Y*#0I.PT**PEI,F,M/FDR8U]I,FUO9"`F
M/2!^,3L-"BLC96YD:68-"BL-"BL)1$5"54=0*#$L(")T>"!S8R`E,#1X+"!R
M>"!S8R`E,#1X7&XB+"!T8F1F+3YC8F1?<V,L(')B9&8M/F-B9%]S8RD[#0HK
M#0HK"6EF("AT8F1F+3YC8F1?<V,@)B!"1%]30U]214%$62D@>PT**PD)<')I
M;G1K*$M%4DY?24Y&3R`B24E#(')E860[(&-O;7!L971E(&)U="!T8G5F(')E
M861Y7&XB*3L-"BL)"69O<F-E7V-L;W-E*&-P;2D[#0HK"0EP<FEN=&LH2T52
M3E])3D9/(")T>"!S8R`E,#1X+"!R>"!S8R`E,#1X7&XB+`T**PD)("`@("`@
M('1B9&8M/F-B9%]S8RP@<F)D9BT^8V)D7W-C*3L-"BL)?0T**PT**PEI9B`H
M=&)D9BT^8V)D7W-C("8@0D1?4T-?3D%+*2![#0HK"0E$14)51U`H,2P@(DE)
M0R!R96%D.R!N;R!A8VM<;B(I.PT**PD)<F5T=7)N("U%4D5-3U1%24\[#0HK
M"7T-"BL-"BL):68@*')B9&8M/F-B9%]S8R`F($)$7U-#7T5-4%19*2![#0HK
M"0DO*B!F;W)C95]C;&]S92AC<&TI.R`J+PT**PD)1$5"54=0*#$L("))24,@
M<F5A9#L@8V]M<&QE=&4@8G5T(')B=68@96UP='E<;B(I.PT**PD)1$5"54=0
M*#$L(")T>"!S8R`E,#1X+"!R>"!S8R`E,#1X7&XB+"!T8F1F+3YC8F1?<V,L
M(')B9&8M/F-B9%]S8RD[#0HK"0ER971U<FX@+45214U/5$5)3SL-"BL)?0T*
M*PT**PEI9B`H<F)D9BT^8V)D7W-C("8@0D1?4T-?3U8I('L-"BL)"41%0E5'
M4"@Q+"`B24E#(')E860[($]V97)R=6Y<;B(I.PT**PD)<F5T=7)N("U%4D5-
M3U1%24\[.PT**PE]#0HK#0HK"41%0E5'4"@Q+"`B<F5A9"`E9"!B>71E<UQN
M(BP@<F)D9BT^8V)D7V1A=&QE;BD[#0HK#0HK"6EF("AR8F1F+3YC8F1?9&%T
M;&5N(#P@8V]U;G0I('L-"BL)"41%0E5'4"@Q+"`B24E#(')E860[('-H;W)T
M+"!W86YT960@)60@9V]T("5D7&XB+"!C;W5N="P-"BL)"2`@("`@("!R8F1F
M+3YC8F1?9&%T;&5N*3L-"BL)"7)E='5R;B`P.PT**PE]#0HK#0HK"7)E='5R
M;B!C;W5N=#L-"BM]#0HK#0HK+RH@5W)I=&4@=&\@24E#+BXN#0HK("H@861D
M<B`](&%D9')E<W,@8GET92P@=VET:"!R+W<@9FQA9R!A;')E861Y('-E=`T*
M*R`J+PT**W-T871I8R!I;G0-"BMC<&U?:6EC7W=R:71E*'-T<G5C="!I,F-?
M86QG;U\X>'A?9&%T82`J8W!M+"!U7V-H87(@86)Y=&4L(&-H87(@*F)U9BQI
M;G0@8V]U;G0I#0HK>PT**PEV;VQA=&EL92!I:6-?="`J:6EP(#T@8W!M+3YI
M:7`[#0HK"79O;&%T:6QE(&DR8SAX>%]T("II,F,@/2!C<&TM/FDR8SL-"BL)
M=F]L871I;&4@8W!M.'AX7W0@*F-P(#T@8W!M+3YC<#L-"BL)=F]L871I;&4@
M8V)D7W0)*G1B9&8[#0HK"75?8VAA<B`J=&([#0HK"75N<VEG;F5D(&QO;F<@
M9FQA9W,L('1M;SL-"BL-"BL)+RH@8VAE8VL@9F]R(&%N9"!U<V4@82!M:6-R
M;V-O9&4@<F5L;V-A=&EO;B!P871C:"`J+PT**PEI9B`H8W!M+3YR96QO8RD-
M"BL)"6-P;5]R97-E=%]I:6-?<&%R86US*&EI<"D[#0HK"71B(#T@8W!M+3YT
M96UP.PT**PET8B`]("AU7V-H87(@*BDH*"AU:6YT*71B("L@,34I("8@?C$U
M*3L-"BL)*G1B(#T@86)Y=&4["0DO*B!$979I8V4@861D<F5S<R!B>71E('<O
M<G<@9FQA9R`J+PT**PT**PEF;'5S:%]D8V%C:&5?<F%N9V4H*'5N<VEG;F5D
M(&QO;F<I('1B+"`H=6YS:6=N960@;&]N9RD@*'1B*S$I*3L-"BL)9FQU<VA?
M9&-A8VAE7W)A;F=E*"AU;G-I9VYE9"!L;VYG*2!B=68L("AU;G-I9VYE9"!L
M;VYG*2`H8G5F*V-O=6YT*2D[#0HK#0HK"41%0E5'4"@Q+"`B8W!M7VEI8U]W
M<FET92AA8GET93TP>"5X*5QN(BP@86)Y=&4I.PT**PT**PDO*B!S970@=7`@
M,B!D97-C<FEP=&]R<R`J+PT**PET8F1F(#T@*&-B9%]T("HI)F-P+3YC<%]D
M<&UE;5MI:7`M/FEI8U]T8F%S95T[#0HK#0HK"71B9&9;,%TN8V)D7V)U9F%D
M9'(@/2!?7W!A*'1B*3L-"BL)=&)D9ELP72YC8F1?9&%T;&5N(#T@,3L-"BL)
M=&)D9ELP72YC8F1?<V,@/2!"1%]30U]214%$62!\($)$7TE)0U]35$%25#L-
M"BL-"BL)=&)D9ELQ72YC8F1?8G5F861D<B`](%]?<&$H8G5F*3L-"BL)=&)D
M9ELQ72YC8F1?9&%T;&5N(#T@8V]U;G0[#0HK"71B9&9;,5TN8V)D7W-C(#T@
M0D1?4T-?4D5!1%D@?"!"1%]30U])3E124%0@?"!"1%]30U],05-4('P@0D1?
M4T-?5U)!4#L-"BL-"BL)+RH@0VAI<"!B=6<L('-E="!E;F%B;&4@:&5R92`J
M+PT**PEL;V-A;%]I<G%?<V%V92AF;&%G<RD[#0HK"6DR8RT^:3)C7VDR8VUR
M(#T@,'@Q,SL)+RH@16YA8FQE('-O;64@:6YT97)U<'1S("HO#0HK"6DR8RT^
M:3)C7VDR8V5R(#T@,'AF9CL-"BL):3)C+3YI,F-?:3)M;V0@?#T@,3L)+RH@
M16YA8FQE("HO#0HK"2\J#0HK"2`J($)E9VEN('1R86YS;6ES<VEO;B!A;F0@
M9F]R8V4@;6%S=&5R+@T**PD@*B!3;VUE(&5R<F]R<RA#3"D@8VQE87)S('1H
M92!-+U,@8FET#0HK"2`J+PT**PEI,F,M/FDR8U]I,F-O;2!\/2`P>#@P('P@
M,'@P,3L-"BL-"BL)+RH@5V%I="!F;W(@24E#('1R86YS9F5R("HO#0HK"71M
M;R`](&EN=&5R<G5P=&EB;&5?<VQE97!?;VY?=&EM96]U="@F:6EC7W=A:70L
M,2I(6BD[#0HK"6QO8V%L7VER<5]R97-T;W)E*&9L86=S*3L-"BL-"BL):68@
M*'-I9VYA;%]P96YD:6YG*&-U<G)E;G0I('Q\("%T;6\I>PT**PD)9F]R8V5?
M8VQO<V4H8W!M*3L-"BL)"6EF("@A=&UO*0T**PD)"41%0E5'4"@Q+"`B24E#
M('=R:71E.B!T:6UE;W5T(5QN(BD[#0HK"0ER971U<FX@+45)3SL-"BL)?0T*
M*PT**R-I9B!),D-?0TA)4%]%4E)!5$$-"BL)+RH@0VAI<"!E<G)A=&$L(&-L
M96%R(&5N86)L92X@5&AI<R!I<R!N;W0@;F5E9&5D(&]N(')E=B!$-"!#4%5S
M+@T**PD@1&ES86)L:6YG($DR0R!T;V\@96%R;'D@;6%Y(&-A=7-E('1O;R!S
M:&]R="!S=&]P(&-O;F1I=&EO;B`J+PT**PEU9&5L87DH-"D[#0HK"6DR8RT^
M:3)C7VDR;6]D("8]('XQ.PT**R-E;F1I9@T**PE$14)51U`H,2P@(G1X,"!S
M8R`E,#1X+"!T>#$@<V,@)3`T>%QN(BP@=&)D9ELP72YC8F1?<V,L#0HK"2`@
M("`@("!T8F1F6S%=+F-B9%]S8RD[#0HK#0HK"6EF("@H=&)D9ELP72YC8F1?
M<V,@?"!T8F1F6S%=+F-B9%]S8RD@)B!"1%]30U].04LI('L-"BL)"41%0E5'
M4"@Q+"`B24E#('=R:71E.R!N;R!A8VM<;B(I.PT**PD)<F5T=7)N(#`[#0HK
M"7T-"BL-"BL):68@*"AT8F1F6S!=+F-B9%]S8R!\('1B9&9;,5TN8V)D7W-C
M*2`F($)$7U-#7U)%0419*2![#0HK"0E$14)51U`H,2P@(DE)0R!W<FET93L@
M8V]M<&QE=&4@8G5T('1B=68@<F5A9'E<;B(I.PT**PD)<F5T=7)N(#`[#0HK
M"7T-"BL-"BL)<F5T=7)N(&-O=6YT.PT**WT-"BL-"BLO*B!3964@:68@86X@
M24E#(&%D9')E<W,@97AI<W1S+BX-"BL@*B!A9&1R(#T@-R!B:70@861D<F5S
M<RP@=6YS:&EF=&5D#0HK("HO#0HK<W1A=&EC(&EN=`T**V-P;5]I:6-?=')Y
M861D<F5S<RAS=')U8W0@:3)C7V%L9V]?.'AX7V1A=&$@*F-P;2P@:6YT(&%D
M9'(I#0HK>PT**PEV;VQA=&EL92!I:6-?="`J:6EP(#T@8W!M+3YI:7`[#0HK
M"79O;&%T:6QE(&DR8SAX>%]T("II,F,@/2!C<&TM/FDR8SL-"BL)=F]L871I
M;&4@8W!M.'AX7W0@*F-P(#T@8W!M+3YC<#L-"BL)=F]L871I;&4@8V)D7W0@
M*G1B9&8L("IR8F1F.PT**PEU7V-H87(@*G1B.PT**PEU;G-I9VYE9"!L;VYG
M(&9L86=S+"!L96XL('1M;SL-"BL-"BL)1$5"54=0*#(L(")C<&U?:6EC7W1R
M>6%D9')E<W,H8W!M/25P+&%D9'(])60I7&XB+"!C<&TL(&%D9'(I.PT**PT*
M*PDO*B!C:&5C:R!F;W(@86YD('5S92!A(&UI8W)O8V]D92!R96QO8V%T:6]N
M('!A=&-H("HO#0HK"6EF("AC<&TM/G)E;&]C*0T**PD)8W!M7W)E<V5T7VEI
M8U]P87)A;7,H:6EP*3L-"BL-"BL):68@*&%D9'(@/3T@,"D@>PT**PD)1$5"
M54=0*#$L(")I:7`@)7`L(&1P7V%D9'(@,'@E>%QN(BP@8W!M+3YI:7`L(&-P
M;2T^9'!?861D<BD[#0HK"0E$14)51U`H,2P@(FEI8U]T8F%S92`E9"P@<E]T
M8F%S92`E9%QN(BP@:6EP+3YI:6-?=&)A<V4L#0HK"0D@("`@("`@<E]T8F%S
M92D[#0HK"7T-"BL-"BL)=&)D9B`]("AC8F1?="`J*29C<"T^8W!?9'!M96U;
M:6EP+3YI:6-?=&)A<V5=.PT**PER8F1F(#T@*&-B9%]T("HI)F-P+3YC<%]D
M<&UE;5MI:7`M/FEI8U]R8F%S95T[#0HK#0HK"71B(#T@8W!M+3YT96UP.PT*
M*PET8B`]("AU7V-H87(@*BDH*"AU:6YT*71B("L@,34I("8@?C$U*3L-"BL-
M"BL)+RH@9&\@82!S:6UP;&4@<F5A9"`J+PT**PET8ELP72`]("AA9&1R(#P\
M(#$I('P@,3L)+RH@9&5V:6-E(&%D9')E<W,@*"L@<F5A9"D@*B\-"BL);&5N
M(#T@,CL-"BL-"BL)9FQU<VA?9&-A8VAE7W)A;F=E*"AU;G-I9VYE9"!L;VYG
M*2!T8BP@*'5N<VEG;F5D(&QO;F<I("AT8BLQ*2D[#0HK#0HK"71B9&8M/F-B
M9%]B=69A9&1R(#T@7U]P82AT8BD[#0HK"71B9&8M/F-B9%]D871L96X@/2!L
M96X[#0HK"71B9&8M/F-B9%]S8R`]#0HK"0E"1%]30U]214%$62!\($)$7U-#
M7TQ!4U0@?`T**PD)0D1?4T-?5U)!4"!\($)$7TE)0U]35$%25#L-"BL-"BL)
M<F)D9BT^8V)D7V1A=&QE;B`](#`[#0HK"7)B9&8M/F-B9%]B=69A9&1R(#T@
M7U]P82AT8BLR*3L-"BL)<F)D9BT^8V)D7W-C(#T@0D1?4T-?14U05%D@?"!"
M1%]30U]74D%0('P@0D1?4T-?24Y44E!4.PT**PT**PDO*B!#:&EP(&)U9RP@
M<V5T(&5N86)L92!H97)E("HO#0HK"6QO8V%L7VER<5]S879E*&9L86=S*3L-
M"BL):3)C+3YI,F-?:3)C;7(@/2`P>#$S.PDO*B!%;F%B;&4@<V]M92!I;G1E
M<G5P=',@*B\-"BL):3)C+3YI,F-?:3)C97(@/2`P>&9F.PT**PEI,F,M/FDR
M8U]I,FUO9"!\/2`Q.PDO*B!%;F%B;&4@*B\-"BL)+RH-"BL)("H@0F5G:6X@
M=')A;G-M:7-S:6]N(&%N9"!F;W)C92!M87-T97(N#0HK"2`J(%-O;64@97)R
M;W)S*$-,*2!C;&5A<G,@=&AE($TO4R!B:70-"BL)("HO#0HK"6DR8RT^:3)C
M7VDR8V]M('P](#!X.#`@?"`P>#`Q.PT**PT**PDO*B!786ET(&9O<B!)24,@
M=')A;G-F97(@*B\-"BL)=&UO(#T@:6YT97)R=7!T:6)L95]S;&5E<%]O;E]T
M:6UE;W5T*"9I:6-?=V%I="PQ*DA:*3L-"BL);&]C86Q?:7)Q7W)E<W1O<F4H
M9FQA9W,I.PT**PT**R-I9F1E9B!),D-?0TA)4%]%4E)!5$$-"BL)+RH@0VAI
M<"!E<G)A=&$L(&-L96%R(&5N86)L92X@5&AI<R!I<R!N;W0@;F5E9&5D(&]N
M(')E=B!$-"!#4%5S+@T**PD@1&ES86)L:6YG($DR0R!T;V\@96%R;'D@;6%Y
M(&-A=7-E('1O;R!S:&]R="!S=&]P(&-O;F1I=&EO;B`J+PT**PEU9&5L87DH
M-"D[#0HK"6DR8RT^:3)C7VDR;6]D("8]('XQ.PT**R-E;F1I9@T**PT**PEI
M9B`H<VEG;F%L7W!E;F1I;F<H8W5R<F5N="D@?'P@(71M;RE[#0HK"0EF;W)C
M95]C;&]S92AC<&TI.PT**PD):68@*"%T;6\I#0HK"0D)1$5"54=0*#$L("))
M24,@=')Y861D<F5S<SH@=&EM96]U="%<;B(I.PT**PD)<F5T=7)N("U%24\[
M#0HK"7T-"BL-"BL)1$5"54=0*#(L(")B86-K(&9R;VT@<VQE97!<;B(I.PT*
M*PT**PEI9B`H=&)D9BT^8V)D7W-C("8@0D1?4T-?3D%+*2![#0HK"0E$14)5
M1U`H,BP@(DE)0R!T<GD[(&YO(&%C:UQN(BD[#0HK"0ER971U<FX@,#L-"BL)
M?0T**PT**PEI9B`H=&)D9BT^8V)D7W-C("8@0D1?4T-?4D5!1%DI#0HK"0EP
M<FEN=&LH2T523E])3D9/("))24,@=')Y.R!C;VUP;&5T92!B=70@=&)U9B!R
M96%D>5QN(BD[#0HK#0HK"7)E='5R;B`Q.PT**WT-"BL-"BMS=&%T:6,@:6YT
M(&-P;5]X9F5R*'-T<G5C="!I,F-?861A<'1E<B`J:3)C7V%D87`L#0HK"0D@
M("`@<W1R=6-T(&DR8U]M<V<@;7-G<UM=+`T**PD)("`@(&EN="!N=6TI#0HK
M>PT**PES=')U8W0@:3)C7V%L9V]?.'AX7V1A=&$@*F%D87`@/2!I,F-?861A
M<"T^86QG;U]D871A.PT**PES=')U8W0@:3)C7VUS9R`J<&US9SL-"BL):6YT
M(&DL(')E=#L-"BL)=5]C:&%R(&%D9'([#0HK#0HK"69O<B`H:2`](#`[(&D@
M/"!N=6T[(&DK*RD@>PT**PD)<&US9R`]("9M<V=S6VE=.PT**PT**PD)1$5"
M54=0*#$L("(C)60@861D<CTP>"5X(&9L86=S/3!X)7@@;&5N/25D7&X@8G5F
M/25P7&XB+`T**PD)("`@("`@(&DL('!M<V<M/F%D9'(L('!M<V<M/F9L86=S
M+"!P;7-G+3YL96XL('!M<V<M/F)U9BD[#0HK#0HK"0EA9&1R(#T@<&US9RT^
M861D<B`\/"`Q.PT**PD):68@*'!M<V<M/F9L86=S("8@23)#7TU?4D0I#0HK
M"0D)861D<B!\/2`Q.PT**PD):68@*'!M<V<M/F9L86=S("8@23)#7TU?4D56
M7T1)4E]!1$12*0T**PD)"6%D9'(@7CT@,3L-"BL-"BL)"6EF("AP;7-G+3YF
M;&%G<R`F($DR0U]-7U)$*2![#0HK"0D)+RH@<F5A9"!B>71E<R!I;G1O(&)U
M9F9E<BHO#0HK"0D)<F5T(#T@8W!M7VEI8U]R96%D*&%D87`L(&%D9'(L('!M
M<V<M/F)U9BP@<&US9RT^;&5N*3L-"BL)"0E$14)51U`H,2P@(G)E860@)60@
M8GET97-<;B(L(')E="D[#0HK"0D):68@*')E="`\('!M<V<M/FQE;BD-"BL)
M"0D)<F5T=7)N("AR970@/"`P*3\@<F5T.BU%4D5-3U1%24\[#0HK"0E](&5L
M<V4@>PT**PD)"2\J('=R:71E(&)Y=&5S(&9R;VT@8G5F9F5R("HO#0HK"0D)
M<F5T(#T@8W!M7VEI8U]W<FET92AA9&%P+"!A9&1R+"!P;7-G+3YB=68L('!M
M<V<M/FQE;BD[#0HK"0D)1$5"54=0*#$L(")W<F]T92`E9%QN(BP@<F5T*3L-
M"BL)"0EI9B`H<F5T(#P@<&US9RT^;&5N*0T**PD)"0ER971U<FX@*')E="`\
M(#`I/R!R970Z+45214U/5$5)3SL-"BL)"7T-"BL)?0T**PER971U<FX@;G5M
M.PT**WT-"BL-"BMS=&%T:6,@=3,R(&-P;5]F=6YC*'-T<G5C="!I,F-?861A
M<'1E<B`J861A<"D-"BM[#0HK"7)E='5R;B!),D-?1E5.0U]334)54U]%355,
M('P@23)#7T953D-?,3!"251?041$4B!\#0HK"2`@("`@("!),D-?1E5.0U]0
M4D]43T-/3%]-04Y'3$E.1SL-"BM]#0HK#0HK<W1A=&EC('-T<G5C="!I,F-?
M86QG;W)I=&AM(&DR8U]A;&=O7SAX>"`]('L-"BL)+FYA;64@/2`B35!#.'AX
M($-032!A;&=O<FET:&TB+`T**PDN:60@/2!),D-?04Q'3U]-4$,X6%@L#0HK
M"2YM87-T97)?>&9E<B`](&-P;5]X9F5R+`T**PDN9G5N8W1I;VYA;&ET>2`]
M(&-P;5]F=6YC+`T**WT[#0HK#0HK+RH-"BL@*B!R96=I<W1E<FEN9R!F=6YC
M=&EO;G,@=&\@;&]A9"!A;&=O<FET:&US(&%T(')U;G1I;64-"BL@*B\-"BMI
M;G0@:3)C7SAX>%]A9&1?8G5S*'-T<G5C="!I,F-?861A<'1E<B`J861A<"D-
M"BM[#0HK"6EN="!I.PT**PES=')U8W0@:3)C7V%L9V]?.'AX7V1A=&$@*F-P
M;5]A9&%P(#T@861A<"T^86QG;U]D871A.PT**PT**PE$14)51U`H,2P@(FAW
M(')O=71I;F5S(&9O<B`E<R!R96=I<W1E<F5D+EQN(BP@861A<"T^;F%M92D[
M#0HK#0HK"2\J(')E9VES=&5R(&YE=R!A9&%P=&5R('1O(&DR8R!M;V1U;&4N
M+BX@*B\-"BL-"BL)861A<"T^:60@?#T@:3)C7V%L9V]?.'AX+FED.PT**PEA
M9&%P+3YA;&=O(#T@)FDR8U]A;&=O7SAX>#L-"BL-"BL):3)C7V%D9%]A9&%P
M=&5R*&%D87`I.PT**PEC<&U?:6EC7VEN:70H8W!M7V%D87`I.PT**PT**PDO
M*B!S8V%N(&)U<R`J+PT**PEI9B`H8W!M7W-C86XI('L-"BL)"7!R:6YT:RA+
M15).7TE.1D\@(B5S.B!S8V%N;FEN9R!B=7,@)7,N+BY<;B(L(&UO9'5L95]N
M86UE+`T**PD)("`@("`@(&%D87`M/FYA;64I.PT**PD)9F]R("AI(#T@,#L@
M:2`\(#$R.#L@:2LK*0T**PD)"6EF("AC<&U?:6EC7W1R>6%D9')E<W,H8W!M
M7V%D87`L(&DI*2![#0HK"0D)"7!R:6YT:R@B*"4P,G@I(BP@:2`\/"`Q*3L-
M"BL)"0E]#0HK"0EP<FEN=&LH(EQN(BD[#0HK"7T-"BL)<F5T=7)N(#`[#0HK
M?0T**PT**VEN="!I,F-?.'AX7V1E;%]B=7,H<W1R=6-T(&DR8U]A9&%P=&5R
M("IA9&%P*0T**WL-"BL):6YT(')E<SL-"BL)<W1R=6-T(&DR8U]A;&=O7SAX
M>%]D871A("IC<&U?861A<"`](&%D87`M/F%L9V]?9&%T83L-"BL-"BL)8W!M
M7VEI8U]S:'5T9&]W;BAC<&U?861A<"D[#0HK#0HK"6EF("@H<F5S(#T@:3)C
M7V1E;%]A9&%P=&5R*&%D87`I*2`\(#`I#0HK"0ER971U<FX@<F5S.PT**PT*
M*PEP<FEN=&LH2T523E])3D9/("(E<SH@861A<'1E<B!U;G)E9VES=&5R960Z
M("5S7&XB+"!M;V1U;&5?;F%M92P-"BL)("`@("`@(&%D87`M/FYA;64I.PT*
M*PT**PER971U<FX@,#L-"BM]#0HK#0HK;6]D=6QE7W!A<F%M*&-P;5]D96)U
M9RP@:6YT+"!37TE254=/('P@4U])5U534BD[#0HK34]$54Q%7U!!4DU?1$53
M0RAC<&U?9&5B=6<L(")3971S('1H92!D96)U9R!L979E;"X@*#`@/2!N;VYE
M+"`Q(#T@;F]R;6%L+"`B#0HK"0D@(CXQ(#T@<&QE;G1Y(BD[#0HK34]$54Q%
M7T%55$A/4B@B0G)A9"!087)K97(@/&)R861`:&5E;'1O92YC;VT^(BD[#0HK
M34]$54Q%7T1%4T-225!424].*")),D,M0G5S($U00SA86"!A;&=O<FET:&TB
M*3L-"BM-3T153$5?3$E#14Y312@B1U!,(BD[#0HK#0HK15A03U)47U-934)/
M3"AI,F-?.'AX7V%D9%]B=7,I.PT**T584$]25%]364U"3TPH:3)C7SAX>%]D
M96Q?8G5S*3L-"BL-"DEN9&5X.B`R+C8M.'AX+V1R:79E<G,O:3)C+V%L9V]S
M+TUA:V5F:6QE#0H]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]
M/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]#0HM+2T@,BXV+3AX
M>"YO<FEG+V1R:79E<G,O:3)C+V%L9V]S+TUA:V5F:6QE"3(P,#4M,#@M,#@@
M,#DZ-3`Z-3<N,#`P,#`P,#`P("TP,S`P#0HK*RL@,BXV+3AX>"]D<FEV97)S
M+VDR8R]A;&=O<R]-86ME9FEL90DR,#`U+3`X+3`X(#`Y.C4P.C4Y+C`P,#`P
M,#`P,"`M,#,P,`T*0$`@+3@L-B`K."PW($!`#0H@;V)J+20H0T].1DE'7TDR
M0U]!3$=/251%*0DK/2!I,F,M86QG;RUI=&4N;PT*(&]B:BTD*$-/3D9)1U])
M,D-?04Q'3U]324)95$4I"2L](&DR8RUA;&=O+7-I8GET92YO#0H@;V)J+20H
M0T].1DE'7TDR0U]!3$=/7U-'22D)*ST@:3)C+6%L9V\M<V=I+F\-"BMO8FHM
M)"A#3TY&24=?23)#7T%,1T\X6%@I"2L](&DR8RUA;&=O+3AX>"YO#0H@#0H@
M:69E<2`H)"A#3TY&24=?23)#7T1%0E5'7T%,1T\I+'DI#0H@15A44D%?0T9,
M04=3("L]("U$1$5"54<-"DEN9&5X.B`R+C8M.'AX+VEN8VQU9&4O;&EN=7@O
M:3)C+6%L9V\M.'AX+F@-"CT]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]
M/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T]/3T-"BTM+2`O
M9&5V+VYU;&P),3DW,"TP,2TP,2`P,#HP,#HP,"XP,#`P,#`P,#`@*S`P,#`-
M"BLK*R`R+C8M.'AX+VEN8VQU9&4O;&EN=7@O:3)C+6%L9V\M.'AX+F@),C`P
M-2TP."TP."`P.3HU,#HU.2XP,#`P,#`P,#`@+3`S,#`-"D!`("TP+#`@*S$L
M,C@@0$`-"BLO*B`M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM("HO#0HK
M+RH@:3)C+6%L9V\M.'AX+F@@:3)C(&1R:79E<B!A;&=O<FET:&US(&9O<B!-
M4%@X6%@@0U!-"0D)("`@("`J+PT**R\J("TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2T@*B\-"BL-"BLO*B`D260D("HO#0HK#0HK(VEF;F1E9B!),D-?
M04Q'3U\X6%A?2`T**R-D969I;F4@23)#7T%,1T]?.%A87T@-"BL-"BLC:6YC
M;'5D92`\;&EN=7@O:3)C+F@^#0HK(VEN8VQU9&4@/&%S;2\X>'A?:6UM87`N
M:#X-"BLC:6YC;'5D92`\87-M+V-O;6UP<F]C+F@^#0HK#0HK<W1R=6-T(&DR
M8U]A;&=O7SAX>%]D871A('L-"BL)=6EN="!D<%]A9&1R.PT**PEI;G0@<F5L
M;V,[#0HK"79O;&%T:6QE(&DR8SAX>%]T("II,F,[#0HK"79O;&%T:6QE(&EI
M8U]T"2II:7`[#0HK"79O;&%T:6QE(&-P;3AX>%]T("IC<#L-"BL-"BL)=5]C
M:&%R"71E;7!;-3$S73L-"BM].PT**PT**VEN="!I,F-?.'AX7V%D9%]B=7,H
M<W1R=6-T(&DR8U]A9&%P=&5R("HI.PT**VEN="!I,F-?.'AX7V1E;%]B=7,H
M<W1R=6-T(&DR8U]A9&%P=&5R("HI.PT**PT**R-E;F1I9B`O*B!),D-?04Q'
13U\X6%A?2"`J+PT**PT*#0I
`
end

^ permalink raw reply	[flat|nested] 13+ messages in thread
* 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors
@ 2005-08-10  7:27 cajus.hahn
  2005-08-10 13:58 ` Marcelo Tosatti
  0 siblings, 1 reply; 13+ messages in thread
From: cajus.hahn @ 2005-08-10  7:27 UTC (permalink / raw)
  To: linuxppc-embedded





Hi all,

I had some problems on my MPC855M based board when I tried to access th=
e
i2c bus.
The cause were some disturbances on the i2c bus. If a slave device or
another master device hold the SDA or SCL line low, the CPM will get in=
to a
state, where no more transmissions are made. The  only way I found, to =
get
the CPM back to work, was a complete re-initialisation. -> force_reinit=
()
In this case the busy-wait for transmissions with count < 16 will lock =
the
complete system (CPU load 99.9%)
I added the define I2C_BUSY_WAIT to switch between faster access or saf=
er
system.
I found out that the i2c-algo-8xx.c has a bug in cpm_iic_read() and
cpm_iic_write(): the timeout detection will not work in the case of cou=
nt <
16.
I also added the define I2C_INTERRUPTIBLE_SLEEP: the old driver reporte=
d
IO-error (-EIO) if a timeout occured (which was not working, see above)=
 or
if a signal was pending. This caused some problems if the process recei=
ves
user-signals. The driver will report IO-error, which is not correct. Wi=
th
the busy-wait this effect might not be seen, because there will be no
process scheduling -> no signals might be send.
My modified file is appended. The defines for  I2C_BUSY_WAIT and
I2C_INTERRUPTIBLE_SLEEP are active, which let the driver act like the o=
ld
one.
Maybe this is helpful for others too and some of the modifications find=

it=B4s way into the official kernel tree.

Cajus Hahn

/*
 * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
 * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
 *
    This program is free software; you can redistribute it and/or modif=
y
    it under the terms of the GNU General Public License as published b=
y
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * moved into proper i2c interface; separated out platform specific
 * parts into i2c-rpx.c
 * Brad Parker (brad@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.1.1.1 2004/12/10 08:44:35 cajus Exp $ */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/sched.h>

#include <asm/mpc8xx.h>
#include <asm/commproc.h>

#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 olde=
r
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 */
#define I2C_INTERRUPTIBLE_SLEEP /* Uncomment this if you want the waiti=
ng
in cpm_iic_read and
                                         cpm_iic_write beeing interrupt=
able
by signals */

static wait_queue_head_t iic_wait;
static ushort r_tbase, r_rbase;

int cpm_scan =3D 0;
int cpm_debug =3D 0;

static  void
cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
 {
      volatile i2c8xx_t *i2c =3D (i2c8xx_t *)dev_id;

      if (cpm_debug > 1)
            printk(KERN_DEBUG "cpm_iic_interrupt(dev_id=3D%p)\n", dev_i=
d);

#ifdef I2C_CHIP_ERRATA
      /* Chip errata, clear enable.
       * This seems to not be needed on rev D4 or newer CPUs.
       * Someone with an older CPU needs to verify this.
       */
      i2c->i2c_i2mod &=3D ~1;
#endif

      /* Clear interrupt.
      */
      i2c->i2c_i2cer =3D 0xff;

      /* Get 'me going again.
      */
#ifdef I2C_INTERRUPTIBLE_SLEEP
      wake_up_interruptible(&iic_wait);
#else
      wake_up(&iic_wait);
#endif
}

static void
cpm_iic_init(struct i2c_algo_8xx_data *cpm_adap)
{
      volatile iic_t          *iip =3D cpm_adap->iip;
      volatile i2c8xx_t *i2c =3D cpm_adap->i2c;
      unsigned char brg;
      bd_t *bd =3D (bd_t *)__res;

      if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init() - iip=3D%p\n",ii=
p);

      /* Initialize the parameter ram.
       * We need to make sure many things are initialized to zero,
       * especially in the case of a microcode patch.
       */
      iip->iic_rstate =3D 0;
      iip->iic_rdp =3D 0;
      iip->iic_rbptr =3D 0;
      iip->iic_rbc =3D 0;
      iip->iic_rxtmp =3D 0;
      iip->iic_tstate =3D 0;
      iip->iic_tdp =3D 0;
      iip->iic_tbptr =3D 0;
      iip->iic_tbc =3D 0;
      iip->iic_txtmp =3D 0;

      /* Set up the IIC parameters in the parameter ram.
      */
      iip->iic_tbase =3D r_tbase =3D cpm_adap->dp_addr;
      iip->iic_rbase =3D r_rbase =3D cpm_adap->dp_addr + sizeof(cbd_t)*=
2;

      iip->iic_tfcr =3D SMC_EB;
      iip->iic_rfcr =3D SMC_EB;

      /* Set maximum receive size.
      */
      iip->iic_mrblr =3D CPM_MAX_READ;

      /* Initialize Tx/Rx parameters.
      */
      if (cpm_adap->reloc =3D=3D 0) {
            volatile cpm8xx_t *cp =3D cpm_adap->cp;

            cp->cp_cpcr =3D
                  mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FL=
G;
            while (cp->cp_cpcr & CPM_CR_FLG);
      } else {
            iip->iic_rbptr =3D iip->iic_rbase;
            iip->iic_tbptr =3D iip->iic_tbase;
            iip->iic_rstate   =3D 0;
            iip->iic_tstate   =3D 0;
      }

      /* Select an arbitrary address.  Just make sure it is unique.
      */
      i2c->i2c_i2add =3D 0xfe;

      /* Make clock run at 60 KHz.
      */
      brg =3D (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
      i2c->i2c_i2brg =3D brg;

      i2c->i2c_i2mod =3D 0x00;
      i2c->i2c_i2com =3D 0x01; /* Master mode */

      /* Disable interrupts.
      */
      i2c->i2c_i2cmr =3D 0;
      i2c->i2c_i2cer =3D 0xff;

      init_waitqueue_head(&iic_wait);

      /* Install interrupt handler.
      */
      if (cpm_debug) {
            printk (KERN_DEBUG "%s[%d] Install ISR for IRQ %d\n",
                  __func__,__LINE__, CPMVEC_I2C);
      }
      cpm_install_handler(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
}


static int
cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm_adap)
{
      volatile i2c8xx_t *i2c =3D cpm_adap->i2c;

      /* Shut down IIC.
      */
      i2c->i2c_i2mod &=3D ~1;
      i2c->i2c_i2cmr =3D 0;
      i2c->i2c_i2cer =3D 0xff;

      return(0);
}

static void
cpm_reset_iic_params(volatile iic_t *iip)
{
      iip->iic_tbase =3D r_tbase;
      iip->iic_rbase =3D r_rbase;

      iip->iic_tfcr =3D SMC_EB;
      iip->iic_rfcr =3D SMC_EB;

      iip->iic_mrblr =3D CPM_MAX_READ;

      iip->iic_rstate =3D 0;
      iip->iic_rdp =3D 0;
      iip->iic_rbptr =3D iip->iic_rbase;
      iip->iic_rbc =3D 0;
      iip->iic_rxtmp =3D 0;
      iip->iic_tstate =3D 0;
      iip->iic_tdp =3D 0;
      iip->iic_tbptr =3D iip->iic_tbase;
      iip->iic_tbc =3D 0;
      iip->iic_txtmp =3D 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)
{
      volatile i2c8xx_t *i2c =3D cpm->i2c;

        if (cpm_debug)
            printk(KERN_DEBUG "force_close()");

      if (cpm->reloc =3D=3D 0) { /* micro code disabled */
            volatile cpm8xx_t *cp =3D cpm->cp;
            cp->cp_cpcr =3D
                  mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
                  CPM_CR_FLG;

            while (cp->cp_cpcr & CPM_CR_FLG);
      }

      i2c->i2c_i2cmr =3D 0x00;  /* Disable all interrupts */
      i2c->i2c_i2cer =3D 0xff;
}

static void force_reinit(struct i2c_algo_8xx_data *cpm)
{
      volatile iic_t *iip =3D cpm->iip;
      volatile i2c8xx_t *i2c =3D cpm->i2c;
      volatile cpm8xx_t *cp =3D cpm->cp;
      unsigned char brg;
      bd_t *bd =3D (bd_t *)__res;

      // Disable interrupts.
      i2c->i2c_i2cmr =3D 0;
      i2c->i2c_i2cer =3D 0xff;
        // Clear enable
      i2c->i2c_i2mod &=3D ~1;

      // Initialize the parameter ram.
      iip->iic_rstate =3D 0;
      iip->iic_rdp =3D 0;
      iip->iic_rbptr =3D 0;
      iip->iic_rbc =3D 0;
      iip->iic_rxtmp =3D 0;
      iip->iic_tstate =3D 0;
      iip->iic_tdp =3D 0;
      iip->iic_tbptr =3D 0;
      iip->iic_tbc =3D 0;
      iip->iic_txtmp =3D 0;
        iip->iic_tbase =3D r_tbase;
      iip->iic_rbase =3D r_rbase;
      iip->iic_tfcr =3D SMC_EB;
      iip->iic_rfcr =3D SMC_EB;
      iip->iic_mrblr =3D CPM_MAX_READ;

      if (cpm->reloc =3D=3D 0)
        {
            cp->cp_cpcr =3D 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 =3D iip->iic_rbase;
            iip->iic_tbptr =3D iip->iic_tbase;
            iip->iic_rstate   =3D 0;
            iip->iic_tstate   =3D 0;
      }

      // Select an arbitrary address.  Just make sure it is unique.
      i2c->i2c_i2add =3D 0xfe;

      // Make clock run at 60 KHz.
      brg =3D (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
      i2c->i2c_i2brg =3D brg;

      i2c->i2c_i2mod =3D 0x00;
      i2c->i2c_i2com =3D 0x01; /* Master mode */
}

/* Read from IIC...
 * abyte =3D address byte, with r/w flag already set
 */
static int
cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, in=
t
count)
{
      volatile iic_t *iip =3D cpm->iip;
      volatile i2c8xx_t *i2c =3D cpm->i2c;
      volatile cpm8xx_t *cp =3D cpm->cp;
      volatile cbd_t    *tbdf, *rbdf;
      u_char *tb;
      unsigned long flags, tmo, timedout;

      if (count >=3D CPM_MAX_READ)
            return -EINVAL;

      /* check for and use a microcode relocation patch */
      if (cpm->reloc) {
            cpm_reset_iic_params(iip);
      }

      tbdf =3D (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
      rbdf =3D (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];

      /* To read, we need an empty buffer of the proper length.
       * All that is used is the first byte for address, the remainder
       * is just used for timing (and doesn't really have to exist).
       */
      tb =3D cpm->temp;
      tb =3D (u_char *)(((uint)tb + 15) & ~15);
      tb[0] =3D abyte;          /* Device address byte w/rw flag */

      flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));

      if (cpm_debug) printk(KERN_DEBUG "cpm_iic_read(abyte=3D0x%x)\n",
abyte);

      tbdf->cbd_bufaddr =3D __pa(tb);
      tbdf->cbd_datlen =3D count + 1;
      tbdf->cbd_sc =3D
            BD_SC_READY | BD_SC_LAST |
            BD_SC_WRAP | BD_IIC_START;

      iip->iic_mrblr =3D count + 1; /* prevent excessive read, +1
                              is needed otherwise will the
                              RXB interrupt come too early */

      /* flush will invalidate too. */
      flush_dcache_range((unsigned long) buf, (unsigned long) (buf+coun=
t));

      rbdf->cbd_datlen =3D 0;
      rbdf->cbd_bufaddr =3D __pa(buf);

      rbdf->cbd_sc =3D BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
        timedout =3D 0;
#ifdef I2C_BUSY_WAIT
      if(count > 16){
#endif
            /* Chip bug, set enable here */
            local_irq_save(flags);
            i2c->i2c_i2cmr =3D 0x13;  /* Enable some interupts */
            i2c->i2c_i2cer =3D 0xff;
            i2c->i2c_i2mod |=3D 1;    /* Enable */
            i2c->i2c_i2com |=3D 0x80; /* Begin transmission */

            /* Wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
            tmo =3D interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
            tmo =3D sleep_on_timeout(&iic_wait,1*HZ);
#endif
                if(tmo =3D=3D 0) timedout=3D1;
            local_irq_restore(flags);
#ifdef I2C_BUSY_WAIT
      } else { /* busy wait for small transfers, its faster */
            i2c->i2c_i2cmr =3D 0x00;  /* Disable I2C interupts */
            i2c->i2c_i2cer =3D 0xff;
            i2c->i2c_i2mod |=3D 1;    /* Enable */
            i2c->i2c_i2com |=3D 0x80; /* Begin transmission */
            tmo =3D jiffies + 1*HZ;
            while(!(i2c->i2c_i2cer & 0x11 || (timedout =3D
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

#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 &=3D ~1;
#endif

      if (cpm_debug) {
            printk(KERN_DEBUG "tx sc %04x, rx sc %04x\n",
                   tbdf->cbd_sc, rbdf->cbd_sc);
      }

      if (tbdf->cbd_sc & BD_SC_READY) {
            printk(KERN_INFO "IIC read; complete but tbuf ready\n");
            force_close(cpm);
            printk(KERN_INFO "tx sc %04x, rx sc %04x\n",
                   tbdf->cbd_sc, rbdf->cbd_sc);
      }

      if (tbdf->cbd_sc & BD_SC_NAK) {
            if (cpm_debug)
                  printk(KERN_DEBUG "IIC read; no ack\n");
            return -EREMOTEIO;
      }

      if (rbdf->cbd_sc & BD_SC_EMPTY) {
            /* force_close(cpm); */
            if (cpm_debug){
                  printk(KERN_DEBUG "IIC read; complete but rbuf empty\=
n");
                  printk(KERN_DEBUG "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(KERN_DEBUG "IIC read; Overrun\n");
            return -EREMOTEIO;;
      }

      if (cpm_debug) printk(KERN_DEBUG "read %d bytes\n",
rbdf->cbd_datlen);

      if (rbdf->cbd_datlen < count) {
            if (cpm_debug)
                  printk(KERN_DEBUG "IIC read; short, wanted %d got %d\=
n",
                         count, rbdf->cbd_datlen);
            return 0;
      }

      return count;
}

/* Write to IIC...
 * addr =3D address byte, with r/w flag already set
 */
static int
cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,in=
t
count)
{
      volatile iic_t *iip =3D cpm->iip;
      volatile i2c8xx_t *i2c =3D cpm->i2c;
      volatile cpm8xx_t *cp =3D cpm->cp;
      volatile cbd_t    *tbdf;
      u_char *tb;
      unsigned long flags, tmo, timedout;

      /* check for and use a microcode relocation patch */
      if (cpm->reloc) {
            cpm_reset_iic_params(iip);
      }
      tb =3D cpm->temp;
      tb =3D (u_char *)(((uint)tb + 15) & ~15);
      *tb =3D abyte;            /* Device address byte w/rw flag */

      flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
      flush_dcache_range((unsigned long) buf, (unsigned long) (buf+coun=
t));

      if (cpm_debug) printk(KERN_DEBUG "cpm_iic_write(abyte=3D0x%x)\n",=

abyte);

      /* set up 2 descriptors */
      tbdf =3D (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];

      tbdf[0].cbd_bufaddr =3D __pa(tb);
      tbdf[0].cbd_datlen =3D 1;
      tbdf[0].cbd_sc =3D BD_SC_READY | BD_IIC_START;

      tbdf[1].cbd_bufaddr =3D __pa(buf);
      tbdf[1].cbd_datlen =3D count;
      tbdf[1].cbd_sc =3D BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST |
BD_SC_WRAP;

        timedout =3D 0;
#ifdef I2C_BUSY_WAIT
      if(count > 16){
#endif
            /* Chip bug, set enable here */
            local_irq_save(flags);
            i2c->i2c_i2cmr =3D 0x13;  /* Enable some interupts */
            i2c->i2c_i2cer =3D 0xff;
            i2c->i2c_i2mod |=3D 1;    /* Enable */
            i2c->i2c_i2com |=3D 0x80; /* Begin transmission */

            /* Wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
            tmo =3D interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
            tmo =3D sleep_on_timeout(&iic_wait,1*HZ);
#endif
                if(tmo =3D=3D 0) timedout=3D1;
            local_irq_restore(flags);
#ifdef I2C_BUSY_WAIT
      } else {  /* busy wait for small transfers, its faster */
            i2c->i2c_i2cmr =3D 0x00;  /* Disable I2C interupts */
            i2c->i2c_i2cer =3D 0xff;
            i2c->i2c_i2mod |=3D 1;    /* Enable */
            i2c->i2c_i2com |=3D 0x80; /* Begin transmission */
            tmo =3D jiffies + 1*HZ;
            while(!(i2c->i2c_i2cer & 0x12 || (timedout =3D
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.
       Disabling I2C too early may cause too short stop condition */
      udelay(4);
      i2c->i2c_i2mod &=3D ~1;
#endif
      if (cpm_debug) {
            printk(KERN_DEBUG "tx0 sc %04x, tx1 sc %04x\n",
                   tbdf[0].cbd_sc, tbdf[1].cbd_sc);
      }

      if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_NAK) {
            if (cpm_debug)
                  printk(KERN_DEBUG "IIC write; no ack\n");
            return 0;
      }

      if ((tbdf[0].cbd_sc | tbdf[1].cbd_sc) & BD_SC_READY) {
            if (cpm_debug)
                  printk(KERN_DEBUG "IIC write; complete but tbuf
ready\n");
            return 0;
      }

      return count;
}

/* See if an IIC address exists..
 * addr =3D 7 bit address, unshifted
 */
static int
cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
{
      volatile iic_t *iip =3D cpm->iip;
      volatile i2c8xx_t *i2c =3D cpm->i2c;
      volatile cpm8xx_t *cp =3D cpm->cp;
      volatile cbd_t *tbdf, *rbdf;
      u_char *tb;
      unsigned long flags, len, tmo;

      if (cpm_debug > 1)
            printk(KERN_DEBUG "cpm_iic_tryaddress(cpm=3D%p,addr=3D%d)\n=
", cpm,
addr);

      /* check for and use a microcode relocation patch */
      if (cpm->reloc) {
            cpm_reset_iic_params(iip);
      }

      if (cpm_debug && addr =3D=3D 0) {
            printk(KERN_DEBUG "iip %p, dp_addr 0x%x\n", cpm->iip,
cpm->dp_addr);
            printk(KERN_DEBUG "iic_tbase %d, r_tbase %d\n", iip->iic_tb=
ase,
r_tbase);
      }

      tbdf =3D (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
      rbdf =3D (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];

      tb =3D cpm->temp;
      tb =3D (u_char *)(((uint)tb + 15) & ~15);

      /* do a simple read */
      tb[0] =3D (addr << 1) | 1;      /* device address (+ read) */
      len =3D 2;

      flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));

      tbdf->cbd_bufaddr =3D __pa(tb);
      tbdf->cbd_datlen =3D len;
      tbdf->cbd_sc =3D
            BD_SC_READY | BD_SC_LAST |
            BD_SC_WRAP | BD_IIC_START;

      rbdf->cbd_datlen =3D 0;
      rbdf->cbd_bufaddr =3D __pa(tb+2);
      rbdf->cbd_sc =3D BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;

      local_irq_save(flags);
      i2c->i2c_i2cmr =3D 0x13;  /* Enable some interupts */
      i2c->i2c_i2cer =3D 0xff;
      i2c->i2c_i2mod |=3D 1;    /* Enable */
      i2c->i2c_i2com |=3D 0x80; /* Begin transmission */

      if (cpm_debug > 1) printk(KERN_DEBUG "about to sleep\n");

      /* wait for IIC transfer */
#ifdef I2C_INTERRUPTIBLE_SLEEP
      tmo =3D interruptible_sleep_on_timeout(&iic_wait,1*HZ);
#else
      tmo =3D sleep_on_timeout(&iic_wait,1*HZ);
#endif
      local_irq_restore(flags);

#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 &=3D ~1;
#endif

      if (signal_pending(current) || !tmo){
            force_close(cpm);
            if(cpm_debug && !tmo)
                  printk(KERN_DEBUG "IIC tryaddress: timeout!\n");
            return -EIO;
      }

      if (cpm_debug > 1) printk(KERN_DEBUG "back from sleep\n");

      if (tbdf->cbd_sc & BD_SC_NAK) {
            if (cpm_debug > 1) printk(KERN_DEBUG "IIC try; no ack\n");
            return 0;
      }

      if (tbdf->cbd_sc & BD_SC_READY) {
            printk(KERN_INFO "IIC try; complete but tbuf ready\n");
      }

      return 1;
}

static int cpm_xfer(struct i2c_adapter *i2c_adap,
                struct i2c_msg msgs[],
                int num)
{
      struct i2c_algo_8xx_data *adap =3D i2c_adap->algo_data;
      struct i2c_msg *pmsg;
      int i, ret;
      u_char addr;

      for (i =3D 0; i < num; i++) {
            pmsg =3D &msgs[i];

            if (cpm_debug)
                  printk(KERN_DEBUG "i2c-algo-8xx.o: "
                         "#%d addr=3D0x%x flags=3D0x%x len=3D%d\n buf=3D=
%lx\n",
                         i, pmsg->addr, pmsg->flags, pmsg->len, (unsign=
ed
long)pmsg->buf);

            addr =3D pmsg->addr << 1;
            if (pmsg->flags & I2C_M_RD )
                  addr |=3D 1;
            if (pmsg->flags & I2C_M_REV_DIR_ADDR )
                  addr ^=3D 1;

            if (!(pmsg->flags & I2C_M_NOSTART)) {
            }
            if (pmsg->flags & I2C_M_RD ) {
                  /* read bytes into buffer*/
                  ret =3D cpm_iic_read(adap, addr, pmsg->buf, pmsg->len=
);
                  if (cpm_debug)
                        printk(KERN_DEBUG "i2c-algo-8xx.o: read %d
bytes\n", ret);
                  if (ret < pmsg->len ) {
                        return (ret<0)? ret : -EREMOTEIO;
                  }
            } else {
                  /* write bytes from buffer */
                  ret =3D cpm_iic_write(adap, addr, pmsg->buf, pmsg->le=
n);
                  if (cpm_debug)
                        printk(KERN_DEBUG "i2c-algo-8xx.o: wrote %d\n",=

ret);
                  if (ret < pmsg->len ) {
                        return (ret<0) ? ret : -EREMOTEIO;
                  }
            }
      }
      return (num);
}

static int algo_control(struct i2c_adapter *adapter,
      unsigned int cmd, unsigned long arg)
{
      return 0;
}

static u32 cpm_func(struct i2c_adapter *adap)
{
      return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
             I2C_FUNC_PROTOCOL_MANGLING;
}

/* -----exported algorithm data: ------------------------------------- =
 */

static struct i2c_algorithm cpm_algo =3D {
      "MPC8xx CPM algorithm",
      I2C_ALGO_MPC8XX,
      cpm_xfer,
      NULL,
      NULL,                   /* slave_xmit           */
      NULL,                   /* slave_recv           */
      algo_control,                 /* ioctl          */
      cpm_func,               /* functionality  */
};

/*
 * registering functions to load algorithms at runtime
 */
int i2c_8xx_add_bus(struct i2c_adapter *adap)
{
      int i;
      struct i2c_algo_8xx_data *cpm_adap =3D adap->algo_data;

      if (cpm_debug)
            printk(KERN_DEBUG "i2c-algo-8xx.o: hw routines for %s
registered.\n",
                   adap->name);

      /* register new adapter to i2c module... */

      adap->id |=3D cpm_algo.id;
      adap->algo =3D &cpm_algo;

#ifdef MODULE
      MOD_INC_USE_COUNT;
#endif

      i2c_add_adapter(adap);
      cpm_iic_init(cpm_adap);

      /* scan bus */
      if (cpm_scan) {
            printk(KERN_INFO " i2c-algo-8xx.o: scanning bus %s...\n",
                   adap->name);
            for (i =3D 0; i < 128; i++) {
                  if (cpm_iic_tryaddress(cpm_adap, i)) {
                        printk("(%02x)",i<<1);
                  }
            }
            printk("\n");
      }
      return 0;
}

int i2c_8xx_del_bus(struct i2c_adapter *adap)
{
      int res;
      struct i2c_algo_8xx_data *cpm_adap =3D adap->algo_data;

      cpm_iic_shutdown(cpm_adap);

      if ((res =3D i2c_del_adapter(adap)) < 0)
            return res;

      printk(KERN_INFO "i2c-algo-8xx.o: adapter unregistered:
%s\n",adap->name);

#ifdef MODULE
      MOD_DEC_USE_COUNT;
#endif
      return 0;
}

EXPORT_SYMBOL(i2c_8xx_add_bus);
EXPORT_SYMBOL(i2c_8xx_del_bus);

int __init i2c_algo_8xx_init (void)
{
      printk(KERN_INFO "i2c-algo-8xx.o: i2c mpc8xx algorithm module ver=
sion
%s (%s)\n", I2C_ALGO_8XX_VERSION, I2C_ALGO_8XX_DATE);
      return 0;
}


#ifdef MODULE
MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif

int init_module(void)
{
      return i2c_algo_8xx_init();
}

void cleanup_module(void)
{
}
#endif=

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2005-08-15  8:08 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-12  5:11 8xx: i2c-algo-8xx - fixed timeout detection and transmission errors Debora Liu
  -- strict thread matches above, loose matches on Subject: below --
2005-08-15  5:59 cajus.hahn
2005-08-15  8:08 ` Joakim Tjernlund
2005-08-13 15:13 Joakim Tjernlund
2005-08-12  7:49 cajus.hahn
2005-08-12  8:01 ` Wolfgang Denk
2005-08-12  8:21   ` cajus.hahn
2005-08-11 17:50 Tjernlund
2005-08-11  7:42 Cajus Hahn
2005-08-10  9:37 Debora Liu
2005-08-10  9:48 ` Wolfgang Denk
2005-08-10  7:27 cajus.hahn
2005-08-10 13:58 ` Marcelo Tosatti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).