1 #include "boot.h" 2 3 /* 4 * basic read/write interface to mpc8xx I2C bus (master mode) 5 */ 6 7 typedef struct I2C I2C; 8 9 struct I2C { 10 uchar i2mod; 11 uchar rsv12a[3]; 12 uchar i2add; 13 uchar rsv12b[3]; 14 uchar i2brg; 15 uchar rsv12c[3]; 16 uchar i2com; 17 uchar rsv12d[3]; 18 uchar i2cer; 19 uchar rsv12e[3]; 20 uchar i2cmr; 21 }; 22 23 enum { 24 /* i2c-specific BD flags */ 25 RxeOV= 1<<1, /* overrun */ 26 TxS= 1<<10, /* transmit start condition */ 27 TxeNAK= 1<<2, /* last transmitted byte not acknowledged */ 28 TxeUN= 1<<1, /* underflow */ 29 TxeCL= 1<<0, /* collision */ 30 TxERR= (TxeNAK|TxeUN|TxeCL), 31 32 /* i2cmod */ 33 REVD= 1<<5, /* =1, LSB first */ 34 GCD= 1<<4, /* =1, general call address disabled */ 35 FLT= 1<<3, /* =0, not filtered; =1, filtered */ 36 PDIV= 3<<1, /* predivisor field */ 37 EN= 1<<0, /* enable */ 38 39 /* i2com */ 40 STR= 1<<7, /* start transmit */ 41 I2CM= 1<<0, /* master */ 42 I2CS= 0<<0, /* slave */ 43 44 /* i2cer */ 45 TXE = 1<<4, 46 BSY = 1<<2, 47 TXB = 1<<1, 48 RXB = 1<<0, 49 50 /* port B bits */ 51 I2CSDA = IBIT(27), 52 I2CSCL = IBIT(26), 53 54 Rbit = 1<<0, /* bit in address byte denoting read */ 55 56 /* maximum I2C I/O (can change) */ 57 MaxIO= 128, 58 Bufsize = MaxIO+4, /* extra space for address/clock bytes and alignment */ 59 Freq = 100000, 60 I2CTimeout = 250, /* msec */ 61 }; 62 63 /* data cache needn't be flushed if buffers allocated in uncached INTMEM */ 64 #define DCFLUSH(a,n) 65 66 /* 67 * I2C software structures 68 */ 69 70 struct Ctlr { 71 Lock; 72 QLock io; 73 int init; 74 I2C* i2c; 75 IOCparam* sp; 76 77 BD* rd; 78 BD* td; 79 int phase; 80 int timeout; 81 char* addr; 82 char* txbuf; 83 char* rxbuf; 84 }; 85 typedef struct Ctlr Ctlr; 86 87 static Ctlr i2ctlr[1]; 88 extern int predawn; 89 90 static void interrupt(Ureg*, void*); 91 92 static void 93 enable(void) 94 { 95 I2C *i2c; 96 97 i2c = i2ctlr->i2c; 98 i2c->i2cer = ~0; /* clear events */ 99 eieio(); 100 i2c->i2mod |= EN; 101 eieio(); 102 i2c->i2cmr = TXE|BSY|TXB|RXB; /* enable all interrupts */ 103 eieio(); 104 } 105 106 static void 107 disable(void) 108 { 109 I2C *i2c; 110 111 i2c = i2ctlr->i2c; 112 i2c->i2cmr = 0; /* mask all interrupts */ 113 i2c->i2mod &= ~EN; 114 } 115 116 /* 117 * called by the reset routine of any driver using the I2C 118 */ 119 void 120 i2csetup(void) 121 { 122 IMM *io; 123 I2C *i2c; 124 IOCparam *sp; 125 Ctlr *ctlr; 126 long f, e, emin; 127 int p, d, dmax; 128 129 ctlr = i2ctlr; 130 if(ctlr->init) 131 return; 132 print("i2c setup...\n"); 133 ctlr->init = 1; 134 i2c = KADDR(INTMEM+0x860); 135 ctlr->i2c = i2c; 136 sp = KADDR(INTMEM+0x3c80); 137 ctlr->sp = sp; 138 disable(); 139 140 if(ctlr->txbuf == nil){ 141 ctlr->txbuf = ialloc(Bufsize, 2); 142 ctlr->addr = ctlr->txbuf+Bufsize; 143 } 144 if(ctlr->rxbuf == nil) 145 ctlr->rxbuf = ialloc(Bufsize, 2); 146 if(ctlr->rd == nil){ 147 ctlr->rd = bdalloc(1); 148 ctlr->rd->addr = PADDR(ctlr->rxbuf); 149 ctlr->rd->length = 0; 150 ctlr->rd->status = BDWrap; 151 } 152 if(ctlr->td == nil){ 153 ctlr->td = bdalloc(2); 154 ctlr->td->addr = PADDR(ctlr->txbuf); 155 ctlr->td->length = 0; 156 ctlr->td->status = BDWrap|BDLast; 157 } 158 159 /* select port pins */ 160 io = ioplock(); 161 io->pbdir |= I2CSDA | I2CSCL; 162 io->pbodr |= I2CSDA | I2CSCL; 163 io->pbpar |= I2CSDA | I2CSCL; 164 iopunlock(); 165 166 /* explicitly initialise parameters, because InitRxTx can't be used (see i2c/spi relocation errata) */ 167 sp = ctlr->sp; 168 sp->rbase = PADDR(ctlr->rd); 169 sp->tbase = PADDR(ctlr->td); 170 sp->rfcr = 0x18; 171 sp->tfcr = 0x18; 172 sp->mrblr = Bufsize; 173 sp->rstate = 0; 174 sp->rptr = 0; 175 sp->rbptr = sp->rbase; 176 sp->rcnt = 0; 177 sp->tstate = 0; 178 sp->tbptr = sp->tbase; 179 sp->tptr = 0; 180 sp->tcnt = 0; 181 eieio(); 182 183 i2c->i2com = I2CM; 184 i2c->i2mod = 0; /* normal mode */ 185 i2c->i2add = 0; 186 187 emin = Freq; 188 dmax = (m->cpuhz/Freq)/2-3; 189 for(d=0; d < dmax; d++){ 190 for(p=3; p>=0; p--){ 191 f = (m->cpuhz>>(p+2))/(2*(d+3)); 192 e = Freq - f; 193 if(e < 0) 194 e = -e; 195 if(e < emin){ 196 emin = e; 197 i2c->i2brg = d; 198 i2c->i2mod = (i2c->i2mod&~PDIV)|((3-p)<<1); /* set PDIV */ 199 } 200 } 201 } 202 //print("i2brg=%d i2mod=#%2.2ux\n", i2c->i2brg, i2c->i2mod); 203 setvec(VectorCPIC+0x10, interrupt, i2ctlr); 204 } 205 206 enum { 207 Idling, 208 Done, 209 Busy, 210 Sending, 211 Recving, 212 }; 213 214 static void 215 interrupt(Ureg*, void *arg) 216 { 217 int events; 218 Ctlr *ctlr; 219 I2C *i2c; 220 221 ctlr = arg; 222 i2c = ctlr->i2c; 223 events = i2c->i2cer; 224 eieio(); 225 i2c->i2cer = events; 226 if(events & (BSY|TXE)){ 227 print("I2C#%x\n", events); 228 if(ctlr->phase != Idling){ 229 ctlr->phase = Idling; 230 } 231 }else{ 232 if(events & TXB){ 233 //print("i2c: xmt %d %4.4ux %4.4ux\n", ctlr->phase, ctlr->td->status, ctlr->td[1].status); 234 if(ctlr->phase == Sending){ 235 ctlr->phase = Done; 236 } 237 } 238 if(events & RXB){ 239 //print("i2c: rcv %d %4.4ux %d\n", ctlr->phase, ctlr->rd->status, ctlr->rd->length); 240 if(ctlr->phase == Recving){ 241 ctlr->phase = Done; 242 } 243 } 244 } 245 } 246 247 static int 248 done(void *a) 249 { 250 return ((Ctlr*)a)->phase < Busy; 251 } 252 253 static void 254 i2cwait(Ctlr *ctlr) 255 { 256 int i; 257 258 ctlr->timeout = 0; 259 i = 0; 260 while(!done(ctlr)){ 261 if(predawn){ 262 if(++i > 100){ 263 ctlr->phase = Done; 264 ctlr->timeout = 1; 265 return; 266 } 267 delay(1); 268 interrupt(nil, ctlr); 269 } 270 } 271 } 272 273 long 274 i2csend(int addr, void *buf, long n) 275 { 276 Ctlr *ctlr; 277 int i, p, s; 278 279 ctlr = i2ctlr; 280 if(n > MaxIO) 281 return -1; 282 i = 1; 283 ctlr->txbuf[0] = addr & ~1; 284 if(addr & 1){ 285 ctlr->txbuf[1] = addr>>8; 286 i++; 287 } 288 memmove(ctlr->txbuf+i, buf, n); 289 DCFLUSH(ctlr->txbuf, Bufsize); 290 ctlr->phase = Sending; 291 ctlr->rd->status = BDEmpty|BDWrap|BDInt; 292 ctlr->td->addr = PADDR(ctlr->txbuf); 293 ctlr->td->length = n+i; 294 ctlr->td->status = BDReady|BDWrap|BDLast|BDInt; 295 enable(); 296 ctlr->i2c->i2com = STR|I2CM; 297 eieio(); 298 i2cwait(ctlr); 299 disable(); 300 p = ctlr->phase; 301 s = ctlr->td->status; 302 if(s & BDReady || s & TxERR || p != Done || ctlr->timeout) 303 return -1; 304 return n; 305 } 306 307 long 308 i2crecv(int addr, void *buf, long n) 309 { 310 Ctlr *ctlr; 311 int p, s, flag; 312 BD *td; 313 long nr; 314 315 ctlr = i2ctlr; 316 if(n > MaxIO) 317 return -1; 318 ctlr->txbuf[0] = addr|Rbit; 319 if(addr & 1){ /* special select sequence */ 320 ctlr->addr[0] = addr &~ 1; 321 ctlr->addr[1] = addr>>8; 322 } 323 DCFLUSH(ctlr->txbuf, Bufsize); 324 DCFLUSH(ctlr->rxbuf, Bufsize); 325 ctlr->phase = Recving; 326 ctlr->rd->addr = PADDR(ctlr->rxbuf); 327 ctlr->rd->status = BDEmpty|BDWrap|BDInt; 328 flag = 0; 329 td = ctlr->td; 330 td[1].status = 0; 331 if(addr & 1){ 332 /* special select sequence */ 333 td->addr = PADDR(ctlr->addr); 334 td->length = 2; 335 /* td->status made BDReady below */ 336 td++; 337 flag = TxS; 338 } 339 td->addr = PADDR(ctlr->txbuf); 340 td->length = n+1; 341 td->status = BDReady|BDWrap|BDLast | flag; /* not BDInt: leave that to receive */ 342 if(flag) 343 ctlr->td->status = BDReady; 344 enable(); 345 ctlr->i2c->i2com = STR|I2CM; 346 eieio(); 347 i2cwait(ctlr); 348 disable(); 349 p = ctlr->phase; 350 s = ctlr->td->status; 351 if(flag) 352 s |= ctlr->td[1].status; 353 nr = ctlr->rd->length; 354 if(nr > n) 355 nr = n; /* shouldn't happen */ 356 if(s & TxERR || s & BDReady || p != Done || ctlr->rd->status & BDEmpty || ctlr->timeout) 357 return -1; 358 memmove(buf, ctlr->rxbuf, nr); 359 return nr; 360 } 361