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 #endif
00071
00072
00073
00074
00075 #ifndef TWI_PIO_ASR
00076 #define TWI_PIO_ASR PIOA_ASR
00077 #endif
00078 #ifndef TWI_PIO_PDR
00079 #define TWI_PIO_PDR PIOA_PDR
00080 #endif
00081 #ifndef TWI_PIO_MDER
00082 #define TWI_PIO_MDER PIOA_MDER
00083 #endif
00084
00085 static HANDLE tw_mm_mutex;
00086 static HANDLE tw_mm_que;
00087
00088 static volatile int tw_mm_err;
00089 static int tw_mm_error;
00090
00091 static uint8_t *tw_mm_buf;
00092 static volatile size_t tw_mm_len;
00093 static volatile size_t tw_mm_idx;
00094
00095
00096
00097
00098 static void TwInterrupt(void *arg)
00099 {
00100 register unsigned int twsr;
00101
00102
00103 twsr = inr(TWI_SR);
00104 if (twsr & (TWI_NACK | TWI_OVRE | TWI_ARBLST)) {
00105 if (twsr & TWI_NACK) {
00106 tw_mm_err = TWERR_SLA_NACK;
00107 } else {
00108 tw_mm_err = TWERR_BUS;
00109 }
00110 }
00111
00112
00113 twsr &= inr(TWI_IMR);
00114 if (twsr & TWI_TXRDY) {
00115
00116 if (tw_mm_idx < tw_mm_len) {
00117
00118 outb(TWI_THR, tw_mm_buf[tw_mm_idx]);
00119 tw_mm_idx++;
00120 } else {
00121
00122 outr(TWI_IDR, TWI_TXRDY);
00123 outr(TWI_IER, TWI_TXCOMP);
00124 }
00125 } else if (twsr & TWI_RXRDY) {
00126
00127 if (tw_mm_idx < tw_mm_len) {
00128
00129 tw_mm_buf[tw_mm_idx++] = inb(TWI_RHR);
00130 if (tw_mm_idx == tw_mm_len - 1) {
00131
00132 outr(TWI_CR, TWI_STOP);
00133 } else if (tw_mm_idx == tw_mm_len) {
00134
00135 outr(TWI_IDR, TWI_RXRDY);
00136 outr(TWI_IER, TWI_TXCOMP);
00137 }
00138 }
00139 } else if (twsr & TWI_TXCOMP) {
00140
00141
00142 outr(TWI_IDR, 0xFFFFFFFF);
00143 NutEventPostFromIrq(&tw_mm_que);
00144 }
00145 }
00146
00172 int TwMasterTransact(uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00173 {
00174 int rc = -1;
00175
00176
00177 if (NutEventWait(&tw_mm_mutex, tmo)) {
00178 tw_mm_error = TWERR_IF_LOCKED;
00179 return -1;
00180 }
00181
00182
00183 tw_mm_err = 0;
00184
00185
00186 if (txlen) {
00187
00188 tw_mm_buf = (uint8_t *) txdata;
00189 tw_mm_len = (size_t) txlen;
00190 tw_mm_idx = 1;
00191
00192
00193 outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
00194 outr(TWI_THR, tw_mm_buf[0]);
00195 outr(TWI_IER, TWI_TXRDY);
00196
00197
00198 if (NutEventWait(&tw_mm_que, tmo)) {
00199 tw_mm_err = TWERR_TIMEOUT;
00200 }
00201 }
00202
00203 if (tw_mm_err == 0) {
00204
00205
00206 tw_mm_idx = 0;
00207
00208 if (rxsiz) {
00209
00210 tw_mm_buf = (uint8_t *) rxdata;
00211 tw_mm_len = (size_t) rxsiz;
00212
00213
00214 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
00215 if (rxsiz == 1) {
00216
00217 outr(TWI_CR, TWI_START | TWI_STOP);
00218 } else {
00219 outr(TWI_CR, TWI_START);
00220 }
00221 outr(TWI_IER, TWI_RXRDY);
00222
00223
00224 if (NutEventWait(&tw_mm_que, tmo)) {
00225 tw_mm_err = TWERR_TIMEOUT;
00226 }
00227 }
00228 }
00229
00230 outr(TWI_IDR, 0xFFFFFFFF);
00231
00232
00233
00234 if (tw_mm_err) {
00235 tw_mm_error = tw_mm_err;
00236 } else {
00237 rc = (int) tw_mm_idx;
00238 }
00239
00240
00241 NutEventPost(&tw_mm_mutex);
00242
00243 return rc;
00244 }
00245
00268 int TwMasterRegRead(uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00269 {
00270 int rc = -1;
00271
00272 if (rxsiz == 0) {
00273 return -1;
00274 }
00275
00276 if (NutEventWait(&tw_mm_mutex, tmo)) {
00277 tw_mm_error = TWERR_IF_LOCKED;
00278 NutEventPost(&tw_mm_mutex);
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 NutEventPost(&tw_mm_mutex);
00351 return -1;
00352 }
00353
00354 tw_mm_err = 0;
00355
00356 if (txsiz) {
00357 tw_mm_buf = (uint8_t *) txdata;
00358 tw_mm_len = (size_t) txsiz;
00359 tw_mm_idx = 1;
00360
00361
00362 outr(TWI_IADRR, iadr);
00363
00364 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
00365 outb(TWI_THR, tw_mm_buf[0]);
00366 outr(TWI_IER, TWI_TXRDY);
00367
00368
00369 if (NutEventWait(&tw_mm_que, tmo)) {
00370 tw_mm_error = TWERR_TIMEOUT;
00371 } else if (tw_mm_err) {
00372 tw_mm_error = tw_mm_err;
00373 } else {
00374 rc = (int) tw_mm_idx;
00375 }
00376 outr(TWI_IDR, 0xFFFFFFFF);
00377 }
00378
00379
00380 NutEventPost(&tw_mm_mutex);
00381
00382 return rc;
00383 }
00384
00392 int TwMasterError(void)
00393 {
00394 int rc = tw_mm_error;
00395 tw_mm_error = 0;
00396 return rc;
00397 }
00398
00408 uint16_t TwMasterIndexes(uint8_t idx)
00409 {
00410 switch (idx) {
00411 case 0:
00412 return (uint16_t) tw_mm_idx;
00413 case 1:
00414 return (uint16_t) tw_mm_idx;
00415 case 2:
00416 return (uint16_t) tw_mm_len;
00417 default:
00418 return 0;
00419 }
00420 }
00421
00437 int TwIOCtl(int req, void *conf)
00438 {
00439 int rc = 0;
00440 unsigned int cldiv, ckdiv;
00441 unsigned int twi_clk;
00442 switch (req) {
00443
00444 case TWI_SETSPEED:
00445 ckdiv = 1;
00446 twi_clk = *((uint32_t *) conf);
00447
00448 if (twi_clk > 400000)
00449 return -1;
00450
00451
00452
00453
00454
00455
00456
00457 while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * twi_clk)) - 3) / (1 << ckdiv)) > 255) {
00458 ckdiv++;
00459 }
00460
00461
00462 if (cldiv * (1 << ckdiv) > 8191)
00463 return -1;
00464
00465 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00466 break;
00467
00468 case TWI_GETSPEED:
00469 ckdiv = 1;
00470 twi_clk = *((uint32_t *) conf);
00471
00472 cldiv = inr(TWI_CWGR) & 0x000000FF;
00473 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00474
00475 *((uint32_t *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00476 break;
00477
00478 case TWI_GETSTATUS:
00479 break;
00480
00481 case TWI_SETSTATUS:
00482 break;
00483
00484 default:
00485 rc = -1;
00486 break;
00487 }
00488 return rc;
00489 }
00490
00502 int TwInit(uint8_t sla)
00503 {
00504 uint32_t speed = 4800;
00505
00506 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00507 return -1;
00508 }
00509
00510
00511 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00512
00513 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00514
00515 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00516
00517 outr(PMC_PCER, _BV(TWI_ID));
00518
00519
00520 outr(TWI_IDR, 0xFFFFFFFF);
00521
00522 outr(TWI_CR, TWI_SWRST);
00523
00524 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00525
00526 if (TwIOCtl(TWI_SETSPEED, &speed)) {
00527 return -1;
00528 }
00529
00530
00531 NutIrqSetMode(&sig_TWI, NUT_IRQMODE_LEVEL);
00532 NutIrqEnable(&sig_TWI);
00533
00534
00535 NutEventPost(&tw_mm_mutex);
00536
00537 return 0;
00538 }
00539