i2c: Add i2c block transaction support
The previous code always uses SMBus block read/write.
On some PSU (e.g. FP5280G2's PSU) the I2C block read/write is
required, so add that support.
Specifically, add a Mode enum class and add the parameter for block
read/write to indicate whether SMBus or I2C block read/write is to be
called.
Tested: Verify the code works on FP5280G2 with I2C block write.
Note: Currently there is no case for I2C block read, so that function is
not tested.
Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I5f77ffe6900d14f3703dae7241799a7b37c5a726
diff --git a/tools/i2c/i2c.cpp b/tools/i2c/i2c.cpp
index 76756be..624bc60 100644
--- a/tools/i2c/i2c.cpp
+++ b/tools/i2c/i2c.cpp
@@ -76,6 +76,13 @@
devAddr);
}
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
+ {
+ throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
+ busStr, devAddr);
+ }
+ break;
default:
fprintf(stderr, "Unexpected read size type: %d\n", type);
assert(false);
@@ -123,6 +130,13 @@
devAddr);
}
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
+ {
+ throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
+ busStr, devAddr);
+ }
+ break;
default:
fprintf(stderr, "Unexpected read size type: %d\n", type);
assert(false);
@@ -164,11 +178,25 @@
data = static_cast<uint16_t>(ret);
}
-void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data)
+void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
{
- checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
-
- int ret = i2c_smbus_read_block_data(fd, addr, data);
+ int ret;
+ switch (mode)
+ {
+ case Mode::SMBUS:
+ checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
+ ret = i2c_smbus_read_block_data(fd, addr, data);
+ break;
+ case Mode::I2C:
+ checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
+ ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
+ if (ret != size)
+ {
+ throw I2CException("Failed to read i2c block data", busStr,
+ devAddr, errno);
+ }
+ break;
+ }
if (ret < 0)
{
throw I2CException("Failed to read block data", busStr, devAddr, errno);
@@ -206,11 +234,22 @@
}
}
-void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data)
+void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
+ Mode mode)
{
- checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
-
- if (i2c_smbus_write_block_data(fd, addr, size, data) < 0)
+ int ret;
+ switch (mode)
+ {
+ case Mode::SMBUS:
+ checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
+ ret = i2c_smbus_write_block_data(fd, addr, size, data);
+ break;
+ case Mode::I2C:
+ checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
+ ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
+ break;
+ }
+ if (ret < 0)
{
throw I2CException("Failed to write block data", busStr, devAddr,
errno);
diff --git a/tools/i2c/i2c.hpp b/tools/i2c/i2c.hpp
index befeaba..05b02b5 100644
--- a/tools/i2c/i2c.hpp
+++ b/tools/i2c/i2c.hpp
@@ -79,8 +79,9 @@
/** @copydoc I2CInterface::read(uint8_t,uint16_t&) */
void read(uint8_t addr, uint16_t& data) override;
- /** @copydoc I2CInterface::read(uint8_t,uint8_t&,uint8_t*) */
- void read(uint8_t addr, uint8_t& size, uint8_t* data) override;
+ /** @copydoc I2CInterface::read(uint8_t,uint8_t&,uint8_t*,Mode) */
+ void read(uint8_t addr, uint8_t& size, uint8_t* data,
+ Mode mode = Mode::SMBUS) override;
/** @copydoc I2CInterface::write(uint8_t) */
void write(uint8_t data) override;
@@ -91,8 +92,9 @@
/** @copydoc I2CInterface::write(uint8_t,uint16_t) */
void write(uint8_t addr, uint16_t data) override;
- /** @copydoc I2CInterface::write(uint8_t,uint8_t,const uint8_t*) */
- void write(uint8_t addr, uint8_t size, const uint8_t* data) override;
+ /** @copydoc I2CInterface::write(uint8_t,uint8_t,const uint8_t*,Mode) */
+ void write(uint8_t addr, uint8_t size, const uint8_t* data,
+ Mode mode = Mode::SMBUS) override;
/** @brief Create an I2CInterface instance
*
diff --git a/tools/i2c/i2c_interface.hpp b/tools/i2c/i2c_interface.hpp
index ab12e32..152f1e9 100644
--- a/tools/i2c/i2c_interface.hpp
+++ b/tools/i2c/i2c_interface.hpp
@@ -47,6 +47,13 @@
public:
virtual ~I2CInterface() = default;
+ /** @brief The block transaction mode */
+ enum class Mode
+ {
+ SMBUS,
+ I2C,
+ };
+
/** @brief Read byte data from i2c
*
* @param[out] data - The data read from the i2c device
@@ -76,15 +83,22 @@
/** @brief Read block data from i2c
*
* @param[in] addr - The register address of the i2c device
- * @param[out] size - The size of data read from i2c device
+ * @param[in,out] size - The out parameter to indicate the size of data read
+ * from i2c device; when mode is I2C, it is also the
+ * input parameter to indicate how many bytes to read
* @param[out] data - The pointer to buffer to read from the i2c device,
* the buffer shall be big enough to hold the data
* returned by the device. SMBus allows at most 32
* bytes.
+ * @param[in] mode - The block read mode, either SMBus or I2C.
+ * Internally, it invokes functions from libi2c:
+ * * For SMBus: i2c_smbus_read_block_data()
+ * * For I2C: i2c_smbus_read_i2c_block_data()
*
* @throw I2CException on error
*/
- virtual void read(uint8_t addr, uint8_t& size, uint8_t* data) = 0;
+ virtual void read(uint8_t addr, uint8_t& size, uint8_t* data,
+ Mode mode = Mode::SMBUS) = 0;
/** @brief Write byte data to i2c
*
@@ -118,10 +132,15 @@
* @param[in] size - The size of data to write, SMBus allows at most 32
* bytes
* @param[in] data - The data to write to the i2c device
+ * @param[in] mode - The block write mode, either SMBus or I2C.
+ * Internally, it invokes functions from libi2c:
+ * * For SMBus: i2c_smbus_write_block_data()
+ * * For I2C: i2c_smbus_write_i2c_block_data()
*
* @throw I2CException on error
*/
- virtual void write(uint8_t addr, uint8_t size, const uint8_t* data) = 0;
+ virtual void write(uint8_t addr, uint8_t size, const uint8_t* data,
+ Mode mode = Mode::SMBUS) = 0;
};
/** @brief Create an I2CInterface instance
diff --git a/tools/i2c/test/mocked_i2c_interface.hpp b/tools/i2c/test/mocked_i2c_interface.hpp
index feb8f74..5bb0a3a 100644
--- a/tools/i2c/test/mocked_i2c_interface.hpp
+++ b/tools/i2c/test/mocked_i2c_interface.hpp
@@ -15,13 +15,15 @@
MOCK_METHOD(void, read, (uint8_t & data), (override));
MOCK_METHOD(void, read, (uint8_t addr, uint8_t& data), (override));
MOCK_METHOD(void, read, (uint8_t addr, uint16_t& data), (override));
- MOCK_METHOD(void, read, (uint8_t addr, uint8_t& size, uint8_t* data),
+ MOCK_METHOD(void, read,
+ (uint8_t addr, uint8_t& size, uint8_t* data, Mode mode),
(override));
MOCK_METHOD(void, write, (uint8_t data), (override));
MOCK_METHOD(void, write, (uint8_t addr, uint8_t data), (override));
MOCK_METHOD(void, write, (uint8_t addr, uint16_t data), (override));
- MOCK_METHOD(void, write, (uint8_t addr, uint8_t size, const uint8_t* data),
+ MOCK_METHOD(void, write,
+ (uint8_t addr, uint8_t size, const uint8_t* data, Mode mode),
(override));
};