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 outr(TWI_IDR, TWI_TXRDY);
00126 outr(TWI_IER, TWI_TXCOMP);
00127 }
00128 } else if (twsr & TWI_RXRDY) {
00129
00130 if (tw_mm_idx < tw_mm_len) {
00131
00132 tw_mm_buf[tw_mm_idx++] = inb(TWI_RHR);
00133 if (tw_mm_idx == tw_mm_len - 1) {
00134
00135 outr(TWI_CR, TWI_STOP);
00136 } else if (tw_mm_idx == tw_mm_len) {
00137
00138 outr(TWI_IDR, TWI_RXRDY);
00139 outr(TWI_IER, TWI_TXCOMP);
00140 }
00141 }
00142 } else if (twsr & TWI_TXCOMP) {
00143
00144
00145 outr(TWI_IDR, 0xFFFFFFFF);
00146 NutEventPostFromIrq(&tw_mm_que);
00147 }
00148 }
00149
00175 int TwMasterTransact(uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00176 {
00177 int rc = -1;
00178
00179
00180 if (NutEventWait(&tw_mm_mutex, tmo)) {
00181 tw_mm_error = TWERR_IF_LOCKED;
00182 return -1;
00183 }
00184
00185
00186 tw_mm_err = 0;
00187
00188
00189 if (txlen) {
00190
00191 tw_mm_buf = (uint8_t *) txdata;
00192 tw_mm_len = (size_t) txlen;
00193 tw_mm_idx = 1;
00194
00195
00196 outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
00197 outr(TWI_THR, tw_mm_buf[0]);
00198 outr(TWI_IER, TWI_TXRDY);
00199
00200
00201 if (NutEventWait(&tw_mm_que, tmo)) {
00202 tw_mm_err = TWERR_TIMEOUT;
00203 }
00204 }
00205
00206 if (tw_mm_err == 0) {
00207
00208
00209 tw_mm_idx = 0;
00210
00211 if (rxsiz) {
00212
00213 tw_mm_buf = (uint8_t *) rxdata;
00214 tw_mm_len = (size_t) rxsiz;
00215
00216
00217 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
00218 if (rxsiz == 1) {
00219
00220 outr(TWI_CR, TWI_START | TWI_STOP);
00221 } else {
00222 outr(TWI_CR, TWI_START);
00223 }
00224 outr(TWI_IER, TWI_RXRDY);
00225
00226
00227 if (NutEventWait(&tw_mm_que, tmo)) {
00228 tw_mm_err = TWERR_TIMEOUT;
00229 }
00230 }
00231 }
00232
00233 outr(TWI_IDR, 0xFFFFFFFF);
00234
00235
00236
00237 if (tw_mm_err) {
00238 tw_mm_error = tw_mm_err;
00239 } else {
00240 rc = (int) tw_mm_idx;
00241 }
00242
00243
00244 NutEventPost(&tw_mm_mutex);
00245
00246 return rc;
00247 }
00248
00271 int TwMasterRegRead(uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00272 {
00273 int rc = -1;
00274
00275 if (rxsiz == 0) {
00276 return -1;
00277 }
00278
00279 if (NutEventWait(&tw_mm_mutex, tmo)) {
00280 tw_mm_error = TWERR_IF_LOCKED;
00281 return -1;
00282 }
00283
00284 tw_mm_err = 0;
00285
00286 if (rxsiz) {
00287 tw_mm_buf = rxdata;
00288 tw_mm_len = (size_t) rxsiz;
00289 tw_mm_idx = 0;
00290
00291
00292 outr(TWI_IADRR, iadr);
00293
00294 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8) | TWI_MREAD);
00295
00296 if (rxsiz == 1) {
00297 outr(TWI_CR, TWI_START | TWI_STOP);
00298 } else {
00299 outr(TWI_CR, TWI_START);
00300 }
00301 outr(TWI_IER, TWI_RXRDY);
00302
00303
00304 if (NutEventWait(&tw_mm_que, tmo)) {
00305 tw_mm_error = TWERR_TIMEOUT;
00306 } else if (tw_mm_err) {
00307 tw_mm_error = tw_mm_err;
00308 } else {
00309 rc = (int) tw_mm_idx;
00310 }
00311 outr(TWI_IDR, 0xFFFFFFFF);
00312 }
00313
00314
00315 NutEventPost(&tw_mm_mutex);
00316
00317 return rc;
00318 }
00319
00345 int TwMasterRegWrite(uint8_t sla, uint32_t iadr, uint8_t iadrlen, CONST void *txdata, uint16_t txsiz, uint32_t tmo)
00346 {
00347 int rc = -1;
00348
00349
00350 if (NutEventWait(&tw_mm_mutex, tmo)) {
00351 tw_mm_err = TWERR_IF_LOCKED;
00352 return -1;
00353 }
00354
00355 tw_mm_err = 0;
00356
00357 if (txsiz) {
00358 tw_mm_buf = (uint8_t *) txdata;
00359 tw_mm_len = (size_t) txsiz;
00360 tw_mm_idx = 1;
00361
00362
00363 outr(TWI_IADRR, iadr);
00364
00365 outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
00366 outb(TWI_THR, tw_mm_buf[0]);
00367 outr(TWI_IER, TWI_TXRDY);
00368
00369
00370 if (NutEventWait(&tw_mm_que, tmo)) {
00371 tw_mm_error = TWERR_TIMEOUT;
00372 } else if (tw_mm_err) {
00373 tw_mm_error = tw_mm_err;
00374 } else {
00375 rc = (int) tw_mm_idx;
00376 }
00377 outr(TWI_IDR, 0xFFFFFFFF);
00378 }
00379
00380
00381 NutEventPost(&tw_mm_mutex);
00382
00383 return rc;
00384 }
00385
00393 int TwMasterError(void)
00394 {
00395 int rc = tw_mm_error;
00396 tw_mm_error = 0;
00397 return rc;
00398 }
00399
00409 uint16_t TwMasterIndexes(uint8_t idx)
00410 {
00411 switch (idx) {
00412 case 0:
00413 return (uint16_t) tw_mm_idx;
00414 case 1:
00415 return (uint16_t) tw_mm_idx;
00416 case 2:
00417 return (uint16_t) tw_mm_len;
00418 default:
00419 return 0;
00420 }
00421 }
00422
00438 int TwIOCtl(int req, void *conf)
00439 {
00440 int rc = 0;
00441 unsigned int cldiv, ckdiv;
00442 unsigned int twi_clk;
00443 switch (req) {
00444
00445 case TWI_SETSPEED:
00446 ckdiv = 1;
00447 twi_clk = *((uint32_t *) conf);
00448
00449 if (twi_clk > 400000)
00450 return -1;
00451
00452
00453
00454
00455
00456
00457
00458 while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * twi_clk)) - 3) / (1 << ckdiv)) > 255) {
00459 ckdiv++;
00460 }
00461
00462
00463 if (cldiv * (1 << ckdiv) > 8191)
00464 return -1;
00465
00466 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00467 break;
00468
00469 case TWI_GETSPEED:
00470 ckdiv = 1;
00471 twi_clk = *((uint32_t *) conf);
00472
00473 cldiv = inr(TWI_CWGR) & 0x000000FF;
00474 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00475
00476 *((uint32_t *) conf) = NutGetCpuClock() / ((cldiv * 2 << ckdiv) - 3);
00477 break;
00478
00479 case TWI_GETSTATUS:
00480 break;
00481
00482 case TWI_SETSTATUS:
00483 break;
00484
00485 default:
00486 rc = -1;
00487 break;
00488 }
00489 return rc;
00490 }
00491
00503 int TwInit(uint8_t sla)
00504 {
00505 uint32_t speed = 4800;
00506
00507 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00508 return -1;
00509 }
00510
00511
00512 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00513
00514 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00515
00516 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00517
00518 outr(PMC_PCER, _BV(TWI_ID));
00519
00520
00521 outr(TWI_IDR, 0xFFFFFFFF);
00522
00523 outr(TWI_CR, TWI_SWRST);
00524
00525 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00526
00527 if (TwIOCtl(TWI_SETSPEED, &speed)) {
00528 return -1;
00529 }
00530
00531
00532 NutIrqSetMode(&sig_TWI, NUT_IRQMODE_LEVEL);
00533 NutIrqEnable(&sig_TWI);
00534
00535
00536 NutEventPost(&tw_mm_mutex);
00537
00538 return 0;
00539 }
00540