mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 02:15:57 +00:00
I2C core removes an argument from the i2c_mux_add_adapter() call to
further deprecate class based I2C device instantiation. All users are converted, too. Other that that, Andi collected a number if I2C host driver patches. Those merges have their own description. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmZLFfoACgkQFA3kzBSg KbaTlxAAq+VXWNEEK41X6SNVnzwm1H9zoq/vg92rQ1oKh/AUfO6W4pJTg3OQz0gT 4x5Z4yeRZwtWE7zdTQlQUdUvcj490cTUF9f7gTTeH0uhFCyECzOZSIpa4kG+A/mI JUCCVLMziq6rIscYFdomvKSzwitzhoCuLVsOthYgK3TvbbGH6FHe4h6MDP/u3ok7 seL7ZhqsudL26fFv5+U9095xM0OLDB1R7+DJXaibS6hY1/+WX3qMWHjCF7tf4gAr bHg/LaDNIiW2pwj7LFhaLrQzchxV/zPKRJYlO05M4mn9hxyVM9ztKtGPLRqglZEX yPqD857/Rac4y30PihWSVf4uG9pJWY0BEMjucuL0DZLX98C8kqJKK1SSi1FMd5qf ROAlCMQt+pSVcO6V9cEVIxzpJ2ZhAT4NM2T7yaGrdt6WX9W/an9hNqPcMUBVU6G2 Fzk960eftI/V+IRGswHuBD4w4duIlxUMWd5961UdI0LqzQrhzyNq3IZu/jpw49DH ZnJ/0UPkV9FfZvZpglf/ztlUESkCqWFjbxOfiejHCnUrvla5JGQTPXVTyP9p38X9 cxevlLgdsKz4F9WqEzpeI7L0HrxpTI863lmhFy+LuWYjYUfYSqIbiB0lWuCP+9Fy Cjnfp8KRp0lJD206Yyj4WC1B8xi1G44MkB2seGH7GtejM4I9A+U= =viLd -----END PGP SIGNATURE----- Merge tag 'i2c-for-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux Pull i2c updates from Wolfram Sang: "i2c core removes an argument from the i2c_mux_add_adapter() call to further deprecate class based I2C device instantiation. All users are converted, too. Other that that, Andi collected a number if I2C host driver patches. Those merges have their own description" * tag 'i2c-for-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (72 commits) power: supply: sbs-manager: Remove class argument from i2c_mux_add_adapter() i2c: mux: Remove class argument from i2c_mux_add_adapter() i2c: synquacer: Fix an error handling path in synquacer_i2c_probe() i2c: acpi: Unbind mux adapters before delete i2c: designware: Replace MODULE_ALIAS() with MODULE_DEVICE_TABLE() i2c: pxa: use 'time_left' variable with wait_event_timeout() i2c: s3c2410: use 'time_left' variable with wait_event_timeout() i2c: rk3x: use 'time_left' variable with wait_event_timeout() i2c: qcom-geni: use 'time_left' variable with wait_for_completion_timeout() i2c: jz4780: use 'time_left' variable with wait_for_completion_timeout() i2c: synquacer: use 'time_left' variable with wait_for_completion_timeout() i2c: stm32f7: use 'time_left' variable with wait_for_completion_timeout() i2c: stm32f4: use 'time_left' variable with wait_for_completion_timeout() i2c: st: use 'time_left' variable with wait_for_completion_timeout() i2c: omap: use 'time_left' variable with wait_for_completion_timeout() i2c: imx-lpi2c: use 'time_left' variable with wait_for_completion_timeout() i2c: hix5hd2: use 'time_left' variable with wait_for_completion_timeout() i2c: exynos5: use 'time_left' variable with wait_for_completion_timeout() i2c: digicolor: use 'time_left' variable with wait_for_completion_timeout() i2c: amd-mp2-plat: use 'time_left' variable with wait_for_completion_timeout() ...
This commit is contained in:
commit
0a07e09085
@ -1,34 +0,0 @@
|
||||
* NXP PNX I2C Controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- reg: Offset and length of the register set for the device
|
||||
- compatible: should be "nxp,pnx-i2c"
|
||||
- interrupts: configure one interrupt line
|
||||
- #address-cells: always 1 (for i2c addresses)
|
||||
- #size-cells: always 0
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz
|
||||
|
||||
Examples:
|
||||
|
||||
i2c1: i2c@400a0000 {
|
||||
compatible = "nxp,pnx-i2c";
|
||||
reg = <0x400a0000 0x100>;
|
||||
interrupt-parent = <&mic>;
|
||||
interrupts = <51 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
i2c2: i2c@400a8000 {
|
||||
compatible = "nxp,pnx-i2c";
|
||||
reg = <0x400a8000 0x100>;
|
||||
interrupt-parent = <&mic>;
|
||||
interrupts = <50 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
46
Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml
Normal file
46
Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP PNX I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Animesh Agarwal <animeshagarwal28@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,pnx-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
default: 100000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@400a0000 {
|
||||
compatible = "nxp,pnx-i2c";
|
||||
reg = <0x400a0000 0x100>;
|
||||
interrupt-parent = <&mic>;
|
||||
interrupts = <51 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -26,6 +26,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,sc7280-cci
|
||||
- qcom,sc8280xp-cci
|
||||
- qcom,sdm845-cci
|
||||
- qcom,sm6350-cci
|
||||
- qcom,sm8250-cci
|
||||
@ -176,6 +177,24 @@ allOf:
|
||||
- const: cci
|
||||
- const: cci_src
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8280xp-cci
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: camnoc_axi
|
||||
- const: slow_ahb_src
|
||||
- const: cpas_ahb
|
||||
- const: cci
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -15,14 +15,17 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,riic-r7s72100 # RZ/A1H
|
||||
- renesas,riic-r7s9210 # RZ/A2M
|
||||
- renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five
|
||||
- renesas,riic-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,riic-r9a07g054 # RZ/V2L
|
||||
- const: renesas,riic-rz # RZ/A or RZ/G2L
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,riic-r7s72100 # RZ/A1H
|
||||
- renesas,riic-r7s9210 # RZ/A2M
|
||||
- renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five
|
||||
- renesas,riic-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,riic-r9a07g054 # RZ/V2L
|
||||
- const: renesas,riic-rz # RZ/A or RZ/G2L
|
||||
|
||||
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
12
MAINTAINERS
12
MAINTAINERS
@ -2362,7 +2362,7 @@ M: Vladimir Zapolskiy <vz@mleia.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
T: git git://github.com/vzapolskiy/linux-lpc32xx.git
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-pnx.txt
|
||||
F: Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml
|
||||
F: arch/arm/boot/dts/nxp/lpc/lpc32*
|
||||
F: arch/arm/mach-lpc32xx/
|
||||
F: drivers/i2c/busses/i2c-pnx.c
|
||||
@ -3082,7 +3082,7 @@ S: Orphan
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-wmt.txt
|
||||
F: arch/arm/mach-vt8500/
|
||||
F: drivers/clocksource/timer-vt8500.c
|
||||
F: drivers/i2c/busses/i2c-wmt.c
|
||||
F: drivers/i2c/busses/i2c-viai2c-wmt.c
|
||||
F: drivers/mmc/host/wmt-sdmmc.c
|
||||
F: drivers/pwm/pwm-vt8500.c
|
||||
F: drivers/rtc/rtc-vt8500.c
|
||||
@ -10400,6 +10400,14 @@ L: linux-i2c@vger.kernel.org
|
||||
F: Documentation/i2c/busses/i2c-ismt.rst
|
||||
F: drivers/i2c/busses/i2c-ismt.c
|
||||
|
||||
I2C/SMBUS ZHAOXIN DRIVER
|
||||
M: Hans Hu <hanshu@zhaoxin.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://www.zhaoxin.com
|
||||
F: drivers/i2c/busses/i2c-viai2c-common.c
|
||||
F: drivers/i2c/busses/i2c-viai2c-zhaoxin.c
|
||||
|
||||
I2C/SMBUS STUB DRIVER
|
||||
M: Jean Delvare <jdelvare@suse.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
|
@ -1092,7 +1092,7 @@ static int sii902x_init(struct sii902x *sii902x)
|
||||
}
|
||||
|
||||
sii902x->i2cmux->priv = sii902x;
|
||||
ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0);
|
||||
if (ret)
|
||||
goto err_unreg_audio;
|
||||
|
||||
|
@ -18,7 +18,7 @@ config I2C_CCGX_UCSI
|
||||
|
||||
config I2C_ALI1535
|
||||
tristate "ALI 1535"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the SMB
|
||||
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
|
||||
@ -30,7 +30,7 @@ config I2C_ALI1535
|
||||
|
||||
config I2C_ALI1563
|
||||
tristate "ALI 1563"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the SMB
|
||||
Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
|
||||
@ -42,7 +42,7 @@ config I2C_ALI1563
|
||||
|
||||
config I2C_ALI15X3
|
||||
tristate "ALI 15x3"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
|
||||
@ -52,7 +52,7 @@ config I2C_ALI15X3
|
||||
|
||||
config I2C_AMD756
|
||||
tristate "AMD 756/766/768/8111 and nVidia nForce"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the AMD
|
||||
756/766/768 mainboard I2C interfaces. The driver also includes
|
||||
@ -77,7 +77,7 @@ config I2C_AMD756_S4882
|
||||
|
||||
config I2C_AMD8111
|
||||
tristate "AMD 8111"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
|
||||
@ -107,7 +107,7 @@ config I2C_HIX5HD2
|
||||
|
||||
config I2C_I801
|
||||
tristate "Intel 82801 (ICH/PCH)"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
select P2SB if X86
|
||||
select CHECK_SIGNATURE if X86 && DMI
|
||||
select I2C_SMBUS
|
||||
@ -163,9 +163,17 @@ config I2C_I801
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
||||
config I2C_I801_MUX
|
||||
def_bool I2C_I801
|
||||
depends on DMI && I2C_MUX_GPIO
|
||||
depends on !(I2C_I801=y && I2C_MUX=m)
|
||||
help
|
||||
Optional support for multiplexed SMBUS on certain systems with
|
||||
more than 8 memory slots.
|
||||
|
||||
config I2C_ISCH
|
||||
tristate "Intel SCH SMBus 1.0"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
select LPC_SCH
|
||||
help
|
||||
Say Y here if you want to use SMBus controller on the Intel SCH
|
||||
@ -186,7 +194,7 @@ config I2C_ISMT
|
||||
|
||||
config I2C_PIIX4
|
||||
tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
PIIX4 family of mainboard I2C interfaces. Specifically, the following
|
||||
@ -232,7 +240,7 @@ config I2C_CHT_WC
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Nvidia
|
||||
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
|
||||
@ -265,7 +273,7 @@ config I2C_NVIDIA_GPU
|
||||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
@ -275,7 +283,7 @@ config I2C_SIS5595
|
||||
|
||||
config I2C_SIS630
|
||||
tristate "SiS 630/730/964"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface.
|
||||
@ -285,7 +293,7 @@ config I2C_SIS630
|
||||
|
||||
config I2C_SIS96X
|
||||
tristate "SiS 96x"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the SiS
|
||||
96x SMBus (a subset of I2C) interfaces. Specifically, the following
|
||||
@ -303,7 +311,7 @@ config I2C_SIS96X
|
||||
|
||||
config I2C_VIA
|
||||
tristate "VIA VT82C586B"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
@ -314,7 +322,7 @@ config I2C_VIA
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
VT82C596 and later SMBus interface. Specifically, the following
|
||||
@ -336,6 +344,16 @@ config I2C_VIAPRO
|
||||
|
||||
if ACPI
|
||||
|
||||
config I2C_ZHAOXIN
|
||||
tristate "Zhaoxin I2C Interface"
|
||||
depends on PCI || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
ZHAOXIN I2C interface
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-zhaoxin.
|
||||
|
||||
comment "ACPI drivers"
|
||||
|
||||
config I2C_SCMI
|
||||
@ -500,7 +518,7 @@ config I2C_BRCMSTB
|
||||
|
||||
config I2C_CADENCE
|
||||
tristate "Cadence I2C Controller"
|
||||
depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST
|
||||
depends on ARCH_ZYNQ || ARM64 || XTENSA || RISCV || COMPILE_TEST
|
||||
help
|
||||
Say yes here to select Cadence I2C Host Controller. This controller is
|
||||
e.g. used by Xilinx Zynq.
|
||||
@ -1397,6 +1415,7 @@ config I2C_ICY
|
||||
config I2C_MLXCPLD
|
||||
tristate "Mellanox I2C driver"
|
||||
depends on X86_64 || (ARM64 && ACPI) || COMPILE_TEST
|
||||
depends on HAS_IOPORT
|
||||
help
|
||||
This exposes the Mellanox platform I2C busses to the linux I2C layer
|
||||
for X86 and ARM64/ACPI based systems.
|
||||
|
@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
|
||||
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
|
||||
obj-$(CONFIG_I2C_VIA) += i2c-via.o
|
||||
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
|
||||
i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
|
||||
obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o
|
||||
|
||||
# Mac SMBus host controller drivers
|
||||
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
|
||||
@ -118,6 +120,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o
|
||||
obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
|
||||
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
|
||||
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
|
||||
i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
|
||||
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
|
||||
i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
|
||||
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
|
||||
|
@ -285,10 +285,8 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout > MAX_TIMEOUT) {
|
||||
if (timeout > MAX_TIMEOUT)
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "SMBus Timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & ALI1535_STS_FAIL) {
|
||||
result = -EIO;
|
||||
@ -313,10 +311,8 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
||||
}
|
||||
|
||||
/* check to see if the "command complete" indication is set */
|
||||
if (!(temp & ALI1535_STS_DONE)) {
|
||||
if (!(temp & ALI1535_STS_DONE))
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "Error: command never completed\n");
|
||||
}
|
||||
|
||||
dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, "
|
||||
"CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
|
||||
|
@ -99,7 +99,6 @@ static int ali1563_transaction(struct i2c_adapter *a, int size)
|
||||
return 0;
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
|
||||
/* Issue 'kill' to host controller */
|
||||
outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2);
|
||||
data = inb_p(SMB_HST_STS);
|
||||
|
@ -294,10 +294,8 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout > MAX_TIMEOUT) {
|
||||
if (timeout > MAX_TIMEOUT)
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "SMBus Timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & ALI15X3_STS_TERM) {
|
||||
result = -EIO;
|
||||
|
@ -97,17 +97,17 @@ static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common)
|
||||
static int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct amd_i2c_common *i2c_common = &i2c_dev->common;
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->cmd_complete,
|
||||
i2c_dev->adap.timeout);
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->cmd_complete,
|
||||
i2c_dev->adap.timeout);
|
||||
|
||||
if ((i2c_common->reqcmd == i2c_read ||
|
||||
i2c_common->reqcmd == i2c_write) &&
|
||||
i2c_common->msg->len > 32)
|
||||
i2c_amd_dma_unmap(i2c_common);
|
||||
|
||||
if (timeout == 0) {
|
||||
if (time_left == 0) {
|
||||
amd_mp2_rw_timeout(i2c_common);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -591,7 +591,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||||
dev->adapter.timeout);
|
||||
if (time_left == 0) {
|
||||
dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR);
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
at91_init_twi_bus(dev);
|
||||
ret = -ETIMEDOUT;
|
||||
goto error;
|
||||
|
@ -811,8 +811,6 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
}
|
||||
|
||||
if (!time_left && !iproc_i2c->xfer_is_done) {
|
||||
dev_err(iproc_i2c->device, "transaction timed out\n");
|
||||
|
||||
/* flush both TX/RX FIFOs */
|
||||
val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
|
||||
|
@ -370,7 +370,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
if (!time_left) {
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
|
||||
BCM2835_I2C_C_CLEAR);
|
||||
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -633,6 +633,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
|
||||
|
||||
if (hold_clear) {
|
||||
ctrl_reg &= ~CDNS_I2C_CR_HOLD;
|
||||
ctrl_reg &= ~CDNS_I2C_CR_CLR_FIFO;
|
||||
/*
|
||||
* 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
|
||||
@ -789,8 +790,6 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
||||
time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
|
||||
if (time_left == 0) {
|
||||
cdns_i2c_master_reset(adap);
|
||||
dev_err(id->adap.dev.parent,
|
||||
"timeout waiting on completion\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
||||
time_left = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
dev->adapter.timeout);
|
||||
if (!time_left) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
i2c_recover_bus(adap);
|
||||
dev->buf_len = 0;
|
||||
return -ETIMEDOUT;
|
||||
|
@ -424,8 +424,6 @@ static struct pci_driver dw_i2c_driver = {
|
||||
};
|
||||
module_pci_driver(dw_i2c_driver);
|
||||
|
||||
/* Work with hotplug and coldplug */
|
||||
MODULE_ALIAS("i2c_designware-pci");
|
||||
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -46,6 +46,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
||||
{ "INT33C3", 0 },
|
||||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "INTC10EF", 0 },
|
||||
{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
|
||||
{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
|
||||
{ "AMD0010", ACCESS_INTR_MASK },
|
||||
@ -479,8 +480,11 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
|
||||
RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
/* Work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:i2c_designware");
|
||||
static const struct platform_device_id dw_i2c_platform_ids[] = {
|
||||
{ "i2c_designware" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids);
|
||||
|
||||
static struct platform_driver dw_i2c_driver = {
|
||||
.probe = dw_i2c_plat_probe,
|
||||
@ -491,6 +495,7 @@ static struct platform_driver dw_i2c_driver = {
|
||||
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
|
||||
.pm = pm_ptr(&dw_i2c_dev_pm_ops),
|
||||
},
|
||||
.id_table = dw_i2c_platform_ids,
|
||||
};
|
||||
|
||||
static int __init dw_i2c_init_driver(void)
|
||||
|
@ -213,7 +213,7 @@ out:
|
||||
static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
|
||||
int last)
|
||||
{
|
||||
unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
|
||||
unsigned long time_left = msecs_to_jiffies(TIMEOUT_MS);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
@ -227,9 +227,9 @@ static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
|
||||
dc_i2c_start_msg(i2c, first);
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c->done, timeout);
|
||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
||||
dc_i2c_set_irq(i2c, 0);
|
||||
if (timeout == 0) {
|
||||
if (time_left == 0) {
|
||||
i2c->state = STATE_IDLE;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -763,7 +763,7 @@ static bool exynos5_i2c_poll_irqs_timeout(struct exynos5_i2c *i2c,
|
||||
static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||
struct i2c_msg *msgs, int stop)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
i2c->msg = msgs;
|
||||
@ -775,13 +775,13 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||
exynos5_i2c_message_start(i2c, stop);
|
||||
|
||||
if (!i2c->atomic)
|
||||
timeout = wait_for_completion_timeout(&i2c->msg_complete,
|
||||
EXYNOS5_I2C_TIMEOUT);
|
||||
else
|
||||
timeout = exynos5_i2c_poll_irqs_timeout(i2c,
|
||||
time_left = wait_for_completion_timeout(&i2c->msg_complete,
|
||||
EXYNOS5_I2C_TIMEOUT);
|
||||
else
|
||||
time_left = exynos5_i2c_poll_irqs_timeout(i2c,
|
||||
EXYNOS5_I2C_TIMEOUT);
|
||||
|
||||
if (timeout == 0)
|
||||
if (time_left == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
ret = i2c->state;
|
||||
|
@ -314,7 +314,7 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop)
|
||||
static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
|
||||
struct i2c_msg *msgs, int stop)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
priv->msg = msgs;
|
||||
@ -327,9 +327,9 @@ static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
|
||||
reinit_completion(&priv->msg_complete);
|
||||
hix5hd2_i2c_message_start(priv, stop);
|
||||
|
||||
timeout = wait_for_completion_timeout(&priv->msg_complete,
|
||||
priv->adap.timeout);
|
||||
if (timeout == 0) {
|
||||
time_left = wait_for_completion_timeout(&priv->msg_complete,
|
||||
priv->adap.timeout);
|
||||
if (time_left == 0) {
|
||||
priv->state = HIX5I2C_STAT_RW_ERR;
|
||||
priv->err = -ETIMEDOUT;
|
||||
dev_warn(priv->dev, "%s timeout=%d\n",
|
||||
|
@ -105,6 +105,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
@ -119,7 +120,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
|
||||
#ifdef CONFIG_I2C_I801_MUX
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_data/i2c-mux-gpio.h>
|
||||
#endif
|
||||
@ -263,7 +264,6 @@ struct i801_mux_config {
|
||||
char *gpio_chip;
|
||||
unsigned values[3];
|
||||
int n_values;
|
||||
unsigned classes[3];
|
||||
unsigned gpios[2]; /* Relative to gpio_chip->base */
|
||||
int n_gpios;
|
||||
};
|
||||
@ -288,9 +288,10 @@ struct i801_priv {
|
||||
int len;
|
||||
u8 *data;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
|
||||
#ifdef CONFIG_I2C_I801_MUX
|
||||
struct platform_device *mux_pdev;
|
||||
struct gpiod_lookup_table *lookup;
|
||||
struct notifier_block mux_notifier_block;
|
||||
#endif
|
||||
struct platform_device *tco_pdev;
|
||||
|
||||
@ -398,9 +399,7 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
||||
* If the SMBus is still busy, we give up
|
||||
*/
|
||||
if (unlikely(status < 0)) {
|
||||
dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
|
||||
/* try to stop the current command */
|
||||
dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
|
||||
outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
|
||||
usleep_range(1000, 2000);
|
||||
outb_p(0, SMBHSTCNT(priv));
|
||||
@ -409,7 +408,7 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
if ((status & SMBHSTSTS_HOST_BUSY) ||
|
||||
!(status & SMBHSTSTS_FAILED))
|
||||
dev_err(&priv->pci_dev->dev,
|
||||
dev_dbg(&priv->pci_dev->dev,
|
||||
"Failed terminating the transaction\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -1059,7 +1058,7 @@ static const struct pci_device_id i801_ids[] = {
|
||||
MODULE_DEVICE_TABLE(pci, i801_ids);
|
||||
|
||||
#if defined CONFIG_X86 && defined CONFIG_DMI
|
||||
static unsigned char apanel_addr;
|
||||
static unsigned char apanel_addr __ro_after_init;
|
||||
|
||||
/* Scan the system ROM for the signature "FJKEYINF" */
|
||||
static __init const void __iomem *bios_signature(const void __iomem *bios)
|
||||
@ -1298,7 +1297,7 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
|
||||
register_dell_lis3lv02d_i2c_device(priv);
|
||||
|
||||
/* Instantiate SPD EEPROMs unless the SMBus is multiplexed */
|
||||
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO)
|
||||
#ifdef CONFIG_I2C_I801_MUX
|
||||
if (!priv->mux_pdev)
|
||||
#endif
|
||||
i2c_register_spd(&priv->adapter);
|
||||
@ -1308,12 +1307,11 @@ static void __init input_apanel_init(void) {}
|
||||
static void i801_probe_optional_slaves(struct i801_priv *priv) {}
|
||||
#endif /* CONFIG_X86 && CONFIG_DMI */
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
|
||||
#ifdef CONFIG_I2C_I801_MUX
|
||||
static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
|
||||
.gpio_chip = "gpio_ich",
|
||||
.values = { 0x02, 0x03 },
|
||||
.n_values = 2,
|
||||
.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
|
||||
.gpios = { 52, 53 },
|
||||
.n_gpios = 2,
|
||||
};
|
||||
@ -1322,7 +1320,6 @@ static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
|
||||
.gpio_chip = "gpio_ich",
|
||||
.values = { 0x02, 0x03, 0x01 },
|
||||
.n_values = 3,
|
||||
.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
|
||||
.gpios = { 52, 53 },
|
||||
.n_gpios = 2,
|
||||
};
|
||||
@ -1394,6 +1391,23 @@ static const struct dmi_system_id mux_dmi_table[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static int i801_notifier_call(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct i801_priv *priv = container_of(nb, struct i801_priv, mux_notifier_block);
|
||||
struct device *dev = data;
|
||||
|
||||
if (action != BUS_NOTIFY_ADD_DEVICE ||
|
||||
dev->type != &i2c_adapter_type ||
|
||||
i2c_root_adapter(dev) != &priv->adapter)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Call i2c_register_spd for muxed child segments */
|
||||
i2c_register_spd(to_i2c_adapter(dev));
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/* Setup multiplexing if needed */
|
||||
static void i801_add_mux(struct i801_priv *priv)
|
||||
{
|
||||
@ -1415,7 +1429,6 @@ static void i801_add_mux(struct i801_priv *priv)
|
||||
gpio_data.parent = priv->adapter.nr;
|
||||
gpio_data.values = mux_config->values;
|
||||
gpio_data.n_values = mux_config->n_values;
|
||||
gpio_data.classes = mux_config->classes;
|
||||
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
|
||||
|
||||
/* Register GPIO descriptor lookup table */
|
||||
@ -1430,6 +1443,9 @@ static void i801_add_mux(struct i801_priv *priv)
|
||||
mux_config->gpios[i], "mux", 0);
|
||||
gpiod_add_lookup_table(lookup);
|
||||
|
||||
priv->mux_notifier_block.notifier_call = i801_notifier_call;
|
||||
if (bus_register_notifier(&i2c_bus_type, &priv->mux_notifier_block))
|
||||
return;
|
||||
/*
|
||||
* Register the mux device, we use PLATFORM_DEVID_NONE here
|
||||
* because since we are referring to the GPIO chip by name we are
|
||||
@ -1451,6 +1467,7 @@ static void i801_add_mux(struct i801_priv *priv)
|
||||
|
||||
static void i801_del_mux(struct i801_priv *priv)
|
||||
{
|
||||
bus_unregister_notifier(&i2c_bus_type, &priv->mux_notifier_block);
|
||||
platform_device_unregister(priv->mux_pdev);
|
||||
gpiod_remove_lookup_table(priv->lookup);
|
||||
}
|
||||
|
@ -1124,11 +1124,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
IMG_I2C_TIMEOUT);
|
||||
del_timer_sync(&i2c->check_timer);
|
||||
|
||||
if (time_left == 0) {
|
||||
dev_err(adap->dev.parent, "i2c transfer timed out\n");
|
||||
if (time_left == 0)
|
||||
i2c->msg_status = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i2c->msg_status)
|
||||
break;
|
||||
|
@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
|
||||
__u8 *rx_buf;
|
||||
__u8 *tx_buf;
|
||||
struct completion complete;
|
||||
unsigned long rate_per;
|
||||
unsigned int msglen;
|
||||
unsigned int delivered;
|
||||
unsigned int block_data;
|
||||
@ -212,9 +213,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
|
||||
|
||||
lpi2c_imx_set_mode(lpi2c_imx);
|
||||
|
||||
clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
|
||||
if (!clk_rate)
|
||||
return -EINVAL;
|
||||
clk_rate = lpi2c_imx->rate_per;
|
||||
|
||||
if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
|
||||
filt = 0;
|
||||
@ -308,11 +307,11 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
|
||||
|
||||
static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
|
||||
timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ);
|
||||
time_left = wait_for_completion_timeout(&lpi2c_imx->complete, HZ);
|
||||
|
||||
return timeout ? 0 : -ETIMEDOUT;
|
||||
return time_left ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
|
||||
@ -611,6 +610,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Lock the parent clock rate to avoid getting parent clock upon
|
||||
* each transfer
|
||||
*/
|
||||
ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't lock I2C peripheral clock rate\n");
|
||||
|
||||
lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk);
|
||||
if (!lpi2c_imx->rate_per)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"can't get I2C peripheral clock rate\n");
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
@ -623,7 +623,6 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
|
||||
dma_unmap_single(dev, dma_addr, dma_size, dma_direction);
|
||||
|
||||
if (unlikely(!time_left)) {
|
||||
dev_err(dev, "completion wait timed out\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
|
||||
int idx)
|
||||
{
|
||||
int ret = 0;
|
||||
long timeout;
|
||||
unsigned long time_left;
|
||||
int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
|
||||
unsigned short tmp;
|
||||
unsigned long flags;
|
||||
@ -600,10 +600,10 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||
msecs_to_jiffies(wait_time));
|
||||
time_left = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||
msecs_to_jiffies(wait_time));
|
||||
|
||||
if (!timeout) {
|
||||
if (!time_left) {
|
||||
dev_err(&i2c->adap.dev, "irq read timeout\n");
|
||||
dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n",
|
||||
i2c->cmd, i2c->cmd_buf[i2c->cmd]);
|
||||
@ -627,7 +627,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
||||
{
|
||||
int ret = 0;
|
||||
int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
|
||||
long timeout;
|
||||
unsigned long time_left;
|
||||
unsigned short tmp;
|
||||
unsigned long flags;
|
||||
|
||||
@ -655,14 +655,14 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||
msecs_to_jiffies(wait_time));
|
||||
if (timeout && !i2c->stop_hold) {
|
||||
time_left = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||
msecs_to_jiffies(wait_time));
|
||||
if (time_left && !i2c->stop_hold) {
|
||||
unsigned short i2c_sta;
|
||||
int write_in_process;
|
||||
|
||||
timeout = JZ4780_I2C_TIMEOUT * 100;
|
||||
for (; timeout > 0; timeout--) {
|
||||
time_left = JZ4780_I2C_TIMEOUT * 100;
|
||||
for (; time_left > 0; time_left--) {
|
||||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||
|
||||
write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) ||
|
||||
@ -673,7 +673,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
||||
}
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
if (!time_left) {
|
||||
dev_err(&i2c->adap.dev, "write wait timeout\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
@ -304,13 +304,12 @@ static void mpc_i2c_setup_512x(struct device_node *node,
|
||||
struct mpc_i2c *i2c,
|
||||
u32 clock)
|
||||
{
|
||||
struct device_node *node_ctrl;
|
||||
void __iomem *ctrl;
|
||||
u32 idx;
|
||||
|
||||
/* Enable I2C interrupts for mpc5121 */
|
||||
node_ctrl = of_find_compatible_node(NULL, NULL,
|
||||
"fsl,mpc5121-i2c-ctrl");
|
||||
struct device_node *node_ctrl __free(device_node) =
|
||||
of_find_compatible_node(NULL, NULL, "fsl,mpc5121-i2c-ctrl");
|
||||
if (node_ctrl) {
|
||||
ctrl = of_iomap(node_ctrl, 0);
|
||||
if (ctrl) {
|
||||
@ -321,7 +320,6 @@ static void mpc_i2c_setup_512x(struct device_node *node,
|
||||
setbits32(ctrl, 1 << (24 + idx * 2));
|
||||
iounmap(ctrl);
|
||||
}
|
||||
of_node_put(node_ctrl);
|
||||
}
|
||||
|
||||
/* The clock setup for the 52xx works also fine for the 512x */
|
||||
@ -358,11 +356,11 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
|
||||
|
||||
static u32 mpc_i2c_get_sec_cfg_8xxx(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
u32 __iomem *reg;
|
||||
u32 val = 0;
|
||||
|
||||
node = of_find_node_by_name(NULL, "global-utilities");
|
||||
struct device_node *node __free(device_node) =
|
||||
of_find_node_by_name(NULL, "global-utilities");
|
||||
if (node) {
|
||||
const u32 *prop = of_get_property(node, "reg", NULL);
|
||||
if (prop) {
|
||||
@ -383,7 +381,6 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
|
||||
iounmap(reg);
|
||||
}
|
||||
}
|
||||
of_node_put(node);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -542,12 +542,9 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
|
||||
|
||||
xfer_done = nmk_i2c_wait_xfer_done(priv);
|
||||
|
||||
if (!xfer_done) {
|
||||
/* Controller timed out */
|
||||
dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n",
|
||||
priv->cli.slave_adr);
|
||||
if (!xfer_done)
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
*/
|
||||
struct ocores_i2c {
|
||||
void __iomem *base;
|
||||
int iobase;
|
||||
u32 reg_shift;
|
||||
u32 reg_io_width;
|
||||
unsigned long flags;
|
||||
@ -136,16 +135,6 @@ static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
|
||||
return ioread32be(i2c->base + (reg << i2c->reg_shift));
|
||||
}
|
||||
|
||||
static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value)
|
||||
{
|
||||
outb(value, i2c->iobase + reg);
|
||||
}
|
||||
|
||||
static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg)
|
||||
{
|
||||
return inb(i2c->iobase + reg);
|
||||
}
|
||||
|
||||
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
|
||||
{
|
||||
i2c->setreg(i2c, reg, value);
|
||||
@ -618,15 +607,19 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
i2c->iobase = res->start;
|
||||
if (!devm_request_region(&pdev->dev, res->start,
|
||||
resource_size(res),
|
||||
pdev->name)) {
|
||||
dev_err(&pdev->dev, "Can't get I/O resource.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
i2c->setreg = oc_setreg_io_8;
|
||||
i2c->getreg = oc_getreg_io_8;
|
||||
i2c->base = devm_ioport_map(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!i2c->base) {
|
||||
dev_err(&pdev->dev, "Can't map I/O resource.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
i2c->reg_io_width = 1;
|
||||
}
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
@ -17,9 +17,14 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "i2c-octeon-core.h"
|
||||
|
||||
#define INITIAL_DELTA_HZ 1000000
|
||||
#define TWSI_MASTER_CLK_REG_DEF_VAL 0x18
|
||||
#define TWSI_MASTER_CLK_REG_OTX2_VAL 0x3
|
||||
|
||||
/* interrupt service routine */
|
||||
irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
|
||||
{
|
||||
@ -80,7 +85,7 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
|
||||
|
||||
static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
|
||||
{
|
||||
return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0;
|
||||
return (__raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)) & SW_TWSI_V) == 0;
|
||||
}
|
||||
|
||||
static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
|
||||
@ -177,13 +182,14 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
|
||||
static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
|
||||
{
|
||||
u8 stat;
|
||||
u64 mode;
|
||||
|
||||
/*
|
||||
* This is ugly... in HLC mode the status is not in the status register
|
||||
* but in the lower 8 bits of SW_TWSI.
|
||||
* but in the lower 8 bits of OCTEON_REG_SW_TWSI.
|
||||
*/
|
||||
if (i2c->hlc_enabled)
|
||||
stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
stat = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
else
|
||||
stat = octeon_i2c_stat_read(i2c);
|
||||
|
||||
@ -239,6 +245,13 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
|
||||
case STAT_RXADDR_NAK:
|
||||
case STAT_AD2W_NAK:
|
||||
return -ENXIO;
|
||||
|
||||
case STAT_WDOG_TOUT:
|
||||
mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c));
|
||||
/* Set BUS_MON_RST to reset bus monitor */
|
||||
mode |= BUS_MON_RST_MASK;
|
||||
octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c));
|
||||
return -EIO;
|
||||
default:
|
||||
dev_err(i2c->dev, "unhandled state: %d\n", stat);
|
||||
return -EIO;
|
||||
@ -419,12 +432,12 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
else
|
||||
cmd |= SW_TWSI_OP_7;
|
||||
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if ((cmd & SW_TWSI_R) == 0)
|
||||
return octeon_i2c_check_status(i2c, false);
|
||||
|
||||
@ -432,7 +445,7 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
|
||||
|
||||
if (msgs[0].len > 4) {
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
|
||||
msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
|
||||
}
|
||||
@ -469,15 +482,15 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
|
||||
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
|
||||
ext |= (u64)msgs[0].buf[j] << (8 * i);
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
}
|
||||
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if ((cmd & SW_TWSI_R) == 0)
|
||||
return octeon_i2c_check_status(i2c, false);
|
||||
|
||||
@ -510,19 +523,19 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
|
||||
cmd |= SW_TWSI_EIA;
|
||||
ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
} else {
|
||||
cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
}
|
||||
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if ((cmd & SW_TWSI_R) == 0)
|
||||
return octeon_i2c_check_status(i2c, false);
|
||||
|
||||
@ -530,7 +543,7 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
|
||||
msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
|
||||
|
||||
if (msgs[1].len > 4) {
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
|
||||
msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
|
||||
}
|
||||
@ -577,16 +590,16 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
|
||||
set_ext = true;
|
||||
}
|
||||
if (set_ext)
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if ((cmd & SW_TWSI_R) == 0)
|
||||
return octeon_i2c_check_status(i2c, false);
|
||||
|
||||
@ -607,25 +620,27 @@ int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
|
||||
int i, ret = 0;
|
||||
|
||||
if (num == 1) {
|
||||
if (msgs[0].len > 0 && msgs[0].len <= 8) {
|
||||
if (msgs[0].flags & I2C_M_RD)
|
||||
ret = octeon_i2c_hlc_read(i2c, msgs);
|
||||
else
|
||||
ret = octeon_i2c_hlc_write(i2c, msgs);
|
||||
goto out;
|
||||
}
|
||||
} else if (num == 2) {
|
||||
if ((msgs[0].flags & I2C_M_RD) == 0 &&
|
||||
(msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
|
||||
msgs[0].len > 0 && msgs[0].len <= 2 &&
|
||||
msgs[1].len > 0 && msgs[1].len <= 8 &&
|
||||
msgs[0].addr == msgs[1].addr) {
|
||||
if (msgs[1].flags & I2C_M_RD)
|
||||
ret = octeon_i2c_hlc_comp_read(i2c, msgs);
|
||||
else
|
||||
ret = octeon_i2c_hlc_comp_write(i2c, msgs);
|
||||
goto out;
|
||||
if (IS_LS_FREQ(i2c->twsi_freq)) {
|
||||
if (num == 1) {
|
||||
if (msgs[0].len > 0 && msgs[0].len <= 8) {
|
||||
if (msgs[0].flags & I2C_M_RD)
|
||||
ret = octeon_i2c_hlc_read(i2c, msgs);
|
||||
else
|
||||
ret = octeon_i2c_hlc_write(i2c, msgs);
|
||||
goto out;
|
||||
}
|
||||
} else if (num == 2) {
|
||||
if ((msgs[0].flags & I2C_M_RD) == 0 &&
|
||||
(msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
|
||||
msgs[0].len > 0 && msgs[0].len <= 2 &&
|
||||
msgs[1].len > 0 && msgs[1].len <= 8 &&
|
||||
msgs[0].addr == msgs[1].addr) {
|
||||
if (msgs[1].flags & I2C_M_RD)
|
||||
ret = octeon_i2c_hlc_comp_read(i2c, msgs);
|
||||
else
|
||||
ret = octeon_i2c_hlc_comp_write(i2c, msgs);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -658,31 +673,64 @@ out:
|
||||
void octeon_i2c_set_clock(struct octeon_i2c *i2c)
|
||||
{
|
||||
int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
|
||||
int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
|
||||
bool is_plat_otx2;
|
||||
/*
|
||||
* Find divisors to produce target frequency, start with large delta
|
||||
* to cover wider range of divisors, note thp = TCLK half period and
|
||||
* ds is OSCL output frequency divisor.
|
||||
*/
|
||||
unsigned int thp, mdiv_min, mdiv = 2, ndiv = 0, ds = 10;
|
||||
unsigned int delta_hz = INITIAL_DELTA_HZ;
|
||||
|
||||
is_plat_otx2 = octeon_i2c_is_otx2(to_pci_dev(i2c->dev));
|
||||
|
||||
if (is_plat_otx2) {
|
||||
thp = TWSI_MASTER_CLK_REG_OTX2_VAL;
|
||||
mdiv_min = 0;
|
||||
if (!IS_LS_FREQ(i2c->twsi_freq))
|
||||
ds = 15;
|
||||
} else {
|
||||
thp = TWSI_MASTER_CLK_REG_DEF_VAL;
|
||||
mdiv_min = 2;
|
||||
}
|
||||
|
||||
for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
|
||||
/*
|
||||
* An mdiv value of less than 2 seems to not work well
|
||||
* with ds1337 RTCs, so we constrain it to larger values.
|
||||
*/
|
||||
for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
|
||||
for (mdiv_idx = 15; mdiv_idx >= mdiv_min && delta_hz != 0; mdiv_idx--) {
|
||||
/*
|
||||
* For given ndiv and mdiv values check the
|
||||
* two closest thp values.
|
||||
*/
|
||||
tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
|
||||
tclk = i2c->twsi_freq * (mdiv_idx + 1) * ds;
|
||||
tclk *= (1 << ndiv_idx);
|
||||
thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
|
||||
if (is_plat_otx2)
|
||||
thp_base = (i2c->sys_freq / tclk) - 2;
|
||||
else
|
||||
thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
|
||||
|
||||
for (inc = 0; inc <= 1; inc++) {
|
||||
thp_idx = thp_base + inc;
|
||||
if (thp_idx < 5 || thp_idx > 0xff)
|
||||
continue;
|
||||
|
||||
foscl = i2c->sys_freq / (2 * (thp_idx + 1));
|
||||
if (is_plat_otx2)
|
||||
foscl = i2c->sys_freq / (thp_idx + 2);
|
||||
else
|
||||
foscl = i2c->sys_freq /
|
||||
(2 * (thp_idx + 1));
|
||||
foscl = foscl / (1 << ndiv_idx);
|
||||
foscl = foscl / (mdiv_idx + 1) / 10;
|
||||
foscl = foscl / (mdiv_idx + 1) / ds;
|
||||
if (foscl > i2c->twsi_freq)
|
||||
continue;
|
||||
diff = abs(foscl - i2c->twsi_freq);
|
||||
/*
|
||||
* Diff holds difference between calculated frequency
|
||||
* value vs desired frequency.
|
||||
* Delta_hz is updated with last minimum diff.
|
||||
*/
|
||||
if (diff < delta_hz) {
|
||||
delta_hz = diff;
|
||||
thp = thp_idx;
|
||||
@ -694,6 +742,17 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c)
|
||||
}
|
||||
octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp);
|
||||
octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
|
||||
if (is_plat_otx2) {
|
||||
u64 mode;
|
||||
|
||||
mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c));
|
||||
/* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */
|
||||
if (!IS_LS_FREQ(i2c->twsi_freq))
|
||||
mode |= TWSX_MODE_HS_MASK;
|
||||
else
|
||||
mode &= ~TWSX_MODE_HS_MASK;
|
||||
octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c));
|
||||
}
|
||||
}
|
||||
|
||||
int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
@ -7,6 +8,7 @@
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* Controller command patterns */
|
||||
#define SW_TWSI_V BIT_ULL(63) /* Valid bit */
|
||||
@ -71,6 +73,7 @@
|
||||
#define STAT_SLAVE_ACK 0xC8
|
||||
#define STAT_AD2W_ACK 0xD0
|
||||
#define STAT_AD2W_NAK 0xD8
|
||||
#define STAT_WDOG_TOUT 0xF0
|
||||
#define STAT_IDLE 0xF8
|
||||
|
||||
/* TWSI_INT values */
|
||||
@ -92,11 +95,21 @@ struct octeon_i2c_reg_offset {
|
||||
unsigned int sw_twsi;
|
||||
unsigned int twsi_int;
|
||||
unsigned int sw_twsi_ext;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
#define SW_TWSI(x) (x->roff.sw_twsi)
|
||||
#define TWSI_INT(x) (x->roff.twsi_int)
|
||||
#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext)
|
||||
#define OCTEON_REG_SW_TWSI(x) ((x)->roff.sw_twsi)
|
||||
#define OCTEON_REG_TWSI_INT(x) ((x)->roff.twsi_int)
|
||||
#define OCTEON_REG_SW_TWSI_EXT(x) ((x)->roff.sw_twsi_ext)
|
||||
#define OCTEON_REG_MODE(x) ((x)->roff.mode)
|
||||
|
||||
/* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */
|
||||
#define TWSX_MODE_REFCLK_SRC BIT(4)
|
||||
#define TWSX_MODE_HS_MODE BIT(0)
|
||||
#define TWSX_MODE_HS_MASK (TWSX_MODE_REFCLK_SRC | TWSX_MODE_HS_MODE)
|
||||
|
||||
/* Set BUS_MON_RST to reset bus monitor */
|
||||
#define BUS_MON_RST_MASK BIT(3)
|
||||
|
||||
struct octeon_i2c {
|
||||
wait_queue_head_t queue;
|
||||
@ -134,16 +147,16 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
|
||||
* @eop_reg: Register selector
|
||||
* @data: Value to be written
|
||||
*
|
||||
* The I2C core registers are accessed indirectly via the SW_TWSI CSR.
|
||||
* The I2C core registers are accessed indirectly via the OCTEON_REG_SW_TWSI CSR.
|
||||
*/
|
||||
static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
|
||||
{
|
||||
int tries = 1000;
|
||||
u64 tmp;
|
||||
|
||||
__raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
|
||||
__raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
do {
|
||||
tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if (--tries < 0)
|
||||
return;
|
||||
} while ((tmp & SW_TWSI_V) != 0);
|
||||
@ -169,9 +182,9 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
|
||||
int tries = 1000;
|
||||
u64 tmp;
|
||||
|
||||
__raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
|
||||
__raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
do {
|
||||
tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
|
||||
tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
if (--tries < 0) {
|
||||
/* signal that the returned data is invalid */
|
||||
if (error)
|
||||
@ -191,24 +204,40 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
|
||||
octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
|
||||
|
||||
/**
|
||||
* octeon_i2c_read_int - read the TWSI_INT register
|
||||
* octeon_i2c_read_int - read the OCTEON_REG_TWSI_INT register
|
||||
* @i2c: The struct octeon_i2c
|
||||
*
|
||||
* Returns the value of the register.
|
||||
*/
|
||||
static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
|
||||
{
|
||||
return __raw_readq(i2c->twsi_base + TWSI_INT(i2c));
|
||||
return __raw_readq(i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c));
|
||||
}
|
||||
|
||||
/**
|
||||
* octeon_i2c_write_int - write the TWSI_INT register
|
||||
* octeon_i2c_write_int - write the OCTEON_REG_TWSI_INT register
|
||||
* @i2c: The struct octeon_i2c
|
||||
* @data: Value to be written
|
||||
*/
|
||||
static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
|
||||
{
|
||||
octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c));
|
||||
octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c));
|
||||
}
|
||||
|
||||
#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000)
|
||||
#define PCI_SUBSYS_DEVID_9XXX 0xB
|
||||
#define PCI_SUBSYS_MASK GENMASK(15, 12)
|
||||
/**
|
||||
* octeon_i2c_is_otx2 - check for chip ID
|
||||
* @pdev: PCI dev structure
|
||||
*
|
||||
* Returns true if the device is an OcteonTX2, false otherwise.
|
||||
*/
|
||||
static inline bool octeon_i2c_is_otx2(struct pci_dev *pdev)
|
||||
{
|
||||
u32 chip_id = FIELD_GET(PCI_SUBSYS_MASK, pdev->subsystem_device);
|
||||
|
||||
return (chip_id == PCI_SUBSYS_DEVID_9XXX);
|
||||
}
|
||||
|
||||
/* Prototypes */
|
||||
|
@ -660,7 +660,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int stop, bool polling)
|
||||
{
|
||||
struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
u16 w;
|
||||
int ret;
|
||||
|
||||
@ -740,19 +740,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
||||
* into arbitration and we're currently unable to recover from it.
|
||||
*/
|
||||
if (!polling) {
|
||||
timeout = wait_for_completion_timeout(&omap->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
time_left = wait_for_completion_timeout(&omap->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
} else {
|
||||
do {
|
||||
omap_i2c_wait(omap);
|
||||
ret = omap_i2c_xfer_data(omap);
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
timeout = !ret;
|
||||
time_left = !ret;
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
dev_err(omap->dev, "controller timed out\n");
|
||||
if (time_left == 0) {
|
||||
omap_i2c_reset(omap);
|
||||
__omap_i2c_init(omap);
|
||||
return -ETIMEDOUT;
|
||||
|
@ -826,7 +826,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
|
||||
static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c)
|
||||
{
|
||||
u32 icr;
|
||||
long timeout;
|
||||
long time_left;
|
||||
|
||||
spin_lock_irq(&i2c->lock);
|
||||
i2c->highmode_enter = true;
|
||||
@ -837,12 +837,12 @@ static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c)
|
||||
writel(icr, _ICR(i2c));
|
||||
|
||||
spin_unlock_irq(&i2c->lock);
|
||||
timeout = wait_event_timeout(i2c->wait,
|
||||
i2c->highmode_enter == false, HZ * 1);
|
||||
time_left = wait_event_timeout(i2c->wait,
|
||||
i2c->highmode_enter == false, HZ * 1);
|
||||
|
||||
i2c->highmode_enter = false;
|
||||
|
||||
return (timeout == 0) ? I2C_RETRY : 0;
|
||||
return (time_left == 0) ? I2C_RETRY : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1050,7 +1050,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
|
||||
*/
|
||||
static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
|
||||
{
|
||||
long timeout;
|
||||
long time_left;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -1095,7 +1095,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
|
||||
/*
|
||||
* The rest of the processing occurs in the interrupt handler.
|
||||
*/
|
||||
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
||||
time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
||||
i2c_pxa_stop_message(i2c);
|
||||
|
||||
/*
|
||||
@ -1103,7 +1103,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
|
||||
*/
|
||||
ret = i2c->msg_idx;
|
||||
|
||||
if (!timeout && i2c->msg_num) {
|
||||
if (!time_left && i2c->msg_num) {
|
||||
i2c_pxa_scream_blue_murder(i2c, "timeout with active message");
|
||||
i2c_recover_bus(&i2c->adap);
|
||||
ret = I2C_RETRY;
|
||||
|
@ -586,7 +586,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
|
||||
{
|
||||
struct dma_slave_config config = {};
|
||||
struct gpi_i2c_config peripheral = {};
|
||||
int i, ret = 0, timeout;
|
||||
int i, ret = 0;
|
||||
unsigned long time_left;
|
||||
dma_addr_t tx_addr, rx_addr;
|
||||
void *tx_buf = NULL, *rx_buf = NULL;
|
||||
const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
|
||||
@ -629,12 +630,9 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
|
||||
|
||||
dma_async_issue_pending(gi2c->tx_c);
|
||||
|
||||
timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!timeout) {
|
||||
dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n",
|
||||
gi2c->cur->flags, gi2c->cur->addr);
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!time_left)
|
||||
gi2c->err = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (gi2c->err) {
|
||||
ret = gi2c->err;
|
||||
|
@ -793,10 +793,8 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
|
||||
dma_async_issue_pending(qup->brx.dma);
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
|
||||
dev_err(qup->dev, "normal trans timed out\n");
|
||||
if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout))
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ret || qup->bus_err || qup->qup_err) {
|
||||
reinit_completion(&qup->xfer);
|
||||
|
@ -46,18 +46,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define RIIC_ICCR1 0x00
|
||||
#define RIIC_ICCR2 0x04
|
||||
#define RIIC_ICMR1 0x08
|
||||
#define RIIC_ICMR3 0x10
|
||||
#define RIIC_ICSER 0x18
|
||||
#define RIIC_ICIER 0x1c
|
||||
#define RIIC_ICSR2 0x24
|
||||
#define RIIC_ICBRL 0x34
|
||||
#define RIIC_ICBRH 0x38
|
||||
#define RIIC_ICDRT 0x3c
|
||||
#define RIIC_ICDRR 0x40
|
||||
|
||||
#define ICCR1_ICE 0x80
|
||||
#define ICCR1_IICRST 0x40
|
||||
#define ICCR1_SOWP 0x10
|
||||
@ -87,6 +75,25 @@
|
||||
|
||||
#define RIIC_INIT_MSG -1
|
||||
|
||||
enum riic_reg_list {
|
||||
RIIC_ICCR1 = 0,
|
||||
RIIC_ICCR2,
|
||||
RIIC_ICMR1,
|
||||
RIIC_ICMR3,
|
||||
RIIC_ICSER,
|
||||
RIIC_ICIER,
|
||||
RIIC_ICSR2,
|
||||
RIIC_ICBRL,
|
||||
RIIC_ICBRH,
|
||||
RIIC_ICDRT,
|
||||
RIIC_ICDRR,
|
||||
RIIC_REG_END,
|
||||
};
|
||||
|
||||
struct riic_of_data {
|
||||
u8 regs[RIIC_REG_END];
|
||||
};
|
||||
|
||||
struct riic_dev {
|
||||
void __iomem *base;
|
||||
u8 *buf;
|
||||
@ -94,6 +101,7 @@ struct riic_dev {
|
||||
int bytes_left;
|
||||
int err;
|
||||
int is_last;
|
||||
const struct riic_of_data *info;
|
||||
struct completion msg_done;
|
||||
struct i2c_adapter adapter;
|
||||
struct clk *clk;
|
||||
@ -105,9 +113,19 @@ struct riic_irq_desc {
|
||||
char *name;
|
||||
};
|
||||
|
||||
static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset)
|
||||
{
|
||||
writeb(val, riic->base + riic->info->regs[offset]);
|
||||
}
|
||||
|
||||
static inline u8 riic_readb(struct riic_dev *riic, u8 offset)
|
||||
{
|
||||
return readb(riic->base + riic->info->regs[offset]);
|
||||
}
|
||||
|
||||
static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg)
|
||||
{
|
||||
writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg);
|
||||
riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg);
|
||||
}
|
||||
|
||||
static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
@ -119,7 +137,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
|
||||
pm_runtime_get_sync(adap->dev.parent);
|
||||
|
||||
if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) {
|
||||
if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) {
|
||||
riic->err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -127,7 +145,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
reinit_completion(&riic->msg_done);
|
||||
riic->err = 0;
|
||||
|
||||
writeb(0, riic->base + RIIC_ICSR2);
|
||||
riic_writeb(riic, 0, RIIC_ICSR2);
|
||||
|
||||
for (i = 0, start_bit = ICCR2_ST; i < num; i++) {
|
||||
riic->bytes_left = RIIC_INIT_MSG;
|
||||
@ -135,9 +153,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
riic->msg = &msgs[i];
|
||||
riic->is_last = (i == num - 1);
|
||||
|
||||
writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER);
|
||||
riic_writeb(riic, ICIER_NAKIE | ICIER_TIE, RIIC_ICIER);
|
||||
|
||||
writeb(start_bit, riic->base + RIIC_ICCR2);
|
||||
riic_writeb(riic, start_bit, RIIC_ICCR2);
|
||||
|
||||
time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout);
|
||||
if (time_left == 0)
|
||||
@ -191,7 +209,7 @@ static irqreturn_t riic_tdre_isr(int irq, void *data)
|
||||
* value could be moved to the shadow shift register right away. So
|
||||
* this must be after updates to ICIER (where we want to disable TIE)!
|
||||
*/
|
||||
writeb(val, riic->base + RIIC_ICDRT);
|
||||
riic_writeb(riic, val, RIIC_ICDRT);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -200,9 +218,9 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
|
||||
{
|
||||
struct riic_dev *riic = data;
|
||||
|
||||
if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
|
||||
if (riic_readb(riic, RIIC_ICSR2) & ICSR2_NACKF) {
|
||||
/* We got a NACKIE */
|
||||
readb(riic->base + RIIC_ICDRR); /* dummy read */
|
||||
riic_readb(riic, RIIC_ICDRR); /* dummy read */
|
||||
riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
|
||||
riic->err = -ENXIO;
|
||||
} else if (riic->bytes_left) {
|
||||
@ -211,7 +229,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
|
||||
|
||||
if (riic->is_last || riic->err) {
|
||||
riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER);
|
||||
writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
|
||||
riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
|
||||
} else {
|
||||
/* Transfer is complete, but do not send STOP */
|
||||
riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER);
|
||||
@ -230,7 +248,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
|
||||
|
||||
if (riic->bytes_left == RIIC_INIT_MSG) {
|
||||
riic->bytes_left = riic->msg->len;
|
||||
readb(riic->base + RIIC_ICDRR); /* dummy read */
|
||||
riic_readb(riic, RIIC_ICDRR); /* dummy read */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -238,7 +256,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
|
||||
/* STOP must come before we set ACKBT! */
|
||||
if (riic->is_last) {
|
||||
riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
|
||||
writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
|
||||
riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
|
||||
}
|
||||
|
||||
riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
|
||||
@ -248,7 +266,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
|
||||
}
|
||||
|
||||
/* Reading acks the RIE interrupt */
|
||||
*riic->buf = readb(riic->base + RIIC_ICDRR);
|
||||
*riic->buf = riic_readb(riic, RIIC_ICDRR);
|
||||
riic->buf++;
|
||||
riic->bytes_left--;
|
||||
|
||||
@ -260,10 +278,10 @@ static irqreturn_t riic_stop_isr(int irq, void *data)
|
||||
struct riic_dev *riic = data;
|
||||
|
||||
/* read back registers to confirm writes have fully propagated */
|
||||
writeb(0, riic->base + RIIC_ICSR2);
|
||||
readb(riic->base + RIIC_ICSR2);
|
||||
writeb(0, riic->base + RIIC_ICIER);
|
||||
readb(riic->base + RIIC_ICIER);
|
||||
riic_writeb(riic, 0, RIIC_ICSR2);
|
||||
riic_readb(riic, RIIC_ICSR2);
|
||||
riic_writeb(riic, 0, RIIC_ICIER);
|
||||
riic_readb(riic, RIIC_ICIER);
|
||||
|
||||
complete(&riic->msg_done);
|
||||
|
||||
@ -365,15 +383,15 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
|
||||
t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
|
||||
|
||||
/* Changing the order of accessing IICRST and ICE may break things! */
|
||||
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
|
||||
riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1);
|
||||
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
|
||||
|
||||
writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
|
||||
writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
|
||||
writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
|
||||
riic_writeb(riic, ICMR1_CKS(cks), RIIC_ICMR1);
|
||||
riic_writeb(riic, brh | ICBR_RESERVED, RIIC_ICBRH);
|
||||
riic_writeb(riic, brl | ICBR_RESERVED, RIIC_ICBRL);
|
||||
|
||||
writeb(0, riic->base + RIIC_ICSER);
|
||||
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
|
||||
riic_writeb(riic, 0, RIIC_ICSER);
|
||||
riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, RIIC_ICMR3);
|
||||
|
||||
riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
|
||||
|
||||
@ -443,6 +461,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
riic->info = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
adap = &riic->adapter;
|
||||
i2c_set_adapdata(adap, riic);
|
||||
strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name));
|
||||
@ -481,14 +501,47 @@ static void riic_i2c_remove(struct platform_device *pdev)
|
||||
struct riic_dev *riic = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
writeb(0, riic->base + RIIC_ICIER);
|
||||
riic_writeb(riic, 0, RIIC_ICIER);
|
||||
pm_runtime_put(&pdev->dev);
|
||||
i2c_del_adapter(&riic->adapter);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct riic_of_data riic_rz_a_info = {
|
||||
.regs = {
|
||||
[RIIC_ICCR1] = 0x00,
|
||||
[RIIC_ICCR2] = 0x04,
|
||||
[RIIC_ICMR1] = 0x08,
|
||||
[RIIC_ICMR3] = 0x10,
|
||||
[RIIC_ICSER] = 0x18,
|
||||
[RIIC_ICIER] = 0x1c,
|
||||
[RIIC_ICSR2] = 0x24,
|
||||
[RIIC_ICBRL] = 0x34,
|
||||
[RIIC_ICBRH] = 0x38,
|
||||
[RIIC_ICDRT] = 0x3c,
|
||||
[RIIC_ICDRR] = 0x40,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct riic_of_data riic_rz_v2h_info = {
|
||||
.regs = {
|
||||
[RIIC_ICCR1] = 0x00,
|
||||
[RIIC_ICCR2] = 0x01,
|
||||
[RIIC_ICMR1] = 0x02,
|
||||
[RIIC_ICMR3] = 0x04,
|
||||
[RIIC_ICSER] = 0x06,
|
||||
[RIIC_ICIER] = 0x07,
|
||||
[RIIC_ICSR2] = 0x09,
|
||||
[RIIC_ICBRL] = 0x10,
|
||||
[RIIC_ICBRH] = 0x11,
|
||||
[RIIC_ICDRT] = 0x12,
|
||||
[RIIC_ICDRR] = 0x13,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id riic_i2c_dt_ids[] = {
|
||||
{ .compatible = "renesas,riic-rz", },
|
||||
{ .compatible = "renesas,riic-rz", .data = &riic_rz_a_info },
|
||||
{ .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
|
@ -1060,7 +1060,8 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num, bool polling)
|
||||
{
|
||||
struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
|
||||
unsigned long timeout, flags;
|
||||
unsigned long flags;
|
||||
long time_left;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
int i;
|
||||
@ -1092,23 +1093,20 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
|
||||
if (!polling) {
|
||||
rk3x_i2c_start(i2c);
|
||||
|
||||
timeout = wait_event_timeout(i2c->wait, !i2c->busy,
|
||||
msecs_to_jiffies(WAIT_TIMEOUT));
|
||||
time_left = wait_event_timeout(i2c->wait, !i2c->busy,
|
||||
msecs_to_jiffies(WAIT_TIMEOUT));
|
||||
} else {
|
||||
disable_irq(i2c->irq);
|
||||
rk3x_i2c_start(i2c);
|
||||
|
||||
timeout = rk3x_i2c_wait_xfer_poll(i2c);
|
||||
time_left = rk3x_i2c_wait_xfer_poll(i2c);
|
||||
|
||||
enable_irq(i2c->irq);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
|
||||
if (timeout == 0) {
|
||||
dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n",
|
||||
i2c_readl(i2c, REG_IPD), i2c->state);
|
||||
|
||||
if (time_left == 0) {
|
||||
/* Force a STOP condition without interrupt */
|
||||
i2c_writel(i2c, 0, REG_IEN);
|
||||
val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
|
||||
|
@ -685,7 +685,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
|
||||
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
unsigned long timeout = 0;
|
||||
long time_left = 0;
|
||||
int ret;
|
||||
|
||||
ret = s3c24xx_i2c_set_master(i2c);
|
||||
@ -715,7 +715,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
dev_err(i2c->dev, "deal with arbitration loss\n");
|
||||
}
|
||||
} else {
|
||||
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
||||
time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
||||
}
|
||||
|
||||
ret = i2c->msg_idx;
|
||||
@ -724,7 +724,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
* Having these next two as dev_err() makes life very
|
||||
* noisy when doing an i2cdetect
|
||||
*/
|
||||
if (timeout == 0)
|
||||
if (time_left == 0)
|
||||
dev_dbg(i2c->dev, "timeout\n");
|
||||
else if (ret != num)
|
||||
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
|
||||
|
@ -688,7 +688,6 @@ static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
|
||||
}
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(pd->dev, "Transfer request timed out\n");
|
||||
if (pd->dma_direction != DMA_NONE)
|
||||
sh_mobile_i2c_cleanup_dma(pd, true);
|
||||
|
||||
|
@ -647,7 +647,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 ctl, i2c, it;
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
c->addr = i2c_8bit_addr_from_msg(msg);
|
||||
@ -685,15 +685,12 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG);
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = c->result;
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(i2c_dev->dev, "Write to slave 0x%x timed out\n",
|
||||
c->addr);
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG;
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, i2c);
|
||||
|
@ -681,7 +681,7 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
|
||||
{
|
||||
struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg;
|
||||
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
@ -706,11 +706,11 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
|
||||
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = f4_msg->result;
|
||||
|
||||
if (!timeout)
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
return ret;
|
||||
|
@ -1789,7 +1789,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
|
||||
struct stm32_i2c_dma *dma = i2c_dev->dma;
|
||||
struct device *dev = i2c_dev->dev;
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
int i, ret;
|
||||
|
||||
f7_msg->addr = addr;
|
||||
@ -1809,8 +1809,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
if (ret)
|
||||
goto pm_free;
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = f7_msg->result;
|
||||
if (ret) {
|
||||
if (i2c_dev->use_dma)
|
||||
@ -1826,7 +1826,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
goto pm_free;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
if (!time_left) {
|
||||
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
|
||||
if (i2c_dev->use_dma)
|
||||
dmaengine_terminate_sync(dma->chan_using);
|
||||
|
@ -311,7 +311,7 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
unsigned char bsr;
|
||||
unsigned long timeout;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
synquacer_i2c_hw_init(i2c);
|
||||
@ -335,9 +335,9 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c->completion,
|
||||
msecs_to_jiffies(i2c->timeout_ms));
|
||||
if (timeout == 0) {
|
||||
time_left = wait_for_completion_timeout(&i2c->completion,
|
||||
msecs_to_jiffies(i2c->timeout_ms));
|
||||
if (time_left == 0) {
|
||||
dev_dbg(i2c->dev, "timeout\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -550,17 +550,13 @@ static int synquacer_i2c_probe(struct platform_device *pdev)
|
||||
device_property_read_u32(&pdev->dev, "socionext,pclk-rate",
|
||||
&i2c->pclkrate);
|
||||
|
||||
i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (PTR_ERR(i2c->pclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (!IS_ERR_OR_NULL(i2c->pclk)) {
|
||||
dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk);
|
||||
i2c->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
|
||||
if (IS_ERR(i2c->pclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk),
|
||||
"failed to get and enable clock\n");
|
||||
|
||||
ret = clk_prepare_enable(i2c->pclk);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to enable clock\n");
|
||||
i2c->pclkrate = clk_get_rate(i2c->pclk);
|
||||
}
|
||||
dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk);
|
||||
i2c->pclkrate = clk_get_rate(i2c->pclk);
|
||||
|
||||
if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE ||
|
||||
i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE)
|
||||
@ -615,8 +611,6 @@ static void synquacer_i2c_remove(struct platform_device *pdev)
|
||||
struct synquacer_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&i2c->adapter);
|
||||
if (!IS_ERR(i2c->pclk))
|
||||
clk_disable_unprepare(i2c->pclk);
|
||||
};
|
||||
|
||||
static const struct of_device_id synquacer_i2c_dt_ids[] __maybe_unused = {
|
||||
|
@ -1331,7 +1331,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
dmaengine_terminate_sync(i2c_dev->dma_chan);
|
||||
|
||||
if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
|
||||
dev_err(i2c_dev->dev, "DMA transfer timed out\n");
|
||||
tegra_i2c_init(i2c_dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -1351,7 +1350,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
||||
|
||||
if (time_left == 0) {
|
||||
dev_err(i2c_dev->dev, "I2C transfer timed out\n");
|
||||
tegra_i2c_init(i2c_dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -27,7 +27,8 @@
|
||||
|
||||
#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
|
||||
|
||||
#define SYS_FREQ_DEFAULT 700000000
|
||||
#define SYS_FREQ_DEFAULT 800000000
|
||||
#define OTX2_REF_FREQ_DEFAULT 100000000
|
||||
|
||||
#define TWSI_INT_ENA_W1C 0x1028
|
||||
#define TWSI_INT_ENA_W1S 0x1030
|
||||
@ -99,7 +100,8 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
|
||||
i2c->sys_freq = clk_get_rate(i2c->clk);
|
||||
} else {
|
||||
/* ACPI */
|
||||
device_property_read_u32(dev, "sclk", &i2c->sys_freq);
|
||||
if (device_property_read_u32(dev, "sclk", &i2c->sys_freq))
|
||||
device_property_read_u32(dev, "ioclk", &i2c->sys_freq);
|
||||
}
|
||||
|
||||
skip:
|
||||
@ -165,6 +167,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
|
||||
i2c->roff.sw_twsi = 0x1000;
|
||||
i2c->roff.twsi_int = 0x1010;
|
||||
i2c->roff.sw_twsi_ext = 0x1018;
|
||||
i2c->roff.mode = 0x1038;
|
||||
|
||||
i2c->dev = dev;
|
||||
pci_set_drvdata(pdev, i2c);
|
||||
@ -205,6 +208,12 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* For OcteonTX2 chips, set reference frequency to 100MHz
|
||||
* as refclk_src in TWSI_MODE register defaults to 100MHz.
|
||||
*/
|
||||
if (octeon_i2c_is_otx2(pdev) && IS_LS_FREQ(i2c->twsi_freq))
|
||||
i2c->sys_freq = OTX2_REF_FREQ_DEFAULT;
|
||||
octeon_i2c_set_clock(i2c);
|
||||
|
||||
i2c->adap = thunderx_i2c_ops;
|
||||
|
@ -358,7 +358,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(&adap->dev, "transaction timeout.\n");
|
||||
uniphier_fi2c_recover(priv);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -71,10 +71,8 @@ static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
|
||||
writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
|
||||
|
||||
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
|
||||
if (unlikely(!time_left)) {
|
||||
dev_err(&adap->dev, "transaction timeout\n");
|
||||
if (unlikely(!time_left))
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
|
||||
if (rxdatap)
|
||||
|
256
drivers/i2c/busses/i2c-viai2c-common.c
Normal file
256
drivers/i2c/busses/i2c-viai2c-common.c
Normal file
@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <linux/of_irq.h>
|
||||
#include "i2c-viai2c-common.h"
|
||||
|
||||
int viai2c_wait_bus_not_busy(struct viai2c *i2c)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + VIAI2C_TIMEOUT;
|
||||
while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(i2c->dev, "timeout waiting for bus ready\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
|
||||
{
|
||||
u16 val, tcr_val = i2c->tcr;
|
||||
|
||||
i2c->last = last;
|
||||
|
||||
if (pmsg->len == 0) {
|
||||
/*
|
||||
* We still need to run through the while (..) once, so
|
||||
* start at -1 and break out early from the loop
|
||||
*/
|
||||
i2c->xfered_len = -1;
|
||||
writew(0, i2c->base + VIAI2C_REG_CDR);
|
||||
} else {
|
||||
writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
|
||||
}
|
||||
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
|
||||
val = readw(i2c->base + VIAI2C_REG_CR);
|
||||
val &= ~VIAI2C_CR_TX_END;
|
||||
val |= VIAI2C_CR_CPU_RDY;
|
||||
writew(val, i2c->base + VIAI2C_REG_CR);
|
||||
}
|
||||
|
||||
reinit_completion(&i2c->complete);
|
||||
|
||||
tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK;
|
||||
|
||||
writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
|
||||
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
|
||||
val = readw(i2c->base + VIAI2C_REG_CR);
|
||||
val |= VIAI2C_CR_CPU_RDY;
|
||||
writew(val, i2c->base + VIAI2C_REG_CR);
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return i2c->ret;
|
||||
}
|
||||
|
||||
static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
|
||||
{
|
||||
u16 val, tcr_val = i2c->tcr;
|
||||
|
||||
val = readw(i2c->base + VIAI2C_REG_CR);
|
||||
val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
|
||||
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
|
||||
val |= VIAI2C_CR_CPU_RDY;
|
||||
|
||||
if (pmsg->len == 1)
|
||||
val |= VIAI2C_CR_RX_END;
|
||||
|
||||
writew(val, i2c->base + VIAI2C_REG_CR);
|
||||
|
||||
reinit_completion(&i2c->complete);
|
||||
|
||||
tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK);
|
||||
|
||||
writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
|
||||
|
||||
if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) ||
|
||||
(i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
|
||||
val = readw(i2c->base + VIAI2C_REG_CR);
|
||||
val |= VIAI2C_CR_CPU_RDY;
|
||||
writew(val, i2c->base + VIAI2C_REG_CR);
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return i2c->ret;
|
||||
}
|
||||
|
||||
int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct i2c_msg *pmsg;
|
||||
int i;
|
||||
int ret = 0;
|
||||
struct viai2c *i2c = i2c_get_adapdata(adap);
|
||||
|
||||
i2c->mode = VIAI2C_BYTE_MODE;
|
||||
for (i = 0; ret >= 0 && i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
|
||||
ret = viai2c_wait_bus_not_busy(i2c);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c->msg = pmsg;
|
||||
i2c->xfered_len = 0;
|
||||
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
ret = viai2c_read(i2c, pmsg, i == 0);
|
||||
else
|
||||
ret = viai2c_write(i2c, pmsg, (i + 1) == num);
|
||||
}
|
||||
|
||||
return (ret < 0) ? ret : i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main process of the byte mode xfer
|
||||
*
|
||||
* Return value indicates whether the transfer is complete
|
||||
* 1: all the data has been successfully transferred
|
||||
* 0: there is still data that needs to be transferred
|
||||
* -EIO: error occurred
|
||||
*/
|
||||
static int viai2c_irq_xfer(struct viai2c *i2c)
|
||||
{
|
||||
u16 val;
|
||||
struct i2c_msg *msg = i2c->msg;
|
||||
u8 read = msg->flags & I2C_M_RD;
|
||||
void __iomem *base = i2c->base;
|
||||
|
||||
if (read) {
|
||||
msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8;
|
||||
|
||||
val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
|
||||
if (i2c->xfered_len == msg->len - 2)
|
||||
val |= VIAI2C_CR_RX_END;
|
||||
writew(val, base + VIAI2C_REG_CR);
|
||||
} else {
|
||||
val = readw(base + VIAI2C_REG_CSR);
|
||||
if (val & VIAI2C_CSR_RCV_NOT_ACK)
|
||||
return -EIO;
|
||||
|
||||
/* I2C_SMBUS_QUICK */
|
||||
if (msg->len == 0) {
|
||||
val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
|
||||
writew(val, base + VIAI2C_REG_CR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((i2c->xfered_len + 1) == msg->len) {
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
|
||||
writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
|
||||
else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last)
|
||||
writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
|
||||
} else {
|
||||
writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
|
||||
writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
|
||||
}
|
||||
}
|
||||
|
||||
i2c->xfered_len++;
|
||||
|
||||
return i2c->xfered_len == msg->len;
|
||||
}
|
||||
|
||||
int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t viai2c_isr(int irq, void *data)
|
||||
{
|
||||
struct viai2c *i2c = data;
|
||||
u8 status;
|
||||
|
||||
/* save the status and write-clear it */
|
||||
status = readw(i2c->base + VIAI2C_REG_ISR);
|
||||
if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
|
||||
return IRQ_NONE;
|
||||
|
||||
writew(status, i2c->base + VIAI2C_REG_ISR);
|
||||
|
||||
i2c->ret = 0;
|
||||
if (status & VIAI2C_ISR_NACK_ADDR)
|
||||
i2c->ret = -EIO;
|
||||
|
||||
if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
|
||||
i2c->ret = -ETIMEDOUT;
|
||||
|
||||
if (!i2c->ret) {
|
||||
if (i2c->mode == VIAI2C_BYTE_MODE)
|
||||
i2c->ret = viai2c_irq_xfer(i2c);
|
||||
else
|
||||
i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
|
||||
}
|
||||
|
||||
/* All the data has been successfully transferred or error occurred */
|
||||
if (i2c->ret)
|
||||
complete(&i2c->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
|
||||
{
|
||||
int err;
|
||||
int irq_flags;
|
||||
struct viai2c *i2c;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(i2c->base))
|
||||
return PTR_ERR(i2c->base);
|
||||
|
||||
if (plat == VIAI2C_PLAT_WMT) {
|
||||
irq_flags = 0;
|
||||
i2c->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!i2c->irq)
|
||||
return -EINVAL;
|
||||
} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
|
||||
irq_flags = IRQF_SHARED;
|
||||
i2c->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c->irq < 0)
|
||||
return i2c->irq;
|
||||
} else {
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
|
||||
}
|
||||
|
||||
i2c->platform = plat;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
|
||||
irq_flags, pdev->name, i2c);
|
||||
if (err)
|
||||
return dev_err_probe(&pdev->dev, err,
|
||||
"failed to request irq %i\n", i2c->irq);
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
init_completion(&i2c->complete);
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
*pi2c = i2c;
|
||||
return 0;
|
||||
}
|
85
drivers/i2c/busses/i2c-viai2c-common.h
Normal file
85
drivers/i2c/busses/i2c-viai2c-common.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef __I2C_VIAI2C_COMMON_H_
|
||||
#define __I2C_VIAI2C_COMMON_H_
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* REG_CR Bit fields */
|
||||
#define VIAI2C_REG_CR 0x00
|
||||
#define VIAI2C_CR_ENABLE BIT(0)
|
||||
#define VIAI2C_CR_RX_END BIT(1)
|
||||
#define VIAI2C_CR_TX_END BIT(2)
|
||||
#define VIAI2C_CR_CPU_RDY BIT(3)
|
||||
#define VIAI2C_CR_END_MASK GENMASK(2, 1)
|
||||
|
||||
/* REG_TCR Bit fields */
|
||||
#define VIAI2C_REG_TCR 0x02
|
||||
#define VIAI2C_TCR_HS_MODE BIT(13)
|
||||
#define VIAI2C_TCR_READ BIT(14)
|
||||
#define VIAI2C_TCR_FAST BIT(15)
|
||||
#define VIAI2C_TCR_ADDR_MASK GENMASK(6, 0)
|
||||
|
||||
/* REG_CSR Bit fields */
|
||||
#define VIAI2C_REG_CSR 0x04
|
||||
#define VIAI2C_CSR_RCV_NOT_ACK BIT(0)
|
||||
#define VIAI2C_CSR_RCV_ACK_MASK BIT(0)
|
||||
#define VIAI2C_CSR_READY_MASK BIT(1)
|
||||
|
||||
/* REG_ISR Bit fields */
|
||||
#define VIAI2C_REG_ISR 0x06
|
||||
#define VIAI2C_ISR_NACK_ADDR BIT(0)
|
||||
#define VIAI2C_ISR_BYTE_END BIT(1)
|
||||
#define VIAI2C_ISR_SCL_TIMEOUT BIT(2)
|
||||
#define VIAI2C_ISR_MASK_ALL GENMASK(2, 0)
|
||||
|
||||
/* REG_IMR Bit fields */
|
||||
#define VIAI2C_REG_IMR 0x08
|
||||
#define VIAI2C_IMR_BYTE BIT(1)
|
||||
#define VIAI2C_IMR_ENABLE_ALL GENMASK(2, 0)
|
||||
|
||||
#define VIAI2C_REG_CDR 0x0A
|
||||
#define VIAI2C_REG_TR 0x0C
|
||||
#define VIAI2C_REG_MCR 0x0E
|
||||
|
||||
#define VIAI2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
enum {
|
||||
VIAI2C_PLAT_WMT,
|
||||
VIAI2C_PLAT_ZHAOXIN
|
||||
};
|
||||
|
||||
enum {
|
||||
VIAI2C_BYTE_MODE,
|
||||
VIAI2C_FIFO_MODE
|
||||
};
|
||||
|
||||
struct viai2c {
|
||||
struct i2c_adapter adapter;
|
||||
struct completion complete;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
u16 tcr;
|
||||
int irq;
|
||||
u16 xfered_len;
|
||||
struct i2c_msg *msg;
|
||||
int ret;
|
||||
bool last;
|
||||
unsigned int mode;
|
||||
unsigned int platform;
|
||||
void *pltfm_priv;
|
||||
};
|
||||
|
||||
int viai2c_wait_bus_not_busy(struct viai2c *i2c);
|
||||
int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
|
||||
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
|
||||
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
|
||||
|
||||
#endif
|
148
drivers/i2c/busses/i2c-viai2c-wmt.c
Normal file
148
drivers/i2c/busses/i2c-viai2c-wmt.c
Normal file
@ -0,0 +1,148 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Wondermedia I2C Master Mode Driver
|
||||
*
|
||||
* Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
|
||||
*
|
||||
* Derived from GPLv2+ licensed source:
|
||||
* - Copyright (C) 2008 WonderMedia Technologies, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include "i2c-viai2c-common.h"
|
||||
|
||||
#define REG_SLAVE_CR 0x10
|
||||
#define REG_SLAVE_SR 0x12
|
||||
#define REG_SLAVE_ISR 0x14
|
||||
#define REG_SLAVE_IMR 0x16
|
||||
#define REG_SLAVE_DR 0x18
|
||||
#define REG_SLAVE_TR 0x1A
|
||||
|
||||
/* REG_TR */
|
||||
#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8)
|
||||
#define TR_STD 0x0064
|
||||
#define TR_HS 0x0019
|
||||
|
||||
/* REG_MCR */
|
||||
#define MCR_APB_96M 7
|
||||
#define MCR_APB_166M 12
|
||||
|
||||
static u32 wmt_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm wmt_i2c_algo = {
|
||||
.master_xfer = viai2c_xfer,
|
||||
.functionality = wmt_i2c_func,
|
||||
};
|
||||
|
||||
static int wmt_i2c_reset_hardware(struct viai2c *i2c)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(i2c->clk);
|
||||
if (err) {
|
||||
dev_err(i2c->dev, "failed to enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_set_rate(i2c->clk, 20000000);
|
||||
if (err) {
|
||||
dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
writew(0, i2c->base + VIAI2C_REG_CR);
|
||||
writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR);
|
||||
writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
|
||||
writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR);
|
||||
writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
|
||||
readw(i2c->base + VIAI2C_REG_CSR); /* read clear */
|
||||
writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
|
||||
|
||||
if (i2c->tcr == VIAI2C_TCR_FAST)
|
||||
writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR);
|
||||
else
|
||||
writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmt_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct viai2c *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
int err;
|
||||
u32 clk_rate;
|
||||
|
||||
err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
i2c->clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
dev_err(&pdev->dev, "unable to request clock\n");
|
||||
return PTR_ERR(i2c->clk);
|
||||
}
|
||||
|
||||
err = of_property_read_u32(np, "clock-frequency", &clk_rate);
|
||||
if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)
|
||||
i2c->tcr = VIAI2C_TCR_FAST;
|
||||
|
||||
adap = &i2c->adapter;
|
||||
i2c_set_adapdata(adap, i2c);
|
||||
strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &wmt_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
err = wmt_i2c_reset_hardware(i2c);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "error initializing hardware\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = i2c_add_adapter(adap);
|
||||
if (err)
|
||||
/* wmt_i2c_reset_hardware() enables i2c_dev->clk */
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void wmt_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct viai2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
/* Disable interrupts, clock and delete adapter */
|
||||
writew(0, i2c->base + VIAI2C_REG_IMR);
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
i2c_del_adapter(&i2c->adapter);
|
||||
}
|
||||
|
||||
static const struct of_device_id wmt_i2c_dt_ids[] = {
|
||||
{ .compatible = "wm,wm8505-i2c" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver wmt_i2c_driver = {
|
||||
.probe = wmt_i2c_probe,
|
||||
.remove_new = wmt_i2c_remove,
|
||||
.driver = {
|
||||
.name = "wmt-i2c",
|
||||
.of_match_table = wmt_i2c_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(wmt_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
|
||||
MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
|
298
drivers/i2c/busses/i2c-viai2c-zhaoxin.c
Normal file
298
drivers/i2c/busses/i2c-viai2c-zhaoxin.c
Normal file
@ -0,0 +1,298 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include "i2c-viai2c-common.h"
|
||||
|
||||
/*
|
||||
* registers
|
||||
*/
|
||||
/* Zhaoxin specific register bit fields */
|
||||
/* REG_CR Bit fields */
|
||||
#define ZXI2C_CR_MST_RST BIT(7)
|
||||
#define ZXI2C_CR_FIFO_MODE BIT(14)
|
||||
/* REG_ISR/IMR Bit fields */
|
||||
#define ZXI2C_IRQ_FIFONACK BIT(4)
|
||||
#define ZXI2C_IRQ_FIFOEND BIT(3)
|
||||
#define ZXI2C_IRQ_MASK (VIAI2C_ISR_MASK_ALL \
|
||||
| ZXI2C_IRQ_FIFOEND \
|
||||
| ZXI2C_IRQ_FIFONACK)
|
||||
/* Zhaoxin specific registers */
|
||||
#define ZXI2C_REG_CLK 0x10
|
||||
#define ZXI2C_CLK_50M BIT(0)
|
||||
#define ZXI2C_REG_REV 0x11
|
||||
#define ZXI2C_REG_HCR 0x12
|
||||
#define ZXI2C_HCR_RST_FIFO GENMASK(1, 0)
|
||||
#define ZXI2C_REG_HTDR 0x13
|
||||
#define ZXI2C_REG_HRDR 0x14
|
||||
#define ZXI2C_REG_HTLR 0x15
|
||||
#define ZXI2C_REG_HRLR 0x16
|
||||
#define ZXI2C_REG_HWCNTR 0x18
|
||||
#define ZXI2C_REG_HRCNTR 0x19
|
||||
|
||||
/* parameters Constants */
|
||||
#define ZXI2C_GOLD_FSTP_100K 0xF3
|
||||
#define ZXI2C_GOLD_FSTP_400K 0x38
|
||||
#define ZXI2C_GOLD_FSTP_1M 0x13
|
||||
#define ZXI2C_GOLD_FSTP_3400K 0x37
|
||||
#define ZXI2C_HS_MASTER_CODE (0x08 << 8)
|
||||
|
||||
#define ZXI2C_FIFO_SIZE 32
|
||||
|
||||
struct viai2c_zhaoxin {
|
||||
u8 hrv;
|
||||
u16 tr;
|
||||
u16 mcr;
|
||||
u16 xfer_len;
|
||||
};
|
||||
|
||||
/* 'irq == true' means in interrupt context */
|
||||
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
|
||||
{
|
||||
u16 i;
|
||||
u8 tmp;
|
||||
struct i2c_msg *msg = i2c->msg;
|
||||
void __iomem *base = i2c->base;
|
||||
bool read = !!(msg->flags & I2C_M_RD);
|
||||
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
|
||||
|
||||
if (irq) {
|
||||
/* get the received data */
|
||||
if (read)
|
||||
for (i = 0; i < priv->xfer_len; i++)
|
||||
msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
|
||||
|
||||
i2c->xfered_len += priv->xfer_len;
|
||||
if (i2c->xfered_len == msg->len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* reset fifo buffer */
|
||||
tmp = ioread8(base + ZXI2C_REG_HCR);
|
||||
iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
|
||||
|
||||
/* set xfer len */
|
||||
priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE);
|
||||
if (read) {
|
||||
iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR);
|
||||
} else {
|
||||
iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR);
|
||||
/* set write data */
|
||||
for (i = 0; i < priv->xfer_len; i++)
|
||||
iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR);
|
||||
}
|
||||
|
||||
/* prepare to stop transmission */
|
||||
if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
|
||||
tmp = ioread8(base + VIAI2C_REG_CR);
|
||||
tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
|
||||
iowrite8(tmp, base + VIAI2C_REG_CR);
|
||||
}
|
||||
|
||||
if (irq) {
|
||||
/* continue transmission */
|
||||
tmp = ioread8(base + VIAI2C_REG_CR);
|
||||
iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
|
||||
} else {
|
||||
u16 tcr_val = i2c->tcr;
|
||||
|
||||
/* start transmission */
|
||||
tcr_val |= read ? VIAI2C_TCR_READ : 0;
|
||||
writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
u8 tmp;
|
||||
int ret;
|
||||
struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap);
|
||||
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
|
||||
void __iomem *base = i2c->base;
|
||||
|
||||
ret = viai2c_wait_bus_not_busy(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tmp = ioread8(base + VIAI2C_REG_CR);
|
||||
tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
|
||||
|
||||
if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
|
||||
/* enable fifo mode */
|
||||
iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR);
|
||||
/* clear irq status */
|
||||
iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
|
||||
/* enable fifo irq */
|
||||
iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR);
|
||||
|
||||
i2c->msg = msgs;
|
||||
i2c->mode = VIAI2C_FIFO_MODE;
|
||||
priv->xfer_len = 0;
|
||||
i2c->xfered_len = 0;
|
||||
|
||||
viai2c_fifo_irq_xfer(i2c, 0);
|
||||
|
||||
if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
ret = i2c->ret;
|
||||
} else {
|
||||
/* enable byte mode */
|
||||
iowrite16(tmp, base + VIAI2C_REG_CR);
|
||||
/* clear irq status */
|
||||
iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
|
||||
/* enable byte irq */
|
||||
iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR);
|
||||
|
||||
ret = viai2c_xfer(adap, msgs, num);
|
||||
if (ret == -ETIMEDOUT)
|
||||
iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR);
|
||||
}
|
||||
/* dis interrupt */
|
||||
iowrite8(0, base + VIAI2C_REG_IMR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 zxi2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm zxi2c_algorithm = {
|
||||
.master_xfer = zxi2c_master_xfer,
|
||||
.functionality = zxi2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks zxi2c_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
};
|
||||
|
||||
static const u32 zxi2c_speed_params_table[][3] = {
|
||||
/* speed, ZXI2C_TCR, ZXI2C_FSTP */
|
||||
{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
|
||||
{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
|
||||
{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
|
||||
{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
|
||||
ZXI2C_GOLD_FSTP_3400K },
|
||||
};
|
||||
|
||||
static void zxi2c_set_bus_speed(struct viai2c *i2c)
|
||||
{
|
||||
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
|
||||
|
||||
iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR);
|
||||
iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
|
||||
iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR);
|
||||
}
|
||||
|
||||
static void zxi2c_get_bus_speed(struct viai2c *i2c)
|
||||
{
|
||||
u8 i, count;
|
||||
u8 fstp;
|
||||
const u32 *params;
|
||||
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
|
||||
u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
|
||||
|
||||
count = ARRAY_SIZE(zxi2c_speed_params_table);
|
||||
for (i = 0; i < count; i++)
|
||||
if (acpi_speed == zxi2c_speed_params_table[i][0])
|
||||
break;
|
||||
/* if not found, use 400k as default */
|
||||
i = i < count ? i : 1;
|
||||
|
||||
params = zxi2c_speed_params_table[i];
|
||||
fstp = ioread8(i2c->base + VIAI2C_REG_TR);
|
||||
if (abs(fstp - params[2]) > 0x10) {
|
||||
/*
|
||||
* if BIOS setting value far from golden value,
|
||||
* use golden value and warn user
|
||||
*/
|
||||
dev_warn(i2c->dev, "FW FSTP[%x] might cause wrong timings, dropped\n", fstp);
|
||||
priv->tr = params[2] | 0xff00;
|
||||
} else {
|
||||
priv->tr = fstp | 0xff00;
|
||||
}
|
||||
|
||||
i2c->tcr = params[1];
|
||||
priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
|
||||
/* for Hs-mode, use 0x80 as master code */
|
||||
if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
|
||||
priv->mcr |= ZXI2C_HS_MASTER_CODE;
|
||||
|
||||
dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
|
||||
}
|
||||
|
||||
static int zxi2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
int error;
|
||||
struct viai2c *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
struct viai2c_zhaoxin *priv;
|
||||
|
||||
error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
i2c->pltfm_priv = priv;
|
||||
|
||||
zxi2c_get_bus_speed(i2c);
|
||||
zxi2c_set_bus_speed(i2c);
|
||||
|
||||
priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
|
||||
|
||||
adap = &i2c->adapter;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &zxi2c_algorithm;
|
||||
adap->quirks = &zxi2c_quirks;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
|
||||
snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
|
||||
dev_name(pdev->dev.parent), dev_name(i2c->dev));
|
||||
i2c_set_adapdata(adap, i2c);
|
||||
|
||||
return devm_i2c_add_adapter(&pdev->dev, adap);
|
||||
}
|
||||
|
||||
static int __maybe_unused zxi2c_resume(struct device *dev)
|
||||
{
|
||||
struct viai2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
|
||||
zxi2c_set_bus_speed(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops zxi2c_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
|
||||
};
|
||||
|
||||
static const struct acpi_device_id zxi2c_acpi_match[] = {
|
||||
{"IIC1D17", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
|
||||
|
||||
static struct platform_driver zxi2c_driver = {
|
||||
.probe = zxi2c_probe,
|
||||
.driver = {
|
||||
.name = "i2c_zhaoxin",
|
||||
.acpi_match_table = zxi2c_acpi_match,
|
||||
.pm = &zxi2c_pm,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(zxi2c_driver);
|
||||
|
||||
MODULE_AUTHOR("HansHu@zhaoxin.com");
|
||||
MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -416,7 +416,6 @@ static void vprbrd_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver vprbrd_i2c_driver = {
|
||||
.driver.name = "viperboard-i2c",
|
||||
.driver.owner = THIS_MODULE,
|
||||
.probe = vprbrd_i2c_probe,
|
||||
.remove_new = vprbrd_i2c_remove,
|
||||
};
|
||||
|
@ -1,421 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Wondermedia I2C Master Mode Driver
|
||||
*
|
||||
* Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
|
||||
*
|
||||
* Derived from GPLv2+ licensed source:
|
||||
* - Copyright (C) 2008 WonderMedia Technologies, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define REG_CR 0x00
|
||||
#define REG_TCR 0x02
|
||||
#define REG_CSR 0x04
|
||||
#define REG_ISR 0x06
|
||||
#define REG_IMR 0x08
|
||||
#define REG_CDR 0x0A
|
||||
#define REG_TR 0x0C
|
||||
#define REG_MCR 0x0E
|
||||
#define REG_SLAVE_CR 0x10
|
||||
#define REG_SLAVE_SR 0x12
|
||||
#define REG_SLAVE_ISR 0x14
|
||||
#define REG_SLAVE_IMR 0x16
|
||||
#define REG_SLAVE_DR 0x18
|
||||
#define REG_SLAVE_TR 0x1A
|
||||
|
||||
/* REG_CR Bit fields */
|
||||
#define CR_TX_NEXT_ACK 0x0000
|
||||
#define CR_ENABLE 0x0001
|
||||
#define CR_TX_NEXT_NO_ACK 0x0002
|
||||
#define CR_TX_END 0x0004
|
||||
#define CR_CPU_RDY 0x0008
|
||||
#define SLAV_MODE_SEL 0x8000
|
||||
|
||||
/* REG_TCR Bit fields */
|
||||
#define TCR_STANDARD_MODE 0x0000
|
||||
#define TCR_MASTER_WRITE 0x0000
|
||||
#define TCR_HS_MODE 0x2000
|
||||
#define TCR_MASTER_READ 0x4000
|
||||
#define TCR_FAST_MODE 0x8000
|
||||
#define TCR_SLAVE_ADDR_MASK 0x007F
|
||||
|
||||
/* REG_ISR Bit fields */
|
||||
#define ISR_NACK_ADDR 0x0001
|
||||
#define ISR_BYTE_END 0x0002
|
||||
#define ISR_SCL_TIMEOUT 0x0004
|
||||
#define ISR_WRITE_ALL 0x0007
|
||||
|
||||
/* REG_IMR Bit fields */
|
||||
#define IMR_ENABLE_ALL 0x0007
|
||||
|
||||
/* REG_CSR Bit fields */
|
||||
#define CSR_RCV_NOT_ACK 0x0001
|
||||
#define CSR_RCV_ACK_MASK 0x0001
|
||||
#define CSR_READY_MASK 0x0002
|
||||
|
||||
/* REG_TR */
|
||||
#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8)
|
||||
#define TR_STD 0x0064
|
||||
#define TR_HS 0x0019
|
||||
|
||||
/* REG_MCR */
|
||||
#define MCR_APB_96M 7
|
||||
#define MCR_APB_166M 12
|
||||
|
||||
#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
struct wmt_i2c_dev {
|
||||
struct i2c_adapter adapter;
|
||||
struct completion complete;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
u16 tcr;
|
||||
int irq;
|
||||
u16 cmd_status;
|
||||
};
|
||||
|
||||
static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + WMT_I2C_TIMEOUT;
|
||||
while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long wait_result;
|
||||
|
||||
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
msecs_to_jiffies(500));
|
||||
if (!wait_result)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (i2c_dev->cmd_status & ISR_NACK_ADDR)
|
||||
ret = -EIO;
|
||||
|
||||
if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
|
||||
int last)
|
||||
{
|
||||
u16 val, tcr_val = i2c_dev->tcr;
|
||||
int ret;
|
||||
int xfer_len = 0;
|
||||
|
||||
if (pmsg->len == 0) {
|
||||
/*
|
||||
* We still need to run through the while (..) once, so
|
||||
* start at -1 and break out early from the loop
|
||||
*/
|
||||
xfer_len = -1;
|
||||
writew(0, i2c_dev->base + REG_CDR);
|
||||
} else {
|
||||
writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
|
||||
}
|
||||
|
||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||
val = readw(i2c_dev->base + REG_CR);
|
||||
val &= ~CR_TX_END;
|
||||
val |= CR_CPU_RDY;
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
}
|
||||
|
||||
reinit_completion(&i2c_dev->complete);
|
||||
|
||||
tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
|
||||
|
||||
writew(tcr_val, i2c_dev->base + REG_TCR);
|
||||
|
||||
if (pmsg->flags & I2C_M_NOSTART) {
|
||||
val = readw(i2c_dev->base + REG_CR);
|
||||
val |= CR_CPU_RDY;
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
}
|
||||
|
||||
while (xfer_len < pmsg->len) {
|
||||
ret = wmt_check_status(i2c_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xfer_len++;
|
||||
|
||||
val = readw(i2c_dev->base + REG_CSR);
|
||||
if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
|
||||
dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (pmsg->len == 0) {
|
||||
val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
break;
|
||||
}
|
||||
|
||||
if (xfer_len == pmsg->len) {
|
||||
if (last != 1)
|
||||
writew(CR_ENABLE, i2c_dev->base + REG_CR);
|
||||
} else {
|
||||
writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
|
||||
REG_CDR);
|
||||
writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
|
||||
{
|
||||
u16 val, tcr_val = i2c_dev->tcr;
|
||||
int ret;
|
||||
u32 xfer_len = 0;
|
||||
|
||||
val = readw(i2c_dev->base + REG_CR);
|
||||
val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
|
||||
|
||||
if (!(pmsg->flags & I2C_M_NOSTART))
|
||||
val |= CR_CPU_RDY;
|
||||
|
||||
if (pmsg->len == 1)
|
||||
val |= CR_TX_NEXT_NO_ACK;
|
||||
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
|
||||
reinit_completion(&i2c_dev->complete);
|
||||
|
||||
tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
|
||||
|
||||
writew(tcr_val, i2c_dev->base + REG_TCR);
|
||||
|
||||
if (pmsg->flags & I2C_M_NOSTART) {
|
||||
val = readw(i2c_dev->base + REG_CR);
|
||||
val |= CR_CPU_RDY;
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
}
|
||||
|
||||
while (xfer_len < pmsg->len) {
|
||||
ret = wmt_check_status(i2c_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
|
||||
xfer_len++;
|
||||
|
||||
val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
|
||||
if (xfer_len == pmsg->len - 1)
|
||||
val |= CR_TX_NEXT_NO_ACK;
|
||||
writew(val, i2c_dev->base + REG_CR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmt_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[],
|
||||
int num)
|
||||
{
|
||||
struct i2c_msg *pmsg;
|
||||
int i;
|
||||
int ret = 0;
|
||||
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
|
||||
for (i = 0; ret >= 0 && i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||
ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
ret = wmt_i2c_read(i2c_dev, pmsg);
|
||||
else
|
||||
ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
|
||||
}
|
||||
|
||||
return (ret < 0) ? ret : i;
|
||||
}
|
||||
|
||||
static u32 wmt_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm wmt_i2c_algo = {
|
||||
.master_xfer = wmt_i2c_xfer,
|
||||
.functionality = wmt_i2c_func,
|
||||
};
|
||||
|
||||
static irqreturn_t wmt_i2c_isr(int irq, void *data)
|
||||
{
|
||||
struct wmt_i2c_dev *i2c_dev = data;
|
||||
|
||||
/* save the status and write-clear it */
|
||||
i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
|
||||
writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
|
||||
|
||||
complete(&i2c_dev->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(i2c_dev->clk);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_set_rate(i2c_dev->clk, 20000000);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
writew(0, i2c_dev->base + REG_CR);
|
||||
writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
|
||||
writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
|
||||
writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
|
||||
writew(CR_ENABLE, i2c_dev->base + REG_CR);
|
||||
readw(i2c_dev->base + REG_CSR); /* read clear */
|
||||
writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
|
||||
|
||||
if (i2c_dev->tcr == TCR_FAST_MODE)
|
||||
writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
|
||||
else
|
||||
writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmt_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct wmt_i2c_dev *i2c_dev;
|
||||
struct i2c_adapter *adap;
|
||||
int err;
|
||||
u32 clk_rate;
|
||||
|
||||
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
i2c_dev->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!i2c_dev->irq) {
|
||||
dev_err(&pdev->dev, "irq missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2c_dev->clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(&pdev->dev, "unable to request clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
|
||||
err = of_property_read_u32(np, "clock-frequency", &clk_rate);
|
||||
if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
|
||||
i2c_dev->tcr = TCR_FAST_MODE;
|
||||
|
||||
i2c_dev->dev = &pdev->dev;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
|
||||
"i2c", i2c_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
adap = &i2c_dev->adapter;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &wmt_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
init_completion(&i2c_dev->complete);
|
||||
|
||||
err = wmt_i2c_reset_hardware(i2c_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "error initializing hardware\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = i2c_add_adapter(adap);
|
||||
if (err)
|
||||
goto err_disable_clk;
|
||||
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void wmt_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
/* Disable interrupts, clock and delete adapter */
|
||||
writew(0, i2c_dev->base + REG_IMR);
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
i2c_del_adapter(&i2c_dev->adapter);
|
||||
}
|
||||
|
||||
static const struct of_device_id wmt_i2c_dt_ids[] = {
|
||||
{ .compatible = "wm,wm8505-i2c" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver wmt_i2c_driver = {
|
||||
.probe = wmt_i2c_probe,
|
||||
.remove_new = wmt_i2c_remove,
|
||||
.driver = {
|
||||
.name = "wmt-i2c",
|
||||
.of_match_table = wmt_i2c_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(wmt_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
|
||||
MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
|
@ -445,6 +445,11 @@ static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
|
||||
return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev));
|
||||
}
|
||||
|
||||
static struct i2c_adapter *i2c_acpi_find_adapter_by_adev(struct acpi_device *adev)
|
||||
{
|
||||
return i2c_find_adapter_by_fwnode(acpi_fwnode_handle(adev));
|
||||
}
|
||||
|
||||
static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
|
||||
void *arg)
|
||||
{
|
||||
@ -471,11 +476,17 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
|
||||
break;
|
||||
|
||||
client = i2c_acpi_find_client_by_adev(adev);
|
||||
if (!client)
|
||||
break;
|
||||
if (client) {
|
||||
i2c_unregister_device(client);
|
||||
put_device(&client->dev);
|
||||
}
|
||||
|
||||
adapter = i2c_acpi_find_adapter_by_adev(adev);
|
||||
if (adapter) {
|
||||
acpi_unbind_one(&adapter->dev);
|
||||
put_device(&adapter->dev);
|
||||
}
|
||||
|
||||
i2c_unregister_device(client);
|
||||
put_device(&client->dev);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -127,19 +127,6 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap)
|
||||
return parent->algo->functionality(parent);
|
||||
}
|
||||
|
||||
/* Return all parent classes, merged */
|
||||
static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
|
||||
{
|
||||
unsigned int class = 0;
|
||||
|
||||
do {
|
||||
class |= parent->class;
|
||||
parent = i2c_parent_is_i2c_adapter(parent);
|
||||
} while (parent);
|
||||
|
||||
return class;
|
||||
}
|
||||
|
||||
static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
@ -281,8 +268,7 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = {
|
||||
};
|
||||
|
||||
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
|
||||
u32 force_nr, u32 chan_id,
|
||||
unsigned int class)
|
||||
u32 force_nr, u32 chan_id)
|
||||
{
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
struct i2c_mux_priv *priv;
|
||||
@ -340,14 +326,6 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
|
||||
else
|
||||
priv->adap.lock_ops = &i2c_parent_lock_ops;
|
||||
|
||||
/* Sanity check on class */
|
||||
if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED)
|
||||
dev_err(&parent->dev,
|
||||
"Segment %d behind mux can't share classes with ancestors\n",
|
||||
chan_id);
|
||||
else
|
||||
priv->adap.class = class;
|
||||
|
||||
/*
|
||||
* Try to populate the mux adapter's of_node, expands to
|
||||
* nothing if !CONFIG_OF.
|
||||
|
@ -167,7 +167,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Actually add the mux adapter */
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0);
|
||||
if (ret)
|
||||
i2c_put_adapter(muxc->parent);
|
||||
|
||||
|
@ -206,9 +206,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < mux->data.n_values; i++) {
|
||||
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
|
||||
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]);
|
||||
if (ret)
|
||||
goto add_adapter_failed;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ static int i2c_mux_probe(struct platform_device *pdev)
|
||||
goto err_children;
|
||||
}
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan);
|
||||
if (ret)
|
||||
goto err_children;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ static int ltc4306_probe(struct i2c_client *client)
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < chip->nchans; num++) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, num, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, num);
|
||||
if (ret) {
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return ret;
|
||||
|
@ -154,7 +154,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev)
|
||||
|
||||
/* Create an adapter for each channel. */
|
||||
for (num = 0; num < pdata->num_adaps; num++) {
|
||||
err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0);
|
||||
err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num]);
|
||||
if (err)
|
||||
goto virt_reg_failed;
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ static int pca9541_probe(struct i2c_client *client)
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -644,7 +644,7 @@ static int pca954x_probe(struct i2c_client *client)
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < data->chip->nchans; num++) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, num, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, num);
|
||||
if (ret)
|
||||
goto fail_cleanup;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
|
||||
/* Do not add any adapter for the idle state (if it's there at all). */
|
||||
for (i = 0; i < num_names - !!muxc->deselect; i++) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, i, 0);
|
||||
ret = i2c_mux_add_adapter(muxc, 0, i);
|
||||
if (ret)
|
||||
goto err_del_adapter;
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
for (i = 0; i < mux->data.n_values; i++) {
|
||||
nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], 0);
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]);
|
||||
if (ret)
|
||||
goto err_del_mux_adapters;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ static int mpu3050_i2c_probe(struct i2c_client *client)
|
||||
else {
|
||||
mpu3050->i2cmux->priv = mpu3050;
|
||||
/* Ignore failure, not critical */
|
||||
i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
|
||||
i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -142,7 +142,7 @@ static int inv_mpu_probe(struct i2c_client *client)
|
||||
if (!st->muxc)
|
||||
return -ENOMEM;
|
||||
st->muxc->priv = dev_get_drvdata(&client->dev);
|
||||
result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
|
||||
result = i2c_mux_add_adapter(st->muxc, 0, 0);
|
||||
if (result)
|
||||
return result;
|
||||
result = inv_mpu_acpi_create_mux_client(client);
|
||||
|
@ -1480,7 +1480,7 @@ static int af9013_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
state->muxc->priv = state;
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@ -2208,7 +2208,7 @@ static int lgdt3306a_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
state->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@ -1873,7 +1873,7 @@ static int m88ds3103_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
dev->muxc->priv = dev;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@ -838,7 +838,7 @@ static int rtl2830_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
dev->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ static int rtl2832_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
dev->muxc->priv = dev;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@ -744,7 +744,7 @@ static int si2168_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
dev->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@ -383,7 +383,7 @@ static int max9286_i2c_mux_init(struct max9286_priv *priv)
|
||||
for_each_source(priv, source) {
|
||||
unsigned int index = to_index(priv, source);
|
||||
|
||||
ret = i2c_mux_add_adapter(priv->mux, 0, index, 0);
|
||||
ret = i2c_mux_add_adapter(priv->mux, 0, index);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
@ -567,10 +567,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
|
||||
|
||||
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
|
||||
{
|
||||
return i2c_mux_add_adapter(dev->muxc,
|
||||
0,
|
||||
mux_no /* chan_id */,
|
||||
0 /* class */);
|
||||
return i2c_mux_add_adapter(dev->muxc, 0, mux_no);
|
||||
}
|
||||
|
||||
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
|
||||
|
@ -2811,7 +2811,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client)
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < nchans; i++) {
|
||||
if (i2c_mux_add_adapter(muxc, 0, i, 0)) {
|
||||
if (i2c_mux_add_adapter(muxc, 0, i)) {
|
||||
dev_err(dev, "Failed to register mux #%d\n", i);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return -ENODEV;
|
||||
|
@ -358,7 +358,7 @@ static int sbsm_probe(struct i2c_client *client)
|
||||
/* register muxed i2c channels. One for each supported battery */
|
||||
for (i = 0; i < SBSM_MAX_BATS; ++i) {
|
||||
if (data->supported_bats & BIT(i)) {
|
||||
ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0);
|
||||
ret = i2c_mux_add_adapter(data->muxc, 0, i + 1);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ struct i2c_adapter *i2c_root_adapter(struct device *dev);
|
||||
* callback functions to perform hardware-specific mux control.
|
||||
*/
|
||||
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
|
||||
u32 force_nr, u32 chan_id,
|
||||
unsigned int class);
|
||||
u32 force_nr, u32 chan_id);
|
||||
|
||||
void i2c_mux_del_adapters(struct i2c_mux_core *muxc);
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
* @values: Array of bitmasks of GPIO settings (low/high) for each
|
||||
* position
|
||||
* @n_values: Number of multiplexer positions (busses to instantiate)
|
||||
* @classes: Optional I2C auto-detection classes
|
||||
* @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
|
||||
*/
|
||||
struct i2c_mux_gpio_platform_data {
|
||||
@ -26,7 +25,6 @@ struct i2c_mux_gpio_platform_data {
|
||||
int base_nr;
|
||||
const unsigned *values;
|
||||
int n_values;
|
||||
const unsigned *classes;
|
||||
unsigned idle;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user