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
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include <arch/arm.h>
00065 #include <dev/irqreg.h>
00066
00067 #include <sys/event.h>
00068 #include <sys/atom.h>
00069 #include <sys/timer.h>
00070 #include <sys/thread.h>
00071 #include <sys/heap.h>
00072
00073 #include <dev/twif.h>
00074
00079
00080 HANDLE tw_mm_mutex;
00081 HANDLE tw_mm_que;
00082
00083 static uint8_t tw_mm_sla;
00084 static volatile uint8_t tw_mm_err;
00085 static uint8_t tw_mm_error;
00086
00087 static CONST uint8_t *tw_mt_buf;
00088 static volatile uint16_t tw_mt_len;
00089 static volatile uint16_t tw_mt_idx;
00090
00091 static uint8_t *tw_mr_buf;
00092 static volatile uint16_t tw_mr_siz;
00093 static volatile uint16_t tw_mr_idx;
00094
00095 #if defined (MCU_AT91SAM7X256) || defined (MCU_AT91SAM7S256) || defined (MCU_AT91SAM7SE512)
00096
00097 #define TWI_PIO_ASR PIOA_ASR
00098 #define TWI_PIO_PDR PIOA_PDR
00099 #define TWI_PIO_MDER PIOA_MDER
00100
00101 #if defined (MCU_AT91SAM7X256)
00102 #define TWI_TWD PA10_TWD_A
00103 #define TWI_TWCK PA11_TWCK_A
00104 #elif defined (MCU_AT91SAM7S256) || defined (MCU_AT91SAM7SE512)
00105 #define TWI_TWD PA3_TWD_A
00106 #define TWI_TWCK PA4_TWCK_A
00107 #endif
00108 #endif
00109
00110 #if defined (MCU_AT91SAM9260)
00111 #define TWI_PIO_ASR PIOA_ASR
00112 #define TWI_PIO_PDR PIOA_PDR
00113 #define TWI_PIO_MDER PIOA_MDER
00114 #define TWI_TWD PA23_TWD_A
00115 #define TWI_TWCK PA24_TWCK_A
00116 #endif
00117
00118
00119
00120
00121 static void TwInterrupt(void *arg)
00122 {
00123 register unsigned int twsr = inr(TWI_SR) & (TWI_NACK | TWI_RXRDY | TWI_TXRDY | TWI_TXCOMP);;
00124
00125
00126 if (twsr & TWI_TXCOMP) {
00127 outr(TWI_IDR, 0xFFFFFFFF);
00128 NutEventPostFromIrq(&tw_mm_que);
00129 }
00130
00131 if (twsr & TWI_RXRDY) {
00132 if (tw_mr_idx < tw_mr_siz) {
00133 tw_mr_buf[tw_mr_idx++] = inb(TWI_RHR);
00134
00135 if (tw_mr_idx == tw_mr_siz - 1) {
00136 outr(TWI_CR, TWI_STOP);
00137 }
00138
00139 if (tw_mr_idx == tw_mr_siz) {
00140
00141 outr(TWI_IDR, TWI_RXRDY);
00142 outr(TWI_IER, TWI_TXCOMP);
00143 }
00144 }
00145 }
00146
00147 if (twsr & TWI_TXRDY) {
00148 if (tw_mt_idx < tw_mt_len) {
00149 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00150
00151 if (tw_mt_idx == tw_mt_len) {
00152 if (tw_mr_siz == 0) {
00153 outr(TWI_CR, TWI_STOP);
00154 outr(TWI_IDR, TWI_TXRDY);
00155 outr(TWI_IER, TWI_TXCOMP);
00156 } else {
00157
00158 outr(TWI_MMR, inb(TWI_MMR) | TWI_MREAD);
00159 outr(TWI_CR, TWI_START | (tw_mr_siz == 1) ? TWI_STOP : 0);
00160 outr(TWI_IDR, TWI_TXRDY);
00161 outr(TWI_IER, TWI_RXRDY);
00162 }
00163 }
00164 }
00165 }
00166
00167
00168 if (twsr & TWI_NACK) {;
00169
00170 outr(TWI_CR, TWI_STOP);
00171 tw_mm_err = TWERR_DATA_NACK;
00172 tw_mt_idx = 0;
00173 tw_mt_len = 0;
00174 tw_mr_siz = 0;
00175 outr(TWI_IDR, 0xFFFFFFFF);
00176
00177 NutEventPostFromIrq(&tw_mm_que);
00178 }
00179 }
00180
00207 int TwMasterTransact(uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
00208 {
00209 int rc = -1;
00210
00211
00212 if(NutEventWait(&tw_mm_mutex, 500)) {
00213 tw_mm_err = TWERR_IF_LOCKED;
00214 NutEventPost(&tw_mm_mutex);
00215 return -1;
00216 }
00217 NutIrqEnable(&sig_TWI);
00218
00219 NutEnterCritical();
00220
00221 tw_mm_sla = sla;
00222 tw_mm_err = 0;
00223 tw_mt_len = txlen;
00224 tw_mt_idx = 0;
00225 tw_mt_buf = txdata;
00226 tw_mr_siz = rxsiz;
00227 tw_mr_buf = rxdata;
00228 tw_mr_idx = 0;
00229
00230 if ((tw_mt_len == 0) && (tw_mr_siz == 0)) return -1;
00231
00232
00233
00234 outr(TWI_MMR, (tw_mm_sla << 16) | (tw_mt_len == 0 ? TWI_MREAD : 0));
00235
00236
00237 if (tw_mt_len == 0) {
00238 outr(TWI_IDR, TWI_TXRDY | TWI_TXCOMP);
00239 outr(TWI_IER, TWI_RXRDY | TWI_NACK);
00240 } else {
00241 outr(TWI_IDR, TWI_RXRDY);
00242 if ((tw_mt_len == 1) && (tw_mr_siz == 0)) {
00243 outr(TWI_IDR, TWI_TXRDY);
00244 outr(TWI_IER, TWI_TXCOMP);
00245 } else {
00246 outr(TWI_IER, TWI_TXRDY);
00247 outr(TWI_IDR, TWI_TXCOMP);
00248 }
00249 outr(TWI_IER, TWI_NACK);
00250 }
00251
00252
00253 if (tw_mt_len > 0) {
00254 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00255 }
00256
00257
00258 outr(TWI_CR, TWI_START | (((tw_mt_len == 1) && (tw_mr_siz == 0)) ||
00259 ((tw_mt_len == 0) && (tw_mr_siz == 1))) ? TWI_STOP : 0);
00260
00261 NutExitCritical();
00262
00263
00264 rc = -1;
00265 if (NutEventWait(&tw_mm_que, tmo)) {
00266 tw_mm_error = TWERR_TIMEOUT;
00267 } else {
00268 NutEnterCritical();
00269 if (tw_mm_err) {
00270 tw_mm_error = tw_mm_err;
00271 } else {
00272 rc = tw_mr_idx;
00273 }
00274 NutExitCritical();
00275 }
00276
00277 NutIrqDisable(&sig_TWI);
00278
00279
00280 NutEventPost(&tw_mm_mutex);
00281
00282 return rc;
00283 }
00284
00294 int TwMasterError(void)
00295 {
00296 int rc = (int) tw_mm_error;
00297 tw_mm_error = 0;
00298 return rc;
00299 }
00300
00316 int TwIOCtl(int req, void *conf)
00317 {
00318 int rc = 0;
00319 unsigned int cldiv, ckdiv;
00320 unsigned int twi_clk;
00321 switch (req) {
00322
00323 case TWI_SETSPEED:
00324 ckdiv=1 ;
00325 twi_clk = *((uint32_t *) conf);
00326
00327 if (twi_clk > 400000) return -1;
00328
00329
00330
00331
00332
00333
00334
00335 while ((cldiv = ((NutGetCpuClock() / (2*twi_clk))-3 ) / (1 << ckdiv)) > 255) {
00336 ckdiv++;
00337 }
00338
00339
00340 if (cldiv * (2 << ckdiv) > 8191) return -1;
00341
00342 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00343 break;
00344
00345 case TWI_GETSPEED:
00346 ckdiv=1 ;
00347 twi_clk = *((uint32_t *) conf);
00348
00349 cldiv = inr(TWI_CWGR) & 0x000000FF;
00350 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00351
00352 *((uint32_t *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00353 break;
00354
00355 case TWI_GETSTATUS:
00356 break;
00357
00358 case TWI_SETSTATUS:
00359 break;
00360
00361 default:
00362 rc = -1;
00363 break;
00364 }
00365 return rc;
00366 }
00367
00380 int TwInit(uint8_t sla)
00381 {
00382 uint32_t speed = 2400;
00383
00384 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00385 return -1;
00386 }
00387
00388 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00389 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00390
00391 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00392
00393 outr(PMC_PCER, _BV(TWI_ID));
00394
00395 outr(TWI_IDR, 0xFFFFFFFF);
00396 outr(TWI_CR, TWI_SWRST);
00397 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00398
00399 TwIOCtl(TWI_SETSPEED, &speed);
00400
00401
00402 NutEventPost(&tw_mm_mutex);
00403
00404 return 0;
00405 }