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