summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@chromium.org>2019-12-08 13:13:09 -0700
committerCommit Bot <commit-bot@chromium.org>2020-12-23 16:20:54 +0000
commitecbc0440b48b4fe2c5ddc483eda982d29b6bc665 (patch)
treeda99d8b919dcabea04284d46db6b854ee3f26490
parent61502a458f6801080b0e4ee3bdea42ded4dd8dab (diff)
downloadchrome-ec-ecbc0440b48b4fe2c5ddc483eda982d29b6bc665.tar.gz
i2c: add generic read/modify/write operations
i2c_update is used to set or clear a mask i2c_field_update is used to clear out a field before the set BUG=none BRANCH=none TEST=make buildall -j Change-Id: I7f8f93f4894fb9635092931a93961d328eacfeb9 Signed-off-by: Denis Brockus <dbrockus@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1956437 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Commit-Queue: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2600800 Tested-by: David Huang <david.huang@quanta.corp-partner.google.com> Auto-Submit: David Huang <david.huang@quanta.corp-partner.google.com>
-rw-r--r--common/i2c_master.c86
-rw-r--r--include/i2c.h51
2 files changed, 137 insertions, 0 deletions
diff --git a/common/i2c_master.c b/common/i2c_master.c
index c6d9d3db25..ec906f94d9 100644
--- a/common/i2c_master.c
+++ b/common/i2c_master.c
@@ -431,6 +431,92 @@ int i2c_write_offset16_block(const int port,
return rv;
}
+int i2c_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t mask,
+ const enum mask_update_action action)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read8(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (action == MASK_SET) ? oldval | mask
+ : oldval & ~mask;
+
+ if (val != oldval)
+ return i2c_write8(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t mask,
+ const enum mask_update_action action)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read16(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (action == MASK_SET) ? oldval | mask
+ : oldval & ~mask;
+
+ if (val != oldval)
+ return i2c_write16(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_field_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t field_mask,
+ const uint8_t set_value)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read8(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (oldval & (~field_mask)) | set_value;
+
+ if (val != oldval)
+ return i2c_write8(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_field_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t field_mask,
+ const uint16_t set_value)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read16(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (oldval & (~field_mask)) | set_value;
+
+ if (val != oldval)
+ return i2c_write16(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
int i2c_read_string(const int port,
const uint16_t slave_addr_flags,
int offset, uint8_t *data, int len)
diff --git a/include/i2c.h b/include/i2c.h
index f1868dc8c8..805254e738 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -69,6 +69,16 @@ enum i2c_freq {
I2C_FREQ_COUNT,
};
+/*
+ * I2C mask update actions.
+ * MASK_SET will OR the mask into the old value
+ * MASK_CLR will AND the ~mask from the old value
+ */
+enum mask_update_action {
+ MASK_CLR,
+ MASK_SET
+};
+
struct i2c_info_t {
uint16_t port; /* Physical port for device */
uint16_t addr_flags;
@@ -359,6 +369,47 @@ int i2c_write_offset16_block(const int port,
uint16_t offset, const uint8_t *data, int len);
/**
+ * Read, modify, write an i2c register to the slave at 7-bit slave address
+ * <slave_addr_flags>, at the specified 8-bit <offset> in the slave's
+ * address space. The <action> will specify whether this is setting the
+ * <mask> bit value(s) or clearing them. If the value to be written is the
+ * same as the original value of the register, the write will not be
+ * performed.
+ */
+int i2c_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t mask,
+ const enum mask_update_action action);
+
+int i2c_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t mask,
+ const enum mask_update_action action);
+
+/**
+ * Read, modify, write field of an i2c register to the slave at 7-bit
+ * slave address <slave_addr_flags>, at the specified 8-bit <offset> in
+ * the slave's address space. The register will be read, the <field_mask>
+ * will be cleared and then the <set_value> will be set. The field mask
+ * and the set value do not have to be in the same bit locations. If the
+ * new value is not the same as the original value, the new value will be
+ * written back out to the device, otherwise no write will be performed.
+ */
+int i2c_field_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t field_mask,
+ const uint8_t set_value);
+
+int i2c_field_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t field_mask,
+ const uint16_t set_value);
+
+/**
* @return non-zero if i2c bus is busy
*/
int i2c_is_busy(int port);