From 9fd12f385720a85b4ce9a3cb98e66d470a5efd20 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 24 Nov 2023 11:16:10 +0100 Subject: i2c: Don't let i2c adapters declare I2C_CLASS_SPD support if they support I2C_CLASS_HWMON After removal of the legacy eeprom driver the only remaining I2C client device driver supporting I2C_CLASS_SPD is jc42. Because this driver also supports I2C_CLASS_HWMON, adapters don't have to declare support for I2C_CLASS_SPD if they support I2C_CLASS_HWMON. It's one step towards getting rid of I2C_CLASS_SPD mid-term. Signed-off-by: Heiner Kallweit Acked-by: Andi Shyti Acked-by: Jim Cromie # for SCX Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ali1535.c | 2 +- drivers/i2c/busses/i2c-ali1563.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 2 +- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-amd8111.c | 2 +- drivers/i2c/busses/i2c-elektor.c | 2 +- drivers/i2c/busses/i2c-gpio.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 2 +- drivers/i2c/busses/i2c-iop3xx.c | 2 +- drivers/i2c/busses/i2c-isch.c | 2 +- drivers/i2c/busses/i2c-kempld.c | 3 +-- drivers/i2c/busses/i2c-mlxcpld.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-pasemi-pci.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-scmi.c | 2 +- drivers/i2c/busses/i2c-sh7760.c | 2 +- drivers/i2c/busses/i2c-sibyte.c | 4 ++-- drivers/i2c/busses/i2c-sis5595.c | 2 +- drivers/i2c/busses/i2c-sis630.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-viapro.c | 2 +- drivers/i2c/busses/scx200_acb.c | 2 +- 24 files changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index ee83c4581bce..461eb23f9d47 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -477,7 +477,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 55a9e93fbfeb..307fb0666ecb 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -390,7 +390,7 @@ static const struct i2c_algorithm ali1563_algorithm = { static struct i2c_adapter ali1563_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &ali1563_algorithm, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 0231c5be6354..d2fa30deb054 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -461,7 +461,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index ef1307a258e9..208310db906d 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -285,7 +285,7 @@ static const struct i2c_algorithm smbus_algorithm = { struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 1ed7e945bb6d..42a9b1221065 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -449,7 +449,7 @@ static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus2 AMD8111 adapter at %04x", smbus->base); - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index b0f50dce9d0f..cfe8665cacd2 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -188,7 +188,7 @@ static struct i2c_algo_pcf_data pcf_isa_data = { static struct i2c_adapter pcf_isa_ops = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo_data = &pcf_isa_data, .name = "i2c-elektor", }; diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index fb35a75fe0e3..df2b183caa23 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -444,7 +444,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) 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->class = I2C_CLASS_HWMON; adap->dev.parent = dev; device_set_node(&adap->dev, fwnode); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 408820319ec4..7fb87b78923e 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -739,7 +739,7 @@ static int iic_probe(struct platform_device *ofdev) adap->dev.of_node = of_node_get(np); strscpy(adap->name, "IBM IIC", sizeof(adap->name)); i2c_set_adapdata(adap, dev); - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON; adap->algo = &iic_algo; adap->timeout = HZ; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index f2f7ebeeaecb..2e5f0165c3d3 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -478,7 +478,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) memcpy(new_adapter->name, pdev->name, strlen(pdev->name)); new_adapter->owner = THIS_MODULE; - new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + new_adapter->class = I2C_CLASS_HWMON; new_adapter->dev.parent = &pdev->dev; new_adapter->dev.of_node = pdev->dev.of_node; new_adapter->nr = pdev->id; diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 1dc1ceaa4443..416a9968ed28 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -249,7 +249,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sch_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index e01d75308288..c3a529a73b5b 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -283,8 +283,7 @@ static const struct i2c_algorithm kempld_i2c_algorithm = { static const struct i2c_adapter kempld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-kempld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | - I2C_CLASS_DEPRECATED, + .class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED, .algo = &kempld_i2c_algorithm, }; diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 6fec64ea67fb..099291a0411d 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -477,7 +477,7 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext2 = { static struct i2c_adapter mlxcpld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-mlxcpld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &mlxcpld_i2c_algo, .quirks = &mlxcpld_i2c_quirks, .retries = MLXCPLD_I2C_RETR_NUM, diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 38d203d93eee..fab662e6bc08 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -349,7 +349,7 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, return -EBUSY; } smbus->adapter.owner = THIS_MODULE; - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; diff --git a/drivers/i2c/busses/i2c-pasemi-pci.c b/drivers/i2c/busses/i2c-pasemi-pci.c index cfc89e04eb94..77f90c7436ed 100644 --- a/drivers/i2c/busses/i2c-pasemi-pci.c +++ b/drivers/i2c/busses/i2c-pasemi-pci.c @@ -56,7 +56,7 @@ static int pasemi_smb_pci_probe(struct pci_dev *dev, if (!smbus->ioaddr) return -EBUSY; - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; error = pasemi_i2c_common_probe(smbus); if (error) return error; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 809fbd014cd6..6a0392172b2f 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -943,7 +943,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, } adap->owner = THIS_MODULE; - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON; adap->algo = sb800_main ? &piix4_smbus_algorithm_sb800 : &smbus_algorithm; diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 421735acfa14..d7af8e0d7599 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -385,7 +385,7 @@ static int smbus_cmi_probe(struct platform_device *device) smbus_cmi->adapter.owner = THIS_MODULE; smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm; smbus_cmi->adapter.algo_data = smbus_cmi; - smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus_cmi->adapter.class = I2C_CLASS_HWMON; smbus_cmi->adapter.dev.parent = &device->dev; ret = i2c_add_adapter(&smbus_cmi->adapter); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 1ad2a26156d1..8a043f5fca1e 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -477,7 +477,7 @@ static int sh7760_i2c_probe(struct platform_device *pdev) id->adap.nr = pdev->id; id->adap.algo = &sh7760_i2c_algo; - id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + id->adap.class = I2C_CLASS_HWMON; id->adap.retries = 3; id->adap.algo_data = id; id->adap.dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 8f71f01cb169..49f8f4f1b0f0 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -142,7 +142,7 @@ static struct i2c_algo_sibyte_data sibyte_board_data[2] = { static struct i2c_adapter sibyte_board_adapter[2] = { { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = NULL, .algo_data = &sibyte_board_data[0], .nr = 0, @@ -150,7 +150,7 @@ static struct i2c_adapter sibyte_board_adapter[2] = { }, { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = NULL, .algo_data = &sibyte_board_data[1], .nr = 1, diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 486f1e9dfb74..32476dc10ad6 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -353,7 +353,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 87d56250d78a..3505cf29cedd 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -493,7 +493,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .retries = 3 }; diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index cde8003985a5..77529dda6fcd 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -228,7 +228,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index ad4f09c7f027..7ed29992a97f 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -70,7 +70,7 @@ static struct i2c_algo_bit_data bit_data = { static struct i2c_adapter vt586b_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .name = "VIA i2c", .algo_data = &bit_data, }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 970ccdcbb889..2cc7bba3b8bf 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -304,7 +304,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 83c1db610f54..3648382b885a 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -427,7 +427,7 @@ static struct scx200_acb_iface *scx200_create_iface(const char *text, snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index); adapter->owner = THIS_MODULE; adapter->algo = &scx200_acb_algorithm; - adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = dev; mutex_init(&iface->mutex); -- cgit v1.2.3 From c1cc7ccb0ff7596a7025a844d29487df0efd40b2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 24 Nov 2023 11:16:14 +0100 Subject: i2c: stub: Don't let i2c adapters declare I2C_CLASS_SPD support if they support I2C_CLASS_HWMON After removal of the legacy eeprom driver the only remaining I2C client device driver supporting I2C_CLASS_SPD is jc42. Because this driver also supports I2C_CLASS_HWMON, adapters don't have to declare support for I2C_CLASS_SPD if they support I2C_CLASS_HWMON. It's one step towards getting rid of I2C_CLASS_SPD mid-term. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c index d642cad219d9..09e7b7bf4c5f 100644 --- a/drivers/i2c/i2c-stub.c +++ b/drivers/i2c/i2c-stub.c @@ -308,7 +308,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter stub_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .name = "SMBus stub driver", }; -- cgit v1.2.3 From 73febd775bdbdb98c81255ff85773ac410ded5c4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 12 Nov 2023 17:54:41 -0500 Subject: i2c: create debugfs entry per adapter Two drivers already implement custom debugfs handling for their i2c_adapter and more will come. So, let the core create a debugfs directory per adapter and pass that to drivers for their debugfs files. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index eac90a3cf61a..f6c828bbd166 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key); static bool is_registered; +static struct dentry *i2c_debugfs_root; + int i2c_transfer_trace_reg(void) { static_branch_inc(&i2c_trace_msg_key); @@ -1524,6 +1527,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } + adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root); + res = i2c_setup_smbus_alert(adap); if (res) goto out_reg; @@ -1563,6 +1568,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return 0; out_reg: + debugfs_remove_recursive(adap->debugfs); init_completion(&adap->dev_released); device_unregister(&adap->dev); wait_for_completion(&adap->dev_released); @@ -1764,6 +1770,8 @@ void i2c_del_adapter(struct i2c_adapter *adap) i2c_host_notify_irq_teardown(adap); + debugfs_remove_recursive(adap->debugfs); + /* wait until all references to the device are gone * * FIXME: This is old code and should ideally be replaced by an @@ -2061,6 +2069,8 @@ static int __init i2c_init(void) is_registered = true; + i2c_debugfs_root = debugfs_create_dir("i2c", NULL); + #ifdef CONFIG_I2C_COMPAT i2c_adapter_compat_class = class_compat_register("i2c-adapter"); if (!i2c_adapter_compat_class) { @@ -2099,6 +2109,7 @@ static void __exit i2c_exit(void) #ifdef CONFIG_I2C_COMPAT class_compat_unregister(i2c_adapter_compat_class); #endif + debugfs_remove_recursive(i2c_debugfs_root); bus_unregister(&i2c_bus_type); tracepoint_synchronize_unregister(); } -- cgit v1.2.3 From c66520c02c2f5b75e4f06a83ece4382fe2f92cfc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 12 Nov 2023 17:59:10 -0500 Subject: i2c: gpio: move to per-adapter debugfs directory The I2C core now provides a per-adapter debugfs directory. Use it instead of creating a custom one. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index df2b183caa23..4f1411b1a775 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -25,7 +25,6 @@ struct i2c_gpio_private_data { struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR - struct dentry *debug_dir; /* these must be protected by bus lock */ struct completion scl_irq_completion; u64 scl_irq_data; @@ -72,7 +71,6 @@ static int i2c_gpio_getscl(void *data) } #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR -static struct dentry *i2c_gpio_debug_dir; #define setsda(bd, val) ((bd)->setsda((bd)->data, val)) #define setscl(bd, val) ((bd)->setscl((bd)->data, val)) @@ -258,41 +256,23 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); - /* - * If there will be a debugfs-dir per i2c adapter somewhen, put the - * 'fault-injector' dir there. Until then, we have a global dir with - * all adapters as subdirs. - */ - if (!i2c_gpio_debug_dir) - i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); - - priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); - init_completion(&priv->scl_irq_completion); - debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->adap.debugfs, priv, &fops_incomplete_addr_phase); - debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->adap.debugfs, priv, &fops_incomplete_write_byte); if (priv->bit_data.getscl) { - debugfs_create_file_unsafe("inject_panic", 0200, priv->debug_dir, + debugfs_create_file_unsafe("inject_panic", 0200, priv->adap.debugfs, priv, &fops_inject_panic); - debugfs_create_file_unsafe("lose_arbitration", 0200, priv->debug_dir, + debugfs_create_file_unsafe("lose_arbitration", 0200, priv->adap.debugfs, priv, &fops_lose_arbitration); } - debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); - debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); -} - -static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) -{ - struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); - - debugfs_remove_recursive(priv->debug_dir); + debugfs_create_file_unsafe("scl", 0600, priv->adap.debugfs, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->adap.debugfs, priv, &fops_sda); } #else static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} -static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} #endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ /* Get i2c-gpio properties from DT or ACPI table */ @@ -475,8 +455,6 @@ static void i2c_gpio_remove(struct platform_device *pdev) struct i2c_gpio_private_data *priv; struct i2c_adapter *adap; - i2c_gpio_fault_injector_exit(pdev); - priv = platform_get_drvdata(pdev); adap = &priv->adap; -- cgit v1.2.3 From e19e1abc9ce45f4d4cad2f7eab1827e683be4e84 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 12 Nov 2023 17:59:11 -0500 Subject: i2c: npcm7xx: move to per-adapter debugfs directory The I2C core now provides a per-adapter debugfs directory. Use it instead of creating a custom one. Signed-off-by: Wolfram Sang Reviewed-by: Tali Perry Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-npcm7xx.c | 49 ++++++---------------------------------- 1 file changed, 7 insertions(+), 42 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index ae4bae63ad4f..54181b3f1919 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -326,7 +326,6 @@ struct npcm_i2c { u8 slv_rd_buf[MAX_I2C_HW_FIFO_SIZE]; u8 slv_wr_buf[MAX_I2C_HW_FIFO_SIZE]; #endif - struct dentry *debugfs; /* debugfs device directory */ u64 ber_cnt; u64 rec_succ_cnt; u64 rec_fail_cnt; @@ -2250,27 +2249,15 @@ static const struct i2c_algorithm npcm_i2c_algo = { #endif }; -/* i2c debugfs directory: used to keep health monitor of i2c devices */ -static struct dentry *npcm_i2c_debugfs_dir; - static void npcm_i2c_init_debugfs(struct platform_device *pdev, struct npcm_i2c *bus) { - struct dentry *d; - - if (!npcm_i2c_debugfs_dir) - return; - d = debugfs_create_dir(dev_name(&pdev->dev), npcm_i2c_debugfs_dir); - if (IS_ERR_OR_NULL(d)) - return; - debugfs_create_u64("ber_cnt", 0444, d, &bus->ber_cnt); - debugfs_create_u64("nack_cnt", 0444, d, &bus->nack_cnt); - debugfs_create_u64("rec_succ_cnt", 0444, d, &bus->rec_succ_cnt); - debugfs_create_u64("rec_fail_cnt", 0444, d, &bus->rec_fail_cnt); - debugfs_create_u64("timeout_cnt", 0444, d, &bus->timeout_cnt); - debugfs_create_u64("tx_complete_cnt", 0444, d, &bus->tx_complete_cnt); - - bus->debugfs = d; + debugfs_create_u64("ber_cnt", 0444, bus->adap.debugfs, &bus->ber_cnt); + debugfs_create_u64("nack_cnt", 0444, bus->adap.debugfs, &bus->nack_cnt); + debugfs_create_u64("rec_succ_cnt", 0444, bus->adap.debugfs, &bus->rec_succ_cnt); + debugfs_create_u64("rec_fail_cnt", 0444, bus->adap.debugfs, &bus->rec_fail_cnt); + debugfs_create_u64("timeout_cnt", 0444, bus->adap.debugfs, &bus->timeout_cnt); + debugfs_create_u64("tx_complete_cnt", 0444, bus->adap.debugfs, &bus->tx_complete_cnt); } static int npcm_i2c_probe_bus(struct platform_device *pdev) @@ -2362,7 +2349,6 @@ static void npcm_i2c_remove_bus(struct platform_device *pdev) unsigned long lock_flags; struct npcm_i2c *bus = platform_get_drvdata(pdev); - debugfs_remove_recursive(bus->debugfs); spin_lock_irqsave(&bus->lock, lock_flags); npcm_i2c_disable(bus); spin_unlock_irqrestore(&bus->lock, lock_flags); @@ -2385,28 +2371,7 @@ static struct platform_driver npcm_i2c_bus_driver = { } }; -static int __init npcm_i2c_init(void) -{ - int ret; - - npcm_i2c_debugfs_dir = debugfs_create_dir("npcm_i2c", NULL); - - ret = platform_driver_register(&npcm_i2c_bus_driver); - if (ret) { - debugfs_remove_recursive(npcm_i2c_debugfs_dir); - return ret; - } - - return 0; -} -module_init(npcm_i2c_init); - -static void __exit npcm_i2c_exit(void) -{ - platform_driver_unregister(&npcm_i2c_bus_driver); - debugfs_remove_recursive(npcm_i2c_debugfs_dir); -} -module_exit(npcm_i2c_exit); +module_platform_driver(npcm_i2c_bus_driver); MODULE_AUTHOR("Avi Fishman "); MODULE_AUTHOR("Tali Perry "); -- cgit v1.2.3 From 2b523c46e81ebd621515ab47117f95de197dfcbf Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 14 Dec 2023 08:43:57 +0100 Subject: i2c: rcar: introduce Gen4 devices So far, we treated Gen4 as Gen3. But we are soon adding FM+ as a Gen4 specific feature, so prepare the code for the new devtype. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 829ac053bbb7..973811a6c27b 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -132,6 +132,7 @@ enum rcar_i2c_type { I2C_RCAR_GEN1, I2C_RCAR_GEN2, I2C_RCAR_GEN3, + I2C_RCAR_GEN4, }; struct rcar_i2c_priv { @@ -431,8 +432,8 @@ static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate) dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg), sg_dma_len(&priv->sg), priv->dma_direction); - /* Gen3 can only do one RXDMA per transfer and we just completed it */ - if (priv->devtype == I2C_RCAR_GEN3 && + /* Gen3+ can only do one RXDMA per transfer and we just completed it */ + if (priv->devtype >= I2C_RCAR_GEN3 && priv->dma_direction == DMA_FROM_DEVICE) priv->flags |= ID_P_NO_RXDMA; @@ -886,8 +887,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (ret < 0) goto out; - /* Gen3 needs a reset before allowing RXDMA once */ - if (priv->devtype == I2C_RCAR_GEN3) { + /* Gen3+ needs a reset. That also allows RXDMA once */ + if (priv->devtype >= I2C_RCAR_GEN3) { priv->flags &= ~ID_P_NO_RXDMA; ret = rcar_i2c_do_reset(priv); if (ret) @@ -1075,7 +1076,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 }, - { .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN3 }, + { .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN4 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -1151,7 +1152,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (of_property_read_bool(dev->of_node, "smbus")) priv->flags |= ID_P_HOST_NOTIFY; - if (priv->devtype == I2C_RCAR_GEN3) { + if (priv->devtype >= I2C_RCAR_GEN3) { priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(priv->rstc)) { ret = PTR_ERR(priv->rstc); -- cgit v1.2.3 From d0520eb3ed54df89eb5961ec3b88634f313123f2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 14 Dec 2023 08:43:58 +0100 Subject: i2c: rcar: add FastMode+ support for Gen4 To support FM+, we mainly need to turn the SMD constant into a parameter and set it accordingly. That also means we can finally fix SMD to our needs instead of bailing out. A sanity check for SMD then becomes a sanity check for 'x == 0'. After all that, activating the enable bit for FM+ is all we need to do. Tested with a Renesas Falcon board using R-Car V3U. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 973811a6c27b..828aa2ea0fe4 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -89,6 +89,7 @@ #define TMDMAE BIT(0) /* DMA Master Transmitted Enable */ /* ICCCR2 */ +#define FMPE BIT(7) /* Fast Mode Plus Enable */ #define CDFD BIT(2) /* CDF Disable */ #define HLSE BIT(1) /* HIGH/LOW Separate Control Enable */ #define SME BIT(0) /* SCL Mask Enable */ @@ -122,11 +123,12 @@ #define ID_NACK BIT(4) #define ID_EPROTO BIT(5) /* persistent flags */ +#define ID_P_FMPLUS BIT(27) #define ID_P_NOT_ATOMIC BIT(28) #define ID_P_HOST_NOTIFY BIT(29) #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ #define ID_P_PM_BLOCKED BIT(31) -#define ID_P_MASK GENMASK(31, 28) +#define ID_P_MASK GENMASK(31, 27) enum rcar_i2c_type { I2C_RCAR_GEN1, @@ -149,6 +151,7 @@ struct rcar_i2c_priv { u32 icccr; u16 schd; u16 scld; + u8 smd; u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; @@ -240,9 +243,14 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) if (priv->devtype < I2C_RCAR_GEN3) { rcar_i2c_write(priv, ICCCR, priv->icccr); } else { - rcar_i2c_write(priv, ICCCR2, CDFD | HLSE | SME); + u32 icccr2 = CDFD | HLSE | SME; + + if (priv->flags & ID_P_FMPLUS) + icccr2 |= FMPE; + + rcar_i2c_write(priv, ICCCR2, icccr2); rcar_i2c_write(priv, ICCCR, priv->icccr); - rcar_i2c_write(priv, ICMPR, RCAR_DEFAULT_SMD); + rcar_i2c_write(priv, ICMPR, priv->smd); rcar_i2c_write(priv, ICHPR, priv->schd); rcar_i2c_write(priv, ICLPR, priv->scld); rcar_i2c_write(priv, ICFBSCR, TCYC17); @@ -279,6 +287,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) /* Fall back to previously used values if not supplied */ i2c_parse_fw_timings(dev, &t, false); + priv->smd = RCAR_DEFAULT_SMD; /* * calculate SCL clock @@ -304,6 +313,11 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) if (cdf >= 1U << cdf_width) goto err_no_val; + if (t.bus_freq_hz > I2C_MAX_FAST_MODE_FREQ && priv->devtype >= I2C_RCAR_GEN4) + priv->flags |= ID_P_FMPLUS; + else + priv->flags &= ~ID_P_FMPLUS; + /* On Gen3+, we use cdf only for the filters, not as a SCL divider */ ick = rate / (priv->devtype < I2C_RCAR_GEN3 ? (cdf + 1) : 1); @@ -345,30 +359,30 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) * x as a base value for the SCLD/SCHD ratio: * * SCL = clkp / (8 + 2 * SMD + SCLD + SCHD + F[(ticf + tr + intd) * clkp]) - * SCL = clkp / (8 + 2 * RCAR_DEFAULT_SMD + RCAR_SCLD_RATIO * x + * SCL = clkp / (8 + 2 * SMD + RCAR_SCLD_RATIO * x * + RCAR_SCHD_RATIO * x + F[...]) * * with: sum_ratio = RCAR_SCLD_RATIO + RCAR_SCHD_RATIO - * and: smd = RCAR_DEFAULT_SMD * * SCL = clkp / (8 + 2 * smd + sum_ratio * x + F[...]) * 8 + 2 * smd + sum_ratio * x + F[...] = clkp / SCL * x = ((clkp / SCL) - 8 - 2 * smd - F[...]) / sum_ratio */ x = DIV_ROUND_UP(rate, t.bus_freq_hz ?: 1); - x = DIV_ROUND_UP(x - 8 - 2 * RCAR_DEFAULT_SMD - round, sum_ratio); - scl = rate / (8 + 2 * RCAR_DEFAULT_SMD + sum_ratio * x + round); + x = DIV_ROUND_UP(x - 8 - 2 * priv->smd - round, sum_ratio); + scl = rate / (8 + 2 * priv->smd + sum_ratio * x + round); - /* Bail out if values don't fit into 16 bit or SMD became too large */ - if (x * RCAR_SCLD_RATIO > 0xffff || RCAR_DEFAULT_SMD > x * RCAR_SCHD_RATIO) + if (x == 0 || x * RCAR_SCLD_RATIO > 0xffff) goto err_no_val; priv->icccr = cdf; priv->schd = RCAR_SCHD_RATIO * x; priv->scld = RCAR_SCLD_RATIO * x; + if (priv->smd >= priv->schd) + priv->smd = priv->schd - 1; - dev_dbg(dev, "clk %u/%u(%lu), round %u, CDF: %u SCHD %u SCLD %u\n", - scl, t.bus_freq_hz, rate, round, cdf, priv->schd, priv->scld); + dev_dbg(dev, "clk %u/%u(%lu), round %u, CDF: %u SCHD %u SCLD %u SMD %u\n", + scl, t.bus_freq_hz, rate, round, cdf, priv->schd, priv->scld, priv->smd); } return 0; @@ -1073,6 +1087,8 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 }, + /* S4 has no FM+ bit */ + { .compatible = "renesas,i2c-r8a779f0", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 }, -- cgit v1.2.3 From 0d9cf23ed55d7ba3ab26d617a3ae507863674c8f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 8 Nov 2023 17:43:52 +0100 Subject: i2c: s3c24xx: fix read transfers in polling mode To properly handle read transfers in polling mode, no waiting for the ACK state is needed as it will never come. Just wait a bit to ensure start state is on the bus and continue processing next bytes. Fixes: 117053f77a5a ("i2c: s3c2410: Add polling mode support") Signed-off-by: Marek Szyprowski Reviewed-by: Chanho Park Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index c56886af724e..bf9a5670ef33 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -216,8 +216,17 @@ static bool is_ack(struct s3c24xx_i2c *i2c) int tries; for (tries = 50; tries; --tries) { - if (readl(i2c->regs + S3C2410_IICCON) - & S3C2410_IICCON_IRQPEND) { + unsigned long tmp = readl(i2c->regs + S3C2410_IICCON); + + if (!(tmp & S3C2410_IICCON_ACKEN)) { + /* + * Wait a bit for the bus to stabilize, + * delay estimated experimentally. + */ + usleep_range(100, 200); + return true; + } + if (tmp & S3C2410_IICCON_IRQPEND) { if (!(readl(i2c->regs + S3C2410_IICSTAT) & S3C2410_IICSTAT_LASTBIT)) return true; -- cgit v1.2.3 From 990489e1042c6c5d6bccf56deca68f8dbeed8180 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 8 Nov 2023 17:43:53 +0100 Subject: i2c: s3c24xx: fix transferring more than one message in polling mode To properly handle ACK on the bus when transferring more than one message in polling mode, move the polling handling loop from s3c24xx_i2c_message_start() to s3c24xx_i2c_doxfer(). This way i2c_s3c_irq_nextbyte() is always executed till the end, properly acknowledging the IRQ bits and no recursive calls to i2c_s3c_irq_nextbyte() are made. While touching this, also fix finishing transfers in polling mode by using common code path and always waiting for the bus to become idle and disabled. Fixes: 117053f77a5a ("i2c: s3c2410: Add polling mode support") Signed-off-by: Marek Szyprowski Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index bf9a5670ef33..c0fe96a4f2c4 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -279,16 +279,6 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, stat |= S3C2410_IICSTAT_START; writel(stat, i2c->regs + S3C2410_IICSTAT); - - if (i2c->quirks & QUIRK_POLL) { - while ((i2c->msg_num != 0) && is_ack(i2c)) { - i2c_s3c_irq_nextbyte(i2c, stat); - stat = readl(i2c->regs + S3C2410_IICSTAT); - - if (stat & S3C2410_IICSTAT_ARBITR) - dev_err(i2c->dev, "deal with arbitration loss\n"); - } - } } static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) @@ -694,7 +684,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long timeout; + unsigned long timeout = 0; int ret; ret = s3c24xx_i2c_set_master(i2c); @@ -714,16 +704,19 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_message_start(i2c, msgs); if (i2c->quirks & QUIRK_POLL) { - ret = i2c->msg_idx; + while ((i2c->msg_num != 0) && is_ack(i2c)) { + unsigned long stat = readl(i2c->regs + S3C2410_IICSTAT); - if (ret != num) - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + i2c_s3c_irq_nextbyte(i2c, stat); - goto out; + stat = readl(i2c->regs + S3C2410_IICSTAT); + if (stat & S3C2410_IICSTAT_ARBITR) + dev_err(i2c->dev, "deal with arbitration loss\n"); + } + } else { + timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); } - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - ret = i2c->msg_idx; /* -- cgit v1.2.3 From 187432b82173c86e0450d0e3d516b415ab2455f8 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 8 Nov 2023 17:43:54 +0100 Subject: i2c: s3c24xx: add support for atomic transfers Add support for atomic transfers using polling mode with interrupts intentionally disabled to get rid of the following warning introduced by commit 63b96983a5dd ("i2c: core: introduce callbacks for atomic transfers") during system reboot and power-off: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1518 at drivers/i2c/i2c-core.h:40 i2c_transfer+0xe8/0xf4 No atomic I2C transfer handler for 'i2c-0' ... ---[ end trace 0000000000000000 ]--- Signed-off-by: Marek Szyprowski Reviewed-by: Chanho Park Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index c0fe96a4f2c4..275f7c42165c 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -76,6 +76,7 @@ #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) #define QUIRK_POLL (1 << 3) +#define QUIRK_ATOMIC (1 << 4) /* Max time to wait for bus to become idle after a xfer (in us) */ #define S3C2410_IDLE_TIMEOUT 5000 @@ -174,7 +175,7 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret) if (ret) i2c->msg_idx = ret; - if (!(i2c->quirks & QUIRK_POLL)) + if (!(i2c->quirks & (QUIRK_POLL | QUIRK_ATOMIC))) wake_up(&i2c->wait); } @@ -703,7 +704,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_enable_irq(i2c); s3c24xx_i2c_message_start(i2c, msgs); - if (i2c->quirks & QUIRK_POLL) { + if (i2c->quirks & (QUIRK_POLL | QUIRK_ATOMIC)) { while ((i2c->msg_num != 0) && is_ack(i2c)) { unsigned long stat = readl(i2c->regs + S3C2410_IICSTAT); @@ -775,6 +776,21 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, return -EREMOTEIO; } +static int s3c24xx_i2c_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; + int ret; + + disable_irq(i2c->irq); + i2c->quirks |= QUIRK_ATOMIC; + ret = s3c24xx_i2c_xfer(adap, msgs, num); + i2c->quirks &= ~QUIRK_ATOMIC; + enable_irq(i2c->irq); + + return ret; +} + /* declare our i2c functionality */ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) { @@ -785,6 +801,7 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) /* i2c bus registration info */ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { .master_xfer = s3c24xx_i2c_xfer, + .master_xfer_atomic = s3c24xx_i2c_xfer_atomic, .functionality = s3c24xx_i2c_func, }; -- cgit v1.2.3 From 92a85b7c6262f19c65a1c115cf15f411ba65a57c Mon Sep 17 00:00:00 2001 From: Tim Lunn Date: Sun, 3 Dec 2023 23:39:59 +1100 Subject: i2c: rk3x: Adjust mask/value offset for i2c2 on rv1126 Rockchip RV1126 is using old style i2c controller, the i2c2 bus uses a non-sequential offset in the grf register for the mask/value bits for this bus. This patch fixes i2c2 bus on rv1126 SoCs. Signed-off-by: Tim Lunn Acked-by: Heiko Stuebner Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index a044ca0c35a1..06fec2344575 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1288,8 +1288,12 @@ static int rk3x_i2c_probe(struct platform_device *pdev) return -EINVAL; } - /* 27+i: write mask, 11+i: value */ - value = BIT(27 + bus_nr) | BIT(11 + bus_nr); + /* rv1126 i2c2 uses non-sequential write mask 20, value 4 */ + if (i2c->soc_data == &rv1126_soc_data && bus_nr == 2) + value = BIT(20) | BIT(4); + else + /* 27+i: write mask, 11+i: value */ + value = BIT(27 + bus_nr) | BIT(11 + bus_nr); ret = regmap_write(grf, i2c->soc_data->grf_offset, value); if (ret != 0) { -- cgit v1.2.3 From 13e3a512a29001cab68fe9a0c12be94e6d42a10c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 14 Nov 2023 15:13:28 +0100 Subject: i2c: smbus: Support up to 8 SPD EEPROMs I originally restricted i2c_register_spd() to only support systems with up to 4 memory slots, so that we can experiment with it on a limited numbers of systems. It's been more than 3 years and it seems to work just fine, so the time has come to lift this arbitrary limitation. The maximum number of memory slots which can be connected to a single I2C segment is 8, so support that many SPD EEPROMs. Any system with more than 8 memory slots would have either multiple SMBus channels or SMBus multiplexing, so it would need dedicated care. We'll get to that later as needed. Signed-off-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-smbus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 138c3f5e0093..74807c6db596 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -308,8 +308,8 @@ EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device); * target systems are the same. * Restrictions to automatic SPD instantiation: * - Only works if all filled slots have the same memory type - * - Only works for DDR2, DDR3 and DDR4 for now - * - Only works on systems with 1 to 4 memory slots + * - Only works for DDR, DDR2, DDR3 and DDR4 for now + * - Only works on systems with 1 to 8 memory slots */ #if IS_ENABLED(CONFIG_DMI) void i2c_register_spd(struct i2c_adapter *adap) @@ -354,9 +354,9 @@ void i2c_register_spd(struct i2c_adapter *adap) dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n", dimm_count, slot_count); - if (slot_count > 4) { + if (slot_count > 8) { dev_warn(&adap->dev, - "Systems with more than 4 memory slots not supported yet, not instantiating SPD\n"); + "Systems with more than 8 memory slots not supported yet, not instantiating SPD\n"); return; } -- cgit v1.2.3 From db63eacdf61d6bbcde783f15aaafbd8e66476e9a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 30 Nov 2023 10:57:51 +0100 Subject: i2c: imx: Make SDA actually optional for bus recovering Both i2c_generic_scl_recovery() and the debug output indicate that SDA is purely optional for bus recovery. But devm_gpiod_get() never returns NULL making it mandatory. Fix this by calling devm_gpiod_get_optional instead. Signed-off-by: Alexander Stein Reviewed-by: Andi Shyti Reviewed-by: Oleksij Rempel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 1775a79aeba2..88a053987403 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1401,7 +1401,7 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, "gpio"); - rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); + rinfo->sda_gpiod = devm_gpiod_get_optional(&pdev->dev, "sda", GPIOD_IN); rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || -- cgit v1.2.3 From e535af5c4225fe2715d12322b645853ab9724648 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 6 Dec 2023 23:24:03 +0100 Subject: i2c: cpm: Remove linux,i2c-index conversion from be32 sparse reports an error on some data that gets converted from be32. That's because that data is typed u32 instead of __be32. The type is correct, the be32_to_cpu() conversion is not. Remove the conversion. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312042210.QL4DA8Av-lkp@intel.com/ Signed-off-by: Christophe Leroy Acked-By: Jochen Friedrich Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-cpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 9a664abf734d..4404b4aac676 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -658,7 +658,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev) /* register new adapter to i2c module... */ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); - cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; + cpm->adap.nr = (data && len == 4) ? *data : -1; result = i2c_add_numbered_adapter(&cpm->adap); if (result < 0) -- cgit v1.2.3 From 94959c0e796e41128483588d133b9a7003b409f9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Dec 2023 16:22:43 +0100 Subject: i2c: make i2c_bus_type const Now that the driver core can properly handle constant struct bus_type, move the i2c_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Note, the sound/soc/rockchip/rk3399_gru_sound.c also needed tweaking as it decided to save off a pointer to a bus type for internal stuff, and it was using the i2c_bus_type as well. Signed-off-by: Greg Kroah-Hartman Acked-by: Mark Brown Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index f6c828bbd166..3bd48d4b6318 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -692,7 +692,7 @@ static struct attribute *i2c_dev_attrs[] = { }; ATTRIBUTE_GROUPS(i2c_dev); -struct bus_type i2c_bus_type = { +const struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, -- cgit v1.2.3 From a8355235dbd571b32c750ee756dd6dac216d18f2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 8 Nov 2023 07:38:07 +0100 Subject: i2c: mux: reg: Remove class-based device auto-detection support Legacy class-based device auto-detection shouldn't be used in new code. Therefore remove support in i2c-mux-reg as long as we don't have a user of this feature yet. Link: https://lore.kernel.org/linux-i2c/a22978a4-88e4-46f4-b71c-032b22321599@gmail.com/ Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-reg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 9efc1ed01577..8489971babd3 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -159,7 +159,6 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) struct regmux *mux; struct i2c_adapter *parent; struct resource *res; - unsigned int class; int i, ret, nr; mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); @@ -213,9 +212,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - class = mux->data.classes ? mux->data.classes[i] : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], 0); if (ret) goto err_del_mux_adapters; } -- cgit v1.2.3 From 462e9804d2c90bfffb494718b5aae5c374ff3b78 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Thu, 2 Nov 2023 10:53:51 +0800 Subject: i2c: wmt: Reduce redundant: bus busy check Put wmt_i2c_wait_bus_not_busy() in a more appropriate place to reduce code redundancy Signed-off-by: Hans Hu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-wmt.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 76118abc6e10..d554c6377533 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -128,12 +128,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, unsigned long wait_result; int xfer_len = 0; - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - if (pmsg->len == 0) { /* * We still need to run through the while (..) once, so @@ -219,12 +213,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, unsigned long wait_result; u32 xfer_len = 0; - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - val = readw(i2c_dev->base + REG_CR); val &= ~CR_TX_END; writew(val, i2c_dev->base + REG_CR); @@ -297,11 +285,18 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg; int i, is_last; int ret = 0; + struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); for (i = 0; ret >= 0 && i < num; i++) { is_last = ((i + 1) == num); pmsg = &msgs[i]; + if (!(pmsg->flags & I2C_M_NOSTART)) { + ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + if (ret < 0) + return ret; + } + if (pmsg->flags & I2C_M_RD) ret = wmt_i2c_read(adap, pmsg, is_last); else -- cgit v1.2.3 From 8a22991a48f2602aaab79df1301483d50bc51b2c Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Thu, 2 Nov 2023 10:53:52 +0800 Subject: i2c: wmt: Reduce redundant: wait event complete Put the handling of interrupt events in a function class to reduce code redundancy. Signed-off-by: Hans Hu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-wmt.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index d554c6377533..1b31330ba4eb 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -109,6 +109,12 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) { int ret = 0; + unsigned long wait_result; + + wait_result = wait_for_completion_timeout(&i2c_dev->complete, + msecs_to_jiffies(500)); + if (!wait_result) + return -ETIMEDOUT; if (i2c_dev->cmd_status & ISR_NACK_ADDR) ret = -EIO; @@ -125,7 +131,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val; int ret; - unsigned long wait_result; int xfer_len = 0; if (pmsg->len == 0) { @@ -167,12 +172,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, } while (xfer_len < pmsg->len) { - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - - if (wait_result == 0) - return -ETIMEDOUT; - ret = wmt_check_status(i2c_dev); if (ret) return ret; @@ -210,7 +209,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val; int ret; - unsigned long wait_result; u32 xfer_len = 0; val = readw(i2c_dev->base + REG_CR); @@ -251,12 +249,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, } while (xfer_len < pmsg->len) { - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - - if (!wait_result) - return -ETIMEDOUT; - ret = wmt_check_status(i2c_dev); if (ret) return ret; -- cgit v1.2.3 From 7108ecf3cbc728ec4a72ce29136cbcfedf4a9242 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Thu, 2 Nov 2023 10:53:53 +0800 Subject: i2c: wmt: Reduce redundant: clock mode setting The frequency setting mode is adjusted to reduce the code redundancy, and it is also convenient to share with zhaoxin Signed-off-by: Hans Hu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-wmt.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 1b31330ba4eb..a44ce5fdde8a 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -74,9 +74,6 @@ #define MCR_APB_96M 7 #define MCR_APB_166M 12 -#define I2C_MODE_STANDARD 0 -#define I2C_MODE_FAST 1 - #define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) struct wmt_i2c_dev { @@ -85,7 +82,7 @@ struct wmt_i2c_dev { struct device *dev; void __iomem *base; struct clk *clk; - int mode; + u16 tcr; int irq; u16 cmd_status; }; @@ -129,7 +126,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, int last) { struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - u16 val, tcr_val; + u16 val, tcr_val = i2c_dev->tcr; int ret; int xfer_len = 0; @@ -156,11 +153,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, reinit_completion(&i2c_dev->complete); - if (i2c_dev->mode == I2C_MODE_STANDARD) - tcr_val = TCR_STANDARD_MODE; - else - tcr_val = TCR_FAST_MODE; - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); writew(tcr_val, i2c_dev->base + REG_TCR); @@ -207,7 +199,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, int last) { struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - u16 val, tcr_val; + u16 val, tcr_val = i2c_dev->tcr; int ret; u32 xfer_len = 0; @@ -233,11 +225,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, reinit_completion(&i2c_dev->complete); - if (i2c_dev->mode == I2C_MODE_STANDARD) - tcr_val = TCR_STANDARD_MODE; - else - tcr_val = TCR_FAST_MODE; - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); writew(tcr_val, i2c_dev->base + REG_TCR); @@ -346,10 +333,10 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) readw(i2c_dev->base + REG_CSR); /* read clear */ writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - if (i2c_dev->mode == I2C_MODE_STANDARD) - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); - else + if (i2c_dev->tcr == TCR_FAST_MODE) writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + else + writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); return 0; } @@ -382,10 +369,9 @@ static int wmt_i2c_probe(struct platform_device *pdev) return PTR_ERR(i2c_dev->clk); } - i2c_dev->mode = I2C_MODE_STANDARD; err = of_property_read_u32(np, "clock-frequency", &clk_rate); if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ)) - i2c_dev->mode = I2C_MODE_FAST; + i2c_dev->tcr = TCR_FAST_MODE; i2c_dev->dev = &pdev->dev; -- cgit v1.2.3 From 4c541c6a66df396c35693a21c5bc40553cd4d2fa Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Thu, 2 Nov 2023 10:53:55 +0800 Subject: i2c: wmt: Reduce redundant: function parameter Use more appropriate parameter passing to reduce the amount of code Signed-off-by: Hans Hu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-wmt.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index a44ce5fdde8a..7de67886e8ca 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -122,10 +122,9 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) return ret; } -static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, +static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last) { - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val = i2c_dev->tcr; int ret; int xfer_len = 0; @@ -195,10 +194,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, return 0; } -static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, - int last) +static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) { - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val = i2c_dev->tcr; int ret; u32 xfer_len = 0; @@ -262,13 +259,11 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap, int num) { struct i2c_msg *pmsg; - int i, is_last; + int i; int ret = 0; struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); for (i = 0; ret >= 0 && i < num; i++) { - is_last = ((i + 1) == num); - pmsg = &msgs[i]; if (!(pmsg->flags & I2C_M_NOSTART)) { ret = wmt_i2c_wait_bus_not_busy(i2c_dev); @@ -277,9 +272,9 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap, } if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(adap, pmsg, is_last); + ret = wmt_i2c_read(i2c_dev, pmsg); else - ret = wmt_i2c_write(adap, pmsg, is_last); + ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); } return (ret < 0) ? ret : i; -- cgit v1.2.3 From bb7c0209c4fead37fbc9fd07f9617f40ba21189e Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Thu, 2 Nov 2023 10:53:54 +0800 Subject: i2c: wmt: Reduce redundant: REG_CR setting These Settings for the same register, REG_CR, can be put together to reduce code redundancy. Signed-off-by: Hans Hu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-wmt.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 7de67886e8ca..ec2a8da134e5 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -143,9 +143,6 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, if (!(pmsg->flags & I2C_M_NOSTART)) { val = readw(i2c_dev->base + REG_CR); val &= ~CR_TX_END; - writew(val, i2c_dev->base + REG_CR); - - val = readw(i2c_dev->base + REG_CR); val |= CR_CPU_RDY; writew(val, i2c_dev->base + REG_CR); } @@ -201,24 +198,15 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) u32 xfer_len = 0; val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - writew(val, i2c_dev->base + REG_CR); + val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - - if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); + if (!(pmsg->flags & I2C_M_NOSTART)) val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - if (pmsg->len == 1) { - val = readw(i2c_dev->base + REG_CR); + if (pmsg->len == 1) val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - } + + writew(val, i2c_dev->base + REG_CR); reinit_completion(&i2c_dev->complete); @@ -240,15 +228,10 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; xfer_len++; - if (xfer_len == pmsg->len - 1) { - val = readw(i2c_dev->base + REG_CR); - val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY); - writew(val, i2c_dev->base + REG_CR); - } else { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } + val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; + if (xfer_len == pmsg->len - 1) + val |= CR_TX_NEXT_NO_ACK; + writew(val, i2c_dev->base + REG_CR); } return 0; -- cgit v1.2.3 From 6d9450464ce1825d7d0e7ef5d33a9d2701f41c76 Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Wed, 20 Dec 2023 17:10:01 +0100 Subject: i2c: i801: Add lis3lv02d for Dell Precision 3540 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Dell Precision 3540/0M14W7, BIOS 1.7.4 05/12/2020, Linux prints the warning below. i801_smbus 0000:00:1f.4: Accelerometer lis3lv02d is present on SMBus but its address is unknown, skipping registration With the help of Wolfram Sang, the test to probe it on I2C bus 6 at address 0x29 was successful. $ echo lis3lv02d 0x29 | sudo tee /sys/bus/i2c/devices/i2c-6/new_device [ 2110.787000] i2c i2c-6: new_device: Instantiated device lis3lv02d at 0x29 [ 2110.791932] lis3lv02d_i2c 6-0029: supply Vdd not found, using dummy regulator [ 2110.791981] lis3lv02d_i2c 6-0029: supply Vdd_IO not found, using dummy regulator [ 2110.809233] lis3lv02d: 8 bits 3DC sensor found [ 2110.900668] input: ST LIS3LV02DL Accelerometer as /devices/platform/lis3lv02d/input/input23 So, the device has that accelerometer. Add the I2C address to the mapping list. Link: https://lore.kernel.org/linux-i2c/97708c11-ac85-fb62-2c8e-d37739ca826f@molgen.mpg.de/ Signed-off-by: Paul Menzel Acked-by: Pali Rohár Reviewed-by: Andi Shyti [wsa: shortened commit message a little] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 070999139c6d..cb9660f84117 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1230,6 +1230,7 @@ static const struct { * Additional individual entries were added after verification. */ { "Latitude 5480", 0x29 }, + { "Precision 3540", 0x29 }, { "Vostro V131", 0x1d }, { "Vostro 5568", 0x29 }, }; -- cgit v1.2.3 From 2f189493ae32be9768b27072c9388e62b38d2dda Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Wed, 20 Dec 2023 17:10:02 +0100 Subject: i2c: i801: Add lis3lv02d for Dell XPS 15 7590 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Dell XPS 15 7590/0VYV0G, BIOS 1.24.0 09/11/2023, Linux prints the warning below. i801_smbus 0000:00:1f.4: Accelerometer lis3lv02d is present on SMBus but its address is unknown, skipping registration Following the same suggestions by Wolfram Sang as for the Dell Precision 3540 [1], the accelerometer can be successfully found on I2C bus 2 at address 0x29. $ echo lis3lv02d 0x29 | sudo tee /sys/bus/i2c/devices/i2c-2/new_device lis3lv02d 0x29 $ dmesg | tail -5 [ 549.522876] lis3lv02d_i2c 2-0029: supply Vdd not found, using dummy regulator [ 549.522904] lis3lv02d_i2c 2-0029: supply Vdd_IO not found, using dummy regulator [ 549.542486] lis3lv02d: 8 bits 3DC sensor found [ 549.630022] input: ST LIS3LV02DL Accelerometer as /devices/platform/lis3lv02d/input/input35 [ 549.630586] i2c i2c-2: new_device: Instantiated device lis3lv02d at 0x29 So, the device has that accelerometer. Add the I2C address to the mapping list, and test it successfully on the device. [1]: https://lore.kernel.org/linux-i2c/97708c11-ac85-fb62-2c8e-d37739ca826f@molgen.mpg.de/ Signed-off-by: Paul Menzel Acked-by: Pali Rohár Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index cb9660f84117..3932e8d96a17 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1233,6 +1233,7 @@ static const struct { { "Precision 3540", 0x29 }, { "Vostro V131", 0x1d }, { "Vostro 5568", 0x29 }, + { "XPS 15 7590", 0x29 }, }; static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) -- cgit v1.2.3 From a51e224c2f42417e95a3e1a672ade221bcd006ba Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 15 Dec 2023 18:06:05 +0100 Subject: i2c: stm32f7: use dev_err_probe upon calls of devm_request_irq Convert error handling upon calls of devm_request_irq functions during the probe of the driver. Signed-off-by: Alain Volmat Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 983509936727..d99f152ac727 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2199,19 +2199,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) stm32f7_i2c_isr_event_thread, IRQF_ONESHOT, pdev->name, i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq event %i\n", - irq_event); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0, pdev->name, i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq error %i\n", - irq_error); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); setup = of_device_get_match_data(&pdev->dev); if (!setup) { -- cgit v1.2.3 From e6103cd45ef0e14eb02f0666bc6b494902cfe821 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 15 Dec 2023 18:06:06 +0100 Subject: i2c: stm32f7: perform most of irq job in threaded handler The irq handling is currently split between the irq handler and the threaded irq handler. Some of the handling (such as dma related stuffs) done within the irq handler might sleep or take some time leading to issues if the kernel is built with realtime constraints. In order to fix that, perform an overall rework to perform most of the job within the threaded handler and only keep fifo access in the non threaded handler. Signed-off-by: Alain Volmat Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 126 +++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 70 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d99f152ac727..dde70e7ec722 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1497,17 +1497,11 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - struct stm32_i2c_dma *dma = i2c_dev->dma; - void __iomem *base = i2c_dev->base; - u32 status, mask; - int ret = IRQ_HANDLED; + u32 status; - /* Check if the interrupt if for a slave device */ - if (!i2c_dev->master_mode) { - ret = stm32f7_i2c_slave_isr_event(i2c_dev); - return ret; - } + /* Check if the interrupt is for a slave device */ + if (!i2c_dev->master_mode) + return IRQ_WAKE_THREAD; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -1519,6 +1513,29 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) if (status & STM32F7_I2C_ISR_RXNE) stm32f7_i2c_read_rx_data(i2c_dev); + /* Wake up the thread if other flags are raised */ + if (status & + (STM32F7_I2C_ISR_NACKF | STM32F7_I2C_ISR_STOPF | + STM32F7_I2C_ISR_TC | STM32F7_I2C_ISR_TCR)) + return IRQ_WAKE_THREAD; + + return IRQ_HANDLED; +} + +static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) +{ + struct stm32f7_i2c_dev *i2c_dev = data; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + void __iomem *base = i2c_dev->base; + u32 status, mask; + int ret; + + if (!i2c_dev->master_mode) + return stm32f7_i2c_slave_isr_event(i2c_dev); + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + /* NACK received */ if (status & STM32F7_I2C_ISR_NACKF) { dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", @@ -1531,33 +1548,28 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) f7_msg->result = -ENXIO; } - /* STOP detection flag */ - if (status & STM32F7_I2C_ISR_STOPF) { - /* Disable interrupts */ - if (stm32f7_i2c_is_slave_registered(i2c_dev)) - mask = STM32F7_I2C_XFER_IRQ_MASK; + if (status & STM32F7_I2C_ISR_TCR) { + if (f7_msg->smbus) + stm32f7_i2c_smbus_reload(i2c_dev); else - mask = STM32F7_I2C_ALL_IRQ_MASK; - stm32f7_i2c_disable_irq(i2c_dev, mask); - - /* Clear STOP flag */ - writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - - if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; - } else { - i2c_dev->master_mode = false; - complete(&i2c_dev->complete); - } + stm32f7_i2c_reload(i2c_dev); } /* Transfer complete */ if (status & STM32F7_I2C_ISR_TC) { + /* Wait for dma transfer completion before sending next message */ + if (i2c_dev->use_dma && !f7_msg->result) { + ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); + if (!ret) { + dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_async(dma->chan_using); + f7_msg->result = -ETIMEDOUT; + } + } if (f7_msg->stop) { mask = STM32F7_I2C_CR2_STOP; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); - } else if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; } else if (f7_msg->smbus) { stm32f7_i2c_smbus_rep_start(i2c_dev); } else { @@ -1567,47 +1579,18 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) } } - if (status & STM32F7_I2C_ISR_TCR) { - if (f7_msg->smbus) - stm32f7_i2c_smbus_reload(i2c_dev); + /* STOP detection flag */ + if (status & STM32F7_I2C_ISR_STOPF) { + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; else - stm32f7_i2c_reload(i2c_dev); - } - - return ret; -} - -static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) -{ - struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - struct stm32_i2c_dma *dma = i2c_dev->dma; - u32 status; - int ret; - - /* - * Wait for dma transfer completion before sending next message or - * notity the end of xfer to the client - */ - ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); - if (!ret) { - dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); - stm32f7_i2c_disable_dma_req(i2c_dev); - dmaengine_terminate_async(dma->chan_using); - f7_msg->result = -ETIMEDOUT; - } + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + /* Clear STOP flag */ + writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - if (status & STM32F7_I2C_ISR_TC) { - if (f7_msg->smbus) { - stm32f7_i2c_smbus_rep_start(i2c_dev); - } else { - i2c_dev->msg_id++; - i2c_dev->msg++; - stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); - } - } else { i2c_dev->master_mode = false; complete(&i2c_dev->complete); } @@ -1615,7 +1598,7 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) +static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; @@ -2202,8 +2185,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); - ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0, - pdev->name, i2c_dev); + ret = devm_request_threaded_irq(&pdev->dev, irq_error, + NULL, + stm32f7_i2c_isr_error_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); -- cgit v1.2.3 From 33a00d919253022aabafecae6bc88a6fad446589 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 15 Dec 2023 18:06:07 +0100 Subject: i2c: stm32f7: simplify status messages in case of errors Avoid usage of __func__ when reporting an error message since dev_err/dev_dbg are already providing enough details to identify the source of the message. Signed-off-by: Alain Volmat Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index dde70e7ec722..15100fed0a3f 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1602,6 +1602,7 @@ static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u16 addr = f7_msg->addr; void __iomem *base = i2c_dev->base; struct device *dev = i2c_dev->dev; struct stm32_i2c_dma *dma = i2c_dev->dma; @@ -1611,8 +1612,7 @@ static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) /* Bus error */ if (status & STM32F7_I2C_ISR_BERR) { - dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n", - __func__, f7_msg->addr); + dev_err(dev, "Bus error accessing addr 0x%x\n", addr); writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); stm32f7_i2c_release_bus(&i2c_dev->adap); f7_msg->result = -EIO; @@ -1620,21 +1620,19 @@ static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) /* Arbitration loss */ if (status & STM32F7_I2C_ISR_ARLO) { - dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n", - __func__, f7_msg->addr); + dev_dbg(dev, "Arbitration loss accessing addr 0x%x\n", addr); writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); f7_msg->result = -EAGAIN; } if (status & STM32F7_I2C_ISR_PECERR) { - dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n", - __func__, f7_msg->addr); + dev_err(dev, "PEC error in reception accessing addr 0x%x\n", addr); writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); f7_msg->result = -EINVAL; } if (status & STM32F7_I2C_ISR_ALERT) { - dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); + dev_dbg(dev, "SMBus alert received\n"); writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); i2c_handle_smbus_alert(i2c_dev->alert->ara); return IRQ_HANDLED; -- cgit v1.2.3 From a058b24c08023ea0ea0a7c38e6845f1d25139a22 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 15 Dec 2023 18:06:09 +0100 Subject: i2c: stm32f7: perform I2C_ISR read once at beginning of event isr Move readl_relaxed of I2C_ISR register at beginning of event isr so that it done once for both master & slave handling. Signed-off-by: Alain Volmat Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 15100fed0a3f..f7abf6d3a7b9 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1419,15 +1419,13 @@ static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev) return i == busy; } -static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) +static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev, u32 status) { void __iomem *base = i2c_dev->base; - u32 cr2, status, mask; + u32 cr2, mask; u8 val; int ret; - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); - /* Slave transmitter mode */ if (status & STM32F7_I2C_ISR_TXIS) { i2c_slave_event(i2c_dev->slave_running, @@ -1531,11 +1529,11 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) u32 status, mask; int ret; - if (!i2c_dev->master_mode) - return stm32f7_i2c_slave_isr_event(i2c_dev); - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + if (!i2c_dev->master_mode) + return stm32f7_i2c_slave_isr_event(i2c_dev, status); + /* NACK received */ if (status & STM32F7_I2C_ISR_NACKF) { dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", -- cgit v1.2.3 From 90f9b1406236853bd524ddde86cc5a945690c6b7 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 15 Dec 2023 18:06:10 +0100 Subject: i2c: stm32f7: add support for stm32mp25 soc The stm32mp25 has only a single interrupt line used for both events and errors. In order to cope with that, reorganise the error handling code so that it can be called either from the common handler (used in case of SoC having only a single IT line) and the error handler for others. The CR1 register also embeds a new FMP bit, necessary when running at Fast Mode Plus frequency. This bit should be used instead of the SYSCFG bit used on other platforms. Add a new compatible to distinguish between the SoCs and two boolean within the setup structure in order to know if the platform has a single/multiple IT lines and if the FMP bit within CR1 is available or not. Signed-off-by: Valentin Caron Signed-off-by: Alain Volmat Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 214 +++++++++++++++++++++++---------------- 1 file changed, 126 insertions(+), 88 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index f7abf6d3a7b9..01210452216b 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -50,6 +50,7 @@ #define STM32F7_I2C_TXDR 0x28 /* STM32F7 I2C control 1 */ +#define STM32_I2C_CR1_FMP BIT(24) #define STM32F7_I2C_CR1_PECEN BIT(23) #define STM32F7_I2C_CR1_ALERTEN BIT(22) #define STM32F7_I2C_CR1_SMBHEN BIT(20) @@ -226,6 +227,8 @@ struct stm32f7_i2c_spec { * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) * @fmp_clr_offset: Fast Mode Plus clear register offset from set register + * @single_it_line: Only a single IT line is used for both events/errors + * @fmp_cr1_bit: Fast Mode Plus control is done via a bit in CR1 */ struct stm32f7_i2c_setup { u32 speed_freq; @@ -233,6 +236,8 @@ struct stm32f7_i2c_setup { u32 rise_time; u32 fall_time; u32 fmp_clr_offset; + bool single_it_line; + bool fmp_cr1_bit; }; /** @@ -418,6 +423,13 @@ static const struct stm32f7_i2c_setup stm32mp13_setup = { .fmp_clr_offset = 0x4, }; +static const struct stm32f7_i2c_setup stm32mp25_setup = { + .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, + .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, + .single_it_line = true, + .fmp_cr1_bit = true, +}; + static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask) { writel_relaxed(readl_relaxed(reg) | mask, reg); @@ -1492,17 +1504,81 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev, return IRQ_HANDLED; } +static irqreturn_t stm32f7_i2c_handle_isr_errs(struct stm32f7_i2c_dev *i2c_dev, u32 status) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u16 addr = f7_msg->addr; + void __iomem *base = i2c_dev->base; + struct device *dev = i2c_dev->dev; + struct stm32_i2c_dma *dma = i2c_dev->dma; + + /* Bus error */ + if (status & STM32F7_I2C_ISR_BERR) { + dev_err(dev, "Bus error accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); + stm32f7_i2c_release_bus(&i2c_dev->adap); + f7_msg->result = -EIO; + } + + /* Arbitration loss */ + if (status & STM32F7_I2C_ISR_ARLO) { + dev_dbg(dev, "Arbitration loss accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EAGAIN; + } + + if (status & STM32F7_I2C_ISR_PECERR) { + dev_err(dev, "PEC error in reception accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EINVAL; + } + + if (status & STM32F7_I2C_ISR_ALERT) { + dev_dbg(dev, "SMBus alert received\n"); + writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); + i2c_handle_smbus_alert(i2c_dev->alert->ara); + return IRQ_HANDLED; + } + + if (!i2c_dev->slave_running) { + u32 mask; + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); + } + + /* Disable dma */ + if (i2c_dev->use_dma) { + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_async(dma->chan_using); + } + + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +#define STM32F7_ERR_EVENTS (STM32F7_I2C_ISR_BERR | STM32F7_I2C_ISR_ARLO |\ + STM32F7_I2C_ISR_PECERR | STM32F7_I2C_ISR_ALERT) static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; u32 status; - /* Check if the interrupt is for a slave device */ - if (!i2c_dev->master_mode) - return IRQ_WAKE_THREAD; - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + /* + * Check if the interrupt is for a slave device or related + * to errors flags (in case of single it line mode) + */ + if (!i2c_dev->master_mode || + (i2c_dev->setup.single_it_line && (status & STM32F7_ERR_EVENTS))) + return IRQ_WAKE_THREAD; + /* Tx empty */ if (status & STM32F7_I2C_ISR_TXIS) stm32f7_i2c_write_tx_data(i2c_dev); @@ -1534,6 +1610,10 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) if (!i2c_dev->master_mode) return stm32f7_i2c_slave_isr_event(i2c_dev, status); + /* Handle errors in case of this handler is used for events/errors */ + if (i2c_dev->setup.single_it_line && (status & STM32F7_ERR_EVENTS)) + return stm32f7_i2c_handle_isr_errs(i2c_dev, status); + /* NACK received */ if (status & STM32F7_I2C_ISR_NACKF) { dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", @@ -1599,63 +1679,11 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - u16 addr = f7_msg->addr; - void __iomem *base = i2c_dev->base; - struct device *dev = i2c_dev->dev; - struct stm32_i2c_dma *dma = i2c_dev->dma; u32 status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); - /* Bus error */ - if (status & STM32F7_I2C_ISR_BERR) { - dev_err(dev, "Bus error accessing addr 0x%x\n", addr); - writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); - stm32f7_i2c_release_bus(&i2c_dev->adap); - f7_msg->result = -EIO; - } - - /* Arbitration loss */ - if (status & STM32F7_I2C_ISR_ARLO) { - dev_dbg(dev, "Arbitration loss accessing addr 0x%x\n", addr); - writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EAGAIN; - } - - if (status & STM32F7_I2C_ISR_PECERR) { - dev_err(dev, "PEC error in reception accessing addr 0x%x\n", addr); - writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EINVAL; - } - - if (status & STM32F7_I2C_ISR_ALERT) { - dev_dbg(dev, "SMBus alert received\n"); - writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); - i2c_handle_smbus_alert(i2c_dev->alert->ara); - return IRQ_HANDLED; - } - - if (!i2c_dev->slave_running) { - u32 mask; - /* Disable interrupts */ - if (stm32f7_i2c_is_slave_registered(i2c_dev)) - mask = STM32F7_I2C_XFER_IRQ_MASK; - else - mask = STM32F7_I2C_ALL_IRQ_MASK; - stm32f7_i2c_disable_irq(i2c_dev, mask); - } - - /* Disable dma */ - if (i2c_dev->use_dma) { - stm32f7_i2c_disable_dma_req(i2c_dev); - dmaengine_terminate_async(dma->chan_using); - } - - i2c_dev->master_mode = false; - complete(&i2c_dev->complete); - - return IRQ_HANDLED; + return stm32f7_i2c_handle_isr_errs(i2c_dev, status); } static int stm32f7_i2c_wait_polling(struct stm32f7_i2c_dev *i2c_dev) @@ -1991,23 +2019,27 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev, bool enable) { - int ret; + int ret = 0; if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ || - IS_ERR_OR_NULL(i2c_dev->regmap)) + (!i2c_dev->setup.fmp_cr1_bit && IS_ERR_OR_NULL(i2c_dev->regmap))) /* Optional */ return 0; - if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg) - ret = regmap_update_bits(i2c_dev->regmap, - i2c_dev->fmp_sreg, - i2c_dev->fmp_mask, - enable ? i2c_dev->fmp_mask : 0); - else - ret = regmap_write(i2c_dev->regmap, - enable ? i2c_dev->fmp_sreg : - i2c_dev->fmp_creg, - i2c_dev->fmp_mask); + if (i2c_dev->setup.fmp_cr1_bit) { + if (enable) + stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32_I2C_CR1_FMP); + else + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32_I2C_CR1_FMP); + } else { + if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg) + ret = regmap_update_bits(i2c_dev->regmap, i2c_dev->fmp_sreg, + i2c_dev->fmp_mask, enable ? i2c_dev->fmp_mask : 0); + else + ret = regmap_write(i2c_dev->regmap, + enable ? i2c_dev->fmp_sreg : i2c_dev->fmp_creg, + i2c_dev->fmp_mask); + } return ret; } @@ -2141,6 +2173,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; + setup = of_device_get_match_data(&pdev->dev); + if (!setup) { + dev_err(&pdev->dev, "Can't get device data\n"); + return -ENODEV; + } + i2c_dev->setup = *setup; + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); @@ -2150,10 +2189,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (irq_event < 0) return irq_event; - irq_error = platform_get_irq(pdev, 1); - if (irq_error < 0) - return irq_error; - i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, "wakeup-source"); @@ -2181,20 +2216,19 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); - ret = devm_request_threaded_irq(&pdev->dev, irq_error, - NULL, - stm32f7_i2c_isr_error_thread, - IRQF_ONESHOT, - pdev->name, i2c_dev); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); + if (!i2c_dev->setup.single_it_line) { + irq_error = platform_get_irq(pdev, 1); + if (irq_error < 0) + return irq_error; - setup = of_device_get_match_data(&pdev->dev); - if (!setup) { - dev_err(&pdev->dev, "Can't get device data\n"); - return -ENODEV; + ret = devm_request_threaded_irq(&pdev->dev, irq_error, + NULL, + stm32f7_i2c_isr_error_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); } - i2c_dev->setup = *setup; ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup); if (ret) @@ -2202,9 +2236,12 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) /* Setup Fast mode plus if necessary */ if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) { - ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); - if (ret) - return ret; + if (!i2c_dev->setup.fmp_cr1_bit) { + ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); + if (ret) + return ret; + } + ret = stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); if (ret) return ret; @@ -2483,6 +2520,7 @@ static const struct of_device_id stm32f7_i2c_match[] = { { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup}, { .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup}, + { .compatible = "st,stm32mp25-i2c", .data = &stm32mp25_setup}, {}, }; MODULE_DEVICE_TABLE(of, stm32f7_i2c_match); -- cgit v1.2.3