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