Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:40

0001 /* this is not much more than a shell; it does not do anything useful yet */
0002 
0003 /*  TWI (I2C) driver for Blackfin
0004  *
0005  *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
0006  *             written by Allan Hessenflow <allanh@kallisti.com>
0007  *
0008  *  The license and distribution terms for this file may be
0009  *  found in the file LICENSE in this distribution or at
0010  *  http://www.rtems.org/license/LICENSE.
0011  */
0012 
0013 
0014 #include <stdlib.h>
0015 #include <rtems.h>
0016 
0017 #include <libcpu/twiRegs.h>
0018 #include <libcpu/twi.h>
0019 
0020 
0021 #ifndef N_BFIN_TWI
0022 #define N_BFIN_TWI 1
0023 #endif
0024 
0025 #define BFIN_REG16(base, offset) \
0026         (*((uint16_t volatile *) ((char *)(base) + (offset))))
0027 
0028 
0029 static struct {
0030   void *base;
0031   rtems_id irqSem;
0032   rtems_id mutex;
0033   bfin_twi_callback_t callback;
0034   void *callbackArg;
0035   bfin_twi_request_t volatile *req;
0036   uint8_t volatile *dataPtr;
0037   int volatile count;
0038   bool volatile masterActive;
0039   rtems_status_code volatile masterResult;
0040   bool volatile slaveActive;
0041 } twi[N_BFIN_TWI];
0042 
0043 
0044 rtems_status_code bfin_twi_init(int channel, bfin_twi_config_t *config) {
0045   rtems_status_code result;
0046   void *base;
0047 
0048   if (channel < 0 || channel >= N_BFIN_TWI)
0049     return RTEMS_INVALID_NUMBER;
0050 
0051   base = config->base;
0052   twi[channel].base = base;
0053 
0054   result = rtems_semaphore_create(rtems_build_name('t','w','i','s'),
0055                                   0,
0056                                   RTEMS_FIFO |
0057                                   RTEMS_SIMPLE_BINARY_SEMAPHORE |
0058                                   RTEMS_NO_INHERIT_PRIORITY |
0059                                   RTEMS_NO_PRIORITY_CEILING |
0060                                   RTEMS_LOCAL,
0061                                   0,
0062                                   &twi[channel].irqSem);
0063   result = rtems_semaphore_create(rtems_build_name('t','w','i','m'),
0064                                   1,
0065                                   RTEMS_PRIORITY |
0066                                   RTEMS_SIMPLE_BINARY_SEMAPHORE |
0067                                   RTEMS_INHERIT_PRIORITY |
0068                                   RTEMS_NO_PRIORITY_CEILING |
0069                                   RTEMS_LOCAL,
0070                                   0,
0071                                   &twi[channel].mutex);
0072   BFIN_REG16(base, TWI_CONTROL_OFFSET) =
0073       (uint16_t) (((config->sclk +9999999) / 10000000) <<
0074                   TWI_CONTROL_PRESCALE_SHIFT) |
0075       TWI_CONTROL_TWI_ENA;
0076   BFIN_REG16(base, TWI_CLKDIV_OFFSET) = config->fast ?
0077                                         ((8 << TWI_CLKDIV_CLKHI_SHIFT) |
0078                                          (17 << TWI_CLKDIV_CLKLOW_SHIFT)) :
0079                                         ((33 << TWI_CLKDIV_CLKHI_SHIFT) |
0080                                          (67 << TWI_CLKDIV_CLKLOW_SHIFT));
0081   BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
0082   BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = config->fast ?
0083                                             TWI_MASTER_CTL_FAST :
0084                                             0;
0085   BFIN_REG16(base, TWI_SLAVE_ADDR_OFFSET) = (uint16_t) config->slave_address <<
0086                                             TWI_SLAVE_ADDR_SADDR_SHIFT;
0087   BFIN_REG16(base, TWI_MASTER_STAT_OFFSET) = TWI_MASTER_STAT_BUFWRERR |
0088                                              TWI_MASTER_STAT_BUFRDERR |
0089                                              TWI_MASTER_STAT_DNAK |
0090                                              TWI_MASTER_STAT_ANAK |
0091                                              TWI_MASTER_STAT_LOSTARB;
0092   BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = TWI_FIFO_CTL_XMTFLUSH |
0093                                           TWI_FIFO_CTL_RCVFLUSH;
0094   BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = 0;
0095   BFIN_REG16(base, TWI_INT_STAT_OFFSET) = TWI_INT_STAT_RCVSERV |
0096                                           TWI_INT_STAT_XMTSERV |
0097                                           TWI_INT_STAT_MERR |
0098                                           TWI_INT_STAT_MCOMP |
0099                                           TWI_INT_STAT_SOVF |
0100                                           TWI_INT_STAT_SERR |
0101                                           TWI_INT_STAT_SCOMP |
0102                                           TWI_INT_STAT_SINIT;
0103   BFIN_REG16(base, TWI_INT_MASK_OFFSET) = TWI_INT_MASK_RCVSERVM |
0104                                           TWI_INT_MASK_XMTSERVM;
0105 
0106   return result;
0107 }
0108 
0109 rtems_status_code bfin_twi_register_callback(int channel,
0110                                              bfin_twi_callback_t callback,
0111                                              void *arg) {
0112   void *base;
0113   int level;
0114 
0115   if (channel < 0 || channel >= N_BFIN_TWI)
0116     return RTEMS_INVALID_NUMBER;
0117 
0118   base = twi[channel].base;
0119   if (callback == NULL)
0120     BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
0121   rtems_interrupt_disable(level);
0122   twi[channel].callback = callback;
0123   twi[channel].callbackArg = arg;
0124   rtems_interrupt_enable(level);
0125   if (callback != NULL)
0126     BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = TWI_SLAVE_CTL_GEN |
0127                                              TWI_SLAVE_CTL_SEN;
0128 
0129   return RTEMS_SUCCESSFUL;
0130 }
0131 
0132 void bfin_twi_isr(int source) {
0133   void *base;
0134   int i;
0135   uint16_t r;
0136   uint16_t stat;
0137 
0138   for (i = 0; i < N_BFIN_TWI; i++) {
0139     base = twi[i].base;
0140     if (base) {
0141       stat = BFIN_REG16(base, TWI_INT_STAT_OFFSET);
0142       if (stat) {
0143         BFIN_REG16(base, TWI_INT_STAT_OFFSET) = stat;
0144         if ((stat & TWI_INT_STAT_SINIT) && !twi[i].slaveActive) {
0145           twi[i].slaveActive = true;
0146           r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
0147           BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
0148           BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
0149           r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
0150           BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r | TWI_SLAVE_CTL_STDVAL;
0151         }
0152         if (twi[i].slaveActive) {
0153 
0154 
0155           if (stat & (TWI_INT_STAT_SCOMP | TWI_INT_STAT_SERR)) {
0156 
0157 
0158             r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
0159             BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r & ~TWI_SLAVE_CTL_STDVAL;
0160             twi[i].slaveActive = false;
0161 
0162 
0163           }
0164         }
0165         if (twi[i].masterActive && !twi[i].slaveActive) {
0166 
0167 
0168           if (stat & (TWI_INT_STAT_MCOMP | TWI_INT_STAT_MERR)) {
0169             if (!(stat & TWI_INT_STAT_MERR)) {
0170 
0171 
0172               rtems_semaphore_release(twi[i].irqSem);
0173 
0174 
0175             } else
0176               rtems_semaphore_release(twi[i].irqSem);
0177           }
0178         }
0179       }
0180     }
0181   }
0182 }
0183 
0184 rtems_status_code bfin_twi_request(int channel, uint8_t address,
0185                                    bfin_twi_request_t *request,
0186                                    rtems_interval timeout) {
0187   rtems_status_code result;
0188   void *base;
0189   rtems_interrupt_level level;
0190   uint16_t r;
0191   uint16_t masterMode;
0192 
0193   if (channel < 0 || channel >= N_BFIN_TWI)
0194     return RTEMS_INVALID_NUMBER;
0195   result = rtems_semaphore_obtain(twi[channel].mutex,
0196                                   RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0197   if (result == RTEMS_SUCCESSFUL) {
0198     base = twi[channel].base;
0199     twi[channel].req = request;
0200 
0201     if (request->write) {
0202       twi[channel].dataPtr = request->data;
0203       twi[channel].count = request->count;
0204     } else
0205       twi[channel].count = 0;
0206 
0207     BFIN_REG16(base, TWI_MASTER_ADDR_OFFSET) = (uint16_t) address <<
0208                                                TWI_MASTER_ADDR_MADDR_SHIFT;
0209     masterMode = BFIN_REG16(base, TWI_MASTER_CTL_OFFSET);
0210     masterMode |= (request->count << TWI_MASTER_CTL_DCNT_SHIFT);
0211     if (request->next)
0212       masterMode |= TWI_MASTER_CTL_RSTART;
0213     if (!request->write)
0214       masterMode |= TWI_MASTER_CTL_MDIR;
0215     masterMode |= TWI_MASTER_CTL_MEN;
0216     rtems_interrupt_disable(level);
0217     if (!twi[channel].slaveActive) {
0218       r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
0219       BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
0220       BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
0221       if (request->write) {
0222         while (twi[channel].count &&
0223                (BFIN_REG16(base, TWI_FIFO_STAT_OFFSET) &
0224                 TWI_FIFO_STAT_XMTSTAT_MASK) !=
0225                TWI_FIFO_STAT_XMTSTAT_FULL) {
0226           BFIN_REG16(base, TWI_XMT_DATA8_OFFSET) =
0227               (uint16_t) *twi[channel].dataPtr++;
0228           twi[channel].count--;
0229         }
0230       }
0231       twi[channel].masterActive = true;
0232       BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = masterMode;
0233     } else {
0234       twi[channel].masterActive = false;
0235       twi[channel].masterResult = -1; /* BISON (code should be equiv to lost arbitration) */
0236     }
0237     rtems_interrupt_enable(level);
0238     while (result == RTEMS_SUCCESSFUL && twi[channel].masterActive)
0239       result = rtems_semaphore_obtain(twi[channel].irqSem,
0240                                       RTEMS_WAIT, timeout);
0241     if (result == RTEMS_SUCCESSFUL)
0242       result = twi[channel].masterResult;
0243     else {
0244       /* BISON abort */
0245 
0246 
0247 
0248     }
0249     rtems_semaphore_release(twi[channel].mutex);
0250   }
0251   return result;
0252 }
0253