src/dev/i2c/bus.cc
/**
 * The default i2c bus driver used by the realview pbx board writes to
 * this device one bit at a time. To facilitate making new i2c devices,
 * i2cBus::write takes care of the low-level details of the i2c protocol.
 * See the I2C Specification [1] for a detailed description of the
 * protocol.
 *
 * [1] - http://www.nxp.com/documents/user_manual/UM10204.pdf
 */
The default i2c bus driver used by the realview pbx board writes to
this device one bit at a time. To facilitate making new i2c devices,
i2cBus::write takes care of the low-level details of the i2c protocol.
See the I2C Specification [1] for a detailed description of the
protocol.


The default i2c bus driver used by the realview pbx board writes to this device one bit at a time . To facilitate making new i2c devices i2cBus :: write takes care of the low - level details of the i2c protocol . See the I2C Specification [ 1 ] for a detailed description of the protocol .
Tick
I2CBus::write(PacketPtr pkt)
{
    assert(pkt->getAddr() == pioAddr + SB_CONTROLS ||
           pkt->getAddr() == pioAddr + SB_CONTROLC);
    updateSignals(pkt);
    if (isStart(pkt)) {
        state = RECEIVING_ADDR;
        message = 0x00;
        currBit = 7;
        for (auto& d : devices) {
            d.second->i2cStart();
        }
        return pioDelay;
    }
    if (isEnd(pkt)) {
        state = IDLE;
        return pioDelay;
    }
    if (isClockSet(pkt)) {
        switch (state) {
          case RECEIVING_ADDR:
            if (currBit >= 0) {
                message |= sda << currBit;
                currBit--;
            } else {
                i2cAddr = message >> 1;
                assert(devices.find(i2cAddr) != devices.end());
                if (message & 0x01) {
                    state = SENDING_DATA;
                    message = devices[i2cAddr]->read();
                } else {
                    state = RECEIVING_DATA;
                    message = 0x00;
                }
                currBit = 7;
                sda = 0; 
            }
            break;
          case RECEIVING_DATA:
            if (currBit >= 0) {
                message |= sda << currBit;
                currBit--;
            } else {
                devices[i2cAddr]->write(message);
                message = 0x00;
                currBit = 7;
                sda = 0; 
            }
            break;
          case SENDING_DATA:
            if (currBit >= 0) {
                sda = (message >> currBit) & 0x01;
                currBit--;
            } else {
                if (!sda) 
                    message = devices[i2cAddr]->read();
                currBit = 7;
            }
            break;
          case IDLE:
          default:
            panic("Invalid state on posedge of clock in I2CBus::write.\n");
            break;
        }
    }
    return pioDelay;
}
Tick I2CBus :: write ( PacketPtr pkt ) { assert ( pkt -> getAddr ( ) == pioAddr + SB_CONTROLS || pkt -> getAddr ( ) == pioAddr + SB_CONTROLC ) ; updateSignals ( pkt ) ; if ( isStart ( pkt ) ) { state = RECEIVING_ADDR ; message = 0x00 ; currBit = 7 ; for ( auto & d : devices ) { d . second -> i2cStart ( ) ; } return pioDelay ; } if ( isEnd ( pkt ) ) { state = IDLE ; return pioDelay ; } if ( isClockSet ( pkt ) ) { switch ( state ) { case RECEIVING_ADDR : if ( currBit >= 0 ) { message |= sda << currBit ; currBit -- ; } else { i2cAddr = message >> 1 ; assert ( devices . find ( i2cAddr ) != devices . end ( ) ) ; if ( message & 0x01 ) { state = SENDING_DATA ; message = devices [ i2cAddr ] -> read ( ) ; } else { state = RECEIVING_DATA ; message = 0x00 ; } currBit = 7 ; sda = 0 ; } break ; case RECEIVING_DATA : if ( currBit >= 0 ) { message |= sda << currBit ; currBit -- ; } else { devices [ i2cAddr ] -> write ( message ) ; message = 0x00 ; currBit = 7 ; sda = 0 ; } break ; case SENDING_DATA : if ( currBit >= 0 ) { sda = ( message >> currBit ) & 0x01 ; currBit -- ; } else { if ( ! sda ) message = devices [ i2cAddr ] -> read ( ) ; currBit = 7 ; } break ; case IDLE : default : panic ( " \n " ) ; break ; } } return pioDelay ; }
The default i2c bus driver used by the realview pbx board writes to
 this device one bit at a time.
The default i2c bus driver used by the realview pbx board writes to this device one bit at a time .
// Check if the bus master is starting a new transmission. /* Most i2c devices expect something special (e.g., command,
         * register address) in the first byte they receive so they
         * must be notified somehow that this is a new transmission.
         */ // Check if the bus master is ending a transmission. // Only change state when the clock is transitioning from low to high. // This may not perfectly mimic physical i2c devices but the important // part is to only do the following once per clock cycle. /* Ack */ /* Ack */ /* Check for ack from the bus master. */