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 <stdio.h>
00043 #include <arch/arm.h>
00044 #include <dev/irqreg.h>
00045
00046 #include <sys/event.h>
00047 #include <sys/atom.h>
00048 #include <sys/timer.h>
00049 #include <sys/thread.h>
00050 #include <sys/heap.h>
00051
00052 #include <dev/twif.h>
00053
00054 HANDLE tw_mm_mutex;
00055 HANDLE tw_mm_que;
00056
00057 static u_char tw_mm_sla;
00058 static volatile u_char tw_mm_err;
00059 static u_char tw_mm_error;
00060
00061 static CONST u_char *tw_mt_buf;
00062 static volatile u_short tw_mt_len;
00063 static volatile u_short tw_mt_idx;
00064
00065 static u_char *tw_mr_buf;
00066 static volatile u_short tw_mr_siz;
00067 static volatile u_short tw_mr_idx;
00068
00069 #if defined (MCU_AT91SAM7X256)
00070
00071 #define TWI_PIO_ASR PIOA_ASR
00072 #define TWI_PIO_PDR PIOA_PDR
00073 #define TWI_PIO_MDER PIOA_MDER
00074
00075 #define TWI_TWD PA10_TWD_A
00076 #define TWI_TWCK PA11_TWCK_A
00077
00078 #endif
00079
00080
00081
00082
00083 static void TwInterrupt(void *arg)
00084 {
00085 register u_int twsr = inr(TWI_SR) & (TWI_NACK | TWI_RXRDY | TWI_TXRDY | TWI_TXCOMP);;
00086
00087
00088 if (twsr & TWI_TXCOMP) {
00089 outr(TWI_IDR, 0xFFFFFFFF);
00090 NutEventPostFromIrq(&tw_mm_que);
00091 }
00092
00093 if (twsr & TWI_RXRDY) {
00094 if (tw_mr_idx < tw_mr_siz) {
00095 tw_mr_buf[tw_mr_idx++] = inb(TWI_RHR);
00096
00097 if (tw_mr_idx == tw_mr_siz - 1) {
00098 outr(TWI_CR, TWI_STOP);
00099 }
00100
00101 if (tw_mr_idx == tw_mr_siz) {
00102
00103 outr(TWI_IDR, TWI_RXRDY);
00104 outr(TWI_IER, TWI_TXCOMP);
00105 }
00106 }
00107 }
00108
00109 if (twsr & TWI_TXRDY) {
00110 if (tw_mt_idx < tw_mt_len) {
00111 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00112
00113 if (tw_mt_idx == tw_mt_len) {
00114 if (tw_mr_siz == 0) {
00115 outr(TWI_CR, TWI_STOP);
00116 outr(TWI_IDR, TWI_TXRDY);
00117 outr(TWI_IER, TWI_TXCOMP);
00118 } else {
00119
00120 outr(TWI_MMR, inb(TWI_MMR) | TWI_MREAD);
00121 outr(TWI_CR, TWI_START | (tw_mr_siz == 1) ? TWI_STOP : 0);
00122 outr(TWI_IDR, TWI_TXRDY);
00123 outr(TWI_IER, TWI_RXRDY);
00124 }
00125 }
00126 }
00127 }
00128
00129
00130 if (twsr & TWI_NACK) {;
00131
00132 outr(TWI_CR, TWI_STOP);
00133 tw_mm_err = TWERR_DATA_NACK;
00134 tw_mt_idx = 0;
00135 tw_mt_len = 0;
00136 tw_mr_siz = 0;
00137 outr(TWI_IDR, 0xFFFFFFFF);
00138
00139 NutEventPostFromIrq(&tw_mm_que);
00140 }
00141 }
00142
00169 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00170 {
00171 int rc = -1;
00172
00173
00174 if(NutEventWait(&tw_mm_mutex, 500)) {
00175 tw_mm_err = TWERR_IF_LOCKED;
00176 NutEventPost(&tw_mm_mutex);
00177 return -1;
00178 }
00179 NutIrqEnable(&sig_TWI);
00180
00181 NutEnterCritical();
00182
00183 tw_mm_sla = sla;
00184 tw_mm_err = 0;
00185 tw_mt_len = txlen;
00186 tw_mt_idx = 0;
00187 tw_mt_buf = txdata;
00188 tw_mr_siz = rxsiz;
00189 tw_mr_buf = rxdata;
00190 tw_mr_idx = 0;
00191
00192 if ((tw_mt_len == 0) && (tw_mr_siz == 0)) return -1;
00193
00194
00195
00196 outr(TWI_MMR, (tw_mm_sla << 16) | (tw_mt_len == 0 ? TWI_MREAD : 0));
00197
00198
00199 if (tw_mt_len == 0) {
00200 outr(TWI_IDR, TWI_TXRDY | TWI_TXCOMP);
00201 outr(TWI_IER, TWI_RXRDY | TWI_NACK);
00202 } else {
00203 outr(TWI_IDR, TWI_RXRDY);
00204 if ((tw_mt_len == 1) && (tw_mr_siz == 0)) {
00205 outr(TWI_IDR, TWI_TXRDY);
00206 outr(TWI_IER, TWI_TXCOMP);
00207 } else {
00208 outr(TWI_IER, TWI_TXRDY);
00209 outr(TWI_IDR, TWI_TXCOMP);
00210 }
00211 outr(TWI_IER, TWI_NACK);
00212 }
00213
00214
00215 if (tw_mt_len > 0) {
00216 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00217 }
00218
00219
00220 outr(TWI_CR, TWI_START | (((tw_mt_len == 1) && (tw_mr_siz == 0)) ||
00221 ((tw_mt_len == 0) && (tw_mr_siz == 1))) ? TWI_STOP : 0);
00222
00223 NutExitCritical();
00224
00225
00226 rc = -1;
00227 if (NutEventWait(&tw_mm_que, tmo)) {
00228 tw_mm_error = TWERR_TIMEOUT;
00229 } else {
00230 NutEnterCritical();
00231 if (tw_mm_err) {
00232 tw_mm_error = tw_mm_err;
00233 } else {
00234 rc = tw_mr_idx;
00235 }
00236 NutExitCritical();
00237 }
00238
00239 NutIrqDisable(&sig_TWI);
00240
00241
00242 NutEventPost(&tw_mm_mutex);
00243
00244 return rc;
00245 }
00246
00256 int TwMasterError(void)
00257 {
00258 int rc = (int) tw_mm_error;
00259 tw_mm_error = 0;
00260 return rc;
00261 }
00262
00278 int TwIOCtl(int req, void *conf)
00279 {
00280 int rc = 0;
00281 unsigned int cldiv, ckdiv;
00282 unsigned int twi_clk;
00283 switch (req) {
00284
00285 case TWI_SETSPEED:
00286 ckdiv=1 ;
00287 twi_clk = *((u_long *) conf);
00288
00289 if (twi_clk > 400000) return -1;
00290
00291
00292
00293
00294
00295
00296
00297 while ((cldiv = ((NutGetCpuClock() / (2*twi_clk))-3 ) / (1 << ckdiv)) > 255) {
00298 ckdiv++;
00299 }
00300
00301
00302 if (cldiv * (2 << ckdiv) > 8191) return -1;
00303
00304 outr(TWI_CWGR, (ckdiv << 16) | ((u_int) cldiv << 8) | (u_int) cldiv);
00305 break;
00306
00307 case TWI_GETSPEED:
00308 ckdiv=1 ;
00309 twi_clk = *((u_long *) conf);
00310
00311 cldiv = inr(TWI_CWGR) & 0x000000FF;
00312 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00313
00314 *((u_long *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00315 break;
00316
00317 case TWI_GETSTATUS:
00318 break;
00319
00320 case TWI_SETSTATUS:
00321 break;
00322
00323 default:
00324 rc = -1;
00325 break;
00326 }
00327 return rc;
00328 }
00329
00342 int TwInit(u_char sla)
00343 {
00344 u_long speed = 2400;
00345
00346 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00347 return -1;
00348 }
00349
00350 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00351 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00352
00353 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00354
00355 outr(PMC_PCER, _BV(TWI_ID));
00356
00357 outr(TWI_IDR, 0xFFFFFFFF);
00358 outr(TWI_CR, TWI_SWRST);
00359 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00360
00361 TwIOCtl(TWI_SETSPEED, &speed);
00362
00363
00364 NutEventPost(&tw_mm_mutex);
00365
00366 return 0;
00367 }