summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c7
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-amd-asf-plat.c9
-rw-r--r--drivers/i2c/busses/i2c-amd-mp2-plat.c4
-rw-r--r--drivers/i2c/busses/i2c-at91-core.c3
-rw-r--r--drivers/i2c/busses/i2c-at91-master.c12
-rw-r--r--drivers/i2c/busses/i2c-at91.h1
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c14
-rw-r--r--drivers/i2c/busses/i2c-bcm-kona.c2
-rw-r--r--drivers/i2c/busses/i2c-cadence.c20
-rw-r--r--drivers/i2c/busses/i2c-davinci.c8
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c38
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h86
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c33
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c92
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c17
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c2
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c10
-rw-r--r--drivers/i2c/busses/i2c-gpio.c223
-rw-r--r--drivers/i2c/busses/i2c-gxp.c3
-rw-r--r--drivers/i2c/busses/i2c-hisi.c3
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-icy.c4
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c127
-rw-r--r--drivers/i2c/busses/i2c-imx.c110
-rw-r--r--drivers/i2c/busses/i2c-jz4780.c5
-rw-r--r--drivers/i2c/busses/i2c-k1.c197
-rw-r--r--drivers/i2c/busses/i2c-ls2x-v2.c544
-rw-r--r--drivers/i2c/busses/i2c-ls2x.c2
-rw-r--r--drivers/i2c/busses/i2c-microchip-corei2c.c7
-rw-r--r--drivers/i2c/busses/i2c-mlxbf.c6
-rw-r--r--drivers/i2c/busses/i2c-mpc.c2
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c2
-rw-r--r--drivers/i2c/busses/i2c-mxs.c13
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c7
-rw-r--r--drivers/i2c/busses/i2c-ocores.c6
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.h2
-rw-r--r--drivers/i2c/busses/i2c-pnx.c3
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c3
-rw-r--r--drivers/i2c/busses/i2c-pxa.c10
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c99
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c483
-rw-r--r--drivers/i2c/busses/i2c-qup.c31
-rw-r--r--drivers/i2c/busses/i2c-rcar.c17
-rw-r--r--drivers/i2c/busses/i2c-riic.c7
-rw-r--r--drivers/i2c/busses/i2c-rtl9300.c1
-rw-r--r--drivers/i2c/busses/i2c-rzv2m.c3
-rw-r--r--drivers/i2c/busses/i2c-sis630.c31
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c30
-rw-r--r--drivers/i2c/busses/i2c-sprd.c15
-rw-r--r--drivers/i2c/busses/i2c-st.c31
-rw-r--r--drivers/i2c/busses/i2c-stm32.c4
-rw-r--r--drivers/i2c/busses/i2c-stm32f4.c47
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c103
-rw-r--r--drivers/i2c/busses/i2c-sun6i-p2wi.c57
-rw-r--r--drivers/i2c/busses/i2c-synquacer.c2
-rw-r--r--drivers/i2c/busses/i2c-tegra.c117
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c5
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c2
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c2
-rw-r--r--drivers/i2c/busses/i2c-viai2c-wmt.c3
-rw-r--r--drivers/i2c/busses/i2c-viai2c-zhaoxin.c3
-rw-r--r--drivers/i2c/busses/i2c-virtio.c2
-rw-r--r--drivers/i2c/busses/i2c-xlp9xx.c2
-rw-r--r--drivers/i2c/i2c-atr.c1
-rw-r--r--drivers/i2c/i2c-core-acpi.c29
-rw-r--r--drivers/i2c/i2c-core-base.c187
-rw-r--r--drivers/i2c/i2c-core-of.c5
-rw-r--r--drivers/i2c/i2c-core-smbus.c13
-rw-r--r--drivers/i2c/i2c-core.h1
-rw-r--r--drivers/i2c/i2c-dev.c9
-rw-r--r--drivers/i2c/i2c-mux.c1
-rw-r--r--drivers/i2c/i2c-slave-eeprom.c16
-rw-r--r--drivers/i2c/i2c-slave-testunit.c6
-rw-r--r--drivers/i2c/i2c-smbus.c2
-rw-r--r--drivers/i2c/i2c-stub.c5
-rw-r--r--drivers/i2c/muxes/i2c-demux-pinctrl.c1
-rw-r--r--drivers/i2c/muxes/i2c-mux-ltc4306.c4
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca9541.c4
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c36
-rw-r--r--drivers/i2c/muxes/i2c-mux-reg.c90
82 files changed, 2156 insertions, 1009 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 6544d27e4419..7ca565cbff5b 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/string_choices.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -562,7 +563,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
- ret, ret == 1 ? "" : "s");
+ ret, str_plural(ret));
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
@@ -573,7 +574,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
- ret, ret == 1 ? "" : "s");
+ ret, str_plural(ret));
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
@@ -638,7 +639,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
int ret;
- if (bit_test) {
+ if (bit_test && !bit_adap->skip_bit_test) {
ret = test_bus(adap);
if (bit_test >= 2 && ret < 0)
return -ENODEV;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8c935f867a37..d7b89508311f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -417,7 +417,7 @@ config I2C_ASPEED
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_MICROCHIP || COMPILE_TEST
+ depends on ARCH_MICROCHIP || MCHP_LAN966X_PCI || COMPILE_TEST
help
This supports the use of the I2C interface on Atmel AT91
processors.
@@ -793,7 +793,8 @@ config I2C_JZ4780
config I2C_K1
tristate "SpacemiT K1 I2C adapter"
depends on ARCH_SPACEMIT || COMPILE_TEST
- depends on OF
+ depends on OF && COMMON_CLK
+ default ARCH_SPACEMIT
help
This option enables support for the I2C interface on the SpacemiT K1
platform.
@@ -850,6 +851,17 @@ config I2C_LS2X
This driver can also be built as a module. If so, the module
will be called i2c-ls2x.
+config I2C_LS2X_V2
+ tristate "Loongson-2 Fast Speed I2C adapter"
+ depends on LOONGARCH || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Loongson-2K0300 SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ls2x-v2.
+
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on (MELLANOX_PLATFORM && ARM64) || COMPILE_TEST
@@ -1046,7 +1058,7 @@ config I2C_QCOM_CCI
will be called i2c-qcom-cci.
config I2C_QCOM_GENI
- tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
+ tristate "Qualcomm GENI based I2C controller"
depends on ARCH_QCOM || COMPILE_TEST
depends on QCOM_GENI_SE
help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 547123ab351f..3755c54b3d82 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_I2C_KEBA) += i2c-keba.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
+obj-$(CONFIG_I2C_LS2X_V2) += i2c-ls2x-v2.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c
index ca45f0f23321..b0b40fe1d79b 100644
--- a/drivers/i2c/busses/i2c-amd-asf-plat.c
+++ b/drivers/i2c/busses/i2c-amd-asf-plat.c
@@ -18,7 +18,6 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/sprintf.h>
@@ -90,6 +89,10 @@ static void amd_asf_process_target(struct work_struct *work)
outb_p(reg, ASFDATABNKSEL);
cmd = inb_p(ASFINDEX);
len = inb_p(ASFDATARWPTR);
+
+ if (len > ASF_BLOCK_MAX_BYTES)
+ return;
+
for (idx = 0; idx < len; idx++)
data[idx] = inb_p(ASFINDEX);
@@ -334,11 +337,11 @@ static int amd_asf_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return dev_err_probe(dev, irq, "missing IRQ resources\n");
+ return irq;
ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev);
if (ret)
- return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq);
+ return ret;
asf_dev->adap.owner = THIS_MODULE;
asf_dev->adap.algo = &amd_asf_smbus_algorithm;
diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c
index 188e24cc4d35..9fdd6a5fb8b6 100644
--- a/drivers/i2c/busses/i2c-amd-mp2-plat.c
+++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c
@@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platform_device *pdev)
amd_mp2_pm_runtime_put(mp2_dev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
+ amd_mp2_unregister_cb(&i2c_dev->common);
+ }
return ret;
}
diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c
index b64adef778d4..8ca4556d9664 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -255,6 +255,7 @@ static int at91_twi_probe(struct platform_device *pdev)
if (rc) {
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
+ at91_twi_dma_release(dev);
return rc;
}
@@ -270,6 +271,8 @@ static void at91_twi_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter);
+ at91_twi_dma_release(dev);
+
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
}
diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c
index 894cedbca99f..68238cc8aee0 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -817,11 +817,21 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
error:
if (ret != -EPROBE_DEFER)
dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n");
+ at91_twi_dma_release(dev);
+ return ret;
+}
+
+void at91_twi_dma_release(struct at91_twi_dev *dev)
+{
+ struct at91_twi_dma *dma = &dev->dma;
+
if (dma->chan_rx)
dma_release_channel(dma->chan_rx);
if (dma->chan_tx)
dma_release_channel(dma->chan_tx);
- return ret;
+ dma->chan_rx = NULL;
+ dma->chan_tx = NULL;
+ dev->use_dma = false;
}
static int at91_init_twi_recovery_gpio(struct platform_device *pdev,
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index 942e9c3973bb..d68fcbbc3e0f 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -172,6 +172,7 @@ void at91_twi_irq_restore(struct at91_twi_dev *dev);
void at91_init_twi_bus(struct at91_twi_dev *dev);
void at91_init_twi_bus_master(struct at91_twi_dev *dev);
+void at91_twi_dma_release(struct at91_twi_dev *dev);
int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr,
struct at91_twi_dev *dev);
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index b5629cffe99b..66bb3bfdaa4c 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -803,6 +803,17 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
}
if (!time_left && !iproc_i2c->xfer_is_done) {
+ /*
+ * The controller may fail to clear START_BUSY after a timeout,
+ * reset the controller to recover in that case.
+ */
+ if (!!(iproc_i2c_rd_reg(iproc_i2c, M_CMD_OFFSET) &
+ BIT(M_CMD_START_BUSY_SHIFT))) {
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+ bcm_iproc_i2c_init(iproc_i2c);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+ }
+
/* flush both TX/RX FIFOs */
val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
@@ -1136,8 +1147,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
bcm_iproc_i2c_isr, 0, pdev->name,
iproc_i2c);
if (ret < 0)
- return dev_err_probe(iproc_i2c->device, ret,
- "unable to request irq %i\n", irq);
+ return ret;
iproc_i2c->irq = irq;
} else {
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 9d8838bbd938..d4f287b31fd7 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -427,7 +427,7 @@ static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
return -EREMOTEIO;
}
- /* Check if a timeout occured */
+ /* Check if a timeout occurred */
if (!time_left) {
dev_err(dev->device, "completion timed out\n");
return -EREMOTEIO;
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 0fb728ade92e..da8770182a18 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -1635,6 +1635,25 @@ static void cdns_i2c_remove(struct platform_device *pdev)
reset_control_assert(id->reset);
}
+/**
+ * cdns_i2c_shutdown - Prepare I2C controller for system shutdown
+ * @pdev: Handle to the platform device structure
+ *
+ * Mark the adapter as suspended and reset the controller to ensure a clean
+ * handoff during system reboot or kexec.
+ */
+static void cdns_i2c_shutdown(struct platform_device *pdev)
+{
+ struct cdns_i2c *id = platform_get_drvdata(pdev);
+
+ /* Mark the adapter as suspended to prevent further I2C transfers */
+ i2c_mark_adapter_suspended(&id->adap);
+
+ /* Reset the controller state if active - clocks are disabled when suspended */
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ cdns_i2c_master_reset(&id->adap);
+}
+
static struct platform_driver cdns_i2c_drv = {
.driver = {
.name = DRIVER_NAME,
@@ -1643,6 +1662,7 @@ static struct platform_driver cdns_i2c_drv = {
},
.probe = cdns_i2c_probe,
.remove = cdns_i2c_remove,
+ .shutdown = cdns_i2c_shutdown,
};
module_platform_driver(cdns_i2c_drv);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index a773ba082321..e15eef163a8f 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -117,8 +117,6 @@
/* timeout for pm runtime autosuspend */
#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
-#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100
-
struct davinci_i2c_dev {
struct device *dev;
void __iomem *base;
@@ -760,7 +758,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
if (r)
- prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
+ prop = I2C_MAX_STANDARD_MODE_FREQ;
dev->bus_freq = prop / 1000;
@@ -818,12 +816,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
if (r)
- goto err_unuse_clocks;
+ goto err_cpufreq;
pm_runtime_put_autosuspend(dev->dev);
return 0;
+err_cpufreq:
+ i2c_davinci_cpufreq_deregister(dev);
err_unuse_clocks:
pm_runtime_dont_use_autosuspend(dev->dev);
pm_runtime_put_sync(dev->dev);
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 4dc57fd56170..a1eca6cd4b75 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -33,6 +33,8 @@
#include <linux/types.h>
#include <linux/units.h>
+#include <linux/designware_i2c.h>
+
#include "i2c-designware-core.h"
#define DW_IC_DEFAULT_BUS_CAPACITANCE_pF 100
@@ -633,6 +635,14 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
abort_needed = (raw_intr_stats & DW_IC_INTR_MST_ON_HOLD) ||
(ic_stats & DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY);
+
+ /*
+ * If we are in target mode and there is activity, we should also
+ * trigger an abort to clear the internal state machines.
+ */
+ if (dev->mode == DW_IC_SLAVE && (ic_stats & DW_IC_STATUS_SLAVE_ACTIVITY))
+ abort_needed = true;
+
if (abort_needed) {
if (!(enable & DW_IC_ENABLE_ENABLE)) {
regmap_write(dev->map, DW_IC_ENABLE, DW_IC_ENABLE_ENABLE);
@@ -958,8 +968,8 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
* registered to the device core and immediate resume in case bus has
* registered I2C slaves that do I2C transfers in their probe.
*/
- ACQUIRE(pm_runtime_noresume, pm)(dev->dev);
- ret = ACQUIRE_ERR(pm_runtime_noresume, &pm);
+ PM_RUNTIME_ACQUIRE(dev->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret)
return ret;
@@ -1028,5 +1038,29 @@ EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = {
RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL)
};
+void i2c_dw_shutdown(struct dw_i2c_dev *dev)
+{
+ unsigned int con;
+
+ /*
+ * We only need to handle shutdown for target mode to ensure
+ * we NACK any incoming controller requests. Controller mode cleanup
+ * is handled after each transfer in i2c_dw_xfer().
+ */
+ if (dev->mode != DW_IC_SLAVE)
+ return;
+
+ /*
+ * To quickly NACK the controller during shutdown, we set the target
+ * disable bit while the controller is still enabled.
+ */
+ regmap_read(dev->map, DW_IC_CON, &con);
+ con |= DW_IC_CON_SLAVE_DISABLE;
+ regmap_write(dev->map, DW_IC_CON, con);
+
+ i2c_dw_disable(dev);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_shutdown);
+
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9d8d104cc391..2c929a6e8da2 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -18,6 +18,8 @@
#include <linux/regmap.h>
#include <linux/types.h>
+#include <linux/designware_i2c.h>
+
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
@@ -25,23 +27,6 @@
I2C_FUNC_SMBUS_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
-#define DW_IC_CON_MASTER BIT(0)
-#define DW_IC_CON_SPEED_STD (1 << 1)
-#define DW_IC_CON_SPEED_FAST (2 << 1)
-#define DW_IC_CON_SPEED_HIGH (3 << 1)
-#define DW_IC_CON_SPEED_MASK GENMASK(2, 1)
-#define DW_IC_CON_10BITADDR_SLAVE BIT(3)
-#define DW_IC_CON_10BITADDR_MASTER BIT(4)
-#define DW_IC_CON_RESTART_EN BIT(5)
-#define DW_IC_CON_SLAVE_DISABLE BIT(6)
-#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
-#define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
-#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
-#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11)
-
-#define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
-#define DW_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11)
-
/*
* Register access parameters
*/
@@ -55,65 +40,9 @@
#define DW_IC_FIFO_RX_FIELD GENMASK(15, 8)
#define DW_IC_FIFO_MIN_DEPTH 2
-/*
- * Registers offset
- */
-#define DW_IC_CON 0x00
-#define DW_IC_TAR 0x04
-#define DW_IC_SAR 0x08
-#define DW_IC_DATA_CMD 0x10
-#define DW_IC_SS_SCL_HCNT 0x14
-#define DW_IC_SS_SCL_LCNT 0x18
-#define DW_IC_FS_SCL_HCNT 0x1c
-#define DW_IC_FS_SCL_LCNT 0x20
-#define DW_IC_HS_SCL_HCNT 0x24
-#define DW_IC_HS_SCL_LCNT 0x28
-#define DW_IC_INTR_STAT 0x2c
-#define DW_IC_INTR_MASK 0x30
-#define DW_IC_RAW_INTR_STAT 0x34
-#define DW_IC_RX_TL 0x38
-#define DW_IC_TX_TL 0x3c
-#define DW_IC_CLR_INTR 0x40
-#define DW_IC_CLR_RX_UNDER 0x44
-#define DW_IC_CLR_RX_OVER 0x48
-#define DW_IC_CLR_TX_OVER 0x4c
-#define DW_IC_CLR_RD_REQ 0x50
-#define DW_IC_CLR_TX_ABRT 0x54
-#define DW_IC_CLR_RX_DONE 0x58
-#define DW_IC_CLR_ACTIVITY 0x5c
-#define DW_IC_CLR_STOP_DET 0x60
-#define DW_IC_CLR_START_DET 0x64
-#define DW_IC_CLR_GEN_CALL 0x68
-#define DW_IC_ENABLE 0x6c
-#define DW_IC_STATUS 0x70
-#define DW_IC_TXFLR 0x74
-#define DW_IC_RXFLR 0x78
-#define DW_IC_SDA_HOLD 0x7c
-#define DW_IC_TX_ABRT_SOURCE 0x80
-#define DW_IC_ENABLE_STATUS 0x9c
-#define DW_IC_CLR_RESTART_DET 0xa8
-#define DW_IC_SMBUS_INTR_MASK 0xcc
-#define DW_IC_COMP_PARAM_1 0xf4
-#define DW_IC_COMP_VERSION 0xf8
#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */
-#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140 /* "DW" + 0x0140 */
-#define DW_IC_INTR_RX_UNDER BIT(0)
-#define DW_IC_INTR_RX_OVER BIT(1)
-#define DW_IC_INTR_RX_FULL BIT(2)
-#define DW_IC_INTR_TX_OVER BIT(3)
-#define DW_IC_INTR_TX_EMPTY BIT(4)
-#define DW_IC_INTR_RD_REQ BIT(5)
-#define DW_IC_INTR_TX_ABRT BIT(6)
-#define DW_IC_INTR_RX_DONE BIT(7)
-#define DW_IC_INTR_ACTIVITY BIT(8)
-#define DW_IC_INTR_STOP_DET BIT(9)
-#define DW_IC_INTR_START_DET BIT(10)
-#define DW_IC_INTR_GEN_CALL BIT(11)
-#define DW_IC_INTR_RESTART_DET BIT(12)
-#define DW_IC_INTR_MST_ON_HOLD BIT(13)
-
#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
DW_IC_INTR_TX_ABRT | \
DW_IC_INTR_STOP_DET)
@@ -123,16 +52,6 @@
DW_IC_INTR_RX_UNDER | \
DW_IC_INTR_RD_REQ)
-#define DW_IC_ENABLE_ENABLE BIT(0)
-#define DW_IC_ENABLE_ABORT BIT(1)
-
-#define DW_IC_STATUS_ACTIVITY BIT(0)
-#define DW_IC_STATUS_TFE BIT(2)
-#define DW_IC_STATUS_RFNE BIT(3)
-#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
-#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
-#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7)
-
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
@@ -417,6 +336,7 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
int i2c_dw_probe(struct dw_i2c_dev *dev);
int i2c_dw_init(struct dw_i2c_dev *dev);
+void i2c_dw_shutdown(struct dw_i2c_dev *dev);
void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index de929b91d5ea..a1bcc3797e4f 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -25,6 +25,8 @@
#include <linux/regmap.h>
#include <linux/reset.h>
+#include <linux/designware_i2c.h>
+
#include "i2c-designware-core.h"
#define AMD_TIMEOUT_MIN_US 25
@@ -785,18 +787,25 @@ __i2c_dw_xfer_one_part(struct dw_i2c_dev *dev, struct i2c_msg *msgs, size_t num)
* IC_RAW_INTR_STAT.MASTER_ON_HOLD holding SCL low. Check if
* controller is still ACTIVE before disabling I2C.
*/
- if (i2c_dw_is_controller_active(dev))
- dev_err(dev->dev, "controller active\n");
-
- /*
- * We must disable the adapter before returning and signaling the end
- * of the current transfer. Otherwise the hardware might continue
- * generating interrupts which in turn causes a race condition with
- * the following transfer. Needs some more investigation if the
- * additional interrupts are a hardware bug or this driver doesn't
- * handle them correctly yet.
- */
- __i2c_dw_disable_nowait(dev);
+ if (i2c_dw_is_controller_active(dev)) {
+ /*
+ * If the controller is still active after the timeout, attempt a
+ * bus recovery to clear any potentially locked state.
+ */
+ dev_err(dev->dev, "controller active after xfer, recovering\n");
+ i2c_recover_bus(&dev->adapter);
+ i2c_dw_init(dev);
+ } else {
+ /*
+ * We must disable the adapter before returning and signaling the end
+ * of the current transfer. Otherwise the hardware might continue
+ * generating interrupts which in turn causes a race condition with
+ * the following transfer. Needs some more investigation if the
+ * additional interrupts are a hardware bug or this driver doesn't
+ * handle them correctly yet.
+ */
+ __i2c_dw_disable_nowait(dev);
+ }
if (dev->msg_err)
return dev->msg_err;
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index f21f9877c040..468287922363 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -308,58 +308,72 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
static const struct pci_device_id i2c_designware_pci_ids[] = {
/* Medfield */
- { PCI_VDEVICE(INTEL, 0x0817), medfield },
- { PCI_VDEVICE(INTEL, 0x0818), medfield },
- { PCI_VDEVICE(INTEL, 0x0819), medfield },
- { PCI_VDEVICE(INTEL, 0x082C), medfield },
- { PCI_VDEVICE(INTEL, 0x082D), medfield },
- { PCI_VDEVICE(INTEL, 0x082E), medfield },
+ { PCI_VDEVICE(INTEL, 0x0817), .driver_data = medfield },
+ { PCI_VDEVICE(INTEL, 0x0818), .driver_data = medfield },
+ { PCI_VDEVICE(INTEL, 0x0819), .driver_data = medfield },
+ { PCI_VDEVICE(INTEL, 0x082C), .driver_data = medfield },
+ { PCI_VDEVICE(INTEL, 0x082D), .driver_data = medfield },
+ { PCI_VDEVICE(INTEL, 0x082E), .driver_data = medfield },
/* Merrifield */
- { PCI_VDEVICE(INTEL, 0x1195), merrifield },
- { PCI_VDEVICE(INTEL, 0x1196), merrifield },
+ { PCI_VDEVICE(INTEL, 0x1195), .driver_data = merrifield },
+ { PCI_VDEVICE(INTEL, 0x1196), .driver_data = merrifield },
/* Baytrail */
- { PCI_VDEVICE(INTEL, 0x0F41), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F42), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F43), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F44), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F45), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F46), baytrail },
- { PCI_VDEVICE(INTEL, 0x0F47), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F41), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F42), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F43), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F44), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F45), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F46), .driver_data = baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F47), .driver_data = baytrail },
/* Haswell */
- { PCI_VDEVICE(INTEL, 0x9c61), haswell },
- { PCI_VDEVICE(INTEL, 0x9c62), haswell },
+ { PCI_VDEVICE(INTEL, 0x9c61), .driver_data = haswell },
+ { PCI_VDEVICE(INTEL, 0x9c62), .driver_data = haswell },
/* Braswell / Cherrytrail */
- { PCI_VDEVICE(INTEL, 0x22C1), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C2), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C3), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C4), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C5), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C6), cherrytrail },
- { PCI_VDEVICE(INTEL, 0x22C7), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C1), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C2), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C3), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C4), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C5), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C6), .driver_data = cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C7), .driver_data = cherrytrail },
/* Elkhart Lake (PSE I2C) */
- { PCI_VDEVICE(INTEL, 0x4bb9), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bba), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bbb), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bbc), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bbd), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
- { PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bb9), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bba), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bbb), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bbc), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bbd), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bbe), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bbf), .driver_data = elkhartlake },
+ { PCI_VDEVICE(INTEL, 0x4bc0), .driver_data = elkhartlake },
/* AMD NAVI */
- { PCI_VDEVICE(ATI, 0x7314), navi_amd },
- { PCI_VDEVICE(ATI, 0x73a4), navi_amd },
- { PCI_VDEVICE(ATI, 0x73e4), navi_amd },
- { PCI_VDEVICE(ATI, 0x73c4), navi_amd },
- { PCI_VDEVICE(ATI, 0x7444), navi_amd },
- { PCI_VDEVICE(ATI, 0x7464), navi_amd },
- {}
+ { PCI_VDEVICE(ATI, 0x7314), .driver_data = navi_amd },
+ { PCI_VDEVICE(ATI, 0x73a4), .driver_data = navi_amd },
+ { PCI_VDEVICE(ATI, 0x73e4), .driver_data = navi_amd },
+ { PCI_VDEVICE(ATI, 0x73c4), .driver_data = navi_amd },
+ { PCI_VDEVICE(ATI, 0x7444), .driver_data = navi_amd },
+ { PCI_VDEVICE(ATI, 0x7464), .driver_data = navi_amd },
+ { }
};
MODULE_DEVICE_TABLE(pci, i2c_designware_pci_ids);
+static void i2c_dw_pci_shutdown(struct pci_dev *pdev)
+{
+ struct dw_i2c_dev *i_dev;
+
+ i_dev = pci_get_drvdata(pdev);
+ if (!i_dev)
+ return;
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ i2c_dw_shutdown(i_dev);
+}
+
static struct pci_driver dw_i2c_driver = {
.name = DRIVER_NAME,
.probe = i2c_dw_pci_probe,
.remove = i2c_dw_pci_remove,
+ .shutdown = i2c_dw_pci_shutdown,
.driver = {
.pm = pm_ptr(&i2c_dw_dev_pm_ops),
},
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 3351c4a9ef11..447af5523c2e 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -272,13 +272,14 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "HISI02A1", 0 },
{ "HISI02A2", 0 },
{ "HISI02A3", 0 },
- { "HJMC3001", 0 },
+ { "HJMC3001", ACCESS_INTR_MASK },
{ "HYGO0010", ACCESS_INTR_MASK },
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
{ "INTC10EF", 0 },
+ { "LECA0003", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@@ -289,9 +290,23 @@ static const struct platform_device_id dw_i2c_platform_ids[] = {
};
MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids);
+static void dw_i2c_plat_shutdown(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *i_dev;
+
+ i_dev = platform_get_drvdata(pdev);
+ if (!i_dev)
+ return;
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ i2c_dw_shutdown(i_dev);
+}
+
static struct platform_driver dw_i2c_driver = {
.probe = dw_i2c_plat_probe,
.remove = dw_i2c_plat_remove,
+ .shutdown = dw_i2c_plat_shutdown,
.driver = {
.name = "i2c_designware",
.of_match_table = dw_i2c_of_match,
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index ad0d5fbfa6d5..0abcc7757b23 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -19,6 +19,8 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/designware_i2c.h>
+
#include "i2c-designware-core.h"
int i2c_dw_reg_slave(struct i2c_client *slave)
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index f83238868802..8c67ab4f2aad 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -169,11 +169,11 @@ static DEFINE_MUTEX(pch_mutex);
#define PCI_DEVICE_ID_ML7831_I2C 0x8817
static const struct pci_device_id pch_pcidev_id[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
- { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
- { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
- { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
- {0,}
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), .driver_data = 1 },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), .driver_data = 2 },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), .driver_data = 1 },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), .driver_data = 1 },
+ { }
};
MODULE_DEVICE_TABLE(pci, pch_pcidev_id);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index f4355b17bfbf..6294b0b0cc8f 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -18,9 +18,21 @@
#include <linux/property.h>
#include <linux/slab.h>
+static LIST_HEAD(i2c_gpio_scl_list);
+static DEFINE_MUTEX(i2c_gpio_scl_list_lock);
+static struct lock_class_key i2c_gpio_scl_lock_key;
+
+struct i2c_gpio_scl_data {
+ struct fwnode_reference_args args;
+ struct gpio_desc *gpio;
+ struct rt_mutex lock;
+ struct list_head list;
+ refcount_t ref;
+};
+
struct i2c_gpio_private_data {
struct gpio_desc *sda;
- struct gpio_desc *scl;
+ struct i2c_gpio_scl_data *scl;
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
@@ -31,6 +43,11 @@ struct i2c_gpio_private_data {
#endif
};
+static inline struct i2c_gpio_private_data *adap_to_priv(struct i2c_adapter *adap)
+{
+ return container_of(adap, struct i2c_gpio_private_data, adap);
+}
+
/*
* 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
@@ -53,7 +70,7 @@ static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
- gpiod_set_value_cansleep(priv->scl, state);
+ gpiod_set_value_cansleep(priv->scl->gpio, state);
}
static int i2c_gpio_getsda(void *data)
@@ -67,9 +84,41 @@ static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_private_data *priv = data;
- return gpiod_get_value_cansleep(priv->scl);
+ return gpiod_get_value_cansleep(priv->scl->gpio);
+}
+
+static void i2c_gpio_lock_bus(struct i2c_adapter *adap, unsigned int flags)
+{
+ /* Take care about adapter lock. See i2c_adapter_lock_bus() and others. */
+ rt_mutex_lock_nested(&adap->bus_lock, i2c_adapter_depth(adap));
+ rt_mutex_lock(&adap_to_priv(adap)->scl->lock);
+}
+
+static int i2c_gpio_trylock_bus(struct i2c_adapter *adap, unsigned int flags)
+{
+ if (!rt_mutex_trylock(&adap->bus_lock))
+ return 0;
+
+ if (!rt_mutex_trylock(&adap_to_priv(adap)->scl->lock)) {
+ rt_mutex_unlock(&adap->bus_lock);
+ return 0;
+ }
+
+ return 1;
}
+static void i2c_gpio_unlock_bus(struct i2c_adapter *adap, unsigned int flags)
+{
+ rt_mutex_unlock(&adap_to_priv(adap)->scl->lock);
+ rt_mutex_unlock(&adap->bus_lock);
+}
+
+static const struct i2c_lock_operations i2c_gpio_lock_ops = {
+ .lock_bus = i2c_gpio_lock_bus,
+ .trylock_bus = i2c_gpio_trylock_bus,
+ .unlock_bus = i2c_gpio_unlock_bus,
+};
+
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
@@ -165,14 +214,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write
static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
irqreturn_t handler(int, void*))
{
- int ret, irq = gpiod_to_irq(priv->scl);
+ int ret, irq = gpiod_to_irq(priv->scl->gpio);
if (irq < 0)
return irq;
i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
- ret = gpiod_direction_input(priv->scl);
+ ret = gpiod_direction_input(priv->scl->gpio);
if (ret)
goto unlock;
@@ -187,7 +236,7 @@ static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
free_irq(irq, priv);
output:
- ret = gpiod_direction_output(priv->scl, 1) ?: ret;
+ ret = gpiod_direction_output(priv->scl->gpio, 1) ?: ret;
unlock:
i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
@@ -308,13 +357,17 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
struct gpio_desc *retdesc;
int ret;
- retdesc = devm_gpiod_get(dev, con_id, gflags);
+ /*
+ * Don't use resource-managed functions. SCL may be shared across adapters and has
+ * its own lifetime management. SDA uses the same path for consistency.
+ */
+ retdesc = 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);
+ retdesc = gpiod_get_index(dev, NULL, index, gflags);
if (!IS_ERR(retdesc)) {
dev_dbg(dev, "got GPIO from index %u\n", index);
return retdesc;
@@ -336,6 +389,134 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
return retdesc;
}
+static struct i2c_gpio_scl_data *i2c_gpio_create_scl(struct device *dev)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct fwnode_reference_args args;
+ struct i2c_gpio_scl_data *scl;
+ bool sharable = false;
+ int ret;
+
+ /*
+ * SCL gpios can be shared if they are defined in the devicetree and have at least one
+ * cell in addition to the phandle. This is usually the pin. To support complex designs
+ * with arbitrary of_xlate() mappings handle the node cells opaque.
+ */
+ if (fwnode) {
+ ret = fwnode_property_get_reference_args(fwnode, "scl-gpios",
+ "#gpio-cells", 0, 0, &args);
+ if (ret)
+ /* try the ancient way */
+ ret = fwnode_property_get_reference_args(fwnode, "gpios",
+ "#gpio-cells", 0, 1, &args);
+
+ if (!ret) {
+ if (args.nargs >= 1)
+ sharable = true;
+ else
+ fwnode_handle_put(args.fwnode);
+ }
+ }
+
+ scl = kzalloc_obj(*scl);
+ if (!scl) {
+ if (sharable)
+ fwnode_handle_put(args.fwnode);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (sharable) {
+ scl->args.fwnode = args.fwnode;
+ scl->args.nargs = args.nargs;
+ memcpy(scl->args.args, args.args, sizeof(args.args[0]) * args.nargs);
+ }
+
+ rt_mutex_init(&scl->lock);
+ lockdep_set_class(&scl->lock, &i2c_gpio_scl_lock_key);
+ refcount_set(&scl->ref, 1);
+
+ return scl;
+}
+
+static void i2c_gpio_free_scl(struct i2c_gpio_scl_data *scl)
+{
+ if (scl->args.fwnode)
+ fwnode_handle_put(scl->args.fwnode);
+ kfree(scl);
+}
+
+static bool i2c_gpio_scl_matches(struct i2c_gpio_scl_data *a, struct i2c_gpio_scl_data *b)
+{
+ if (!a->args.fwnode || !b->args.fwnode ||
+ a->args.fwnode != b->args.fwnode || a->args.nargs != b->args.nargs)
+ return false;
+
+ return memcmp(a->args.args, b->args.args, sizeof(a->args.args[0]) * a->args.nargs) == 0;
+}
+
+/*
+ * Look up an existing or create a new shared SCL structure. Optimistic setup sequence always
+ * creates and tries to add a new entry to the list. This uses minimum locking and afterwards
+ * requests the GPIO without a lock held. Concurrent probes for the same SCL pin see the entry
+ * and do not race into a second gpiod_get(). Until everything is setup they terminate with
+ * -EPROBE_DEFER.
+ */
+static struct i2c_gpio_scl_data *i2c_gpio_lookup_scl(struct device *dev, enum gpiod_flags gflags)
+{
+ struct i2c_gpio_scl_data *scl, *new_scl;
+ struct gpio_desc *gpio;
+
+ new_scl = i2c_gpio_create_scl(dev);
+ if (IS_ERR(new_scl))
+ return new_scl;
+
+ scoped_guard(mutex, &i2c_gpio_scl_list_lock) {
+ list_for_each_entry(scl, &i2c_gpio_scl_list, list) {
+ if (!i2c_gpio_scl_matches(scl, new_scl))
+ continue;
+
+ i2c_gpio_free_scl(new_scl);
+ if (!scl->gpio)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ refcount_inc(&scl->ref);
+ if (scl->args.fwnode)
+ dev_dbg(dev, "reusing shared SCL (%pfwP)\n", scl->args.fwnode);
+
+ return scl;
+ }
+ list_add(&new_scl->list, &i2c_gpio_scl_list);
+ }
+
+ gpio = i2c_gpio_get_desc(dev, "scl", 1, gflags);
+ if (IS_ERR(gpio)) {
+ scoped_guard(mutex, &i2c_gpio_scl_list_lock)
+ list_del(&new_scl->list);
+ i2c_gpio_free_scl(new_scl);
+
+ return ERR_CAST(gpio);
+ }
+
+ scoped_guard(mutex, &i2c_gpio_scl_list_lock)
+ new_scl->gpio = gpio;
+
+ if (new_scl->args.fwnode)
+ dev_dbg(dev, "registered shared SCL (%pfwP)\n", new_scl->args.fwnode);
+
+ return new_scl;
+}
+
+static void i2c_gpio_cleanup_scl(struct i2c_gpio_scl_data *scl)
+{
+ if (!refcount_dec_and_mutex_lock(&scl->ref, &i2c_gpio_scl_list_lock))
+ return;
+
+ list_del(&scl->list);
+ mutex_unlock(&i2c_gpio_scl_list_lock);
+ gpiod_put(scl->gpio);
+ i2c_gpio_free_scl(scl);
+}
+
static int i2c_gpio_probe(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv;
@@ -386,15 +567,18 @@ static int i2c_gpio_probe(struct platform_device *pdev)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
- priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags);
- if (IS_ERR(priv->scl))
- return PTR_ERR(priv->scl);
+ priv->scl = i2c_gpio_lookup_scl(dev, gflags);
+ if (IS_ERR(priv->scl)) {
+ ret = PTR_ERR(priv->scl);
+ goto err_cleanup_sda;
+ }
- if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
+ if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl->gpio))
dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
else
bit_data->can_do_atomic = true;
+ bit_data->skip_bit_test = !!priv->scl->args.fwnode;
bit_data->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val;
@@ -423,6 +607,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+ /* Always use shared SCL aware locking */
+ adap->lock_ops = &i2c_gpio_lock_ops;
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON;
adap->dev.parent = dev;
@@ -431,7 +617,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
- return ret;
+ goto err_cleanup_scl;
platform_set_drvdata(pdev, priv);
@@ -441,13 +627,20 @@ static int i2c_gpio_probe(struct platform_device *pdev)
* from the descriptor, then provide that instead.
*/
dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n",
- desc_to_gpio(priv->sda), desc_to_gpio(priv->scl),
+ desc_to_gpio(priv->sda), desc_to_gpio(priv->scl->gpio),
pdata->scl_is_output_only
? ", no clock stretching" : "");
i2c_gpio_fault_injector_init(pdev);
return 0;
+
+err_cleanup_scl:
+ i2c_gpio_cleanup_scl(priv->scl);
+err_cleanup_sda:
+ gpiod_put(priv->sda);
+
+ return ret;
}
static void i2c_gpio_remove(struct platform_device *pdev)
@@ -459,6 +652,8 @@ static void i2c_gpio_remove(struct platform_device *pdev)
adap = &priv->adap;
i2c_del_adapter(adap);
+ i2c_gpio_cleanup_scl(priv->scl);
+ gpiod_put(priv->sda);
}
static const struct of_device_id i2c_gpio_dt_ids[] = {
diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c
index 2d117e7e3cb6..6a5cef7e4383 100644
--- a/drivers/i2c/busses/i2c-gxp.c
+++ b/drivers/i2c/busses/i2c-gxp.c
@@ -4,7 +4,6 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -552,7 +551,7 @@ static int gxp_i2c_probe(struct platform_device *pdev)
rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler,
IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata);
if (rc < 0)
- return dev_err_probe(&pdev->dev, rc, "irq request failed\n");
+ return rc;
i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true);
diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c
index 4b735ad9e193..ba5c9579ae19 100644
--- a/drivers/i2c/busses/i2c-hisi.c
+++ b/drivers/i2c/busses/i2c-hisi.c
@@ -13,7 +13,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
@@ -482,7 +481,7 @@ static int hisi_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq handler\n");
+ return ret;
ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR_OR_NULL(ctlr->clk)) {
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 32a3cef02c7b..b29c99ed3883 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
*/
if (hwpec)
iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
-out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
* and clear status flags if not done already.
*/
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
+out:
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
return ret;
diff --git a/drivers/i2c/busses/i2c-icy.c b/drivers/i2c/busses/i2c-icy.c
index febcb6f01d4d..55496e48ccd1 100644
--- a/drivers/i2c/busses/i2c-icy.c
+++ b/drivers/i2c/busses/i2c-icy.c
@@ -193,8 +193,8 @@ static void icy_remove(struct zorro_dev *z)
}
static const struct zorro_device_id icy_zorro_tbl[] = {
- { ZORRO_ID(VMC, 15, 0), },
- { 0 }
+ { .id = ZORRO_ID(VMC, 15, 0) },
+ { }
};
MODULE_DEVICE_TABLE(zorro, icy_zorro_tbl);
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index a01c23696481..1cfd7a4c8237 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -29,6 +29,7 @@
#define DRIVER_NAME "imx-lpi2c"
+#define LPI2C_VERID 0x00 /* i2c version ID */
#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
#define LPI2C_MCR 0x10 /* i2c contrl register */
#define LPI2C_MSR 0x14 /* i2c status register */
@@ -136,6 +137,9 @@
#define I2C_PM_LONG_TIMEOUT_MS 1000 /* Avoid dead lock caused by big clock prepare lock */
#define I2C_DMA_THRESHOLD 8 /* bytes */
+/* Bit 0 indicates the presence of the target feature */
+#define VERID_FEATURE_TARGET_PRESENT BIT(0)
+
enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */
FAST, /* 400+Kbps */
@@ -194,6 +198,7 @@ struct lpi2c_imx_struct {
bool can_use_dma;
struct lpi2c_imx_dma *dma;
struct i2c_client *target;
+ bool target_supported;
int irq;
const struct imx_lpi2c_hwdata *hwdata;
};
@@ -1330,6 +1335,10 @@ static int lpi2c_imx_register_target(struct i2c_client *client)
struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter);
int ret;
+ /* Reject target-mode registration on controllers that don't support it. */
+ if (!lpi2c_imx->target_supported)
+ return -EOPNOTSUPP;
+
if (lpi2c_imx->target)
return -EBUSY;
@@ -1383,55 +1392,66 @@ static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
return 0;
}
-static void dma_exit(struct device *dev, struct lpi2c_imx_dma *dma)
-{
- if (dma->chan_rx)
- dma_release_channel(dma->chan_rx);
-
- if (dma->chan_tx)
- dma_release_channel(dma->chan_tx);
-
- devm_kfree(dev, dma);
-}
-
static int lpi2c_dma_init(struct device *dev, dma_addr_t phy_addr)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
struct lpi2c_imx_dma *dma;
+ void *group;
int ret;
- dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
- if (!dma)
+ /*
+ * Open a devres group so that all resources allocated within
+ * this function can be released together if DMA init fails but
+ * probe continues in PIO mode.
+ */
+ group = devres_open_group(dev, NULL, GFP_KERNEL);
+ if (!group)
return -ENOMEM;
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma) {
+ ret = -ENOMEM;
+ goto release_group;
+ }
+
dma->phy_addr = phy_addr;
/* Prepare for TX DMA: */
- dma->chan_tx = dma_request_chan(dev, "tx");
+ dma->chan_tx = devm_dma_request_chan(dev, "tx");
if (IS_ERR(dma->chan_tx)) {
ret = PTR_ERR(dma->chan_tx);
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(dev, "can't request DMA tx channel (%d)\n", ret);
- dma->chan_tx = NULL;
- goto dma_exit;
+ goto release_group;
}
/* Prepare for RX DMA: */
- dma->chan_rx = dma_request_chan(dev, "rx");
+ dma->chan_rx = devm_dma_request_chan(dev, "rx");
if (IS_ERR(dma->chan_rx)) {
ret = PTR_ERR(dma->chan_rx);
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(dev, "can't request DMA rx channel (%d)\n", ret);
- dma->chan_rx = NULL;
- goto dma_exit;
+ goto release_group;
}
+ /*
+ * DMA init succeeded. Remove the group marker but keep all resources
+ * bound to the device, they will be freed at device removal.
+ */
+ devres_remove_group(dev, group);
+
lpi2c_imx->can_use_dma = true;
lpi2c_imx->dma = dma;
return 0;
-dma_exit:
- dma_exit(dev, dma);
+release_group:
+ /*
+ * DMA init failed. Release ALL resources allocated inside this
+ * group (dma memory, TX channel if already acquired, etc.) so
+ * that a successful PIO-mode probe does not hold unused resources
+ * for the entire device lifetime.
+ */
+ devres_release_group(dev, group);
return ret;
}
@@ -1499,11 +1519,6 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
if (ret)
lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
- ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
- pdev->name, lpi2c_imx);
- if (ret)
- return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq);
-
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
platform_set_drvdata(pdev, lpi2c_imx);
@@ -1516,14 +1531,18 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
* each transfer
*/
ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk);
- if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "can't lock I2C peripheral clock rate\n");
+ if (ret) {
+ ret = dev_err_probe(&pdev->dev, ret,
+ "can't lock I2C peripheral clock rate\n");
+ goto clk_disable;
+ }
lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk);
- if (!lpi2c_imx->rate_per)
- return dev_err_probe(&pdev->dev, -EINVAL,
- "can't get I2C peripheral clock rate\n");
+ if (!lpi2c_imx->rate_per) {
+ ret = dev_err_probe(&pdev->dev, -EINVAL,
+ "can't get I2C peripheral clock rate\n");
+ goto clk_disable;
+ }
if (lpi2c_imx->hwdata->need_prepare_unprepare_clk)
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS);
@@ -1535,6 +1554,30 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ /*
+ * Reset all internal controller registers to avoid effects of any
+ * state left over from a previous stage (e.g. the bootloader).
+ *
+ * The Master block (MCR) is present on every controller, so reset it
+ * unconditionally. VERID shows whether the target feature is supported.
+ * Do not touch the Target block (SCR) on a master-only controller to
+ * avoid an asynchronous SError.
+ */
+ writel(MCR_RST, lpi2c_imx->base + LPI2C_MCR);
+ writel(0, lpi2c_imx->base + LPI2C_MCR);
+
+ lpi2c_imx->target_supported = !!(readl(lpi2c_imx->base + LPI2C_VERID) &
+ VERID_FEATURE_TARGET_PRESENT);
+ if (lpi2c_imx->target_supported) {
+ writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
+ writel(0, lpi2c_imx->base + LPI2C_SCR);
+ }
+
+ ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
+ pdev->name, lpi2c_imx);
+ if (ret)
+ goto rpm_disable;
+
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
@@ -1565,8 +1608,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
rpm_disable:
pm_runtime_dont_use_autosuspend(&pdev->dev);
- pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+clk_disable:
+ clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks);
return ret;
}
@@ -1635,7 +1681,18 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
static int __maybe_unused lpi2c_suspend_noirq(struct device *dev)
{
- return pm_runtime_force_suspend(dev);
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ i2c_mark_adapter_suspended(&lpi2c_imx->adapter);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+ return ret;
+ }
+
+ return 0;
}
static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
@@ -1655,6 +1712,8 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
if (lpi2c_imx->target)
lpi2c_imx_target_init(lpi2c_imx);
+ i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
+
return 0;
}
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a208fefd3c3b..ff5a91158df9 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
if (i2c_imx->slave)
return -EBUSY;
- i2c_imx->slave = client;
- i2c_imx->last_slave_event = I2C_SLAVE_STOP;
-
/* Resume */
ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (ret < 0) {
@@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
return ret;
}
+ scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
+ i2c_imx->slave = client;
+ i2c_imx->last_slave_event = I2C_SLAVE_STOP;
+ }
+
i2c_imx_slave_init(i2c_imx);
return 0;
@@ -958,6 +960,7 @@ static int i2c_imx_unreg_slave(struct i2c_client *client)
i2c_imx_reset_regs(i2c_imx);
+ hrtimer_cancel(&i2c_imx->slave_timer);
i2c_imx->slave = NULL;
/* Suspend */
@@ -1061,11 +1064,28 @@ static inline enum imx_i2c_state i2c_imx_isr_read_continue(struct imx_i2c_struct
static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
{
u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ unsigned int temp;
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
+ /*
+ * SMBus 3.1 6.5.7: support count byte of 0.
+ * I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
+ * So NACK it (TXAK) to not hold the bus.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ if (len == 0) {
+ i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = 0;
+ i2c_imx->msg->len = 2;
+ return;
+ }
+
i2c_imx->isr_result = -EPROTO;
i2c_imx->state = IMX_I2C_STATE_FAILED;
wake_up(&i2c_imx->queue);
+ return;
}
i2c_imx->msg->len += len;
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len;
@@ -1415,6 +1435,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
int i, result;
unsigned int temp;
int block_data = msgs->flags & I2C_M_RECV_LEN;
+ int block_err = 0;
result = i2c_imx_prepare_read(i2c_imx, msgs, false);
if (result)
@@ -1436,8 +1457,20 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
*/
if ((!i) && block_data) {
len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
- if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
- return -EPROTO;
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ /*
+ * SMBus 3.1 6.5.7: support count byte of 0.
+ * I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
+ */
+ if (len > I2C_SMBUS_BLOCK_MAX)
+ block_err = -EPROTO;
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ msgs->buf[0] = 0;
+ msgs->len = 2;
+ continue;
+ }
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read length: 0x%X\n",
__func__, len);
@@ -1485,7 +1518,7 @@ static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
}
- return 0;
+ return block_err;
}
static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
@@ -1720,7 +1753,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return dev_err_probe(&pdev->dev, irq, "can't get IRQ\n");
+ return irq;
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
@@ -1847,6 +1880,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
clk_notifier_unregister:
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+ if (i2c_imx->dma)
+ i2c_imx_dma_free(i2c_imx);
free_irq(irq, i2c_imx);
rpm_disable:
pm_runtime_put_noidle(&pdev->dev);
@@ -1887,14 +1922,21 @@ static void i2c_imx_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
}
static int i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pinctrl_pm_select_sleep_state(dev);
+ if (ret)
+ return ret;
clk_disable(i2c_imx->clk);
- return pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
}
static int i2c_imx_runtime_resume(struct device *dev)
@@ -1907,10 +1949,54 @@ static int i2c_imx_runtime_resume(struct device *dev)
return ret;
ret = clk_enable(i2c_imx->clk);
- if (ret)
+ if (ret) {
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
+ pinctrl_pm_select_sleep_state(dev);
+ return ret;
+ }
- return ret;
+ return 0;
+}
+
+static int __maybe_unused i2c_imx_suspend_noirq(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ i2c_mark_adapter_suspended(&i2c_imx->adapter);
+
+ /*
+ * Cancel the slave timer before powering down to prevent
+ * i2c_imx_slave_timeout() from accessing hardware registers
+ * while the clock is disabled.
+ */
+ hrtimer_cancel(&i2c_imx->slave_timer);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ i2c_mark_adapter_resumed(&i2c_imx->adapter);
+ if (i2c_imx->slave) {
+ hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY);
+ hrtimer_restart(&i2c_imx->slave_timer);
+ }
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused i2c_imx_resume_noirq(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ i2c_mark_adapter_resumed(&i2c_imx->adapter);
+
+ return 0;
}
static int i2c_imx_suspend(struct device *dev)
@@ -1946,8 +2032,8 @@ static int i2c_imx_resume(struct device *dev)
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
- NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend_noirq,
+ i2c_imx_resume_noirq)
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
};
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
index 664a5471d933..695be3b21460 100644
--- a/drivers/i2c/busses/i2c-jz4780.c
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -141,6 +141,7 @@ struct jz4780_i2c {
void __iomem *iomem;
int irq;
struct clk *clk;
+ unsigned long clk_rate_khz;
struct i2c_adapter adap;
const struct ingenic_i2c_config *cdata;
@@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
{
- int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
+ int dev_clk_khz = i2c->clk_rate_khz;
int cnt_high = 0; /* HIGH period count of the SCL clock */
int cnt_low = 0; /* LOW period count of the SCL clock */
int cnt_period = 0; /* period count of the SCL clock */
@@ -796,6 +797,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->clk))
return PTR_ERR(i2c->clk);
+ i2c->clk_rate_khz = clk_get_rate(i2c->clk) / 1000;
+
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&clk_freq);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
index 9152cf436bea..4e1d67541132 100644
--- a/drivers/i2c/busses/i2c-k1.c
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -4,7 +4,9 @@
*/
#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@@ -17,6 +19,8 @@
#define SPACEMIT_ISR 0x4 /* Status register */
#define SPACEMIT_IDBR 0xc /* Data buffer register */
#define SPACEMIT_IRCR 0x18 /* Reset cycle counter */
+#define SPACEMIT_ILCR 0x10 /* Load Count Register */
+#define SPACEMIT_IWCR 0x14 /* Wait Count Register */
#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
/* SPACEMIT_ICR register fields */
@@ -88,12 +92,22 @@
#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
+#define SPACEMIT_LCR_LV_STANDARD_MASK GENMASK(8, 0)
+#define SPACEMIT_LCR_LV_FAST_MASK GENMASK(17, 9)
+
+/* SPACEMIT_IWCR register fields */
+#define SPACEMIT_WCR_COUNT GENMASK(4, 0)
+#define SPACEMIT_WCR_HS_COUNT1 GENMASK(9, 5)
+#define SPACEMIT_WCR_HS_COUNT2 GENMASK(14, 10)
+
+/* Required by I2C IP for correct SCL timing */
+#define SPACEMIT_IWCR_INIT_VALUE (FIELD_PREP(SPACEMIT_WCR_COUNT, 10) | \
+ FIELD_PREP(SPACEMIT_WCR_HS_COUNT1, 1) | \
+ FIELD_PREP(SPACEMIT_WCR_HS_COUNT2, 5))
+
/* i2c bus recover timeout: us */
#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
-#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
-#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
-
#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9
@@ -109,11 +123,20 @@ enum spacemit_i2c_state {
SPACEMIT_STATE_WRITE,
};
+enum spacemit_i2c_mode {
+ SPACEMIT_MODE_STANDARD,
+ SPACEMIT_MODE_FAST
+};
+
/* i2c-spacemit driver's main struct */
struct spacemit_i2c_dev {
struct device *dev;
struct i2c_adapter adapt;
+ struct clk_hw scl_clk_hw;
+ struct clk *scl_clk;
+ enum spacemit_i2c_mode mode;
+
/* hardware resources */
void __iomem *base;
int irq;
@@ -135,6 +158,85 @@ struct spacemit_i2c_dev {
u32 status;
};
+static void spacemit_i2c_scl_clk_disable_unprepare(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+/*
+ * Calculate the ILCR divider value (lv) from the target SCL rate.
+ *
+ * Hardware timing formulas:
+ * - standard mode: SCL = FCLK / (2 * SLV + 8)
+ * - fast mode: SCL = FCLK / (2 * FLV + 10)
+ */
+static u32 spacemit_i2c_calc_lv(struct spacemit_i2c_dev *i2c,
+ unsigned long parent_rate,
+ unsigned long target_rate)
+{
+ u32 offset, denom;
+
+ offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
+ denom = DIV_ROUND_CLOSEST(parent_rate, target_rate);
+
+ return (denom <= offset) ? 0 : DIV_ROUND_CLOSEST(denom - offset, 2);
+}
+
+static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
+ u32 lv, lcr, mask;
+
+ lv = spacemit_i2c_calc_lv(i2c, parent_rate, rate);
+
+ mask = (i2c->mode == SPACEMIT_MODE_STANDARD) ?
+ SPACEMIT_LCR_LV_STANDARD_MASK : SPACEMIT_LCR_LV_FAST_MASK;
+
+ lcr = readl(i2c->base + SPACEMIT_ILCR);
+ lcr &= ~mask;
+ lcr |= field_prep(mask, lv);
+ writel(lcr, i2c->base + SPACEMIT_ILCR);
+
+ return 0;
+}
+
+static int spacemit_i2c_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
+ u32 lv, offset;
+
+ lv = spacemit_i2c_calc_lv(i2c, req->best_parent_rate, req->rate);
+ offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
+ req->rate = DIV_ROUND_CLOSEST(req->best_parent_rate, lv * 2 + offset);
+
+ return 0;
+}
+
+static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
+ u32 lcr, lv = 0;
+
+ lcr = readl(i2c->base + SPACEMIT_ILCR);
+
+ if (i2c->mode == SPACEMIT_MODE_STANDARD) {
+ lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr);
+ return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 8);
+ }
+
+ lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr);
+ return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 10);
+}
+
+static const struct clk_ops spacemit_i2c_clk_ops = {
+ .set_rate = spacemit_i2c_clk_set_rate,
+ .determine_rate = spacemit_i2c_clk_determine_rate,
+ .recalc_rate = spacemit_i2c_clk_recalc_rate,
+};
+
static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
{
u32 val;
@@ -153,6 +255,28 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
writel(val, i2c->base + SPACEMIT_ICR);
}
+static int spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c)
+{
+ struct clk_init_data init = {};
+ char name[64];
+ int ret;
+
+ ret = snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev));
+ if (ret >= ARRAY_SIZE(name))
+ dev_warn(i2c->dev, "scl clock name truncated");
+
+ init.name = name;
+ init.ops = &spacemit_i2c_clk_ops;
+ init.parent_data = (struct clk_parent_data[]) {
+ { .fw_name = "func" },
+ };
+ init.num_parents = 1;
+
+ i2c->scl_clk_hw.init = &init;
+
+ return devm_clk_hw_register(i2c->dev, &i2c->scl_clk_hw);
+}
+
static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
{
writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
@@ -286,7 +410,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
val |= SPACEMIT_CR_MSDIE;
}
- if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
+ if (i2c->mode == SPACEMIT_MODE_FAST)
val |= SPACEMIT_CR_MODE_FAST;
/* disable response to general call */
@@ -309,6 +433,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
writel(val, i2c->base + SPACEMIT_IRCR);
spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
+
+ /*
+ * Initialize IWCR to the value specified by the I2C IP designer.
+ * The SCL frequency formulas (SCL = FCLK / (2*SLV+8) for standard
+ * mode, SCL = FCLK / (2*FLV+10) for fast mode) are only valid when
+ * IWCR contains this specific value.
+ */
+ writel(SPACEMIT_IWCR_INIT_VALUE, i2c->base + SPACEMIT_IWCR);
}
static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
@@ -596,7 +728,7 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
status = readl(i2c->base + SPACEMIT_ISR);
if (!status)
- return IRQ_HANDLED;
+ return IRQ_NONE;
i2c->status = status;
@@ -698,19 +830,18 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
- ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
- if (ret && ret != -EINVAL)
- dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
+ of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
/* For now, this driver doesn't support high-speed. */
- if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
- dev_warn(dev, "unsupported clock frequency %u; using %u\n",
- i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
- i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
- } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
- dev_warn(dev, "unsupported clock frequency %u; using %u\n",
- i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
- i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
+ if (i2c->clock_freq > I2C_MAX_STANDARD_MODE_FREQ &&
+ i2c->clock_freq <= I2C_MAX_FAST_MODE_FREQ) {
+ i2c->mode = SPACEMIT_MODE_FAST;
+ } else if (i2c->clock_freq && i2c->clock_freq <= I2C_MAX_STANDARD_MODE_FREQ) {
+ i2c->mode = SPACEMIT_MODE_STANDARD;
+ } else {
+ dev_info(dev, "clock-frequency not set or out of range, using fast mode\n");
+ i2c->mode = SPACEMIT_MODE_FAST;
+ i2c->clock_freq = I2C_MAX_FAST_MODE_FREQ;
}
i2c->dev = &pdev->dev;
@@ -721,17 +852,21 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0)
- return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
-
- ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
- IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
- if (ret)
- return dev_err_probe(dev, ret, "failed to request irq");
+ return i2c->irq;
clk = devm_clk_get_enabled(dev, "func");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
+ ret = spacemit_i2c_register_scl_clk(i2c);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register scl clock\n");
+
+ i2c->scl_clk = devm_clk_hw_get_clk(dev, &i2c->scl_clk_hw, "scl");
+ if (IS_ERR(i2c->scl_clk))
+ return dev_err_probe(dev, PTR_ERR(i2c->scl_clk),
+ "failed to get scl clock\n");
+
clk = devm_clk_get_enabled(dev, "bus");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
@@ -741,6 +876,19 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(rst),
"failed to acquire deasserted reset\n");
+ ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set rate for SCL clock");
+
+ ret = clk_prepare_enable(i2c->scl_clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to prepare and enable clock");
+
+ ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare,
+ i2c->scl_clk);
+ if (ret)
+ return ret;
+
spacemit_i2c_reset(i2c);
i2c_set_adapdata(&i2c->adapt, i2c);
@@ -755,6 +903,11 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
init_completion(&i2c->complete);
+ ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
+ IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
+ if (ret)
+ return ret;
+
platform_set_drvdata(pdev, i2c);
ret = i2c_add_numbered_adapter(&i2c->adapt);
diff --git a/drivers/i2c/busses/i2c-ls2x-v2.c b/drivers/i2c/busses/i2c-ls2x-v2.c
new file mode 100644
index 000000000000..9df73557ecc4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ls2x-v2.c
@@ -0,0 +1,544 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Loongson-2K0300 I2C controller driver
+ *
+ * Copyright (C) 2025-2026 Loongson Technology Corporation Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+/* Loongson-2 fast I2C offset registers */
+#define LOONGSON2_I2C_CR1 0x00 /* I2C control 1 register */
+#define LOONGSON2_I2C_CR2 0x04 /* I2C control 2 register */
+#define LOONGSON2_I2C_OAR 0x08 /* I2C slave address register */
+#define LOONGSON2_I2C_DR 0x10 /* I2C data register */
+#define LOONGSON2_I2C_SR1 0x14 /* I2C status 1 register */
+#define LOONGSON2_I2C_SR2 0x18 /* I2C status 2 register */
+#define LOONGSON2_I2C_CCR 0x1c /* I2C clock control register */
+#define LOONGSON2_I2C_TRISE 0x20 /* I2C trise register */
+#define LOONGSON2_I2C_FLTR 0x24
+
+/* Bitfields of I2C control 1 register */
+#define LOONGSON2_I2C_CR1_PE BIT(0) /* Peripheral enable */
+#define LOONGSON2_I2C_CR1_START BIT(8) /* Start generation */
+#define LOONGSON2_I2C_CR1_STOP BIT(9) /* Stop generation */
+#define LOONGSON2_I2C_CR1_ACK BIT(10) /* Acknowledge enable */
+#define LOONGSON2_I2C_CR1_POS BIT(11) /* Acknowledge/PEC Position (for data reception) */
+
+#define LOONGSON2_I2C_CR1_OP_MASK (LOONGSON2_I2C_CR1_START | LOONGSON2_I2C_CR1_STOP)
+
+/* Bitfields of I2C control 2 register */
+#define LOONGSON2_I2C_CR2_FREQ GENMASK(5, 0) /* APB Clock Frequency in MHz */
+#define LOONGSON2_I2C_CR2_ITERREN BIT(8) /* Fault-Class Interrupt Enable */
+#define LOONGSON2_I2C_CR2_ITEVTEN BIT(9) /* Event-Based Interrupt Enable */
+#define LOONGSON2_I2C_CR2_ITBUFEN BIT(10) /* Cache-Class Interrupt Enable */
+
+#define LOONGSON2_I2C_CR2_INT_MASK \
+ (LOONGSON2_I2C_CR2_ITBUFEN | LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN)
+
+/* Bitfields of I2C status 1 register */
+#define LOONGSON2_I2C_SR1_SB BIT(0) /* Start bit (Master mode) */
+#define LOONGSON2_I2C_SR1_ADDR BIT(1) /* Address sent (master mode) */
+#define LOONGSON2_I2C_SR1_BTF BIT(2) /* Byte transfer finished */
+#define LOONGSON2_I2C_SR1_RXNE BIT(6) /* Data register not empty (receivers) */
+#define LOONGSON2_I2C_SR1_TXE BIT(7) /* Data register empty (transmitters) */
+#define LOONGSON2_I2C_SR1_BERR BIT(8) /* Bus error */
+#define LOONGSON2_I2C_SR1_ARLO BIT(9) /* Arbitration lost (master mode) */
+#define LOONGSON2_I2C_SR1_AF BIT(10) /* Acknowledge failure */
+
+#define LOONGSON2_I2C_SR1_ITEVTEN_MASK \
+ (LOONGSON2_I2C_SR1_BTF | LOONGSON2_I2C_SR1_ADDR | LOONGSON2_I2C_SR1_SB)
+#define LOONGSON2_I2C_SR1_ITBUFEN_MASK (LOONGSON2_I2C_SR1_TXE | LOONGSON2_I2C_SR1_RXNE)
+#define LOONGSON2_I2C_SR1_ITERREN_MASK \
+ (LOONGSON2_I2C_SR1_AF | LOONGSON2_I2C_SR1_ARLO | LOONGSON2_I2C_SR1_BERR)
+
+/* Bitfields of I2C status 2 register */
+#define LOONGSON2_I2C_SR2_MSL BIT(0) /* Master/slave */
+#define LOONGSON2_I2C_SR2_BUSY BIT(1) /* Bus busy */
+#define LOONGSON2_I2C_SR2_TRA BIT(2) /* Transmitter/receiver */
+#define LOONGSON2_I2C_SR2_GENCALL BIT(4) /* General call address (Slave mode) */
+
+/* Bitfields of I2C clock control register */
+#define LOONGSON2_I2C_CCR_CCR GENMASK(11, 0)
+#define LOONGSON2_I2C_CCR_DUTY BIT(14)
+#define LOONGSON2_I2C_CCR_FS BIT(15)
+
+/* Bitfields of I2C trise register */
+#define LOONGSON2_I2C_TRISE_SCL GENMASK(5, 0)
+
+#define LOONGSON2_I2C_FREE_SLEEP_US 10
+#define LOONGSON2_I2C_FREE_TIMEOUT_US (2 * USEC_PER_MSEC)
+
+/**
+ * struct loongson2_i2c_msg - client specific data
+ * @buf: data buffer
+ * @count: number of bytes to be transferred
+ * @result: result of the transfer
+ * @addr: 8-bit slave addr, including r/w bit
+ * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ */
+struct loongson2_i2c_msg {
+ u8 *buf;
+ u32 count;
+ int result;
+ u8 addr;
+ bool stop;
+};
+
+/**
+ * struct loongson2_i2c_priv - private data of the controller
+ * @adapter: I2C adapter for this controller
+ * @complete: completion of I2C message
+ * @clk: hw i2c clock
+ * @regmap: regmap of the I2C device
+ * @parent_rate_MHz: I2C clock parent rate
+ * @msg: I2C transfer information
+ */
+struct loongson2_i2c_priv {
+ struct i2c_adapter adapter;
+ struct completion complete;
+ struct clk *clk;
+ struct regmap *regmap;
+ unsigned long parent_rate_MHz;
+ struct loongson2_i2c_msg msg;
+};
+
+static void loongson2_i2c_disable_irq(struct loongson2_i2c_priv *priv)
+{
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_INT_MASK, 0);
+}
+
+static void loongson2_i2c_read_msg(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+ u32 rbuf;
+
+ regmap_read(priv->regmap, LOONGSON2_I2C_DR, &rbuf);
+ *msg->buf++ = rbuf;
+ msg->count--;
+}
+
+static void loongson2_i2c_write_msg(struct loongson2_i2c_priv *priv, u8 byte)
+{
+ regmap_write(priv->regmap, LOONGSON2_I2C_DR, byte);
+}
+
+static void loongson2_i2c_terminate_xfer(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ loongson2_i2c_disable_irq(priv);
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
+ msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
+ complete(&priv->complete);
+}
+
+static void loongson2_i2c_handle_write(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ if (msg->count) {
+ loongson2_i2c_write_msg(priv, *msg->buf++);
+ if (!--msg->count)
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2,
+ LOONGSON2_I2C_CR2_ITBUFEN, 0);
+ } else {
+ loongson2_i2c_terminate_xfer(priv);
+ }
+}
+
+static void loongson2_i2c_handle_rx_addr(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ switch (msg->count) {
+ case 0:
+ loongson2_i2c_terminate_xfer(priv);
+ break;
+ case 1:
+ /* Enable NACK and reset POS (Acknowledge position) */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1,
+ LOONGSON2_I2C_CR1_ACK | LOONGSON2_I2C_CR1_POS, 0);
+ /* Set STOP or RepSTART */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
+ msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
+ break;
+ case 2:
+ /* Enable NACK */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK, 0);
+ /* Set POS (NACK position) */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_POS,
+ LOONGSON2_I2C_CR1_POS);
+ break;
+
+ default:
+ /* Enable ACK */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK,
+ LOONGSON2_I2C_CR1_ACK);
+ /* Reset POS (ACK position) */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_POS, 0);
+ break;
+ }
+}
+
+static void loongson2_i2c_isr_error(u32 status, void *data)
+{
+ struct loongson2_i2c_priv *priv = data;
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ /* Arbitration lost */
+ if (status & LOONGSON2_I2C_SR1_ARLO) {
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_ARLO, 0);
+ msg->result = -EAGAIN;
+ goto out;
+ }
+
+ /*
+ * Acknowledge failure:
+ * In master transmitter mode a Stop must be generated by software.
+ */
+ if (status & LOONGSON2_I2C_SR1_AF) {
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_STOP,
+ LOONGSON2_I2C_CR1_STOP);
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_AF, 0);
+ msg->result = -EIO;
+ goto out;
+ }
+
+ /* Bus error */
+ if (status & LOONGSON2_I2C_SR1_BERR) {
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_BERR, 0);
+ msg->result = -EIO;
+ goto out;
+ }
+
+out:
+ loongson2_i2c_disable_irq(priv);
+ complete(&priv->complete);
+}
+
+static void loongson2_i2c_handle_read(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ switch (msg->count) {
+ case 1:
+ loongson2_i2c_disable_irq(priv);
+ loongson2_i2c_read_msg(priv);
+ complete(&priv->complete);
+ break;
+ case 2:
+ case 3:
+ /*
+ * For 2-byte/3-byte reception and for N-byte reception with N > 3, we have to
+ * wait for byte transferred finished event before reading data.
+ * Just disable buffer interrupt in order to avoid another system preemption due
+ * to RX not empty event.
+ */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_ITBUFEN, 0);
+ break;
+ default:
+ /*
+ * For N byte reception with N > 3 we directly read data register
+ * until N-2 data.
+ */
+ loongson2_i2c_read_msg(priv);
+ break;
+ }
+}
+
+static void loongson2_i2c_handle_rx_done(struct loongson2_i2c_priv *priv)
+{
+ struct loongson2_i2c_msg *msg = &priv->msg;
+
+ switch (msg->count) {
+ case 2:
+ /*
+ * The STOP/START bit has to be set before reading the last two bytes.
+ * After that, we could read the last two bytes.
+ */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
+ msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
+
+ for (unsigned int i = msg->count; i > 0; i--)
+ loongson2_i2c_read_msg(priv);
+
+ loongson2_i2c_disable_irq(priv);
+
+ complete(&priv->complete);
+ break;
+ case 3:
+ /*
+ * In order to generate the NACK after the last received data byte, enable NACK
+ * before reading N-2 data.
+ */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK, 0);
+ loongson2_i2c_read_msg(priv);
+ break;
+ default:
+ loongson2_i2c_read_msg(priv);
+ break;
+ }
+}
+
+static irqreturn_t loongson2_i2c_isr_event(int irq, void *data)
+{
+ struct loongson2_i2c_priv *priv = data;
+ struct device *dev = regmap_get_device(priv->regmap);
+ struct loongson2_i2c_msg *msg = &priv->msg;
+ u32 status, ien, event, cr2, possible_status;
+
+ regmap_read(priv->regmap, LOONGSON2_I2C_SR1, &status);
+ if (status & LOONGSON2_I2C_SR1_ITERREN_MASK) {
+ loongson2_i2c_isr_error(status, data);
+ return IRQ_HANDLED;
+ }
+
+ regmap_read(priv->regmap, LOONGSON2_I2C_CR2, &cr2);
+ ien = cr2 & LOONGSON2_I2C_CR2_INT_MASK;
+
+ /* Update possible_status if buffer interrupt is enabled */
+ possible_status = LOONGSON2_I2C_SR1_ITEVTEN_MASK;
+ if (ien & LOONGSON2_I2C_CR2_ITBUFEN)
+ possible_status |= LOONGSON2_I2C_SR1_ITBUFEN_MASK;
+
+ event = status & possible_status;
+ if (!event) {
+ dev_dbg(dev, "spurious evt IRQ (status=0x%08x, ien=0x%08x)\n", status, ien);
+ return IRQ_NONE;
+ }
+
+ /* Start condition generated */
+ if (event & LOONGSON2_I2C_SR1_SB)
+ loongson2_i2c_write_msg(priv, msg->addr);
+
+ /* I2C Address sent */
+ if (event & LOONGSON2_I2C_SR1_ADDR) {
+ if (msg->addr & I2C_M_RD)
+ loongson2_i2c_handle_rx_addr(priv);
+ /* Clear ADDR flag */
+ regmap_read(priv->regmap, LOONGSON2_I2C_SR2, &status);
+ /* Enable buffer interrupts for RX/TX not empty events */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_ITBUFEN,
+ LOONGSON2_I2C_CR2_ITBUFEN);
+ }
+
+ /* TX empty */
+ if ((event & LOONGSON2_I2C_SR1_TXE) && !(msg->addr & I2C_M_RD))
+ loongson2_i2c_handle_write(priv);
+
+ /* RX not empty */
+ if ((event & LOONGSON2_I2C_SR1_RXNE) && (msg->addr & I2C_M_RD))
+ loongson2_i2c_handle_read(priv);
+
+ /*
+ * The BTF (Byte Transfer finished) event occurs when:
+ * - in reception: a new byte is received in the shift register
+ * but the previous byte has not been read yet from data register
+ * - in transmission: a new byte should be sent but the data register
+ * has not been written yet
+ */
+ if (event & LOONGSON2_I2C_SR1_BTF) {
+ if (msg->addr & I2C_M_RD)
+ loongson2_i2c_handle_rx_done(priv);
+ else
+ loongson2_i2c_handle_write(priv);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int loongson2_i2c_xfer_msg(struct loongson2_i2c_priv *priv, struct i2c_msg *msg,
+ bool is_stop)
+{
+ struct loongson2_i2c_msg *l_msg = &priv->msg;
+ unsigned long timeout;
+
+ l_msg->addr = i2c_8bit_addr_from_msg(msg);
+ l_msg->buf = msg->buf;
+ l_msg->count = msg->len;
+ l_msg->stop = is_stop;
+ l_msg->result = 0;
+
+ reinit_completion(&priv->complete);
+
+ /* Enable events and errors interrupts */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2,
+ LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN,
+ LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN);
+
+ timeout = wait_for_completion_timeout(&priv->complete, priv->adapter.timeout);
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ return l_msg->result;
+}
+
+static int loongson2_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+ struct loongson2_i2c_priv *priv = i2c_get_adapdata(i2c_adap);
+ struct device *dev = regmap_get_device(priv->regmap);
+ unsigned int status;
+ int ret;
+
+ /* Wait I2C bus free */
+ ret = regmap_read_poll_timeout(priv->regmap, LOONGSON2_I2C_SR2, status,
+ !(status & LOONGSON2_I2C_SR2_BUSY),
+ LOONGSON2_I2C_FREE_SLEEP_US,
+ LOONGSON2_I2C_FREE_TIMEOUT_US);
+ if (ret) {
+ dev_dbg(dev, "The I2C bus is busy now.\n");
+ return ret;
+ }
+
+ /* Start generation */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_START,
+ LOONGSON2_I2C_CR1_START);
+
+ for (unsigned int i = 0; i < num; i++) {
+ ret = loongson2_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 loongson2_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm loongson2_i2c_algo = {
+ .xfer = loongson2_i2c_xfer,
+ .functionality = loongson2_i2c_func,
+};
+
+static int loongson2_i2c_adjust_bus_speed(struct loongson2_i2c_priv *priv)
+{
+ struct device *dev = regmap_get_device(priv->regmap);
+ struct i2c_timings i2c_t;
+ u32 val, freq_MHz, ccr;
+
+ i2c_parse_fw_timings(dev, &i2c_t, true);
+ priv->parent_rate_MHz = clk_get_rate(priv->clk);
+
+ if (i2c_t.bus_freq_hz == I2C_MAX_STANDARD_MODE_FREQ) {
+ /* Select Standard mode */
+ ccr = 0;
+ val = DIV_ROUND_UP(priv->parent_rate_MHz, i2c_t.bus_freq_hz * 2);
+ } else if (i2c_t.bus_freq_hz == I2C_MAX_FAST_MODE_FREQ) {
+ /* Select Fast mode */
+ ccr = LOONGSON2_I2C_CCR_FS;
+ val = DIV_ROUND_UP(priv->parent_rate_MHz, i2c_t.bus_freq_hz * 3);
+ } else {
+ return dev_err_probe(dev, -EINVAL, "Unsupported speed (%uHz)\n", i2c_t.bus_freq_hz);
+ }
+
+ FIELD_MODIFY(LOONGSON2_I2C_CCR_CCR, &ccr, val);
+ regmap_write(priv->regmap, LOONGSON2_I2C_CCR, ccr);
+
+ freq_MHz = DIV_ROUND_UP(priv->parent_rate_MHz, HZ_PER_MHZ);
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_FREQ,
+ FIELD_GET(LOONGSON2_I2C_CR2_FREQ, freq_MHz));
+
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_TRISE, LOONGSON2_I2C_TRISE_SCL,
+ LOONGSON2_I2C_TRISE_SCL);
+
+ /* Enable I2C */
+ regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_PE,
+ LOONGSON2_I2C_CR1_PE);
+
+ return 0;
+}
+
+static const struct regmap_config loongson2_i2c_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = LOONGSON2_I2C_TRISE,
+};
+
+static int loongson2_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct loongson2_i2c_priv *priv;
+ struct i2c_adapter *adap;
+ void __iomem *base;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base, &loongson2_i2c_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap), "Failed to init regmap.\n");
+
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to enable clock.\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ adap = &priv->adapter;
+ adap->retries = 5;
+ adap->nr = pdev->id;
+ adap->dev.parent = dev;
+ adap->owner = THIS_MODULE;
+ adap->algo = &loongson2_i2c_algo;
+ adap->timeout = 2 * HZ;
+ device_set_node(&adap->dev, dev_fwnode(dev));
+ i2c_set_adapdata(adap, priv);
+ strscpy(adap->name, pdev->name);
+ init_completion(&priv->complete);
+ platform_set_drvdata(pdev, priv);
+
+ ret = loongson2_i2c_adjust_bus_speed(priv);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(dev, irq, loongson2_i2c_isr_event, IRQF_SHARED, pdev->name, priv);
+ if (ret)
+ return ret;
+
+ return devm_i2c_add_adapter(dev, adap);
+}
+
+static const struct of_device_id loongson2_i2c_id_table[] = {
+ { .compatible = "loongson,ls2k0300-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, loongson2_i2c_id_table);
+
+static struct platform_driver loongson2_i2c_driver = {
+ .driver = {
+ .name = "loongson2-i2c-v2",
+ .of_match_table = loongson2_i2c_id_table,
+ },
+ .probe = loongson2_i2c_probe,
+};
+module_platform_driver(loongson2_i2c_driver);
+
+MODULE_DESCRIPTION("Loongson-2K0300 I2C bus driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
index b475dd27b7af..af7bf61b0f4d 100644
--- a/drivers/i2c/busses/i2c-ls2x.c
+++ b/drivers/i2c/busses/i2c-ls2x.c
@@ -323,7 +323,7 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
priv);
if (ret < 0)
- return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+ return ret;
return devm_i2c_add_adapter(dev, adap);
}
diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c
index c8599733633e..5a429f17359f 100644
--- a/drivers/i2c/busses/i2c-microchip-corei2c.c
+++ b/drivers/i2c/busses/i2c-microchip-corei2c.c
@@ -565,10 +565,10 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
&idev->bus_clk_rate);
if (ret || !idev->bus_clk_rate) {
dev_info(&pdev->dev, "default to 100kHz\n");
- idev->bus_clk_rate = 100000;
+ idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ;
}
- if (idev->bus_clk_rate > 400000)
+ if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
return dev_err_probe(&pdev->dev, -EINVAL,
"clock-frequency too high: %d\n",
idev->bus_clk_rate);
@@ -581,8 +581,7 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED,
pdev->name, idev);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to claim irq %d\n", irq);
+ return ret;
ret = clk_prepare_enable(idev->i2c_clk);
if (ret)
diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c
index 6c1cfe9ec8ac..24ccc4546ab8 100644
--- a/drivers/i2c/busses/i2c-mlxbf.c
+++ b/drivers/i2c/busses/i2c-mlxbf.c
@@ -1051,8 +1051,10 @@ static int mlxbf_i2c_init_resource(struct platform_device *pdev,
tmp_res->io = devm_platform_get_and_ioremap_resource(pdev, type, &tmp_res->params);
if (IS_ERR(tmp_res->io)) {
+ int ret = PTR_ERR(tmp_res->io);
+
devm_kfree(dev, tmp_res);
- return PTR_ERR(tmp_res->io);
+ return ret;
}
tmp_res->type = type;
@@ -2348,7 +2350,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev)
IRQF_SHARED | IRQF_PROBE_SHARED,
dev_name(dev), priv);
if (ret < 0)
- return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq);
+ return ret;
priv->irq = irq;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 28c5c5c1fb7a..a21fa45bd64c 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -844,7 +844,7 @@ static int fsl_i2c_probe(struct platform_device *op)
"fsl,timeout", &mpc_ops.timeout);
if (!result) {
- mpc_ops.timeout *= HZ / 1000000;
+ mpc_ops.timeout = mpc_ops.timeout * HZ / 1000000;
if (mpc_ops.timeout < 5)
mpc_ops.timeout = 5;
} else {
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 126040ca05f1..307925fb78e3 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -1258,7 +1258,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
i2c->auto_restart = i2c->dev_comp->auto_restart;
/* checking if we can skip restart and optimize using WRRD mode */
- if (i2c->auto_restart && num == 2) {
+ if (num == 2) {
if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
msgs[0].addr == msgs[1].addr) {
i2c->auto_restart = 0;
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 08c9091a1e35..eee4fdcd9df3 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -108,6 +108,14 @@ enum mxs_i2c_devtype {
* @cmd_complete: completion object for transaction wait
* @cmd_err: error code for last transaction
* @adapter: i2c subsystem adapter node
+ * @timing0: I2C TIMING0 register value
+ * @timing1: I2C TIMING1 register value
+ * @timing2: I2C TIMING2 register value
+ * @dmach: DMA channel
+ * @pio_data: PIO data for DMA
+ * @addr_data: address data for DMA
+ * @sg_io: scatterlist for I/O
+ * @dma_read: flag indicating DMA read
*/
struct mxs_i2c_dev {
struct device *dev;
@@ -831,7 +839,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
}
/* Setup the DMA */
- i2c->dmach = dma_request_chan(dev, "rx-tx");
+ i2c->dmach = devm_dma_request_chan(dev, "rx-tx");
if (IS_ERR(i2c->dmach)) {
return dev_err_probe(dev, PTR_ERR(i2c->dmach),
"Failed to request dma\n");
@@ -869,9 +877,6 @@ static void mxs_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adapter);
- if (i2c->dmach)
- dma_release_channel(i2c->dmach);
-
writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
}
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index b63ee51c1652..c3878670da9c 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -1050,9 +1050,9 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv)
if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks))
return -ENOENT;
- if (priv->clk_freq <= 400000)
+ if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ)
speed_mode = I2C_EYEQ5_SPEED_FAST;
- else if (priv->clk_freq <= 1000000)
+ else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ)
speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS;
else
speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED;
@@ -1137,8 +1137,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0,
DRIVER_NAME, priv);
if (ret)
- return dev_err_probe(dev, ret,
- "cannot claim the irq %d\n", priv->irq);
+ return ret;
priv->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(priv->clk))
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index df6ebf32d6e8..2d18c1035837 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -755,7 +755,11 @@ static int ocores_i2c_resume(struct device *dev)
rate = clk_get_rate(i2c->clk) / 1000;
if (rate)
i2c->ip_clock_khz = rate;
- return ocores_init(dev, i2c);
+ ret = ocores_init(dev, i2c);
+ if (ret)
+ clk_disable_unprepare(i2c->clk);
+
+ return ret;
}
static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm,
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
index 32a44f2d6274..aba81477d7d4 100644
--- a/drivers/i2c/busses/i2c-octeon-core.h
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -235,7 +235,7 @@ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c));
}
-#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000)
+#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= I2C_MAX_FAST_MODE_FREQ)
#define PCI_SUBSYS_DEVID_9XXX 0xB
#define PCI_SUBSYS_MASK GENMASK(15, 12)
/**
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 8daa0008bd05..e1cc2b2bd628 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -24,7 +24,6 @@
#include <linux/of.h>
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
-#define I2C_PNX_SPEED_KHZ_DEFAULT 100
#define I2C_PNX_REGION_SIZE 0x100
struct i2c_pnx_mif {
@@ -606,12 +605,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
static int i2c_pnx_probe(struct platform_device *pdev)
{
+ u32 speed = I2C_MAX_STANDARD_MODE_FREQ;
unsigned long tmp;
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
unsigned long freq;
struct resource *res;
- u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL);
if (!alg_data)
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index dbd542300f80..92a0647f08c6 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -76,7 +76,8 @@ static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
goto out;
}
pdev->dev.parent = &dev->dev;
- pdev->dev.of_node = child;
+
+ platform_device_set_of_node(pdev, child);
ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
if (ret)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 9a8b154ab69e..c9927a389aaf 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -214,11 +214,11 @@ static const struct of_device_id i2c_pxa_dt_ids[] = {
MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
static const struct platform_device_id i2c_pxa_id_table[] = {
- { "pxa2xx-i2c", REGS_PXA2XX },
- { "pxa3xx-pwri2c", REGS_PXA3XX },
- { "ce4100-i2c", REGS_CE4100 },
- { "pxa910-i2c", REGS_PXA910 },
- { "armada-3700-i2c", REGS_A3700 },
+ { .name = "pxa2xx-i2c", .driver_data = REGS_PXA2XX },
+ { .name = "pxa3xx-pwri2c", .driver_data = REGS_PXA3XX },
+ { .name = "ce4100-i2c", .driver_data = REGS_CE4100 },
+ { .name = "pxa910-i2c", .driver_data = REGS_PXA910 },
+ { .name = "armada-3700-i2c", .driver_data = REGS_A3700 },
{ }
};
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index f3ccfbbc4bea..873e901a23d7 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -225,25 +225,7 @@ static int cci_halt(struct cci *cci, u8 master_num)
return 0;
}
-static int cci_reset(struct cci *cci)
-{
- /*
- * we reset the whole controller, here and for implicity use
- * master[0].xxx for waiting on it.
- */
- reinit_completion(&cci->master[0].irq_complete);
- writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
-
- if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
- CCI_TIMEOUT)) {
- dev_err(cci->dev, "CCI reset timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int cci_init(struct cci *cci)
+static void cci_init(struct cci *cci)
{
u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE |
CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT |
@@ -284,6 +266,24 @@ static int cci_init(struct cci *cci)
val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp;
writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i));
}
+}
+
+static int cci_reset(struct cci *cci)
+{
+ /*
+ * we reset the whole controller, here and for implicity use
+ * master[0].xxx for waiting on it.
+ */
+ reinit_completion(&cci->master[0].irq_complete);
+ writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
+
+ if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
+ CCI_TIMEOUT)) {
+ dev_err(cci->dev, "CCI reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ cci_init(cci);
return 0;
}
@@ -304,7 +304,6 @@ static int cci_run_queue(struct cci *cci, u8 master, u8 queue)
dev_err(cci->dev, "master %d queue %d timeout\n",
master, queue);
cci_reset(cci);
- cci_init(cci);
return -ETIMEDOUT;
}
@@ -493,31 +492,19 @@ static int __maybe_unused cci_resume_runtime(struct device *dev)
return 0;
}
-static int __maybe_unused cci_suspend(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- return cci_suspend_runtime(dev);
-
- return 0;
-}
-
-static int __maybe_unused cci_resume(struct device *dev)
-{
- cci_resume_runtime(dev);
- pm_request_autosuspend(dev);
-
- return 0;
-}
-
static const struct dev_pm_ops qcom_cci_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL)
};
+static void cci_put_of_node(void *data)
+{
+ of_node_put(data);
+}
+
static int cci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *child;
struct resource *r;
struct cci *cci;
int ret, i;
@@ -533,7 +520,7 @@ static int cci_probe(struct platform_device *pdev)
if (!cci->data)
return -ENOENT;
- for_each_available_child_of_node(dev->of_node, child) {
+ for_each_available_child_of_node_scoped(dev->of_node, child) {
struct cci_master *master;
u32 idx;
@@ -554,6 +541,9 @@ static int cci_probe(struct platform_device *pdev)
master->adap.algo = &cci_algo;
master->adap.dev.parent = dev;
master->adap.dev.of_node = of_node_get(child);
+ ret = devm_add_action_or_reset(dev, cci_put_of_node, child);
+ if (ret)
+ return ret;
master->master = idx;
master->cci = cci;
@@ -609,42 +599,32 @@ static int cci_probe(struct platform_device *pdev)
ret = cci_reset(cci);
if (ret < 0)
- goto error;
-
- ret = cci_init(cci);
- if (ret < 0)
- goto error;
+ goto disable_clocks;
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ goto disable_clocks;
+
pm_runtime_use_autosuspend(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
for (i = 0; i < cci->data->num_masters; i++) {
if (!cci->master[i].cci)
continue;
ret = i2c_add_adapter(&cci->master[i].adap);
- if (ret < 0) {
- of_node_put(cci->master[i].adap.dev.of_node);
+ if (ret < 0)
goto error_i2c;
- }
}
return 0;
error_i2c:
- pm_runtime_disable(dev);
- pm_runtime_dont_use_autosuspend(dev);
for (--i ; i >= 0; i--) {
- if (cci->master[i].cci) {
+ if (cci->master[i].cci)
i2c_del_adapter(&cci->master[i].adap);
- of_node_put(cci->master[i].adap.dev.of_node);
- }
}
-error:
- disable_irq(cci->irq);
disable_clocks:
cci_disable_clocks(cci);
@@ -659,14 +639,9 @@ static void cci_remove(struct platform_device *pdev)
for (i = 0; i < cci->data->num_masters; i++) {
if (cci->master[i].cci) {
i2c_del_adapter(&cci->master[i].adap);
- of_node_put(cci->master[i].adap.dev.of_node);
+ cci_halt(cci, i);
}
- cci_halt(cci, i);
}
-
- disable_irq(cci->irq);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
}
static const struct cci_data cci_v1_data = {
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index a482a4c60744..e9e41a174c20 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+#define CREATE_TRACE_POINTS
+#include <trace/events/qcom_geni_i2c.h>
+
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
@@ -56,7 +59,8 @@
enum geni_i2c_err_code {
GP_IRQ0,
- NACK,
+ ADDR_NACK,
+ DATA_NACK,
GP_IRQ2,
BUS_PROTO,
ARB_LOST,
@@ -67,16 +71,26 @@ enum geni_i2c_err_code {
GENI_TIMEOUT,
};
-#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
+#define DM_I2C_CB_ERR ((BIT(ADDR_NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
<< 5)
#define I2C_AUTO_SUSPEND_DELAY 250
#define PACKING_BYTES_PW 4
#define ABORT_TIMEOUT HZ
+#define CANCEL_TIMEOUT HZ
#define XFER_TIMEOUT HZ
#define RST_TIMEOUT HZ
+struct geni_i2c_desc {
+ bool no_dma_support;
+ unsigned int tx_fifo_depth;
+ int (*resources_init)(struct geni_se *se);
+ int (*set_rate)(struct geni_se *se, unsigned long freq);
+ int (*power_on)(struct geni_se *se);
+ int (*power_off)(struct geni_se *se);
+};
+
#define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2
/**
@@ -103,14 +117,16 @@ struct geni_i2c_dev {
int err;
struct i2c_adapter adap;
struct completion done;
+ struct completion abort_done;
+ struct completion cancel_done;
+ struct completion tx_reset_done;
+ struct completion rx_reset_done;
struct i2c_msg *cur;
int cur_wr;
int cur_rd;
spinlock_t lock;
- struct clk *core_clk;
u32 clk_freq_out;
const struct geni_i2c_clk_fld *clk_fld;
- int suspended;
void *dma_buf;
size_t xfer_len;
dma_addr_t dma_addr;
@@ -118,17 +134,10 @@ struct geni_i2c_dev {
struct dma_chan *rx_c;
bool no_dma;
bool gpi_mode;
- bool abort_done;
bool is_tx_multi_desc_xfer;
u32 num_msgs;
struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config;
-};
-
-struct geni_i2c_desc {
- bool has_core_clk;
- char *icc_ddr;
- bool no_dma_support;
- unsigned int tx_fifo_depth;
+ const struct geni_i2c_desc *dev_data;
};
struct geni_i2c_err_log {
@@ -138,7 +147,8 @@ struct geni_i2c_err_log {
static const struct geni_i2c_err_log gi2c_log[] = {
[GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"},
- [NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"},
+ [ADDR_NACK] = {-ENXIO, "NACK: target device unresponsive, check its power/reset-ln"},
+ [DATA_NACK] = {-EIO, "Data NACK: TX transfer NACK"},
[GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"},
[BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unexpected start/stop"},
[ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"},
@@ -178,8 +188,8 @@ static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
/* source_clock = 32 MHz */
static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = {
- { I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 38 },
- { I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 },
+ { I2C_MAX_STANDARD_MODE_FREQ, 12, 9, 10, 26 },
+ { I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 },
{ I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 5, 15 },
{}
};
@@ -203,8 +213,9 @@ static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
return -EINVAL;
}
-static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
+static int qcom_geni_i2c_conf(struct geni_se *se, unsigned long freq)
{
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev);
const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
u32 val;
@@ -217,6 +228,10 @@ static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
val |= itr->t_cycle_cnt;
writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
+ trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
+ itr->clk_div, itr->t_high_cnt,
+ itr->t_low_cnt, itr->t_cycle_cnt);
+ return 0;
}
static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c)
@@ -249,11 +264,12 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
+ trace_geni_i2c_err(gi2c->se.dev, gi2c_log[err].err, gi2c_log[err].msg);
+
switch (err) {
case GENI_ABORT_DONE:
- gi2c->abort_done = true;
- break;
- case NACK:
+ case ADDR_NACK:
+ case DATA_NACK:
case GENI_TIMEOUT:
dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
break;
@@ -264,6 +280,14 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
}
}
+static void geni_i2c_check_addr_data_nack(struct geni_i2c_dev *gi2c)
+{
+ if (!readl_relaxed(gi2c->se.base + SE_GENI_M_GP_LENGTH))
+ geni_i2c_err(gi2c, ADDR_NACK);
+ else if (!(gi2c->cur->flags & I2C_M_RD))
+ geni_i2c_err(gi2c, DATA_NACK);
+}
+
static irqreturn_t geni_i2c_irq(int irq, void *dev)
{
struct geni_i2c_dev *gi2c = dev;
@@ -285,11 +309,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
cur = gi2c->cur;
+ trace_geni_i2c_irq(gi2c->se.dev, m_stat, rx_st, dm_tx_st, dm_rx_st);
+
if (!cur ||
m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
dm_rx_st & (DM_I2C_CB_ERR)) {
if (m_stat & M_GP_IRQ_1_EN)
- geni_i2c_err(gi2c, NACK);
+ geni_i2c_check_addr_data_nack(gi2c);
if (m_stat & M_GP_IRQ_3_EN)
geni_i2c_err(gi2c, BUS_PROTO);
if (m_stat & M_GP_IRQ_4_EN)
@@ -354,10 +380,18 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
/* if this is err with done-bit not set, handle that through timeout. */
- if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
- dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
- dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
+ if (m_stat & M_CMD_DONE_EN ||
+ dm_tx_st & TX_DMA_DONE ||
+ dm_rx_st & RX_DMA_DONE)
complete(&gi2c->done);
+ if (m_stat & M_CMD_CANCEL_EN)
+ complete(&gi2c->cancel_done);
+ if (m_stat & M_CMD_ABORT_EN)
+ complete(&gi2c->abort_done);
+ if (dm_tx_st & TX_RESET_DONE)
+ complete(&gi2c->tx_reset_done);
+ if (dm_rx_st & RX_RESET_DONE)
+ complete(&gi2c->rx_reset_done);
spin_unlock(&gi2c->lock);
@@ -369,48 +403,59 @@ static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
unsigned long time_left = ABORT_TIMEOUT;
unsigned long flags;
+ reinit_completion(&gi2c->abort_done);
+
spin_lock_irqsave(&gi2c->lock, flags);
- geni_i2c_err(gi2c, GENI_TIMEOUT);
- gi2c->cur = NULL;
- gi2c->abort_done = false;
geni_se_abort_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- } while (!gi2c->abort_done && time_left);
-
+ time_left = wait_for_completion_timeout(&gi2c->abort_done, time_left);
if (!time_left)
dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
}
+static void geni_i2c_cancel_xfer(struct geni_i2c_dev *gi2c)
+{
+ unsigned long time_left = msecs_to_jiffies(CANCEL_TIMEOUT);
+ unsigned long flags;
+
+ reinit_completion(&gi2c->cancel_done);
+
+ spin_lock_irqsave(&gi2c->lock, flags);
+ if (!gi2c->err)
+ geni_i2c_err(gi2c, GENI_TIMEOUT);
+ gi2c->cur = NULL;
+ geni_se_cancel_m_cmd(&gi2c->se);
+ spin_unlock_irqrestore(&gi2c->lock, flags);
+
+ time_left = wait_for_completion_timeout(&gi2c->cancel_done, time_left);
+ if (!time_left) {
+ dev_err(gi2c->se.dev, "Timeout cancel_m_cmd\n");
+ geni_i2c_abort_xfer(gi2c);
+ }
+}
+
static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
{
- u32 val;
unsigned long time_left = RST_TIMEOUT;
+ reinit_completion(&gi2c->rx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
- } while (!(val & RX_RESET_DONE) && time_left);
- if (!(val & RX_RESET_DONE))
+ time_left = wait_for_completion_timeout(&gi2c->rx_reset_done, time_left);
+ if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
}
static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
{
- u32 val;
unsigned long time_left = RST_TIMEOUT;
+ reinit_completion(&gi2c->tx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
- } while (!(val & TX_RESET_DONE) && time_left);
- if (!(val & TX_RESET_DONE))
+ time_left = wait_for_completion_timeout(&gi2c->tx_reset_done, time_left);
+ if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
}
@@ -419,7 +464,7 @@ static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c,
{
gi2c->cur_rd = 0;
if (gi2c->dma_buf) {
- if (gi2c->err)
+ if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)
geni_i2c_rx_fsm_rst(gi2c);
geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
@@ -431,7 +476,7 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
{
gi2c->cur_wr = 0;
if (gi2c->dma_buf) {
- if (gi2c->err)
+ if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)
geni_i2c_tx_fsm_rst(gi2c);
geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
@@ -469,8 +514,8 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
- if (!time_left)
- geni_i2c_abort_xfer(gi2c);
+ if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err))
+ geni_i2c_cancel_xfer(gi2c);
geni_i2c_rx_msg_cleanup(gi2c, cur);
@@ -511,8 +556,8 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
- if (!time_left)
- geni_i2c_abort_xfer(gi2c);
+ if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err))
+ geni_i2c_cancel_xfer(gi2c);
geni_i2c_tx_msg_cleanup(gi2c, cur);
@@ -785,6 +830,10 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
peripheral.set_config = 1;
peripheral.multi_msg = false;
+ trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
+ itr->clk_div, itr->t_high_cnt,
+ itr->t_low_cnt, itr->t_cycle_cnt);
+
gi2c->num_msgs = num;
gi2c->is_tx_multi_desc_xfer = false;
@@ -823,6 +872,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
for (i = 0; i < num; i++) {
gi2c->cur = &msgs[i];
gi2c->err = 0;
+ reinit_completion(&gi2c->done);
dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
peripheral.stretch = 0;
@@ -892,6 +942,8 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
gi2c->cur = &msgs[i];
+ gi2c->err = 0;
+ reinit_completion(&gi2c->done);
if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else
@@ -911,8 +963,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
int ret;
- gi2c->err = 0;
- reinit_completion(&gi2c->done);
ret = pm_runtime_get_sync(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
@@ -922,7 +972,9 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
return ret;
}
- qcom_geni_i2c_conf(gi2c);
+ ret = gi2c->dev_data->set_rate(&gi2c->se, gi2c->clk_freq_out);
+ if (ret)
+ return ret;
if (gi2c->gpi_mode)
ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
@@ -945,15 +997,6 @@ static const struct i2c_algorithm geni_i2c_algo = {
.functionality = geni_i2c_func,
};
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id geni_i2c_acpi_match[] = {
- { "QCOM0220"},
- { "QCOM0411" },
- { }
-};
-MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
-#endif
-
static void release_gpi_dma(struct geni_i2c_dev *gi2c)
{
if (gi2c->rx_c)
@@ -991,13 +1034,95 @@ err_tx:
return ret;
}
+static int geni_i2c_init(struct geni_i2c_dev *gi2c)
+{
+ u32 proto, tx_depth;
+ bool fifo_disable;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(gi2c->se.dev);
+ if (ret < 0) {
+ dev_err(gi2c->se.dev, "error turning on device :%d\n", ret);
+ return ret;
+ }
+
+ proto = geni_se_read_proto(&gi2c->se);
+ if (proto == GENI_SE_INVALID_PROTO) {
+ ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
+ if (ret) {
+ dev_err_probe(gi2c->se.dev, ret, "i2c firmware load failed ret: %d\n", ret);
+ goto err;
+ }
+ } else if (proto != GENI_SE_I2C) {
+ ret = dev_err_probe(gi2c->se.dev, -ENXIO, "Invalid proto %d\n", proto);
+ goto err;
+ }
+
+ if (gi2c->dev_data->no_dma_support) {
+ fifo_disable = false;
+ gi2c->no_dma = true;
+ } else {
+ fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
+ }
+
+ if (fifo_disable) {
+ /* FIFO is disabled, so we can only use GPI DMA */
+ gi2c->gpi_mode = true;
+ ret = setup_gpi_dma(gi2c);
+ if (ret)
+ goto err;
+
+ dev_dbg(gi2c->se.dev, "Using GPI DMA mode for I2C\n");
+ } else {
+ gi2c->gpi_mode = false;
+ tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
+
+ /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
+ if (!tx_depth && gi2c->se.core_clk)
+ tx_depth = gi2c->dev_data->tx_fifo_depth;
+
+ if (!tx_depth) {
+ ret = dev_err_probe(gi2c->se.dev, -EINVAL,
+ "Invalid TX FIFO depth\n");
+ goto err;
+ }
+
+ gi2c->tx_wm = tx_depth - 1;
+ geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
+ geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
+ PACKING_BYTES_PW, true, true, true);
+
+ dev_dbg(gi2c->se.dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
+ }
+
+err:
+ pm_runtime_put(gi2c->se.dev);
+ return ret;
+}
+
+static int geni_i2c_resources_init(struct geni_se *se)
+{
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev);
+ int ret;
+
+ ret = geni_se_resources_init(&gi2c->se);
+ if (ret)
+ return ret;
+
+ ret = geni_i2c_clk_map_idx(gi2c);
+ if (ret)
+ return dev_err_probe(gi2c->se.dev, ret, "Invalid clk frequency %d Hz\n",
+ gi2c->clk_freq_out);
+
+ return geni_icc_set_bw_ab(&gi2c->se, GENI_DEFAULT_BW, GENI_DEFAULT_BW,
+ Bps_to_icc(gi2c->clk_freq_out));
+}
+
static int geni_i2c_probe(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c;
- u32 proto, tx_depth, fifo_disable;
int ret;
struct device *dev = &pdev->dev;
- const struct geni_i2c_desc *desc = NULL;
gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL);
if (!gi2c)
@@ -1009,17 +1134,9 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (IS_ERR(gi2c->se.base))
return PTR_ERR(gi2c->se.base);
- desc = device_get_match_data(&pdev->dev);
-
- if (desc && desc->has_core_clk) {
- gi2c->core_clk = devm_clk_get(dev, "core");
- if (IS_ERR(gi2c->core_clk))
- return PTR_ERR(gi2c->core_clk);
- }
-
- gi2c->se.clk = devm_clk_get(dev, "se");
- if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev))
- return PTR_ERR(gi2c->se.clk);
+ gi2c->dev_data = device_get_match_data(&pdev->dev);
+ if (!gi2c->dev_data)
+ return -EINVAL;
ret = device_property_read_u32(dev, "clock-frequency",
&gi2c->clk_freq_out);
@@ -1035,142 +1152,51 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (gi2c->irq < 0)
return gi2c->irq;
- ret = geni_i2c_clk_map_idx(gi2c);
- if (ret)
- return dev_err_probe(dev, ret, "Invalid clk frequency %d Hz\n",
- gi2c->clk_freq_out);
-
gi2c->adap.algo = &geni_i2c_algo;
init_completion(&gi2c->done);
+ init_completion(&gi2c->abort_done);
+ init_completion(&gi2c->cancel_done);
+ init_completion(&gi2c->tx_reset_done);
+ init_completion(&gi2c->rx_reset_done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
+ ret = gi2c->dev_data->resources_init(&gi2c->se);
+ if (ret)
+ return ret;
+
/* Keep interrupts disabled initially to allow for low-power modes */
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
dev_name(dev), gi2c);
if (ret)
- return dev_err_probe(dev, ret,
- "Request_irq failed: %d\n", gi2c->irq);
+ return ret;
i2c_set_adapdata(&gi2c->adap, gi2c);
gi2c->adap.dev.parent = dev;
gi2c->adap.dev.of_node = dev->of_node;
strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
- ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory");
- if (ret)
- return ret;
- /*
- * Set the bus quota for core and cpu to a reasonable value for
- * register access.
- * Set quota for DDR based on bus speed.
- */
- gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
- gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
- if (!desc || desc->icc_ddr)
- gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_set_autosuspend_delay(dev, I2C_AUTO_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(dev);
- ret = geni_icc_set_bw(&gi2c->se);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
- ret = clk_prepare_enable(gi2c->core_clk);
- if (ret)
+ ret = geni_i2c_init(gi2c);
+ if (ret < 0)
return ret;
- ret = geni_se_resources_on(&gi2c->se);
- if (ret) {
- dev_err_probe(dev, ret, "Error turning on resources\n");
- goto err_clk;
- }
- proto = geni_se_read_proto(&gi2c->se);
- if (proto == GENI_SE_INVALID_PROTO) {
- ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
- if (ret) {
- dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret);
- goto err_resources;
- }
- } else if (proto != GENI_SE_I2C) {
- ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto);
- goto err_resources;
- }
-
- if (desc && desc->no_dma_support) {
- fifo_disable = false;
- gi2c->no_dma = true;
- } else {
- fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
- }
-
- if (fifo_disable) {
- /* FIFO is disabled, so we can only use GPI DMA */
- gi2c->gpi_mode = true;
- ret = setup_gpi_dma(gi2c);
- if (ret)
- goto err_resources;
-
- dev_dbg(dev, "Using GPI DMA mode for I2C\n");
- } else {
- gi2c->gpi_mode = false;
- tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
-
- /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
- if (!tx_depth && desc)
- tx_depth = desc->tx_fifo_depth;
-
- if (!tx_depth) {
- ret = dev_err_probe(dev, -EINVAL,
- "Invalid TX FIFO depth\n");
- goto err_resources;
- }
-
- gi2c->tx_wm = tx_depth - 1;
- geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
- geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
- PACKING_BYTES_PW, true, true, true);
-
- dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
- }
-
- clk_disable_unprepare(gi2c->core_clk);
- ret = geni_se_resources_off(&gi2c->se);
- if (ret) {
- dev_err_probe(dev, ret, "Error turning off resources\n");
- goto err_dma;
- }
-
- ret = geni_icc_disable(&gi2c->se);
- if (ret)
- goto err_dma;
-
- gi2c->suspended = 1;
- pm_runtime_set_suspended(gi2c->se.dev);
- pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
- pm_runtime_use_autosuspend(gi2c->se.dev);
- pm_runtime_enable(gi2c->se.dev);
-
ret = i2c_add_adapter(&gi2c->adap);
if (ret) {
- dev_err_probe(dev, ret, "Error adding i2c adapter\n");
- pm_runtime_disable(gi2c->se.dev);
- goto err_dma;
+ release_gpi_dma(gi2c);
+ return dev_err_probe(dev, ret, "Error adding i2c adapter\n");
}
dev_dbg(dev, "Geni-I2C adaptor successfully added\n");
- return ret;
-
-err_resources:
- geni_se_resources_off(&gi2c->se);
-err_clk:
- clk_disable_unprepare(gi2c->core_clk);
-
- return ret;
-
-err_dma:
- release_gpi_dma(gi2c);
-
- return ret;
+ return 0;
}
static void geni_i2c_remove(struct platform_device *pdev)
@@ -1179,7 +1205,6 @@ static void geni_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&gi2c->adap);
release_gpi_dma(gi2c);
- pm_runtime_disable(gi2c->se.dev);
}
static void geni_i2c_shutdown(struct platform_device *pdev)
@@ -1192,72 +1217,60 @@ static void geni_i2c_shutdown(struct platform_device *pdev)
static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
{
- int ret;
+ int ret = 0;
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
disable_irq(gi2c->irq);
- ret = geni_se_resources_off(&gi2c->se);
- if (ret) {
- enable_irq(gi2c->irq);
- return ret;
- } else {
- gi2c->suspended = 1;
+ if (gi2c->dev_data->power_off) {
+ ret = gi2c->dev_data->power_off(&gi2c->se);
+ if (ret) {
+ enable_irq(gi2c->irq);
+ return ret;
+ }
}
- clk_disable_unprepare(gi2c->core_clk);
-
- return geni_icc_disable(&gi2c->se);
+ return 0;
}
static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
{
- int ret;
+ int ret = 0;
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
- ret = geni_icc_enable(&gi2c->se);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(gi2c->core_clk);
- if (ret)
- goto out_icc_disable;
-
- ret = geni_se_resources_on(&gi2c->se);
- if (ret)
- goto out_clk_disable;
+ if (gi2c->dev_data->power_on) {
+ ret = gi2c->dev_data->power_on(&gi2c->se);
+ if (ret)
+ return ret;
+ }
enable_irq(gi2c->irq);
- gi2c->suspended = 0;
return 0;
-
-out_clk_disable:
- clk_disable_unprepare(gi2c->core_clk);
-out_icc_disable:
- geni_icc_disable(&gi2c->se);
-
- return ret;
}
static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
{
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+ int ret;
i2c_mark_adapter_suspended(&gi2c->adap);
- if (!gi2c->suspended) {
- geni_i2c_runtime_suspend(dev);
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
- pm_runtime_enable(dev);
- }
- return 0;
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ i2c_mark_adapter_resumed(&gi2c->adap);
+
+ return ret;
}
static int __maybe_unused geni_i2c_resume_noirq(struct device *dev)
{
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
i2c_mark_adapter_resumed(&gi2c->adap);
return 0;
@@ -1269,16 +1282,40 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
NULL)
};
+static const struct geni_i2c_desc geni_i2c = {
+ .resources_init = geni_i2c_resources_init,
+ .set_rate = qcom_geni_i2c_conf,
+ .power_on = geni_se_resources_activate,
+ .power_off = geni_se_resources_deactivate,
+};
+
static const struct geni_i2c_desc i2c_master_hub = {
- .has_core_clk = true,
- .icc_ddr = NULL,
.no_dma_support = true,
.tx_fifo_depth = 16,
+ .resources_init = geni_i2c_resources_init,
+ .set_rate = qcom_geni_i2c_conf,
+ .power_on = geni_se_resources_activate,
+ .power_off = geni_se_resources_deactivate,
+};
+
+static const struct geni_i2c_desc sa8255p_geni_i2c = {
+ .resources_init = geni_se_domain_attach,
+ .set_rate = geni_se_set_perf_opp,
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id geni_i2c_acpi_match[] = {
+ { "QCOM0220", (kernel_ulong_t)&geni_i2c},
+ { "QCOM0411", (kernel_ulong_t)&geni_i2c},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
+#endif
+
static const struct of_device_id geni_i2c_dt_match[] = {
- { .compatible = "qcom,geni-i2c" },
+ { .compatible = "qcom,geni-i2c", .data = &geni_i2c },
{ .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub },
+ { .compatible = "qcom,sa8255p-geni-i2c", .data = &sa8255p_geni_i2c },
{}
};
MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a0e076fc5f36..ee7915ee2ba2 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1657,10 +1657,21 @@ static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
-static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
+static int qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
- clk_prepare_enable(qup->clk);
- clk_prepare_enable(qup->pclk);
+ int ret;
+
+ ret = clk_prepare_enable(qup->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(qup->pclk);
+ if (ret) {
+ clk_disable_unprepare(qup->clk);
+ return ret;
+ }
+
+ return 0;
}
static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
@@ -1823,7 +1834,9 @@ nodma:
ret = PTR_ERR(qup->pclk);
goto fail_dma;
}
- qup_i2c_enable_clocks(qup);
+ ret = qup_i2c_enable_clocks(qup);
+ if (ret)
+ goto fail_dma;
src_clk_freq = clk_get_rate(qup->clk);
}
qup->src_clk_freq = src_clk_freq;
@@ -1975,8 +1988,7 @@ static int qup_i2c_pm_resume_runtime(struct device *device)
struct qup_i2c_dev *qup = dev_get_drvdata(device);
dev_dbg(device, "pm_runtime: resuming...\n");
- qup_i2c_enable_clocks(qup);
- return 0;
+ return qup_i2c_enable_clocks(qup);
}
static int qup_i2c_suspend(struct device *device)
@@ -1988,7 +2000,12 @@ static int qup_i2c_suspend(struct device *device)
static int qup_i2c_resume(struct device *device)
{
- qup_i2c_pm_resume_runtime(device);
+ int ret;
+
+ ret = qup_i2c_pm_resume_runtime(device);
+ if (ret)
+ return ret;
+
pm_request_autosuspend(device);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 5ce8f8e4856f..755064804cb2 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -123,12 +123,13 @@
#define ID_NACK BIT(4)
#define ID_EPROTO BIT(5)
/* persistent flags */
+#define ID_P_NO_RST_STAT BIT(26)
#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, 27)
+#define ID_P_MASK GENMASK(31, 26)
#define ID_SLAVE_NACK BIT(0)
@@ -137,6 +138,7 @@ enum rcar_i2c_type {
I2C_RCAR_GEN2,
I2C_RCAR_GEN3,
I2C_RCAR_GEN4,
+ I2C_RCAR_GEN5,
};
struct rcar_i2c_priv {
@@ -900,8 +902,11 @@ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
if (ret)
return ret;
- return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, 1,
- 100, false, priv->rstc);
+ if (priv->flags & ID_P_NO_RST_STAT)
+ return 0;
+
+ return read_poll_timeout_atomic(reset_control_status, ret, ret == 0,
+ 1, 100, false, priv->rstc);
}
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
@@ -1111,6 +1116,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .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_GEN4 },
+ { .compatible = "renesas,rcar-gen5-i2c", .data = (void *)I2C_RCAR_GEN5 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@@ -1195,7 +1201,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)
}
ret = reset_control_status(priv->rstc);
- if (ret < 0)
+ /* Some SCMI firmware does not support reading reset status */
+ if (ret == -ENOTSUPP)
+ priv->flags |= ID_P_NO_RST_STAT;
+ else if (ret < 0)
goto out_pm_put;
/* hard reset disturbs HostNotify local target, so disable it */
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index 9e3595b3623e..2fa48219b66b 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -554,8 +554,7 @@ static int riic_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, irq_desc->isr, 0, irq_desc->name, riic);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq %s\n",
- irq_desc->name);
+ return ret;
}
@@ -725,8 +724,10 @@ static int riic_i2c_resume_noirq(struct device *dev)
return ret;
ret = pm_runtime_force_resume(dev);
- if (ret)
+ if (ret) {
+ reset_control_assert(riic->rstc);
return ret;
+ }
ret = riic_init_hw(riic);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 8cedffbb2964..3a8225b0666c 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -4,7 +4,6 @@
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
-#include <linux/mod_devicetable.h>
#include <linux/mfd/syscon.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c
index 238714850673..206a99e722a3 100644
--- a/drivers/i2c/busses/i2c-rzv2m.c
+++ b/drivers/i2c/busses/i2c-rzv2m.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -443,7 +442,7 @@ static int rzv2m_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0,
dev_name(dev), priv);
if (ret < 0)
- return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+ return ret;
adap = &priv->adap;
adap->nr = pdev->id;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index a19c3d251804..3d0638c2bc51 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -431,24 +431,23 @@ static int sis630_setup(struct pci_dev *sis630_dev)
in acpi io space and read acpi base addr
*/
if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, &b)) {
- dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
- retval = -ENODEV;
+ retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
+ "Error: Can't read bios ctl reg\n");
goto exit;
}
/* if ACPI already enabled , do nothing */
if (!(b & 0x80) &&
pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
- dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
- retval = -ENODEV;
+ retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
+ "Error: Can't enable ACPI\n");
goto exit;
}
/* Determine the ACPI base address */
if (pci_read_config_word(sis630_dev,
SIS630_ACPI_BASE_REG, &acpi_base)) {
- dev_err(&sis630_dev->dev,
- "Error: Can't determine ACPI base address\n");
- retval = -ENODEV;
+ retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
+ "Error: Can't determine ACPI base address\n");
goto exit;
}
@@ -469,11 +468,10 @@ static int sis630_setup(struct pci_dev *sis630_dev)
/* Everything is happy, let's grab the memory and set things up. */
if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
sis630_driver.name)) {
- dev_err(&sis630_dev->dev,
- "I/O Region 0x%04x-0x%04x for SMBus already in use.\n",
- smbus_base + SMB_STS,
- smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
- retval = -EBUSY;
+ retval = dev_err_probe(&sis630_dev->dev, -EBUSY,
+ "I/O Region 0x%04x-0x%04x for SMBus already in use.\n",
+ smbus_base + SMB_STS,
+ smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
goto exit;
}
@@ -511,12 +509,9 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int ret;
- if (sis630_setup(dev)) {
- dev_err(&dev->dev,
- "SIS630 compatible bus not detected, "
- "module not inserted.\n");
- return -ENODEV;
- }
+ if (sis630_setup(dev))
+ return dev_err_probe(&dev->dev, -ENODEV,
+ "Compatible bus not detected, module not inserted.\n");
/* set up the sysfs linkage to our parent device */
sis630_adapter.dev.parent = &dev->dev;
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 77529dda6fcd..eee41dc9d706 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -245,23 +245,19 @@ static int sis96x_probe(struct pci_dev *dev,
u16 ww = 0;
int retval;
- if (sis96x_smbus_base) {
- dev_err(&dev->dev, "Only one device supported.\n");
- return -EBUSY;
- }
+ if (sis96x_smbus_base)
+ return dev_err_probe(&dev->dev, -EBUSY, "Only one device supported.\n");
pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
- if (PCI_CLASS_SERIAL_SMBUS != ww) {
- dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
- return -ENODEV;
- }
+ if (ww != PCI_CLASS_SERIAL_SMBUS)
+ return dev_err_probe(&dev->dev, -ENODEV,
+ "Unsupported device class 0x%04x!\n", ww);
sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
- if (!sis96x_smbus_base) {
- dev_err(&dev->dev, "SiS96x SMBus base address "
- "not initialized!\n");
- return -EINVAL;
- }
+ if (!sis96x_smbus_base)
+ return dev_err_probe(&dev->dev, -EINVAL,
+ "SiS96x SMBus base address not initialized!\n");
+
dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
sis96x_smbus_base);
@@ -272,9 +268,9 @@ static int sis96x_probe(struct pci_dev *dev,
/* Everything is happy, let's grab the memory and set things up. */
if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
sis96x_driver.name)) {
- dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
- "already in use!\n", sis96x_smbus_base,
- sis96x_smbus_base + SMB_IOSIZE - 1);
+ dev_err_probe(&dev->dev, -EINVAL,
+ "SMBus registers 0x%04x-0x%04x already in use!\n",
+ sis96x_smbus_base, sis96x_smbus_base + SMB_IOSIZE - 1);
sis96x_smbus_base = 0;
return -EINVAL;
@@ -287,7 +283,7 @@ static int sis96x_probe(struct pci_dev *dev,
"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
if ((retval = i2c_add_adapter(&sis96x_adapter))) {
- dev_err(&dev->dev, "Couldn't register adapter!\n");
+ dev_err_probe(&dev->dev, retval, "Couldn't register adapter!\n");
release_region(sis96x_smbus_base, SMB_IOSIZE);
sis96x_smbus_base = 0;
}
diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c
index 1b490525d8dd..c42925f9a330 100644
--- a/drivers/i2c/busses/i2c-sprd.c
+++ b/drivers/i2c/busses/i2c-sprd.c
@@ -469,11 +469,10 @@ static int sprd_i2c_clk_init(struct sprd_i2c *i2c_dev)
i2c_dev->adap.nr, i2c_dev->src_clk);
i2c_dev->clk = devm_clk_get(i2c_dev->dev, "enable");
- if (IS_ERR(i2c_dev->clk)) {
- dev_err(i2c_dev->dev, "i2c%d can't get the enable clock\n",
- i2c_dev->adap.nr);
- return PTR_ERR(i2c_dev->clk);
- }
+ if (IS_ERR(i2c_dev->clk))
+ return dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->clk),
+ "i2c%d can't get the enable clock\n",
+ i2c_dev->adap.nr);
return 0;
}
@@ -547,14 +546,12 @@ static int sprd_i2c_probe(struct platform_device *pdev)
sprd_i2c_isr, sprd_i2c_isr_thread,
IRQF_NO_SUSPEND | IRQF_ONESHOT,
pdev->name, i2c_dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to request irq %d\n", i2c_dev->irq);
+ if (ret)
goto err_rpm_put;
- }
ret = i2c_add_numbered_adapter(&i2c_dev->adap);
if (ret) {
- dev_err(&pdev->dev, "add adapter failed\n");
+ dev_err_probe(&pdev->dev, ret, "add adapter failed\n");
goto err_rpm_put;
}
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 751ea421caaf..0a2b43b5577b 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -775,17 +775,15 @@ static int st_i2c_of_get_deglitch(struct device_node *np,
ret = of_property_read_u32(np, "st,i2c-min-scl-pulse-width-us",
&i2c_dev->scl_min_width_us);
- if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
- dev_err(i2c_dev->dev, "st,i2c-min-scl-pulse-width-us invalid\n");
- return ret;
- }
+ if ((ret == -ENODATA) || (ret == -EOVERFLOW))
+ return dev_err_probe(i2c_dev->dev, ret,
+ "st,i2c-min-scl-pulse-width-us invalid\n");
ret = of_property_read_u32(np, "st,i2c-min-sda-pulse-width-us",
&i2c_dev->sda_min_width_us);
- if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
- dev_err(i2c_dev->dev, "st,i2c-min-sda-pulse-width-us invalid\n");
- return ret;
- }
+ if ((ret == -ENODATA) || (ret == -EOVERFLOW))
+ return dev_err_probe(i2c_dev->dev, ret,
+ "st,i2c-min-sda-pulse-width-us invalid\n");
return 0;
}
@@ -808,16 +806,13 @@ static int st_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
i2c_dev->irq = irq_of_parse_and_map(np, 0);
- if (!i2c_dev->irq) {
- dev_err(&pdev->dev, "IRQ missing or invalid\n");
- return -EINVAL;
- }
+ if (!i2c_dev->irq)
+ return dev_err_probe(&pdev->dev, -EINVAL, "IRQ missing or invalid\n");
i2c_dev->clk = of_clk_get_by_name(np, "ssc");
- if (IS_ERR(i2c_dev->clk)) {
- dev_err(&pdev->dev, "Unable to request clock\n");
- return PTR_ERR(i2c_dev->clk);
- }
+ if (IS_ERR(i2c_dev->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
+ "Unable to request clock\n");
i2c_dev->mode = I2C_MODE_STANDARD;
ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
@@ -829,10 +824,8 @@ static int st_i2c_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq,
NULL, st_i2c_isr_thread,
IRQF_ONESHOT, pdev->name, i2c_dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
+ if (ret)
return ret;
- }
pinctrl_pm_select_default_state(i2c_dev->dev);
/* In case idle state available, select it */
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
index becf8977979f..064e47d6c96f 100644
--- a/drivers/i2c/busses/i2c-stm32.c
+++ b/drivers/i2c/busses/i2c-stm32.c
@@ -39,7 +39,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
dma_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
if (ret < 0) {
- dev_err(dev, "can't configure tx channel\n");
+ dev_err_probe(dev, ret, "can't configure tx channel\n");
goto fail_tx;
}
@@ -60,7 +60,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
dma_sconfig.direction = DMA_DEV_TO_MEM;
ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
if (ret < 0) {
- dev_err(dev, "can't configure rx channel\n");
+ dev_err_probe(dev, ret, "can't configure rx channel\n");
goto fail_rx;
}
diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
index b3d56d0aa9d0..579ab29ef554 100644
--- a/drivers/i2c/busses/i2c-stm32f4.c
+++ b/drivers/i2c/busses/i2c-stm32f4.c
@@ -163,11 +163,9 @@ static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
* to hardware limitation
*/
if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
- freq > STM32F4_I2C_MAX_FREQ) {
- dev_err(i2c_dev->dev,
- "bad parent clk freq for standard mode\n");
- return -EINVAL;
- }
+ freq > STM32F4_I2C_MAX_FREQ)
+ return dev_err_probe(i2c_dev->dev, -EINVAL,
+ "bad parent clk freq for standard mode\n");
} else {
/*
* To be as close as possible to 400 kHz, the parent clk
@@ -175,11 +173,9 @@ static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
* maximum value of 46 MHz due to hardware limitation
*/
if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
- freq > STM32F4_I2C_MAX_FREQ) {
- dev_err(i2c_dev->dev,
- "bad parent clk freq for fast mode\n");
- return -EINVAL;
- }
+ freq > STM32F4_I2C_MAX_FREQ)
+ return dev_err_probe(i2c_dev->dev, -EINVAL,
+ "bad parent clk freq for fast mode\n");
}
cr2 |= STM32F4_I2C_CR2_FREQ(freq);
@@ -772,22 +768,19 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
irq_event = irq_of_parse_and_map(np, 0);
- if (!irq_event) {
- dev_err(&pdev->dev, "IRQ event missing or invalid\n");
- return -EINVAL;
- }
+ if (!irq_event)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "IRQ event missing or invalid\n");
irq_error = irq_of_parse_and_map(np, 1);
- if (!irq_error) {
- dev_err(&pdev->dev, "IRQ error missing or invalid\n");
- return -EINVAL;
- }
+ if (!irq_error)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "IRQ error missing or invalid\n");
i2c_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL);
- if (IS_ERR(i2c_dev->clk)) {
- dev_err(&pdev->dev, "Failed to enable clock\n");
- return PTR_ERR(i2c_dev->clk);
- }
+ if (IS_ERR(i2c_dev->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
+ "Failed to enable clock\n");
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(rst))
@@ -807,19 +800,13 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0,
pdev->name, i2c_dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq event %i\n",
- irq_event);
+ if (ret)
return ret;
- }
ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0,
pdev->name, i2c_dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq error %i\n",
- irq_error);
+ if (ret)
return ret;
- }
ret = stm32f4_i2c_hw_config(i2c_dev);
if (ret)
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 70cb5822bf17..6bd281a9ef72 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -464,8 +464,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
{
struct stm32f7_i2c_spec *specs;
u32 p_prev = STM32F7_PRESC_MAX;
- u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
- setup->clock_src);
+ /*
+ * Truncate instead of rounding to closest: if the clock period is
+ * overestimated, the computed SCL timings will come out shorter on
+ * the wire, which can push the bus above the target rate and below
+ * the spec's tLOW/tHIGH minimums.
+ */
+ u32 i2cclk = NSEC_PER_SEC / setup->clock_src;
u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
setup->speed_freq);
u32 clk_error_prev = i2cbus;
@@ -481,28 +486,22 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
int ret = 0;
specs = stm32f7_get_specs(setup->speed_freq);
- if (specs == ERR_PTR(-EINVAL)) {
- dev_err(i2c_dev->dev, "speed out of bound {%d}\n",
- setup->speed_freq);
- return -EINVAL;
- }
+ if (specs == ERR_PTR(-EINVAL))
+ return dev_err_probe(i2c_dev->dev, -EINVAL, "speed out of bound {%d}\n",
+ setup->speed_freq);
if ((setup->rise_time > specs->rise_max) ||
- (setup->fall_time > specs->fall_max)) {
- dev_err(i2c_dev->dev,
- "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
- setup->rise_time, specs->rise_max,
- setup->fall_time, specs->fall_max);
- return -EINVAL;
- }
+ (setup->fall_time > specs->fall_max))
+ return dev_err_probe(i2c_dev->dev, -EINVAL,
+ "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
+ setup->rise_time, specs->rise_max,
+ setup->fall_time, specs->fall_max);
i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk);
- if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) {
- dev_err(i2c_dev->dev,
- "DNF out of bound %d/%d\n",
- i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
- return -EINVAL;
- }
+ if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX)
+ return dev_err_probe(i2c_dev->dev, -EINVAL,
+ "DNF out of bound %d/%d\n", i2c_dev->dnf * i2cclk,
+ STM32F7_I2C_DNF_MAX * i2cclk);
/* Analog and Digital Filters */
af_delay_min =
@@ -567,8 +566,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
}
if (list_empty(&solutions)) {
- dev_err(i2c_dev->dev, "no Prescaler solution\n");
- ret = -EPERM;
+ ret = dev_err_probe(i2c_dev->dev, -EPERM, "no Prescaler solution\n");
goto exit;
}
@@ -624,8 +622,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
}
if (!s) {
- dev_err(i2c_dev->dev, "no solution at all\n");
- ret = -EPERM;
+ ret = dev_err_probe(i2c_dev->dev, -EPERM, "no solution at all\n");
goto exit;
}
@@ -674,11 +671,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
i2c_parse_fw_timings(i2c_dev->dev, t, false);
- if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) {
- dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n",
- t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
- return -EINVAL;
- }
+ if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)
+ return dev_err_probe(i2c_dev->dev, -EINVAL, "Invalid bus speed (%i>%i)\n",
+ t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
setup->speed_freq = t->bus_freq_hz;
i2c_dev->setup.rise_time = t->scl_rise_ns;
@@ -686,20 +681,21 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
i2c_dev->dnf_dt = t->digital_filter_width_ns;
setup->clock_src = clk_get_rate(i2c_dev->clk);
- if (!setup->clock_src) {
- dev_err(i2c_dev->dev, "clock rate is 0\n");
- return -EINVAL;
- }
+ if (!setup->clock_src)
+ return dev_err_probe(i2c_dev->dev, -EINVAL, "clock rate is 0\n");
if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
+ i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
+ "i2c-analog-filter");
+
do {
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
&i2c_dev->timing);
if (ret) {
- dev_err(i2c_dev->dev,
- "failed to compute I2C timings.\n");
+ dev_err_probe(i2c_dev->dev, ret,
+ "failed to compute I2C timings.\n");
if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ)
break;
setup->speed_freq =
@@ -710,13 +706,8 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
}
} while (ret);
- if (ret) {
- dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n");
- return ret;
- }
-
- i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
- "i2c-analog-filter");
+ if (ret)
+ return dev_err_probe(i2c_dev->dev, ret, "Impossible to compute I2C timings.\n");
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
setup->speed_freq, setup->clock_src);
@@ -895,8 +886,6 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
f7_msg->result = 0;
f7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1);
- reinit_completion(&i2c_dev->complete);
-
cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
@@ -1728,6 +1717,8 @@ static int stm32f7_i2c_xfer_core(struct i2c_adapter *i2c_adap,
if (ret)
goto pm_free;
+ reinit_completion(&i2c_dev->complete);
+
stm32f7_i2c_xfer_msg(i2c_dev, msgs);
if (!i2c_dev->atomic)
@@ -2175,10 +2166,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
setup = of_device_get_match_data(&pdev->dev);
- if (!setup) {
- dev_err(&pdev->dev, "Can't get device data\n");
- return -ENODEV;
- }
+ if (!setup)
+ return dev_err_probe(&pdev->dev, -ENODEV, "Can't get device data\n");
i2c_dev->setup = *setup;
i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
@@ -2215,7 +2204,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
IRQF_ONESHOT,
pdev->name, i2c_dev);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n");
+ return ret;
if (!i2c_dev->setup.single_it_line) {
irq_error = platform_get_irq(pdev, 1);
@@ -2228,7 +2217,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
IRQF_ONESHOT,
pdev->name, i2c_dev);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n");
+ return ret;
}
ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup);
@@ -2253,7 +2242,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
&res->start);
adap->owner = THIS_MODULE;
- adap->timeout = 2 * HZ;
+ adap->timeout = 8 * HZ;
adap->retries = 3;
adap->algo = &stm32f7_i2c_algo;
adap->dev.parent = &pdev->dev;
@@ -2279,7 +2268,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
ret = dev_pm_set_wake_irq(i2c_dev->dev, irq_event);
if (ret) {
- dev_err(i2c_dev->dev, "Failed to set wake up irq\n");
+ dev_err_probe(i2c_dev->dev, ret, "Failed to set wake up irq\n");
goto clr_wakeup_capable;
}
}
@@ -2305,9 +2294,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
if (i2c_dev->smbus_mode) {
ret = stm32f7_i2c_enable_smbus_host(i2c_dev);
if (ret) {
- dev_err(i2c_dev->dev,
- "failed to enable SMBus Host-Notify protocol (%d)\n",
- ret);
+ dev_err_probe(i2c_dev->dev, ret,
+ "failed to enable SMBus Host-Notify protocol\n");
goto i2c_adapter_remove;
}
}
@@ -2315,9 +2303,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
if (ret) {
- dev_err(i2c_dev->dev,
- "failed to enable SMBus alert protocol (%d)\n",
- ret);
+ dev_err_probe(i2c_dev->dev, ret,
+ "failed to enable SMBus alert protocol\n");
goto i2c_disable_smbus_host;
}
}
diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c
index fb5280b8cf7f..4f70b12a9559 100644
--- a/drivers/i2c/busses/i2c-sun6i-p2wi.c
+++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c
@@ -194,22 +194,16 @@ static int p2wi_probe(struct platform_device *pdev)
int ret;
of_property_read_u32(np, "clock-frequency", &clk_freq);
- if (clk_freq > P2WI_MAX_FREQ) {
- dev_err(dev,
- "required clock-frequency (%u Hz) is too high (max = 6MHz)",
- clk_freq);
- return -EINVAL;
- }
+ if (clk_freq > P2WI_MAX_FREQ)
+ return dev_err_probe(dev, -EINVAL,
+ "required clock-frequency (%u Hz) is too high (max = 6MHz)",
+ clk_freq);
- if (clk_freq == 0) {
- dev_err(dev, "clock-frequency is set to 0 in DT\n");
- return -EINVAL;
- }
+ if (clk_freq == 0)
+ return dev_err_probe(dev, -EINVAL, "clock-frequency is set to 0 in DT\n");
- if (of_get_child_count(np) > 1) {
- dev_err(dev, "P2WI only supports one target device\n");
- return -EINVAL;
- }
+ if (of_get_child_count(np) > 1)
+ return dev_err_probe(dev, -EINVAL, "P2WI only supports one target device\n");
p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);
if (!p2wi)
@@ -226,11 +220,9 @@ static int p2wi_probe(struct platform_device *pdev)
childnp = of_get_next_available_child(np, NULL);
if (childnp) {
ret = of_property_read_u32(childnp, "reg", &target_addr);
- if (ret) {
- dev_err(dev, "invalid target address on node %pOF\n",
- childnp);
- return -EINVAL;
- }
+ if (ret)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid target address on node %pOF\n", childnp);
p2wi->target_addr = target_addr;
}
@@ -245,26 +237,20 @@ static int p2wi_probe(struct platform_device *pdev)
return irq;
p2wi->clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(p2wi->clk)) {
- ret = PTR_ERR(p2wi->clk);
- dev_err(dev, "failed to enable clk: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(p2wi->clk))
+ return dev_err_probe(dev, PTR_ERR(p2wi->clk),
+ "failed to enable clk\n");
parent_clk_freq = clk_get_rate(p2wi->clk);
p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);
- if (IS_ERR(p2wi->rstc)) {
- dev_err(dev, "failed to retrieve reset controller: %pe\n",
- p2wi->rstc);
- return PTR_ERR(p2wi->rstc);
- }
+ if (IS_ERR(p2wi->rstc))
+ return dev_err_probe(dev, PTR_ERR(p2wi->rstc),
+ "failed to retrieve reset controller\n");
ret = reset_control_deassert(p2wi->rstc);
- if (ret) {
- dev_err(dev, "failed to deassert reset line: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert reset line\n");
init_completion(&p2wi->complete);
p2wi->adapter.dev.parent = dev;
@@ -275,11 +261,8 @@ static int p2wi_probe(struct platform_device *pdev)
i2c_set_adapdata(&p2wi->adapter, p2wi);
ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);
- if (ret) {
- dev_err(dev, "can't register interrupt handler irq%d: %d\n",
- irq, ret);
+ if (ret)
goto err_reset_assert;
- }
writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL);
diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c
index 4891d68bf0ee..0216e398f274 100644
--- a/drivers/i2c/busses/i2c-synquacer.c
+++ b/drivers/i2c/busses/i2c-synquacer.c
@@ -576,7 +576,7 @@ static int synquacer_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr,
0, dev_name(&pdev->dev), i2c);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret, "cannot claim IRQ %d\n", i2c->irq);
+ return ret;
i2c->state = STATE_IDLE;
i2c->dev = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 9fd5ade774a0..9c281b4905eb 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -164,6 +164,7 @@ struct tegra_i2c_regs {
unsigned int master_reset_cntrl;
unsigned int mst_fifo_control;
unsigned int mst_fifo_status;
+ unsigned int fairness_arb;
unsigned int sw_mutex;
};
@@ -272,6 +273,7 @@ static const struct tegra_i2c_regs tegra264_i2c_regs = {
.master_reset_cntrl = 0x0a8,
.mst_fifo_control = 0x0b4,
.mst_fifo_status = 0x0b8,
+ .fairness_arb = 0x0e8,
.sw_mutex = 0x0ec,
};
@@ -300,6 +302,7 @@ static const struct tegra_i2c_regs tegra410_i2c_regs = {
.master_reset_cntrl = 0x0ac,
.mst_fifo_control = 0x0b8,
.mst_fifo_status = 0x0bc,
+ .fairness_arb = 0x0ec,
.sw_mutex = 0x0f0,
};
@@ -379,6 +382,7 @@ enum tegra_i2c_variant {
* timing settings.
* @enable_hs_mode_support: Enable support for high speed (HS) mode transfers.
* @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
+ * @has_fairarb_reg: Has fairness arbitration register for SMBUS/MCTP support.
* @variant: This represents the I2C controller variant.
* @regs: Register offsets for the specific SoC variant.
*/
@@ -412,6 +416,7 @@ struct tegra_i2c_hw_feature {
bool has_interface_timing_reg;
bool enable_hs_mode_support;
bool has_mutex;
+ bool has_fairarb_reg;
enum tegra_i2c_variant variant;
const struct tegra_i2c_regs *regs;
};
@@ -436,6 +441,7 @@ struct tegra_i2c_hw_feature {
* @msg_read: indicates that the transfer is a read access
* @timings: i2c timings information like bus frequency
* @multimaster_mode: indicates that I2C controller is in multi-master mode
+ * @is_mctp: indicates that the I2C controller is used as an MCTP controller
* @dma_chan: DMA channel
* @dma_phys: handle to DMA resources
* @dma_buf: pointer to allocated DMA buffer
@@ -476,6 +482,7 @@ struct tegra_i2c_dev {
void *dma_buf;
bool multimaster_mode;
+ bool is_mctp;
bool atomic_mode;
bool dma_mode;
bool msg_read;
@@ -589,25 +596,22 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
return ret;
}
-static int tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
+static void tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
{
unsigned int reg = i2c_dev->hw->regs->sw_mutex;
u32 val, id;
if (!i2c_dev->hw->has_mutex)
- return 0;
+ return;
val = readl(i2c_dev->base + reg);
id = FIELD_GET(I2C_SW_MUTEX_GRANT, val);
- if (id && id != I2C_SW_MUTEX_ID_CCPLEX) {
- dev_warn(i2c_dev->dev, "unable to unlock mutex, mutex is owned by: %u\n", id);
- return -EPERM;
- }
+ if (WARN(id && id != I2C_SW_MUTEX_ID_CCPLEX,
+ "unable to unlock mutex, mutex is owned by: %u\n", id))
+ return;
writel(0, i2c_dev->base + reg);
-
- return 0;
}
static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
@@ -712,15 +716,15 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
goto err_out;
}
- i2c_dev->dma_dev = i2c_dev->dma_chan->device->dev;
+ i2c_dev->dma_dev = dmaengine_get_dma_device(i2c_dev->dma_chan);
i2c_dev->dma_buf_size = i2c_dev->hw->quirks->max_write_len +
I2C_PACKET_HEADER_SIZE;
dma_buf = dma_alloc_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size,
&dma_phys, GFP_KERNEL | __GFP_NOWARN);
if (!dma_buf) {
- dev_err(i2c_dev->dev, "failed to allocate DMA buffer\n");
- err = -ENOMEM;
+ err = dev_err_probe(i2c_dev->dev, -ENOMEM,
+ "failed to allocate DMA buffer\n");
goto err_out;
}
@@ -732,8 +736,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
err_out:
tegra_i2c_release_dma(i2c_dev);
if (err != -EPROBE_DEFER) {
- dev_err(i2c_dev->dev, "cannot use DMA: %d\n", err);
- dev_err(i2c_dev->dev, "falling back to PIO\n");
+ dev_err(i2c_dev->dev, "cannot use DMA, falling back to PIO\n");
return 0;
}
@@ -914,6 +917,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (IS_VI(i2c_dev))
tegra_i2c_vi_init(i2c_dev);
+ /* Disable fairness arbitration if not an MCTP controller */
+ if (i2c_dev->hw->has_fairarb_reg && !i2c_dev->is_mctp)
+ i2c_writel(i2c_dev, 0, i2c_dev->hw->regs->fairness_arb);
+
if (i2c_dev->hw->enable_hs_mode_support)
max_bus_freq_hz = I2C_MAX_HIGH_SPEED_MODE_FREQ;
else
@@ -1666,8 +1673,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
}
ret = tegra_i2c_mutex_lock(i2c_dev);
- if (ret)
+ if (ret) {
+ pm_runtime_put(i2c_dev->dev);
return ret;
+ }
for (i = 0; i < num; i++) {
enum msg_end_type end_type = MSG_END_STOP;
@@ -1698,7 +1707,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
break;
}
- ret = tegra_i2c_mutex_unlock(i2c_dev);
+ tegra_i2c_mutex_unlock(i2c_dev);
pm_runtime_put(i2c_dev->dev);
return ret ?: i;
@@ -1779,6 +1788,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -1812,6 +1822,7 @@ static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DVC,
.regs = &tegra20_dvc_i2c_regs,
};
@@ -1845,6 +1856,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -1877,6 +1889,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -1909,6 +1922,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -1941,6 +1955,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -1974,6 +1989,7 @@ static const struct tegra_i2c_hw_feature tegra210_vi_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_VI,
.regs = &tegra210_vi_i2c_regs,
};
@@ -2007,6 +2023,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -2041,6 +2058,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = false,
+ .has_fairarb_reg = false,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra20_i2c_regs,
};
@@ -2075,6 +2093,7 @@ static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = true,
+ .has_fairarb_reg = true,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra264_i2c_regs,
};
@@ -2109,6 +2128,7 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = true,
+ .has_fairarb_reg = true,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra264_i2c_regs,
};
@@ -2116,9 +2136,9 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
- .clk_divisor_hs_mode = 1,
+ .clk_divisor_hs_mode = 2,
.clk_divisor_std_mode = 0x3f,
- .clk_divisor_fast_mode = 0x2c,
+ .clk_divisor_fast_mode = 0x2f,
.clk_divisor_fast_plus_mode = 0x11,
.has_config_load_reg = true,
.has_multi_master_mode = true,
@@ -2134,8 +2154,8 @@ static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x2,
.thigh_fastplus_mode = 0x2,
- .tlow_hs_mode = 0x8,
- .thigh_hs_mode = 0x6,
+ .tlow_hs_mode = 0x5,
+ .thigh_hs_mode = 0x2,
.setup_hold_time_std_mode = 0x08080808,
.setup_hold_time_fast_mode = 0x02020202,
.setup_hold_time_fastplus_mode = 0x02020202,
@@ -2143,6 +2163,7 @@ static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = true,
+ .has_fairarb_reg = true,
.variant = TEGRA_I2C_VARIANT_DEFAULT,
.regs = &tegra410_i2c_regs,
};
@@ -2175,6 +2196,7 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
i2c_dev->multimaster_mode = multi_mode;
+ i2c_dev->is_mctp = device_property_present(i2c_dev->dev, "mctp-controller");
}
static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
@@ -2208,7 +2230,7 @@ static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
err = clk_enable(i2c_dev->div_clk);
if (err) {
- dev_err(i2c_dev->dev, "failed to enable div-clk: %d\n", err);
+ dev_err_probe(i2c_dev->dev, err, "failed to enable div-clk\n");
goto unprepare_clocks;
}
@@ -2234,7 +2256,7 @@ static int tegra_i2c_init_hardware(struct tegra_i2c_dev *i2c_dev)
ret = pm_runtime_get_sync(i2c_dev->dev);
if (ret < 0)
- dev_err(i2c_dev->dev, "runtime resume failed: %d\n", ret);
+ dev_err_probe(i2c_dev->dev, ret, "runtime resume failed\n");
else
ret = tegra_i2c_init(i2c_dev);
@@ -2403,28 +2425,37 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
{
+ /*
+ * Bring the controller up and hold a usage count so it stays
+ * available until the noirq phase.
+ */
+ return pm_runtime_resume_and_get(dev);
+}
+
+static int __maybe_unused tegra_i2c_suspend_noirq(struct device *dev)
+{
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
- int err;
i2c_mark_adapter_suspended(&i2c_dev->adapter);
- if (!pm_runtime_status_suspended(dev)) {
- err = tegra_i2c_runtime_suspend(dev);
- if (err)
- return err;
- }
-
- return 0;
+ /*
+ * Runtime PM is already disabled at this point, so invoke the
+ * runtime_suspend callback directly to put the controller down.
+ */
+ return tegra_i2c_runtime_suspend(dev);
}
-static int __maybe_unused tegra_i2c_resume(struct device *dev)
+static int __maybe_unused tegra_i2c_resume_noirq(struct device *dev)
{
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int err;
/*
- * We need to ensure that clocks are enabled so that registers can be
- * restored in tegra_i2c_init().
+ * Runtime PM is still disabled at this point, so invoke the
+ * runtime_resume callback directly to bring the controller back up
+ * before re-initializing the hardware. The adapter is then marked
+ * resumed so that consumers can issue transfers from their own
+ * resume_noirq() handlers and onwards.
*/
err = tegra_i2c_runtime_resume(dev);
if (err)
@@ -2434,24 +2465,22 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
if (err)
return err;
- /*
- * In case we are runtime suspended, disable clocks again so that we
- * don't unbalance the clock reference counts during the next runtime
- * resume transition.
- */
- if (pm_runtime_status_suspended(dev)) {
- err = tegra_i2c_runtime_suspend(dev);
- if (err)
- return err;
- }
-
i2c_mark_adapter_resumed(&i2c_dev->adapter);
return 0;
}
+static int __maybe_unused tegra_i2c_resume(struct device *dev)
+{
+ pm_runtime_put(dev);
+
+ return 0;
+}
+
static const struct dev_pm_ops tegra_i2c_pm = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend_noirq,
+ tegra_i2c_resume_noirq)
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
NULL)
};
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 88d66593d9fc..73355a56aabf 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -254,9 +254,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
- dev_err(&dev->adapter.dev,
- "failure setting delay to %dus\n", delay);
- retval = -EIO;
+ retval = dev_err_probe(&dev->adapter.dev, -EIO,
+ "failure setting delay to %dus\n", delay);
goto error;
}
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index ca0358e8f928..7190802a493c 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -560,7 +560,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
pdev->name, priv);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq %d\n", irq);
+ return ret;
return i2c_add_adapter(&priv->adap);
}
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 9d49a3d5d612..ad7bbf5e2466 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -354,7 +354,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
priv);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq %d\n", irq);
+ return ret;
return i2c_add_adapter(&priv->adap);
}
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 2cf3cc0165fb..d3dda7534b0a 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -114,8 +114,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
0, pdev->name, i2c);
if (err)
- return dev_err_probe(&pdev->dev, err,
- "failed to request irq %i\n", i2c->irq);
+ return err;
i2c->clk = of_clk_get(np, 0);
if (IS_ERR(i2c->clk))
diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
index 95dc64902b7c..764a2dbc957a 100644
--- a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
+++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
@@ -305,8 +305,7 @@ static int zxi2c_probe(struct platform_device *pdev)
error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr,
IRQF_SHARED, pdev->name, i2c);
if (error)
- return dev_err_probe(&pdev->dev, error,
- "failed to request irq %i\n", i2c->irq);
+ return error;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
index 7b0b0bff8000..5da6fef92bec 100644
--- a/drivers/i2c/busses/i2c-virtio.c
+++ b/drivers/i2c/busses/i2c-virtio.c
@@ -222,6 +222,8 @@ static int virtio_i2c_probe(struct virtio_device *vdev)
*/
ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(vdev->dev.parent));
+ virtio_device_ready(vdev);
+
ret = i2c_add_adapter(&vi->adap);
if (ret)
virtio_i2c_del_vqs(vdev);
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index ddb1c3e8bc9d..ad0e5cd218f0 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -530,7 +530,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
pdev->name, priv);
if (err)
- return dev_err_probe(&pdev->dev, err, "IRQ request failed!\n");
+ return err;
init_completion(&priv->msg_complete);
priv->adapter.dev.parent = &pdev->dev;
diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c
index e6d2af659d81..ca29633dcd62 100644
--- a/drivers/i2c/i2c-atr.c
+++ b/drivers/i2c/i2c-atr.c
@@ -855,6 +855,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc)
ret = i2c_add_adapter(&chan->adap);
if (ret) {
+ atr->adapter[chan_id] = NULL;
dev_err(dev, "failed to add atr-adapter %u (error=%d)\n",
chan_id, ret);
goto err_free_alias_pool;
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 2cbd31f77667..8f3bdd50186e 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -84,8 +84,11 @@ static int i2c_acpi_resource_count(struct acpi_resource *ares, void *data)
* i2c_acpi_client_count - Count the number of I2cSerialBus resources
* @adev: ACPI device
*
- * Returns the number of I2cSerialBus resources in the ACPI-device's
+ * Return:
+ * The number of I2cSerialBus resources in the ACPI-device's
* resource-list; or a negative error code.
+ *
+ * Specifically returns -ENOENT when no resources found.
*/
int i2c_acpi_client_count(struct acpi_device *adev)
{
@@ -97,7 +100,7 @@ int i2c_acpi_client_count(struct acpi_device *adev)
return ret;
acpi_dev_free_resource_list(&r);
- return count;
+ return count ?: -ENOENT;
}
EXPORT_SYMBOL_GPL(i2c_acpi_client_count);
@@ -128,15 +131,6 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
return 1;
}
-static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = {
- /*
- * ACPI video acpi_devices, which are handled by the acpi-video driver
- * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
- */
- { ACPI_VIDEO_HID, 0 },
- {}
-};
-
struct i2c_acpi_irq_context {
int irq;
bool wake_capable;
@@ -155,7 +149,11 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
if (!acpi_dev_ready_for_enumeration(adev))
return -ENODEV;
- if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
+ /*
+ * ACPI video devices, which are handled by the acpi-video driver,
+ * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
+ */
+ if (acpi_dev_is_video_device(adev))
return -ENODEV;
memset(info, 0, sizeof(*info));
@@ -165,9 +163,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
i2c_acpi_fill_info, lookup);
+ if (ret < 0)
+ return ret;
+
acpi_dev_free_resource_list(&resource_list);
- if (ret < 0 || !info->addr)
+ if (!info->addr)
return -EINVAL;
return 0;
@@ -371,7 +372,9 @@ static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = {
* a 400KHz frequency. The root cause of the issue is not known.
*/
{ "DLL0945", 0 },
+ { "ELAN0678", 0 },
{ "ELAN06FA", 0 },
+ { "ELAN1300", 0 },
{}
};
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 9c46147e3506..ddaacf876dad 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -63,6 +63,7 @@
static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);
+static void i2c_deregister_clients(struct i2c_adapter *adap);
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key);
@@ -445,8 +446,8 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
bri->set_scl = set_scl_gpio_value;
if (bri->sda_gpiod) {
bri->get_sda = get_sda_gpio_value;
- /* FIXME: add proper flag instead of '0' once available */
- if (gpiod_get_direction(bri->sda_gpiod) == 0)
+ if (gpiod_get_direction(bri->sda_gpiod) == GPIO_LINE_DIRECTION_OUT ||
+ gpiod_is_single_ended(bri->sda_gpiod))
bri->set_sda = set_sda_gpio_value;
}
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
@@ -1107,8 +1108,8 @@ EXPORT_SYMBOL(i2c_find_device_by_fwnode);
static const struct i2c_device_id dummy_id[] = {
- { "dummy", },
- { "smbus_host_notify", },
+ { .name = "dummy" },
+ { .name = "smbus_host_notify" },
{ }
};
@@ -1516,23 +1517,48 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
}
EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
+static int i2c_allocate_adapter_id(struct i2c_adapter *adap)
+{
+ int id, start, end;
+
+ if (adap->nr == -1) {
+ start = __i2c_first_dynamic_bus_num;
+ end = 0;
+ } else {
+ start = adap->nr;
+ end = adap->nr + 1;
+ }
+
+ mutex_lock(&core_lock);
+ id = idr_alloc(&i2c_adapter_idr, NULL, start, end, GFP_KERNEL);
+ mutex_unlock(&core_lock);
+ if (id < 0) {
+ if (adap->nr != -1 && id == -ENOSPC)
+ id = -EBUSY;
+ pr_err("adapter '%s': failed to allocate id: %d\n", adap->name, id);
+ return id;
+ }
+
+ adap->nr = id;
+
+ return 0;
+}
+
static int i2c_register_adapter(struct i2c_adapter *adap)
{
- int res = -EINVAL;
+ int res;
/* Can't register until after driver model init */
- if (WARN_ON(!is_registered)) {
- res = -EAGAIN;
- goto out_list;
- }
+ if (WARN_ON(!is_registered))
+ return -EAGAIN;
/* Sanity checks */
if (WARN(!adap->name[0], "i2c adapter has no name"))
- goto out_list;
+ return -EINVAL;
if (!adap->algo) {
pr_err("adapter '%s': no algo supplied!\n", adap->name);
- goto out_list;
+ return -EINVAL;
}
if (!adap->lock_ops)
@@ -1553,14 +1579,25 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
if (res) {
pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n",
adap->name, res);
- goto out_list;
+ return res;
}
- dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+ res = i2c_allocate_adapter_id(adap);
+ if (res)
+ goto err_remove_irq_domain;
+
+ res = dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+ if (res)
+ goto err_free_id;
+
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
device_initialize(&adap->dev);
+ res = i2c_init_recovery(adap);
+ if (res == -EPROBE_DEFER)
+ goto err_put_adap;
+
/*
* This adapter can be used as a parent immediately after device_add(),
* setup runtime-pm (especially ignore-children) before hand.
@@ -1570,22 +1607,21 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev);
+ adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
+
+ mutex_lock(&core_lock);
+ idr_replace(&i2c_adapter_idr, adap, adap->nr);
+ mutex_unlock(&core_lock);
+
res = device_add(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
- put_device(&adap->dev);
- goto out_list;
+ goto err_replace_id;
}
- adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
-
res = i2c_setup_smbus_alert(adap);
if (res)
- goto out_reg;
-
- res = i2c_init_recovery(adap);
- if (res == -EPROBE_DEFER)
- goto out_reg;
+ goto err_deregister_clients;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
@@ -1604,36 +1640,27 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return 0;
-out_reg:
+err_deregister_clients:
+ i2c_deregister_clients(adap);
+ device_del(&adap->dev);
+err_replace_id:
+ mutex_lock(&core_lock);
+ idr_replace(&i2c_adapter_idr, NULL, adap->nr);
+ mutex_unlock(&core_lock);
debugfs_remove_recursive(adap->debugfs);
+ pm_runtime_disable(&adap->dev);
+err_put_adap:
init_completion(&adap->dev_released);
- device_unregister(&adap->dev);
+ put_device(&adap->dev);
wait_for_completion(&adap->dev_released);
-out_list:
+err_free_id:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
- return res;
-}
-
-/**
- * __i2c_add_numbered_adapter - i2c_add_numbered_adapter where nr is never -1
- * @adap: the adapter to register (with adap->nr initialized)
- * Context: can sleep
- *
- * See i2c_add_numbered_adapter() for details.
- */
-static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
-{
- int id;
-
- mutex_lock(&core_lock);
- id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL);
- mutex_unlock(&core_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
+err_remove_irq_domain:
+ i2c_host_notify_irq_teardown(adap);
- return i2c_register_adapter(adap);
+ return res;
}
/**
@@ -1656,17 +1683,8 @@ int i2c_add_adapter(struct i2c_adapter *adapter)
int id;
id = of_alias_get_id(dev->of_node, "i2c");
- if (id >= 0) {
- adapter->nr = id;
- return __i2c_add_numbered_adapter(adapter);
- }
-
- mutex_lock(&core_lock);
- id = idr_alloc(&i2c_adapter_idr, adapter,
- __i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
- mutex_unlock(&core_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id;
+ if (id < 0)
+ id = -1;
adapter->nr = id;
@@ -1702,7 +1720,7 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap)
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
- return __i2c_add_numbered_adapter(adap);
+ return i2c_register_adapter(adap);
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
@@ -1744,29 +1762,10 @@ static int __process_removed_adapter(struct device_driver *d, void *data)
return 0;
}
-/**
- * i2c_del_adapter - unregister I2C adapter
- * @adap: the adapter being unregistered
- * Context: can sleep
- *
- * This unregisters an I2C adapter which was previously registered
- * by @i2c_add_adapter or @i2c_add_numbered_adapter.
- */
-void i2c_del_adapter(struct i2c_adapter *adap)
+static void i2c_deregister_clients(struct i2c_adapter *adap)
{
- struct i2c_adapter *found;
struct i2c_client *client, *next;
- /* First make sure that this adapter was ever added */
- mutex_lock(&core_lock);
- found = idr_find(&i2c_adapter_idr, adap->nr);
- mutex_unlock(&core_lock);
- if (found != adap) {
- pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
- return;
- }
-
- i2c_acpi_remove_space_handler(adap);
/* Tell drivers about this removal */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap,
@@ -1792,6 +1791,40 @@ void i2c_del_adapter(struct i2c_adapter *adap)
* them up properly, so we give them a chance to do that first. */
device_for_each_child(&adap->dev, NULL, __unregister_client);
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
+}
+
+/**
+ * i2c_del_adapter - unregister I2C adapter
+ * @adap: the adapter being unregistered
+ * Context: can sleep
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ */
+void i2c_del_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_adapter *found;
+
+ /* First make sure that this adapter was ever added */
+ mutex_lock(&core_lock);
+ found = idr_find(&i2c_adapter_idr, adap->nr);
+ if (found == adap)
+ idr_replace(&i2c_adapter_idr, NULL, adap->nr);
+ mutex_unlock(&core_lock);
+ if (found != adap) {
+ pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
+ return;
+ }
+
+ /*
+ * This drains any in-flight writers, so all
+ * clients will be caught by i2c_deregister_clients().
+ */
+ device_remove_file(&adap->dev, &dev_attr_new_device);
+
+ i2c_acpi_remove_space_handler(adap);
+
+ i2c_deregister_clients(adap);
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index 354a88d0599e..30b48a428c0b 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -176,11 +176,6 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
return NOTIFY_OK;
}
- /*
- * Clear the flag before adding the device so that fw_devlink
- * doesn't skip adding consumers to this device.
- */
- fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
client = of_i2c_register_device(adap, rd->dn);
if (IS_ERR(client)) {
dev_err(&adap->dev, "failed to create client for '%pOF'\n",
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
index 71eb1ef56f0c..fa63bee0b345 100644
--- a/drivers/i2c/i2c-core-smbus.c
+++ b/drivers/i2c/i2c-core-smbus.c
@@ -353,6 +353,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
msgbuf0[0] = command;
+ msgbuf1[0] = 0;
switch (size) {
case I2C_SMBUS_QUICK:
msg[0].len = 0;
@@ -566,6 +567,18 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
if (res)
return res;
+ /* Reject invalid caller-supplied block lengths before any
+ * tracepoint or native smbus_xfer callback runs.
+ */
+ if (data &&
+ (protocol == I2C_SMBUS_I2C_BLOCK_DATA ||
+ protocol == I2C_SMBUS_BLOCK_PROC_CALL ||
+ (protocol == I2C_SMBUS_BLOCK_DATA &&
+ read_write == I2C_SMBUS_WRITE)) &&
+ (data->block[0] == 0 ||
+ data->block[0] > I2C_SMBUS_BLOCK_MAX))
+ return -EINVAL;
+
/* If enabled, the following two tracepoints are conditional on
* read_write and protocol.
*/
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 4797ba88331c..c519da536647 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -3,6 +3,7 @@
* i2c-core.h - interfaces internal to the I2C framework
*/
+#include <linux/i2c.h>
#include <linux/kconfig.h>
#include <linux/rwsem.h>
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 7bbe0263411e..ccaac5e29f90 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -487,12 +487,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
client->adapter->retries = arg;
break;
case I2C_TIMEOUT:
- if (arg > INT_MAX)
+ /*
+ * For historical reasons, user-space sets the timeout value in
+ * units of 10 ms.
+ */
+ if (arg > INT_MAX / 10)
return -EINVAL;
- /* For historical reasons, user-space sets the timeout
- * value in units of 10 ms.
- */
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 681a201c239b..68a4c34b5987 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -408,6 +408,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
return 0;
err_free_priv:
+ of_node_put(priv->adap.dev.of_node);
kfree(priv);
return ret;
}
diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c
index 6bc2ef650a74..226d722af662 100644
--- a/drivers/i2c/i2c-slave-eeprom.c
+++ b/drivers/i2c/i2c-slave-eeprom.c
@@ -191,14 +191,14 @@ static void i2c_slave_eeprom_remove(struct i2c_client *client)
}
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
- { "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
- { "slave-24c02ro", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
- { "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
- { "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
- { "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
- { "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
- { "slave-24c512", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
- { "slave-24c512ro", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
+ { .name = "slave-24c02", .driver_data = I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
+ { .name = "slave-24c02ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
+ { .name = "slave-24c32", .driver_data = I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
+ { .name = "slave-24c32ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
+ { .name = "slave-24c64", .driver_data = I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
+ { .name = "slave-24c64ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
+ { .name = "slave-24c512", .driver_data = I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
+ { .name = "slave-24c512ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
{ }
};
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c
index 6de4307050dd..4a1bf1aa504b 100644
--- a/drivers/i2c/i2c-slave-testunit.c
+++ b/drivers/i2c/i2c-slave-testunit.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
-#include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
+#include <linux/workqueue.h>
#define TU_VERSION_MAX_LENGTH 128
@@ -124,7 +124,7 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
case I2C_SLAVE_STOP:
if (tu->reg_idx == TU_NUM_REGS) {
set_bit(TU_FLAG_IN_PROCESS, &tu->flags);
- queue_delayed_work(system_long_wq, &tu->worker,
+ queue_delayed_work(system_dfl_long_wq, &tu->worker,
msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY]));
}
@@ -270,7 +270,7 @@ static void i2c_slave_testunit_remove(struct i2c_client *client)
}
static const struct i2c_device_id i2c_slave_testunit_id[] = {
- { "slave-testunit" },
+ { .name = "slave-testunit" },
{ }
};
MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index bc7bd55e6370..069f08f68bc1 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -220,7 +220,7 @@ static void smbalert_remove(struct i2c_client *ara)
}
static const struct i2c_device_id smbalert_ids[] = {
- { "smbus_alert" },
+ { .name = "smbus_alert" },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, smbalert_ids);
diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c
index fbb0db41b10e..04314e3ed24c 100644
--- a/drivers/i2c/i2c-stub.c
+++ b/drivers/i2c/i2c-stub.c
@@ -214,6 +214,11 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
* We ignore banks here, because banked chips don't use I2C
* block transfers
*/
+ if (data->block[0] == 0 ||
+ data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+ ret = -EINVAL;
+ break;
+ }
if (data->block[0] > 256 - command) /* Avoid overrun */
data->block[0] = 256 - command;
len = data->block[0];
diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c
index f2a1f4744978..2403c0bf7c43 100644
--- a/drivers/i2c/muxes/i2c-demux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c
@@ -247,6 +247,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL);
if (!props[i].name || !props[i].value) {
err = -ENOMEM;
+ of_node_put(adap_np);
goto err_rollback;
}
props[i].length = 3;
diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
index 50fbc0d06e62..18228f5b80e8 100644
--- a/drivers/i2c/muxes/i2c-mux-ltc4306.c
+++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
@@ -191,8 +191,8 @@ static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
}
static const struct i2c_device_id ltc4306_id[] = {
- { "ltc4305", ltc_4305 },
- { "ltc4306", ltc_4306 },
+ { .name = "ltc4305", .driver_data = ltc_4305 },
+ { .name = "ltc4306", .driver_data = ltc_4306 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4306_id);
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 3d8002caf703..9a59129bc50f 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -74,8 +74,8 @@ struct pca9541 {
};
static const struct i2c_device_id pca9541_id[] = {
- { "pca9541" },
- {}
+ { .name = "pca9541" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, pca9541_id);
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index b9f370c9f018..8fca709ed279 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -250,24 +250,24 @@ static const struct chip_desc chips[] = {
};
static const struct i2c_device_id pca954x_id[] = {
- { "max7356", max_7356 },
- { "max7357", max_7357 },
- { "max7358", max_7358 },
- { "max7367", max_7367 },
- { "max7368", max_7368 },
- { "max7369", max_7369 },
- { "pca9540", pca_9540 },
- { "pca9542", pca_9542 },
- { "pca9543", pca_9543 },
- { "pca9544", pca_9544 },
- { "pca9545", pca_9545 },
- { "pca9546", pca_9546 },
- { "pca9547", pca_9547 },
- { "pca9548", pca_9548 },
- { "pca9846", pca_9846 },
- { "pca9847", pca_9847 },
- { "pca9848", pca_9848 },
- { "pca9849", pca_9849 },
+ { .name = "max7356", .driver_data = max_7356 },
+ { .name = "max7357", .driver_data = max_7357 },
+ { .name = "max7358", .driver_data = max_7358 },
+ { .name = "max7367", .driver_data = max_7367 },
+ { .name = "max7368", .driver_data = max_7368 },
+ { .name = "max7369", .driver_data = max_7369 },
+ { .name = "pca9540", .driver_data = pca_9540 },
+ { .name = "pca9542", .driver_data = pca_9542 },
+ { .name = "pca9543", .driver_data = pca_9543 },
+ { .name = "pca9544", .driver_data = pca_9544 },
+ { .name = "pca9545", .driver_data = pca_9545 },
+ { .name = "pca9546", .driver_data = pca_9546 },
+ { .name = "pca9547", .driver_data = pca_9547 },
+ { .name = "pca9548", .driver_data = pca_9548 },
+ { .name = "pca9846", .driver_data = pca_9846 },
+ { .name = "pca9847", .driver_data = pca_9847 },
+ { .name = "pca9848", .driver_data = pca_9848 },
+ { .name = "pca9849", .driver_data = pca_9849 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 1e566ea92bc9..13da757100fe 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_address.h>
#include <linux/platform_data/i2c-mux-reg.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -75,37 +74,34 @@ static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
-#ifdef CONFIG_OF
-static int i2c_mux_reg_probe_dt(struct regmux *mux,
- struct platform_device *pdev)
+static int i2c_mux_reg_probe_fw(struct regmux *mux, struct device *dev)
{
- struct device_node *np = pdev->dev.of_node;
- struct device_node *adapter_np, *child;
+ struct fwnode_handle *fwnode, *child;
struct i2c_adapter *adapter;
- struct resource res;
unsigned *values;
- int i = 0;
+ int ret, i = 0;
- if (!np)
+ if (!dev_fwnode(dev))
return -ENODEV;
- adapter_np = of_parse_phandle(np, "i2c-parent", 0);
- if (!adapter_np) {
- dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
+ fwnode = fwnode_find_reference(dev_fwnode(dev), "i2c-parent", 0);
+ if (IS_ERR(fwnode)) {
+ dev_err(dev, "missing 'i2c-parent' property\n");
return -ENODEV;
}
- adapter = of_find_i2c_adapter_by_node(adapter_np);
- of_node_put(adapter_np);
+
+ adapter = i2c_find_adapter_by_fwnode(fwnode);
+ fwnode_handle_put(fwnode);
if (!adapter)
return -EPROBE_DEFER;
mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev);
- mux->data.n_values = of_get_child_count(np);
- if (of_property_read_bool(np, "little-endian")) {
+ mux->data.n_values = device_get_child_node_count(dev);
+ if (device_property_read_bool(dev, "little-endian")) {
mux->data.little_endian = true;
- } else if (of_property_read_bool(np, "big-endian")) {
+ } else if (device_property_read_bool(dev, "big-endian")) {
mux->data.little_endian = false;
} else {
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \
@@ -118,40 +114,35 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
#error Endianness not defined?
#endif
}
- mux->data.write_only = of_property_read_bool(np, "write-only");
+ mux->data.write_only = device_property_read_bool(dev, "write-only");
- values = devm_kcalloc(&pdev->dev,
- mux->data.n_values, sizeof(*mux->data.values),
+ values = devm_kcalloc(dev, mux->data.n_values, sizeof(*mux->data.values),
GFP_KERNEL);
if (!values)
return -ENOMEM;
- for_each_child_of_node(np, child) {
- of_property_read_u32(child, "reg", values + i);
+ device_for_each_child_node(dev, child) {
+ if (is_acpi_device_node(child)) {
+ ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child),
+ &values[i]);
+ if (ret) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, ret,
+ "Cannot get address\n");
+ }
+ } else {
+ fwnode_property_read_u32(child, "reg", &values[i]);
+ }
+
i++;
}
mux->data.values = values;
- if (!of_property_read_u32(np, "idle-state", &mux->data.idle))
+ if (!device_property_read_u32(dev, "idle-state", &mux->data.idle))
mux->data.idle_in_use = true;
- /* map address from "reg" if exists */
- if (of_address_to_resource(np, 0, &res) == 0) {
- mux->data.reg_size = resource_size(&res);
- mux->data.reg = devm_ioremap_resource(&pdev->dev, &res);
- if (IS_ERR(mux->data.reg))
- return PTR_ERR(mux->data.reg);
- }
-
return 0;
}
-#else
-static int i2c_mux_reg_probe_dt(struct regmux *mux,
- struct platform_device *pdev)
-{
- return 0;
-}
-#endif
static int i2c_mux_reg_probe(struct platform_device *pdev)
{
@@ -169,34 +160,29 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
sizeof(mux->data));
} else {
- ret = i2c_mux_reg_probe_dt(mux, pdev);
+ ret = i2c_mux_reg_probe_fw(mux, &pdev->dev);
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
- "Error parsing device tree");
+ "Error parsing firmware description\n");
}
- parent = i2c_get_adapter(mux->data.parent);
- if (!parent)
- return -EPROBE_DEFER;
-
if (!mux->data.reg) {
- dev_info(&pdev->dev,
- "Register not set, using platform resource\n");
mux->data.reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(mux->data.reg)) {
- ret = PTR_ERR(mux->data.reg);
- goto err_put_parent;
- }
+ if (IS_ERR(mux->data.reg))
+ return PTR_ERR(mux->data.reg);
mux->data.reg_size = resource_size(res);
}
if (mux->data.reg_size != 4 && mux->data.reg_size != 2 &&
mux->data.reg_size != 1) {
dev_err(&pdev->dev, "Invalid register size\n");
- ret = -EINVAL;
- goto err_put_parent;
+ return -EINVAL;
}
+ parent = i2c_get_adapter(mux->data.parent);
+ if (!parent)
+ return -EPROBE_DEFER;
+
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
i2c_mux_reg_select, NULL);
if (!muxc) {