Merge branch 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - core supports now bus regulators controlling power for SCL/SDA - quite some DT binding conversions to YAML - added a seperate DT binding for the optional SMBus Alert feature - documentation with examples how to deal with I2C sysfs files - some bigger rework for the i801 driver - and a few usual driver updates * 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (42 commits) i2c: ali1535: mention that the device should not be disabled i2c: mpc: Restore reread of I2C status register i2c: core-smbus: Expose PEC calculate function for generic use Documentation: i2c: Add doc for I2C sysfs i2c: core: Disable client irq on reboot/shutdown dt-bindings: i2c: update bindings for MT8195 SoC i2c: imx: Fix some checkpatch warnings i2c: davinci: Simplify with dev_err_probe() i2c: cadence: Simplify with dev_err_probe() i2c: xiic: Simplify with dev_err_probe() i2c: cadence: Clear HOLD bit before xfer_size register rolls over dt-bindings: i2c: ce4100: Replace "ti,pcf8575" by "nxp,pcf8575" i2c: i801: Improve i801_setup_hstcfg i2c: i801: Use driver name constant instead of function dev_driver_string i2c: i801: Simplify initialization of i2c_board_info in i801_probe_optional_slaves i2c: i801: Improve status polling i2c: cht-wc: Replace of_node by NULL i2c: riic: Add RZ/G2L support dt-bindings: i2c: renesas,riic: Document RZ/G2L I2C controller dt-bindings: i2c: renesas,iic: Convert to json-schema ...
This commit is contained in:
commit
855ff900b8
|
@ -15,6 +15,7 @@ Required properties:
|
|||
"mediatek,mt8173-i2c": for MediaTek MT8173
|
||||
"mediatek,mt8183-i2c": for MediaTek MT8183
|
||||
"mediatek,mt8192-i2c": for MediaTek MT8192
|
||||
"mediatek,mt8195-i2c", "mediatek,mt8192-i2c": for MediaTek MT8195
|
||||
"mediatek,mt8516-i2c", "mediatek,mt2712-i2c": for MediaTek MT8516
|
||||
- reg: physical base address of the controller and dma base, length of memory
|
||||
mapped region.
|
||||
|
@ -32,6 +33,7 @@ Optional properties:
|
|||
- mediatek,have-pmic: platform can control i2c form special pmic side.
|
||||
Only mt6589 and mt8135 support this feature.
|
||||
- mediatek,use-push-pull: IO config use push-pull mode.
|
||||
- vbus-supply: phandle to the regulator that provides power to SCL/SDA.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ Example:
|
|||
reg = <0x3c>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7 1>;
|
||||
reset-active-low;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
I2C for OMAP platforms
|
||||
|
||||
Required properties :
|
||||
- compatible : Must be
|
||||
"ti,omap2420-i2c" for OMAP2420 SoCs
|
||||
"ti,omap2430-i2c" for OMAP2430 SoCs
|
||||
"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,am64-i2c", "ti,omap4-i2c" for AM64 SoCs
|
||||
- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
|
||||
Recommended properties :
|
||||
- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise
|
||||
the default 100 kHz frequency will be used.
|
||||
|
||||
Optional properties:
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
||||
Note: Current implementation will fetch base address, irq and dma
|
||||
from omap hwmod data base during device registration.
|
||||
Future plan is to migrate hwmod data base contents into device tree
|
||||
blob so that, all the required data will be used from device tree dts
|
||||
file.
|
||||
|
||||
Examples :
|
||||
|
||||
i2c1: i2c@0 {
|
||||
compatible = "ti,omap3-i2c";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ti,hwmods = "i2c1";
|
||||
clock-frequency = <400000>;
|
||||
};
|
|
@ -71,7 +71,7 @@ This is an example which is used on FalconFalls:
|
|||
/* This I2C controller has one gpio controller */
|
||||
gpio@26 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "ti,pcf8575";
|
||||
compatible = "nxp,pcf8575";
|
||||
reg = <0x26>;
|
||||
gpio-controller;
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ This is an example which is used on FalconFalls:
|
|||
|
||||
gpio@26 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "ti,pcf8575";
|
||||
compatible = "nxp,pcf8575";
|
||||
reg = <0x26>;
|
||||
gpio-controller;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ PROPERTIES:
|
|||
"qcom,msm8916-cci"
|
||||
"qcom,msm8996-cci"
|
||||
"qcom,sdm845-cci"
|
||||
"qcom,sm8250-cci"
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
|
@ -41,8 +42,8 @@ PROPERTIES:
|
|||
|
||||
SUBNODES:
|
||||
|
||||
The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8996 and
|
||||
sdm845), described as subdevices named "i2c-bus@0" and "i2c-bus@1".
|
||||
The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8996,
|
||||
sdm845 and sm8250), described as subdevices named "i2c-bus@0" and "i2c-bus@1".
|
||||
|
||||
PROPERTIES:
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ properties:
|
|||
- rockchip,px30-i2c
|
||||
- rockchip,rk3308-i2c
|
||||
- rockchip,rk3328-i2c
|
||||
- rockchip,rk3568-i2c
|
||||
- const: rockchip,rk3399-i2c
|
||||
|
||||
reg:
|
||||
|
|
|
@ -89,8 +89,11 @@ wants to support one of the below features, it should adapt these bindings.
|
|||
|
||||
- smbus
|
||||
states that additional SMBus restrictions and features apply to this bus.
|
||||
Examples of features are SMBusHostNotify and SMBusAlert. Examples of
|
||||
restrictions are more reserved addresses and timeout definitions.
|
||||
An example of feature is SMBusHostNotify. Examples of restrictions are
|
||||
more reserved addresses and timeout definitions.
|
||||
|
||||
- smbus-alert
|
||||
states that the optional SMBus-Alert feature apply to this bus.
|
||||
|
||||
Required properties (per child device)
|
||||
--------------------------------------
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
I2C for R-Car platforms
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
"renesas,i2c-r8a7742" if the device is a part of a R8A7742 SoC.
|
||||
"renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC.
|
||||
"renesas,i2c-r8a7744" if the device is a part of a R8A7744 SoC.
|
||||
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
||||
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
|
||||
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
||||
"renesas,i2c-r8a774b1" if the device is a part of a R8A774B1 SoC.
|
||||
"renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
|
||||
"renesas,i2c-r8a774e1" if the device is a part of a R8A774E1 SoC.
|
||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
||||
"renesas,i2c-r8a7791" if the device is a part of a R8A7791 SoC.
|
||||
"renesas,i2c-r8a7792" if the device is a part of a R8A7792 SoC.
|
||||
"renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC.
|
||||
"renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC.
|
||||
"renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A77960 SoC.
|
||||
"renesas,i2c-r8a77961" if the device is a part of a R8A77961 SoC.
|
||||
"renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC.
|
||||
"renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC.
|
||||
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
|
||||
"renesas,i2c-r8a77990" if the device is a part of a R8A77990 SoC.
|
||||
"renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC.
|
||||
"renesas,i2c-r8a779a0" if the device is a part of a R8A779A0 SoC.
|
||||
"renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
|
||||
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible
|
||||
device.
|
||||
"renesas,rcar-gen3-i2c" for a generic R-Car Gen3 or RZ/G2 compatible
|
||||
device.
|
||||
"renesas,i2c-rcar" (deprecated)
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first followed
|
||||
by the generic version.
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt specifier.
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
|
||||
property indicates the default frequency 100 kHz.
|
||||
- clocks: clock specifier.
|
||||
- dmas: Must contain a list of two references to DMA specifiers, one for
|
||||
transmission, and one for reception.
|
||||
- dma-names: Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
- i2c-scl-falling-time-ns: see i2c.txt
|
||||
- i2c-scl-internal-delay-ns: see i2c.txt
|
||||
- i2c-scl-rising-time-ns: see i2c.txt
|
||||
|
||||
Examples :
|
||||
|
||||
i2c0: i2c@e6508000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
|
||||
reg = <0 0xe6508000 0 0x40>;
|
||||
interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp9_clks R8A7791_CLK_I2C0>;
|
||||
clock-frequency = <400000>;
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
Device tree configuration for Renesas EMEV2 IIC controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,iic-emev2"
|
||||
- reg : address start and address range size of device
|
||||
- interrupts : specifier for the IIC controller interrupt
|
||||
- clocks : phandle to the IP core SCLK
|
||||
- clock-names : must be "sclk"
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Example:
|
||||
|
||||
iic0: i2c@e0070000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "renesas,iic-emev2";
|
||||
reg = <0xe0070000 0x28>;
|
||||
interrupts = <0 32 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&iic0_sclk>;
|
||||
clock-names = "sclk";
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/renesas,iic-emev2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas EMMA Mobile EV2 IIC Interface
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,iic-emev2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: sclk
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
iic0: i2c@e0070000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "renesas,iic-emev2";
|
||||
reg = <0xe0070000 0x28>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&iic0_sclk>;
|
||||
clock-names = "sclk";
|
||||
};
|
|
@ -1,72 +0,0 @@
|
|||
Device tree configuration for Renesas IIC (sh_mobile) driver
|
||||
|
||||
Required properties:
|
||||
- compatible :
|
||||
- "renesas,iic-r8a73a4" (R-Mobile APE6)
|
||||
- "renesas,iic-r8a7740" (R-Mobile A1)
|
||||
- "renesas,iic-r8a7742" (RZ/G1H)
|
||||
- "renesas,iic-r8a7743" (RZ/G1M)
|
||||
- "renesas,iic-r8a7744" (RZ/G1N)
|
||||
- "renesas,iic-r8a7745" (RZ/G1E)
|
||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||
- "renesas,iic-r8a774b1" (RZ/G2N)
|
||||
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||
- "renesas,iic-r8a774e1" (RZ/G2H)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||
- "renesas,iic-r8a7793" (R-Car M2-N)
|
||||
- "renesas,iic-r8a7794" (R-Car E2)
|
||||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-r8a77961" (R-Car M3-W+)
|
||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||
- "renesas,iic-r8a77990" (R-Car E3)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
|
||||
compatible device)
|
||||
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 or RZ/G2
|
||||
compatible device)
|
||||
- "renesas,rmobile-iic" (generic device)
|
||||
|
||||
When compatible with a generic R-Car version, nodes
|
||||
must list the SoC-specific version corresponding to
|
||||
the platform first followed by the generic R-Car
|
||||
version.
|
||||
|
||||
When compatible with "renesas,rmobile-iic" it should
|
||||
be the last compatibility string listed.
|
||||
|
||||
The r8a77990 (R-Car E3) and r8a774c0 (RZ/G2E)
|
||||
controllers are not considered compatible with
|
||||
"renesas,rcar-gen3-iic" or "renesas,rmobile-iic"
|
||||
due to the absence of automatic transmission registers.
|
||||
|
||||
- reg : address start and address range size of device
|
||||
- interrupts : interrupt of device
|
||||
- clocks : clock for device
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset.
|
||||
- dmas : Must contain a list of two references to DMA
|
||||
specifiers, one for transmission, and one for
|
||||
reception.
|
||||
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
|
||||
Pinctrl properties might be needed, too. See there.
|
||||
|
||||
Example:
|
||||
|
||||
iic0: i2c@e6500000 {
|
||||
compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
|
||||
"renesas,rmobile-iic";
|
||||
reg = <0 0xe6500000 0 0x425>;
|
||||
interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp3_clks R8A7790_CLK_IIC0>;
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,158 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/renesas,rcar-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,i2c-r8a7778 # R-Car M1A
|
||||
- renesas,i2c-r8a7779 # R-Car H1
|
||||
- const: renesas,rcar-gen1-i2c # R-Car Gen1
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,i2c-r8a7742 # RZ/G1H
|
||||
- renesas,i2c-r8a7743 # RZ/G1M
|
||||
- renesas,i2c-r8a7744 # RZ/G1N
|
||||
- renesas,i2c-r8a7745 # RZ/G1E
|
||||
- renesas,i2c-r8a77470 # RZ/G1C
|
||||
- renesas,i2c-r8a7790 # R-Car H2
|
||||
- renesas,i2c-r8a7791 # R-Car M2-W
|
||||
- renesas,i2c-r8a7792 # R-Car V2H
|
||||
- renesas,i2c-r8a7793 # R-Car M2-N
|
||||
- renesas,i2c-r8a7794 # R-Car E2
|
||||
- const: renesas,rcar-gen2-i2c # R-Car Gen2 and RZ/G1
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,i2c-r8a774a1 # RZ/G2M
|
||||
- renesas,i2c-r8a774b1 # RZ/G2N
|
||||
- renesas,i2c-r8a774c0 # RZ/G2E
|
||||
- renesas,i2c-r8a774e1 # RZ/G2H
|
||||
- renesas,i2c-r8a7795 # R-Car H3
|
||||
- renesas,i2c-r8a7796 # R-Car M3-W
|
||||
- renesas,i2c-r8a77961 # R-Car M3-W+
|
||||
- renesas,i2c-r8a77965 # R-Car M3-N
|
||||
- renesas,i2c-r8a77970 # R-Car V3M
|
||||
- renesas,i2c-r8a77980 # R-Car V3H
|
||||
- renesas,i2c-r8a77990 # R-Car E3
|
||||
- renesas,i2c-r8a77995 # R-Car D3
|
||||
- renesas,i2c-r8a779a0 # R-Car V3U
|
||||
- const: renesas,rcar-gen3-i2c # R-Car Gen3 and RZ/G2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description:
|
||||
Desired I2C bus clock frequency in Hz. The absence of this property
|
||||
indicates the default frequency 100 kHz.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
description:
|
||||
Must contain a list of pairs of references to DMA specifiers, one for
|
||||
transmission, and one for reception.
|
||||
|
||||
dma-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
i2c-scl-falling-time-ns:
|
||||
default: 35
|
||||
description:
|
||||
Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C
|
||||
specification.
|
||||
|
||||
i2c-scl-internal-delay-ns:
|
||||
default: 50
|
||||
description:
|
||||
Number of nanoseconds the IP core additionally needs to setup SCL.
|
||||
|
||||
i2c-scl-rising-time-ns:
|
||||
default: 200
|
||||
description:
|
||||
Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C
|
||||
specification.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- power-domains
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,rcar-gen1-i2c
|
||||
- renesas,rcar-gen2-i2c
|
||||
then:
|
||||
properties:
|
||||
dmas: false
|
||||
dma-names: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,rcar-gen2-i2c
|
||||
- renesas,rcar-gen3-i2c
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7791-sysc.h>
|
||||
|
||||
i2c0: i2c@e6508000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
|
||||
reg = <0xe6508000 0x40>;
|
||||
interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-frequency = <400000>;
|
||||
clocks = <&cpg CPG_MOD 931>;
|
||||
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 931>;
|
||||
i2c-scl-internal-delay-ns = <6>;
|
||||
};
|
|
@ -1,32 +0,0 @@
|
|||
Device tree configuration for Renesas RIIC driver
|
||||
|
||||
Required properties:
|
||||
- compatible :
|
||||
"renesas,riic-r7s72100" if the device is a part of a R7S72100 SoC.
|
||||
"renesas,riic-r7s9210" if the device is a part of a R7S9210 SoC.
|
||||
"renesas,riic-rz" for a generic RZ/A compatible device.
|
||||
- reg : address start and address range size of device
|
||||
- interrupts : 8 interrupts (TEI, RI, TI, SPI, STI, NAKI, ALI, TMOI)
|
||||
- clock-frequency : frequency of bus clock in Hz
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Pinctrl properties might be needed, too. See there.
|
||||
|
||||
Example:
|
||||
|
||||
i2c0: i2c@fcfee000 {
|
||||
compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
|
||||
reg = <0xfcfee000 0x44>;
|
||||
interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 158 IRQ_TYPE_EDGE_RISING>,
|
||||
<0 159 IRQ_TYPE_EDGE_RISING>,
|
||||
<0 160 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 161 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 162 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 163 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 164 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-frequency = <100000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/renesas,riic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/A and RZ/G2L I2C Bus Interface (RIIC)
|
||||
|
||||
maintainers:
|
||||
- Chris Brandt <chris.brandt@renesas.com>
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,riic-r7s72100 # RZ/A1H
|
||||
- renesas,riic-r7s9210 # RZ/A2M
|
||||
- renesas,riic-r9a07g044 # RZ/G2{L,LC}
|
||||
- const: renesas,riic-rz # RZ/A or RZ/G2L
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Transmit End Interrupt (TEI)
|
||||
- description: Receive Data Full Interrupt (RI)
|
||||
- description: Transmit Data Empty Interrupt (TI)
|
||||
- description: Stop Condition Detection Interrupt (SPI)
|
||||
- description: Start Condition Detection Interrupt (STI)
|
||||
- description: NACK Reception Interrupt (NAKI)
|
||||
- description: Arbitration-Lost Interrupt (ALI)
|
||||
- description: Timeout Interrupt (TMOI)
|
||||
|
||||
clock-frequency:
|
||||
description:
|
||||
Desired I2C bus clock frequency in Hz. The absence of this property
|
||||
indicates the default frequency 100 kHz.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-frequency
|
||||
- power-domains
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,riic-r9a07g044
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r7s72100-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
i2c0: i2c@fcfee000 {
|
||||
compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
|
||||
reg = <0xfcfee000 0x44>;
|
||||
interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 158 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp9_clks R7S72100_CLK_I2C0>;
|
||||
clock-frequency = <100000>;
|
||||
power-domains = <&cpg_clocks>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,149 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/renesas,rmobile-iic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Mobile I2C Bus Interface (IIC)
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,iic-r8a73a4 # R-Mobile APE6
|
||||
- renesas,iic-r8a7740 # R-Mobile A1
|
||||
- renesas,iic-sh73a0 # SH-Mobile AG5
|
||||
- const: renesas,rmobile-iic # Generic
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,iic-r8a7742 # RZ/G1H
|
||||
- renesas,iic-r8a7743 # RZ/G1M
|
||||
- renesas,iic-r8a7744 # RZ/G1N
|
||||
- renesas,iic-r8a7745 # RZ/G1E
|
||||
- renesas,iic-r8a7790 # R-Car H2
|
||||
- renesas,iic-r8a7791 # R-Car M2-W
|
||||
- renesas,iic-r8a7792 # R-Car V2H
|
||||
- renesas,iic-r8a7793 # R-Car M2-N
|
||||
- renesas,iic-r8a7794 # R-Car E2
|
||||
- const: renesas,rcar-gen2-iic # R-Car Gen2 and RZ/G1
|
||||
- const: renesas,rmobile-iic # Generic
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,iic-r8a774a1 # RZ/G2M
|
||||
- renesas,iic-r8a774b1 # RZ/G2N
|
||||
- renesas,iic-r8a774c0 # RZ/G2E
|
||||
- renesas,iic-r8a774e1 # RZ/G2H
|
||||
- renesas,iic-r8a7795 # R-Car H3
|
||||
- renesas,iic-r8a7796 # R-Car M3-W
|
||||
- renesas,iic-r8a77961 # R-Car M3-W+
|
||||
- renesas,iic-r8a77965 # R-Car M3-N
|
||||
- renesas,iic-r8a77990 # R-Car E3
|
||||
- const: renesas,rcar-gen3-iic # R-Car Gen3 and RZ/G2
|
||||
- const: renesas,rmobile-iic # Generic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts: true
|
||||
|
||||
clock-frequency:
|
||||
description:
|
||||
Desired I2C bus clock frequency in Hz. The absence of this property
|
||||
indicates the default frequency 100 kHz.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
description:
|
||||
Must contain a list of pairs of references to DMA specifiers, one for
|
||||
transmission, and one for reception.
|
||||
|
||||
dma-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- power-domains
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,iic-r8a7740
|
||||
- renesas,iic-sh73a0
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
items:
|
||||
- description: Arbitration Lost Interrupt (ALI)
|
||||
- description: Non-acknowledge Detection Interrupt (TACKI)
|
||||
- description: Wait Interrupt (WAITI)
|
||||
- description: Data Transmit Enable interrupt (DTEI)
|
||||
else:
|
||||
properties:
|
||||
interrupts:
|
||||
items:
|
||||
- description: Single combined interrupt
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,rcar-gen2-iic
|
||||
- renesas,rcar-gen3-iic
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7790-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7790-sysc.h>
|
||||
|
||||
iic0: i2c@e6500000 {
|
||||
compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
|
||||
"renesas,rmobile-iic";
|
||||
reg = <0xe6500000 0x425>;
|
||||
interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 318>;
|
||||
clock-frequency = <400000>;
|
||||
dmas = <&dmac0 0x61>, <&dmac0 0x62>, <&dmac1 0x61>, <&dmac1 0x62>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 318>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,102 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/ti,omap4-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bindings for I2C controllers on TI's OMAP and K3 SoCs
|
||||
|
||||
maintainers:
|
||||
- Vignesh Raghavendra <vigneshr@ti.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- ti,omap2420-i2c
|
||||
- ti,omap2430-i2c
|
||||
- ti,omap3-i2c
|
||||
- ti,omap4-i2c
|
||||
- items:
|
||||
- enum:
|
||||
- ti,am4372-i2c
|
||||
- ti,am64-i2c
|
||||
- ti,am654-i2c
|
||||
- ti,j721e-i2c
|
||||
- const: ti,omap4-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: fck
|
||||
|
||||
clock-frequency: true
|
||||
|
||||
power-domains: true
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
ti,hwmods:
|
||||
description:
|
||||
Must be "i2c<n>", n being the instance number (1-based).
|
||||
This property is applicable only on legacy platforms mainly omap2/3
|
||||
and ti81xx and should not be used on other platforms.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
|
||||
# subnode's properties
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
type: object
|
||||
description:
|
||||
Flash device uses the below defined properties in the subnode.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: ti,omap2420-i2c
|
||||
- const: ti,omap2430-i2c
|
||||
- const: ti,omap3-i2c
|
||||
- const: ti,omap4-i2c
|
||||
|
||||
then:
|
||||
properties:
|
||||
ti,hwmods:
|
||||
items:
|
||||
- pattern: "^i2c([1-9])$"
|
||||
|
||||
else:
|
||||
properties:
|
||||
ti,hwmods: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
main_i2c0: i2c@2000000 {
|
||||
compatible = "ti,j721e-i2c", "ti,omap4-i2c";
|
||||
reg = <0x2000000 0x100>;
|
||||
interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,395 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
Linux I2C Sysfs
|
||||
===============
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
I2C topology can be complex because of the existence of I2C MUX
|
||||
(I2C Multiplexer). The Linux
|
||||
kernel abstracts the MUX channels into logical I2C bus numbers. However, there
|
||||
is a gap of knowledge to map from the I2C bus physical number and MUX topology
|
||||
to logical I2C bus number. This doc is aimed to fill in this gap, so the
|
||||
audience (hardware engineers and new software developers for example) can learn
|
||||
the concept of logical I2C buses in the kernel, by knowing the physical I2C
|
||||
topology and navigating through the I2C sysfs in Linux shell. This knowledge is
|
||||
useful and essential to use ``i2c-tools`` for the purpose of development and
|
||||
debugging.
|
||||
|
||||
Target audience
|
||||
---------------
|
||||
|
||||
People who need to use Linux shell to interact with I2C subsystem on a system
|
||||
which the Linux is running on.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
1. Knowledge of general Linux shell file system commands and operations.
|
||||
|
||||
2. General knowledge of I2C, I2C MUX and I2C topology.
|
||||
|
||||
Location of I2C Sysfs
|
||||
=====================
|
||||
|
||||
Typically, the Linux Sysfs filesystem is mounted at the ``/sys`` directory,
|
||||
so you can find the I2C Sysfs under ``/sys/bus/i2c/devices``
|
||||
where you can directly ``cd`` to it.
|
||||
There is a list of symbolic links under that directory. The links that
|
||||
start with ``i2c-`` are I2C buses, which may be either physical or logical. The
|
||||
other links that begin with numbers and end with numbers are I2C devices, where
|
||||
the first number is I2C bus number, and the second number is I2C address.
|
||||
|
||||
Google Pixel 3 phone for example::
|
||||
|
||||
blueline:/sys/bus/i2c/devices $ ls
|
||||
0-0008 0-0061 1-0028 3-0043 4-0036 4-0041 i2c-1 i2c-3
|
||||
0-000c 0-0066 2-0049 4-000b 4-0040 i2c-0 i2c-2 i2c-4
|
||||
|
||||
``i2c-2`` is an I2C bus whose number is 2, and ``2-0049`` is an I2C device
|
||||
on bus 2 address 0x49 bound with a kernel driver.
|
||||
|
||||
Terminologies
|
||||
=============
|
||||
|
||||
First, let us define a couple of terminologies to avoid confusions in the later
|
||||
sections.
|
||||
|
||||
(Physical) I2C Bus Controller
|
||||
-----------------------------
|
||||
|
||||
The hardware system that the Linux kernel is running on may have multiple
|
||||
physical I2C bus controllers. The controllers are hardware and physical, and the
|
||||
system may define multiple registers in the memory space to manipulate the
|
||||
controllers. Linux kernel has I2C bus drivers under source directory
|
||||
``drivers/i2c/busses`` to translate kernel I2C API into register
|
||||
operations for different systems. This terminology is not limited to Linux
|
||||
kernel only.
|
||||
|
||||
I2C Bus Physical Number
|
||||
-----------------------
|
||||
|
||||
For each physical I2C bus controller, the system vendor may assign a physical
|
||||
number to each controller. For example, the first I2C bus controller which has
|
||||
the lowest register addresses may be called ``I2C-0``.
|
||||
|
||||
Logical I2C Bus
|
||||
---------------
|
||||
|
||||
Every I2C bus number you see in Linux I2C Sysfs is a logical I2C bus with a
|
||||
number assigned. This is similar to the fact that software code is usually
|
||||
written upon virtual memory space, instead of physical memory space.
|
||||
|
||||
Each logical I2C bus may be an abstraction of a physical I2C bus controller, or
|
||||
an abstraction of a channel behind an I2C MUX. In case it is an abstraction of a
|
||||
MUX channel, whenever we access an I2C device via a such logical bus, the kernel
|
||||
will switch the I2C MUX for you to the proper channel as part of the
|
||||
abstraction.
|
||||
|
||||
Physical I2C Bus
|
||||
----------------
|
||||
|
||||
If the logical I2C bus is a direct abstraction of a physical I2C bus controller,
|
||||
let us call it a physical I2C bus.
|
||||
|
||||
Caveat
|
||||
------
|
||||
|
||||
This may be a confusing part for people who only know about the physical I2C
|
||||
design of a board. It is actually possible to rename the I2C bus physical number
|
||||
to a different number in logical I2C bus level in Device Tree Source (DTS) under
|
||||
section ``aliases``. See
|
||||
`arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
|
||||
<../../arch/arm/boot/dts/nuvoton-npcm730-gsj.dts>`_
|
||||
for an example of DTS file.
|
||||
|
||||
Best Practice: **(To kernel software developers)** It is better to keep the I2C
|
||||
bus physical number the same as their corresponding logical I2C bus number,
|
||||
instead of renaming or mapping them, so that it may be less confusing to other
|
||||
users. These physical I2C buses can be served as good starting points for I2C
|
||||
MUX fanouts. For the following examples, we will assume that the physical I2C
|
||||
bus has a number same as their I2C bus physical number.
|
||||
|
||||
Walk through Logical I2C Bus
|
||||
============================
|
||||
|
||||
For the following content, we will use a more complex I2C topology as an
|
||||
example. Here is a brief graph for the I2C topology. If you do not understand
|
||||
this graph at the first glance, do not be afraid to continue reading this doc
|
||||
and review it when you finish reading.
|
||||
|
||||
::
|
||||
|
||||
i2c-7 (physical I2C bus controller 7)
|
||||
`-- 7-0071 (4-channel I2C MUX at 0x71)
|
||||
|-- i2c-60 (channel-0)
|
||||
|-- i2c-73 (channel-1)
|
||||
| |-- 73-0040 (I2C sensor device with hwmon directory)
|
||||
| |-- 73-0070 (I2C MUX at 0x70, exists in DTS, but failed to probe)
|
||||
| `-- 73-0072 (8-channel I2C MUX at 0x72)
|
||||
| |-- i2c-78 (channel-0)
|
||||
| |-- ... (channel-1...6, i2c-79...i2c-84)
|
||||
| `-- i2c-85 (channel-7)
|
||||
|-- i2c-86 (channel-2)
|
||||
`-- i2c-203 (channel-3)
|
||||
|
||||
Distinguish Physical and Logical I2C Bus
|
||||
----------------------------------------
|
||||
|
||||
One simple way to distinguish between a physical I2C bus and a logical I2C bus,
|
||||
is to read the symbolic link ``device`` under the I2C bus directory by using
|
||||
command ``ls -l`` or ``readlink``.
|
||||
|
||||
An alternative symbolic link to check is ``mux_device``. This link only exists
|
||||
in logical I2C bus directory which is fanned out from another I2C bus.
|
||||
Reading this link will also tell you which I2C MUX device created
|
||||
this logical I2C bus.
|
||||
|
||||
If the symbolic link points to a directory ending with ``.i2c``, it should be a
|
||||
physical I2C bus, directly abstracting a physical I2C bus controller. For
|
||||
example::
|
||||
|
||||
$ readlink /sys/bus/i2c/devices/i2c-7/device
|
||||
../../f0087000.i2c
|
||||
$ ls /sys/bus/i2c/devices/i2c-7/mux_device
|
||||
ls: /sys/bus/i2c/devices/i2c-7/mux_device: No such file or directory
|
||||
|
||||
In this case, ``i2c-7`` is a physical I2C bus, so it does not have the symbolic
|
||||
link ``mux_device`` under its directory. And if the kernel software developer
|
||||
follows the common practice by not renaming physical I2C buses, this should also
|
||||
mean the physical I2C bus controller 7 of the system.
|
||||
|
||||
On the other hand, if the symbolic link points to another I2C bus, the I2C bus
|
||||
presented by the current directory has to be a logical bus. The I2C bus pointed
|
||||
by the link is the parent bus which may be either a physical I2C bus or a
|
||||
logical one. In this case, the I2C bus presented by the current directory
|
||||
abstracts an I2C MUX channel under the parent bus.
|
||||
|
||||
For example::
|
||||
|
||||
$ readlink /sys/bus/i2c/devices/i2c-73/device
|
||||
../../i2c-7
|
||||
$ readlink /sys/bus/i2c/devices/i2c-73/mux_device
|
||||
../7-0071
|
||||
|
||||
``i2c-73`` is a logical bus fanout by an I2C MUX under ``i2c-7``
|
||||
whose I2C address is 0x71.
|
||||
Whenever we access an I2C device with bus 73, the kernel will always
|
||||
switch the I2C MUX addressed 0x71 to the proper channel for you as part of the
|
||||
abstraction.
|
||||
|
||||
Finding out Logical I2C Bus Number
|
||||
----------------------------------
|
||||
|
||||
In this section, we will describe how to find out the logical I2C bus number
|
||||
representing certain I2C MUX channels based on the knowledge of physical
|
||||
hardware I2C topology.
|
||||
|
||||
In this example, we have a system which has a physical I2C bus 7 and not renamed
|
||||
in DTS. There is a 4-channel MUX at address 0x71 on that bus. There is another
|
||||
8-channel MUX at address 0x72 behind the channel 1 of the 0x71 MUX. Let us
|
||||
navigate through Sysfs and find out the logical I2C bus number of the channel 3
|
||||
of the 0x72 MUX.
|
||||
|
||||
First of all, let us go to the directory of ``i2c-7``::
|
||||
|
||||
~$ cd /sys/bus/i2c/devices/i2c-7
|
||||
/sys/bus/i2c/devices/i2c-7$ ls
|
||||
7-0071 i2c-60 name subsystem
|
||||
delete_device i2c-73 new_device uevent
|
||||
device i2c-86 of_node
|
||||
i2c-203 i2c-dev power
|
||||
|
||||
There, we see the 0x71 MUX as ``7-0071``. Go inside it::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-7$ cd 7-0071/
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071$ ls -l
|
||||
channel-0 channel-3 modalias power
|
||||
channel-1 driver name subsystem
|
||||
channel-2 idle_state of_node uevent
|
||||
|
||||
Read the link ``channel-1`` using ``readlink`` or ``ls -l``::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071$ readlink channel-1
|
||||
../i2c-73
|
||||
|
||||
We find out that the channel 1 of 0x71 MUX on ``i2c-7`` is assigned
|
||||
with a logical I2C bus number of 73.
|
||||
Let us continue the journey to directory ``i2c-73`` in either ways::
|
||||
|
||||
# cd to i2c-73 under I2C Sysfs root
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071$ cd /sys/bus/i2c/devices/i2c-73
|
||||
/sys/bus/i2c/devices/i2c-73$
|
||||
|
||||
# cd the channel symbolic link
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071$ cd channel-1
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071/channel-1$
|
||||
|
||||
# cd the link content
|
||||
/sys/bus/i2c/devices/i2c-7/7-0071$ cd ../i2c-73
|
||||
/sys/bus/i2c/devices/i2c-7/i2c-73$
|
||||
|
||||
Either ways, you will end up in the directory of ``i2c-73``. Similar to above,
|
||||
we can now find the 0x72 MUX and what logical I2C bus numbers
|
||||
that its channels are assigned::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73$ ls
|
||||
73-0040 device i2c-83 new_device
|
||||
73-004e i2c-78 i2c-84 of_node
|
||||
73-0050 i2c-79 i2c-85 power
|
||||
73-0070 i2c-80 i2c-dev subsystem
|
||||
73-0072 i2c-81 mux_device uevent
|
||||
delete_device i2c-82 name
|
||||
/sys/bus/i2c/devices/i2c-73$ cd 73-0072
|
||||
/sys/bus/i2c/devices/i2c-73/73-0072$ ls
|
||||
channel-0 channel-4 driver of_node
|
||||
channel-1 channel-5 idle_state power
|
||||
channel-2 channel-6 modalias subsystem
|
||||
channel-3 channel-7 name uevent
|
||||
/sys/bus/i2c/devices/i2c-73/73-0072$ readlink channel-3
|
||||
../i2c-81
|
||||
|
||||
There, we find out the logical I2C bus number of the channel 3 of the 0x72 MUX
|
||||
is 81. We can later use this number to switch to its own I2C Sysfs directory or
|
||||
issue ``i2c-tools`` commands.
|
||||
|
||||
Tip: Once you understand the I2C topology with MUX, command
|
||||
`i2cdetect -l
|
||||
<https://manpages.debian.org/unstable/i2c-tools/i2cdetect.8.en.html>`_
|
||||
in
|
||||
`I2C Tools
|
||||
<https://i2c.wiki.kernel.org/index.php/I2C_Tools>`_
|
||||
can give you
|
||||
an overview of the I2C topology easily, if it is available on your system. For
|
||||
example::
|
||||
|
||||
$ i2cdetect -l | grep -e '\-73' -e _7 | sort -V
|
||||
i2c-7 i2c npcm_i2c_7 I2C adapter
|
||||
i2c-73 i2c i2c-7-mux (chan_id 1) I2C adapter
|
||||
i2c-78 i2c i2c-73-mux (chan_id 0) I2C adapter
|
||||
i2c-79 i2c i2c-73-mux (chan_id 1) I2C adapter
|
||||
i2c-80 i2c i2c-73-mux (chan_id 2) I2C adapter
|
||||
i2c-81 i2c i2c-73-mux (chan_id 3) I2C adapter
|
||||
i2c-82 i2c i2c-73-mux (chan_id 4) I2C adapter
|
||||
i2c-83 i2c i2c-73-mux (chan_id 5) I2C adapter
|
||||
i2c-84 i2c i2c-73-mux (chan_id 6) I2C adapter
|
||||
i2c-85 i2c i2c-73-mux (chan_id 7) I2C adapter
|
||||
|
||||
Pinned Logical I2C Bus Number
|
||||
-----------------------------
|
||||
|
||||
If not specified in DTS, when an I2C MUX driver is applied and the MUX device is
|
||||
successfully probed, the kernel will assign the MUX channels with a logical bus
|
||||
number based on the current biggest logical bus number incrementally. For
|
||||
example, if the system has ``i2c-15`` as the highest logical bus number, and a
|
||||
4-channel MUX is applied successfully, we will have ``i2c-16`` for the
|
||||
MUX channel 0, and all the way to ``i2c-19`` for the MUX channel 3.
|
||||
|
||||
The kernel software developer is able to pin the fanout MUX channels to a static
|
||||
logical I2C bus number in the DTS. This doc will not go through the details on
|
||||
how to implement this in DTS, but we can see an example in:
|
||||
`arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts
|
||||
<../../arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts>`_
|
||||
|
||||
In the above example, there is an 8-channel I2C MUX at address 0x70 on physical
|
||||
I2C bus 2. The channel 2 of the MUX is defined as ``imux18`` in DTS,
|
||||
and pinned to logical I2C bus number 18 with the line of ``i2c18 = &imux18;``
|
||||
in section ``aliases``.
|
||||
|
||||
Take it further, it is possible to design a logical I2C bus number schema that
|
||||
can be easily remembered by humans or calculated arithmetically. For example, we
|
||||
can pin the fanout channels of a MUX on bus 3 to start at 30. So 30 will be the
|
||||
logical bus number of the channel 0 of the MUX on bus 3, and 37 will be the
|
||||
logical bus number of the channel 7 of the MUX on bus 3.
|
||||
|
||||
I2C Devices
|
||||
===========
|
||||
|
||||
In previous sections, we mostly covered the I2C bus. In this section, let us see
|
||||
what we can learn from the I2C device directory whose link name is in the format
|
||||
of ``${bus}-${addr}``. The ``${bus}`` part in the name is a logical I2C bus
|
||||
decimal number, while the ``${addr}`` part is a hex number of the I2C address
|
||||
of each device.
|
||||
|
||||
I2C Device Directory Content
|
||||
----------------------------
|
||||
|
||||
Inside each I2C device directory, there is a file named ``name``.
|
||||
This file tells what device name it was used for the kernel driver to
|
||||
probe this device. Use command ``cat`` to read its content. For example::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73$ cat 73-0040/name
|
||||
ina230
|
||||
/sys/bus/i2c/devices/i2c-73$ cat 73-0070/name
|
||||
pca9546
|
||||
/sys/bus/i2c/devices/i2c-73$ cat 73-0072/name
|
||||
pca9547
|
||||
|
||||
There is a symbolic link named ``driver`` to tell what Linux kernel driver was
|
||||
used to probe this device::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73$ readlink -f 73-0040/driver
|
||||
/sys/bus/i2c/drivers/ina2xx
|
||||
/sys/bus/i2c/devices/i2c-73$ readlink -f 73-0072/driver
|
||||
/sys/bus/i2c/drivers/pca954x
|
||||
|
||||
But if the link ``driver`` does not exist at the first place,
|
||||
it may mean that the kernel driver failed to probe this device due to
|
||||
some errors. The error may be found in ``dmesg``::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73$ ls 73-0070/driver
|
||||
ls: 73-0070/driver: No such file or directory
|
||||
/sys/bus/i2c/devices/i2c-73$ dmesg | grep 73-0070
|
||||
pca954x 73-0070: probe failed
|
||||
pca954x 73-0070: probe failed
|
||||
|
||||
Depending on what the I2C device is and what kernel driver was used to probe the
|
||||
device, we may have different content in the device directory.
|
||||
|
||||
I2C MUX Device
|
||||
--------------
|
||||
|
||||
While you may be already aware of this in previous sections, an I2C MUX device
|
||||
will have symbolic link ``channel-*`` inside its device directory.
|
||||
These symbolic links point to their logical I2C bus directories::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73$ ls -l 73-0072/channel-*
|
||||
lrwxrwxrwx ... 73-0072/channel-0 -> ../i2c-78
|
||||
lrwxrwxrwx ... 73-0072/channel-1 -> ../i2c-79
|
||||
lrwxrwxrwx ... 73-0072/channel-2 -> ../i2c-80
|
||||
lrwxrwxrwx ... 73-0072/channel-3 -> ../i2c-81
|
||||
lrwxrwxrwx ... 73-0072/channel-4 -> ../i2c-82
|
||||
lrwxrwxrwx ... 73-0072/channel-5 -> ../i2c-83
|
||||
lrwxrwxrwx ... 73-0072/channel-6 -> ../i2c-84
|
||||
lrwxrwxrwx ... 73-0072/channel-7 -> ../i2c-85
|
||||
|
||||
I2C Sensor Device / Hwmon
|
||||
-------------------------
|
||||
|
||||
I2C sensor device is also common to see. If they are bound by a kernel hwmon
|
||||
(Hardware Monitoring) driver successfully, you will see a ``hwmon`` directory
|
||||
inside the I2C device directory. Keep digging into it, you will find the Hwmon
|
||||
Sysfs for the I2C sensor device::
|
||||
|
||||
/sys/bus/i2c/devices/i2c-73/73-0040/hwmon/hwmon17$ ls
|
||||
curr1_input in0_lcrit_alarm name subsystem
|
||||
device in1_crit power uevent
|
||||
in0_crit in1_crit_alarm power1_crit update_interval
|
||||
in0_crit_alarm in1_input power1_crit_alarm
|
||||
in0_input in1_lcrit power1_input
|
||||
in0_lcrit in1_lcrit_alarm shunt_resistor
|
||||
|
||||
For more info on the Hwmon Sysfs, refer to the doc:
|
||||
|
||||
`Naming and data format standards for sysfs files
|
||||
<../hwmon/sysfs-interface.rst>`_
|
||||
|
||||
Instantiate I2C Devices in I2C Sysfs
|
||||
------------------------------------
|
||||
|
||||
Refer to the doc:
|
||||
|
||||
`How to instantiate I2C devices, Method 4: Instantiate from user-space
|
||||
<instantiating-devices.rst#method-4-instantiate-from-user-space>`_
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -13494,7 +13494,7 @@ M: Vignesh R <vigneshr@ti.com>
|
|||
L: linux-omap@vger.kernel.org
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-omap.txt
|
||||
F: Documentation/devicetree/bindings/i2c/ti,omap4-i2c.yaml
|
||||
F: drivers/i2c/busses/i2c-omap.c
|
||||
|
||||
OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
|
||||
|
@ -15722,8 +15722,9 @@ F: drivers/clk/renesas/
|
|||
|
||||
RENESAS EMEV2 I2C DRIVER
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.yaml
|
||||
F: drivers/i2c/busses/i2c-emev2.c
|
||||
|
||||
RENESAS ETHERNET DRIVERS
|
||||
|
@ -15743,9 +15744,10 @@ F: drivers/iio/adc/rcar-gyroadc.c
|
|||
|
||||
RENESAS R-CAR I2C DRIVERS
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,i2c.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,iic.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
|
||||
F: drivers/i2c/busses/i2c-rcar.c
|
||||
F: drivers/i2c/busses/i2c-sh_mobile.c
|
||||
|
||||
|
@ -15760,8 +15762,9 @@ F: drivers/thermal/rcar_thermal.c
|
|||
|
||||
RENESAS RIIC DRIVER
|
||||
M: Chris Brandt <chris.brandt@renesas.com>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,riic.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,riic.yaml
|
||||
F: drivers/i2c/busses/i2c-riic.c
|
||||
|
||||
RENESAS USB PHY DRIVER
|
||||
|
|
|
@ -508,6 +508,11 @@ static void ali1535_remove(struct pci_dev *dev)
|
|||
{
|
||||
i2c_del_adapter(&ali1535_adapter);
|
||||
release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
|
||||
|
||||
/*
|
||||
* do not call pci_disable_device(dev) since it can cause hard hangs on
|
||||
* some systems during power-off
|
||||
*/
|
||||
}
|
||||
|
||||
static struct pci_driver ali1535_driver = {
|
||||
|
|
|
@ -727,10 +727,14 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
|
|||
{
|
||||
u32 addr_reg_val, func_ctrl_reg_val;
|
||||
|
||||
/* Set slave addr. */
|
||||
addr_reg_val = readl(bus->base + ASPEED_I2C_DEV_ADDR_REG);
|
||||
addr_reg_val &= ~ASPEED_I2CD_DEV_ADDR_MASK;
|
||||
addr_reg_val |= slave_addr & ASPEED_I2CD_DEV_ADDR_MASK;
|
||||
/*
|
||||
* Set slave addr. Reserved bits can all safely be written with zeros
|
||||
* on all of ast2[456]00, so zero everything else to ensure we only
|
||||
* enable a single slave address (ast2500 has two, ast2600 has three,
|
||||
* the enable bits for which are also in this register) so that we don't
|
||||
* end up with additional phantom devices responding on the bus.
|
||||
*/
|
||||
addr_reg_val = slave_addr & ASPEED_I2CD_DEV_ADDR_MASK;
|
||||
writel(addr_reg_val, bus->base + ASPEED_I2C_DEV_ADDR_REG);
|
||||
|
||||
/* Turn on slave mode. */
|
||||
|
|
|
@ -578,6 +578,11 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
|
|||
{
|
||||
unsigned int ctrl_reg;
|
||||
unsigned int isr_status;
|
||||
unsigned long flags;
|
||||
bool hold_clear = false;
|
||||
bool irq_save = false;
|
||||
|
||||
u32 addr;
|
||||
|
||||
id->p_recv_buf = id->p_msg->buf;
|
||||
id->recv_count = id->p_msg->len;
|
||||
|
@ -618,14 +623,43 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
|
|||
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
}
|
||||
|
||||
/* Set the slave address in address register - triggers operation */
|
||||
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
|
||||
CDNS_I2C_ADDR_OFFSET);
|
||||
/* Clear the bus hold flag if bytes to receive is less than FIFO size */
|
||||
/* Determine hold_clear based on number of bytes to receive and hold flag */
|
||||
if (!id->bus_hold_flag &&
|
||||
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
|
||||
(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
|
||||
cdns_i2c_clear_bus_hold(id);
|
||||
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
|
||||
(id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
|
||||
if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
|
||||
hold_clear = true;
|
||||
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
|
||||
irq_save = true;
|
||||
}
|
||||
}
|
||||
|
||||
addr = id->p_msg->addr;
|
||||
addr &= CDNS_I2C_ADDR_MASK;
|
||||
|
||||
if (hold_clear) {
|
||||
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & ~CDNS_I2C_CR_HOLD;
|
||||
/*
|
||||
* In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size
|
||||
* register reaches '0'. This is an IP bug which causes transfer size
|
||||
* register overflow to 0xFF. To satisfy this timing requirement,
|
||||
* disable the interrupts on current processor core between register
|
||||
* writes to slave address register and control register.
|
||||
*/
|
||||
if (irq_save)
|
||||
local_irq_save(flags);
|
||||
|
||||
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
|
||||
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
|
||||
/* Read it back to avoid bufferring and make sure write happens */
|
||||
cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
|
||||
|
||||
if (irq_save)
|
||||
local_irq_restore(flags);
|
||||
} else {
|
||||
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
|
||||
}
|
||||
|
||||
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
|
||||
}
|
||||
|
||||
|
@ -1217,11 +1251,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
|
||||
|
||||
id->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(id->clk)) {
|
||||
if (PTR_ERR(id->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(id->clk);
|
||||
}
|
||||
if (IS_ERR(id->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(id->clk),
|
||||
"input clock not found.\n");
|
||||
|
||||
ret = clk_prepare_enable(id->clk);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
|
|
|
@ -354,8 +354,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
/* Alloc and register client IRQ */
|
||||
adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
|
||||
&irq_domain_simple_ops, NULL);
|
||||
adap->irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL);
|
||||
if (!adap->irq_domain)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -768,10 +768,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|||
if (irq <= 0) {
|
||||
if (!irq)
|
||||
irq = -ENXIO;
|
||||
if (irq != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"can't get irq resource ret=%d\n", irq);
|
||||
return irq;
|
||||
return dev_err_probe(&pdev->dev, irq, "can't get irq resource\n");
|
||||
}
|
||||
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev),
|
||||
|
|
|
@ -88,6 +88,8 @@
|
|||
* See the file Documentation/i2c/busses/i2c-i801.rst for details.
|
||||
*/
|
||||
|
||||
#define DRV_NAME "i801_smbus"
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
@ -103,7 +105,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/itco_wdt.h>
|
||||
|
@ -131,8 +133,6 @@
|
|||
|
||||
/* PCI Address Constants */
|
||||
#define SMBBAR 4
|
||||
#define SMBPCICTL 0x004
|
||||
#define SMBPCISTS 0x006
|
||||
#define SMBHSTCFG 0x040
|
||||
#define TCOBASE 0x050
|
||||
#define TCOCTL 0x054
|
||||
|
@ -141,12 +141,6 @@
|
|||
#define SBREG_SMBCTRL 0xc6000c
|
||||
#define SBREG_SMBCTRL_DNV 0xcf000c
|
||||
|
||||
/* Host status bits for SMBPCISTS */
|
||||
#define SMBPCISTS_INTS BIT(3)
|
||||
|
||||
/* Control bits for SMBPCICTL */
|
||||
#define SMBPCICTL_INTDIS BIT(10)
|
||||
|
||||
/* Host configuration bits for SMBHSTCFG */
|
||||
#define SMBHSTCFG_HST_EN BIT(0)
|
||||
#define SMBHSTCFG_SMB_SMI_EN BIT(1)
|
||||
|
@ -164,9 +158,6 @@
|
|||
#define SMBAUXCTL_CRC BIT(0)
|
||||
#define SMBAUXCTL_E32B BIT(1)
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_RETRIES 400
|
||||
|
||||
/* I801 command constants */
|
||||
#define I801_QUICK 0x00
|
||||
#define I801_BYTE 0x04
|
||||
|
@ -270,7 +261,7 @@ struct i801_priv {
|
|||
unsigned int features;
|
||||
|
||||
/* isr processing */
|
||||
wait_queue_head_t waitq;
|
||||
struct completion done;
|
||||
u8 status;
|
||||
|
||||
/* Command state used by isr for byte-by-byte block transactions */
|
||||
|
@ -453,67 +444,53 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
|||
/* Wait for BUSY being cleared and either INTR or an error flag being set */
|
||||
static int i801_wait_intr(struct i801_priv *priv)
|
||||
{
|
||||
int timeout = 0;
|
||||
int status;
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status, busy;
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while (((status & SMBHSTSTS_HOST_BUSY) ||
|
||||
!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
|
||||
(timeout++ < MAX_RETRIES));
|
||||
busy = status & SMBHSTSTS_HOST_BUSY;
|
||||
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
|
||||
if (!busy && status)
|
||||
return status;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
if (timeout > MAX_RETRIES) {
|
||||
dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait for either BYTE_DONE or an error flag being set */
|
||||
static int i801_wait_byte_done(struct i801_priv *priv)
|
||||
{
|
||||
int timeout = 0;
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status;
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
} while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
|
||||
(timeout++ < MAX_RETRIES));
|
||||
if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
if (timeout > MAX_RETRIES) {
|
||||
dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int i801_transaction(struct i801_priv *priv, int xact)
|
||||
{
|
||||
int status;
|
||||
int result;
|
||||
unsigned long result;
|
||||
const struct i2c_adapter *adap = &priv->adapter;
|
||||
|
||||
result = i801_check_pre(priv);
|
||||
if (result < 0)
|
||||
return result;
|
||||
status = i801_check_pre(priv);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
reinit_completion(&priv->done);
|
||||
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
|
||||
SMBHSTCNT(priv));
|
||||
result = wait_event_timeout(priv->waitq,
|
||||
(status = priv->status),
|
||||
adap->timeout);
|
||||
if (!result) {
|
||||
status = -ETIMEDOUT;
|
||||
dev_warn(&priv->pci_dev->dev,
|
||||
"Timeout waiting for interrupt!\n");
|
||||
}
|
||||
priv->status = 0;
|
||||
return i801_check_post(priv, status);
|
||||
result = wait_for_completion_timeout(&priv->done, adap->timeout);
|
||||
return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
|
||||
}
|
||||
|
||||
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
|
||||
|
@ -638,7 +615,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
|
|||
* DEV_ERR - Invalid command, NAK or communication timeout
|
||||
* BUS_ERR - SMI# transaction collision
|
||||
* FAILED - transaction was canceled due to a KILL request
|
||||
* When any of these occur, update ->status and wake up the waitq.
|
||||
* When any of these occur, update ->status and signal completion.
|
||||
* ->status must be cleared before kicking off the next transaction.
|
||||
*
|
||||
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
|
||||
|
@ -653,8 +630,8 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
|
|||
u8 status;
|
||||
|
||||
/* Confirm this is our interrupt */
|
||||
pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
|
||||
if (!(pcists & SMBPCISTS_INTS))
|
||||
pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
|
||||
if (!(pcists & PCI_STATUS_INTERRUPT))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (priv->features & FEATURE_HOST_NOTIFY) {
|
||||
|
@ -675,7 +652,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
|
|||
if (status) {
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
priv->status = status;
|
||||
wake_up(&priv->waitq);
|
||||
complete(&priv->done);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -694,15 +671,15 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
|||
int i, len;
|
||||
int smbcmd;
|
||||
int status;
|
||||
int result;
|
||||
unsigned long 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;
|
||||
status = i801_check_pre(priv);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
len = data->block[0];
|
||||
|
||||
|
@ -726,17 +703,10 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
|||
priv->count = 0;
|
||||
priv->data = &data->block[1];
|
||||
|
||||
reinit_completion(&priv->done);
|
||||
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
result = wait_event_timeout(priv->waitq,
|
||||
(status = priv->status),
|
||||
adap->timeout);
|
||||
if (!result) {
|
||||
status = -ETIMEDOUT;
|
||||
dev_warn(&priv->pci_dev->dev,
|
||||
"Timeout waiting for interrupt!\n");
|
||||
}
|
||||
priv->status = 0;
|
||||
return i801_check_post(priv, status);
|
||||
result = wait_for_completion_timeout(&priv->done, adap->timeout);
|
||||
return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
|
||||
}
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
|
@ -1322,11 +1292,11 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
|
|||
return;
|
||||
|
||||
if (apanel_addr) {
|
||||
struct i2c_board_info info;
|
||||
struct i2c_board_info info = {
|
||||
.addr = apanel_addr,
|
||||
.type = "fujitsu_apanel",
|
||||
};
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = apanel_addr;
|
||||
strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
|
||||
i2c_new_client_device(&priv->adapter, &info);
|
||||
}
|
||||
|
||||
|
@ -1715,19 +1685,17 @@ static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
|
|||
static inline void i801_acpi_remove(struct i801_priv *priv) { }
|
||||
#endif
|
||||
|
||||
static unsigned char i801_setup_hstcfg(struct i801_priv *priv)
|
||||
static void i801_setup_hstcfg(struct i801_priv *priv)
|
||||
{
|
||||
unsigned char hstcfg = priv->original_hstcfg;
|
||||
|
||||
hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
|
||||
hstcfg |= SMBHSTCFG_HST_EN;
|
||||
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
|
||||
return hstcfg;
|
||||
}
|
||||
|
||||
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
unsigned char temp;
|
||||
int err, i;
|
||||
struct i801_priv *priv;
|
||||
|
||||
|
@ -1838,8 +1806,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
if (i801_acpi_probe(priv))
|
||||
return -ENODEV;
|
||||
|
||||
err = pcim_iomap_regions(dev, 1 << SMBBAR,
|
||||
dev_driver_string(&dev->dev));
|
||||
err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME);
|
||||
if (err) {
|
||||
dev_err(&dev->dev,
|
||||
"Failed to request SMBus region 0x%lx-0x%Lx\n",
|
||||
|
@ -1850,16 +1817,16 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
}
|
||||
|
||||
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
|
||||
temp = i801_setup_hstcfg(priv);
|
||||
i801_setup_hstcfg(priv);
|
||||
if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
|
||||
dev_info(&dev->dev, "Enabling SMBus device\n");
|
||||
|
||||
if (temp & SMBHSTCFG_SMB_SMI_EN) {
|
||||
if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) {
|
||||
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
|
||||
/* Disable SMBus interrupt feature if SMBus using SMI# */
|
||||
priv->features &= ~FEATURE_IRQ;
|
||||
}
|
||||
if (temp & SMBHSTCFG_SPD_WD)
|
||||
if (priv->original_hstcfg & SMBHSTCFG_SPD_WD)
|
||||
dev_info(&dev->dev, "SPD Write Disable is set\n");
|
||||
|
||||
/* Clear special mode bits */
|
||||
|
@ -1881,24 +1848,23 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
u16 pcictl, pcists;
|
||||
|
||||
/* Complain if an interrupt is already pending */
|
||||
pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
|
||||
if (pcists & SMBPCISTS_INTS)
|
||||
pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
|
||||
if (pcists & PCI_STATUS_INTERRUPT)
|
||||
dev_warn(&dev->dev, "An interrupt is pending!\n");
|
||||
|
||||
/* Check if interrupts have been disabled */
|
||||
pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl);
|
||||
if (pcictl & SMBPCICTL_INTDIS) {
|
||||
pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pcictl);
|
||||
if (pcictl & PCI_COMMAND_INTX_DISABLE) {
|
||||
dev_info(&dev->dev, "Interrupts are disabled\n");
|
||||
priv->features &= ~FEATURE_IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
init_waitqueue_head(&priv->waitq);
|
||||
init_completion(&priv->done);
|
||||
|
||||
err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
|
||||
IRQF_SHARED,
|
||||
dev_driver_string(&dev->dev), priv);
|
||||
IRQF_SHARED, DRV_NAME, priv);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
|
||||
dev->irq, err);
|
||||
|
@ -1988,7 +1954,7 @@ static int i801_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);
|
||||
|
||||
static struct pci_driver i801_driver = {
|
||||
.name = "i801_smbus",
|
||||
.name = DRV_NAME,
|
||||
.id_table = i801_ids,
|
||||
.probe = i801_probe,
|
||||
.remove = i801_remove,
|
||||
|
|
|
@ -170,11 +170,11 @@ enum imx_i2c_type {
|
|||
|
||||
struct imx_i2c_hwdata {
|
||||
enum imx_i2c_type devtype;
|
||||
unsigned regshift;
|
||||
unsigned int regshift;
|
||||
struct imx_i2c_clk_pair *clk_div;
|
||||
unsigned ndivs;
|
||||
unsigned i2sr_clr_opcode;
|
||||
unsigned i2cr_ien_opcode;
|
||||
unsigned int ndivs;
|
||||
unsigned int i2sr_clr_opcode;
|
||||
unsigned int i2cr_ien_opcode;
|
||||
};
|
||||
|
||||
struct imx_i2c_dma {
|
||||
|
@ -452,8 +452,6 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
|
|||
unsigned long orig_jiffies = jiffies;
|
||||
unsigned int temp;
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
|
||||
|
||||
while (1) {
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
|
||||
|
||||
|
@ -599,8 +597,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic)
|
|||
unsigned int temp = 0;
|
||||
int result;
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
|
||||
|
||||
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
|
||||
/* Enable I2C controller */
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
|
||||
|
@ -635,7 +631,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
|
|||
|
||||
if (!i2c_imx->stopped) {
|
||||
/* Stop I2C transaction */
|
||||
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
|
||||
if (!(temp & I2CR_MSTA))
|
||||
i2c_imx->stopped = 1;
|
||||
|
@ -1167,8 +1162,6 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
|
|||
bool is_lastmsg = false;
|
||||
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
|
||||
|
||||
/* Start I2C transfer */
|
||||
result = i2c_imx_start(i2c_imx, atomic);
|
||||
if (result) {
|
||||
|
@ -1371,8 +1364,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
dma_addr_t phy_addr;
|
||||
const struct imx_i2c_hwdata *match;
|
||||
|
||||
dev_dbg(&pdev->dev, "<%s>\n", __func__);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
@ -1395,7 +1386,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
/* Setup i2c_imx driver structure */
|
||||
strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
|
||||
strscpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
|
||||
i2c_imx->adapter.owner = THIS_MODULE;
|
||||
i2c_imx->adapter.algo = &i2c_imx_algo;
|
||||
i2c_imx->adapter.dev.parent = &pdev->dev;
|
||||
|
|
|
@ -635,6 +635,8 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
|
|||
|
||||
status = readb(i2c->base + MPC_I2C_SR);
|
||||
if (status & CSR_MIF) {
|
||||
/* Read again to allow register to stabilise */
|
||||
status = readb(i2c->base + MPC_I2C_SR);
|
||||
writeb(0, i2c->base + MPC_I2C_SR);
|
||||
mpc_i2c_do_intr(i2c, status);
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
@ -1225,6 +1225,13 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||
i2c->adap.quirks = i2c->dev_comp->quirks;
|
||||
i2c->adap.timeout = 2 * HZ;
|
||||
i2c->adap.retries = 1;
|
||||
i2c->adap.bus_regulator = devm_regulator_get_optional(&pdev->dev, "vbus");
|
||||
if (IS_ERR(i2c->adap.bus_regulator)) {
|
||||
if (PTR_ERR(i2c->adap.bus_regulator) == -ENODEV)
|
||||
i2c->adap.bus_regulator = NULL;
|
||||
else
|
||||
return PTR_ERR(i2c->adap.bus_regulator);
|
||||
}
|
||||
|
||||
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
|
||||
if (ret)
|
||||
|
@ -1286,7 +1293,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
|
||||
I2C_DRV_NAME, i2c);
|
||||
dev_name(&pdev->dev), i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Request I2C IRQ %d fail\n", irq);
|
||||
|
|
|
@ -769,6 +769,7 @@ static const struct of_device_id cci_dt_match[] = {
|
|||
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
|
||||
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
|
||||
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
|
||||
{ .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cci_dt_match);
|
||||
|
|
|
@ -1013,7 +1013,6 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
|
|||
{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
|
||||
{ .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
|
||||
{ .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 },
|
||||
{ .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, /* Deprecated */
|
||||
{ .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 },
|
||||
{ .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 },
|
||||
{ .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 },
|
||||
|
|
|
@ -42,8 +42,10 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define RIIC_ICCR1 0x00
|
||||
#define RIIC_ICCR2 0x04
|
||||
|
@ -86,6 +88,11 @@
|
|||
|
||||
#define RIIC_INIT_MSG -1
|
||||
|
||||
enum riic_type {
|
||||
RIIC_RZ_A,
|
||||
RIIC_RZ_G2L,
|
||||
};
|
||||
|
||||
struct riic_dev {
|
||||
void __iomem *base;
|
||||
u8 *buf;
|
||||
|
@ -395,7 +402,9 @@ static int riic_i2c_probe(struct platform_device *pdev)
|
|||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
struct i2c_timings i2c_t;
|
||||
struct reset_control *rstc;
|
||||
int i, ret;
|
||||
enum riic_type type;
|
||||
|
||||
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
|
||||
if (!riic)
|
||||
|
@ -412,6 +421,17 @@ static int riic_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(riic->clk);
|
||||
}
|
||||
|
||||
type = (enum riic_type)of_device_get_match_data(&pdev->dev);
|
||||
if (type == RIIC_RZ_G2L) {
|
||||
rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rstc)) {
|
||||
dev_err(&pdev->dev, "Error: missing reset ctrl\n");
|
||||
return PTR_ERR(rstc);
|
||||
}
|
||||
|
||||
reset_control_deassert(rstc);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num);
|
||||
if (!res)
|
||||
|
@ -472,7 +492,8 @@ static int riic_i2c_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id riic_i2c_dt_ids[] = {
|
||||
{ .compatible = "renesas,riic-rz" },
|
||||
{ .compatible = "renesas,riic-r9a07g044", .data = (void *)RIIC_RZ_G2L },
|
||||
{ .compatible = "renesas,riic-rz", .data = (void *)RIIC_RZ_A },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
/* STM32F7 I2C control 1 */
|
||||
#define STM32F7_I2C_CR1_PECEN BIT(23)
|
||||
#define STM32F7_I2C_CR1_ALERTEN BIT(22)
|
||||
#define STM32F7_I2C_CR1_SMBHEN BIT(20)
|
||||
#define STM32F7_I2C_CR1_WUPEN BIT(18)
|
||||
#define STM32F7_I2C_CR1_SBC BIT(16)
|
||||
|
@ -125,6 +126,7 @@
|
|||
(((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
|
||||
#define STM32F7_I2C_ISR_DIR BIT(16)
|
||||
#define STM32F7_I2C_ISR_BUSY BIT(15)
|
||||
#define STM32F7_I2C_ISR_ALERT BIT(13)
|
||||
#define STM32F7_I2C_ISR_PECERR BIT(11)
|
||||
#define STM32F7_I2C_ISR_ARLO BIT(9)
|
||||
#define STM32F7_I2C_ISR_BERR BIT(8)
|
||||
|
@ -138,6 +140,7 @@
|
|||
#define STM32F7_I2C_ISR_TXE BIT(0)
|
||||
|
||||
/* STM32F7 I2C Interrupt Clear */
|
||||
#define STM32F7_I2C_ICR_ALERTCF BIT(13)
|
||||
#define STM32F7_I2C_ICR_PECCF BIT(11)
|
||||
#define STM32F7_I2C_ICR_ARLOCF BIT(9)
|
||||
#define STM32F7_I2C_ICR_BERRCF BIT(8)
|
||||
|
@ -278,6 +281,17 @@ struct stm32f7_i2c_msg {
|
|||
u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_alert - SMBus alert specific data
|
||||
* @setup: platform data for the smbus_alert i2c client
|
||||
* @ara: I2C slave device used to respond to the SMBus Alert with Alert
|
||||
* Response Address
|
||||
*/
|
||||
struct stm32f7_i2c_alert {
|
||||
struct i2c_smbus_alert_setup setup;
|
||||
struct i2c_client *ara;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_dev - private data of the controller
|
||||
* @adap: I2C adapter for this controller
|
||||
|
@ -310,6 +324,7 @@ struct stm32f7_i2c_msg {
|
|||
* @analog_filter: boolean to indicate enabling of the analog filter
|
||||
* @dnf_dt: value of digital filter requested via dt
|
||||
* @dnf: value of digital filter to apply
|
||||
* @alert: SMBus alert specific data
|
||||
*/
|
||||
struct stm32f7_i2c_dev {
|
||||
struct i2c_adapter adap;
|
||||
|
@ -341,6 +356,7 @@ struct stm32f7_i2c_dev {
|
|||
bool analog_filter;
|
||||
u32 dnf_dt;
|
||||
u32 dnf;
|
||||
struct stm32f7_i2c_alert *alert;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1624,6 +1640,13 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
|
|||
f7_msg->result = -EINVAL;
|
||||
}
|
||||
|
||||
if (status & STM32F7_I2C_ISR_ALERT) {
|
||||
dev_dbg(dev, "<%s>: SMBus alert received\n", __func__);
|
||||
writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
|
||||
i2c_handle_smbus_alert(i2c_dev->alert->ara);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (!i2c_dev->slave_running) {
|
||||
u32 mask;
|
||||
/* Disable interrupts */
|
||||
|
@ -1990,6 +2013,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
|
|||
}
|
||||
}
|
||||
|
||||
static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct stm32f7_i2c_alert *alert;
|
||||
struct i2c_adapter *adap = &i2c_dev->adap;
|
||||
struct device *dev = i2c_dev->dev;
|
||||
void __iomem *base = i2c_dev->base;
|
||||
|
||||
alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL);
|
||||
if (!alert)
|
||||
return -ENOMEM;
|
||||
|
||||
alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup);
|
||||
if (IS_ERR(alert->ara))
|
||||
return PTR_ERR(alert->ara);
|
||||
|
||||
i2c_dev->alert = alert;
|
||||
|
||||
/* Enable SMBus Alert */
|
||||
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct stm32f7_i2c_alert *alert = i2c_dev->alert;
|
||||
void __iomem *base = i2c_dev->base;
|
||||
|
||||
if (alert) {
|
||||
/* Disable SMBus Alert */
|
||||
stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_ALERTEN);
|
||||
i2c_unregister_device(alert->ara);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
|
@ -2173,6 +2232,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
|
||||
ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to enable SMBus alert protocol (%d)\n",
|
||||
ret);
|
||||
goto i2c_disable_smbus_host;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
|
||||
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
|
@ -2180,6 +2249,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
i2c_disable_smbus_host:
|
||||
stm32f7_i2c_disable_smbus_host(i2c_dev);
|
||||
|
||||
i2c_adapter_remove:
|
||||
i2c_del_adapter(adap);
|
||||
|
||||
|
@ -2214,6 +2286,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
stm32f7_i2c_disable_smbus_alert(i2c_dev);
|
||||
stm32f7_i2c_disable_smbus_host(i2c_dev);
|
||||
|
||||
i2c_del_adapter(&i2c_dev->adap);
|
||||
|
|
|
@ -798,11 +798,10 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
if (PTR_ERR(i2c->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(i2c->clk);
|
||||
}
|
||||
if (IS_ERR(i2c->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk),
|
||||
"input clock not found.\n");
|
||||
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -399,7 +400,8 @@ static int i2c_gpio_init_recovery(struct i2c_adapter *adap)
|
|||
static int i2c_init_recovery(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||
char *err_str, *err_level = KERN_ERR;
|
||||
bool is_error_level = true;
|
||||
char *err_str;
|
||||
|
||||
if (!bri)
|
||||
return 0;
|
||||
|
@ -409,7 +411,7 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
|
|||
|
||||
if (!bri->recover_bus) {
|
||||
err_str = "no suitable method provided";
|
||||
err_level = KERN_DEBUG;
|
||||
is_error_level = false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -436,7 +438,10 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
|
|||
|
||||
return 0;
|
||||
err:
|
||||
dev_printk(err_level, &adap->dev, "Not using recovery: %s\n", err_str);
|
||||
if (is_error_level)
|
||||
dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
|
||||
else
|
||||
dev_dbg(&adap->dev, "Not using recovery: %s\n", err_str);
|
||||
adap->bus_recovery_info = NULL;
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -461,12 +466,14 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
|
|||
static int i2c_device_probe(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_driver *driver;
|
||||
int status;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
adap = client->adapter;
|
||||
client->irq = client->init_irq;
|
||||
|
||||
if (!client->irq) {
|
||||
|
@ -532,6 +539,14 @@ static int i2c_device_probe(struct device *dev)
|
|||
|
||||
dev_dbg(dev, "probe\n");
|
||||
|
||||
if (adap->bus_regulator) {
|
||||
status = regulator_enable(adap->bus_regulator);
|
||||
if (status < 0) {
|
||||
dev_err(&adap->dev, "Failed to enable bus regulator\n");
|
||||
goto err_clear_wakeup_irq;
|
||||
}
|
||||
}
|
||||
|
||||
status = of_clk_set_defaults(dev->of_node, false);
|
||||
if (status < 0)
|
||||
goto err_clear_wakeup_irq;
|
||||
|
@ -589,8 +604,10 @@ put_sync_adapter:
|
|||
static int i2c_device_remove(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_driver *driver;
|
||||
|
||||
adap = client->adapter;
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (driver->remove) {
|
||||
int status;
|
||||
|
@ -605,6 +622,8 @@ static int i2c_device_remove(struct device *dev)
|
|||
devres_release_group(&client->dev, client->devres_group_id);
|
||||
|
||||
dev_pm_domain_detach(&client->dev, true);
|
||||
if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator)
|
||||
regulator_disable(adap->bus_regulator);
|
||||
|
||||
dev_pm_clear_wake_irq(&client->dev);
|
||||
device_init_wakeup(&client->dev, false);
|
||||
|
@ -617,6 +636,86 @@ static int i2c_device_remove(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int i2c_resume_early(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
int err;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (pm_runtime_status_suspended(&client->dev) &&
|
||||
client->adapter->bus_regulator) {
|
||||
err = regulator_enable(client->adapter->bus_regulator);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return pm_generic_resume_early(&client->dev);
|
||||
}
|
||||
|
||||
static int i2c_suspend_late(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
int err;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
err = pm_generic_suspend_late(&client->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!pm_runtime_status_suspended(&client->dev) &&
|
||||
client->adapter->bus_regulator)
|
||||
return regulator_disable(client->adapter->bus_regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
int err;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (client->adapter->bus_regulator) {
|
||||
err = regulator_enable(client->adapter->bus_regulator);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return pm_generic_runtime_resume(&client->dev);
|
||||
}
|
||||
|
||||
static int i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
int err;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
err = pm_generic_runtime_suspend(&client->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (client->adapter->bus_regulator)
|
||||
return regulator_disable(client->adapter->bus_regulator);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops i2c_device_pm = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(i2c_suspend_late, i2c_resume_early)
|
||||
SET_RUNTIME_PM_OPS(i2c_runtime_suspend, i2c_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static void i2c_device_shutdown(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
|
@ -627,6 +726,8 @@ static void i2c_device_shutdown(struct device *dev)
|
|||
driver = to_i2c_driver(dev->driver);
|
||||
if (driver->shutdown)
|
||||
driver->shutdown(client);
|
||||
else if (client->irq > 0)
|
||||
disable_irq(client->irq);
|
||||
}
|
||||
|
||||
static void i2c_client_dev_release(struct device *dev)
|
||||
|
@ -674,6 +775,7 @@ struct bus_type i2c_bus_type = {
|
|||
.probe = i2c_device_probe,
|
||||
.remove = i2c_device_remove,
|
||||
.shutdown = i2c_device_shutdown,
|
||||
.pm = &i2c_device_pm,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(i2c_bus_type);
|
||||
|
||||
|
|
|
@ -37,8 +37,15 @@ static u8 crc8(u16 data)
|
|||
return (u8)(data >> 8);
|
||||
}
|
||||
|
||||
/* Incremental CRC8 over count bytes in the array pointed to by p */
|
||||
static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
|
||||
/**
|
||||
* i2c_smbus_pec - Incremental CRC8 over the given input data array
|
||||
* @crc: previous return crc8 value
|
||||
* @p: pointer to data buffer.
|
||||
* @count: number of bytes in data buffer.
|
||||
*
|
||||
* Incremental CRC8 over count bytes in the array pointed to by p
|
||||
*/
|
||||
u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -46,6 +53,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
|
|||
crc = crc8((crc ^ p[i]) << 8);
|
||||
return crc;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_pec);
|
||||
|
||||
/* Assume a 7-bit address, which is reasonable for SMBus */
|
||||
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/device.h> /* for struct device */
|
||||
#include <linux/sched.h> /* for completion */
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/rtmutex.h>
|
||||
#include <linux/irqdomain.h> /* for Host Notify IRQ */
|
||||
#include <linux/of.h> /* for struct device_node */
|
||||
|
@ -147,6 +148,7 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|||
/* Now follow the 'nice' access routines. These also document the calling
|
||||
conventions of i2c_smbus_xfer. */
|
||||
|
||||
u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count);
|
||||
s32 i2c_smbus_read_byte(const struct i2c_client *client);
|
||||
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
|
||||
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
|
||||
|
@ -729,6 +731,7 @@ struct i2c_adapter {
|
|||
const struct i2c_adapter_quirks *quirks;
|
||||
|
||||
struct irq_domain *host_notify_domain;
|
||||
struct regulator *bus_regulator;
|
||||
};
|
||||
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
|
||||
|
||||
|
|
Loading…
Reference in New Issue