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 #include <arch/arm.h>
00052 #include <dev/irqreg.h>
00053
00054 #include <sys/event.h>
00055 #include <sys/atom.h>
00056 #include <sys/timer.h>
00057 #include <sys/thread.h>
00058 #include <sys/heap.h>
00059
00060 #include <dev/twif.h>
00061
00066
00067 HANDLE tw_mm_mutex;
00068 HANDLE tw_mm_que;
00069
00070 static u_char tw_mm_sla;
00071 static volatile u_char tw_mm_err;
00072 static u_char tw_mm_error;
00073
00074 static CONST u_char *tw_mt_buf;
00075 static volatile u_short tw_mt_len;
00076 static volatile u_short tw_mt_idx;
00077
00078 static u_char *tw_mr_buf;
00079 static volatile u_short tw_mr_siz;
00080 static volatile u_short tw_mr_idx;
00081
00082 #if defined (MCU_AT91SAM7X256) || defined (MCU_AT91SAM7S256)
00083
00084 #define TWI_PIO_ASR PIOA_ASR
00085 #define TWI_PIO_PDR PIOA_PDR
00086 #define TWI_PIO_MDER PIOA_MDER
00087
00088 #if defined (MCU_AT91SAM7X256)
00089 #define TWI_TWD PA10_TWD_A
00090 #define TWI_TWCK PA11_TWCK_A
00091 #elif defined (MCU_AT91SAM7S256)
00092 #define TWI_TWD PA3_TWD_A
00093 #define TWI_TWCK PA4_TWCK_A
00094 #endif
00095 #endif
00096
00097
00098
00099
00100 static void TwInterrupt(void *arg)
00101 {
00102 register u_int twsr = inr(TWI_SR) & (TWI_NACK | TWI_RXRDY | TWI_TXRDY | TWI_TXCOMP);;
00103
00104
00105 if (twsr & TWI_TXCOMP) {
00106 outr(TWI_IDR, 0xFFFFFFFF);
00107 NutEventPostFromIrq(&tw_mm_que);
00108 }
00109
00110 if (twsr & TWI_RXRDY) {
00111 if (tw_mr_idx < tw_mr_siz) {
00112 tw_mr_buf[tw_mr_idx++] = inb(TWI_RHR);
00113
00114 if (tw_mr_idx == tw_mr_siz - 1) {
00115 outr(TWI_CR, TWI_STOP);
00116 }
00117
00118 if (tw_mr_idx == tw_mr_siz) {
00119
00120 outr(TWI_IDR, TWI_RXRDY);
00121 outr(TWI_IER, TWI_TXCOMP);
00122 }
00123 }
00124 }
00125
00126 if (twsr & TWI_TXRDY) {
00127 if (tw_mt_idx < tw_mt_len) {
00128 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00129
00130 if (tw_mt_idx == tw_mt_len) {
00131 if (tw_mr_siz == 0) {
00132 outr(TWI_CR, TWI_STOP);
00133 outr(TWI_IDR, TWI_TXRDY);
00134 outr(TWI_IER, TWI_TXCOMP);
00135 } else {
00136
00137 outr(TWI_MMR, inb(TWI_MMR) | TWI_MREAD);
00138 outr(TWI_CR, TWI_START | (tw_mr_siz == 1) ? TWI_STOP : 0);
00139 outr(TWI_IDR, TWI_TXRDY);
00140 outr(TWI_IER, TWI_RXRDY);
00141 }
00142 }
00143 }
00144 }
00145
00146
00147 if (twsr & TWI_NACK) {;
00148
00149 outr(TWI_CR, TWI_STOP);
00150 tw_mm_err = TWERR_DATA_NACK;
00151 tw_mt_idx = 0;
00152 tw_mt_len = 0;
00153 tw_mr_siz = 0;
00154 outr(TWI_IDR, 0xFFFFFFFF);
00155
00156 NutEventPostFromIrq(&tw_mm_que);
00157 }
00158 }
00159
00186 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00187 {
00188 int rc = -1;
00189
00190
00191 if(NutEventWait(&tw_mm_mutex, 500)) {
00192 tw_mm_err = TWERR_IF_LOCKED;
00193 NutEventPost(&tw_mm_mutex);
00194 return -1;
00195 }
00196 NutIrqEnable(&sig_TWI);
00197
00198 NutEnterCritical();
00199
00200 tw_mm_sla = sla;
00201 tw_mm_err = 0;
00202 tw_mt_len = txlen;
00203 tw_mt_idx = 0;
00204 tw_mt_buf = txdata;
00205 tw_mr_siz = rxsiz;
00206 tw_mr_buf = rxdata;
00207 tw_mr_idx = 0;
00208
00209 if ((tw_mt_len == 0) && (tw_mr_siz == 0)) return -1;
00210
00211
00212
00213 outr(TWI_MMR, (tw_mm_sla << 16) | (tw_mt_len == 0 ? TWI_MREAD : 0));
00214
00215
00216 if (tw_mt_len == 0) {
00217 outr(TWI_IDR, TWI_TXRDY | TWI_TXCOMP);
00218 outr(TWI_IER, TWI_RXRDY | TWI_NACK);
00219 } else {
00220 outr(TWI_IDR, TWI_RXRDY);
00221 if ((tw_mt_len == 1) && (tw_mr_siz == 0)) {
00222 outr(TWI_IDR, TWI_TXRDY);
00223 outr(TWI_IER, TWI_TXCOMP);
00224 } else {
00225 outr(TWI_IER, TWI_TXRDY);
00226 outr(TWI_IDR, TWI_TXCOMP);
00227 }
00228 outr(TWI_IER, TWI_NACK);
00229 }
00230
00231
00232 if (tw_mt_len > 0) {
00233 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00234 }
00235
00236
00237 outr(TWI_CR, TWI_START | (((tw_mt_len == 1) && (tw_mr_siz == 0)) ||
00238 ((tw_mt_len == 0) && (tw_mr_siz == 1))) ? TWI_STOP : 0);
00239
00240 NutExitCritical();
00241
00242
00243 rc = -1;
00244 if (NutEventWait(&tw_mm_que, tmo)) {
00245 tw_mm_error = TWERR_TIMEOUT;
00246 } else {
00247 NutEnterCritical();
00248 if (tw_mm_err) {
00249 tw_mm_error = tw_mm_err;
00250 } else {
00251 rc = tw_mr_idx;
00252 }
00253 NutExitCritical();
00254 }
00255
00256 NutIrqDisable(&sig_TWI);
00257
00258
00259 NutEventPost(&tw_mm_mutex);
00260
00261 return rc;
00262 }
00263
00273 int TwMasterError(void)
00274 {
00275 int rc = (int) tw_mm_error;
00276 tw_mm_error = 0;
00277 return rc;
00278 }
00279
00295 int TwIOCtl(int req, void *conf)
00296 {
00297 int rc = 0;
00298 unsigned int cldiv, ckdiv;
00299 unsigned int twi_clk;
00300 switch (req) {
00301
00302 case TWI_SETSPEED:
00303 ckdiv=1 ;
00304 twi_clk = *((u_long *) conf);
00305
00306 if (twi_clk > 400000) return -1;
00307
00308
00309
00310
00311
00312
00313
00314 while ((cldiv = ((NutGetCpuClock() / (2*twi_clk))-3 ) / (1 << ckdiv)) > 255) {
00315 ckdiv++;
00316 }
00317
00318
00319 if (cldiv * (2 << ckdiv) > 8191) return -1;
00320
00321 outr(TWI_CWGR, (ckdiv << 16) | ((u_int) cldiv << 8) | (u_int) cldiv);
00322 break;
00323
00324 case TWI_GETSPEED:
00325 ckdiv=1 ;
00326 twi_clk = *((u_long *) conf);
00327
00328 cldiv = inr(TWI_CWGR) & 0x000000FF;
00329 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00330
00331 *((u_long *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00332 break;
00333
00334 case TWI_GETSTATUS:
00335 break;
00336
00337 case TWI_SETSTATUS:
00338 break;
00339
00340 default:
00341 rc = -1;
00342 break;
00343 }
00344 return rc;
00345 }
00346
00359 int TwInit(u_char sla)
00360 {
00361 u_long speed = 2400;
00362
00363 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00364 return -1;
00365 }
00366
00367 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00368 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00369
00370 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00371
00372 outr(PMC_PCER, _BV(TWI_ID));
00373
00374 outr(TWI_IDR, 0xFFFFFFFF);
00375 outr(TWI_CR, TWI_SWRST);
00376 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00377
00378 TwIOCtl(TWI_SETSPEED, &speed);
00379
00380
00381 NutEventPost(&tw_mm_mutex);
00382
00383 return 0;
00384 }