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 if ((txlen == 0) && (rxsiz == 0)) {
00220 return -1;
00221 }
00222
00223 NutEnterCritical();
00224
00225 tw_mm_sla = sla;
00226 tw_mm_err = 0;
00227 tw_mt_len = txlen;
00228 tw_mt_idx = 0;
00229 tw_mt_buf = txdata;
00230 tw_mr_siz = rxsiz;
00231 tw_mr_buf = rxdata;
00232 tw_mr_idx = 0;
00233
00234
00235
00236 outr(TWI_MMR, (tw_mm_sla << 16) | (tw_mt_len == 0 ? TWI_MREAD : 0));
00237
00238
00239 if (tw_mt_len == 0) {
00240 outr(TWI_IDR, TWI_TXRDY | TWI_TXCOMP);
00241 outr(TWI_IER, TWI_RXRDY | TWI_NACK);
00242 } else {
00243 outr(TWI_IDR, TWI_RXRDY);
00244 if ((tw_mt_len == 1) && (tw_mr_siz == 0)) {
00245 outr(TWI_IDR, TWI_TXRDY);
00246 outr(TWI_IER, TWI_TXCOMP);
00247 } else {
00248 outr(TWI_IER, TWI_TXRDY);
00249 outr(TWI_IDR, TWI_TXCOMP);
00250 }
00251 outr(TWI_IER, TWI_NACK);
00252 }
00253
00254
00255 if (tw_mt_len > 0) {
00256 outb(TWI_THR, tw_mt_buf[tw_mt_idx++]);
00257 }
00258
00259
00260 outr(TWI_CR, TWI_START | (((tw_mt_len == 1) && (tw_mr_siz == 0)) ||
00261 ((tw_mt_len == 0) && (tw_mr_siz == 1))) ? TWI_STOP : 0);
00262
00263 NutExitCritical();
00264
00265
00266 rc = -1;
00267 if (NutEventWait(&tw_mm_que, tmo)) {
00268 tw_mm_error = TWERR_TIMEOUT;
00269 } else {
00270 NutEnterCritical();
00271 if (tw_mm_err) {
00272 tw_mm_error = tw_mm_err;
00273 } else {
00274 rc = tw_mr_idx;
00275 }
00276 NutExitCritical();
00277 }
00278
00279 NutIrqDisable(&sig_TWI);
00280
00281
00282 NutEventPost(&tw_mm_mutex);
00283
00284 return rc;
00285 }
00286
00296 int TwMasterError(void)
00297 {
00298 int rc = (int) tw_mm_error;
00299 tw_mm_error = 0;
00300 return rc;
00301 }
00302
00318 int TwIOCtl(int req, void *conf)
00319 {
00320 int rc = 0;
00321 unsigned int cldiv, ckdiv;
00322 unsigned int twi_clk;
00323 switch (req) {
00324
00325 case TWI_SETSPEED:
00326 ckdiv=1 ;
00327 twi_clk = *((uint32_t *) conf);
00328
00329 if (twi_clk > 400000) return -1;
00330
00331
00332
00333
00334
00335
00336
00337 while ((cldiv = ((NutGetCpuClock() / (2*twi_clk))-3 ) / (1 << ckdiv)) > 255) {
00338 ckdiv++;
00339 }
00340
00341
00342 if (cldiv * (1 << ckdiv) > 8191) return -1;
00343
00344 outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
00345 break;
00346
00347 case TWI_GETSPEED:
00348 ckdiv=1 ;
00349 twi_clk = *((uint32_t *) conf);
00350
00351 cldiv = inr(TWI_CWGR) & 0x000000FF;
00352 ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
00353
00354 *((uint32_t *) conf) = NutGetCpuClock() * ((cldiv * 2 << ckdiv) - 3);
00355 break;
00356
00357 case TWI_GETSTATUS:
00358 break;
00359
00360 case TWI_SETSTATUS:
00361 break;
00362
00363 default:
00364 rc = -1;
00365 break;
00366 }
00367 return rc;
00368 }
00369
00382 int TwInit(uint8_t sla)
00383 {
00384 uint32_t speed = 4800;
00385
00386 if (NutRegisterIrqHandler(&sig_TWI, TwInterrupt, 0)) {
00387 return -1;
00388 }
00389
00390 outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00391 outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
00392
00393 outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
00394
00395 outr(PMC_PCER, _BV(TWI_ID));
00396
00397 outr(TWI_IDR, 0xFFFFFFFF);
00398 outr(TWI_CR, TWI_SWRST);
00399 outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
00400
00401 TwIOCtl(TWI_SETSPEED, &speed);
00402
00403
00404 NutEventPost(&tw_mm_mutex);
00405
00406 return 0;
00407 }