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 <arch/arm.h>
00043 #include <dev/irqreg.h>
00044
00045 #include <sys/event.h>
00046 #include <sys/atom.h>
00047 #include <sys/timer.h>
00048 #include <sys/thread.h>
00049 #include <sys/heap.h>
00050
00051 #include <dev/twif.h>
00052
00057
00058
00059
00060
00061 #if defined(MCU_AT91SAM7X)
00062 #define TWI_TWD PA10_TWD_A
00063 #define TWI_TWCK PA11_TWCK_A
00064 #elif defined(MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE)
00065 #define TWI_TWD PA3_TWD_A
00066 #define TWI_TWCK PA4_TWCK_A
00067 #elif defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE)
00068 #define TWI_TWD PA23_TWD_A
00069 #define TWI_TWCK PA24_TWCK_A
00070 #elif defined (MCU_AT91SAM9G45)
00071 #define TWI_TWD PA20_TWD0_A
00072 #define TWI_TWCK PA21_TWCK0_A
00073 #endif
00074
00075
00076
00077
00078 #ifndef TWI_PIO_ASR
00079 #define TWI_PIO_ASR PIOA_ASR
00080 #endif
00081 #ifndef TWI_PIO_PDR
00082 #define TWI_PIO_PDR PIOA_PDR
00083 #endif
00084 #ifndef TWI_PIO_MDER
00085 #define TWI_PIO_MDER PIOA_MDER
00086 #endif
00087
00088 static HANDLE tw_mm_mutex;
00089 static HANDLE tw_mm_que;
00090
00091 static volatile int tw_mm_err;
00092 static int tw_mm_error;
00093
00094 static uint8_t *tw_mm_buf;
00095 static volatile size_t tw_mm_len;
00096 static volatile size_t tw_mm_idx;
00097
00098
00099
00100
00101 static void TwInterrupt(void *arg)
00102 {
00103 register unsigned int twsr;
00104
00105
00106 twsr = inr(TWI_SR);
00107 if (twsr & (TWI_NACK | TWI_OVRE | TWI_ARBLST)) {
00108 if (twsr & TWI_NACK) {
00109 tw_mm_err = TWERR_SLA_NACK;
00110 } else {
00111 tw_mm_err = TWERR_BUS;
00112 }
00113 }
00114
00115
00116 twsr &= inr(TWI_IMR);
00117 if (twsr & TWI_TXRDY) {
00118
00119 if (tw_mm_idx < tw_mm_len) {
00120
00121 outb(TWI_THR, tw_mm_buf[tw_mm_idx]);
00122 tw_mm_idx++;
00123 } else {
00124
00125 #if defined(MCU_AT91SAM9XE)
00126
00127
00128 outr(TWI_CR, TWI_STOP);
00129 #endif
00130 outr(TWI_IDR, TWI_TXRDY);
00131 outr(TWI_IER, TWI_TXCOMP);
00132 }
00133 } else if (twsr & TWI_RXRDY) {
00134
00135 if (tw_mm_idx < tw_mm_len) {
00136
00137 tw_mm_buf[tw_mm_idx++] = inb(TWI_RHR);
00138 if (tw_mm_idx == tw_mm_len - 1) {
00139
00140 outr(TWI_CR, TWI_STOP);
00141 } else if (tw_mm_idx == tw_mm_len) {
00142
00143 outr(TWI_IDR, TWI_RXRDY);
00144 outr(TWI_IER, TWI_TXCOMP);
00145 }
00146 }
00147 } else if (twsr & TWI_TXCOMP) {
00148
00149
00150 outr(TWI_IDR, 0xFFFFFFFF);
00151 NutEventPostFromIrq(&tw_mm_que);
00152 }
00153 }
00154
00180 int TwMasterTransact(uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00181 {
00182 int rc = -1;
00183
00184
00185 if (NutEventWait(&tw_mm_mutex, tmo)) {
00186 tw_mm_error = TWERR_IF_LOCKED;
00187 return -1;
00188 }
00189
00190
00191 tw_mm_err = 0;
00192
00193
00194 if (txlen) {
00195
00196 tw_mm_buf = (uint8_t *) txdata;
00197 tw_mm_len = (size_t) txlen;
00198 tw_mm_idx = 1;
00199
00200
00201 outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
00202 outr(TWI_THR, tw_mm_buf[0]);
00203 outr(TWI_IER, TWI_TXRDY);
00204
00205
00206 if (NutEventWait(&tw_mm_que, tmo)) {
00207 tw_mm_err = TWERR_TIMEOUT;
00208 }
00209 }
00210
00211 if (tw_mm_err == 0) {
00212
00213
00214 tw_mm_idx = 0;
00215
00216 if (rxsiz) {
00217
00218 tw_mm_buf = (uint8_t *) rxdata;
00219 tw_mm_len = (size_t) rxsiz;
00220
00221
00222 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
00223 if (rxsiz == 1) {
00224
00225 outr(TWI_CR, TWI_START | TWI_STOP);
00226 } else {
00227 outr(TWI_CR, TWI_START);
00228 }
00229 outr(TWI_IER, TWI_RXRDY);
00230
00231
00232 if (NutEventWait(&tw_mm_que, tmo)) {
00233 tw_mm_err = TWERR_TIMEOUT;
00234 }
00235 }
00236 }
00237
00238 outr(TWI_IDR, 0xFFFFFFFF);
00239
00240
00241
00242 if (tw_mm_err) {
00243 tw_mm_error = tw_mm_err;
00244 } else {
00245 rc = (int) tw_mm_idx;
00246 }
00247
00248
00249 NutEventPost(&tw_mm_mutex);
00250
00251 return rc;
00252 }
00253
00276 int TwMasterRegRead(uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00277 {
00278 int rc = -1;
00279
00280 if (rxsiz == 0) {
00281 return -1;
00282 }
00283
00284 if (NutEventWait(&tw_mm_mutex, tmo)) {
00285 tw_mm_error = TWERR_IF_LOCKED;
00286 return -1;
00287 }
00288
00289 tw_mm_err = 0;
00290
00291 if (rxsiz) {
00292 tw_mm_buf = rxdata;
00293 tw_mm_len = (size_t) rxsiz;
00294 tw_mm_idx = 0;
00295
00296
00297 outr(TWI_IADRR, iadr);
00298
00299 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8) | TWI_MREAD);
00300
00301 if (rxsiz == 1) {
00302 outr(TWI_CR, TWI_START | TWI_STOP);
00303 } else {
00304 outr(TWI_CR, TWI_START);
00305 }
00306 outr(TWI_IER, TWI_RXRDY);
00307
00308
00309 if (NutEventWait(&tw_mm_que, tmo)) {
00310 tw_mm_error = TWERR_TIMEOUT;
00311 } else if (tw_mm_err) {
00312 tw_mm_error = tw_mm_err;
00313 } else {
00314 rc = (int) tw_mm_idx;
00315 }
00316 outr(TWI_IDR, 0xFFFFFFFF);
00317 }
00318
00319
00320 NutEventPost(&tw_mm_mutex);
00321
00322 return rc;
00323 }
00324
00350 int TwMasterRegWrite(uint8_t sla, uint32_t iadr, uint8_t iadrlen, CONST void *txdata, uint16_t txsiz, uint32_t tmo)
00351 {
00352 int rc = -1;
00353
00354
00355 if (NutEventWait(&tw_mm_mutex, tmo)) {
00356 tw_mm_err = TWERR_IF_LOCKED;
00357 return -1;
00358 }
00359
00360 tw_mm_err = 0;
00361
00362 if (txsiz) {
00363 tw_mm_buf = (uint8_t *) txdata;
00364 tw_mm_len = (size_t) txsiz;
00365 tw_mm_idx = 1;
00366
00367
00368 outr(TWI_IADRR, iadr);
00369
00370 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
00371 outb(TWI_THR, tw_mm_buf[0]);
00372 outr(TWI_IER, TWI_TXRDY);
00373
00374
00375 if (NutEventWait(&tw_mm_que, tmo)) {
00376 tw_mm_error = TWERR_TIMEOUT;
00377 } else if (tw_mm_err) {
00378 tw_mm_error = tw_mm_err;
00379 } else {
00380 rc = (int) tw_mm_idx;
00381 }
00382 outr(TWI_IDR, 0xFFFFFFFF);
00383 }
00384
00385
00386 NutEventPost(&tw_mm_mutex);
00387
00388 return rc;
00389 }
00390
00398 int TwMasterError(void)
00399 {
00400 int rc = tw_mm_error;
00401 tw_mm_error = 0;
00402 return rc;
00403 }
00404
00414 uint16_t TwMasterIndexes(uint8_t idx)
00415 {
00416 switch (idx) {
00417 case 0:
00418 return (uint16_t) tw_mm_idx;
00419 case 1:
00420 return (uint16_t) tw_mm_idx;
00421 case 2:
00422 return (uint16_t) tw_mm_len;
00423 default:
00424 return 0;
00425 }
00426 }
00427
00443 int TwIOCtl(int req, void *conf)
00444 {
00445 int rc = 0;
00446 unsigned int cldiv, ckdiv;
00447 unsigned int twi_clk;
00448 switch (req) {
00449
00450 case TWI_SETSPEED:
00451 ckdiv = 1;
00452 twi_clk = *((uint32_t *) conf);
00453
00454 if (twi_clk > 400000)
00455 return -1;
00456
00457
00458
00459
00460
00461
00462
00463 while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * twi_clk)) - 3) / (1 << ckdiv)) > 255) {
00464 ckdiv++;
00465 }
00466
00467
00468 if (cldiv * (1 << ckdiv) > 8191)
00469 return -1;
00470
00471 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00472 break;
00473
00474 case TWI_GETSPEED:
00475 ckdiv = 1;
00476 twi_clk = *((uint32_t *) conf);
00477
00478 cldiv = inr(TWI_CWGR) & 0x000000FF;
00479 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00480
00481 *((uint32_t *) conf) = NutGetCpuClock() / ((cldiv * 2 << ckdiv) - 3);
00482 break;
00483
00484 case TWI_GETSTATUS:
00485 break;
00486
00487 case TWI_SETSTATUS:
00488 break;
00489
00490 default:
00491 rc = -1;
00492 break;
00493 }
00494 return rc;
00495 }
00496
00508 int TwInit(uint8_t sla)
00509 {
00510 uint32_t speed = 4800;
00511
00512 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00513 return -1;
00514 }
00515
00516
00517 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00518
00519 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00520
00521 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00522
00523 outr(PMC_PCER, _BV(TWI_ID));
00524
00525
00526 outr(TWI_IDR, 0xFFFFFFFF);
00527
00528 outr(TWI_CR, TWI_SWRST);
00529
00530 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00531
00532 if (TwIOCtl(TWI_SETSPEED, &speed)) {
00533 return -1;
00534 }
00535
00536
00537 NutIrqSetMode(&sig_TWI, NUT_IRQMODE_LEVEL);
00538 NutIrqEnable(&sig_TWI);
00539
00540
00541 NutEventPost(&tw_mm_mutex);
00542
00543 return 0;
00544 }
00545