summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-15 21:10:39 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-15 21:10:39 -0700
commit273cbf61c3ddee9574ef1f4959b9bc6db5b24271 (patch)
tree1eb8a54d416453ad7c6adbf57ab05dce2587a012
parent5fe7b600a116187e10317d83fb56922c4ef6b76d (diff)
parentcc6b9dfb2c5769afeb3335048173c730bdf8dbe1 (diff)
downloadlwn-273cbf61c3ddee9574ef1f4959b9bc6db5b24271.tar.gz
lwn-273cbf61c3ddee9574ef1f4959b9bc6db5b24271.zip
Merge branch 'i2c/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "New stuff from the I2C world: - in the core, getting irqs from ACPI is now similar to OF - new driver for MediaTek MT7621/7628/7688 SoCs - bcm2835, i801, and tegra drivers got some more attention - GPIO API cleanups - cleanups in the core headers - lots of usual driver updates" * 'i2c/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (74 commits) i2c: mt7621: Fix platform_no_drv_owner.cocci warnings i2c: cpm: remove casting dma_alloc dt-bindings: i2c: sun6i-p2wi: Fix the binding example dt-bindings: i2c: mv64xxx: Fix the example compatible i2c: i801: Documentation update i2c: i801: Add support for Intel Tiger Lake i2c: i801: Fix PCI ID sorting dt-bindings: i2c-stm32: document optional dmas i2c: i2c-stm32f7: Add I2C_SMBUS_I2C_BLOCK_DATA support i2c: core: Tidy up handling of init_irq i2c: core: Move ACPI gpio IRQ handling into i2c_acpi_get_irq i2c: core: Move ACPI IRQ handling to probe time i2c: acpi: Factor out getting the IRQ from ACPI i2c: acpi: Use available IRQ helper functions i2c: core: Allow whole core to use i2c_dev_irq_from_resources eeprom: at24: modify a comment referring to platform data dt-bindings: i2c: omap: Add new compatible for J721E SoCs dt-bindings: i2c: mv64xxx: Add YAML schemas dt-bindings: i2c: sun6i-p2wi: Add YAML schemas i2c: mt7621: Add MediaTek MT7621/7628/7688 I2C driver ...
-rw-r--r--Documentation/ABI/testing/sysfs-platform-i2c-demux-pinctrl4
-rw-r--r--Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml65
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mt7621.txt25
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt64
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-ocores.txt9
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-omap.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-stm32.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-sun6i-p2wi.txt41
-rw-r--r--Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml124
-rw-r--r--Documentation/i2c/busses/i2c-i80120
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/arm/include/asm/hardware/iop3xx.h2
-rw-r--r--arch/arm/mach-iop32x/em7210.c3
-rw-r--r--arch/arm/mach-iop32x/glantank.c3
-rw-r--r--arch/arm/mach-iop32x/iq31244.c3
-rw-r--r--arch/arm/mach-iop32x/iq80321.c3
-rw-r--r--arch/arm/mach-iop32x/n2100.c2
-rw-r--r--arch/arm/plat-iop/i2c.c24
-rw-r--r--drivers/gpio/gpio-iop.c1
-rw-r--r--drivers/i2c/busses/Kconfig13
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c117
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c135
-rw-r--r--drivers/i2c/busses/i2c-cpm.c4
-rw-r--r--drivers/i2c/busses/i2c-fsi.c32
-rw-r--r--drivers/i2c/busses/i2c-i801.c206
-rw-r--r--drivers/i2c/busses/i2c-imx.c11
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c32
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h2
-rw-r--r--drivers/i2c/busses/i2c-mt7621.c356
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c64
-rw-r--r--drivers/i2c/busses/i2c-ocores.c33
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c17
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c47
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c32
-rw-r--r--drivers/i2c/busses/i2c-tegra.c136
-rw-r--r--drivers/i2c/i2c-core-acpi.c58
-rw-r--r--drivers/i2c/i2c-core-base.c20
-rw-r--r--drivers/i2c/i2c-core-of.c1
-rw-r--r--drivers/i2c/i2c-core.h9
-rw-r--r--drivers/i2c/i2c-mux.c4
-rw-r--r--drivers/i2c/muxes/i2c-arb-gpio-challenge.c79
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpio.c116
-rw-r--r--drivers/i2c/muxes/i2c-mux-pinctrl.c5
-rw-r--r--drivers/misc/eeprom/at24.c86
-rw-r--r--drivers/platform/x86/dell-smo8800.c1
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c10
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h1
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c118
-rw-r--r--include/linux/i2c.h93
-rw-r--r--include/linux/platform_data/i2c-mux-gpio.h7
51 files changed, 1605 insertions, 644 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-i2c-demux-pinctrl b/Documentation/ABI/testing/sysfs-platform-i2c-demux-pinctrl
index 3c3514815cd5..c394b808be19 100644
--- a/Documentation/ABI/testing/sysfs-platform-i2c-demux-pinctrl
+++ b/Documentation/ABI/testing/sysfs-platform-i2c-demux-pinctrl
@@ -1,7 +1,7 @@
What: /sys/devices/platform/<i2c-demux-name>/available_masters
Date: January 2016
KernelVersion: 4.6
-Contact: Wolfram Sang <wsa@the-dreams.de>
+Contact: Wolfram Sang <wsa+renesas@sang-engineering.com>
Description:
Reading the file will give you a list of masters which can be
selected for a demultiplexed bus. The format is
@@ -12,7 +12,7 @@ Description:
What: /sys/devices/platform/<i2c-demux-name>/current_master
Date: January 2016
KernelVersion: 4.6
-Contact: Wolfram Sang <wsa@the-dreams.de>
+Contact: Wolfram Sang <wsa+renesas@sang-engineering.com>
Description:
This file selects/shows the active I2C master for a demultiplexed
bus. It uses the <index> value from the file 'available_masters'.
diff --git a/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml b/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml
new file mode 100644
index 000000000000..f9d526b7da01
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/allwinner,sun6i-a31-p2wi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 P2WI (Push/Pull 2 Wires Interface) Device Tree Bindings
+
+maintainers:
+ - Chen-Yu Tsai <wens@csie.org>
+ - Maxime Ripard <maxime.ripard@bootlin.com>
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+ compatible:
+ const: allwinner,sun6i-a31-p2wi
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ clock-frequency:
+ minimum: 1
+ maximum: 6000000
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - resets
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+examples:
+ - |
+ i2c@1f03400 {
+ compatible = "allwinner,sun6i-a31-p2wi";
+ reg = <0x01f03400 0x400>;
+ interrupts = <0 39 4>;
+ clocks = <&apb0_gates 3>;
+ clock-frequency = <100000>;
+ resets = <&apb0_rst 3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp221: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mt7621.txt b/Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
new file mode 100644
index 000000000000..bc36f0eb94cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
@@ -0,0 +1,25 @@
+MediaTek MT7621/MT7628 I2C master controller
+
+Required properties:
+
+- compatible: Should be one of the following:
+ - "mediatek,mt7621-i2c": for MT7621/MT7628/MT7688 platforms
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- reg: Address and length of the register set for the device
+- resets: phandle to the reset controller asserting this device in
+ reset
+ See ../reset/reset.txt for details.
+
+Optional properties :
+
+Example:
+
+i2c: i2c@900 {
+ compatible = "mediatek,mt7621-i2c";
+ reg = <0x900 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ resets = <&rstctrl 16>;
+ reset-names = "i2c";
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
deleted file mode 100644
index 0ffe65a316ae..000000000000
--- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-
-* Marvell MV64XXX I2C controller
-
-Required properties :
-
- - reg : Offset and length of the register set for the device
- - compatible : Should be either:
- - "allwinner,sun4i-a10-i2c"
- - "allwinner,sun6i-a31-i2c"
- - "marvell,mv64xxx-i2c"
- - "marvell,mv78230-i2c"
- - "marvell,mv78230-a0-i2c"
- * Note: Only use "marvell,mv78230-a0-i2c" for a
- very rare, initial version of the SoC which
- had broken offload support. Linux
- auto-detects this and sets it appropriately.
- - interrupts : The interrupt number
-
-Optional properties :
-
- - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the
-default frequency is 100kHz
-
- - resets : phandle to the parent reset controller. Mandatory
- whenever you're using the "allwinner,sun6i-a31-i2c"
- compatible.
-
- - clocks: : pointers to the reference clocks for this device, the
- first one is the one used for the clock on the i2c bus,
- the second one is the clock used to acces the registers
- of the controller
-
- - clock-names : names of used clocks, mandatory if the second clock is
- used, the name must be "core", and "reg" (the latter is
- only for Armada 7K/8K).
-
-Examples:
-
- i2c@11000 {
- compatible = "marvell,mv64xxx-i2c";
- reg = <0x11000 0x20>;
- interrupts = <29>;
- clock-frequency = <100000>;
- };
-
-For the Armada XP:
-
- i2c@11000 {
- compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
- reg = <0x11000 0x100>;
- interrupts = <29>;
- clock-frequency = <100000>;
- };
-
-For the Armada 7040:
-
- i2c@701000 {
- compatible = "marvell,mv78230-i2c";
- reg = <0x701000 0x20>;
- interrupts = <29>;
- clock-frequency = <100000>;
- clock-names = "core", "reg";
- clocks = <&core_clock>, <&reg_clock>;
- };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a34e50..6b25a80ae8d3 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
Device tree configuration for i2c-ocores
Required properties:
-- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible : "opencores,i2c-ocores"
+ "aeroflexgaisler,i2cmst"
+ "sifive,fu540-c000-i2c", "sifive,i2c0"
+ For Opencore based I2C IP block reimplemented in
+ FU540-C000 SoC. Please refer to sifive-blocks-ip-versioning.txt
+ for additional details.
- reg : bus address start and address range size of device
-- interrupts : interrupt number
- clocks : handle to the controller clock; see the note below.
Mutually exclusive with opencores,ip-clock-frequency
- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
- #size-cells : should be <0>
Optional properties:
+- interrupts : interrupt number.
- clock-frequency : frequency of bus clock in Hz; see the note below.
Defaults to 100 KHz when the property is not specified
- reg-shift : device register offsets are shifted by this value
diff --git a/Documentation/devicetree/bindings/i2c/i2c-omap.txt b/Documentation/devicetree/bindings/i2c/i2c-omap.txt
index 4b90ba9f31b7..a44573d7c118 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-omap.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-omap.txt
@@ -7,6 +7,7 @@ Required properties :
"ti,omap3-i2c" for OMAP3 SoCs
"ti,omap4-i2c" for OMAP4+ SoCs
"ti,am654-i2c", "ti,omap4-i2c" for AM654 SoCs
+ "ti,j721e-i2c", "ti,omap4-i2c" for J721E SoCs
- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
- #address-cells = <1>;
- #size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
index f334738f7a35..ce3df2fff6c8 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
@@ -21,6 +21,8 @@ Optional properties:
100000 and 400000.
For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode, Fast-mode and Fast-mode
Plus are supported, possible values are 100000, 400000 and 1000000.
+- dmas: List of phandles to rx and tx DMA channels. Refer to stm32-dma.txt.
+- dma-names: List of dma names. Valid names are: "rx" and "tx".
- i2c-scl-rising-time-ns: I2C SCL Rising time for the board (default: 25)
For STM32F7, STM32H7 and STM32MP1 only.
- i2c-scl-falling-time-ns: I2C SCL Falling time for the board (default: 10)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-sun6i-p2wi.txt b/Documentation/devicetree/bindings/i2c/i2c-sun6i-p2wi.txt
deleted file mode 100644
index 49df0053347a..000000000000
--- a/Documentation/devicetree/bindings/i2c/i2c-sun6i-p2wi.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-
-* Allwinner P2WI (Push/Pull 2 Wire Interface) controller
-
-Required properties :
-
- - reg : Offset and length of the register set for the device.
- - compatible : Should one of the following:
- - "allwinner,sun6i-a31-p2wi"
- - interrupts : The interrupt line connected to the P2WI peripheral.
- - clocks : The gate clk connected to the P2WI peripheral.
- - resets : The reset line connected to the P2WI peripheral.
-
-Optional properties :
-
- - clock-frequency : Desired P2WI bus clock frequency in Hz. If not set the
-default frequency is 100kHz
-
-A P2WI may contain one child node encoding a P2WI slave device.
-
-Slave device properties:
- Required properties:
- - reg : the I2C slave address used during the initialization
- process to switch from I2C to P2WI mode
-
-Example:
-
- p2wi@1f03400 {
- compatible = "allwinner,sun6i-a31-p2wi";
- reg = <0x01f03400 0x400>;
- interrupts = <0 39 4>;
- clocks = <&apb0_gates 3>;
- clock-frequency = <6000000>;
- resets = <&apb0_rst 3>;
-
- axp221: pmic@68 {
- compatible = "x-powers,axp221";
- reg = <0x68>;
-
- /* ... */
- };
- };
diff --git a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
new file mode 100644
index 000000000000..001f2b7abad0
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/marvell,mv64xxx-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Marvell MV64XXX I2C Controller Device Tree Bindings
+
+maintainers:
+ - Gregory CLEMENT <gregory.clement@bootlin.com>
+
+properties:
+ compatible:
+ oneOf:
+ - const: allwinner,sun4i-a10-i2c
+ - items:
+ - const: allwinner,sun7i-a20-i2c
+ - const: allwinner,sun4i-a10-i2c
+ - const: allwinner,sun6i-a31-i2c
+ - items:
+ - const: allwinner,sun8i-a23-i2c
+ - const: allwinner,sun6i-a31-i2c
+ - items:
+ - const: allwinner,sun8i-a83t-i2c
+ - const: allwinner,sun6i-a31-i2c
+ - items:
+ - const: allwinner,sun50i-a64-i2c
+ - const: allwinner,sun6i-a31-i2c
+
+ - const: marvell,mv64xxx-i2c
+ - const: marvell,mv78230-i2c
+ - const: marvell,mv78230-a0-i2c
+
+ description:
+ Only use "marvell,mv78230-a0-i2c" for a very rare, initial
+ version of the SoC which had broken offload support. Linux
+ auto-detects this and sets it appropriately.
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+ items:
+ - description: Reference clock for the I2C bus
+ - description: Bus clock (Only for Armada 7K/8K)
+
+ clock-names:
+ minItems: 1
+ maxItems: 2
+ items:
+ - const: core
+ - const: reg
+ description:
+ Mandatory if two clocks are used (only for Armada 7k and 8k).
+
+ resets:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - allwinner,sun4i-a10-i2c
+ - allwinner,sun6i-a31-i2c
+
+ then:
+ required:
+ - clocks
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: allwinner,sun6i-a31-i2c
+
+ then:
+ required:
+ - resets
+
+# FIXME: We should set it, but it would report all the generic
+# properties as additional properties.
+# additionalProperties: false
+
+examples:
+ - |
+ i2c@11000 {
+ compatible = "marvell,mv64xxx-i2c";
+ reg = <0x11000 0x20>;
+ interrupts = <29>;
+ clock-frequency = <100000>;
+ };
+
+ - |
+ i2c@11000 {
+ compatible = "marvell,mv78230-i2c";
+ reg = <0x11000 0x100>;
+ interrupts = <29>;
+ clock-frequency = <100000>;
+ };
+
+ - |
+ i2c@701000 {
+ compatible = "marvell,mv78230-i2c";
+ reg = <0x701000 0x20>;
+ interrupts = <29>;
+ clock-frequency = <100000>;
+ clock-names = "core", "reg";
+ clocks = <&core_clock>, <&reg_clock>;
+ };
+
+...
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index ee9984f35868..f426c13c63a9 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -37,6 +37,8 @@ Supported adapters:
* Intel Cedar Fork (PCH)
* Intel Ice Lake (PCH)
* Intel Comet Lake (PCH)
+ * Intel Elkhart Lake (PCH)
+ * Intel Tiger Lake (PCH)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller
@@ -58,6 +60,7 @@ question doesn't work as intended for whatever reason. Bit values:
0x02 disable the block buffer
0x08 disable the I2C block read functionality
0x10 don't use interrupts
+ 0x20 disable SMBus Host Notify
Description
@@ -88,7 +91,7 @@ SMBus controller.
Process Call Support
--------------------
-Not supported.
+Block process call is supported on the 82801EB (ICH5) and later chips.
I2C Block Read Support
@@ -118,16 +121,15 @@ BIOS to enable it, it means it has been hidden by the BIOS code. Asus is
well known for first doing this on their P4B motherboard, and many other
boards after that. Some vendor machines are affected as well.
-The first thing to try is the "i2c_ec" ACPI driver. It could be that the
+The first thing to try is the "i2c-scmi" ACPI driver. It could be that the
SMBus was hidden on purpose because it'll be driven by ACPI. If the
-i2c_ec driver works for you, just forget about the i2c-i801 driver and
-don't try to unhide the ICH SMBus. Even if i2c_ec doesn't work, you
+i2c-scmi driver works for you, just forget about the i2c-i801 driver and
+don't try to unhide the ICH SMBus. Even if i2c-scmi doesn't work, you
better make sure that the SMBus isn't used by the ACPI code. Try loading
-the "fan" and "thermal" drivers, and check in /proc/acpi/fan and
-/proc/acpi/thermal_zone. If you find anything there, it's likely that
-the ACPI is accessing the SMBus and it's safer not to unhide it. Only
-once you are certain that ACPI isn't using the SMBus, you can attempt
-to unhide it.
+the "fan" and "thermal" drivers, and check in /sys/class/thermal. If you
+find a thermal zone with type "acpitz", it's likely that the ACPI is
+accessing the SMBus and it's safer not to unhide it. Only once you are
+certain that ACPI isn't using the SMBus, you can attempt to unhide it.
In order to unhide the SMBus, we need to change the value of a PCI
register before the kernel enumerates the PCI devices. This is done in
diff --git a/MAINTAINERS b/MAINTAINERS
index 91eed595dc9a..4aee3a1de331 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10123,6 +10123,13 @@ L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/mediatek/mt7601u/
+MEDIATEK MT7621/28/88 I2C DRIVER
+M: Stefan Roese <sr@denx.de>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: drivers/i2c/busses/i2c-mt7621.c
+F: Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
+
MEDIATEK NAND CONTROLLER DRIVER
M: Xiaolei Li <xiaolei.li@mediatek.com>
L: linux-mtd@lists.infradead.org
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index 64714c869f9f..3cb6f22f510b 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -302,6 +302,8 @@ extern struct platform_device iop3xx_dma_1_channel;
extern struct platform_device iop3xx_aau_channel;
extern struct platform_device iop3xx_i2c0_device;
extern struct platform_device iop3xx_i2c1_device;
+extern struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup;
+extern struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup;
#endif
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
index 493de4fd8b2e..61a1e593f9ec 100644
--- a/arch/arm/mach-iop32x/em7210.c
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -207,6 +208,8 @@ static void __init em7210_init_machine(void)
{
register_iop32x_gpio();
platform_device_register(&em7210_serial_device);
+ gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
+ gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&em7210_flash_device);
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index 84cdb4587b34..5a45d616d9ac 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -21,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
@@ -185,6 +186,8 @@ static void glantank_power_off(void)
static void __init glantank_init_machine(void)
{
register_iop32x_gpio();
+ gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
+ gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&glantank_flash_device);
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index b177e3900616..8755aa87e591 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -22,6 +22,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -281,6 +282,8 @@ void ep80219_power_off(void)
static void __init iq31244_init_machine(void)
{
register_iop32x_gpio();
+ gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
+ gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq31244_flash_device);
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index 815b9f070007..e12699d1c540 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -19,6 +19,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
@@ -168,6 +169,8 @@ static struct platform_device iq80321_serial_device = {
static void __init iq80321_init_machine(void)
{
register_iop32x_gpio();
+ gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
+ gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq80321_flash_device);
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index 1948180594f4..26d76b377e79 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -27,6 +27,7 @@
#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
@@ -341,6 +342,7 @@ device_initcall(n2100_request_gpios);
static void __init n2100_init_machine(void)
{
register_iop32x_gpio();
+ gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&n2100_flash_device);
platform_device_register(&n2100_serial_device);
diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c
index 7a79213db3e1..dfbd7c332866 100644
--- a/arch/arm/plat-iop/i2c.c
+++ b/arch/arm/plat-iop/i2c.c
@@ -16,6 +16,7 @@
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/io.h>
+#include <linux/gpio/machine.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
@@ -34,6 +35,29 @@
#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
#endif
+/*
+ * Each of the I2C busses have corresponding GPIO lines, and the driver
+ * need to access these directly to drive the bus low at times.
+ */
+
+struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup = {
+ .dev_id = "IOP3xx-I2C.0",
+ .table = {
+ GPIO_LOOKUP("gpio-iop", 7, "scl", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-iop", 6, "sda", GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup = {
+ .dev_id = "IOP3xx-I2C.1",
+ .table = {
+ GPIO_LOOKUP("gpio-iop", 5, "scl", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-iop", 4, "sda", GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
static struct resource iop3xx_i2c0_resources[] = {
[0] = {
.start = 0xfffff680,
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index e355c5961eb9..7390b5ca09e3 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -36,6 +36,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
gc->base = 0;
gc->owner = THIS_MODULE;
+ gc->label = "gpio-iop";
return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ee5dfb5aee2a..09367fc014c3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -143,6 +143,8 @@ config I2C_I801
Cedar Fork (PCH)
Ice Lake (PCH)
Comet Lake (PCH)
+ Elkhart Lake (PCH)
+ Tiger Lake (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -436,7 +438,7 @@ config I2C_AXXIA
config I2C_BCM2835
tristate "Broadcom BCM2835 I2C controller"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || ARCH_BRCMSTB
help
If you say yes to this option, support will be included for the
BCM2835 I2C controller.
@@ -692,7 +694,7 @@ config I2C_IOP3XX
config I2C_JZ4780
tristate "JZ4780 I2C controller interface support"
- depends on MACH_JZ4780 || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
help
If you say yes to this option, support will be included for the
Ingenic JZ4780 I2C controller.
@@ -746,6 +748,13 @@ config I2C_MT65XX
If you want to use MediaTek(R) I2C interface, say Y or M here.
If unsure, say N.
+config I2C_MT7621
+ tristate "MT7621/MT7628 I2C Controller"
+ depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || COMPILE_TEST
+ help
+ Say Y here to include support for I2C controller in the
+ MediaTek MT7621/MT7628 SoCs.
+
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a3245231b0b7..80c23895eaaf 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o
+obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index a845b8decac8..2c7f145a036e 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -165,12 +165,6 @@ enum i2c_slave_read_status {
I2C_SLAVE_RX_END,
};
-enum i2c_slave_xfer_dir {
- I2C_SLAVE_DIR_READ = 0,
- I2C_SLAVE_DIR_WRITE,
- I2C_SLAVE_DIR_NONE,
-};
-
enum bus_speed_index {
I2C_SPD_100K = 0,
I2C_SPD_400K,
@@ -203,7 +197,6 @@ struct bcm_iproc_i2c_dev {
struct i2c_msg *msg;
struct i2c_client *slave;
- enum i2c_slave_xfer_dir xfer_dir;
/* bytes that have been transferred */
unsigned int tx_bytes;
@@ -219,7 +212,8 @@ struct bcm_iproc_i2c_dev {
| BIT(IS_M_RX_THLD_SHIFT))
#define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
- | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT))
+ | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
+ | BIT(IS_S_TX_UNDERRUN_SHIFT))
static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave);
static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave);
@@ -297,15 +291,11 @@ static void bcm_iproc_i2c_slave_init(
/* clear all pending slave interrupts */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
- /* Enable interrupt register for any READ event */
- val = BIT(IE_S_RD_EVENT_SHIFT);
/* Enable interrupt register to indicate a valid byte in receive fifo */
- val |= BIT(IE_S_RX_EVENT_SHIFT);
+ val = BIT(IE_S_RX_EVENT_SHIFT);
/* Enable interrupt register for the Slave BUSY command */
val |= BIT(IE_S_START_BUSY_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
-
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
}
static void bcm_iproc_i2c_check_slave_status(
@@ -314,8 +304,11 @@ static void bcm_iproc_i2c_check_slave_status(
u32 val;
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
- val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
+ /* status is valid only when START_BUSY is cleared after it was set */
+ if (val & BIT(S_CMD_START_BUSY_SHIFT))
+ return;
+ val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
if (val == S_CMD_STATUS_TIMEOUT) {
dev_err(iproc_i2c->device, "slave random stretch time timeout\n");
@@ -327,70 +320,66 @@ static void bcm_iproc_i2c_check_slave_status(
}
static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
- u32 status)
+ u32 status)
{
- u8 value;
u32 val;
- u32 rd_status;
- u32 tmp;
+ u8 value, rx_status;
- /* Start of transaction. check address and populate the direction */
- if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_NONE) {
- tmp = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
- rd_status = (tmp >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
- /* This condition checks whether the request is a new request */
- if (((rd_status == I2C_SLAVE_RX_START) &&
- (status & BIT(IS_S_RX_EVENT_SHIFT))) ||
- ((rd_status == I2C_SLAVE_RX_END) &&
- (status & BIT(IS_S_RD_EVENT_SHIFT)))) {
-
- /* Last bit is W/R bit.
- * If 1 then its a read request(by master).
- */
- iproc_i2c->xfer_dir = tmp & SLAVE_READ_WRITE_BIT_MASK;
- if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE)
- i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_READ_REQUESTED, &value);
- else
- i2c_slave_event(iproc_i2c->slave,
+ /* Slave RX byte receive */
+ if (status & BIT(IS_S_RX_EVENT_SHIFT)) {
+ val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
+ rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
+ if (rx_status == I2C_SLAVE_RX_START) {
+ /* Start of SMBUS for Master write */
+ i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_REQUESTED, &value);
- }
- }
- /* read request from master */
- if ((status & BIT(IS_S_RD_EVENT_SHIFT)) &&
- (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE)) {
- i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_READ_PROCESSED, &value);
- iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+ val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
+ value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ } else if (status & BIT(IS_S_RD_EVENT_SHIFT)) {
+ /* Start of SMBUS for Master Read */
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_READ_REQUESTED, &value);
+ iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
- val = BIT(S_CMD_START_BUSY_SHIFT);
- iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
- }
+ val = BIT(S_CMD_START_BUSY_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
- /* write request from master */
- if ((status & BIT(IS_S_RX_EVENT_SHIFT)) &&
- (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_READ)) {
- val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
- /* Its a write request by Master to Slave.
- * We read data present in receive FIFO
- */
- value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ /*
+ * Enable interrupt for TX FIFO becomes empty and
+ * less than PKT_LENGTH bytes were output on the SMBUS
+ */
+ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
+ val |= BIT(IE_S_TX_UNDERRUN_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
+ } else {
+ /* Master write other than start */
+ value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
+ /* Master read other than start */
i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_WRITE_RECEIVED, &value);
-
- /* check the status for the last byte of the transaction */
- rd_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
- if (rd_status == I2C_SLAVE_RX_END)
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
+ I2C_SLAVE_READ_PROCESSED, &value);
- dev_dbg(iproc_i2c->device, "\nread value = 0x%x\n", value);
+ iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+ val = BIT(S_CMD_START_BUSY_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
}
/* Stop */
if (status & BIT(IS_S_START_BUSY_SHIFT)) {
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
+ /*
+ * Enable interrupt for TX FIFO becomes empty and
+ * less than PKT_LENGTH bytes were output on the SMBUS
+ */
+ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
+ val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
}
/* clear interrupt status */
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index d2fbb4bb4a43..67752f7b0371 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -4,6 +4,8 @@
*/
#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/i2c.h>
@@ -51,9 +53,7 @@
struct bcm2835_i2c_dev {
struct device *dev;
void __iomem *regs;
- struct clk *clk;
int irq;
- u32 bus_clk_rate;
struct i2c_adapter adapter;
struct completion completion;
struct i2c_msg *curr_msg;
@@ -74,12 +74,17 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
return readl(i2c_dev->regs + reg);
}
-static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
+#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
+struct clk_bcm2835_i2c {
+ struct clk_hw hw;
+ struct bcm2835_i2c_dev *i2c_dev;
+};
+
+static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
+ unsigned long parent_rate)
{
- u32 divider, redl, fedl;
+ u32 divider = DIV_ROUND_UP(parent_rate, rate);
- divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
- i2c_dev->bus_clk_rate);
/*
* Per the datasheet, the register is always interpreted as an even
* number, by rounding down. In other words, the LSB is ignored. So,
@@ -88,12 +93,23 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
if (divider & 1)
divider++;
if ((divider < BCM2835_I2C_CDIV_MIN) ||
- (divider > BCM2835_I2C_CDIV_MAX)) {
- dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
+ (divider > BCM2835_I2C_CDIV_MAX))
return -EINVAL;
- }
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
+ return divider;
+}
+
+static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 redl, fedl;
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
+
+ if (divider == -EINVAL)
+ return -EINVAL;
+
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
/*
* Number of core clocks to wait after falling edge before
@@ -108,12 +124,65 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
*/
redl = max(divider / 4, 1u);
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
(fedl << BCM2835_I2C_FEDL_SHIFT) |
(redl << BCM2835_I2C_REDL_SHIFT));
return 0;
}
+static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
+
+ return DIV_ROUND_UP(*parent_rate, divider);
+}
+
+static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
+
+ return DIV_ROUND_UP(parent_rate, divider);
+}
+
+static const struct clk_ops clk_bcm2835_i2c_ops = {
+ .set_rate = clk_bcm2835_i2c_set_rate,
+ .round_rate = clk_bcm2835_i2c_round_rate,
+ .recalc_rate = clk_bcm2835_i2c_recalc_rate,
+};
+
+static struct clk *bcm2835_i2c_register_div(struct device *dev,
+ struct clk *mclk,
+ struct bcm2835_i2c_dev *i2c_dev)
+{
+ struct clk_init_data init;
+ struct clk_bcm2835_i2c *priv;
+ char name[32];
+ const char *mclk_name;
+
+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+
+ mclk_name = __clk_get_name(mclk);
+
+ init.ops = &clk_bcm2835_i2c_ops;
+ init.name = name;
+ init.parent_names = (const char* []) { mclk_name };
+ init.num_parents = 1;
+ init.flags = 0;
+
+ priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
+ if (priv == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ priv->hw.init = &init;
+ priv->i2c_dev = i2c_dev;
+
+ clk_hw_register_clkdev(&priv->hw, "div", dev_name(dev));
+ return devm_clk_register(dev, &priv->hw);
+}
+
static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
{
u32 val;
@@ -271,7 +340,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
{
struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
unsigned long time_left;
- int i, ret;
+ int i;
for (i = 0; i < (num - 1); i++)
if (msgs[i].flags & I2C_M_RD) {
@@ -280,10 +349,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
return -EOPNOTSUPP;
}
- ret = bcm2835_i2c_set_divider(i2c_dev);
- if (ret)
- return ret;
-
i2c_dev->curr_msg = msgs;
i2c_dev->num_msgs = num;
reinit_completion(&i2c_dev->completion);
@@ -338,6 +403,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
struct resource *mem, *irq;
int ret;
struct i2c_adapter *adap;
+ struct clk *bus_clk;
+ struct clk *mclk;
+ u32 bus_clk_rate;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
@@ -351,19 +419,38 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c_dev->regs))
return PTR_ERR(i2c_dev->regs);
- i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2c_dev->clk)) {
- if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
+ mclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mclk)) {
+ if (PTR_ERR(mclk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get clock\n");
- return PTR_ERR(i2c_dev->clk);
+ return PTR_ERR(mclk);
+ }
+
+ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
+
+ if (IS_ERR(bus_clk)) {
+ dev_err(&pdev->dev, "Could not register clock\n");
+ return PTR_ERR(bus_clk);
}
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
- &i2c_dev->bus_clk_rate);
+ &bus_clk_rate);
if (ret < 0) {
dev_warn(&pdev->dev,
"Could not read clock-frequency property\n");
- i2c_dev->bus_clk_rate = 100000;
+ bus_clk_rate = 100000;
+ }
+
+ ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not set clock frequency\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't prepare clock");
+ return ret;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -402,6 +489,10 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
static int bcm2835_i2c_remove(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
+
+ clk_rate_exclusive_put(bus_clk);
+ clk_disable_unprepare(bus_clk);
free_irq(i2c_dev->irq, i2c_dev);
i2c_del_adapter(&i2c_dev->adapter);
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 187900594e3d..1213e1932ccb 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -531,7 +531,9 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm)
}
out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
- cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+ cpm->txbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
+ CPM_MAX_READ + 1,
+ &cpm->txdma[i], GFP_KERNEL);
if (!cpm->txbuf[i]) {
ret = -ENOMEM;
goto out_muram;
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 1e2be2219a60..da5eb3960def 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -658,13 +658,29 @@ static const struct i2c_algorithm fsi_i2c_algorithm = {
.functionality = fsi_i2c_functionality,
};
+static struct device_node *fsi_i2c_find_port_of_node(struct device_node *fsi,
+ int port)
+{
+ struct device_node *np;
+ u32 port_no;
+ int rc;
+
+ for_each_child_of_node(fsi, np) {
+ rc = of_property_read_u32(np, "reg", &port_no);
+ if (!rc && port_no == port)
+ return np;
+ }
+
+ return NULL;
+}
+
static int fsi_i2c_probe(struct device *dev)
{
struct fsi_i2c_master *i2c;
struct fsi_i2c_port *port;
struct device_node *np;
+ u32 port_no, ports, stat;
int rc;
- u32 port_no;
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
@@ -678,10 +694,16 @@ static int fsi_i2c_probe(struct device *dev)
if (rc)
return rc;
- /* Add adapter for each i2c port of the master. */
- for_each_available_child_of_node(dev->of_node, np) {
- rc = of_property_read_u32(np, "reg", &port_no);
- if (rc || port_no > USHRT_MAX)
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
+ if (rc)
+ return rc;
+
+ ports = FIELD_GET(I2C_STAT_MAX_PORT, stat) + 1;
+ dev_dbg(dev, "I2C master has %d ports\n", ports);
+
+ for (port_no = 0; port_no < ports; port_no++) {
+ np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
+ if (np && !of_device_is_available(np))
continue;
port = kzalloc(sizeof(*port), GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ac7f7817dc89..f2956936c3f2 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -64,12 +64,14 @@
* Cedar Fork (PCH) 0x18df 32 hard yes yes yes
* Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes
* Comet Lake (PCH) 0x02a3 32 hard yes yes yes
+ * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
+ * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
* Hardware PEC yes
* Block buffer yes
- * Block process call transaction no
+ * Block process call transaction yes
* I2C block read transaction yes (doesn't use the block buffer)
* Slave mode no
* SMBus Host Notify yes
@@ -92,6 +94,7 @@
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -99,7 +102,7 @@
#include <linux/pm_runtime.h>
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/platform_data/i2c-mux-gpio.h>
#endif
@@ -169,6 +172,7 @@
#define I801_PROC_CALL 0x10 /* unimplemented */
#define I801_BLOCK_DATA 0x14
#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+#define I801_BLOCK_PROC_CALL 0x1C
/* I801 Host Control register bits */
#define SMBHSTCNT_INTREN BIT(0)
@@ -200,6 +204,7 @@
STATUS_ERROR_FLAGS)
/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
@@ -217,6 +222,7 @@
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
@@ -228,12 +234,12 @@
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3
+#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
-#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
struct i801_mux_config {
char *gpio_chip;
@@ -266,6 +272,7 @@ struct i801_priv {
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev;
+ struct gpiod_lookup_table *lookup;
#endif
struct platform_device *tco_pdev;
@@ -509,10 +516,23 @@ static int i801_transaction(struct i801_priv *priv, int xact)
static int i801_block_transaction_by_block(struct i801_priv *priv,
union i2c_smbus_data *data,
- char read_write, int hwpec)
+ char read_write, int command,
+ int hwpec)
{
int i, len;
int status;
+ int xact = hwpec ? SMBHSTCNT_PEC_EN : 0;
+
+ switch (command) {
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ xact |= I801_BLOCK_PROC_CALL;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ xact |= I801_BLOCK_DATA;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
@@ -524,12 +544,12 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
outb_p(data->block[i+1], SMBBLKDAT(priv));
}
- status = i801_transaction(priv, I801_BLOCK_DATA |
- (hwpec ? SMBHSTCNT_PEC_EN : 0));
+ status = i801_transaction(priv, xact);
if (status)
return status;
- if (read_write == I2C_SMBUS_READ) {
+ if (read_write == I2C_SMBUS_READ ||
+ command == I2C_SMBUS_BLOCK_PROC_CALL) {
len = inb_p(SMBHSTDAT0(priv));
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
@@ -667,6 +687,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int result;
const struct i2c_adapter *adap = &priv->adapter;
+ if (command == I2C_SMBUS_BLOCK_PROC_CALL)
+ return -EOPNOTSUPP;
+
result = i801_check_pre(priv);
if (result < 0)
return result;
@@ -798,7 +821,8 @@ static int i801_block_transaction(struct i801_priv *priv,
&& command != I2C_SMBUS_I2C_BLOCK_DATA
&& i801_set_block_buffer_mode(priv) == 0)
result = i801_block_transaction_by_block(priv, data,
- read_write, hwpec);
+ read_write,
+ command, hwpec);
else
result = i801_block_transaction_byte_by_byte(priv, data,
read_write,
@@ -890,6 +914,15 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
outb_p(command, SMBHSTCMD(priv));
block = 1;
break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ /*
+ * Bit 0 of the slave address register always indicate a write
+ * command.
+ */
+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
default:
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
size);
@@ -950,6 +983,8 @@ static u32 i801_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ ((priv->features & FEATURE_BLOCK_PROC) ?
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) |
((priv->features & FEATURE_I2C_BLOCK_READ) ?
I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) |
((priv->features & FEATURE_HOST_NOTIFY) ?
@@ -1033,6 +1068,8 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
{ 0, }
};
@@ -1134,6 +1171,118 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
}
}
+/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */
+static const char *const acpi_smo8800_ids[] = {
+ "SMO8800",
+ "SMO8801",
+ "SMO8810",
+ "SMO8811",
+ "SMO8820",
+ "SMO8821",
+ "SMO8830",
+ "SMO8831",
+};
+
+static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_device_info *info;
+ acpi_status status;
+ char *hid;
+ int i;
+
+ status = acpi_get_object_info(obj_handle, &info);
+ if (!ACPI_SUCCESS(status) || !(info->valid & ACPI_VALID_HID))
+ return AE_OK;
+
+ hid = info->hardware_id.string;
+ if (!hid)
+ return AE_OK;
+
+ i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid);
+ if (i < 0)
+ return AE_OK;
+
+ *((bool *)return_value) = true;
+ return AE_CTRL_TERMINATE;
+}
+
+static bool is_dell_system_with_lis3lv02d(void)
+{
+ bool found;
+ const char *vendor;
+
+ vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+ if (!vendor || strcmp(vendor, "Dell Inc."))
+ return false;
+
+ /*
+ * Check that ACPI device SMO88xx is present and is functioning.
+ * Function acpi_get_devices() already filters all ACPI devices
+ * which are not present or are not functioning.
+ * ACPI device SMO88xx represents our ST microelectronics lis3lv02d
+ * accelerometer but unfortunately ACPI does not provide any other
+ * information (like I2C address).
+ */
+ found = false;
+ acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL,
+ (void **)&found);
+
+ return found;
+}
+
+/*
+ * Accelerometer's I2C address is not specified in DMI nor ACPI,
+ * so it is needed to define mapping table based on DMI product names.
+ */
+static const struct {
+ const char *dmi_product_name;
+ unsigned short i2c_addr;
+} dell_lis3lv02d_devices[] = {
+ /*
+ * Dell platform team told us that these Latitude devices have
+ * ST microelectronics accelerometer at I2C address 0x29.
+ */
+ { "Latitude E5250", 0x29 },
+ { "Latitude E5450", 0x29 },
+ { "Latitude E5550", 0x29 },
+ { "Latitude E6440", 0x29 },
+ { "Latitude E6440 ATG", 0x29 },
+ { "Latitude E6540", 0x29 },
+ /*
+ * Additional individual entries were added after verification.
+ */
+ { "Vostro V131", 0x1d },
+};
+
+static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
+{
+ struct i2c_board_info info;
+ const char *dmi_product_name;
+ int i;
+
+ dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
+ for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
+ if (strcmp(dmi_product_name,
+ dell_lis3lv02d_devices[i].dmi_product_name) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) {
+ dev_warn(&priv->pci_dev->dev,
+ "Accelerometer lis3lv02d is present on SMBus but its"
+ " address is unknown, skipping registration\n");
+ return;
+ }
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = dell_lis3lv02d_devices[i].i2c_addr;
+ strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
+ i2c_new_device(&priv->adapter, &info);
+}
+
/* Register optional slaves */
static void i801_probe_optional_slaves(struct i801_priv *priv)
{
@@ -1152,6 +1301,9 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
if (dmi_name_in_vendors("FUJITSU"))
dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+
+ if (is_dell_system_with_lis3lv02d())
+ register_dell_lis3lv02d_i2c_device(priv);
}
#else
static void __init input_apanel_init(void) {}
@@ -1250,7 +1402,8 @@ static int i801_add_mux(struct i801_priv *priv)
struct device *dev = &priv->adapter.dev;
const struct i801_mux_config *mux_config;
struct i2c_mux_gpio_platform_data gpio_data;
- int err;
+ struct gpiod_lookup_table *lookup;
+ int err, i;
if (!priv->mux_drvdata)
return 0;
@@ -1262,17 +1415,36 @@ static int i801_add_mux(struct i801_priv *priv)
gpio_data.values = mux_config->values;
gpio_data.n_values = mux_config->n_values;
gpio_data.classes = mux_config->classes;
- gpio_data.gpio_chip = mux_config->gpio_chip;
- gpio_data.gpios = mux_config->gpios;
- gpio_data.n_gpios = mux_config->n_gpios;
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
- /* Register the mux device */
+ /* Register GPIO descriptor lookup table */
+ lookup = devm_kzalloc(dev,
+ struct_size(lookup, table, mux_config->n_gpios),
+ GFP_KERNEL);
+ if (!lookup)
+ return -ENOMEM;
+ lookup->dev_id = "i2c-mux-gpio";
+ for (i = 0; i < mux_config->n_gpios; i++) {
+ lookup->table[i].chip_label = mux_config->gpio_chip;
+ lookup->table[i].chip_hwnum = mux_config->gpios[i];
+ lookup->table[i].con_id = "mux";
+ }
+ gpiod_add_lookup_table(lookup);
+ priv->lookup = lookup;
+
+ /*
+ * Register the mux device, we use PLATFORM_DEVID_NONE here
+ * because since we are referring to the GPIO chip by name we are
+ * anyways in deep trouble if there is more than one of these
+ * devices, and there should likely only be one platform controller
+ * hub.
+ */
priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
- PLATFORM_DEVID_AUTO, &gpio_data,
+ PLATFORM_DEVID_NONE, &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);
+ gpiod_remove_lookup_table(lookup);
priv->mux_pdev = NULL;
dev_err(dev, "Failed to register i2c-mux-gpio device\n");
return err;
@@ -1285,6 +1457,8 @@ static void i801_del_mux(struct i801_priv *priv)
{
if (priv->mux_pdev)
platform_device_unregister(priv->mux_pdev);
+ if (priv->lookup)
+ gpiod_remove_lookup_table(priv->lookup);
}
static unsigned int i801_get_adapter_class(struct i801_priv *priv)
@@ -1530,6 +1704,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
+ case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
+ case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
@@ -1549,6 +1726,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->features |= FEATURE_IDF;
/* fall through */
default:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
/* fall through */
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index fd70b110e8f4..b1b8b938d7f4 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1220,8 +1220,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int i2c_imx_runtime_suspend(struct device *dev)
+static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
@@ -1230,7 +1229,7 @@ static int i2c_imx_runtime_suspend(struct device *dev)
return 0;
}
-static int i2c_imx_runtime_resume(struct device *dev)
+static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
@@ -1246,17 +1245,13 @@ static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
};
-#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops)
-#else
-#define I2C_IMX_PM_OPS NULL
-#endif /* CONFIG_PM */
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
- .pm = I2C_IMX_PM_OPS,
+ .pm = &i2c_imx_pm_ops,
.of_match_table = i2c_imx_dt_ids,
},
.id_table = imx_i2c_devtype,
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 87ce788ab90c..38556381f4ca 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -35,7 +35,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include "i2c-iop3xx.h"
@@ -68,17 +68,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
/*
* Every time unit enable is asserted, GPOD needs to be cleared
- * on IOP3XX to avoid data corruption on the bus.
+ * on IOP3XX to avoid data corruption on the bus. We use the
+ * gpiod_set_raw_value() to make sure the 0 hits the hardware
+ * GPOD register. These descriptors are only passed along to
+ * the device if this is necessary.
*/
-#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
- if (iop3xx_adap->id == 0) {
- gpio_set_value(7, 0);
- gpio_set_value(6, 0);
- } else {
- gpio_set_value(5, 0);
- gpio_set_value(4, 0);
- }
-#endif
+ if (iop3xx_adap->gpio_scl)
+ gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0);
+ if (iop3xx_adap->gpio_sda)
+ gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0);
+
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
@@ -431,6 +430,17 @@ iop3xx_i2c_probe(struct platform_device *pdev)
goto free_adapter;
}
+ adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev,
+ "scl",
+ GPIOD_ASIS);
+ if (IS_ERR(adapter_data->gpio_scl))
+ return PTR_ERR(adapter_data->gpio_scl);
+ adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev,
+ "sda",
+ GPIOD_ASIS);
+ if (IS_ERR(adapter_data->gpio_sda))
+ return PTR_ERR(adapter_data->gpio_sda);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index 53ca1fc9b84c..143548335504 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -92,6 +92,8 @@ struct i2c_algo_iop3xx_data {
spinlock_t lock;
u32 SR_enabled, SR_received;
int id;
+ struct gpio_desc *gpio_scl;
+ struct gpio_desc *gpio_sda;
};
#endif /* I2C_IOP3XX_H */
diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c
new file mode 100644
index 000000000000..62df8379bc89
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mt7621.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/i2c/busses/i2c-mt7621.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
+ * Copyright (C) 2018 Jan Breuer <jan.breuer@jaybee.cz>
+ *
+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
+ * (C) 2014 Sittisak <sittisaks@hotmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#define REG_SM0CFG2_REG 0x28
+#define REG_SM0CTL0_REG 0x40
+#define REG_SM0CTL1_REG 0x44
+#define REG_SM0D0_REG 0x50
+#define REG_SM0D1_REG 0x54
+#define REG_PINTEN_REG 0x5c
+#define REG_PINTST_REG 0x60
+#define REG_PINTCL_REG 0x64
+
+/* REG_SM0CFG2_REG */
+#define SM0CFG2_IS_AUTOMODE BIT(0)
+
+/* REG_SM0CTL0_REG */
+#define SM0CTL0_ODRAIN BIT(31)
+#define SM0CTL0_CLK_DIV_MASK (0x7ff << 16)
+#define SM0CTL0_CLK_DIV_MAX 0x7ff
+#define SM0CTL0_CS_STATUS BIT(4)
+#define SM0CTL0_SCL_STATE BIT(3)
+#define SM0CTL0_SDA_STATE BIT(2)
+#define SM0CTL0_EN BIT(1)
+#define SM0CTL0_SCL_STRETCH BIT(0)
+
+/* REG_SM0CTL1_REG */
+#define SM0CTL1_ACK_MASK (0xff << 16)
+#define SM0CTL1_PGLEN_MASK (0x7 << 8)
+#define SM0CTL1_PGLEN(x) ((((x) - 1) << 8) & SM0CTL1_PGLEN_MASK)
+#define SM0CTL1_READ (5 << 4)
+#define SM0CTL1_READ_LAST (4 << 4)
+#define SM0CTL1_STOP (3 << 4)
+#define SM0CTL1_WRITE (2 << 4)
+#define SM0CTL1_START (1 << 4)
+#define SM0CTL1_MODE_MASK (0x7 << 4)
+#define SM0CTL1_TRI BIT(0)
+
+/* timeout waiting for I2C devices to respond */
+#define TIMEOUT_MS 1000
+
+struct mtk_i2c {
+ void __iomem *base;
+ struct device *dev;
+ struct i2c_adapter adap;
+ u32 bus_freq;
+ u32 clk_div;
+ u32 flags;
+ struct clk *clk;
+};
+
+static int mtk_i2c_wait_idle(struct mtk_i2c *i2c)
+{
+ int ret;
+ u32 val;
+
+ ret = readl_relaxed_poll_timeout(i2c->base + REG_SM0CTL1_REG,
+ val, !(val & SM0CTL1_TRI),
+ 10, TIMEOUT_MS * 1000);
+ if (ret)
+ dev_dbg(i2c->dev, "idle err(%d)\n", ret);
+
+ return ret;
+}
+
+static void mtk_i2c_reset(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = device_reset(i2c->adap.dev.parent);
+ if (ret)
+ dev_err(i2c->dev, "I2C reset failed!\n");
+
+ /*
+ * Don't set SM0CTL0_ODRAIN as its bit meaning is inverted. To
+ * configure open-drain mode, this bit needs to be cleared.
+ */
+ iowrite32(((i2c->clk_div << 16) & SM0CTL0_CLK_DIV_MASK) | SM0CTL0_EN |
+ SM0CTL0_SCL_STRETCH, i2c->base + REG_SM0CTL0_REG);
+ iowrite32(0, i2c->base + REG_SM0CFG2_REG);
+}
+
+static void mtk_i2c_dump_reg(struct mtk_i2c *i2c)
+{
+ dev_dbg(i2c->dev,
+ "SM0CFG2 %08x, SM0CTL0 %08x, SM0CTL1 %08x, SM0D0 %08x, SM0D1 %08x\n",
+ ioread32(i2c->base + REG_SM0CFG2_REG),
+ ioread32(i2c->base + REG_SM0CTL0_REG),
+ ioread32(i2c->base + REG_SM0CTL1_REG),
+ ioread32(i2c->base + REG_SM0D0_REG),
+ ioread32(i2c->base + REG_SM0D1_REG));
+}
+
+static int mtk_i2c_check_ack(struct mtk_i2c *i2c, u32 expected)
+{
+ u32 ack = readl_relaxed(i2c->base + REG_SM0CTL1_REG);
+ u32 ack_expected = (expected << 16) & SM0CTL1_ACK_MASK;
+
+ return ((ack & ack_expected) == ack_expected) ? 0 : -ENXIO;
+}
+
+static int mtk_i2c_master_start(struct mtk_i2c *i2c)
+{
+ iowrite32(SM0CTL1_START | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_stop(struct mtk_i2c *i2c)
+{
+ iowrite32(SM0CTL1_STOP | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_cmd(struct mtk_i2c *i2c, u32 cmd, int page_len)
+{
+ iowrite32(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(page_len),
+ i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct mtk_i2c *i2c;
+ struct i2c_msg *pmsg;
+ u16 addr;
+ int i, j, ret, len, page_len;
+ u32 cmd;
+ u32 data[2];
+
+ i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+
+ /* wait hardware idle */
+ ret = mtk_i2c_wait_idle(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* start sequence */
+ ret = mtk_i2c_master_start(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* write address */
+ if (pmsg->flags & I2C_M_TEN) {
+ /* 10 bits address */
+ addr = 0xf0 | ((pmsg->addr >> 7) & 0x06);
+ addr |= (pmsg->addr & 0xff) << 8;
+ if (pmsg->flags & I2C_M_RD)
+ addr |= 1;
+ iowrite32(addr, i2c->base + REG_SM0D0_REG);
+ ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 2);
+ if (ret)
+ goto err_timeout;
+ } else {
+ /* 7 bits address */
+ addr = i2c_8bit_addr_from_msg(pmsg);
+ iowrite32(addr, i2c->base + REG_SM0D0_REG);
+ ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 1);
+ if (ret)
+ goto err_timeout;
+ }
+
+ /* check address ACK */
+ if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
+ ret = mtk_i2c_check_ack(i2c, BIT(0));
+ if (ret)
+ goto err_ack;
+ }
+
+ /* transfer data */
+ for (len = pmsg->len, j = 0; len > 0; len -= 8, j += 8) {
+ page_len = (len >= 8) ? 8 : len;
+
+ if (pmsg->flags & I2C_M_RD) {
+ cmd = (len > 8) ?
+ SM0CTL1_READ : SM0CTL1_READ_LAST;
+ } else {
+ memcpy(data, &pmsg->buf[j], page_len);
+ iowrite32(data[0], i2c->base + REG_SM0D0_REG);
+ iowrite32(data[1], i2c->base + REG_SM0D1_REG);
+ cmd = SM0CTL1_WRITE;
+ }
+
+ ret = mtk_i2c_master_cmd(i2c, cmd, page_len);
+ if (ret)
+ goto err_timeout;
+
+ if (pmsg->flags & I2C_M_RD) {
+ data[0] = ioread32(i2c->base + REG_SM0D0_REG);
+ data[1] = ioread32(i2c->base + REG_SM0D1_REG);
+ memcpy(&pmsg->buf[j], data, page_len);
+ } else {
+ if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
+ ret = mtk_i2c_check_ack(i2c,
+ (1 << page_len)
+ - 1);
+ if (ret)
+ goto err_ack;
+ }
+ }
+ }
+ }
+
+ ret = mtk_i2c_master_stop(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* the return value is number of executed messages */
+ return i;
+
+err_ack:
+ ret = mtk_i2c_master_stop(i2c);
+ if (ret)
+ goto err_timeout;
+ return -ENXIO;
+
+err_timeout:
+ mtk_i2c_dump_reg(i2c);
+ mtk_i2c_reset(i2c);
+ return ret;
+}
+
+static u32 mtk_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm mtk_i2c_algo = {
+ .master_xfer = mtk_i2c_master_xfer,
+ .functionality = mtk_i2c_func,
+};
+
+static const struct of_device_id i2c_mtk_dt_ids[] = {
+ { .compatible = "mediatek,mt7621-i2c" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids);
+
+static void mtk_i2c_init(struct mtk_i2c *i2c)
+{
+ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->bus_freq - 1;
+ if (i2c->clk_div < 99)
+ i2c->clk_div = 99;
+ if (i2c->clk_div > SM0CTL0_CLK_DIV_MAX)
+ i2c->clk_div = SM0CTL0_CLK_DIV_MAX;
+
+ mtk_i2c_reset(i2c);
+}
+
+static int mtk_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mtk_i2c *i2c;
+ struct i2c_adapter *adap;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ return PTR_ERR(i2c->clk);
+ }
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock\n");
+ return ret;
+ }
+
+ i2c->dev = &pdev->dev;
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->bus_freq))
+ i2c->bus_freq = 100000;
+
+ if (i2c->bus_freq == 0) {
+ dev_warn(i2c->dev, "clock-frequency 0 not supported\n");
+ return -EINVAL;
+ }
+
+ adap = &i2c->adap;
+ adap->owner = THIS_MODULE;
+ adap->algo = &mtk_i2c_algo;
+ adap->retries = 3;
+ adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(adap, i2c);
+ adap->dev.of_node = pdev->dev.of_node;
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+
+ platform_set_drvdata(pdev, i2c);
+
+ mtk_i2c_init(i2c);
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0)
+ return ret;
+
+ dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000);
+
+ return ret;
+}
+
+static int mtk_i2c_remove(struct platform_device *pdev)
+{
+ struct mtk_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+static struct platform_driver mtk_i2c_driver = {
+ .probe = mtk_i2c_probe,
+ .remove = mtk_i2c_remove,
+ .driver = {
+ .name = "i2c-mt7621",
+ .of_match_table = i2c_mtk_dt_ids,
+ },
+};
+
+module_platform_driver(mtk_i2c_driver);
+
+MODULE_AUTHOR("Steven Liu");
+MODULE_DESCRIPTION("MT7621 I2C host driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:MT7621-I2C");
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..cfc76b5de726 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+ struct i2c_client *ccgx_client;
};
static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -169,12 +170,14 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
{
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+ bool send_stop = true;
int i, j;
/*
* The controller supports maximum 4 byte read due to known
* limitation of sending STOP after every read.
*/
+ pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -182,37 +185,42 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
- goto stop;
+ goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
- return status;
- goto stop;
+ send_stop = false;
+ goto exit;
}
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
- goto stop;
+ goto exit;
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
- goto stop;
+ goto exit;
}
}
}
+ send_stop = false;
status = gpu_i2c_stop(i2cd);
if (status < 0)
- return status;
-
- return i;
-stop:
- status2 = gpu_i2c_stop(i2cd);
- if (status2 < 0)
- dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+ goto exit;
+
+ status = i;
+exit:
+ if (send_stop) {
+ status2 = gpu_i2c_stop(i2cd);
+ if (status2 < 0)
+ dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+ }
+ pm_runtime_mark_last_busy(i2cd->dev);
+ pm_runtime_put_autosuspend(i2cd->dev);
return status;
}
@@ -261,8 +269,6 @@ static const struct property_entry ccgx_props[] = {
static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
{
- struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
sizeof(*i2cd->gpu_ccgx_ucsi),
GFP_KERNEL);
@@ -274,8 +280,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
- ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
- if (!ccgx_client)
+ i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+ if (!i2cd->ccgx_client)
return -ENODEV;
return 0;
@@ -332,6 +338,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto del_adapter;
}
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
return 0;
del_adapter:
@@ -345,19 +356,38 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
{
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
+ pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
}
+/*
+ * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
+ * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
+ * Documentation/power/pci.txt also insists for driver to provide this.
+ */
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+ return 0;
+}
+
static __maybe_unused int gpu_i2c_resume(struct device *dev)
{
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
gpu_enable_i2c_bus(i2cd);
+ /*
+ * Runtime resume ccgx client so that it can see for any
+ * connector change event. Old ccg firmware has known
+ * issue of not triggering interrupt when a device is
+ * connected to runtime resume the controller.
+ */
+ pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
}
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+ NULL);
static struct pci_driver gpu_i2c_driver = {
.name = "nvidia-gpu",
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee0aa35..4117f1abc7c6 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+ unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -82,6 +83,9 @@ struct ocores_i2c {
#define TYPE_OCORES 0
#define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0 2
+
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
{
@@ -235,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
- if (!(stat & OCI2C_STAT_IF))
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+ if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+ return IRQ_NONE;
+ } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+ }
ocores_process(i2c, stat);
return IRQ_HANDLED;
@@ -352,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+ else {
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+ if (i2c->state == STATE_DONE)
+ break;
+ }
}
}
@@ -462,6 +474,14 @@ static const struct of_device_id ocores_i2c_match[] = {
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+ {
+ .compatible = "sifive,fu540-c000-i2c",
+ .data = (void *)TYPE_SIFIVE_REV0,
+ },
+ {
+ .compatible = "sifive,i2c0",
+ .data = (void *)TYPE_SIFIVE_REV0,
+ },
{},
};
MODULE_DEVICE_TABLE(of, ocores_i2c_match);
@@ -586,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
{
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+ const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -668,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+ /*
+ * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+ * FU540-C000 SoC in polling mode.
+ */
+ match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+ if (match && (long)match->data == TYPE_SIFIVE_REV0)
+ i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index db075bc0d952..a89bfce5388e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
@@ -483,6 +484,14 @@ static const struct i2c_algorithm geni_i2c_algo = {
.functionality = geni_i2c_func,
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id geni_i2c_acpi_match[] = {
+ { "QCOM0220"},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
+#endif
+
static int geni_i2c_probe(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c;
@@ -502,7 +511,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
return PTR_ERR(gi2c->se.base);
gi2c->se.clk = devm_clk_get(&pdev->dev, "se");
- if (IS_ERR(gi2c->se.clk)) {
+ if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(&pdev->dev)) {
ret = PTR_ERR(gi2c->se.clk);
dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
return ret;
@@ -516,6 +525,9 @@ static int geni_i2c_probe(struct platform_device *pdev)
gi2c->clk_freq_out = KHZ(100);
}
+ if (has_acpi_companion(&pdev->dev))
+ ACPI_COMPANION_SET(&gi2c->adap.dev, ACPI_COMPANION(&pdev->dev));
+
gi2c->irq = platform_get_irq(pdev, 0);
if (gi2c->irq < 0) {
dev_err(&pdev->dev, "IRQ error for i2c-geni\n");
@@ -584,6 +596,8 @@ static int geni_i2c_probe(struct platform_device *pdev)
return ret;
}
+ dev_dbg(&pdev->dev, "Geni-I2C adaptor successfully added\n");
+
return 0;
}
@@ -660,6 +674,7 @@ static struct platform_driver geni_i2c_driver = {
.name = "geni_i2c",
.pm = &geni_i2c_pm_ops,
.of_match_table = geni_i2c_dt_match,
+ .acpi_match_table = ACPI_PTR(geni_i2c_acpi_match),
},
};
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index c9510d085c34..d97fb857b0ea 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -113,7 +113,7 @@ struct s3c24xx_i2c {
struct i2c_adapter adap;
struct s3c2410_platform_i2c *pdata;
- int gpios[2];
+ struct gpio_desc *gpios[2];
struct pinctrl *pctrl;
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
struct notifier_block freq_transition;
@@ -947,53 +947,27 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
#ifdef CONFIG_OF
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
- int idx, gpio, ret;
+ int i;
if (i2c->quirks & QUIRK_NO_GPIO)
return 0;
- for (idx = 0; idx < 2; idx++) {
- gpio = of_get_gpio(i2c->dev->of_node, idx);
- if (!gpio_is_valid(gpio)) {
- dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
- goto free_gpio;
- }
- i2c->gpios[idx] = gpio;
-
- ret = gpio_request(gpio, "i2c-bus");
- if (ret) {
- dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
- gpio, ret);
- goto free_gpio;
+ for (i = 0; i < 2; i++) {
+ i2c->gpios[i] = devm_gpiod_get_index(i2c->dev, NULL,
+ i, GPIOD_ASIS);
+ if (IS_ERR(i2c->gpios[i])) {
+ dev_err(i2c->dev, "i2c gpio invalid at index %d\n", i);
+ return -EINVAL;
}
}
return 0;
-
-free_gpio:
- while (--idx >= 0)
- gpio_free(i2c->gpios[idx]);
- return -EINVAL;
}
-static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
-{
- unsigned int idx;
-
- if (i2c->quirks & QUIRK_NO_GPIO)
- return;
-
- for (idx = 0; idx < 2; idx++)
- gpio_free(i2c->gpios[idx]);
-}
#else
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
return 0;
}
-
-static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
-{
-}
#endif
/*
@@ -1222,9 +1196,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap);
- if (pdev->dev.of_node && IS_ERR(i2c->pctrl))
- s3c24xx_i2c_dt_gpio_free(i2c);
-
return 0;
}
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 48337bef5b87..266d1c269b83 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
@@ -953,6 +952,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
f7_msg->read_write = I2C_SMBUS_READ;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* Rely on emulated i2c transfer (through master_xfer) */
+ return -EOPNOTSUPP;
default:
dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
return -EOPNOTSUPP;
@@ -1803,7 +1805,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
static struct i2c_algorithm stm32f7_i2c_algo = {
@@ -1816,15 +1819,14 @@ static struct i2c_algorithm stm32f7_i2c_algo = {
static int stm32f7_i2c_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct stm32f7_i2c_dev *i2c_dev;
const struct stm32f7_i2c_setup *setup;
struct resource *res;
- u32 irq_error, irq_event, clk_rate, rise_time, fall_time;
+ u32 clk_rate, rise_time, fall_time;
struct i2c_adapter *adap;
struct reset_control *rst;
dma_addr_t phy_addr;
- int ret;
+ int irq_error, irq_event, ret;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
@@ -1836,16 +1838,20 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
phy_addr = (dma_addr_t)res->start;
- irq_event = irq_of_parse_and_map(np, 0);
- if (!irq_event) {
- dev_err(&pdev->dev, "IRQ event missing or invalid\n");
- return -EINVAL;
+ irq_event = platform_get_irq(pdev, 0);
+ if (irq_event <= 0) {
+ if (irq_event != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ event: %d\n",
+ irq_event);
+ return irq_event ? : -ENOENT;
}
- irq_error = irq_of_parse_and_map(np, 1);
- if (!irq_error) {
- dev_err(&pdev->dev, "IRQ error missing or invalid\n");
- return -EINVAL;
+ irq_error = platform_get_irq(pdev, 1);
+ if (irq_error <= 0) {
+ if (irq_error != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ error: %d\n",
+ irq_error);
+ return irq_error ? : -ENOENT;
}
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index ebaa78d17d6e..9fcb13beeb8f 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -54,20 +54,15 @@
#define I2C_INT_STATUS 0x068
#define I2C_INT_BUS_CLR_DONE BIT(11)
#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
-#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6)
-#define I2C_INT_TX_FIFO_OVERFLOW BIT(5)
-#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4)
#define I2C_INT_NO_ACK BIT(3)
#define I2C_INT_ARBITRATION_LOST BIT(2)
#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
#define I2C_CLK_DIVISOR 0x06c
#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
-#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
#define DVC_CTRL_REG1 0x000
#define DVC_CTRL_REG1_INTR_EN BIT(10)
-#define DVC_CTRL_REG2 0x004
#define DVC_CTRL_REG3 0x008
#define DVC_CTRL_REG3_SW_PROG BIT(26)
#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30)
@@ -75,24 +70,22 @@
#define DVC_STATUS_I2C_DONE_INTR BIT(30)
#define I2C_ERR_NONE 0x00
-#define I2C_ERR_NO_ACK 0x01
-#define I2C_ERR_ARBITRATION_LOST 0x02
-#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
+#define I2C_ERR_NO_ACK BIT(0)
+#define I2C_ERR_ARBITRATION_LOST BIT(1)
+#define I2C_ERR_UNKNOWN_INTERRUPT BIT(2)
+#define I2C_ERR_RX_BUFFER_OVERFLOW BIT(3)
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
#define PACKET_HEADER0_PACKET_ID_SHIFT 16
#define PACKET_HEADER0_CONT_ID_SHIFT 12
#define PACKET_HEADER0_PROTOCOL_I2C BIT(4)
-#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
#define I2C_HEADER_CONT_ON_NAK BIT(21)
-#define I2C_HEADER_SEND_START_BYTE BIT(20)
#define I2C_HEADER_READ BIT(19)
#define I2C_HEADER_10BIT_ADDR BIT(18)
#define I2C_HEADER_IE_ENABLE BIT(17)
#define I2C_HEADER_REPEAT_START BIT(16)
#define I2C_HEADER_CONTINUE_XFER BIT(15)
-#define I2C_HEADER_MASTER_ADDR_SHIFT 12
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
#define I2C_BUS_CLEAR_CNFG 0x084
@@ -106,8 +99,6 @@
#define I2C_CONFIG_LOAD 0x08C
#define I2C_MSTR_CONFIG_LOAD BIT(0)
-#define I2C_SLV_CONFIG_LOAD BIT(1)
-#define I2C_TIMEOUT_CONFIG_LOAD BIT(2)
#define I2C_CLKEN_OVERRIDE 0x090
#define I2C_MST_CORE_CLKEN_OVR BIT(0)
@@ -133,7 +124,6 @@
#define I2C_STANDARD_MODE 100000
#define I2C_FAST_MODE 400000
#define I2C_FAST_PLUS_MODE 1000000
-#define I2C_HS_MODE 3500000
/* Packet header size in bytes */
#define I2C_PACKET_HEADER_SIZE 12
@@ -280,6 +270,7 @@ struct tegra_i2c_dev {
u32 bus_clk_rate;
u16 clk_divisor_non_hs_mode;
bool is_multimaster_mode;
+ /* xfer_lock: lock to serialize transfer submission and processing */
spinlock_t xfer_lock;
struct dma_chan *tx_dma_chan;
struct dma_chan *rx_dma_chan;
@@ -306,7 +297,7 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
* to the I2C block inside the DVC block
*/
static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
- unsigned long reg)
+ unsigned long reg)
{
if (i2c_dev->is_dvc)
reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
@@ -314,7 +305,7 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
}
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
- unsigned long reg)
+ unsigned long reg)
{
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
@@ -329,13 +320,13 @@ static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
}
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
- unsigned long reg, int len)
+ unsigned long reg, int len)
{
writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
}
static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
- unsigned long reg, int len)
+ unsigned long reg, int len)
{
readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
}
@@ -486,7 +477,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
return -ETIMEDOUT;
}
- msleep(1);
+ usleep_range(1000, 2000);
}
return 0;
}
@@ -499,6 +490,13 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
size_t buf_remaining = i2c_dev->msg_buf_remaining;
int words_to_transfer;
+ /*
+ * Catch overflow due to message fully sent
+ * before the check for RX FIFO availability.
+ */
+ if (WARN_ON_ONCE(!(i2c_dev->msg_buf_remaining)))
+ return -EINVAL;
+
if (i2c_dev->hw->has_mst_fifo) {
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
@@ -525,7 +523,11 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
* prevent overwriting past the end of buf
*/
if (rx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ /*
+ * buf_remaining > 3 check not needed as rx_fifo_avail == 0
+ * when (words_to_transfer was > rx_fifo_avail) earlier
+ * in this function.
+ */
val = i2c_readl(i2c_dev, I2C_RX_FIFO);
val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining);
@@ -533,7 +535,10 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
rx_fifo_avail--;
}
- BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+ /* RX FIFO must be drained, otherwise it's an Overflow case. */
+ if (WARN_ON_ONCE(rx_fifo_avail))
+ return -EINVAL;
+
i2c_dev->msg_buf_remaining = buf_remaining;
i2c_dev->msg_buf = buf;
@@ -591,7 +596,11 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
* boundary and fault.
*/
if (tx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ /*
+ * buf_remaining > 3 check not needed as tx_fifo_avail == 0
+ * when (words_to_transfer was > tx_fifo_avail) earlier
+ * in this function for non-zero words_to_transfer.
+ */
memcpy(&val, buf, buf_remaining);
val = le32_to_cpu(val);
@@ -680,10 +689,11 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
if (in_interrupt())
err = readl_poll_timeout_atomic(addr, val, val == 0,
- 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ 1000,
+ I2C_CONFIG_LOAD_TIMEOUT);
else
- err = readl_poll_timeout(addr, val, val == 0,
- 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ err = readl_poll_timeout(addr, val, val == 0, 1000,
+ I2C_CONFIG_LOAD_TIMEOUT);
if (err) {
dev_warn(i2c_dev->dev,
@@ -700,7 +710,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
u32 val;
int err;
u32 clk_divisor, clk_multiplier;
- u32 tsu_thd = 0;
+ u32 tsu_thd;
u8 tlow, thigh;
err = pm_runtime_get_sync(i2c_dev->dev);
@@ -856,10 +866,15 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (!i2c_dev->is_curr_dma_xfer) {
if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
- if (i2c_dev->msg_buf_remaining)
- tegra_i2c_empty_rx_fifo(i2c_dev);
- else
- BUG();
+ if (tegra_i2c_empty_rx_fifo(i2c_dev)) {
+ /*
+ * Overflow error condition: message fully sent,
+ * with no XFER_COMPLETE interrupt but hardware
+ * asks to transfer more.
+ */
+ i2c_dev->msg_err |= I2C_ERR_RX_BUFFER_OVERFLOW;
+ goto err;
+ }
}
if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
@@ -885,7 +900,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (status & I2C_INT_PACKET_XFER_COMPLETE) {
if (i2c_dev->is_curr_dma_xfer)
i2c_dev->msg_buf_remaining = 0;
- BUG_ON(i2c_dev->msg_buf_remaining);
+ /*
+ * Underflow error condition: XFER_COMPLETE before message
+ * fully sent.
+ */
+ if (WARN_ON_ONCE(i2c_dev->msg_buf_remaining)) {
+ i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+ goto err;
+ }
complete(&i2c_dev->msg_complete);
}
goto done;
@@ -1024,7 +1046,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
}
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
- struct i2c_msg *msg, enum msg_end_type end_state)
+ struct i2c_msg *msg,
+ enum msg_end_type end_state)
{
u32 packet_header;
u32 int_mask;
@@ -1161,9 +1184,8 @@ unlock:
if (err)
return err;
- time_left = wait_for_completion_timeout(
- &i2c_dev->dma_complete,
- msecs_to_jiffies(xfer_time));
+ time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
+ msecs_to_jiffies(xfer_time));
if (time_left == 0) {
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(i2c_dev->msg_read ?
@@ -1225,11 +1247,11 @@ unlock:
}
static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
- int num)
+ int num)
{
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
int i;
- int ret = 0;
+ int ret;
ret = pm_runtime_get_sync(i2c_dev->dev);
if (ret < 0) {
@@ -1271,14 +1293,15 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
{
struct device_node *np = i2c_dev->dev->of_node;
int ret;
+ bool multi_mode;
ret = of_property_read_u32(np, "clock-frequency",
- &i2c_dev->bus_clk_rate);
+ &i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
- i2c_dev->is_multimaster_mode = of_property_read_bool(np,
- "multi-master");
+ multi_mode = of_property_read_bool(np, "multi-master");
+ i2c_dev->is_multimaster_mode = multi_mode;
}
static const struct i2c_algorithm tegra_i2c_algo = {
@@ -1500,7 +1523,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
void __iomem *base;
phys_addr_t base_phys;
int irq;
- int ret = 0;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base_phys = res->start;
@@ -1517,7 +1540,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
div_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(div_clk)) {
- dev_err(&pdev->dev, "missing controller clock\n");
+ if (PTR_ERR(div_clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "missing controller clock\n");
+
return PTR_ERR(div_clk);
}
@@ -1622,7 +1647,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
- tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
+ tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
goto release_dma;
@@ -1687,10 +1712,35 @@ static int tegra_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static int tegra_i2c_suspend(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static int tegra_i2c_resume(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int err;
+
+ err = tegra_i2c_init(i2c_dev, false);
+ if (err)
+ return err;
+
+ i2c_mark_adapter_resumed(&i2c_dev->adapter);
+
+ return 0;
+}
+
static const struct dev_pm_ops tegra_i2c_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
NULL)
};
+
#define TEGRA_I2C_PM (&tegra_i2c_pm)
#else
#define TEGRA_I2C_PM NULL
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 428a82c3a35f..4dbbc9a35f65 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -132,13 +132,52 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
return 0;
}
+static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data)
+{
+ int *irq = data;
+ struct resource r;
+
+ if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
+ *irq = i2c_dev_irq_from_resources(&r, 1);
+
+ return 1; /* No need to add resource to the list */
+}
+
+/**
+ * i2c_acpi_get_irq - get device IRQ number from ACPI
+ * @client: Pointer to the I2C client device
+ *
+ * Find the IRQ number used by a specific client device.
+ *
+ * Return: The IRQ number or an error code.
+ */
+int i2c_acpi_get_irq(struct i2c_client *client)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct list_head resource_list;
+ int irq = -ENOENT;
+ int ret;
+
+ INIT_LIST_HEAD(&resource_list);
+
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ i2c_acpi_add_resource, &irq);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (irq == -ENOENT)
+ irq = acpi_dev_gpio_irq_get(adev, 0);
+
+ return irq;
+}
+
static int i2c_acpi_get_info(struct acpi_device *adev,
struct i2c_board_info *info,
struct i2c_adapter *adapter,
acpi_handle *adapter_handle)
{
- struct list_head resource_list;
- struct resource_entry *entry;
struct i2c_acpi_lookup lookup;
int ret;
@@ -172,21 +211,6 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
if (adapter_handle)
*adapter_handle = lookup.adapter_handle;
- /* Then fill IRQ number if any */
- INIT_LIST_HEAD(&resource_list);
- ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
- if (ret < 0)
- return -EINVAL;
-
- resource_list_for_each_entry(entry, &resource_list) {
- if (resource_type(entry->res) == IORESOURCE_IRQ) {
- info->irq = entry->res->start;
- break;
- }
- }
-
- acpi_dev_free_resource_list(&resource_list);
-
acpi_set_modalias(adev, dev_name(&adev->dev), info->type,
sizeof(info->type));
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 9e43508d4567..f26ed495d384 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -314,6 +314,8 @@ static int i2c_device_probe(struct device *dev)
driver = to_i2c_driver(dev->driver);
+ client->irq = client->init_irq;
+
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
int irq = -ENOENT;
@@ -327,7 +329,7 @@ static int i2c_device_probe(struct device *dev)
if (irq == -EINVAL || irq == -ENODATA)
irq = of_irq_get(dev->of_node, 0);
} else if (ACPI_COMPANION(dev)) {
- irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
+ irq = i2c_acpi_get_irq(client);
}
if (irq == -EPROBE_DEFER)
return irq;
@@ -424,7 +426,7 @@ static int i2c_device_remove(struct device *dev)
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
- client->irq = client->init_irq;
+ client->irq = 0;
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
pm_runtime_put(&client->adapter->dev);
@@ -679,8 +681,8 @@ static void i2c_dev_set_name(struct i2c_adapter *adap,
i2c_encode_flags_to_addr(client));
}
-static int i2c_dev_irq_from_resources(const struct resource *resources,
- unsigned int num_resources)
+int i2c_dev_irq_from_resources(const struct resource *resources,
+ unsigned int num_resources)
{
struct irq_data *irqd;
int i;
@@ -721,7 +723,7 @@ static int i2c_dev_irq_from_resources(const struct resource *resources,
* This returns the new i2c client, which may be saved for later use with
* i2c_unregister_device(); or an ERR_PTR to describe the error.
*/
-static struct i2c_client *
+struct i2c_client *
i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
struct i2c_client *client;
@@ -741,7 +743,6 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
if (!client->init_irq)
client->init_irq = i2c_dev_irq_from_resources(info->resources,
info->num_resources);
- client->irq = client->init_irq;
strlcpy(client->name, info->type, sizeof(client->name));
@@ -887,8 +888,7 @@ static struct i2c_driver dummy_driver = {
* This returns the new i2c client, which should be saved for later use with
* i2c_unregister_device(); or an ERR_PTR to describe the error.
*/
-static struct i2c_client *
-i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address)
+struct i2c_client *i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address)
{
struct i2c_board_info info = {
I2C_BOARD_INFO("dummy", address),
@@ -1663,7 +1663,7 @@ EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
/* ------------------------------------------------------------------------- */
-int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
+int i2c_for_each_dev(void *data, int (*fn)(struct device *dev, void *data))
{
int res;
@@ -2276,7 +2276,7 @@ struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
- int (*probe)(struct i2c_adapter *, unsigned short addr))
+ int (*probe)(struct i2c_adapter *adap, unsigned short addr))
{
int i;
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index 2eb59a260ad4..d1c48dec7118 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/sysfs.h>
#include "i2c-core.h"
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 851c11b4c0f3..517d98be68d2 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -19,6 +19,8 @@ extern struct list_head __i2c_board_list;
extern int __i2c_first_dynamic_bus_num;
int i2c_check_7bit_addr_validity_strict(unsigned short addr);
+int i2c_dev_irq_from_resources(const struct resource *resources,
+ unsigned int num_resources);
/*
* We only allow atomic transfers for very late communication, e.g. to send
@@ -61,6 +63,8 @@ const struct acpi_device_id *
i2c_acpi_match_device(const struct acpi_device_id *matches,
struct i2c_client *client);
void i2c_acpi_register_devices(struct i2c_adapter *adap);
+
+int i2c_acpi_get_irq(struct i2c_client *client);
#else /* CONFIG_ACPI */
static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
static inline const struct acpi_device_id *
@@ -69,6 +73,11 @@ i2c_acpi_match_device(const struct acpi_device_id *matches,
{
return NULL;
}
+
+static inline int i2c_acpi_get_irq(struct i2c_client *client)
+{
+ return 0;
+}
#endif /* CONFIG_ACPI */
extern struct notifier_block i2c_acpi_notifier;
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 603252fa1284..774507b54b57 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
@@ -243,8 +244,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
{
struct i2c_mux_core *muxc;
- muxc = devm_kzalloc(dev, sizeof(*muxc)
- + max_adapters * sizeof(muxc->adapter[0])
+ muxc = devm_kzalloc(dev, struct_size(muxc, adapter, max_adapters)
+ sizeof_priv, GFP_KERNEL);
if (!muxc)
return NULL;
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 255c598dcfc8..6dc88902c189 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -6,12 +6,11 @@
*/
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -19,22 +18,16 @@
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
- * @our_gpio: GPIO we'll use to claim.
- * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
- * this then consider it released.
- * @their_gpio: GPIO that the other side will use to claim.
- * @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
- * this then consider it released.
+ * @our_gpio: GPIO descriptor we'll use to claim.
+ * @their_gpio: GPIO descriptor that the other side will use to claim.
* @slew_delay_us: microseconds to wait for a GPIO to go high.
* @wait_retry_us: we'll attempt another claim after this many microseconds.
* @wait_free_us: we'll give up after this many microseconds.
*/
struct i2c_arbitrator_data {
- int our_gpio;
- int our_gpio_release;
- int their_gpio;
- int their_gpio_release;
+ struct gpio_desc *our_gpio;
+ struct gpio_desc *their_gpio;
unsigned int slew_delay_us;
unsigned int wait_retry_us;
unsigned int wait_free_us;
@@ -55,15 +48,15 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
do {
/* Indicate that we want to claim the bus */
- gpio_set_value(arb->our_gpio, !arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 1);
udelay(arb->slew_delay_us);
/* Wait for the other master to release it */
stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
while (time_before(jiffies, stop_retry)) {
- int gpio_val = !!gpio_get_value(arb->their_gpio);
+ int gpio_val = gpiod_get_value(arb->their_gpio);
- if (gpio_val == arb->their_gpio_release) {
+ if (!gpio_val) {
/* We got it, so return */
return 0;
}
@@ -72,13 +65,13 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
}
/* It didn't release, so give up, wait, and try again */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
} while (time_before(jiffies, stop_time));
/* Give up, release our claim */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
dev_err(muxc->dev, "Could not claim bus, timeout\n");
return -EBUSY;
@@ -94,7 +87,7 @@ static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
/* Release the bus and wait for the other master to notice */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
return 0;
@@ -107,8 +100,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device_node *parent_np;
struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb;
- enum of_gpio_flags gpio_flags;
- unsigned long out_init;
+ struct gpio_desc *dummy;
int ret;
/* We only support probing from device tree; no platform_data */
@@ -129,45 +121,28 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, muxc);
- /* Request GPIOs */
- ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
- if (!gpio_is_valid(ret)) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error getting our-claim-gpio\n");
- return ret;
- }
- arb->our_gpio = ret;
- arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
- out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- ret = devm_gpio_request_one(dev, arb->our_gpio, out_init,
- "our-claim-gpio");
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error requesting our-claim-gpio\n");
- return ret;
+ /* Request GPIOs, our GPIO as unclaimed to begin with */
+ arb->our_gpio = devm_gpiod_get(dev, "our-claim", GPIOD_OUT_LOW);
+ if (IS_ERR(arb->our_gpio)) {
+ dev_err(dev, "could not get \"our-claim\" GPIO (%ld)\n",
+ PTR_ERR(arb->our_gpio));
+ return PTR_ERR(arb->our_gpio);
}
- ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags);
- if (!gpio_is_valid(ret)) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error getting their-claim-gpio\n");
- return ret;
- }
- arb->their_gpio = ret;
- arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
- ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN,
- "their-claim-gpio");
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error requesting their-claim-gpio\n");
- return ret;
+ arb->their_gpio = devm_gpiod_get(dev, "their-claim", GPIOD_IN);
+ if (IS_ERR(arb->their_gpio)) {
+ dev_err(dev, "could not get \"their-claim\" GPIO (%ld)\n",
+ PTR_ERR(arb->their_gpio));
+ return PTR_ERR(arb->their_gpio);
}
/* At the moment we only support a single two master (us + 1 other) */
- if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) {
+ dummy = devm_gpiod_get_index(dev, "their-claim", 1, GPIOD_IN);
+ if (!IS_ERR(dummy)) {
dev_err(dev, "Only one other master is supported\n");
return -EINVAL;
+ } else if (PTR_ERR(dummy) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
}
/* Arbitration parameters */
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 14dc2deba283..4effe563e9e8 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -11,13 +11,14 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+/* FIXME: stop poking around inside gpiolib */
#include "../../gpio/gpiolib.h"
-#include <linux/of_gpio.h>
struct gpiomux {
struct i2c_mux_gpio_platform_data data;
- unsigned gpio_base;
+ int ngpios;
struct gpio_desc **gpios;
};
@@ -27,8 +28,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
values[0] = val;
- gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
- values);
+ gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values);
}
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
@@ -49,12 +49,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
-static int match_gpio_chip_by_label(struct gpio_chip *chip,
- void *data)
-{
- return !strcmp(chip->label, data);
-}
-
#ifdef CONFIG_OF
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
@@ -62,8 +56,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
- unsigned *values, *gpios;
- int i = 0, ret;
+ unsigned *values;
+ int i = 0;
if (!np)
return -ENODEV;
@@ -100,29 +94,6 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
if (of_property_read_u32(np, "idle-state", &mux->data.idle))
mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
- mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios");
- if (mux->data.n_gpios < 0) {
- dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n");
- return -EINVAL;
- }
-
- gpios = devm_kcalloc(&pdev->dev,
- mux->data.n_gpios, sizeof(*mux->data.gpios),
- GFP_KERNEL);
- if (!gpios) {
- dev_err(&pdev->dev, "Cannot allocate gpios array");
- return -ENOMEM;
- }
-
- for (i = 0; i < mux->data.n_gpios; i++) {
- ret = of_get_named_gpio(np, "mux-gpios", i);
- if (ret < 0)
- return ret;
- gpios[i] = ret;
- }
-
- mux->data.gpios = gpios;
-
return 0;
}
#else
@@ -139,8 +110,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
struct gpiomux *mux;
struct i2c_adapter *parent;
struct i2c_adapter *root;
- unsigned initial_state, gpio_base;
- int i, ret;
+ unsigned initial_state;
+ int i, ngpios, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
@@ -155,29 +126,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
sizeof(mux->data));
}
- /*
- * If a GPIO chip name is provided, the GPIO pin numbers provided are
- * relative to its base GPIO number. Otherwise they are absolute.
- */
- if (mux->data.gpio_chip) {
- struct gpio_chip *gpio;
-
- gpio = gpiochip_find(mux->data.gpio_chip,
- match_gpio_chip_by_label);
- if (!gpio)
- return -EPROBE_DEFER;
-
- gpio_base = gpio->base;
- } else {
- gpio_base = 0;
+ ngpios = gpiod_count(&pdev->dev, "mux");
+ if (ngpios <= 0) {
+ dev_err(&pdev->dev, "no valid gpios provided\n");
+ return ngpios ?: -EINVAL;
}
+ mux->ngpios = ngpios;
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
- mux->data.n_gpios * sizeof(*mux->gpios), 0,
+ ngpios * sizeof(*mux->gpios), 0,
i2c_mux_gpio_select, NULL);
if (!muxc) {
ret = -ENOMEM;
@@ -191,7 +152,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
root = i2c_root_adapter(&parent->dev);
muxc->mux_locked = true;
- mux->gpio_base = gpio_base;
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
@@ -200,34 +160,28 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
initial_state = mux->data.values[0];
}
- for (i = 0; i < mux->data.n_gpios; i++) {
+ for (i = 0; i < ngpios; i++) {
struct device *gpio_dev;
- struct gpio_desc *gpio_desc;
-
- ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
- if (ret) {
- dev_err(&pdev->dev, "Failed to request GPIO %d\n",
- mux->data.gpios[i]);
- goto err_request_gpio;
+ struct gpio_desc *gpiod;
+ enum gpiod_flags flag;
+
+ if (initial_state & BIT(i))
+ flag = GPIOD_OUT_HIGH;
+ else
+ flag = GPIOD_OUT_LOW;
+ gpiod = devm_gpiod_get_index(&pdev->dev, "mux", i, flag);
+ if (IS_ERR(gpiod)) {
+ ret = PTR_ERR(gpiod);
+ goto alloc_failed;
}
- ret = gpio_direction_output(gpio_base + mux->data.gpios[i],
- initial_state & (1 << i));
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to set direction of GPIO %d to output\n",
- mux->data.gpios[i]);
- i++; /* gpio_request above succeeded, so must free */
- goto err_request_gpio;
- }
-
- gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
- mux->gpios[i] = gpio_desc;
+ mux->gpios[i] = gpiod;
if (!muxc->mux_locked)
continue;
- gpio_dev = &gpio_desc->gdev->dev;
+ /* FIXME: find a proper way to access the GPIO device */
+ gpio_dev = &gpiod->gdev->dev;
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
}
@@ -250,10 +204,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
add_adapter_failed:
i2c_mux_del_adapters(muxc);
- i = mux->data.n_gpios;
-err_request_gpio:
- for (; i > 0; i--)
- gpio_free(gpio_base + mux->data.gpios[i - 1]);
alloc_failed:
i2c_put_adapter(parent);
@@ -263,14 +213,8 @@ alloc_failed:
static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
- struct gpiomux *mux = i2c_mux_priv(muxc);
- int i;
i2c_mux_del_adapters(muxc);
-
- for (i = 0; i < mux->data.n_gpios; i++)
- gpio_free(mux->gpio_base + mux->data.gpios[i]);
-
i2c_put_adapter(muxc->parent);
return 0;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 41603586f8fa..f1bb00a11ad6 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -16,7 +16,7 @@
struct i2c_mux_pinctrl {
struct pinctrl *pinctrl;
- struct pinctrl_state **states;
+ struct pinctrl_state *states[];
};
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
@@ -93,14 +93,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(parent);
muxc = i2c_mux_alloc(parent, dev, num_names,
- sizeof(*mux) + num_names * sizeof(*mux->states),
+ struct_size(mux, states, num_names),
0, i2c_mux_pinctrl_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto err_put_parent;
}
mux = i2c_mux_priv(muxc);
- mux->states = (struct pinctrl_state **)(mux + 1);
platform_set_drvdata(pdev, muxc);
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 63aa541c9608..35bf2477693d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -507,38 +507,24 @@ static const struct at24_chip_data *at24_get_chip_data(struct device *dev)
return cdata;
}
-static void at24_remove_dummy_clients(struct at24_data *at24)
-{
- int i;
-
- for (i = 1; i < at24->num_addresses; i++)
- i2c_unregister_device(at24->client[i].client);
-}
-
static int at24_make_dummy_client(struct at24_data *at24, unsigned int index,
struct regmap_config *regmap_config)
{
struct i2c_client *base_client, *dummy_client;
- unsigned short int addr;
struct regmap *regmap;
struct device *dev;
base_client = at24->client[0].client;
dev = &base_client->dev;
- addr = base_client->addr + index;
- dummy_client = i2c_new_dummy(base_client->adapter,
- base_client->addr + index);
- if (!dummy_client) {
- dev_err(dev, "address 0x%02x unavailable\n", addr);
- return -EADDRINUSE;
- }
+ dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter,
+ base_client->addr + index);
+ if (IS_ERR(dummy_client))
+ return PTR_ERR(dummy_client);
regmap = devm_regmap_init_i2c(dummy_client, regmap_config);
- if (IS_ERR(regmap)) {
- i2c_unregister_device(dummy_client);
+ if (IS_ERR(regmap))
return PTR_ERR(regmap);
- }
at24->client[index].client = dummy_client;
at24->client[index].regmap = regmap;
@@ -580,7 +566,6 @@ static int at24_probe(struct i2c_client *client)
unsigned int i, num_addresses;
struct at24_data *at24;
struct regmap *regmap;
- size_t at24_size;
bool writable;
u8 test_byte;
int err;
@@ -597,8 +582,8 @@ static int at24_probe(struct i2c_client *client)
if (err)
/*
* This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via platform_data
- * is recommended anyhow.
+ * play safe. Specifying custom eeprom-types via device tree
+ * or properties is recommended anyhow.
*/
page_size = 1;
@@ -664,8 +649,8 @@ static int at24_probe(struct i2c_client *client)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- at24_size = sizeof(*at24) + num_addresses * sizeof(struct at24_client);
- at24 = devm_kzalloc(dev, at24_size, GFP_KERNEL);
+ at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses),
+ GFP_KERNEL);
if (!at24)
return -ENOMEM;
@@ -693,27 +678,8 @@ static int at24_probe(struct i2c_client *client)
/* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) {
err = at24_make_dummy_client(at24, i, &regmap_config);
- if (err) {
- at24_remove_dummy_clients(at24);
+ if (err)
return err;
- }
- }
-
- i2c_set_clientdata(client, at24);
-
- /* enable runtime pm */
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
- /*
- * Perform a one-byte test read to verify that the
- * chip is functional.
- */
- err = at24_read(at24, 0, &test_byte, 1);
- pm_runtime_idle(dev);
- if (err) {
- err = -ENODEV;
- goto err_clients;
}
nvmem_config.name = dev_name(dev);
@@ -731,9 +697,24 @@ static int at24_probe(struct i2c_client *client)
nvmem_config.size = byte_len;
at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
- if (IS_ERR(at24->nvmem)) {
- err = PTR_ERR(at24->nvmem);
- goto err_clients;
+ if (IS_ERR(at24->nvmem))
+ return PTR_ERR(at24->nvmem);
+
+ i2c_set_clientdata(client, at24);
+
+ /* enable runtime pm */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ /*
+ * Perform a one-byte test read to verify that the
+ * chip is functional.
+ */
+ err = at24_read(at24, 0, &test_byte, 1);
+ pm_runtime_idle(dev);
+ if (err) {
+ pm_runtime_disable(dev);
+ return -ENODEV;
}
dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
@@ -741,21 +722,10 @@ static int at24_probe(struct i2c_client *client)
writable ? "writable" : "read-only", at24->write_max);
return 0;
-
-err_clients:
- at24_remove_dummy_clients(at24);
- pm_runtime_disable(dev);
-
- return err;
}
static int at24_remove(struct i2c_client *client)
{
- struct at24_data *at24;
-
- at24 = i2c_get_clientdata(client);
-
- at24_remove_dummy_clients(at24);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c
index 5cdb09cba077..bfcc1d1b9b96 100644
--- a/drivers/platform/x86/dell-smo8800.c
+++ b/drivers/platform/x86/dell-smo8800.c
@@ -198,6 +198,7 @@ static int smo8800_remove(struct acpi_device *device)
return 0;
}
+/* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */
static const struct acpi_device_id smo8800_ids[] = {
{ "SMO8800", 0 },
{ "SMO8801", 0 },
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..ba288b964dc8 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
return ret;
}
+EXPORT_SYMBOL_GPL(ucsi_send_command);
+int ucsi_resume(struct ucsi *ucsi)
+{
+ struct ucsi_control ctrl;
+
+ /* Restore UCSI notification enable mask after system resume */
+ UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+ return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
/* -------------------------------------------------------------------------- */
void ucsi_altmode_update_active(struct ucsi_connector *con)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1e2981aef629..de87d0b8319d 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *retval, size_t size);
void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
#if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
struct typec_altmode *
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index bf63074675fc..f7a79a23ebed 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <asm/unaligned.h>
#include "ucsi.h"
@@ -107,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
#define CCG_VERSION_MIN_SHIFT (0)
#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
#define CCG_VERSION_MAJ_SHIFT (4)
#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
} __packed;
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA (('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
struct version_info {
struct version_format base;
struct version_format app;
@@ -170,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+ u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
#define RESET_PENDING 0
@@ -183,6 +195,8 @@ struct ucsi_ccg {
/* fw build with vendor information */
u16 fw_build;
+ bool run_isr; /* flag to call ISR routine during resume */
+ struct work_struct pm_work;
};
static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -210,6 +224,19 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ /*
+ * Do not schedule pm_work to run ISR in
+ * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+ * since we are already in ISR path.
+ */
+ uc->run_isr = false;
+ mutex_unlock(&uc->lock);
+ }
+
+ pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +245,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
+ pm_runtime_put_sync(uc->dev);
return 0;
}
@@ -249,13 +278,28 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ /*
+ * Do not schedule pm_work to run ISR in
+ * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+ * since we are already in ISR path.
+ */
+ uc->run_isr = false;
+ mutex_unlock(&uc->lock);
+ }
+
+ pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
+ pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
}
@@ -375,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+ struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+ ucsi_notify(uc->ucsi);
+}
+
static int get_fw_info(struct ucsi_ccg *uc)
{
int err;
@@ -384,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
+ uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+ CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
sizeof(uc->info));
if (err < 0)
@@ -732,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name,
}
/* compare input version with FWCT version */
- cur_version = le16_to_cpu(app->build) | app->patch << 16 |
- app->ver << 24;
+ cur_version = le16_to_cpu(app->build) | CCG_VERSION_PATCH(app->patch) |
+ CCG_VERSION(app->ver);
- new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 |
- fw_cfg.app.ver << 24;
+ new_version = le16_to_cpu(fw_cfg.app.build) |
+ CCG_VERSION_PATCH(fw_cfg.app.patch) |
+ CCG_VERSION(fw_cfg.app.ver);
if (!ccg_check_vendor_version(uc, app, &fw_cfg))
goto out_release_firmware;
@@ -1078,8 +1133,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
uc->ppm.sync = ucsi_ccg_sync;
uc->dev = dev;
uc->client = client;
+ uc->run_isr = true;
mutex_init(&uc->lock);
INIT_WORK(&uc->work, ccg_update_firmware);
+ INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
/* Only fail FW flashing when FW build information is not provided */
status = device_property_read_u16(dev, "ccgx,firmware-build",
@@ -1136,6 +1193,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
+ pm_runtime_set_active(uc->dev);
+ pm_runtime_enable(uc->dev);
+ pm_runtime_idle(uc->dev);
+
return 0;
}
@@ -1143,8 +1204,10 @@ static int ucsi_ccg_remove(struct i2c_client *client)
{
struct ucsi_ccg *uc = i2c_get_clientdata(client);
+ cancel_work_sync(&uc->pm_work);
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+ pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
@@ -1157,9 +1220,56 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
+static int ucsi_ccg_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+ return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ucsi_ccg *uc = i2c_get_clientdata(client);
+ bool schedule = true;
+
+ /*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume.
+ * Schedule a work to call ISR as a workaround.
+ */
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ if (!uc->run_isr) {
+ uc->run_isr = true;
+ schedule = false;
+ }
+ mutex_unlock(&uc->lock);
+
+ if (schedule)
+ schedule_work(&uc->pm_work);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+ .resume = ucsi_ccg_resume,
+ .runtime_suspend = ucsi_ccg_runtime_suspend,
+ .runtime_resume = ucsi_ccg_runtime_resume,
+};
+
static struct i2c_driver ucsi_ccg_driver = {
.driver = {
.name = "ucsi_ccg",
+ .pm = &ucsi_ccg_pm,
},
.probe = ucsi_ccg_probe,
.remove = ucsi_ccg_remove,
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index e982b8913b73..fa5552c2307b 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -1,16 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* ------------------------------------------------------------------------- */
-/* */
-/* i2c.h - definitions for the i2c-bus interface */
-/* */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 1995-2000 Simon G. Vogl
-
+/*
+ * i2c.h - definitions for the Linux i2c bus interface
+ * Copyright (C) 1995-2000 Simon G. Vogl
+ * Copyright (C) 2013-2019 Wolfram Sang <wsa@the-dreams.de>
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ * Frodo Looijaard <frodol@dds.nl>
*/
-/* ------------------------------------------------------------------------- */
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
- Frodo Looijaard <frodol@dds.nl> */
#ifndef _LINUX_I2C_H
#define _LINUX_I2C_H
@@ -40,7 +36,8 @@ struct i2c_device_identity;
union i2c_smbus_data;
struct i2c_board_info;
enum i2c_slave_event;
-typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
+typedef int (*i2c_slave_cb_t)(struct i2c_client *client,
+ enum i2c_slave_event event, u8 *val);
struct module;
struct property_entry;
@@ -257,16 +254,16 @@ struct i2c_driver {
unsigned int class;
/* Standard driver model interfaces */
- int (*probe)(struct i2c_client *, const struct i2c_device_id *);
- int (*remove)(struct i2c_client *);
+ int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
+ int (*remove)(struct i2c_client *client);
/* New driver model interface to aid the seamless removal of the
* current probe()'s, more commonly unused than used second parameter.
*/
- int (*probe_new)(struct i2c_client *);
+ int (*probe_new)(struct i2c_client *client);
/* driver model interfaces that don't relate to enumeration */
- void (*shutdown)(struct i2c_client *);
+ void (*shutdown)(struct i2c_client *client);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
@@ -275,7 +272,7 @@ struct i2c_driver {
* For the SMBus Host Notify protocol, the data corresponds to the
* 16-bit payload data reported by the slave device acting as master.
*/
- void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol,
+ void (*alert)(struct i2c_client *client, enum i2c_alert_protocol protocol,
unsigned int data);
/* a ioctl like command that can be used to perform specific functions
@@ -287,7 +284,7 @@ struct i2c_driver {
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
- int (*detect)(struct i2c_client *, struct i2c_board_info *);
+ int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
const unsigned short *address_list;
struct list_head clients;
@@ -297,8 +294,7 @@ struct i2c_driver {
/**
* struct i2c_client - represent an I2C slave device
- * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
- * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
+ * @flags: see I2C_CLIENT_* for possible flags
* @addr: Address used on the I2C bus connected to the parent adapter.
* @name: Indicates the type of the device, usually a chip name that's
* generic enough to hide second-sourcing and compatible revisions.
@@ -316,6 +312,15 @@ struct i2c_driver {
*/
struct i2c_client {
unsigned short flags; /* div., see below */
+#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
+#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
+ /* Must equal I2C_M_TEN below */
+#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */
+#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
+#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
+#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
+ /* Must match I2C_M_STOP|IGNORE_NAK */
+
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
@@ -437,6 +442,9 @@ struct i2c_board_info {
extern struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+extern struct i2c_client *
+i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+
/* If you don't know the exact address of an I2C device, use this variant
* instead, which can probe for device presence in a list of possible
* addresses. The "probe" callback function is optional. If it is provided,
@@ -447,10 +455,10 @@ extern struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
- int (*probe)(struct i2c_adapter *, unsigned short addr));
+ int (*probe)(struct i2c_adapter *adap, unsigned short addr));
/* Common custom probe functions */
-extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
+extern int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr);
/* For devices that use several addresses, use i2c_new_dummy() to make
* client handles for the extra addresses.
@@ -459,6 +467,9 @@ extern struct i2c_client *
i2c_new_dummy(struct i2c_adapter *adap, u16 address);
extern struct i2c_client *
+i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address);
+
+extern struct i2c_client *
devm_i2c_new_dummy_device(struct device *dev, struct i2c_adapter *adap, u16 address);
extern struct i2c_client *
@@ -466,7 +477,7 @@ i2c_new_secondary_device(struct i2c_client *client,
const char *name,
u16 default_addr);
-extern void i2c_unregister_device(struct i2c_client *);
+extern void i2c_unregister_device(struct i2c_client *client);
#endif /* I2C */
/* Mainboard arch_initcall() code should register all its I2C devices.
@@ -551,9 +562,9 @@ struct i2c_algorithm {
* The main operations are wrapped by i2c_lock_bus and i2c_unlock_bus.
*/
struct i2c_lock_operations {
- void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
- int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
- void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
+ void (*lock_bus)(struct i2c_adapter *adapter, unsigned int flags);
+ int (*trylock_bus)(struct i2c_adapter *adapter, unsigned int flags);
+ void (*unlock_bus)(struct i2c_adapter *adapter, unsigned int flags);
};
/**
@@ -703,14 +714,14 @@ struct i2c_adapter {
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
-static inline void *i2c_get_adapdata(const struct i2c_adapter *dev)
+static inline void *i2c_get_adapdata(const struct i2c_adapter *adap)
{
- return dev_get_drvdata(&dev->dev);
+ return dev_get_drvdata(&adap->dev);
}
-static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
+static inline void i2c_set_adapdata(struct i2c_adapter *adap, void *data)
{
- dev_set_drvdata(&dev->dev, data);
+ dev_set_drvdata(&adap->dev, data);
}
static inline struct i2c_adapter *
@@ -726,7 +737,7 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
return NULL;
}
-int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
+int i2c_for_each_dev(void *data, int (*fn)(struct device *dev, void *data));
/* Adapter locking functions, exported for shared pin cases */
#define I2C_LOCK_ROOT_ADAPTER BIT(0)
@@ -802,16 +813,6 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER);
}
-/*flags for the client struct: */
-#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
-#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
- /* Must equal I2C_M_TEN below */
-#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */
-#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
-#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
-#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
- /* Must match I2C_M_STOP|IGNORE_NAK */
-
/* i2c adapter classes (bitmask) */
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
#define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */
@@ -832,12 +833,12 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
/* administration...
*/
#if IS_ENABLED(CONFIG_I2C)
-extern int i2c_add_adapter(struct i2c_adapter *);
-extern void i2c_del_adapter(struct i2c_adapter *);
-extern int i2c_add_numbered_adapter(struct i2c_adapter *);
+extern int i2c_add_adapter(struct i2c_adapter *adap);
+extern void i2c_del_adapter(struct i2c_adapter *adap);
+extern int i2c_add_numbered_adapter(struct i2c_adapter *adap);
-extern int i2c_register_driver(struct module *, struct i2c_driver *);
-extern void i2c_del_driver(struct i2c_driver *);
+extern int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
+extern void i2c_del_driver(struct i2c_driver *driver);
/* use a define to avoid include chaining to get THIS_MODULE */
#define i2c_add_driver(driver) \
diff --git a/include/linux/platform_data/i2c-mux-gpio.h b/include/linux/platform_data/i2c-mux-gpio.h
index 9f6ca406505b..5e4c2c272a73 100644
--- a/include/linux/platform_data/i2c-mux-gpio.h
+++ b/include/linux/platform_data/i2c-mux-gpio.h
@@ -19,10 +19,6 @@
* position
* @n_values: Number of multiplexer positions (busses to instantiate)
* @classes: Optional I2C auto-detection classes
- * @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given
- * relative to the base GPIO number of that chip
- * @gpios: Array of GPIO numbers used to control MUX
- * @n_gpios: Number of GPIOs used to control MUX
* @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
*/
struct i2c_mux_gpio_platform_data {
@@ -31,9 +27,6 @@ struct i2c_mux_gpio_platform_data {
const unsigned *values;
int n_values;
const unsigned *classes;
- char *gpio_chip;
- const unsigned *gpios;
- int n_gpios;
unsigned idle;
};