00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <cfg/twi.h>
00043 #include <arch/arm.h>
00044 #include <dev/irqreg.h>
00045
00046 #include <sys/event.h>
00047 #include <sys/atom.h>
00048 #include <sys/timer.h>
00049 #include <sys/thread.h>
00050 #include <sys/heap.h>
00051
00052 #include <dev/twif.h>
00053
00058
00059
00060
00061
00062 #if defined(MCU_AT91SAM7X)
00063 #define TWI_TWD PA10_TWD_A
00064 #define TWI_TWCK PA11_TWCK_A
00065 #elif defined(MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE)
00066 #define TWI_TWD PA3_TWD_A
00067 #define TWI_TWCK PA4_TWCK_A
00068 #elif defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE)
00069 #define TWI_TWD PA23_TWD_A
00070 #define TWI_TWCK PA24_TWCK_A
00071 #endif
00072
00073
00074
00075
00076 #ifndef TWI_PIO_ASR
00077 #define TWI_PIO_ASR PIOA_ASR
00078 #endif
00079 #ifndef TWI_PIO_PDR
00080 #define TWI_PIO_PDR PIOA_PDR
00081 #endif
00082 #ifndef TWI_PIO_MDER
00083 #define TWI_PIO_MDER PIOA_MDER
00084 #endif
00085
00086 static HANDLE tw_mm_mutex;
00087 static HANDLE tw_mm_que;
00088
00089 static volatile int tw_mm_err;
00090 static int tw_mm_error;
00091
00092 static uint8_t *tw_mm_buf;
00093 static volatile size_t tw_mm_len;
00094 static volatile size_t tw_mm_idx;
00095
00096
00097
00098
00099 static void TwInterrupt(void *arg)
00100 {
00101 register unsigned int twsr;
00102
00103
00104 twsr = inr(TWI_SR);
00105 if (twsr & (TWI_NACK | TWI_OVRE | TWI_ARBLST)) {
00106 if (twsr & TWI_NACK) {
00107 tw_mm_err = TWERR_SLA_NACK;
00108 } else {
00109 tw_mm_err = TWERR_BUS;
00110 }
00111 }
00112
00113
00114 twsr &= inr(TWI_IMR);
00115 if (twsr & TWI_TXRDY) {
00116
00117 if (tw_mm_idx < tw_mm_len) {
00118
00119 outb(TWI_THR, tw_mm_buf[tw_mm_idx]);
00120 tw_mm_idx++;
00121 } else {
00122
00123 outr(TWI_IDR, TWI_TXRDY);
00124 outr(TWI_IER, TWI_TXCOMP);
00125 }
00126 } else if (twsr & TWI_RXRDY) {
00127
00128 if (tw_mm_idx < tw_mm_len) {
00129
00130 tw_mm_buf[tw_mm_idx++] = inb(TWI_RHR);
00131 if (tw_mm_idx == tw_mm_len - 1) {
00132
00133 outr(TWI_CR, TWI_STOP);
00134 } else if (tw_mm_idx == tw_mm_len) {
00135
00136 outr(TWI_IDR, TWI_RXRDY);
00137 outr(TWI_IER, TWI_TXCOMP);
00138 }
00139 }
00140 } else if (twsr & TWI_TXCOMP) {
00141
00142
00143 outr(TWI_IDR, 0xFFFFFFFF);
00144 NutEventPostFromIrq(&tw_mm_que);
00145 }
00146 }
00147
00173 int TwMasterTransact(uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00174 {
00175 int rc = -1;
00176
00177
00178 if (NutEventWait(&tw_mm_mutex, tmo)) {
00179 tw_mm_error = TWERR_IF_LOCKED;
00180 return -1;
00181 }
00182
00183
00184 tw_mm_err = 0;
00185
00186
00187 if (txlen) {
00188
00189 tw_mm_buf = (uint8_t *) txdata;
00190 tw_mm_len = (size_t) txlen;
00191 tw_mm_idx = 1;
00192
00193
00194 outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
00195 outr(TWI_THR, tw_mm_buf[0]);
00196 outr(TWI_IER, TWI_TXRDY);
00197
00198
00199 if (NutEventWait(&tw_mm_que, tmo)) {
00200 tw_mm_err = TWERR_TIMEOUT;
00201 }
00202 }
00203
00204 if (tw_mm_err == 0) {
00205
00206
00207 tw_mm_idx = 0;
00208
00209 if (rxsiz) {
00210
00211 tw_mm_buf = (uint8_t *) rxdata;
00212 tw_mm_len = (size_t) rxsiz;
00213
00214
00215 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
00216 if (rxsiz == 1) {
00217
00218 outr(TWI_CR, TWI_START | TWI_STOP);
00219 } else {
00220 outr(TWI_CR, TWI_START);
00221 }
00222 outr(TWI_IER, TWI_RXRDY);
00223
00224
00225 if (NutEventWait(&tw_mm_que, tmo)) {
00226 tw_mm_err = TWERR_TIMEOUT;
00227 }
00228 }
00229 }
00230
00231 outr(TWI_IDR, 0xFFFFFFFF);
00232
00233
00234
00235 if (tw_mm_err) {
00236 tw_mm_error = tw_mm_err;
00237 } else {
00238 rc = (int) tw_mm_idx;
00239 }
00240
00241
00242 NutEventPost(&tw_mm_mutex);
00243
00244 return rc;
00245 }
00246
00269 int TwMasterRegRead(uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00270 {
00271 int rc = -1;
00272
00273 if (rxsiz == 0) {
00274 return -1;
00275 }
00276
00277 if (NutEventWait(&tw_mm_mutex, tmo)) {
00278 tw_mm_error = TWERR_IF_LOCKED;
00279 return -1;
00280 }
00281
00282 tw_mm_err = 0;
00283
00284 if (rxsiz) {
00285 tw_mm_buf = rxdata;
00286 tw_mm_len = (size_t) rxsiz;
00287 tw_mm_idx = 0;
00288
00289
00290 outr(TWI_IADRR, iadr);
00291
00292 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8) | TWI_MREAD);
00293
00294 if (rxsiz == 1) {
00295 outr(TWI_CR, TWI_START | TWI_STOP);
00296 } else {
00297 outr(TWI_CR, TWI_START);
00298 }
00299 outr(TWI_IER, TWI_RXRDY);
00300
00301
00302 if (NutEventWait(&tw_mm_que, tmo)) {
00303 tw_mm_error = TWERR_TIMEOUT;
00304 } else if (tw_mm_err) {
00305 tw_mm_error = tw_mm_err;
00306 } else {
00307 rc = (int) tw_mm_idx;
00308 }
00309 outr(TWI_IDR, 0xFFFFFFFF);
00310 }
00311
00312
00313 NutEventPost(&tw_mm_mutex);
00314
00315 return rc;
00316 }
00317
00343 int TwMasterRegWrite(uint8_t sla, uint32_t iadr, uint8_t iadrlen, CONST void *txdata, uint16_t txsiz, uint32_t tmo)
00344 {
00345 int rc = -1;
00346
00347
00348 if (NutEventWait(&tw_mm_mutex, tmo)) {
00349 tw_mm_err = TWERR_IF_LOCKED;
00350 return -1;
00351 }
00352
00353 tw_mm_err = 0;
00354
00355 if (txsiz) {
00356 tw_mm_buf = (uint8_t *) txdata;
00357 tw_mm_len = (size_t) txsiz;
00358 tw_mm_idx = 1;
00359
00360
00361 outr(TWI_IADRR, iadr);
00362
00363 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
00364 outb(TWI_THR, tw_mm_buf[0]);
00365 outr(TWI_IER, TWI_TXRDY);
00366
00367
00368 if (NutEventWait(&tw_mm_que, tmo)) {
00369 tw_mm_error = TWERR_TIMEOUT;
00370 } else if (tw_mm_err) {
00371 tw_mm_error = tw_mm_err;
00372 } else {
00373 rc = (int) tw_mm_idx;
00374 }
00375 outr(TWI_IDR, 0xFFFFFFFF);
00376 }
00377
00378
00379 NutEventPost(&tw_mm_mutex);
00380
00381 return rc;
00382 }
00383
00391 int TwMasterError(void)
00392 {
00393 int rc = tw_mm_error;
00394 tw_mm_error = 0;
00395 return rc;
00396 }
00397
00407 uint16_t TwMasterIndexes(uint8_t idx)
00408 {
00409 switch (idx) {
00410 case 0:
00411 return (uint16_t) tw_mm_idx;
00412 case 1:
00413 return (uint16_t) tw_mm_idx;
00414 case 2:
00415 return (uint16_t) tw_mm_len;
00416 default:
00417 return 0;
00418 }
00419 }
00420
00436 int TwIOCtl(int req, void *conf)
00437 {
00438 int rc = 0;
00439 unsigned int cldiv, ckdiv;
00440 unsigned int twi_clk;
00441 switch (req) {
00442
00443 case TWI_SETSPEED:
00444 ckdiv = 1;
00445 twi_clk = *((uint32_t *) conf);
00446
00447 if (twi_clk > 400000)
00448 return -1;
00449
00450
00451
00452
00453
00454
00455
00456 while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * twi_clk)) - 3) / (1 << ckdiv)) > 255) {
00457 ckdiv++;
00458 }
00459
00460
00461 if (cldiv * (1 << ckdiv) > 8191)
00462 return -1;
00463
00464 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00465 break;
00466
00467 case TWI_GETSPEED:
00468 ckdiv = 1;
00469 twi_clk = *((uint32_t *) conf);
00470
00471 cldiv = inr(TWI_CWGR) & 0x000000FF;
00472 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00473
00474 *((uint32_t *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00475 break;
00476
00477 case TWI_GETSTATUS:
00478 break;
00479
00480 case TWI_SETSTATUS:
00481 break;
00482
00483 default:
00484 rc = -1;
00485 break;
00486 }
00487 return rc;
00488 }
00489
00501 int TwInit(uint8_t sla)
00502 {
00503 uint32_t speed = 4800;
00504
00505 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00506 return -1;
00507 }
00508
00509
00510 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00511
00512 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00513
00514 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00515
00516 outr(PMC_PCER, _BV(TWI_ID));
00517
00518
00519 outr(TWI_IDR, 0xFFFFFFFF);
00520
00521 outr(TWI_CR, TWI_SWRST);
00522
00523 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00524
00525 if (TwIOCtl(TWI_SETSPEED, &speed)) {
00526 return -1;
00527 }
00528
00529
00530 NutIrqSetMode(&sig_TWI, NUT_IRQMODE_LEVEL);
00531 NutIrqEnable(&sig_TWI);
00532
00533
00534 NutEventPost(&tw_mm_mutex);
00535
00536 return 0;
00537 }
00538