summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-designware-core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 12:56:35 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 12:56:35 -0800
commit8600b697cd4787ac3ce053d48ca7301836fd0c55 (patch)
treeba0771e53ffb66b2c077b54f620d9bb78b43ba79 /drivers/i2c/busses/i2c-designware-core.c
parent0ab7b12c49b6fbf2d4d0381374b82935f949be5f (diff)
parent6eb89ef029fe22aee518a9dc75b9ee5d6ef9b3fe (diff)
Merge branch 'i2c/for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - the first series of making i2c_device_id optional instead of mandatory (in favor of alternatives like of_device_id). This involves adding a new probe callback (probe_new) which removes some peculiarities I2C had for a long time now. The new probe is matching the other subsystems now and the old one will be removed once all users are converted. It is expected to take a while but there is ongoing interest in that. - SMBus Host Notify introduced 4.9 got refactored. They are now using interrupts instead of the alert callback which solves multiple issues. - new drivers for iMX LowPower I2C, Mellanox CPLD and its I2C mux - significant refactoring for bcm2835 driver - the usual set of driver updates and improvements * 'i2c/for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (46 commits) i2c: fsl-lpi2c: read lpi2c fifo size in probe() i2c: octeon: thunderx: Remove double-check after interrupt i2c: octeon: thunderx: TWSI software reset in recovery i2c: cadence: Allow Cadence I2C to be selected for Cadence Xtensa CPUs i2c: sh_mobile: Add per-Generation fallback bindings i2c: rcar: Add per-Generation fallback bindings i2c: imx-lpi2c: add low power i2c bus driver dt-bindings: i2c: imx-lpi2c: add devicetree bindings i2c: designware-pcidrv: Add 10bit address feature to medfield/merrifield i2c: pxa: Add support for the I2C units found in Armada 3700 i2c: pxa: Add definition of fast and high speed modes via the regs layout dt-bindings: i2c: pxa: Update the documentation for the Armada 3700 i2c: qup: support SMBus block read i2c: qup: add ACPI support i2c: designware: Consolidate default functionality bits i2c: i2c-mux-gpio: update mux with gpiod_set_array_value_cansleep i2c: mux: pca954x: Add ACPI support for pca954x i2c: use an IRQ to report Host Notify events, not alert i2c: i801: remove SMBNTFDDAT reads as they always seem to return 0 i2c: i801: use the BIT() macro for FEATURES_* also ...
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-core.c')
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index b403fa5ecf49..6d81c56184d3 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -536,6 +536,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
intr_mask = DW_IC_INTR_DEFAULT_MASK;
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
+ u32 flags = msgs[dev->msg_write_idx].flags;
+
/*
* if target address has changed, we need to
* reprogram the target address in the i2c
@@ -581,8 +583,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
* detected from the registers so we set it always
* when writing/reading the last byte.
*/
+
+ /*
+ * i2c-core.c always sets the buffer length of
+ * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
+ * be adjusted when receiving the first byte.
+ * Thus we can't stop the transaction here.
+ */
if (dev->msg_write_idx == dev->msgs_num - 1 &&
- buf_len == 1)
+ buf_len == 1 && !(flags & I2C_M_RECV_LEN))
cmd |= BIT(9);
if (need_restart) {
@@ -607,7 +616,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
dev->tx_buf = buf;
dev->tx_buf_len = buf_len;
- if (buf_len > 0) {
+ /*
+ * Because we don't know the buffer length in the
+ * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
+ * the transaction here.
+ */
+ if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
/* more bytes to be written */
dev->status |= STATUS_WRITE_IN_PROGRESS;
break;
@@ -628,6 +642,24 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
}
+static u8
+i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 flags = msgs[dev->msg_read_idx].flags;
+
+ /*
+ * Adjust the buffer length and mask the flag
+ * after receiving the first byte.
+ */
+ len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
+ dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
+ msgs[dev->msg_read_idx].len = len;
+ msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
+
+ return len;
+}
+
static void
i2c_dw_read(struct dw_i2c_dev *dev)
{
@@ -652,7 +684,15 @@ i2c_dw_read(struct dw_i2c_dev *dev)
rx_valid = dw_readl(dev, DW_IC_RXFLR);
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
- *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+ u32 flags = msgs[dev->msg_read_idx].flags;
+
+ *buf = dw_readl(dev, DW_IC_DATA_CMD);
+ /* Ensure length byte is a valid value */
+ if (flags & I2C_M_RECV_LEN &&
+ *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
+ len = i2c_dw_recv_len(dev, *buf);
+ }
+ buf++;
dev->rx_outstanding--;
}