//============================================================================ /*! \file I2cDevice.cxx * \author S.Linev/GSI, SPI interface for SP605/SysCore3 * \author W.F.J.Mueller/GSI, based on earlier work of Norbert Abel/KIP */ //============================================================================ #include "roc/I2cDevice.h" #include #include "roc/defines_roc.h" #include "roc/defines_i2c.h" #include "roc/defines_spi.h" /*! * \class roc::I2cDevice * \brief Base class to represent a ROC I2C Bus Device. * * A ROC can have several I2C bus ports. They are served by a common control * logic, a switch determines which port is active at a given time. Each bus * can have several devices attached, identified by a slave address. * * The class holds the addressing information needed to reach the \c I2cDevice: * \li the ROC board pointer (in the base class) * \li the I2C bus port number * \li the I2C device slave address */ //---------------------------------------------------------------------------- //! Default constructor to make old ROOT hapy roc::I2cDevice::I2cDevice() : base::Peripheral(), fUseSPI(false), fPort(0), fSlaveAddr(0) { } //---------------------------------------------------------------------------- //! Constructor with full addressing path information. /*! * Sets up \c I2cDevice object with full addressing information * \param board ROC board pointer * \param port the I2C bus port number * \param addr the I2C device slave address */ roc::I2cDevice::I2cDevice(base::Board* board, int port, uint8_t addr) : base::Peripheral(board), fUseSPI(false), fPort(port), fSlaveAddr(addr) { if (board->is_SPI_I2C()) fUseSPI = true; } //---------------------------------------------------------------------------- roc::I2cDevice::~I2cDevice() { } //---------------------------------------------------------------------------- //! Write to device register with optional readback verification. /*! * Writes the 8bit value \a val to device register \a reg. If \a veri * is \c true, the register contents is read back and verified. * The I2C status is checked for error flags after the write and * optional read cycle. * * \param reg device register number * \param val value * \param veri if \c true readback verification done (default is \c false) * \returns see \ref roc_board_opererr * * \sa getRegister(), setRegisterVerify() */ int roc::I2cDevice::setRegister(uint8_t reg, uint8_t val, bool veri) { bool isput[7]; uint32_t addr[7]; uint32_t data[7]; int rc; if (isSPI()) { isput[0] = true; addr[0] = ROC_SPI_COMMAND; data[0] = 0x20; isput[1] = true; addr[1] = ROC_SPI_TXDATA; data[1] = (0x1 << 24) | (fSlaveAddr << 16) | (reg << 8) | val; isput[2] = true; addr[2] = ROC_SPI_TRANSMIT; data[2] = 0x1; isput[3] = false; addr[3] = ROC_SPI_RXDATA; data[3] = 0x0; isput[4] = false; addr[4] = ROC_SPI_MASTER_STATUS; data[4] = 0x0; int nop = 5; rc = board().operGen(isput, addr, data, nop); if (rc==0) { if ((data[3] & 0xff00) != 0x2000) { printf("SPI-I2C RXDATA error\n"); rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } if ((data[4] & 1) != 1) { printf("SPI-I2C MASTER_STATUS CRC-error\n"); rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } } } else { isput[0] = true; addr[0] = ROC_NX_I2C_SWITCH; data[0] = fPort; isput[1] = true; addr[1] = ROC_NX_I2C_SLAVEADDR; data[1] = fSlaveAddr; isput[2] = true; addr[2] = ROC_NX_I2C_REGISTER; data[2] = reg; isput[3] = true; addr[3] = ROC_NX_I2C_DATA; data[3] = val; isput[4] = false; addr[4] = ROC_NX_I2C_ERROR; isput[5] = false; addr[5] = ROC_NX_I2C_DATA; isput[6] = false; addr[6] = ROC_NX_I2C_ERROR; int nop = veri ? 7 : 5; rc = board().operGen(isput, addr, data, nop); if ((rc == 0) && (data[4] != 0)) { // check I2C bus error on put rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } if (veri) { if (rc == 0 && data[6] != 0) { // check I2C bus error on readback rc = base::Board::operErrBuild(base::Board::kOperBusErr, 1); } if (rc == 0 && val != (data[5]&0xff)) { // check readback value rc = base::Board::kOperVerifyErr; } } } return rc; } //---------------------------------------------------------------------------- //! Read 8 bit from device register. /*! * Reads an 8bit value from device register \a reg and checks * I2C status for error flags. * * \param reg device register number * \param val value * \returns see \ref roc_board_opererr * * \sa setRegister() */ int roc::I2cDevice::getRegister(uint8_t reg, uint8_t& val) { bool isput[5]; uint32_t addr[5]; uint32_t data[5]; int rc; if (isSPI()) { isput[0] = true; addr[0] = ROC_SPI_COMMAND; data[0] = 0x30; isput[1] = true; addr[1] = ROC_SPI_TXDATA; data[1] = (0x1 << 24) | (fSlaveAddr << 16) | (reg << 8) | 0; isput[2] = true; addr[2] = ROC_SPI_TRANSMIT; data[2] = 0x1; isput[3] = false; addr[3] = ROC_SPI_RXDATA; data[3] = 0x0; isput[4] = false; addr[4] = ROC_SPI_MASTER_STATUS; data[4] = 0x0; int nop = 5; rc = board().operGen(isput, addr, data, nop); printf("Get I2C register %u\n", reg); if (rc==0) { val = data[3] & 0xff; if ((data[3] & 0xff00) != 0x3000) { printf("SPI-I2C error\n"); rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } if ((data[4] & 1) != 1) { printf("SPI-I2C CRC-error\n"); rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } } return rc; } isput[0] = true; addr[0] = ROC_NX_I2C_SWITCH; data[0] = fPort; isput[1] = true; addr[1] = ROC_NX_I2C_SLAVEADDR; data[1] = fSlaveAddr; isput[2] = true; addr[2] = ROC_NX_I2C_REGISTER; data[2] = reg; isput[3] = false; addr[3] = ROC_NX_I2C_DATA; isput[4] = false; addr[4] = ROC_NX_I2C_ERROR; rc = board().operGen(isput, addr, data, 5); val = uint8_t(data[3]); if (rc == 0 && data[4] != 0) { // check I2C bus error on get rc = base::Board::kOperBusErr; } return rc; } //---------------------------------------------------------------------------- //! Read 16 bit from device register. /*! * Reads an 16bit value from device register \a reg and checks * I2C status for error flags. * * \param reg device register number * \param val value * \returns see \ref roc_board_opererr * */ int roc::I2cDevice::getRegister16(uint8_t reg, uint16_t& val) { if (isSPI()) { printf("No 16-bit read operations for SPI-I2C interface\n"); return 1; } bool isput[7]; uint32_t addr[7]; uint32_t data[7]; int rc; isput[0] = true; addr[0] = ROC_NX_I2C_SWITCH; data[0] = fPort; isput[1] = true; addr[1] = ROC_NX_I2C_SLAVEADDR; data[1] = fSlaveAddr; isput[2] = true; addr[2] = ROC_NX_I2C_REGISTER; data[2] = reg; isput[3] = true; addr[3] = ROC_NX_I2C_READ16; data[3] = 1; isput[4] = false; addr[4] = ROC_NX_I2C_DATA; isput[5] = false; addr[5] = ROC_NX_I2C_ERROR; isput[6] = true; addr[6] = ROC_NX_I2C_READ16; data[6] = 0; rc = board().operGen(isput, addr, data, 7); val = uint16_t(data[4]); if (rc == 0 && data[5] != 0) { // check I2C bus error on get rc = base::Board::kOperBusErr; } return rc; } //---------------------------------------------------------------------------- //! Write to device register and return the readback value. /*! * Writes the 8bit value \a valset to device register \a reg, reads * it back and returns the readback value in \a valget. * The I2C status is checked for error flags after the write and read cycle. * * \param reg device register number * \param valset value to be written * \param valget value returned from readback * \returns see \ref roc_board_opererr * * \note The method just returns the readback value and does not test whether * \a valget equals \a valset, thus never returns a base::Board::kOperVerifyErr * return code. * * \sa setRegister(), getRegister() */ int roc::I2cDevice::setRegisterVerify(uint8_t reg, uint8_t valset, uint8_t& valget) { if (isSPI()) { valget = valset; return setRegister(reg, valset, true); } bool isput[7]; uint32_t addr[7]; uint32_t data[7]; int rc; isput[0] = true; addr[0] = ROC_NX_I2C_SWITCH; data[0] = fPort; isput[1] = true; addr[1] = ROC_NX_I2C_SLAVEADDR; data[1] = fSlaveAddr; isput[2] = true; addr[2] = ROC_NX_I2C_REGISTER; data[2] = reg; isput[3] = true; addr[3] = ROC_NX_I2C_DATA; data[3] = valset; isput[4] = false; addr[4] = ROC_NX_I2C_ERROR; isput[5] = false; addr[5] = ROC_NX_I2C_DATA; isput[6] = false; addr[6] = ROC_NX_I2C_ERROR; rc = board().operGen(isput, addr, data, 7); valget = uint8_t(data[5]); if (rc == 0 && data[4] != 0) { // check I2C bus error on put rc = base::Board::operErrBuild(base::Board::kOperBusErr, 0); } if (rc == 0 && data[6] != 0) { // check I2C bus error on readback rc = base::Board::operErrBuild(base::Board::kOperBusErr, 1); } return rc; } //---------------------------------------------------------------------------- //! Write to device register array with optional readback verification. /*! * Writes the \a nreg 8bit values from array \a val to an array of device * registers starting at register number \a reg. When \a veri is \c true, * each value is readback and verified. * The I2C error flags are checked for each transfer, writing is stopped * when the first error is detected. * * \param reg first device register number * \param val value array * \param nreg number of registers to write * \param veri if \c true readback verification done (default is \c false) * \returns see \ref roc_board_opererr * * \sa getRegisterArray() */ int roc::I2cDevice::setRegisterArray(uint8_t reg, const uint8_t *val, int nreg, bool veri) { for (int i=0; iis_SPI_I2C()) { board->addRegAddrMapping("ROC_SPI_COMMAND", ROC_SPI_COMMAND); board->addRegAddrMapping("ROC_SPI_TXDATA", ROC_SPI_TXDATA); board->addRegAddrMapping("ROC_SPI_TRANSMIT", ROC_SPI_TRANSMIT); board->addRegAddrMapping("ROC_SPI_RXDATA", ROC_SPI_RXDATA); board->addRegAddrMapping("ROC_SPI_MASTER_STATUS", ROC_SPI_MASTER_STATUS); } else { board->addRegAddrMapping("ROC_NX_I2C_DATA", ROC_NX_I2C_DATA); board->addRegAddrMapping("ROC_NX_I2C_SLAVEADDR", ROC_NX_I2C_SLAVEADDR); board->addRegAddrMapping("ROC_NX_I2C_REGISTER", ROC_NX_I2C_REGISTER); board->addRegAddrMapping("ROC_NX_I2C_ERROR", ROC_NX_I2C_ERROR); board->addRegAddrMapping("ROC_NX_I2C_SWITCH", ROC_NX_I2C_SWITCH); board->addRegAddrMapping("ROC_NX_I2C_READ16", ROC_NX_I2C_READ16); } } //----------------------------------------------------------------------------