From 7d5cb45655f2e9e37ef75d18f50c0072ef14a38b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 20 Sep 2017 01:02:27 -0400 Subject: i2c compat ioctls: move to ->compat_ioctl() Signed-off-by: Al Viro --- drivers/i2c/i2c-dev.c | 268 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 180 insertions(+), 88 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6f638bbc922d..2cab27a68479 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -35,6 +35,7 @@ #include #include #include +#include /* * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a @@ -238,46 +239,29 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) } static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, - unsigned long arg) + unsigned nmsgs, struct i2c_msg *msgs) { - struct i2c_rdwr_ioctl_data rdwr_arg; - struct i2c_msg *rdwr_pa; u8 __user **data_ptrs; int i, res; - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __user *)arg, - sizeof(rdwr_arg))) - return -EFAULT; - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) - return -EINVAL; - - rdwr_pa = memdup_user(rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg)); - if (IS_ERR(rdwr_pa)) - return PTR_ERR(rdwr_pa); - - data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); + data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { - kfree(rdwr_pa); + kfree(msgs); return -ENOMEM; } res = 0; - for (i = 0; i < rdwr_arg.nmsgs; i++) { + for (i = 0; i < nmsgs; i++) { /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + if (msgs[i].len > 8192) { res = -EINVAL; break; } - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; - rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); - if (IS_ERR(rdwr_pa[i].buf)) { - res = PTR_ERR(rdwr_pa[i].buf); + data_ptrs[i] = (u8 __user *)msgs[i].buf; + msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len); + if (IS_ERR(msgs[i].buf)) { + res = PTR_ERR(msgs[i].buf); break; } @@ -292,121 +276,117 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, * greater (for example to account for a checksum byte at * the end of the message.) */ - if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { - if (!(rdwr_pa[i].flags & I2C_M_RD) || - rdwr_pa[i].buf[0] < 1 || - rdwr_pa[i].len < rdwr_pa[i].buf[0] + + if (msgs[i].flags & I2C_M_RECV_LEN) { + if (!(msgs[i].flags & I2C_M_RD) || + msgs[i].buf[0] < 1 || + msgs[i].len < msgs[i].buf[0] + I2C_SMBUS_BLOCK_MAX) { res = -EINVAL; break; } - rdwr_pa[i].len = rdwr_pa[i].buf[0]; + msgs[i].len = msgs[i].buf[0]; } } if (res < 0) { int j; for (j = 0; j < i; ++j) - kfree(rdwr_pa[j].buf); + kfree(msgs[j].buf); kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } - res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); + res = i2c_transfer(client->adapter, msgs, nmsgs); while (i-- > 0) { - if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { - if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, - rdwr_pa[i].len)) + if (res >= 0 && (msgs[i].flags & I2C_M_RD)) { + if (copy_to_user(data_ptrs[i], msgs[i].buf, + msgs[i].len)) res = -EFAULT; } - kfree(rdwr_pa[i].buf); + kfree(msgs[i].buf); } kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, - unsigned long arg) + u8 read_write, u8 command, u32 size, + union i2c_smbus_data __user *data) { - struct i2c_smbus_ioctl_data data_arg; union i2c_smbus_data temp = {}; int datasize, res; - if (copy_from_user(&data_arg, - (struct i2c_smbus_ioctl_data __user *) arg, - sizeof(struct i2c_smbus_ioctl_data))) - return -EFAULT; - if ((data_arg.size != I2C_SMBUS_BYTE) && - (data_arg.size != I2C_SMBUS_QUICK) && - (data_arg.size != I2C_SMBUS_BYTE_DATA) && - (data_arg.size != I2C_SMBUS_WORD_DATA) && - (data_arg.size != I2C_SMBUS_PROC_CALL) && - (data_arg.size != I2C_SMBUS_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { + if ((size != I2C_SMBUS_BYTE) && + (size != I2C_SMBUS_QUICK) && + (size != I2C_SMBUS_BYTE_DATA) && + (size != I2C_SMBUS_WORD_DATA) && + (size != I2C_SMBUS_PROC_CALL) && + (size != I2C_SMBUS_BLOCK_DATA) && + (size != I2C_SMBUS_I2C_BLOCK_BROKEN) && + (size != I2C_SMBUS_I2C_BLOCK_DATA) && + (size != I2C_SMBUS_BLOCK_PROC_CALL)) { dev_dbg(&client->adapter->dev, "size out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.size); + size); return -EINVAL; } /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, so the check is valid if size==I2C_SMBUS_QUICK too. */ - if ((data_arg.read_write != I2C_SMBUS_READ) && - (data_arg.read_write != I2C_SMBUS_WRITE)) { + if ((read_write != I2C_SMBUS_READ) && + (read_write != I2C_SMBUS_WRITE)) { dev_dbg(&client->adapter->dev, "read_write out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.read_write); + read_write); return -EINVAL; } /* Note that command values are always valid! */ - if ((data_arg.size == I2C_SMBUS_QUICK) || - ((data_arg.size == I2C_SMBUS_BYTE) && - (data_arg.read_write == I2C_SMBUS_WRITE))) + if ((size == I2C_SMBUS_QUICK) || + ((size == I2C_SMBUS_BYTE) && + (read_write == I2C_SMBUS_WRITE))) /* These are special: we do not use data */ return i2c_smbus_xfer(client->adapter, client->addr, - client->flags, data_arg.read_write, - data_arg.command, data_arg.size, NULL); + client->flags, read_write, + command, size, NULL); - if (data_arg.data == NULL) { + if (data == NULL) { dev_dbg(&client->adapter->dev, "data is NULL pointer in ioctl I2C_SMBUS.\n"); return -EINVAL; } - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || - (data_arg.size == I2C_SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || - (data_arg.size == I2C_SMBUS_PROC_CALL)) - datasize = sizeof(data_arg.data->word); + if ((size == I2C_SMBUS_BYTE_DATA) || + (size == I2C_SMBUS_BYTE)) + datasize = sizeof(data->byte); + else if ((size == I2C_SMBUS_WORD_DATA) || + (size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data->word); else /* size == smbus block, i2c block, or block proc. call */ - datasize = sizeof(data_arg.data->block); + datasize = sizeof(data->block); - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || - (data_arg.read_write == I2C_SMBUS_WRITE)) { - if (copy_from_user(&temp, data_arg.data, datasize)) + if ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (size == I2C_SMBUS_I2C_BLOCK_DATA) || + (read_write == I2C_SMBUS_WRITE)) { + if (copy_from_user(&temp, data, datasize)) return -EFAULT; } - if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { + if (size == I2C_SMBUS_I2C_BLOCK_BROKEN) { /* Convert old I2C block commands to the new convention. This preserves binary compatibility. */ - data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; - if (data_arg.read_write == I2C_SMBUS_READ) + size = I2C_SMBUS_I2C_BLOCK_DATA; + if (read_write == I2C_SMBUS_READ) temp.block[0] = I2C_SMBUS_BLOCK_MAX; } res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - data_arg.read_write, data_arg.command, data_arg.size, &temp); - if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) { - if (copy_to_user(data_arg.data, &temp, datasize)) + read_write, command, size, &temp); + if (!res && ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (read_write == I2C_SMBUS_READ))) { + if (copy_to_user(data, &temp, datasize)) return -EFAULT; } return res; @@ -454,12 +434,39 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) funcs = i2c_get_functionality(client->adapter); return put_user(funcs, (unsigned long __user *)arg); - case I2C_RDWR: - return i2cdev_ioctl_rdwr(client, arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data rdwr_arg; + struct i2c_msg *rdwr_pa; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; - case I2C_SMBUS: - return i2cdev_ioctl_smbus(client, arg); + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data data_arg; + if (copy_from_user(&data_arg, + (struct i2c_smbus_ioctl_data __user *) arg, + sizeof(struct i2c_smbus_ioctl_data))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data_arg.read_write, + data_arg.command, + data_arg.size, + data_arg.data); + } case I2C_RETRIES: client->adapter->retries = arg; break; @@ -480,6 +487,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +#ifdef CONFIG_COMPAT + +struct i2c_smbus_ioctl_data32 { + u8 read_write; + u8 command; + u32 size; + compat_caddr_t data; /* union i2c_smbus_data *data */ +}; + +struct i2c_msg32 { + u16 addr; + u16 flags; + u16 len; + compat_caddr_t buf; +}; + +struct i2c_rdwr_ioctl_data32 { + compat_caddr_t msgs; /* struct i2c_msg __user *msgs */ + u32 nmsgs; +}; + +static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = file->private_data; + unsigned long funcs; + switch (cmd) { + case I2C_FUNCS: + funcs = i2c_get_functionality(client->adapter); + return put_user(funcs, (compat_ulong_t __user *)arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data32 rdwr_arg; + struct i2c_msg32 *p; + struct i2c_msg *rdwr_pa; + int i; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data32 __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; + + rdwr_pa = kmalloc_array(rdwr_arg.nmsgs, sizeof(struct i2c_msg), + GFP_KERNEL); + if (!rdwr_pa) + return -ENOMEM; + + p = compat_ptr(rdwr_arg.msgs); + for (i = 0; i < rdwr_arg.nmsgs; i++) { + struct i2c_msg32 umsg; + if (copy_from_user(&umsg, p + i, sizeof(umsg))) { + kfree(rdwr_pa); + return -EFAULT; + } + rdwr_pa[i] = (struct i2c_msg) { + .addr = umsg.addr, + .flags = umsg.flags, + .len = umsg.len, + .buf = compat_ptr(umsg.buf) + }; + } + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data32 data32; + if (copy_from_user(&data32, + (void __user *) arg, + sizeof(data32))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data32.read_write, + data32.command, + data32.size, + compat_ptr(data32.data)); + } + default: + return i2cdev_ioctl(file, cmd, arg); + } +} +#else +#define compat_i2cdev_ioctl NULL +#endif + static int i2cdev_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); @@ -527,6 +618,7 @@ static const struct file_operations i2cdev_fops = { .read = i2cdev_read, .write = i2cdev_write, .unlocked_ioctl = i2cdev_ioctl, + .compat_ioctl = compat_i2cdev_ioctl, .open = i2cdev_open, .release = i2cdev_release, }; -- cgit v1.2.3-55-g7522 From 126dbc6b49c8670ebe78174c159520d5993b4459 Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Mon, 25 Sep 2017 23:10:06 +0200 Subject: PM: i2c-designware-platdrv: Clean up PM handling in probe The power management handling in dw_i2c_plat_probe() is somewhat messy and it is rather hard to figure out the code intention for the case when pm_disabled is set. In that case, the driver doesn't enable runtime PM at all, but in addition to that it calls pm_runtime_forbid() as though it wasn't sure if runtime PM might be enabled for the device later by someone else. Although that concern doesn't seem to be actually valid, the device is clearly still expected to be PM-capable even in the pm_disabled set case, so a better approach would be to enable runtime PM for it unconditionally and prevent it from being runtime-suspended by using pm_runtime_get_noresume(). Make the driver do that. Signed-off-by: Rafael J. Wysocki Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 34 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0e65b97842b4..532e5a6e8512 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -249,6 +249,14 @@ static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) } } +static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) +{ + pm_runtime_disable(dev->dev); + + if (dev->pm_disabled) + pm_runtime_put_noidle(dev->dev); +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -362,14 +370,17 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - if (dev->pm_disabled) { - pm_runtime_forbid(&pdev->dev); - } else { - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - } + /* The code below assumes runtime PM to be disabled. */ + WARN_ON(pm_runtime_enabled(&pdev->dev)); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + + if (dev->pm_disabled) + pm_runtime_get_noresume(&pdev->dev); + + pm_runtime_enable(&pdev->dev); if (dev->mode == DW_IC_SLAVE) ret = i2c_dw_probe_slave(dev); @@ -382,8 +393,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) return ret; exit_probe: - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); exit_reset: if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -402,8 +412,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); + if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); -- cgit v1.2.3-55-g7522 From 541527728341b4bb9a5e3428b0eec450f1b3d8d5 Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Mon, 25 Sep 2017 01:30:51 +0200 Subject: PM: i2c-designware-platdrv: Suspend/resume at the late/early stages As reported by Rajat Jain, there are problems when ACPI operation region handlers or similar, called at the ->resume_early() time, for I2C client devices try to access an I2C controller that has already been suspended at that point. To avoid that, move the suspend/resume of i2c-designware-platdrv to the late/early stages, respectively. While at it, avoid resuming the device from runtime suspend in the driver's ->suspend callback which isn't particularly nice. [A better approach would be to make the driver track the PM state of the device so that it doesn't need to resume it in ->suspend, so implement it.] First, drop dw_i2c_plat_suspend() added by commit a23318feeff6 (i2c: designware: Fix system suspend) and rename dw_i2c_plat_runtime_suspend() back to dw_i2c_plat_suspend(). Second, point the driver's ->late_suspend and ->early_resume callbacks, rather than its ->suspend and ->resume callbacks, to dw_i2c_plat_suspend() and dw_i2c_plat_resume(), respectively, so that they are not executed in parallel with each other, for example if runtime resume of the device takes place during system suspend. Finally, add "suspended" and "skip_resume" flags to struct dw_i2c_dev and make dw_i2c_plat_suspend() and dw_i2c_plat_resume() use them to avoid suspending or resuming the device twice in a row and to avoid resuming a previously runtime-suspended device during system resume. Signed-off-by: Rafael J. Wysocki Tested-by: Jarkko Nikula Tested-by: Mika Westerberg Tested-by: Johannes Stezenbach Tested-by: Rajat Jain Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.h | 2 ++ drivers/i2c/busses/i2c-designware-platdrv.c | 33 +++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9fee4c054d3d..21bf619a86c5 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -280,6 +280,8 @@ struct dw_i2c_dev { int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_disabled; + bool suspended; + bool skip_resume; void (*disable)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 532e5a6e8512..16c027b62a20 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -447,13 +447,20 @@ static void dw_i2c_plat_complete(struct device *dev) #endif #ifdef CONFIG_PM -static int dw_i2c_plat_runtime_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + if (i_dev->suspended) { + i_dev->skip_resume = true; + return 0; + } + i_dev->disable(i_dev); i2c_dw_plat_prepare_clk(i_dev, false); + i_dev->suspended = true; + return 0; } @@ -461,27 +468,27 @@ static int dw_i2c_plat_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + if (!i_dev->suspended) + return 0; + + if (i_dev->skip_resume) { + i_dev->skip_resume = false; + return 0; + } + i2c_dw_plat_prepare_clk(i_dev, true); i_dev->init(i_dev); - return 0; -} + i_dev->suspended = false; -#ifdef CONFIG_PM_SLEEP -static int dw_i2c_plat_suspend(struct device *dev) -{ - pm_runtime_resume(dev); - return dw_i2c_plat_runtime_suspend(dev); + return 0; } -#endif static const struct dev_pm_ops dw_i2c_dev_pm_ops = { .prepare = dw_i2c_plat_prepare, .complete = dw_i2c_plat_complete, - SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, - dw_i2c_plat_resume, - NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL) }; #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) -- cgit v1.2.3-55-g7522 From 17f88151ff190b9357f473d7704eee7ae3097d11 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Mon, 11 Sep 2017 15:11:44 -0500 Subject: i2c: davinci: Add PM Runtime Support 66AK2G has I2C instances that are not apart of the ALWAYS_ON power domain unlike other Keystone 2 SoCs and OMAPL138. Therefore, pm_runtime is required to insure the power domain used by the specific I2C instance is properly turned on along with its functional clock. Signed-off-by: Franklin S Cooper Jr Acked-by: Sekhar Nori Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 67 +++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index b8c43535f16c..a2d9f7c56dac 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -36,6 +36,7 @@ #include #include #include +#include /* ----- global defines ----------------------------------------------- */ @@ -122,6 +123,9 @@ /* set the SDA GPIO low */ #define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) +/* timeout for pm runtime autosuspend */ +#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */ + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -541,10 +545,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret); + pm_runtime_put_noidle(dev->dev); + return ret; + } + ret = i2c_davinci_wait_bus_not_busy(dev); if (ret < 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return ret; + goto out; } for (i = 0; i < num; i++) { @@ -552,14 +563,19 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num, ret); if (ret < 0) - return ret; + goto out; } + ret = num; #ifdef CONFIG_CPU_FREQ complete(&dev->xfr_complete); #endif - return num; +out: + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + return ret; } static u32 i2c_davinci_func(struct i2c_adapter *adap) @@ -599,6 +615,9 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) int count = 0; u16 w; + if (pm_runtime_suspended(dev->dev)) + return IRQ_NONE; + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); if (count++ == 100) { @@ -802,13 +821,24 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); - clk_prepare_enable(dev->clk); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) { - r = PTR_ERR(dev->base); - goto err_unuse_clocks; + return PTR_ERR(dev->base); + } + + pm_runtime_set_autosuspend_delay(dev->dev, + DAVINCI_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(dev->dev); + + pm_runtime_enable(dev->dev); + + r = pm_runtime_get_sync(dev->dev); + if (r < 0) { + dev_err(dev->dev, "failed to runtime_get device: %d\n", r); + pm_runtime_put_noidle(dev->dev); + return r; } i2c_davinci_init(dev); @@ -849,27 +879,40 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (r) goto err_unuse_clocks; + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + return 0; err_unuse_clocks: - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return r; } static int davinci_i2c_remove(struct platform_device *pdev) { struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + int ret; i2c_davinci_cpufreq_deregister(dev); i2c_del_adapter(&dev->adapter); - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + return ret; + } davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return 0; } @@ -880,7 +923,6 @@ static int davinci_i2c_suspend(struct device *dev) /* put I2C into reset */ davinci_i2c_reset_ctrl(i2c_dev, 0); - clk_disable_unprepare(i2c_dev->clk); return 0; } @@ -889,7 +931,6 @@ static int davinci_i2c_resume(struct device *dev) { struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev); - clk_prepare_enable(i2c_dev->clk); /* take I2C out of reset */ davinci_i2c_reset_ctrl(i2c_dev, 1); @@ -899,6 +940,8 @@ static int davinci_i2c_resume(struct device *dev) static const struct dev_pm_ops davinci_i2c_pm = { .suspend = davinci_i2c_suspend, .resume = davinci_i2c_resume, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; #define davinci_i2c_pm_ops (&davinci_i2c_pm) -- cgit v1.2.3-55-g7522 From 4ce8e88f6c25469b83a7d56914995fe892d1f9a8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 21 Sep 2017 23:30:07 +0100 Subject: i2c: designware: make const array supported_speeds static to shink object code size Don't populate const array supported_speeds on the stack, instead make it static. Makes the object code smaller by 150 bytes: Before: text data bss dec hex filename 8474 1440 0 9914 26ba i2c-designware-platdrv.o After: text data bss dec hex filename 8324 1440 0 9764 2624 i2c-designware-platdrv.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 16c027b62a20..58add69a441c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -265,7 +265,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) u32 acpi_speed, ht = 0; struct resource *mem; int i, irq, ret; - const int supported_speeds[] = { 0, 100000, 400000, 1000000, 3400000 }; + static const int supported_speeds[] = { + 0, 100000, 400000, 1000000, 3400000 + }; irq = platform_get_irq(pdev, 0); if (irq < 0) -- cgit v1.2.3-55-g7522 From c347b8fc22b21899154cc153a4951aaf226b4e1a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 10 Oct 2017 11:57:55 +0530 Subject: i2c: xlp9xx: Get clock frequency with clk API Get the input clock frequency to the controller from the linux clk API, if it is available. This allows us to pass in the block input frequency either from ACPI (using APD) or from device tree. The old hardcoded frequency is used as default for backwards compatibility. Signed-off-by: Jayachandran C Signed-off-by: Kamlakant Patel Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 6b106e94bc09..f0bef2d5306c 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -84,6 +85,7 @@ struct xlp9xx_i2c_dev { u32 __iomem *base; u32 msg_buf_remaining; u32 msg_len; + u32 ip_clk_hz; u32 clk_hz; u32 msg_err; u8 *msg_buf; @@ -213,7 +215,7 @@ static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) * The controller uses 5 * SCL clock internally. * So prescale value should be divided by 5. */ - prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); + prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz); prescale = ((prescale - 8) / 5) - 1; xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | @@ -342,9 +344,19 @@ static const struct i2c_algorithm xlp9xx_i2c_algo = { static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, struct xlp9xx_i2c_dev *priv) { + struct clk *clk; u32 freq; int err; + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ; + dev_dbg(&pdev->dev, "using default input frequency %u\n", + priv->ip_clk_hz); + } else { + priv->ip_clk_hz = clk_get_rate(clk); + } + err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); if (err) { freq = XLP9XX_I2C_DEFAULT_FREQ; -- cgit v1.2.3-55-g7522 From 5515ae112172e20667f02b16f45fbf992923dcb0 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Tue, 10 Oct 2017 11:57:56 +0530 Subject: i2c: xlp9xx: Handle I2C_M_RECV_LEN in msg->flags The driver needs to handle the flag I2C_M_RECV_LEN during receive to support SMBus emulation. Update receive logic to handle the case where the length is received as the first byte of a transaction. Also update the code to handle I2C_CLIENT_PEC, which is set when the client sends a packet error checking code byte. Signed-off-by: Jayachandran C Signed-off-by: Kamlakant Patel Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index f0bef2d5306c..b970bf8f38e5 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -82,6 +82,8 @@ struct xlp9xx_i2c_dev { struct completion msg_complete; int irq; bool msg_read; + bool len_recv; + bool client_pec; u32 __iomem *base; u32 msg_buf_remaining; u32 msg_len; @@ -143,10 +145,25 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { u32 len, i; - u8 *buf = priv->msg_buf; + u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & XLP9XX_I2C_FIFO_WCNT_MASK; + if (!len) + return; + if (priv->len_recv) { + /* read length byte */ + rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + *buf++ = rlen; + len--; + if (priv->client_pec) + ++rlen; + /* update remaining bytes and message length */ + priv->msg_buf_remaining = rlen; + priv->msg_len = rlen + 1; + priv->len_recv = false; + } + len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); @@ -230,7 +247,7 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, int last_msg) { unsigned long timeleft; - u32 intr_mask, cmd, val; + u32 intr_mask, cmd, val, len; priv->msg_buf = msg->buf; priv->msg_buf_remaining = priv->msg_len = msg->len; @@ -263,9 +280,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, else val &= ~XLP9XX_I2C_CTRL_ADDMODE; + priv->len_recv = msg->flags & I2C_M_RECV_LEN; + len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len; + priv->client_pec = msg->flags & I2C_CLIENT_PEC; + /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | - (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); /* fill fifo during tx */ @@ -312,6 +333,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, return -ETIMEDOUT; } + /* update msg->len with actual received length */ + if (msg->flags & I2C_M_RECV_LEN) + msg->len = priv->msg_len; return 0; } -- cgit v1.2.3-55-g7522 From ad59c5ea7fa88284b68721c08faf15f0e77abc0d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Oct 2017 14:17:05 +0200 Subject: i2c: sh_mobile: Use of_device_get_match_data() helper Use the of_device_get_match_data() helper instead of open coding. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 6f2aaeb7c4fa..c03acdf71397 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -881,7 +881,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - const struct of_device_id *match; + const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -913,10 +913,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->bus_speed = ret ? STANDARD_MODE : bus_speed; pd->clks_per_count = 1; - match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev); - if (match) { - const struct sh_mobile_dt_config *config = match->data; - + config = of_device_get_match_data(&dev->dev); + if (config) { pd->clks_per_count = config->clks_per_count; if (config->setup) -- cgit v1.2.3-55-g7522 From 3997fb74846f35d0364c5e88e54bc9b166d5a1bc Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 20 Aug 2017 21:06:00 +0200 Subject: i2c: mux: reg: use of_property_read_bool() Use more compact of_property_read_bool() calls for the boolean properties instead of of_find_property() calls in i2c_mux_reg_probe_dt(). Signed-off-by: Sergei Shtylyov Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-reg.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index d97031804de8..f6c9c3dc6cad 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -107,9 +107,9 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, put_device(&adapter->dev); mux->data.n_values = of_get_child_count(np); - if (of_find_property(np, "little-endian", NULL)) { + if (of_property_read_bool(np, "little-endian")) { mux->data.little_endian = true; - } else if (of_find_property(np, "big-endian", NULL)) { + } else if (of_property_read_bool(np, "big-endian")) { mux->data.little_endian = false; } else { #if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \ @@ -122,10 +122,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, #error Endianness not defined? #endif } - if (of_find_property(np, "write-only", NULL)) - mux->data.write_only = true; - else - mux->data.write_only = false; + mux->data.write_only = of_property_read_bool(np, "write-only"); values = devm_kzalloc(&pdev->dev, sizeof(*mux->data.values) * mux->data.n_values, -- cgit v1.2.3-55-g7522 From 631de7a4603439eaa1d7a2a1a7b5b49edcd87f67 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 18 Oct 2017 00:17:09 +0200 Subject: i2c: davinci: use correct format identifier for size_t Fixes this warning (found by build testing with 64bit): format ‘%i’ expects argument of type ‘int’, but argument 3 has type ‘size_t {aka long unsigned int}’ [-Wformat=] Signed-off-by: Wolfram Sang Acked-by: Sekhar Nori --- drivers/i2c/busses/i2c-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index a2d9f7c56dac..2ead9b9eebb7 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -504,7 +504,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) /* This should be 0 if all bytes were transferred * or dev->cmd_err denotes an error. */ - dev_err(dev->dev, "abnormal termination buf_len=%i\n", + dev_err(dev->dev, "abnormal termination buf_len=%zu\n", dev->buf_len); dev->terminate = 1; wmb(); -- cgit v1.2.3-55-g7522 From 728fe6cef27444b6575c5e7ab5de13274610488b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 11 Oct 2017 11:41:19 +0200 Subject: i2c: Allow overriding dev_name through board_info For devices not instantiated through ACPI the i2c-client's device-name gets set to - by default, e.g. "0-0022" this means that the device-name is dependent on the order in which the i2c-busses are enumerated. In some cases having a predictable constant device-name is desirable, for example on non device-tree platforms the link between a regulator and its consumers is specified by the platform code by setting regulator_init_data.consumers. This array identifies the regulator's consumers by dev_name and supply(-name). Which requires a constant dev_name. This commit adds a dev_name field to i2c_board_info allowing platform code to set a contstant dev_name so that the device can be identified by its dev_name in other platform code. Signed-off-by: Hans de Goede Acked-by: Mark Brown (live at ELCE17) Acked-by: Andy Shevchenko (live at ELCE17) Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 10 ++++++++-- include/linux/i2c.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84b..875d6cacaa17 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -666,10 +666,16 @@ static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, } static void i2c_dev_set_name(struct i2c_adapter *adap, - struct i2c_client *client) + struct i2c_client *client, + struct i2c_board_info const *info) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); + if (info && info->dev_name) { + dev_set_name(&client->dev, "i2c-%s", info->dev_name); + return; + } + if (adev) { dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev)); return; @@ -766,7 +772,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; - i2c_dev_set_name(adap, client); + i2c_dev_set_name(adap, client, info); if (info->properties) { status = device_add_properties(&client->dev, info->properties); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d501d3956f13..0f774406fad0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -304,6 +304,7 @@ static inline bool i2c_detect_slave_mode(struct device *dev) { return false; } * @type: chip type, to initialize i2c_client.name * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr + * @dev_name: Overrides the default - dev_name if set * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node @@ -328,6 +329,7 @@ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; + const char *dev_name; void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; -- cgit v1.2.3-55-g7522 From 0224d45c9d46401b6d7018a96cfe049c5da7d91c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 11 Oct 2017 11:41:20 +0200 Subject: i2c-cht-wc: Add device-properties for fusb302 integration Add device-properties to make the bq24292i charger connected to the bus get its input-current-limit from the fusb302 Type-C port controller which is used on boards with the cht-wc PMIC, as well as regulator_init_data for the 5V boost converter on the bq24292i. Since this means we now hook-up the bq24292i to the fusb302 Type-C port controller add a check for the ACPI device which instantiates the fusb302. Signed-off-by: Hans de Goede Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 5 ++++ drivers/i2c/busses/i2c-cht-wc.c | 51 +++++++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 45a3f3ca29b3..009345d8f49d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -198,6 +198,11 @@ config I2C_CHT_WC SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC found on some Intel Cherry Trail systems. + Note this controller is hooked up to a TI bq24292i charger-IC, + combined with a FUSB302 Type-C port-controller as such it is advised + to also select CONFIG_CHARGER_BQ24190=m and CONFIG_TYPEC_FUSB302=m + (the fusb302 driver currently is in drivers/staging). + config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" depends on PCI diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 190bbbc7bfee..0d05dadb2dc5 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #define CHT_WC_I2C_CTRL 0x5e24 @@ -232,13 +234,35 @@ static const struct irq_chip cht_wc_i2c_irq_chip = { .name = "cht_wc_ext_chrg_irq_chip", }; +static const char * const bq24190_suppliers[] = { "fusb302-typec-source" }; + static const struct property_entry bq24190_props[] = { - PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"), + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), PROPERTY_ENTRY_BOOL("omit-battery-class"), PROPERTY_ENTRY_BOOL("disable-reset"), { } }; +static struct regulator_consumer_supply fusb302_consumer = { + .supply = "vbus", + /* Must match fusb302 dev_name in intel_cht_int33fe.c */ + .dev_name = "i2c-fusb302", +}; + +static const struct regulator_init_data bq24190_vbus_init_data = { + .constraints = { + /* The name is used in intel_cht_int33fe.c do not change. */ + .name = "cht_wc_usb_typec_vbus", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &fusb302_consumer, + .num_consumer_supplies = 1, +}; + +static struct bq24190_platform_data bq24190_pdata = { + .regulator_init_data = &bq24190_vbus_init_data, +}; + static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); @@ -246,7 +270,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) struct i2c_board_info board_info = { .type = "bq24190", .addr = 0x6b, + .dev_name = "bq24190", .properties = bq24190_props, + .platform_data = &bq24190_pdata, }; int ret, reg, irq; @@ -314,11 +340,21 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) if (ret) goto remove_irq_domain; - board_info.irq = adap->client_irq; - adap->client = i2c_new_device(&adap->adapter, &board_info); - if (!adap->client) { - ret = -ENOMEM; - goto del_adapter; + /* + * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger, + * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302 + * USB Type-C controller connected to another i2c bus. In this setup + * the max17047 and fusb302 devices are enumerated through an INT33FE + * ACPI device. If this device is present register an i2c-client for + * the TI bq24292i charger. + */ + if (acpi_dev_present("INT33FE", NULL, -1)) { + board_info.irq = adap->client_irq; + adap->client = i2c_new_device(&adap->adapter, &board_info); + if (!adap->client) { + ret = -ENOMEM; + goto del_adapter; + } } platform_set_drvdata(pdev, adap); @@ -335,7 +371,8 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) { struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev); - i2c_unregister_device(adap->client); + if (adap->client) + i2c_unregister_device(adap->client); i2c_del_adapter(&adap->adapter); irq_domain_remove(adap->irq_domain); -- cgit v1.2.3-55-g7522 From b9e43e363d0115ca981c106d968e24140ad37f6c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 16:27:29 -0700 Subject: i2c/busses: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Signed-off-by: Kees Cook Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-img-scb.c | 7 +++---- drivers/i2c/busses/i2c-pnx.c | 8 +++----- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index eb1d91b986fd..823b0b33b2cb 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -826,9 +826,9 @@ next_atomic_cmd: * Timer function to check if something has gone wrong in automatic mode (so we * don't have to handle so many interrupts just to catch an exception). */ -static void img_i2c_check_timer(unsigned long arg) +static void img_i2c_check_timer(struct timer_list *t) { - struct img_i2c *i2c = (struct img_i2c *)arg; + struct img_i2c *i2c = from_timer(i2c, t, check_timer); unsigned long flags; unsigned int line_status; @@ -1362,8 +1362,7 @@ static int img_i2c_probe(struct platform_device *pdev) } /* Set up the exception check timer */ - setup_timer(&i2c->check_timer, img_i2c_check_timer, - (unsigned long)i2c); + timer_setup(&i2c->check_timer, img_i2c_check_timer, 0); i2c->bitrate = timings[0].max_bitrate; if (!of_property_read_u32(node, "clock-frequency", &val)) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 42d6b3a226f8..a542041df0cd 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -112,7 +112,6 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)alg_data; add_timer(timer); } @@ -435,9 +434,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void i2c_pnx_timeout(unsigned long data) +static void i2c_pnx_timeout(struct timer_list *t) { - struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; + struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); u32 ctl; dev_err(&alg_data->adapter.dev, @@ -659,8 +658,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk); - setup_timer(&alg_data->mif.timer, i2c_pnx_timeout, - (unsigned long)alg_data); + timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name); -- cgit v1.2.3-55-g7522 From d982d66514192cdbe74eababa63d0a69be4b0ce1 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Fri, 27 Oct 2017 10:37:56 -0500 Subject: i2c: riic: remove clock and frequency restrictions Remove the restriction that the parent clock has to be a specific frequency and also allow any speed to be supported. Signed-off-by: Chris Brandt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-riic.c | 115 +++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 34 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index c811af4c8d81..95c2f1ce3cad 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -84,12 +84,7 @@ #define ICSR2_NACKF 0x10 -/* ICBRx (@ PCLK 33MHz) */ #define ICBR_RESERVED 0xe0 /* Should be 1 on writes */ -#define ICBRL_SP100K (19 | ICBR_RESERVED) -#define ICBRH_SP100K (16 | ICBR_RESERVED) -#define ICBRL_SP400K (21 | ICBR_RESERVED) -#define ICBRH_SP400K (9 | ICBR_RESERVED) #define RIIC_INIT_MSG -1 @@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = { .functionality = riic_func, }; -static int riic_init_hw(struct riic_dev *riic, u32 spd) +static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) { int ret; unsigned long rate; + int total_ticks, cks, brl, brh; ret = clk_prepare_enable(riic->clk); if (ret) return ret; + if (t->bus_freq_hz > 400000) { + dev_err(&riic->adapter.dev, + "unsupported bus speed (%dHz). 400000 max\n", + t->bus_freq_hz); + clk_disable_unprepare(riic->clk); + return -EINVAL; + } + + rate = clk_get_rate(riic->clk); + /* - * TODO: Implement formula to calculate the timing values depending on - * variable parent clock rate and arbitrary bus speed + * Assume the default register settings: + * FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles) + * FER.NFE = 1 (noise circuit enabled) + * MR3.NF = 0 (1 cycle of noise filtered out) + * + * Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1) + * Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1) */ - rate = clk_get_rate(riic->clk); - if (rate != 33325000) { - dev_err(&riic->adapter.dev, - "invalid parent clk (%lu). Must be 33325000Hz\n", rate); + + /* + * Determine reference clock rate. We must be able to get the desired + * frequency with only 62 clock ticks max (31 high, 31 low). + * Aim for a duty of 60% LOW, 40% HIGH. + */ + total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz); + + for (cks = 0; cks < 7; cks++) { + /* + * 60% low time must be less than BRL + 2 + 1 + * BRL max register value is 0x1F. + */ + brl = ((total_ticks * 6) / 10); + if (brl <= (0x1F + 3)) + break; + + total_ticks /= 2; + rate /= 2; + } + + if (brl > (0x1F + 3)) { + dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n", + (unsigned long)t->bus_freq_hz); clk_disable_unprepare(riic->clk); return -EINVAL; } + brh = total_ticks - brl; + + /* Remove automatic clock ticks for sync circuit and NF */ + if (cks == 0) { + brl -= 4; + brh -= 4; + } else { + brl -= 3; + brh -= 3; + } + + /* + * Remove clock ticks for rise and fall times. Convert ns to clock + * ticks. + */ + brl -= t->scl_fall_ns / (1000000000 / rate); + brh -= t->scl_rise_ns / (1000000000 / rate); + + /* Adjust for min register values for when SCLE=1 and NFE=1 */ + if (brl < 1) + brl = 1; + if (brh < 1) + brh = 1; + + pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n", + rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6), + t->scl_fall_ns / (1000000000 / rate), + t->scl_rise_ns / (1000000000 / rate), cks, brl, brh); + /* Changing the order of accessing IICRST and ICE may break things! */ writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); - switch (spd) { - case 100000: - writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL); - break; - case 400000: - writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL); - break; - default: - dev_err(&riic->adapter.dev, - "unsupported bus speed (%dHz). Use 100000 or 400000\n", spd); - clk_disable_unprepare(riic->clk); - return -EINVAL; - } + writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1); + writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH); + writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL); writeb(0, riic->base + RIIC_ICSER); writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); @@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = { static int riic_i2c_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct riic_dev *riic; struct i2c_adapter *adap; struct resource *res; - u32 bus_rate = 0; + struct i2c_timings i2c_t; int i, ret; riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); @@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev) init_completion(&riic->msg_done); - of_property_read_u32(np, "clock-frequency", &bus_rate); - ret = riic_init_hw(riic, bus_rate); + i2c_parse_fw_timings(&pdev->dev, &i2c_t, true); + + ret = riic_init_hw(riic, &i2c_t); if (ret) return ret; @@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, riic); - dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate); + dev_info(&pdev->dev, "registered with %dHz bus speed\n", + i2c_t.bus_freq_hz); return 0; } -- cgit v1.2.3-55-g7522 From 750bd8b990856ec89a3af5836c7915ea6e2dd712 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Aug 2016 10:56:44 +0200 Subject: i2c: mpc: use of_property_read_bool Use of_property_read_bool to check for the existence of a property. Signed-off-by: Julia Lawall Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 96caf378b1dc..2b221a514974 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -700,7 +700,7 @@ static int fsl_i2c_probe(struct platform_device *op) } } - if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) { + if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) { clock = MPC_I2C_CLOCK_PRESERVE; } else { prop = of_get_property(op->dev.of_node, "clock-frequency", -- cgit v1.2.3-55-g7522 From 93222bd9b966105f43418fd336654ad10045783a Mon Sep 17 00:00:00 2001 From: Ed Blake Date: Sat, 28 Oct 2017 12:44:34 +0100 Subject: i2c: img-scb: Add runtime PM The i2c-img-scb driver already dynamically enables / disables clocks to save power, but doesn't use the runtime PM framework. Convert the driver to use runtime PM, so that dynamic clock management will be disabled when runtime PM is disabled, and so that autosuspend can be used to avoid unnecessarily disabling and re-enabling clocks repeatedly during a sequence of transactions. Signed-off-by: Ed Blake Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-img-scb.c | 97 ++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 19 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index 823b0b33b2cb..f038858b6c54 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -280,6 +281,8 @@ #define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) #define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) +#define IMG_I2C_PM_TIMEOUT 1000 /* ms */ + enum img_i2c_mode { MODE_INACTIVE, MODE_RAW, @@ -408,6 +411,9 @@ struct img_i2c { unsigned int raw_timeout; }; +static int img_i2c_runtime_suspend(struct device *dev); +static int img_i2c_runtime_resume(struct device *dev); + static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value) { writel(value, i2c->base + offset); @@ -1054,8 +1060,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, atomic = true; } - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(adap->dev.parent); + if (ret < 0) return ret; for (i = 0; i < num; i++) { @@ -1131,7 +1137,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, break; } - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(adap->dev.parent); + pm_runtime_put_autosuspend(adap->dev.parent); return i2c->msg_status ? i2c->msg_status : num; } @@ -1149,12 +1156,13 @@ static const struct i2c_algorithm img_i2c_algo = { static int img_i2c_init(struct img_i2c *i2c) { unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh; - unsigned int i, ret, data, prescale, inc, int_bitrate, filt; + unsigned int i, data, prescale, inc, int_bitrate, filt; struct img_i2c_timings timing; u32 rev; + int ret; - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(i2c->adap.dev.parent); + if (ret < 0) return ret; rev = img_i2c_readl(i2c, SCB_CORE_REV_REG); @@ -1163,7 +1171,8 @@ static int img_i2c_init(struct img_i2c *i2c) "Unknown hardware revision (%d.%d.%d.%d)\n", (rev >> 24) & 0xff, (rev >> 16) & 0xff, (rev >> 8) & 0xff, rev & 0xff); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return -EINVAL; } @@ -1314,7 +1323,8 @@ static int img_i2c_init(struct img_i2c *i2c) /* Perform a synchronous sequence to reset the bus */ ret = img_i2c_reset_bus(i2c); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return ret; } @@ -1383,22 +1393,30 @@ static int img_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - ret = clk_prepare_enable(i2c->sys_clk); - if (ret) - return ret; + pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_i2c_runtime_resume(&pdev->dev); + if (ret) + return ret; + } ret = img_i2c_init(i2c); if (ret) - goto disable_clk; + goto rpm_disable; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) - goto disable_clk; + goto rpm_disable; return 0; -disable_clk: - clk_disable_unprepare(i2c->sys_clk); +rpm_disable: + if (!pm_runtime_enabled(&pdev->dev)) + img_i2c_runtime_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return ret; } @@ -1407,19 +1425,55 @@ static int img_i2c_remove(struct platform_device *dev) struct img_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); + pm_runtime_disable(&dev->dev); + if (!pm_runtime_status_suspended(&dev->dev)) + img_i2c_runtime_suspend(&dev->dev); + + return 0; +} + +static int img_i2c_runtime_suspend(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + + clk_disable_unprepare(i2c->scb_clk); clk_disable_unprepare(i2c->sys_clk); return 0; } +static int img_i2c_runtime_resume(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(i2c->sys_clk); + if (ret) { + dev_err(dev, "Unable to enable sys clock\n"); + return ret; + } + + ret = clk_prepare_enable(i2c->scb_clk); + if (ret) { + dev_err(dev, "Unable to enable scb clock\n"); + clk_disable_unprepare(i2c->sys_clk); + return ret; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int img_i2c_suspend(struct device *dev) { struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; - img_i2c_switch_mode(i2c, MODE_SUSPEND); + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; - clk_disable_unprepare(i2c->sys_clk); + img_i2c_switch_mode(i2c, MODE_SUSPEND); return 0; } @@ -1429,7 +1483,7 @@ static int img_i2c_resume(struct device *dev) struct img_i2c *i2c = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(i2c->sys_clk); + ret = pm_runtime_force_resume(dev); if (ret) return ret; @@ -1439,7 +1493,12 @@ static int img_i2c_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(img_i2c_pm, img_i2c_suspend, img_i2c_resume); +static const struct dev_pm_ops img_i2c_pm = { + SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, + img_i2c_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) +}; static const struct of_device_id img_scb_i2c_match[] = { { .compatible = "img,scb-i2c" }, -- cgit v1.2.3-55-g7522 From 1f35b8653687b9c08c8d58489c1b5cb9cf961c17 Mon Sep 17 00:00:00 2001 From: Claudio Foellmi Date: Thu, 5 Oct 2017 14:44:14 +0200 Subject: i2c: generic recovery: check SCL before SDA Move the check for a stuck SCL before the check for a high SDA. This prevent false positives in the specific case that SDA is fine and SCL is stuck, which previously returned 0. Also check SDA again after the loop, if we can. Together, these changes should lead to a lot more failed recoveries being caught and returning error codes. Signed-off-by: Claudio Foellmi Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 875d6cacaa17..db6558e5f657 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -205,9 +205,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) */ while (i++ < RECOVERY_CLK_CNT * 2) { if (val) { - /* Break if SDA is high */ - if (bri->get_sda && bri->get_sda(adap)) - break; /* SCL shouldn't be low here */ if (!bri->get_scl(adap)) { dev_err(&adap->dev, @@ -215,6 +212,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ret = -EBUSY; break; } + /* Break if SDA is high */ + if (bri->get_sda && bri->get_sda(adap)) + break; } val = !val; @@ -222,6 +222,10 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ndelay(RECOVERY_NDELAY); } + /* check if recovery actually succeeded */ + if (bri->get_sda && !bri->get_sda(adap)) + ret = -EBUSY; + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); -- cgit v1.2.3-55-g7522 From 9b9f2b8bc2ac98d91da714660c53d1cdac999e09 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:01 +0800 Subject: i2c: i2c-smbus: Use threaded irq for smbalert Prior to this commit the smbalert_irq was handling in the hard irq context. This change switch to using a thread irq which avoids the need for the work thread. Using threaded irq also removes the need for the edge_triggered flag as the enabling / disabling of the hard irq for level triggered interrupts will be handled by the irq core. Without this change have an irq connected to something like an i2c gpio resulted in a null ptr deferences. Specifically handle_nested_irq calls the threaded irq handler. There are currently 3 in tree drivers affected by this change. i2c-parport driver calls i2c_handle_smbus_alert in a hard irq context. This driver use edge trigger interrupts which skip the enable / disable calls. But it still need to handle the smbus transaction on a thread. So the work thread is kept for this driver. i2c-parport-light & i2c-thunderx-pcidrv provide the irq number in the setup which will result in the thread irq being used. i2c-parport-light is edge trigger so the enable / disable call was skipped as well. i2c-thunderx-pcidrv is getting the edge / level trigger setting from of data and was setting the flag as required. However the irq core should handle this automatically. Signed-off-by: Phil Reid Reviewed-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-parport-light.c | 1 - drivers/i2c/busses/i2c-parport.c | 1 - drivers/i2c/busses/i2c-thunderx-pcidrv.c | 6 ----- drivers/i2c/i2c-smbus.c | 41 +++++++++++++------------------- include/linux/i2c-smbus.h | 1 - 5 files changed, 17 insertions(+), 33 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index faa8fb8f2b8f..fa41ff799533 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = { /* SMBus alert support */ static struct i2c_smbus_alert_setup alert_data = { - .alert_edge_triggered = 1, }; static struct i2c_client *ara; static struct lineop parport_ctrl_irq = { diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index a8e54df4aed6..319209a07353 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port) /* Setup SMBus alert if supported */ if (adapter_parm[type].smbus_alert) { - adapter->alert_data.alert_edge_triggered = 1; adapter->ara = i2c_setup_smbus_alert(&adapter->adapter, &adapter->alert_data); if (adapter->ara) diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index df0976f4432a..1a7cad874756 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, struct device_node *node) { - u32 type; - if (!node) return -EINVAL; @@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, if (!i2c->alert_data.irq) return -EINVAL; - type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq)); - i2c->alert_data.alert_edge_triggered = - (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0; - i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); if (!i2c->ara) return -ENODEV; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f9271c713d20..d4af2701ac6e 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -25,8 +25,6 @@ #include struct i2c_smbus_alert { - unsigned int alert_edge_triggered:1; - int irq; struct work_struct alert; struct i2c_client *ara; /* Alert response address */ }; @@ -72,13 +70,12 @@ static int smbus_do_alert(struct device *dev, void *addrp) * The alert IRQ handler needs to hand work off to a task which can issue * SMBus calls, because those sleeping calls can't be made in IRQ context. */ -static void smbus_alert(struct work_struct *work) +static irqreturn_t smbus_alert(int irq, void *d) { - struct i2c_smbus_alert *alert; + struct i2c_smbus_alert *alert = d; struct i2c_client *ara; unsigned short prev_addr = 0; /* Not a valid address */ - alert = container_of(work, struct i2c_smbus_alert, alert); ara = alert->ara; for (;;) { @@ -115,21 +112,17 @@ static void smbus_alert(struct work_struct *work) prev_addr = data.addr; } - /* We handled all alerts; re-enable level-triggered IRQs */ - if (!alert->alert_edge_triggered) - enable_irq(alert->irq); + return IRQ_HANDLED; } -static irqreturn_t smbalert_irq(int irq, void *d) +static void smbalert_work(struct work_struct *work) { - struct i2c_smbus_alert *alert = d; + struct i2c_smbus_alert *alert; + + alert = container_of(work, struct i2c_smbus_alert, alert); - /* Disable level-triggered IRQs until we handle them */ - if (!alert->alert_edge_triggered) - disable_irq_nosync(irq); + smbus_alert(0, alert); - schedule_work(&alert->alert); - return IRQ_HANDLED; } /* Setup SMBALERT# infrastructure */ @@ -139,28 +132,28 @@ static int smbalert_probe(struct i2c_client *ara, struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; - int res; + int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), GFP_KERNEL); if (!alert) return -ENOMEM; - alert->alert_edge_triggered = setup->alert_edge_triggered; - alert->irq = setup->irq; - INIT_WORK(&alert->alert, smbus_alert); + irq = setup->irq; + INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; - if (setup->irq > 0) { - res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, - 0, "smbus_alert", alert); + if (irq > 0) { + res = devm_request_threaded_irq(&ara->dev, irq, + NULL, smbus_alert, + IRQF_SHARED | IRQF_ONESHOT, + "smbus_alert", alert); if (res) return res; } i2c_set_clientdata(ara, alert); - dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", - setup->alert_edge_triggered ? "edge" : "level"); + dev_info(&adapter->dev, "supports SMBALERT#\n"); return 0; } diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index a1385023a29b..19efbd14e812 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -42,7 +42,6 @@ * properly set. */ struct i2c_smbus_alert_setup { - unsigned int alert_edge_triggered:1; int irq; }; -- cgit v1.2.3-55-g7522 From 3c0a60bee1d157d4ed9ae6a9727d508158d002c7 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:02 +0800 Subject: i2c: i2c-smbus: Move i2c_setup_smbus_alert from i2c-smbus to i2c-core-smbus In preparation to adding of_i2c_setup_smbus_alert() move i2c_setup_smbus_alert() to core module. of_i2c_setup_smbus_alert() will call i2c_setup_smbus_alert() and this avoid module dependecy issues. Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 33 +++++++++++++++++++++++++++++++++ drivers/i2c/i2c-smbus.c | 32 -------------------------------- 2 files changed, 33 insertions(+), 32 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 10f00a82ec9d..7f3ec02f085a 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -17,6 +17,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -592,3 +593,35 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, return i; } EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); + +/** + * i2c_setup_smbus_alert - Setup SMBus alert support + * @adapter: the target adapter + * @setup: setup data for the SMBus alert handler + * Context: can sleep + * + * Setup handling of the SMBus alert protocol on a given I2C bus segment. + * + * Handling can be done either through our IRQ handler, or by the + * adapter (from its handler, periodic polling, or whatever). + * + * NOTE that if we manage the IRQ, we *MUST* know if it's level or + * edge triggered in order to hand it to the workqueue correctly. + * If triggering the alert seems to wedge the system, you probably + * should have said it's level triggered. + * + * This returns the ara client, which should be saved for later use with + * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL + * to indicate an error. + */ +struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, + struct i2c_smbus_alert_setup *setup) +{ + struct i2c_board_info ara_board_info = { + I2C_BOARD_INFO("smbus_alert", 0x0c), + .platform_data = setup, + }; + + return i2c_new_device(adapter, &ara_board_info); +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index d4af2701ac6e..d0bb0358b578 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -182,38 +182,6 @@ static struct i2c_driver smbalert_driver = { .id_table = smbalert_ids, }; -/** - * i2c_setup_smbus_alert - Setup SMBus alert support - * @adapter: the target adapter - * @setup: setup data for the SMBus alert handler - * Context: can sleep - * - * Setup handling of the SMBus alert protocol on a given I2C bus segment. - * - * Handling can be done either through our IRQ handler, or by the - * adapter (from its handler, periodic polling, or whatever). - * - * NOTE that if we manage the IRQ, we *MUST* know if it's level or - * edge triggered in order to hand it to the workqueue correctly. - * If triggering the alert seems to wedge the system, you probably - * should have said it's level triggered. - * - * This returns the ara client, which should be saved for later use with - * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL - * to indicate an error. - */ -struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, - struct i2c_smbus_alert_setup *setup) -{ - struct i2c_board_info ara_board_info = { - I2C_BOARD_INFO("smbus_alert", 0x0c), - .platform_data = setup, - }; - - return i2c_new_device(adapter, &ara_board_info); -} -EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); - /** * i2c_handle_smbus_alert - Handle an SMBus alert * @ara: the ARA client on the relevant adapter -- cgit v1.2.3-55-g7522 From 69d17246ab255dda8e71c8d65396b4aa6121b7ad Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:03 +0800 Subject: i2c: i2c-smbus: add of_i2c_setup_smbus_alert This commit adds of_i2c_setup_smbus_alert which allows the smbalert driver to be attached to an i2c adapter via the device tree. Signed-off-by: Phil Reid Acked-by: Rob Herring Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c.txt | 4 ++-- drivers/i2c/i2c-core-smbus.c | 22 ++++++++++++++++++++++ drivers/i2c/i2c-smbus.c | 10 +++++++++- include/linux/i2c-smbus.h | 9 +++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index cee9d5055fa2..11263982470e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below. interrupts used by the device. - interrupt-names - "irq" and "wakeup" names are recognized by I2C core, other names are - left to individual drivers. + "irq", "wakeup" and "smbus_alert" names are recognized by I2C core, + other names are left to individual drivers. - host-notify device uses SMBus host notify protocol instead of interrupt line. diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 7f3ec02f085a..4bb9927afd01 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -625,3 +625,25 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, return i2c_new_device(adapter, &ara_board_info); } EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); + +#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) +int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) +{ + struct i2c_client *client; + int irq; + + irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", + "smbus_alert"); + if (irq == -EINVAL || irq == -ENODATA) + return 0; + else if (irq < 0) + return irq; + + client = i2c_setup_smbus_alert(adapter, NULL); + if (!client) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); +#endif diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index d0bb0358b578..5a1dd7f13bac 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -139,7 +140,14 @@ static int smbalert_probe(struct i2c_client *ara, if (!alert) return -ENOMEM; - irq = setup->irq; + if (setup) { + irq = setup->irq; + } else { + irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert"); + if (irq <= 0) + return irq; + } + INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index 19efbd14e812..fb0e040b1abb 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, struct i2c_smbus_alert_setup *setup); int i2c_handle_smbus_alert(struct i2c_client *ara); +#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap); +#else +static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap) +{ + return 0; +} +#endif + #endif /* _LINUX_I2C_SMBUS_H */ -- cgit v1.2.3-55-g7522 From f8756c67b3de71a46255aa478ab590ff28e60ac9 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:04 +0800 Subject: i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered so the the smbalert driver can be registered. Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84b..130d22bed563 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1259,6 +1260,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } + res = of_i2c_setup_smbus_alert(adap); + if (res) + goto out_reg; + dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); pm_runtime_no_callbacks(&adap->dev); @@ -1290,6 +1295,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return 0; +out_reg: + init_completion(&adap->dev_released); + device_unregister(&adap->dev); + wait_for_completion(&adap->dev_released); out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); -- cgit v1.2.3-55-g7522 From 148baf1ddfb65019ee510ba2a76c2e7cd9752982 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:05 +0800 Subject: i2c: mux: pca954x: call request irq after adding mux segments The pca954x device do not have the ability to mask interrupts. For i2c slave devices that also don't have masking ability (eg ltc1760 smbalert output) delay registering the irq until after the mux segments have been configured. During the mux add_adaptor call the core i2c system can register an smbalert handler which would then be called immediately when the irq is registered. This smbalert handler will then clear the pending irq. This removes the need for the irq_mask / irq_unmask calls that were original used to do this. Signed-off-by: Phil Reid Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 91 ++++++++++++------------------------- 1 file changed, 28 insertions(+), 63 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 7b992db38021..14aee65298f7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -246,36 +246,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } -static void pca954x_irq_mask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - data->irq_mask &= ~BIT(pos); - if (!data->irq_mask) - disable_irq(data->client->irq); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - -static void pca954x_irq_unmask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - if (!data->irq_mask) - enable_irq(data->client->irq); - data->irq_mask |= BIT(pos); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) { if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) @@ -285,8 +255,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) static struct irq_chip pca954x_irq_chip = { .name = "i2c-mux-pca954x", - .irq_mask = pca954x_irq_mask, - .irq_unmask = pca954x_irq_unmask, .irq_set_type = pca954x_irq_set_type, }; @@ -294,7 +262,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) { struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; - int c, err, irq; + int c, irq; if (!data->chip->has_irq || client->irq <= 0) return 0; @@ -314,24 +282,22 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) handle_simple_irq); } - err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, - pca954x_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - "pca954x", data); - if (err) - goto err_req_irq; + return 0; +} - disable_irq(data->client->irq); +static void pca954x_cleanup(struct i2c_mux_core *muxc) +{ + struct pca954x *data = i2c_mux_priv(muxc); + int c, irq; - return 0; -err_req_irq: - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); + if (data->irq) { + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); } - irq_domain_remove(data->irq); - - return err; + i2c_mux_del_adapters(muxc); } /* @@ -391,7 +357,7 @@ static int pca954x_probe(struct i2c_client *client, ret = pca954x_irq_setup(muxc); if (ret) - goto fail_del_adapters; + goto fail_cleanup; /* Now create an adapter for each channel */ for (num = 0; num < data->chip->nchans; num++) { @@ -414,7 +380,16 @@ static int pca954x_probe(struct i2c_client *client, ret = i2c_mux_add_adapter(muxc, force, num, class); if (ret) - goto fail_del_adapters; + goto fail_cleanup; + } + + if (data->irq) { + ret = devm_request_threaded_irq(&client->dev, data->client->irq, + NULL, pca954x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + "pca954x", data); + if (ret) + goto fail_cleanup; } dev_info(&client->dev, @@ -424,26 +399,16 @@ static int pca954x_probe(struct i2c_client *client, return 0; -fail_del_adapters: - i2c_mux_del_adapters(muxc); +fail_cleanup: + pca954x_cleanup(muxc); return ret; } static int pca954x_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); - struct pca954x *data = i2c_mux_priv(muxc); - int c, irq; - if (data->irq) { - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); - } - irq_domain_remove(data->irq); - } - - i2c_mux_del_adapters(muxc); + pca954x_cleanup(muxc); return 0; } -- cgit v1.2.3-55-g7522 From e460617e85db8af533c9f70c9ab94d4fa111b379 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 24 Aug 2017 17:31:06 +0800 Subject: i2c: mux: pca954x: Return error if irq_create_mapping fails irq_create_mapping can return an error, report error to log and return. Cleanup will occur in the probe function when an error is returned. Suggested-by: Peter Rosin Acked-by: Peter Rosin Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 14aee65298f7..2ca068d8b92d 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -277,6 +277,10 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) for (c = 0; c < data->chip->nchans; c++) { irq = irq_create_mapping(data->irq, c); + if (!irq) { + dev_err(&client->dev, "failed irq create map\n"); + return -EINVAL; + } irq_set_chip_data(irq, data); irq_set_chip_and_handler(irq, &pca954x_irq_chip, handle_simple_irq); -- cgit v1.2.3-55-g7522 From b2e63555592f81331c8da3afaa607d8cf83e8138 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 10 Sep 2017 01:30:46 +0200 Subject: i2c: gpio: Convert to use descriptors This converts the GPIO-based I2C-driver to using GPIO descriptors instead of the old global numberspace-based GPIO interface. We: - Convert the driver to unconditionally grab two GPIOs from the device by index 0 (SDA) and 1 (SCL) which will work fine with device tree and descriptor tables. The existing device trees will continue to work just like before, but without any roundtrip through the global numberspace. - Brutally convert all boardfiles still passing global GPIOs by registering descriptor tables associated with the devices instead so this driver does not need to keep supporting passing any GPIO numbers as platform data. There is no stepwise approach as elegant as this, I strongly prefer this big hammer over any antsteps for this conversion. This way the old GPIO numbers go away and NEVER COME BACK. Special conversion for the different boards utilizing I2C-GPIO: - EP93xx (arch/arm/mach-ep93xx): pretty straight forward as all boards were using the same two GPIO lines, just define these two in a lookup table for "i2c-gpio" and register these along with the device. None of them define any other platform data so just pass NULL as platform data. This platform selects GPIOLIB so all should be smooth. The pins appear on a gpiochip for bank "G" as pins 1 (SDA) and 0 (SCL). - IXP4 (arch/arm/mach-ixp4): descriptor tables have to be registered for each board separately. They all use "IXP4XX_GPIO_CHIP" so it is pretty straight forward. Most board define no other platform data than SCL/SDA so they can drop the #include of and assign NULL to platform data. The "goramo_mlr" (Goramo Multilink Router) board is a bit worrisome: it implements its own I2C bit-banging in the board file, and optionally registers an I2C serial port, but claims the same GPIO lines for itself in the board file. This is not going to work: there will be competition for the GPIO lines, so delete the optional extra I2C bus instead, no I2C devices are registered on it anyway, there are just hints that it may contain an EEPROM that may be accessed from userspace. This needs to be fixed up properly by the serial clock using I2C emulation so drop a note in the code. - KS8695 board acs5k (arch/arm/mach-ks8695/board-acs5.c) has some platform data in addition to the pins so it needs to be kept around sans GPIO lines. Its GPIO chip is named "KS8695" and the arch selects GPIOLIB. - PXA boards (arch/arm/mach-pxa/*) use some of the platform data so it needs to be preserved here. The viper board even registers two GPIO I2Cs. The gpiochip is named "gpio-pxa" and the arch selects GPIOLIB. - SA1100 Simpad (arch/arm/mach-sa1100/simpad.c) defines a GPIO I2C bus, and the arch selects GPIOLIB. - Blackfin boards (arch/blackfin/bf533 etc) for these I assume their I2C GPIOs refer to the local gpiochip defined in arch/blackfin/kernel/bfin_gpio.c names "BFIN-GPIO". The arch selects GPIOLIB. The boards get spiked with IF_ENABLED(I2C_GPIO) but that is a side effect of it being like that already (I would just have Kconfig select I2C_GPIO and get rid of them all.) I also delete any platform data set to 0 as it will get that value anyway from static declartions of platform data. - The MIPS selects GPIOLIB and the Alchemy machine is using two local GPIO chips, one of them has a GPIO I2C. We need to adjust the local offset from the global number space here. The ATH79 has a proper GPIO driver in drivers/gpio/gpio-ath79.c and AFAICT the chip is named "ath79-gpio" and the PB44 PCF857x expander spawns from this on GPIO 1 and 0. The latter board only use the platform data to specify pins so it can be cut altogether after this. - The MFD Silicon Motion SM501 is a special case. It dynamically spawns an I2C bus off the MFD using sm501_create_subdev(). We use an approach to dynamically create a machine descriptor table and attach this to the "SM501-LOW" or "SM501-HIGH" gpiochip. We use chip-local offsets to grab the right lines. We can get rid of two local static inline helpers as part of this refactoring. Cc: Steven Miao Cc: Ralf Baechle Cc: Guenter Roeck Cc: Ville Syrjälä Cc: Magnus Damm Cc: Ben Dooks Cc: Heiko Schocher Acked-by: Wu, Aaron Acked-by: Olof Johansson Acked-by: Lee Jones Acked-by: Ralf Baechle Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- arch/arm/mach-ep93xx/core.c | 39 ++++---- arch/arm/mach-ep93xx/edb93xx.c | 15 +-- arch/arm/mach-ep93xx/include/mach/platform.h | 4 +- arch/arm/mach-ep93xx/simone.c | 12 +-- arch/arm/mach-ep93xx/snappercl15.c | 12 +-- arch/arm/mach-ep93xx/vision_ep9307.c | 7 +- arch/arm/mach-ixp4xx/avila-setup.c | 17 +++- arch/arm/mach-ixp4xx/dsmg600-setup.c | 16 +++- arch/arm/mach-ixp4xx/fsg-setup.c | 16 +++- arch/arm/mach-ixp4xx/goramo_mlr.c | 24 ++--- arch/arm/mach-ixp4xx/ixdp425-setup.c | 16 +++- arch/arm/mach-ixp4xx/nas100d-setup.c | 16 +++- arch/arm/mach-ixp4xx/nslu2-setup.c | 16 +++- arch/arm/mach-ks8695/board-acs5k.c | 13 ++- arch/arm/mach-pxa/palmz72.c | 12 ++- arch/arm/mach-pxa/viper.c | 27 +++++- arch/arm/mach-sa1100/simpad.c | 12 ++- arch/blackfin/mach-bf533/boards/blackstamp.c | 19 +++- arch/blackfin/mach-bf533/boards/ezkit.c | 18 +++- arch/blackfin/mach-bf533/boards/stamp.c | 18 +++- arch/blackfin/mach-bf561/boards/ezkit.c | 18 +++- arch/mips/alchemy/board-gpr.c | 19 +++- arch/mips/ath79/mach-pb44.c | 16 +++- drivers/i2c/busses/i2c-gpio.c | 134 +++++++++++++-------------- drivers/mfd/sm501.c | 49 +++++----- include/linux/i2c-gpio.h | 4 - 26 files changed, 327 insertions(+), 242 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index f53c61813998..7e99fe829ad1 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -320,42 +320,45 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) /************************************************************************* * EP93xx i2c peripheral handling *************************************************************************/ -static struct i2c_gpio_platform_data ep93xx_i2c_data; + +/* All EP93xx devices use the same two GPIO pins for I2C bit-banging */ +static struct gpiod_lookup_table ep93xx_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + /* Use local offsets on gpiochip/port "G" */ + GPIO_LOOKUP_IDX("G", 1, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("G", 0, NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; static struct platform_device ep93xx_i2c_device = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &ep93xx_i2c_data, + .platform_data = NULL, }, }; /** * ep93xx_register_i2c - Register the i2c platform device. - * @data: platform specific i2c-gpio configuration (__initdata) * @devices: platform specific i2c bus device information (__initdata) * @num: the number of devices on the i2c bus */ -void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, - struct i2c_board_info *devices, int num) +void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num) { /* - * Set the EEPROM interface pin drive type control. - * Defines the driver type for the EECLK and EEDAT pins as either - * open drain, which will require an external pull-up, or a normal - * CMOS driver. + * FIXME: this just sets the two pins as non-opendrain, as no + * platforms tries to do that anyway. Flag the applicable lines + * as open drain in the GPIO_LOOKUP above and the driver or + * gpiolib will handle open drain/open drain emulation as need + * be. Right now i2c-gpio emulates open drain which is not + * optimal. */ - if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) - pr_warning("sda != EEDAT, open drain has no effect\n"); - if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) - pr_warning("scl != EECLK, open drain has no effect\n"); - - __raw_writel((data->sda_is_open_drain << 1) | - (data->scl_is_open_drain << 0), + __raw_writel((0 << 1) | (0 << 0), EP93XX_GPIO_EEDRIVE); - ep93xx_i2c_data = *data; i2c_register_board_info(0, devices, num); + gpiod_add_lookup_table(&ep93xx_i2c_gpiod_table); platform_device_register(&ep93xx_i2c_device); } diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 7a7f280b07d7..8e89ec8b6f0f 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -61,14 +60,6 @@ static struct ep93xx_eth_data __initdata edb93xx_eth_data = { /************************************************************************* * EDB93xx i2c peripheral handling *************************************************************************/ -static struct i2c_gpio_platform_data __initdata edb93xx_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, /* default to 100 kHz */ - .timeout = 0, /* default to 100 ms */ -}; static struct i2c_board_info __initdata edb93xxa_i2c_board_info[] = { { @@ -86,13 +77,11 @@ static void __init edb93xx_register_i2c(void) { if (machine_is_edb9302a() || machine_is_edb9307a() || machine_is_edb9315a()) { - ep93xx_register_i2c(&edb93xx_i2c_gpio_data, - edb93xxa_i2c_board_info, + ep93xx_register_i2c(edb93xxa_i2c_board_info, ARRAY_SIZE(edb93xxa_i2c_board_info)); } else if (machine_is_edb9302() || machine_is_edb9307() || machine_is_edb9312() || machine_is_edb9315()) { - ep93xx_register_i2c(&edb93xx_i2c_gpio_data, - edb93xx_i2c_board_info, + ep93xx_register_i2c(edb93xx_i2c_board_info, ARRAY_SIZE(edb93xx_i2c_board_info)); } } diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index db0839691ef5..a686fd6caee1 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -7,7 +7,6 @@ #include struct device; -struct i2c_gpio_platform_data; struct i2c_board_info; struct spi_board_info; struct platform_device; @@ -36,8 +35,7 @@ void ep93xx_register_flash(unsigned int width, resource_size_t start, resource_size_t size); void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); -void ep93xx_register_i2c(struct i2c_gpio_platform_data *data, - struct i2c_board_info *devices, int num); +void ep93xx_register_i2c(struct i2c_board_info *devices, int num); void ep93xx_register_spi(struct ep93xx_spi_info *info, struct spi_board_info *devices, int num); void ep93xx_register_fb(struct ep93xxfb_mach_info *data); diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index c7a40f245892..e61f3dee24c2 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -129,15 +128,6 @@ static struct ep93xx_spi_info simone_spi_info __initdata = { .use_dma = 1, }; -static struct i2c_gpio_platform_data __initdata simone_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, - .timeout = 0, -}; - static struct i2c_board_info __initdata simone_i2c_board_info[] = { { I2C_BOARD_INFO("ds1337", 0x68), @@ -161,7 +151,7 @@ static void __init simone_init_machine(void) ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_8M); ep93xx_register_eth(&simone_eth_data, 1); ep93xx_register_fb(&simone_fb_info); - ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info, + ep93xx_register_i2c(simone_i2c_board_info, ARRAY_SIZE(simone_i2c_board_info)); ep93xx_register_spi(&simone_spi_info, simone_spi_devices, ARRAY_SIZE(simone_spi_devices)); diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index 8b29398f4dc7..45940c1d7787 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -127,15 +126,6 @@ static struct ep93xx_eth_data __initdata snappercl15_eth_data = { .phy_id = 1, }; -static struct i2c_gpio_platform_data __initdata snappercl15_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, - .timeout = 0, -}; - static struct i2c_board_info __initdata snappercl15_i2c_data[] = { { /* Audio codec */ @@ -161,7 +151,7 @@ static void __init snappercl15_init_machine(void) { ep93xx_init_devices(); ep93xx_register_eth(&snappercl15_eth_data, 1); - ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data, + ep93xx_register_i2c(snappercl15_i2c_data, ARRAY_SIZE(snappercl15_i2c_data)); ep93xx_register_fb(&snappercl15_fb_info); snappercl15_register_audio(); diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 1daf9441058c..5a0b6187990a 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -144,10 +143,6 @@ static struct pca953x_platform_data pca953x_77_gpio_data = { /************************************************************************* * I2C Bus *************************************************************************/ -static struct i2c_gpio_platform_data vision_i2c_gpio_data __initdata = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .scl_pin = EP93XX_GPIO_LINE_EECLK, -}; static struct i2c_board_info vision_i2c_info[] __initdata = { { @@ -289,7 +284,7 @@ static void __init vision_init_machine(void) vision_i2c_info[1].irq = gpio_to_irq(EP93XX_GPIO_LINE_F(7)); - ep93xx_register_i2c(&vision_i2c_gpio_data, vision_i2c_info, + ep93xx_register_i2c(vision_i2c_info, ARRAY_SIZE(vision_i2c_info)); ep93xx_register_spi(&vision_spi_master, vision_spi_board_info, ARRAY_SIZE(vision_spi_board_info)); diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c index 6beec150c060..72122b5e7f28 100644 --- a/arch/arm/mach-ixp4xx/avila-setup.c +++ b/arch/arm/mach-ixp4xx/avila-setup.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,16 +49,21 @@ static struct platform_device avila_flash = { .resource = &avila_flash_resource, }; -static struct i2c_gpio_platform_data avila_i2c_gpio_data = { - .sda_pin = AVILA_SDA_PIN, - .scl_pin = AVILA_SCL_PIN, +static struct gpiod_lookup_table avila_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", AVILA_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", AVILA_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device avila_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &avila_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -147,6 +152,8 @@ static void __init avila_init(void) avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&avila_i2c_gpiod_table); + platform_add_devices(avila_devices, ARRAY_SIZE(avila_devices)); avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1); diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index b3bd0e137f6d..68ccd669051b 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include @@ -68,16 +68,21 @@ static struct platform_device dsmg600_flash = { .resource = &dsmg600_flash_resource, }; -static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = { - .sda_pin = DSMG600_SDA_PIN, - .scl_pin = DSMG600_SCL_PIN, +static struct gpiod_lookup_table dsmg600_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", DSMG600_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", DSMG600_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device dsmg600_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &dsmg600_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -269,6 +274,7 @@ static void __init dsmg600_init(void) dsmg600_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&dsmg600_i2c_gpiod_table); i2c_register_board_info(0, dsmg600_i2c_board_info, ARRAY_SIZE(dsmg600_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index 5c4b0c4a1b37..a0350ad15175 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -54,16 +54,21 @@ static struct platform_device fsg_flash = { .resource = &fsg_flash_resource, }; -static struct i2c_gpio_platform_data fsg_i2c_gpio_data = { - .sda_pin = FSG_SDA_PIN, - .scl_pin = FSG_SCL_PIN, +static struct gpiod_lookup_table fsg_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", FSG_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", FSG_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device fsg_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &fsg_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -196,6 +201,7 @@ static void __init fsg_init(void) /* Configure CS2 for operation, 8bit and writable */ *IXP4XX_EXP_CS2 = 0xbfff0002; + gpiod_add_lookup_table(&fsg_i2c_gpiod_table); i2c_register_board_info(0, fsg_i2c_board_info, ARRAY_SIZE(fsg_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c index 80bd9d6d04de..f1529aa3f8e2 100644 --- a/arch/arm/mach-ixp4xx/goramo_mlr.c +++ b/arch/arm/mach-ixp4xx/goramo_mlr.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -78,6 +77,12 @@ static u32 hw_bits = 0xFFFFFFFD; /* assume all hardware present */; static u8 control_value; +/* + * FIXME: this is reimplementing I2C bit-bangining. Move this + * over to using driver/i2c/busses/i2c-gpio.c like all other boards + * and register proper I2C device(s) on the bus for this. (See + * other IXP4xx boards for examples.) + */ static void set_scl(u8 value) { gpio_set_value(GPIO_SCL, !!value); @@ -216,20 +221,6 @@ static struct platform_device device_flash = { .resource = &flash_resource, }; - -/* I^2C interface */ -static struct i2c_gpio_platform_data i2c_data = { - .sda_pin = GPIO_SDA, - .scl_pin = GPIO_SCL, -}; - -static struct platform_device device_i2c = { - .name = "i2c-gpio", - .id = 0, - .dev = { .platform_data = &i2c_data }, -}; - - /* IXP425 2 UART ports */ static struct resource uart_resources[] = { { @@ -411,9 +402,6 @@ static void __init gmlr_init(void) if (hw_bits & CFG_HW_HAS_HSS1) device_tab[devices++] = &device_hss_tab[1]; /* max index 5 */ - if (hw_bits & CFG_HW_HAS_EEPROM) - device_tab[devices++] = &device_i2c; /* max index 6 */ - gpio_request(GPIO_SCL, "SCL/clock"); gpio_request(GPIO_SDA, "SDA/data"); gpio_request(GPIO_STR, "strobe"); diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 93b89291c06b..8937263cec4a 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -122,16 +122,21 @@ static struct platform_device ixdp425_flash_nand = { }; #endif /* CONFIG_MTD_NAND_PLATFORM */ -static struct i2c_gpio_platform_data ixdp425_i2c_gpio_data = { - .sda_pin = IXDP425_SDA_PIN, - .scl_pin = IXDP425_SCL_PIN, +static struct gpiod_lookup_table ixdp425_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", IXDP425_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", IXDP425_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device ixdp425_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &ixdp425_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -245,6 +250,7 @@ static void __init ixdp425_init(void) ixdp425_uart_data[1].flags = 0; } + gpiod_add_lookup_table(&ixdp425_i2c_gpiod_table); platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); } diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 4e0f762bc651..612ec8c63456 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -100,16 +100,21 @@ static struct platform_device nas100d_leds = { .dev.platform_data = &nas100d_led_data, }; -static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = { - .sda_pin = NAS100D_SDA_PIN, - .scl_pin = NAS100D_SCL_PIN, +static struct gpiod_lookup_table nas100d_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NAS100D_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NAS100D_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device nas100d_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &nas100d_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -280,6 +285,7 @@ static void __init nas100d_init(void) nas100d_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&nas100d_i2c_gpiod_table); i2c_register_board_info(0, nas100d_i2c_board_info, ARRAY_SIZE(nas100d_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index 88c025f52d8d..13afb03b50fa 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -68,9 +68,14 @@ static struct platform_device nslu2_flash = { .resource = &nslu2_flash_resource, }; -static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = { - .sda_pin = NSLU2_SDA_PIN, - .scl_pin = NSLU2_SCL_PIN, +static struct gpiod_lookup_table nslu2_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NSLU2_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NSLU2_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct i2c_board_info __initdata nslu2_i2c_board_info [] = { @@ -115,7 +120,7 @@ static struct platform_device nslu2_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &nslu2_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -250,6 +255,7 @@ static void __init nslu2_init(void) nslu2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&nslu2_i2c_gpiod_table); i2c_register_board_info(0, nslu2_i2c_board_info, ARRAY_SIZE(nslu2_i2c_board_info)); diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c index e4d709c8ed32..f034724e01e1 100644 --- a/arch/arm/mach-ks8695/board-acs5k.c +++ b/arch/arm/mach-ks8695/board-acs5k.c @@ -16,7 +16,7 @@ #include #include #include - +#include #include #include #include @@ -38,9 +38,15 @@ #include "generic.h" +static struct gpiod_lookup_table acs5k_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("KS8695", 4, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("KS8695", 5, NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data acs5k_i2c_device_platdata = { - .sda_pin = 4, - .scl_pin = 5, .udelay = 10, }; @@ -95,6 +101,7 @@ static struct i2c_board_info acs5k_i2c_devs[] __initdata = { static void acs5k_i2c_init(void) { /* The gpio interface */ + gpiod_add_lookup_table(&acs5k_i2c_gpiod_table); platform_device_register(&acs5k_i2c_device); /* I2C devices */ i2c_register_board_info(0, acs5k_i2c_devs, diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 29630061e700..94f75632c007 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -320,9 +321,15 @@ static struct soc_camera_link palmz72_iclink = { .flags = SOCAM_DATAWIDTH_8, }; +static struct gpiod_lookup_table palmz72_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", 118, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-pxa", 117, NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data palmz72_i2c_bus_data = { - .sda_pin = 118, - .scl_pin = 117, .udelay = 10, .timeout = 100, }; @@ -369,6 +376,7 @@ static void __init palmz72_camera_init(void) { palmz72_cam_gpio_init(); pxa_set_camera_info(&palmz72_pxacamera_platform_data); + gpiod_add_lookup_table(&palmz72_i2c_gpiod_table); platform_device_register(&palmz72_i2c_bus_device); platform_device_register(&palmz72_camera); } diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index 8e89d91b206b..a680742bee2b 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -458,9 +459,17 @@ static struct platform_device smc91x_device = { }; /* i2c */ +static struct gpiod_lookup_table viper_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_RTC_I2C_SDA_GPIO, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_RTC_I2C_SCL_GPIO, + NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data i2c_bus_data = { - .sda_pin = VIPER_RTC_I2C_SDA_GPIO, - .scl_pin = VIPER_RTC_I2C_SCL_GPIO, .udelay = 10, .timeout = HZ, }; @@ -779,12 +788,20 @@ static int __init viper_tpm_setup(char *str) __setup("tpm=", viper_tpm_setup); +struct gpiod_lookup_table viper_tpm_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_TPM_I2C_SDA_GPIO, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_TPM_I2C_SCL_GPIO, + NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; + static void __init viper_tpm_init(void) { struct platform_device *tpm_device; struct i2c_gpio_platform_data i2c_tpm_data = { - .sda_pin = VIPER_TPM_I2C_SDA_GPIO, - .scl_pin = VIPER_TPM_I2C_SCL_GPIO, .udelay = 10, .timeout = HZ, }; @@ -794,6 +811,7 @@ static void __init viper_tpm_init(void) if (!viper_tpm) return; + gpiod_add_lookup_table(&viper_tpm_i2c_gpiod_table); tpm_device = platform_device_alloc("i2c-gpio", 2); if (tpm_device) { if (!platform_device_add_data(tpm_device, @@ -943,6 +961,7 @@ static void __init viper_init(void) smc91x_device.num_resources--; pxa_set_i2c_info(NULL); + gpiod_add_lookup_table(&viper_i2c_gpiod_table); pwm_add_table(viper_pwm_lookup, ARRAY_SIZE(viper_pwm_lookup)); platform_add_devices(viper_devs, ARRAY_SIZE(viper_devs)); diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index bb3ca9c763de..c6e7e6d8733a 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -323,9 +324,15 @@ static struct platform_device simpad_gpio_leds = { /* * i2c */ +static struct gpiod_lookup_table simpad_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio", GPIO_GPIO21, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio", GPIO_GPIO25, NULL, 1, GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data simpad_i2c_data = { - .sda_pin = GPIO_GPIO21, - .scl_pin = GPIO_GPIO25, .udelay = 10, .timeout = HZ, }; @@ -380,6 +387,7 @@ static int __init simpad_init(void) ARRAY_SIZE(simpad_flash_resources)); sa11x0_register_mcp(&simpad_mcp_data); + gpiod_add_lookup_table(&simpad_i2c_gpiod_table); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if(ret) printk(KERN_WARNING "simpad: Unable to register mq200 framebuffer device"); diff --git a/arch/blackfin/mach-bf533/boards/blackstamp.c b/arch/blackfin/mach-bf533/boards/blackstamp.c index 0ccf0cf4daaf..d801ca5ca6c4 100644 --- a/arch/blackfin/mach-bf533/boards/blackstamp.c +++ b/arch/blackfin/mach-bf533/boards/blackstamp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -362,11 +363,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF8, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF9, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF8, - .scl_pin = GPIO_PF9, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 40, }; /* This hasn't actually been used these pins * are (currently) free pins on the expansion connector */ @@ -462,7 +469,9 @@ static int __init blackstamp_init(void) int ret; printk(KERN_INFO "%s(): registering device resources\n", __func__); - +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif i2c_register_board_info(0, bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info)); diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c index 3625e9eaa8a8..463a72358b0e 100644 --- a/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/arch/blackfin/mach-bf533/boards/ezkit.c @@ -19,6 +19,7 @@ #endif #include #include +#include #include #include #include @@ -390,11 +391,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF1, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF0, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF1, - .scl_pin = GPIO_PF0, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 40, }; @@ -516,6 +523,9 @@ static struct platform_device *ezkit_devices[] __initdata = { static int __init ezkit_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); i2c_register_board_info(0, bfin_i2c_board_info, diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index 23eada79439c..d2479359adb7 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -512,11 +513,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF2, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF3, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF2, - .scl_pin = GPIO_PF3, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 10, }; @@ -848,6 +855,9 @@ static int __init stamp_init(void) printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif i2c_register_board_info(0, bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info)); diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c index 57d1c43726d9..72f757ebaa84 100644 --- a/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/arch/blackfin/mach-bf561/boards/ezkit.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -379,11 +380,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF1, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF0, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF1, - .scl_pin = GPIO_PF0, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 10, }; @@ -633,6 +640,9 @@ static int __init ezkit_init(void) printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif ret = platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); if (ret < 0) return ret; diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c index 6fb6b3faa158..daebc36e5ecb 100644 --- a/arch/mips/alchemy/board-gpr.c +++ b/arch/mips/alchemy/board-gpr.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -218,10 +219,23 @@ static struct platform_device gpr_led_devices = { /* * I2C */ +static struct gpiod_lookup_table gpr_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + /* + * This should be on "GPIO2" which has base at 200 so + * the global numbers 209 and 210 should correspond to + * local offsets 9 and 10. + */ + GPIO_LOOKUP_IDX("alchemy-gpio2", 9, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("alchemy-gpio2", 10, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data gpr_i2c_data = { - .sda_pin = 209, .sda_is_open_drain = 1, - .scl_pin = 210, .scl_is_open_drain = 1, .udelay = 2, /* ~100 kHz */ .timeout = HZ, @@ -295,6 +309,7 @@ arch_initcall(gpr_pci_init); static int __init gpr_dev_init(void) { + gpiod_add_lookup_table(&gpr_i2c_gpiod_table); i2c_register_board_info(0, gpr_i2c_info, ARRAY_SIZE(gpr_i2c_info)); return platform_add_devices(gpr_devices, ARRAY_SIZE(gpr_devices)); diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c index be78298dffb4..a95409063847 100644 --- a/arch/mips/ath79/mach-pb44.c +++ b/arch/mips/ath79/mach-pb44.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "machtypes.h" @@ -33,16 +33,21 @@ #define PB44_KEYS_POLL_INTERVAL 20 /* msecs */ #define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL) -static struct i2c_gpio_platform_data pb44_i2c_gpio_data = { - .sda_pin = PB44_GPIO_I2C_SDA, - .scl_pin = PB44_GPIO_I2C_SCL, +static struct gpiod_lookup_table pb44_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("ath79-gpio", PB44_GPIO_I2C_SDA, + NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("ath79-gpio", PB44_GPIO_I2C_SCL, + NULL, 1, GPIO_ACTIVE_HIGH), + }, }; static struct platform_device pb44_i2c_gpio_device = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &pb44_i2c_gpio_data, + .platform_data = NULL, } }; @@ -103,6 +108,7 @@ static struct ath79_spi_platform_data pb44_spi_data = { static void __init pb44_init(void) { + gpiod_add_lookup_table(&pb44_i2c_gpiod_table); i2c_register_board_info(0, pb44_i2c_board_info, ARRAY_SIZE(pb44_i2c_board_info)); platform_device_register(&pb44_i2c_gpio_device); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 0ef8fcc6ac3a..b4664037eded 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -14,11 +14,12 @@ #include #include #include -#include +#include #include -#include struct i2c_gpio_private_data { + struct gpio_desc *sda; + struct gpio_desc *scl; struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; @@ -27,12 +28,18 @@ struct i2c_gpio_private_data { /* Toggle SDA by changing the direction of the pin */ static void i2c_gpio_setsda_dir(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; - + struct i2c_gpio_private_data *priv = data; + + /* + * This is a way of saying "do not drive + * me actively high" which means emulating open drain. + * The right way to do this is for gpiolib to + * handle this, by the function below. + */ if (state) - gpio_direction_input(pdata->sda_pin); + gpiod_direction_input(priv->sda); else - gpio_direction_output(pdata->sda_pin, 0); + gpiod_direction_output(priv->sda, 0); } /* @@ -42,20 +49,20 @@ static void i2c_gpio_setsda_dir(void *data, int state) */ static void i2c_gpio_setsda_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->sda_pin, state); + gpiod_set_value(priv->sda, state); } /* Toggle SCL by changing the direction of the pin. */ static void i2c_gpio_setscl_dir(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; if (state) - gpio_direction_input(pdata->scl_pin); + gpiod_direction_input(priv->scl); else - gpio_direction_output(pdata->scl_pin, 0); + gpiod_direction_output(priv->scl, 0); } /* @@ -66,44 +73,23 @@ static void i2c_gpio_setscl_dir(void *data, int state) */ static void i2c_gpio_setscl_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->scl_pin, state); + gpiod_set_value(priv->scl, state); } static int i2c_gpio_getsda(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->sda_pin); + return gpiod_get_value(priv->sda); } static int i2c_gpio_getscl(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->scl_pin); -} - -static int of_i2c_gpio_get_pins(struct device_node *np, - unsigned int *sda_pin, unsigned int *scl_pin) -{ - if (of_gpio_count(np) < 2) - return -ENODEV; - - *sda_pin = of_get_gpio(np, 0); - *scl_pin = of_get_gpio(np, 1); - - if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { - pr_err("%pOF: invalid GPIO pins, sda=%d/scl=%d\n", - np, *sda_pin, *scl_pin); - return -ENODEV; - } - - return 0; + return gpiod_get_value(priv->scl); } static void of_i2c_gpio_get_props(struct device_node *np, @@ -130,64 +116,65 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; - unsigned int sda_pin, scl_pin; int ret; - /* First get the GPIO pins; if it fails, we'll defer the probe. */ - if (pdev->dev.of_node) { - ret = of_i2c_gpio_get_pins(pdev->dev.of_node, - &sda_pin, &scl_pin); - if (ret) - return ret; - } else { - if (!dev_get_platdata(&pdev->dev)) - return -ENXIO; - pdata = dev_get_platdata(&pdev->dev); - sda_pin = pdata->sda_pin; - scl_pin = pdata->scl_pin; - } + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); - if (ret) { + /* First get the GPIO pins; if it fails, we'll defer the probe. */ + priv->sda = devm_gpiod_get_index(&pdev->dev, NULL, 0, GPIOD_OUT_HIGH); + if (IS_ERR(priv->sda)) { + ret = PTR_ERR(priv->sda); + /* FIXME: hack in the old code, is this really necessary? */ if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ + ret = -EPROBE_DEFER; return ret; } - ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); - if (ret) { + priv->scl = devm_gpiod_get_index(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); + if (IS_ERR(priv->scl)) { + ret = PTR_ERR(priv->scl); + /* FIXME: hack in the old code, is this really necessary? */ if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ + ret = -EPROBE_DEFER; return ret; } - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; if (pdev->dev.of_node) { - pdata->sda_pin = sda_pin; - pdata->scl_pin = scl_pin; of_i2c_gpio_get_props(pdev->dev.of_node, pdata); } else { - memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); + /* + * If all platform data settings are zero it is OK + * to not provide any platform data from the board. + */ + if (dev_get_platdata(&pdev->dev)) + memcpy(pdata, dev_get_platdata(&pdev->dev), + sizeof(*pdata)); } + /* + * FIXME: this is a hack emulating the open drain emulation + * that gpiolib can already do for us. Make all clients properly + * flag their lines as open drain and get rid of this property + * and the special callback. + */ if (pdata->sda_is_open_drain) { - gpio_direction_output(pdata->sda_pin, 1); + gpiod_direction_output(priv->sda, 1); bit_data->setsda = i2c_gpio_setsda_val; } else { - gpio_direction_input(pdata->sda_pin); + gpiod_direction_input(priv->sda); bit_data->setsda = i2c_gpio_setsda_dir; } if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { - gpio_direction_output(pdata->scl_pin, 1); + gpiod_direction_output(priv->scl, 1); bit_data->setscl = i2c_gpio_setscl_val; } else { - gpio_direction_input(pdata->scl_pin); + gpiod_direction_input(priv->scl); bit_data->setscl = i2c_gpio_setscl_dir; } @@ -207,7 +194,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) else bit_data->timeout = HZ / 10; /* 100 ms */ - bit_data->data = pdata; + bit_data->data = priv; adap->owner = THIS_MODULE; if (pdev->dev.of_node) @@ -227,8 +214,13 @@ static int i2c_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", - pdata->sda_pin, pdata->scl_pin, + /* + * FIXME: using global GPIO numbers is not helpful. If/when we + * get accessors to get the actual name of the GPIO line, + * from the descriptor, then provide that instead. + */ + dev_info(&pdev->dev, "using lines %u (SDA) and %u (SCL%s)\n", + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), pdata->scl_is_output_only ? ", no clock stretching" : ""); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 40534352e574..4d40d013a412 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1107,14 +1108,6 @@ static void sm501_gpio_remove(struct sm501_devdata *sm) kfree(gpio->regs_res); } -static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) -{ - struct sm501_gpio *gpio = &sm->gpio; - int base = (pin < 32) ? gpio->low.gpio.base : gpio->high.gpio.base; - - return (pin % 32) + base; -} - static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) { return sm->gpio.registered; @@ -1129,11 +1122,6 @@ static inline void sm501_gpio_remove(struct sm501_devdata *sm) { } -static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) -{ - return -1; -} - static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) { return 0; @@ -1145,20 +1133,37 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, { struct i2c_gpio_platform_data *icd; struct platform_device *pdev; + struct gpiod_lookup_table *lookup; pdev = sm501_create_subdev(sm, "i2c-gpio", 0, sizeof(struct i2c_gpio_platform_data)); if (!pdev) return -ENOMEM; - icd = dev_get_platdata(&pdev->dev); - - /* We keep the pin_sda and pin_scl fields relative in case the - * same platform data is passed to >1 SM501. - */ + /* Create a gpiod lookup using gpiochip-local offsets */ + lookup = devm_kzalloc(&pdev->dev, + sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup), + GFP_KERNEL); + lookup->dev_id = "i2c-gpio"; + if (iic->pin_sda < 32) + lookup->table[0].chip_label = "SM501-LOW"; + else + lookup->table[0].chip_label = "SM501-HIGH"; + lookup->table[0].chip_hwnum = iic->pin_sda % 32; + lookup->table[0].con_id = NULL; + lookup->table[0].idx = 0; + lookup->table[0].flags = GPIO_ACTIVE_HIGH; + if (iic->pin_scl < 32) + lookup->table[1].chip_label = "SM501-LOW"; + else + lookup->table[1].chip_label = "SM501-HIGH"; + lookup->table[1].chip_hwnum = iic->pin_scl % 32; + lookup->table[1].con_id = NULL; + lookup->table[1].idx = 1; + lookup->table[1].flags = GPIO_ACTIVE_HIGH; + gpiod_add_lookup_table(lookup); - icd->sda_pin = sm501_gpio_pin2nr(sm, iic->pin_sda); - icd->scl_pin = sm501_gpio_pin2nr(sm, iic->pin_scl); + icd = dev_get_platdata(&pdev->dev); icd->timeout = iic->timeout; icd->udelay = iic->udelay; @@ -1170,9 +1175,9 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, pdev->id = iic->bus_num; - dev_info(sm->dev, "registering i2c-%d: sda=%d (%d), scl=%d (%d)\n", + dev_info(sm->dev, "registering i2c-%d: sda=%d, scl=%d\n", iic->bus_num, - icd->sda_pin, iic->pin_sda, icd->scl_pin, iic->pin_scl); + iic->pin_sda, iic->pin_scl); return sm501_register_device(sm, pdev); } diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h index c1bcb1f1d73b..352c1426fd4d 100644 --- a/include/linux/i2c-gpio.h +++ b/include/linux/i2c-gpio.h @@ -12,8 +12,6 @@ /** * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio - * @sda_pin: GPIO pin ID to use for SDA - * @scl_pin: GPIO pin ID to use for SCL * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz * @timeout: clock stretching timeout in jiffies. If the slave keeps * SCL low for longer than this, the transfer will time out. @@ -26,8 +24,6 @@ * @scl_is_output_only: SCL output drivers cannot be turned off. */ struct i2c_gpio_platform_data { - unsigned int sda_pin; - unsigned int scl_pin; int udelay; int timeout; unsigned int sda_is_open_drain:1; -- cgit v1.2.3-55-g7522 From 7bb75029ef34838604357350b4f24d6535e9d01f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 10 Sep 2017 19:54:21 +0200 Subject: i2c: gpio: Enforce open drain through gpiolib The I2C GPIO bitbang driver currently emulates open drain behaviour by implementing what the gpiolib already does: not actively driving the line high, instead setting it to input. This makes no sense. Use the new facility in gpiolib to request the lines enforced into open drain mode, and let the open drain emulation already present in the gpiolib kick in and handle this. As a bonus: if the GPIO driver in the back-end actually supports open drain in hardware using the .set_config() callback, it will be utilized. That's correct: we never used that hardware feature before, instead relying on emulating open drain even if the GPIO controller could actually handle this for us. Users will sometimes get messages like this: gpio-485 (?): enforced open drain please flag it properly in DT/ACPI DSDT/board file gpio-486 (?): enforced open drain please flag it properly in DT/ACPI DSDT/board file i2c-gpio gpio-i2c: using lines 485 (SDA) and 486 (SCL) Which is completely proper: since the line is used as open drain, it should actually be flagged properly with e.g. gpios = <&gpio0 5 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>, <&gpio0 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; Or similar facilities in board file descriptor tables or ACPI DSDT. Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/i2c/busses/i2c-gpio.c | 102 ++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 63 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index b4664037eded..97b9c29e9429 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -25,23 +25,6 @@ struct i2c_gpio_private_data { struct i2c_gpio_platform_data pdata; }; -/* Toggle SDA by changing the direction of the pin */ -static void i2c_gpio_setsda_dir(void *data, int state) -{ - struct i2c_gpio_private_data *priv = data; - - /* - * This is a way of saying "do not drive - * me actively high" which means emulating open drain. - * The right way to do this is for gpiolib to - * handle this, by the function below. - */ - if (state) - gpiod_direction_input(priv->sda); - else - gpiod_direction_output(priv->sda, 0); -} - /* * Toggle SDA by changing the output value of the pin. This is only * valid for pins configured as open drain (i.e. setting the value @@ -54,17 +37,6 @@ static void i2c_gpio_setsda_val(void *data, int state) gpiod_set_value(priv->sda, state); } -/* Toggle SCL by changing the direction of the pin. */ -static void i2c_gpio_setscl_dir(void *data, int state) -{ - struct i2c_gpio_private_data *priv = data; - - if (state) - gpiod_direction_input(priv->scl); - else - gpiod_direction_output(priv->scl, 0); -} - /* * Toggle SCL by changing the output value of the pin. This is used * for pins that are configured as open drain and for output-only @@ -116,30 +88,13 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; + enum gpiod_flags gflags; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - /* First get the GPIO pins; if it fails, we'll defer the probe. */ - priv->sda = devm_gpiod_get_index(&pdev->dev, NULL, 0, GPIOD_OUT_HIGH); - if (IS_ERR(priv->sda)) { - ret = PTR_ERR(priv->sda); - /* FIXME: hack in the old code, is this really necessary? */ - if (ret == -EINVAL) - ret = -EPROBE_DEFER; - return ret; - } - priv->scl = devm_gpiod_get_index(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(priv->scl)) { - ret = PTR_ERR(priv->scl); - /* FIXME: hack in the old code, is this really necessary? */ - if (ret == -EINVAL) - ret = -EPROBE_DEFER; - return ret; - } - adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; @@ -157,27 +112,48 @@ static int i2c_gpio_probe(struct platform_device *pdev) } /* - * FIXME: this is a hack emulating the open drain emulation - * that gpiolib can already do for us. Make all clients properly - * flag their lines as open drain and get rid of this property - * and the special callback. + * First get the GPIO pins; if it fails, we'll defer the probe. + * If the SDA line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. */ - if (pdata->sda_is_open_drain) { - gpiod_direction_output(priv->sda, 1); - bit_data->setsda = i2c_gpio_setsda_val; - } else { - gpiod_direction_input(priv->sda); - bit_data->setsda = i2c_gpio_setsda_dir; + if (pdata->sda_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->sda = devm_gpiod_get_index(&pdev->dev, NULL, 0, gflags); + if (IS_ERR(priv->sda)) { + ret = PTR_ERR(priv->sda); + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + ret = -EPROBE_DEFER; + return ret; } - - if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { - gpiod_direction_output(priv->scl, 1); - bit_data->setscl = i2c_gpio_setscl_val; - } else { - gpiod_direction_input(priv->scl); - bit_data->setscl = i2c_gpio_setscl_dir; + /* + * If the SCL line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->scl_is_open_drain) + gflags = GPIOD_OUT_LOW; + else + gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + priv->scl = devm_gpiod_get_index(&pdev->dev, NULL, 1, gflags); + if (IS_ERR(priv->scl)) { + ret = PTR_ERR(priv->scl); + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + ret = -EPROBE_DEFER; + return ret; } + bit_data->setsda = i2c_gpio_setsda_val; + bit_data->setscl = i2c_gpio_setscl_val; + if (!pdata->scl_is_output_only) bit_data->getscl = i2c_gpio_getscl; bit_data->getsda = i2c_gpio_getsda; -- cgit v1.2.3-55-g7522 From b9ab0517efc0111b516878ab872e2b3dd7bb40a9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 10 Sep 2017 23:15:35 +0200 Subject: i2c: gpio: Local vars in probe By creating local variables for *dev and *np, the code become much easier to read, in my opinion. Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/i2c/busses/i2c-gpio.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 97b9c29e9429..a702e493275c 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -88,10 +88,12 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; enum gpiod_flags gflags; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -99,16 +101,15 @@ static int i2c_gpio_probe(struct platform_device *pdev) bit_data = &priv->bit_data; pdata = &priv->pdata; - if (pdev->dev.of_node) { - of_i2c_gpio_get_props(pdev->dev.of_node, pdata); + if (np) { + of_i2c_gpio_get_props(np, pdata); } else { /* * If all platform data settings are zero it is OK * to not provide any platform data from the board. */ - if (dev_get_platdata(&pdev->dev)) - memcpy(pdata, dev_get_platdata(&pdev->dev), - sizeof(*pdata)); + if (dev_get_platdata(dev)) + memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); } /* @@ -123,7 +124,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - priv->sda = devm_gpiod_get_index(&pdev->dev, NULL, 0, gflags); + priv->sda = devm_gpiod_get_index(dev, NULL, 0, gflags); if (IS_ERR(priv->sda)) { ret = PTR_ERR(priv->sda); /* FIXME: hack in the old code, is this really necessary? */ @@ -142,7 +143,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_LOW; else gflags = GPIOD_OUT_LOW_OPEN_DRAIN; - priv->scl = devm_gpiod_get_index(&pdev->dev, NULL, 1, gflags); + priv->scl = devm_gpiod_get_index(dev, NULL, 1, gflags); if (IS_ERR(priv->scl)) { ret = PTR_ERR(priv->scl); /* FIXME: hack in the old code, is this really necessary? */ @@ -173,15 +174,15 @@ static int i2c_gpio_probe(struct platform_device *pdev) bit_data->data = priv; adap->owner = THIS_MODULE; - if (pdev->dev.of_node) - strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + if (np) + strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; + adap->dev.parent = dev; + adap->dev.of_node = np; adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); @@ -195,7 +196,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) * get accessors to get the actual name of the GPIO line, * from the descriptor, then provide that instead. */ - dev_info(&pdev->dev, "using lines %u (SDA) and %u (SCL%s)\n", + dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), pdata->scl_is_output_only ? ", no clock stretching" : ""); -- cgit v1.2.3-55-g7522 From 05c74778858d7d9907d607172fcc9646b70b6364 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 16 Sep 2017 23:56:49 +0200 Subject: i2c: gpio: Add support for named gpios in DT This adds support for using the "sda" and "scl" GPIOs in device tree instead of anonymously using index 0 and 1 of the "gpios" property. We add a helper function to retrieve the GPIO descriptors and some explicit error handling since the probe may have to be deferred. At least this happened to me when moving to using named "sda" and "scl" lines (all of a sudden this started to probe before the GPIO driver) so we need to gracefully defer probe when we ge -ENOENT in the error pointer. Suggested-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/i2c/busses/i2c-gpio.c | 59 +++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index a702e493275c..d80ea6ce91bb 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -82,6 +82,42 @@ static void of_i2c_gpio_get_props(struct device_node *np, of_property_read_bool(np, "i2c-gpio,scl-output-only"); } +static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags gflags) +{ + struct gpio_desc *retdesc; + int ret; + + retdesc = devm_gpiod_get(dev, con_id, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from name %s\n", con_id); + return retdesc; + } + + retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from index %u\n", index); + return retdesc; + } + + ret = PTR_ERR(retdesc); + + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + retdesc = ERR_PTR(-EPROBE_DEFER); + + /* This happens if the GPIO driver is not yet probed, let's defer */ + if (ret == -ENOENT) + retdesc = ERR_PTR(-EPROBE_DEFER); + + if (ret != -EPROBE_DEFER) + dev_err(dev, "error trying to get descriptor: %d\n", ret); + + return retdesc; +} + static int i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; @@ -124,14 +160,10 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - priv->sda = devm_gpiod_get_index(dev, NULL, 0, gflags); - if (IS_ERR(priv->sda)) { - ret = PTR_ERR(priv->sda); - /* FIXME: hack in the old code, is this really necessary? */ - if (ret == -EINVAL) - ret = -EPROBE_DEFER; - return ret; - } + priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); + if (IS_ERR(priv->sda)) + return PTR_ERR(priv->sda); + /* * If the SCL line is marked from platform data or device tree as * "open drain" it means something outside of our control is making @@ -143,14 +175,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_LOW; else gflags = GPIOD_OUT_LOW_OPEN_DRAIN; - priv->scl = devm_gpiod_get_index(dev, NULL, 1, gflags); - if (IS_ERR(priv->scl)) { - ret = PTR_ERR(priv->scl); - /* FIXME: hack in the old code, is this really necessary? */ - if (ret == -EINVAL) - ret = -EPROBE_DEFER; - return ret; - } + priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(priv->scl)) + return PTR_ERR(priv->scl); bit_data->setsda = i2c_gpio_setsda_val; bit_data->setscl = i2c_gpio_setscl_val; -- cgit v1.2.3-55-g7522 From 93367bfca98f36cece57c01dbce6ea1b4ac58245 Mon Sep 17 00:00:00 2001 From: Claudio Foellmi Date: Wed, 4 Oct 2017 11:43:45 +0200 Subject: i2c: omap: Trigger bus recovery in lockup case A very conservative check for bus activity (to prevent interference in multimaster setups) prevented the bus recovery methods from being triggered in the case that SDA or SCL was stuck low. This defeats the purpose of the recovery mechanism, which was introduced for exactly this situation (a slave device keeping SDA pulled down). Also added a check to make sure SDA is low before attempting recovery. If SDA is not stuck low, recovery will not help, so we can skip it. Note that bus lockups can persist across reboots. The only other options are to reset or power cycle the offending slave device, and many i2c slaves do not even have a reset pin. If we see that one of the lines is low for the entire timeout duration, we can actually be sure that there is no other master driving the bus. It is therefore save for us to attempt a bus recovery. Signed-off-by: Claudio Foellmi Tested-by: Vignesh R Reviewed-by: Grygorii Strashko [wsa: fixed one return code to -EBUSY] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 23c2ea2baedc..b9172f08fd05 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -486,6 +486,22 @@ static int omap_i2c_init(struct omap_i2c_dev *omap) return 0; } +/* + * Try bus recovery, but only if SDA is actually low. + */ +static int omap_i2c_recover_bus(struct omap_i2c_dev *omap) +{ + u16 systest; + + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); + if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && + (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) + return 0; /* bus seems to already be fine */ + if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC)) + return -EBUSY; /* recovery would not fix SCL */ + return i2c_recover_bus(&omap->adapter); +} + /* * Waiting on Bus Busy */ @@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) timeout = jiffies + OMAP_I2C_TIMEOUT; while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { if (time_after(jiffies, timeout)) - return i2c_recover_bus(&omap->adapter); + return omap_i2c_recover_bus(omap); msleep(1); } @@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) } if (time_after(jiffies, timeout)) { + /* + * SDA or SCL were low for the entire timeout without + * any activity detected. Most likely, a slave is + * locking up the bus with no master driving the clock. + */ dev_warn(omap->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + return omap_i2c_recover_bus(omap); } msleep(1); -- cgit v1.2.3-55-g7522 From af3366753fb530528349e05e0953b7357504084a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 27 Oct 2017 22:24:44 +0200 Subject: i2c: mpc: remove useless variable initialization cppcheck rightfully says: drivers/i2c/busses/i2c-mpc.c:329: style: Variable 'node' is reassigned a value before the old one has been used. Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 2b221a514974..950a9d74f54d 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -322,7 +322,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { static u32 mpc_i2c_get_sec_cfg_8xxx(void) { - struct device_node *node = NULL; + struct device_node *node; u32 __iomem *reg; u32 val = 0; -- cgit v1.2.3-55-g7522 From da24b8240fe6afdeef388a2ef1da662b25675a5a Mon Sep 17 00:00:00 2001 From: Hoan Tran Date: Mon, 30 Oct 2017 15:24:16 -0700 Subject: i2c: xgene-slimpro: Support v2 This patch supports xgene-slimpro-i2c v2 which uses the non-cachable memory as the PCC shared memory. Signed-off-by: Hoan Tran Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xgene-slimpro.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 7e89ba6fcf6f..a7ac746018ad 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -129,6 +129,11 @@ struct slimpro_i2c_dev { #define to_slimpro_i2c_dev(cl) \ container_of(cl, struct slimpro_i2c_dev, mbox_client) +enum slimpro_i2c_version { + XGENE_SLIMPRO_I2C_V1 = 0, + XGENE_SLIMPRO_I2C_V2 = 1, +}; + /* * This function tests and clears a bitmask then returns its old value */ @@ -476,6 +481,15 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) } } else { struct acpi_pcct_hw_reduced *cppc_ss; + const struct acpi_device_id *acpi_id; + int version = XGENE_SLIMPRO_I2C_V1; + + acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, + &pdev->dev); + if (!acpi_id) + return -EINVAL; + + version = (int)acpi_id->driver_data; if (device_property_read_u32(&pdev->dev, "pcc-channel", &ctx->mbox_idx)) @@ -514,9 +528,16 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) */ ctx->comm_base_addr = cppc_ss->base_address; if (ctx->comm_base_addr) { - ctx->pcc_comm_addr = memremap(ctx->comm_base_addr, - cppc_ss->length, - MEMREMAP_WB); + if (version == XGENE_SLIMPRO_I2C_V2) + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WT); + else + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WB); } else { dev_err(&pdev->dev, "Failed to get PCC comm region\n"); rc = -ENOENT; @@ -581,7 +602,8 @@ MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids); #ifdef CONFIG_ACPI static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = { - {"APMC0D40", 0}, + {"APMC0D40", XGENE_SLIMPRO_I2C_V1}, + {"APMC0D8B", XGENE_SLIMPRO_I2C_V2}, {} }; MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); -- cgit v1.2.3-55-g7522 From 7b43dd19c9b13a3f5478b9d88a49a5495399ad29 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 31 Oct 2017 16:21:35 +0200 Subject: i2c: Make i2c_unregister_device() NULL-aware It's a common pattern to be NULL-aware when freeing resources. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 7b08f3446bfc..706164b4c5be 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -819,6 +819,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { + if (!client) + return; if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); if (ACPI_COMPANION(&client->dev)) @@ -1436,8 +1438,7 @@ static int __unregister_client(struct device *dev, void *dummy) static int __unregister_dummy(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); - if (client) - i2c_unregister_device(client); + i2c_unregister_device(client); return 0; } -- cgit v1.2.3-55-g7522 From bfd9621259970904b25ad198030275328f09ed46 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 31 Oct 2017 16:21:36 +0200 Subject: i2c: taos-evm: Remove duplicate NULL check Since i2c_unregister_device() became NULL-aware we may remove duplicate NULL check. Signed-off-by: Andy Shevchenko Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-taos-evm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index addd90a8cb59..7c7fc01116a1 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -282,8 +282,7 @@ static void taos_disconnect(struct serio *serio) { struct taos_data *taos = serio_get_drvdata(serio); - if (taos->client) - i2c_unregister_device(taos->client); + i2c_unregister_device(taos->client); i2c_del_adapter(&taos->adapter); serio_close(serio); kfree(taos); -- cgit v1.2.3-55-g7522 From 620c50dc0b301f09b85ce27022d8f7420bf14e7f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 31 Oct 2017 16:21:37 +0200 Subject: i2c: thunderx: Remove duplicate NULL check Since i2c_unregister_device() became NULL-aware we may remove duplicate NULL check. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-thunderx-pcidrv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index 1a7cad874756..19f8eec38717 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -143,8 +143,7 @@ static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c, static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c) { - if (i2c->ara) - i2c_unregister_device(i2c->ara); + i2c_unregister_device(i2c->ara); } static int thunder_i2c_probe_pci(struct pci_dev *pdev, -- cgit v1.2.3-55-g7522 From edd20e95bca4a5434f264d8ab40d729761479825 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 1 Nov 2017 10:53:30 +1030 Subject: i2c: aspeed: Deassert reset in probe In order to use i2c from a cold boot, the i2c peripheral must be taken out of reset. We request a shared reset controller each time a bus driver is loaded, as the reset is shared between the 14 i2c buses. On remove the reset is asserted, which only touches the hardware once the last i2c bus is removed. The reset is required as the I2C buses will not work without releasing the reset. Previously the driver only worked with out of tree hacks that released this reset before the driver was loaded. Update the device tree bindings to reflect this. Signed-off-by: Joel Stanley Acked-by: Rob Herring Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-aspeed.txt | 7 +++++-- drivers/i2c/busses/i2c-aspeed.c | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt index bd6480b19535..e7106bfc1f13 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt @@ -7,7 +7,9 @@ Required Properties: - compatible : should be "aspeed,ast2400-i2c-bus" or "aspeed,ast2500-i2c-bus" - clocks : root clock of bus, should reference the APB - clock + clock in the second cell +- resets : phandle to reset controller with the reset number in + the second cell - interrupts : interrupt number - interrupt-parent : interrupt controller for bus, should reference a aspeed,ast2400-i2c-ic or aspeed,ast2500-i2c-ic @@ -40,7 +42,8 @@ i2c { #interrupt-cells = <1>; reg = <0x40 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <0>; interrupt-parent = <&i2c_ic>; diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 284f8670dbeb..7d4aeb4465b3 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -27,6 +27,7 @@ #include #include #include +#include #include /* I2C Register */ @@ -132,6 +133,7 @@ struct aspeed_i2c_bus { struct i2c_adapter adap; struct device *dev; void __iomem *base; + struct reset_control *rst; /* Synchronizes I/O mem access to base. */ spinlock_t lock; struct completion cmd_complete; @@ -847,6 +849,14 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) /* We just need the clock rate, we don't actually use the clk object. */ devm_clk_put(&pdev->dev, parent_clk); + bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(bus->rst)) { + dev_err(&pdev->dev, + "missing or invalid reset controller device tree entry"); + return PTR_ERR(bus->rst); + } + reset_control_deassert(bus->rst); + ret = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &bus->bus_frequency); if (ret < 0) { @@ -917,6 +927,8 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) spin_unlock_irqrestore(&bus->lock, flags); + reset_control_assert(bus->rst); + i2c_del_adapter(&bus->adap); return 0; -- cgit v1.2.3-55-g7522