summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 07:43:29 +0530
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 07:43:29 +0530
commit2779759c090ea0e78109a0cad0a81d869adfb459 (patch)
treedb4d89445018c49d313640d347dbe1d375fc4170
parent31e6aeafcdde965aa10e10e93ee186520555ec3d (diff)
parent90220ddfa8e2c93e26af2cd51d6158ca2243c622 (diff)
downloadlinux-next-2779759c090ea0e78109a0cad0a81d869adfb459.tar.gz
linux-next-2779759c090ea0e78109a0cad0a81d869adfb459.zip
Merge tag 'i2c-7.2-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux
Pull i2c updates from Andi Shyti: "This pull request is mostly made of cleanups and small infrastructure improvements across the I2C core, drivers and bindings. It also adds support for three drivers and a few new compatibles. Two major cleanup across drivers and core code: - use named initializers in device ID tables - replace dev_err() with dev_err_probe() Drivers: - at24: use named initializers for arrays of i2c_device_data - at91: add MCHP_LAN966X_PCI dependency - cadence: add shutdown callback - k1: enable by default on SpacemiT - mxs: improve documentation - qcom-geni: use pm_runtime_force_suspend/resume for system sleep - tegra: - disable fair arbitration on non-MCTP buses - allocate DMA buffers from the correct DMA device - designware: - handle active target shutdown cleanly - add shutdown callbacks for platform and PCI drivers - adopt the new PM_RUNTIME_ACQUIRE() helpers DT bindings: - convert davinci bindings to DT schema Core and muxes: - acpi: report missing I2C resources as -ENOENT - gpiolib: add gpiod_is_single_ended() helper for I2C GPIO users - i2c-mux-reg: add generic firmware node support - a set of 10 patches from Johan Hovold fixing adapter registration races, cleanup paths and resource management issues New support: - DesignWare LECA0003 (ACPI ID) - Loongson LS2K0300 I2C controller (new driver) - Qualcomm CCI Glymur and Shikra compatibles" * tag 'i2c-7.2-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux: (46 commits) i2c: mxs: add missing kernel-doc for struct mxs_i2c_dev members i2c: qcom-geni: Use pm_runtime_force_{suspend,resume} helpers dt-bindings: i2c: qcom-cci: Document Glymur compatible dt-bindings: i2c: qcom-cci: Document Shikra compatible i2c: mux: reg: use device property accessors i2c: acpi: Return -ENOENT when no resources found in i2c_acpi_client_count() i2c: at91: Add MCHP_LAN966X_PCI dependency i2c: eg20t: Consistently define pci_device_ids using named initializers i2c: designware-pcidrv: Consistently define pci_device_ids using named initializers i2c: bcm-kona: fix spelling mistake in timeout-check comment i2c: cadence: Add shutdown handler i2c: tegra: Disable fair arbitration for non-MCTP buses i2c: tegra: use dmaengine_get_dma_device() for DMA buffer allocation i2c: busses: make K1 driver default for SpacemiT platforms i2c: Use named initializers for arrays of i2c_device_data i2c: core: clean up adapter registration error label i2c: core: clean up bus id allocation i2c: core: fix adapter deregistration race i2c: core: fix adapter registration race i2c: core: disable runtime PM on adapter registration failure ...
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-davinci.txt43
-rw-r--r--Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml4
-rw-r--r--Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml4
-rw-r--r--Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml70
-rw-r--r--MAINTAINERS3
-rw-r--r--drivers/acpi/acpi_apd.c7
-rw-r--r--drivers/i2c/busses/Kconfig14
-rw-r--r--drivers/i2c/busses/Makefile1
-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-designware-common.c36
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h1
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c31
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c92
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c15
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c10
-rw-r--r--drivers/i2c/busses/i2c-icy.c4
-rw-r--r--drivers/i2c/busses/i2c-ls2x-v2.c544
-rw-r--r--drivers/i2c/busses/i2c-mxs.c8
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c24
-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.c13
-rw-r--r--drivers/i2c/busses/i2c-st.c34
-rw-r--r--drivers/i2c/busses/i2c-stm32.c4
-rw-r--r--drivers/i2c/busses/i2c-stm32f4.c53
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c78
-rw-r--r--drivers/i2c/busses/i2c-sun6i-p2wi.c55
-rw-r--r--drivers/i2c/busses/i2c-tegra.c37
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c5
-rw-r--r--drivers/i2c/i2c-core-acpi.c7
-rw-r--r--drivers/i2c/i2c-core-base.c177
-rw-r--r--drivers/i2c/i2c-slave-eeprom.c16
-rw-r--r--drivers/i2c/i2c-slave-testunit.c2
-rw-r--r--drivers/i2c/i2c-smbus.c2
-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
-rw-r--r--drivers/misc/eeprom/at24.c62
40 files changed, 1173 insertions, 500 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
deleted file mode 100644
index 6590501c53d4..000000000000
--- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-* Texas Instruments Davinci/Keystone I2C
-
-This file provides information, what the device node for the
-davinci/keystone i2c interface contains.
-
-Required properties:
-- compatible: "ti,davinci-i2c" or "ti,keystone-i2c";
-- reg : Offset and length of the register set for the device
-- clocks: I2C functional clock phandle.
- For 66AK2G this property should be set per binding,
- Documentation/devicetree/bindings/clock/ti,sci-clk.yaml
-
-SoC-specific Required Properties:
-
-The following are mandatory properties for Keystone 2 66AK2G SoCs only:
-
-- power-domains: Should contain a phandle to a PM domain provider node
- and an args specifier containing the I2C device id
- value. This property is as per the binding,
- Documentation/devicetree/bindings/soc/ti/sci-pm-domain.yaml
-
-Recommended properties :
-- interrupts : standard interrupt property.
-- clock-frequency : desired I2C bus clock frequency in Hz.
-- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC
- registers. PFUNC registers allow to switch I2C pins to function as
- GPIOs, so they can be toggled manually.
-
-Example (enbw_cmc board):
- i2c@1c22000 {
- compatible = "ti,davinci-i2c";
- reg = <0x22000 0x1000>;
- clock-frequency = <100000>;
- interrupts = <15>;
- interrupt-parent = <&intc>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- dtt@48 {
- compatible = "national,lm75";
- reg = <0x48>;
- };
- };
diff --git a/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
index 67882ec6e06a..ee09c6d9c5f0 100644
--- a/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
@@ -16,6 +16,7 @@ properties:
compatible:
enum:
- loongson,ls2k-i2c
+ - loongson,ls2k0300-i2c
- loongson,ls7a-i2c
reg:
@@ -24,6 +25,9 @@ properties:
interrupts:
maxItems: 1
+ clocks:
+ maxItems: 1
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
index 7c497a358e1d..1e8def25ec0e 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
@@ -26,6 +26,7 @@ properties:
- items:
- enum:
+ - qcom,glymur-cci
- qcom,kaanapali-cci
- qcom,milos-cci
- qcom,qcm2290-cci
@@ -35,6 +36,7 @@ properties:
- qcom,sc8280xp-cci
- qcom,sdm670-cci
- qcom,sdm845-cci
+ - qcom,shikra-cci
- qcom,sm6150-cci
- qcom,sm6350-cci
- qcom,sm8250-cci
@@ -134,9 +136,11 @@ allOf:
compatible:
contains:
enum:
+ - qcom,glymur-cci
- qcom,kaanapali-cci
- qcom,qcm2290-cci
- qcom,qcs8300-cci
+ - qcom,shikra-cci
- qcom,sm8750-cci
then:
properties:
diff --git a/Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml b/Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
new file mode 100644
index 000000000000..b94ac06dce36
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/ti,davinci-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments DaVinci/Keystone I2C
+
+maintainers:
+ - Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: ti,keystone-i2c
+ then:
+ required:
+ - power-domains
+
+properties:
+ compatible:
+ enum:
+ - ti,davinci-i2c
+ - ti,keystone-i2c
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ti,has-pfunc:
+ description:
+ Indicates that the SoC supports PFUNC registers, allowing I2C pins
+ to function as GPIOs for manual toggling.
+ type: boolean
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c@1c22000 {
+ compatible = "ti,davinci-i2c";
+ reg = <0x01c22000 0x1000>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ interrupts = <15>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@48 {
+ compatible = "national,lm75";
+ reg = <0x48>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index a068db0ade61..4108b6e62cc3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15069,6 +15069,7 @@ M: Binbin Zhou <zhoubinbin@loongson.cn>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
+F: drivers/i2c/busses/i2c-ls2x-v2.c
F: drivers/i2c/busses/i2c-ls2x.c
LOONGSON PWM DRIVER
@@ -26710,7 +26711,7 @@ M: Bartosz Golaszewski <brgl@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
-F: Documentation/devicetree/bindings/i2c/i2c-davinci.txt
+F: Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
F: arch/arm/boot/dts/ti/davinci/
F: arch/arm/mach-davinci/
F: drivers/i2c/busses/i2c-davinci.c
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index bed0791c17fc..86678ee22a04 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -181,6 +181,12 @@ static const struct apd_device_desc hip08_spi_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 250000000,
};
+
+static const struct apd_device_desc leca_i2c_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 250000000,
+};
+
#endif /* CONFIG_ARM64 */
#endif
@@ -251,6 +257,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "HISI02A2", APD_ADDR(hip08_i2c_desc) },
{ "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) },
{ "HISI0173", APD_ADDR(hip08_spi_desc) },
+ { "LECA0003", APD_ADDR(leca_i2c_desc) },
{ "NXP0001", APD_ADDR(nxp_i2c_desc) },
#endif
{ }
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8c935f867a37..3123ab75600b 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.
@@ -794,6 +794,7 @@ config I2C_K1
tristate "SpacemiT K1 I2C adapter"
depends on ARCH_SPACEMIT || COMPILE_TEST
depends on OF
+ 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
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-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-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 4dc57fd56170..e4dfa2ec58bb 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -633,6 +633,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 +966,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 +1036,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..c71aa2dd368d 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -417,6 +417,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..7a301c8b604e 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -785,18 +785,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..6d6e81242f74 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -279,6 +279,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "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-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-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-ls2x-v2.c b/drivers/i2c/busses/i2c-ls2x-v2.c
new file mode 100644
index 000000000000..517760d70169
--- /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_NONE;
+ }
+
+ 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-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 08c9091a1e35..4e07babea9c3 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;
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index a482a4c60744..d2f5055b0b10 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -110,7 +110,6 @@ struct geni_i2c_dev {
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;
@@ -1143,7 +1142,6 @@ static int geni_i2c_probe(struct platform_device *pdev)
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);
@@ -1200,9 +1198,6 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
if (ret) {
enable_irq(gi2c->irq);
return ret;
-
- } else {
- gi2c->suspended = 1;
}
clk_disable_unprepare(gi2c->core_clk);
@@ -1228,7 +1223,6 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
goto out_clk_disable;
enable_irq(gi2c->irq);
- gi2c->suspended = 0;
return 0;
@@ -1243,21 +1237,25 @@ out_icc_disable:
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;
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..7b321a956fca 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;
}
@@ -548,13 +547,13 @@ static int sprd_i2c_probe(struct platform_device *pdev)
IRQF_NO_SUSPEND | IRQF_ONESHOT,
pdev->name, i2c_dev);
if (ret) {
- dev_err(&pdev->dev, "failed to request irq %d\n", i2c_dev->irq);
+ dev_err_probe(&pdev->dev, ret, "failed to request irq %d\n", i2c_dev->irq);
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..3f89c2145741 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,9 @@ 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);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request irq %i\n", i2c_dev->irq);
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..44e8b04962bb 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,15 @@ 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);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request irq event %i\n", irq_event);
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);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request irq error %i\n", irq_error);
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 067af255bd22..16c6e61c7e11 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -481,28 +481,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 +561,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 +617,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 +666,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,10 +676,8 @@ 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;
@@ -701,8 +689,8 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
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 =
@@ -713,10 +701,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;
- }
+ 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);
@@ -2175,10 +2161,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);
@@ -2279,7 +2263,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 +2289,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 +2298,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..dffbe776a195 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;
@@ -276,8 +262,7 @@ static int p2wi_probe(struct platform_device *pdev)
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);
+ dev_err_probe(dev, ret, "can't register interrupt handler irq%d\n", irq);
goto err_reset_assert;
}
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 400c9089daf0..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;
@@ -709,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;
}
@@ -729,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;
}
@@ -911,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
@@ -1778,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,
};
@@ -1811,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,
};
@@ -1844,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,
};
@@ -1876,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,
};
@@ -1908,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,
};
@@ -1940,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,
};
@@ -1973,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,
};
@@ -2006,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,
};
@@ -2040,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,
};
@@ -2074,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,
};
@@ -2108,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,
};
@@ -2142,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,
};
@@ -2174,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)
@@ -2207,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;
}
@@ -2233,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);
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/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 28c0e4884a7f..e5fddacae9a4 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);
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index a2132d70fb36..3ec04787a737 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);
@@ -1106,8 +1107,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" },
{ }
};
@@ -1515,23 +1516,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)
@@ -1552,14 +1578,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.
@@ -1569,22 +1606,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);
@@ -1603,36 +1639,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;
}
/**
@@ -1655,17 +1682,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;
@@ -1701,7 +1719,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);
@@ -1743,29 +1761,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,
@@ -1791,6 +1790,34 @@ 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;
+ }
+
+ 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-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 871c58461ebc..4a1bf1aa504b 100644
--- a/drivers/i2c/i2c-slave-testunit.c
+++ b/drivers/i2c/i2c-slave-testunit.c
@@ -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/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) {
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 0200288d3a7a..5d5f357a1996 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -215,37 +215,37 @@ AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
static const struct i2c_device_id at24_ids[] = {
- { "24c00", (kernel_ulong_t)&at24_data_24c00 },
- { "24c01", (kernel_ulong_t)&at24_data_24c01 },
- { "24cs01", (kernel_ulong_t)&at24_data_24cs01 },
- { "24c02", (kernel_ulong_t)&at24_data_24c02 },
- { "24cs02", (kernel_ulong_t)&at24_data_24cs02 },
- { "24mac402", (kernel_ulong_t)&at24_data_24mac402 },
- { "24mac602", (kernel_ulong_t)&at24_data_24mac602 },
- { "24aa025e48", (kernel_ulong_t)&at24_data_24aa025e48 },
- { "24aa025e64", (kernel_ulong_t)&at24_data_24aa025e64 },
- { "spd", (kernel_ulong_t)&at24_data_spd },
- { "24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio },
- { "24c04", (kernel_ulong_t)&at24_data_24c04 },
- { "24cs04", (kernel_ulong_t)&at24_data_24cs04 },
- { "24c08", (kernel_ulong_t)&at24_data_24c08 },
- { "24cs08", (kernel_ulong_t)&at24_data_24cs08 },
- { "24c16", (kernel_ulong_t)&at24_data_24c16 },
- { "24cs16", (kernel_ulong_t)&at24_data_24cs16 },
- { "24c32", (kernel_ulong_t)&at24_data_24c32 },
- { "24c32d-wl", (kernel_ulong_t)&at24_data_24c32d_wlp },
- { "24cs32", (kernel_ulong_t)&at24_data_24cs32 },
- { "24c64", (kernel_ulong_t)&at24_data_24c64 },
- { "24c64-wl", (kernel_ulong_t)&at24_data_24c64d_wlp },
- { "24cs64", (kernel_ulong_t)&at24_data_24cs64 },
- { "24c128", (kernel_ulong_t)&at24_data_24c128 },
- { "24c256", (kernel_ulong_t)&at24_data_24c256 },
- { "24256e-wl", (kernel_ulong_t)&at24_data_24256e_wlp },
- { "24c512", (kernel_ulong_t)&at24_data_24c512 },
- { "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
- { "24c1025", (kernel_ulong_t)&at24_data_24c1025 },
- { "24c2048", (kernel_ulong_t)&at24_data_24c2048 },
- { "at24", 0 },
+ { .name = "24c00", .driver_data = (kernel_ulong_t)&at24_data_24c00 },
+ { .name = "24c01", .driver_data = (kernel_ulong_t)&at24_data_24c01 },
+ { .name = "24cs01", .driver_data = (kernel_ulong_t)&at24_data_24cs01 },
+ { .name = "24c02", .driver_data = (kernel_ulong_t)&at24_data_24c02 },
+ { .name = "24cs02", .driver_data = (kernel_ulong_t)&at24_data_24cs02 },
+ { .name = "24mac402", .driver_data = (kernel_ulong_t)&at24_data_24mac402 },
+ { .name = "24mac602", .driver_data = (kernel_ulong_t)&at24_data_24mac602 },
+ { .name = "24aa025e48", .driver_data = (kernel_ulong_t)&at24_data_24aa025e48 },
+ { .name = "24aa025e64", .driver_data = (kernel_ulong_t)&at24_data_24aa025e64 },
+ { .name = "spd", .driver_data = (kernel_ulong_t)&at24_data_spd },
+ { .name = "24c02-vaio", .driver_data = (kernel_ulong_t)&at24_data_24c02_vaio },
+ { .name = "24c04", .driver_data = (kernel_ulong_t)&at24_data_24c04 },
+ { .name = "24cs04", .driver_data = (kernel_ulong_t)&at24_data_24cs04 },
+ { .name = "24c08", .driver_data = (kernel_ulong_t)&at24_data_24c08 },
+ { .name = "24cs08", .driver_data = (kernel_ulong_t)&at24_data_24cs08 },
+ { .name = "24c16", .driver_data = (kernel_ulong_t)&at24_data_24c16 },
+ { .name = "24cs16", .driver_data = (kernel_ulong_t)&at24_data_24cs16 },
+ { .name = "24c32", .driver_data = (kernel_ulong_t)&at24_data_24c32 },
+ { .name = "24c32d-wl", .driver_data = (kernel_ulong_t)&at24_data_24c32d_wlp },
+ { .name = "24cs32", .driver_data = (kernel_ulong_t)&at24_data_24cs32 },
+ { .name = "24c64", .driver_data = (kernel_ulong_t)&at24_data_24c64 },
+ { .name = "24c64-wl", .driver_data = (kernel_ulong_t)&at24_data_24c64d_wlp },
+ { .name = "24cs64", .driver_data = (kernel_ulong_t)&at24_data_24cs64 },
+ { .name = "24c128", .driver_data = (kernel_ulong_t)&at24_data_24c128 },
+ { .name = "24c256", .driver_data = (kernel_ulong_t)&at24_data_24c256 },
+ { .name = "24256e-wl", .driver_data = (kernel_ulong_t)&at24_data_24256e_wlp },
+ { .name = "24c512", .driver_data = (kernel_ulong_t)&at24_data_24c512 },
+ { .name = "24c1024", .driver_data = (kernel_ulong_t)&at24_data_24c1024 },
+ { .name = "24c1025", .driver_data = (kernel_ulong_t)&at24_data_24c1025 },
+ { .name = "24c2048", .driver_data = (kernel_ulong_t)&at24_data_24c2048 },
+ { .name = "at24", .driver_data = 0 },
{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, at24_ids);