diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-21 17:40:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-21 17:40:46 -0700 |
commit | 99cc7ad46b62ef20b0478147677bebd1157bd9cf (patch) | |
tree | f07f33826e6947108234707030867d969230611d /drivers/i2c/busses/i2c-gpio.c | |
parent | 0214f46b3a0383d6e33c297e7706216b6a550e4b (diff) | |
parent | 19358d4488db7e6a04e940730cc75909d7d1e0d8 (diff) |
Merge branch 'i2c/for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
- the core has now a lockless variant of i2c_smbus_xfer. Some open
coded versions of this got removed in drivers. This also enables
proper SCCB support in regmap.
- locking got a more precise naming. i2c_{un}lock_adapter() had to go,
and we know use i2c_lock_bus() consistently with flags like
I2C_LOCK_ROOT_ADAPTER and I2C_LOCK_SEGMENT to avoid ambiguity.
- the gpio fault injector got a new delicate testcase
- the bus recovery procedure got fixed to handle the new testcase
correctly
- a new quirk flag for controllers not able to handle zero length
messages together with driver updates to use it
- new drivers: FSI bus attached I2C masters, GENI I2C controller, Owl
family S900
- and a good set of driver improvements and bugfixes
* 'i2c/for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (77 commits)
i2c: rcar: implement STOP and REP_START according to docs
i2c: rcar: refactor private flags
i2c: core: ACPI: Make acpi_gsb_i2c_read_bytes() check i2c_transfer return value
i2c: core: ACPI: Properly set status byte to 0 for multi-byte writes
dt-bindings: i2c: rcar: Add r8a774a1 support
dt-bindings: i2c: sh_mobile: Add r8a774a1 support
i2c: imx: Simplify stopped state tracking
i2c: imx: Fix race condition in dma read
i2c: pasemi: remove hardcoded bus numbers on smbus
i2c: designware: Add SPDX license tag
i2c: designware: Convert to use struct i2c_timings
i2c: core: Parse SDA hold time from firmware
i2c: designware-pcidrv: Mark expected switch fall-through
i2c: amd8111: Mark expected switch fall-through
i2c: sh_mobile: use core to detect 'no zero length read' quirk
i2c: xlr: use core to detect 'no zero length' quirk
i2c: rcar: use core to detect 'no zero length' quirk
i2c: stu300: use core to detect 'no zero length' quirk
i2c: pmcmsp: use core to detect 'no zero length' quirk
i2c: mxs: use core to detect 'no zero length' quirk
...
Diffstat (limited to 'drivers/i2c/busses/i2c-gpio.c')
-rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 97 |
1 files changed, 63 insertions, 34 deletions
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 66f85bbf3591..c008d209f0b8 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -78,49 +78,43 @@ static struct dentry *i2c_gpio_debug_dir; #define getscl(bd) ((bd)->getscl((bd)->data)) #define WIRE_ATTRIBUTE(wire) \ -static int fops_##wire##_get(void *data, u64 *val) \ -{ \ - struct i2c_gpio_private_data *priv = data; \ - \ - i2c_lock_adapter(&priv->adap); \ - *val = get##wire(&priv->bit_data); \ - i2c_unlock_adapter(&priv->adap); \ - return 0; \ -} \ -static int fops_##wire##_set(void *data, u64 val) \ -{ \ - struct i2c_gpio_private_data *priv = data; \ - \ - i2c_lock_adapter(&priv->adap); \ - set##wire(&priv->bit_data, val); \ - i2c_unlock_adapter(&priv->adap); \ - return 0; \ -} \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") WIRE_ATTRIBUTE(scl); WIRE_ATTRIBUTE(sda); -static int fops_incomplete_transfer_set(void *data, u64 addr) +static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, + u32 pattern, u8 pattern_size) { - struct i2c_gpio_private_data *priv = data; struct i2c_algo_bit_data *bit_data = &priv->bit_data; - int i, pattern; + int i; - if (addr > 0x7f) - return -EINVAL; - - /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ - pattern = (addr << 2) | 3; - - i2c_lock_adapter(&priv->adap); + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); /* START condition */ setsda(bit_data, 0); udelay(bit_data->udelay); - /* Send ADDR+RD, request ACK, don't send STOP */ - for (i = 8; i >= 0; i--) { + /* Send pattern, request ACK, don't send STOP */ + for (i = pattern_size - 1; i >= 0; i--) { setscl(bit_data, 0); udelay(bit_data->udelay / 2); setsda(bit_data, (pattern >> i) & 1); @@ -129,11 +123,44 @@ static int fops_incomplete_transfer_set(void *data, u64 addr) udelay(bit_data->udelay); } - i2c_unlock_adapter(&priv->adap); + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); +} + +static int fops_incomplete_addr_phase_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_gpio_incomplete_transfer(priv, pattern, 9); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); + +static int fops_incomplete_write_byte_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ + pattern = (addr << 2) | 1; + /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (pattern << 9) | 1; + + i2c_gpio_incomplete_transfer(priv, pattern, 18); return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { @@ -156,8 +183,10 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); - debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, - priv, &fops_incomplete_transfer); + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + priv, &fops_incomplete_addr_phase); + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + priv, &fops_incomplete_write_byte); } static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) |