i2c-for-6.13-rc1

i2c-core (Wolfram)
 
  - drivers can now use a GPIO as a side channel for SMBus Alerts
    using a generic binding
 
  - regular stuff like mem leak fix, Makefile maintenance...
 
 i2c-host updates (Andi)
 
 Major Improvements and Refactoring:
 
  - All controllers using the 'remove_new' callback have been
    reverted to use the 'remove' callback.
 
  - Intel SCH controller underwent significant refactoring,
    this brings love and a modern look to the driver.
 
  - PIIX4 driver refactored to enable usage by other drivers
    (e.g., AMD ASF).
 
  - iMX/MXC improved message handling to reduce protocol overhead:
      Refactored DMA/non-DMA read/write and bus polling mechanisms
      to achieve this.
 
  - ACPI documentation for PIIX4.
 
 New Features:
 
  - i2c-cadence added support for atomic transfers.
  - Qualcomm CII added support for a 32MHz serial engine clock.
 
 Deprecated Features:
 
  - Dropped outdated support for AMD756 S4882 and NFORCE2 S4985. If
    somebody misses this, Jean will rewrite support using the proper
    i2c mux framework.
 
 New Hardware Support:
 
  - Added support for:
    - Intel Panther Lake (new ID)
    - AMD ASF (new driver)
    - S32G2/S32G3 SoCs (new ID)
    - Realtek RTL I2C Controller (new driver)
    - HJMC01 DesignWare ACPI HID (new ID)
    - PIC64GX to Microchip Core (new ID)
    - Qualcomm SDM670 to Qualcomm CCI (new ID)
 
 at24 updates (Bartosz)
 
 - add support for the lockable page on ST M24256E
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmc+/UUACgkQFA3kzBSg
 KbZrqA/+MqNiN8NIkgA3nIODQP1Cf/aUhywHITsRgoo85vVDHeiaJtKc25KMi6Tb
 I5GgHp9Q0TtYdXzKM+nC7xjO64h8obGRXPHv5fDbRAZlFbWSR8u+iQp9entuVJe4
 TiRFh9M8chAC82QNCvYVKx3jTHlmZaR7bXDtoAf7bG0LdWnjey1JSFfn6cPweVNM
 0sD95tjBDb53tCRPGVKrCsnrs5uGxugGvH5I16hB6iokbaiIlGosIBg/8YBGHCS8
 V8RqLSfzCl7X7xICeRv2ttRWx78Nz38RBC+truR5OEvvdZ+J2UCZ0710/w6FWfPp
 F85ReZrG5bh49Jobt/AyC7VXqL6djg+C6jVU1rX8Eb3G6TapL4iCJe9CcI4EXANY
 1mtzZ8fqg4EaVMVRQx3tiyjNFWQba9ssSyzRB8ZfCqmS6xV2HXJby3zNoDA9SoxH
 tNn3vp0FfOtdn4lGbYAJE4zUMupXiUkrgswj5sKltYjXh/OmaDLJfYeFhPp+SwvW
 uWuLZveM0mAn6BWyM4g9v6MIHWiUumkF5xwlAfNOh3ogxqUtAPtbzk7FQ332ni0Z
 X11J5EOBzbMQR24moRo7xtQSdoDDSQDpytOVXTY2QWv3rZuk0oVL57aifJdtTkrK
 QktmylTfYlfI2hWLRoWFJ1j7nQyBveiNHh/qq0hxCkXLP3vA5gs=
 =lrn5
 -----END PGP SIGNATURE-----

Merge tag 'i2c-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "Core:

   - drivers can now use a GPIO as a side channel for SMBus Alerts using
     a generic binding

   - regular stuff like mem leak fix, Makefile maintenance...

  Host improvements and refactoring:

   - All controllers using the 'remove_new' callback have been reverted
     to use the 'remove' callback

   - Intel SCH controller underwent significant refactoring, this brings
     love and a modern look to the driver

   - PIIX4 driver refactored to enable usage by other drivers (e.g., AMD
     ASF)

   - iMX/MXC improved message handling to reduce protocol overhead:
     Refactored DMA/non-DMA read/write and bus polling mechanisms to
     achieve this.

   - ACPI documentation for PIIX4

  New host features:

   - i2c-cadence support for atomic transfers

   - Qualcomm CII support for a 32MHz serial engine clock

  Deprecated features:

   - Dropped outdated support for AMD756 S4882 and NFORCE2 S4985. If
     somebody misses this, Jean will rewrite support using the proper
     i2c mux framework.

  New hardware IDs for existing drivers:

   - Intel Panther Lake

   - S32G2/S32G3 SoCs

   - HJMC01 DesignWare ACPI HID

   - PIC64GX to Microchip Core

   - Qualcomm SDM670 to Qualcomm CCI

  New drivers:

   - AMD ASF

   - Realtek RTL I2C Controller

  at24 updates:

   - add support for the lockable page on ST M24256E"

* tag 'i2c-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (59 commits)
  docs: i2c: piix4: Add ACPI section
  i2c: Add driver for the RTL9300 I2C controller
  i2c: qcom-cci: Remove unused struct member cci_clk_rate
  dt-bindings: i2c: Add Realtek RTL I2C Controller
  i2c: busses: Use *-y instead of *-objs in Makefile
  i2c: imx: add support for S32G2/S32G3 SoCs
  dt-bindings: i2c: imx: add SoC specific compatible strings for S32G
  i2c: qcom-cci: Remove the unused variable cci_clk_rate
  i2c: Drop legacy muxing pseudo-drivers
  i2c: imx: prevent rescheduling in non dma mode
  i2c: imx: separate atomic, dma and non-dma use case
  i2c: imx: do not poll for bus busy in single master mode
  i2c: designware: Add a new ACPI HID for HJMC01 I2C controller
  i2c: qcom-geni: Keep comment why interrupts start disabled
  dt-bindings: i2c: microchip: corei2c: Add PIC64GX as compatible with driver
  i2c: designware: constify abort_sources
  i2c: Switch back to struct platform_driver::remove()
  i2c: qcom-geni: Support systems with 32MHz serial engine clock
  i2c: qcom-cci: Stop complaining about DT set clock rate
  dt-bindings: i2c: qcom-cci: Document SDM670 compatible
  ...
This commit is contained in:
Linus Torvalds 2024-11-21 13:19:29 -08:00
commit 55ae3eef10
121 changed files with 2184 additions and 1178 deletions

View File

@ -141,6 +141,8 @@ properties:
- const: microchip,24aa025e48
- items:
- const: microchip,24aa025e64
- items:
- const: st,24256e-wl
- pattern: '^atmel,24c(32|64)d-wl$' # Actual vendor is st
label:

View File

@ -18,6 +18,7 @@ properties:
- const: fsl,imx1-i2c
- const: fsl,imx21-i2c
- const: fsl,vf610-i2c
- const: nxp,s32g2-i2c
- items:
- enum:
- fsl,ls1012a-i2c
@ -54,6 +55,9 @@ properties:
- fsl,imx8mn-i2c
- fsl,imx8mp-i2c
- const: fsl,imx21-i2c
- items:
- const: nxp,s32g3-i2c
- const: nxp,s32g2-i2c
reg:
maxItems: 1

View File

@ -16,7 +16,9 @@ properties:
compatible:
oneOf:
- items:
- const: microchip,mpfs-i2c # Microchip PolarFire SoC compatible SoCs
- enum:
- microchip,pic64gx-i2c
- microchip,mpfs-i2c # Microchip PolarFire SoC compatible SoCs
- const: microchip,corei2c-rtl-v7 # Microchip Fabric based i2c IP core
- const: microchip,corei2c-rtl-v7 # Microchip Fabric based i2c IP core

View File

@ -27,6 +27,7 @@ properties:
- enum:
- qcom,sc7280-cci
- qcom,sc8280xp-cci
- qcom,sdm670-cci
- qcom,sdm845-cci
- qcom,sm6350-cci
- qcom,sm8250-cci
@ -139,6 +140,24 @@ allOf:
- const: cci
- const: camss_ahb
- if:
properties:
compatible:
contains:
enum:
- qcom,sdm670-cci
then:
properties:
clocks:
minItems: 4
maxItems: 4
clock-names:
items:
- const: camnoc_axi
- const: soc_ahb
- const: cpas_ahb
- const: cci
- if:
properties:
compatible:

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/realtek,rtl9301-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek RTL I2C Controller
maintainers:
- Chris Packham <chris.packham@alliedtelesis.co.nz>
description:
The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which
if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be
assigned to either I2C controller.
properties:
compatible:
oneOf:
- items:
- enum:
- realtek,rtl9302b-i2c
- realtek,rtl9302c-i2c
- realtek,rtl9303-i2c
- const: realtek,rtl9301-i2c
- const: realtek,rtl9301-i2c
reg:
description: Register offset and size this I2C controller.
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
'^i2c@[0-7]$':
$ref: /schemas/i2c/i2c-controller.yaml
unevaluatedProperties: false
properties:
reg:
description: The SDA pin associated with the I2C bus.
maxItems: 1
required:
- reg
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c@36c {
compatible = "realtek,rtl9301-i2c";
reg = <0x36c 0x14>;
#address-cells = <1>;
#size-cells = <0>;
i2c@2 {
reg = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
};

View File

@ -49,6 +49,7 @@ Supported adapters:
* Intel Meteor Lake (SOC and PCH)
* Intel Birch Stream (SOC)
* Intel Arrow Lake (SOC)
* Intel Panther Lake (SOC)
Datasheets: Publicly available at the Intel website

View File

@ -109,3 +109,66 @@ which can easily get corrupted due to a state machine bug. These are mostly
Thinkpad laptops, but desktop systems may also be affected. We have no list
of all affected systems, so the only safe solution was to prevent access to
the SMBus on all IBM systems (detected using DMI data.)
Description in the ACPI code
----------------------------
Device driver for the PIIX4 chip creates a separate I2C bus for each of its
ports::
$ i2cdetect -l
...
i2c-7 unknown SMBus PIIX4 adapter port 0 at 0b00 N/A
i2c-8 unknown SMBus PIIX4 adapter port 2 at 0b00 N/A
i2c-9 unknown SMBus PIIX4 adapter port 1 at 0b20 N/A
...
Therefore if you want to access one of these busses in the ACPI code, port
subdevices are needed to be declared inside the PIIX device::
Scope (\_SB_.PCI0.SMBS)
{
Name (_ADR, 0x00140000)
Device (SMB0) {
Name (_ADR, 0)
}
Device (SMB1) {
Name (_ADR, 1)
}
Device (SMB2) {
Name (_ADR, 2)
}
}
If this is not the case for your UEFI firmware and you don't have access to the
source code, you can use ACPI SSDT Overlays to provide the missing parts. Just
keep in mind that in this case you would need to load your extra SSDT table
before the piix4 driver starts, i.e. you should provide SSDT via initrd or EFI
variable methods and not via configfs.
As an example of usage here is the ACPI snippet code that would assign jc42
driver to the 0x1C device on the I2C bus created by the PIIX port 0::
Device (JC42) {
Name (_HID, "PRP0001")
Name (_DDN, "JC42 Temperature sensor")
Name (_CRS, ResourceTemplate () {
I2cSerialBusV2 (
0x001c,
ControllerInitiated,
100000,
AddressingMode7Bit,
"\\_SB.PCI0.SMBS.SMB0",
0
)
})
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "compatible", Package() { "jedec,jc-42.4-temp" } },
}
})
}

View File

@ -31,12 +31,11 @@ driver model device node, and its I2C address.
::
static struct i2c_device_id foo_idtable[] = {
static const struct i2c_device_id foo_idtable[] = {
{ "foo", my_id_for_foo },
{ "bar", my_id_for_bar },
{ }
};
MODULE_DEVICE_TABLE(i2c, foo_idtable);
static struct i2c_driver foo_driver = {

View File

@ -1115,6 +1115,12 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-amd-mp2*
AMD ASF I2C DRIVER
M: Shyam Sundar S K <shyam-sundar.s-k@amd.com>
L: linux-i2c@vger.kernel.org
S: Supported
F: drivers/i2c/busses/i2c-amd-asf-plat.c
AMD PDS CORE DRIVER
M: Shannon Nelson <shannon.nelson@amd.com>
M: Brett Creeley <brett.creeley@amd.com>
@ -10750,14 +10756,12 @@ F: Documentation/i2c/busses/i2c-viapro.rst
F: drivers/i2c/busses/i2c-ali1535.c
F: drivers/i2c/busses/i2c-ali1563.c
F: drivers/i2c/busses/i2c-ali15x3.c
F: drivers/i2c/busses/i2c-amd756-s4882.c
F: drivers/i2c/busses/i2c-amd756.c
F: drivers/i2c/busses/i2c-amd8111.c
F: drivers/i2c/busses/i2c-i801.c
F: drivers/i2c/busses/i2c-isch.c
F: drivers/i2c/busses/i2c-nforce2-s4985.c
F: drivers/i2c/busses/i2c-nforce2.c
F: drivers/i2c/busses/i2c-piix4.c
F: drivers/i2c/busses/i2c-piix4.*
F: drivers/i2c/busses/i2c-sis5595.c
F: drivers/i2c/busses/i2c-sis630.c
F: drivers/i2c/busses/i2c-sis96x.c
@ -20218,6 +20222,13 @@ S: Maintained
T: git https://github.com/pkshih/rtw.git
F: drivers/net/wireless/realtek/rtl8xxxu/
RTL9300 I2C DRIVER (rtl9300-i2c)
M: Chris Packham <chris.packham@alliedtelesis.co.nz>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
F: drivers/i2c/busses/i2c-rtl9300.c
RTRS TRANSPORT DRIVERS
M: Md. Haris Iqbal <haris.iqbal@ionos.com>
M: Jack Wang <jinpu.wang@ionos.com>

View File

@ -5,10 +5,10 @@
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
i2c-core-objs := i2c-core-base.o i2c-core-smbus.o
i2c-core-y := i2c-core-base.o i2c-core-smbus.o
i2c-core-$(CONFIG_ACPI) += i2c-core-acpi.o
i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o
i2c-core-$(CONFIG_OF) += i2c-core-of.o
i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o
i2c-core-$(CONFIG_OF) += i2c-core-of.o
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o

View File

@ -62,19 +62,6 @@ config I2C_AMD756
This driver can also be built as a module. If so, the module
will be called i2c-amd756.
config I2C_AMD756_S4882
tristate "SMBus multiplexing on the Tyan S4882"
depends on I2C_AMD756 && X86
help
Enabling this option will add specific SMBus support for the Tyan
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
over 8 different channels, where the various memory module EEPROMs
and temperature sensors live. Saying yes here will give you access
to these in addition to the trunk.
This driver can also be built as a module. If so, the module
will be called i2c-amd756-s4882.
config I2C_AMD8111
tristate "AMD 8111"
depends on PCI && HAS_IOPORT
@ -95,6 +82,23 @@ config I2C_AMD_MP2
This driver can also be built as modules. If so, the modules will
be called i2c-amd-mp2-pci and i2c-amd-mp2-plat.
config I2C_AMD_ASF
tristate "AMD ASF I2C Controller Support"
depends on I2C_PIIX4
select I2C_SLAVE
help
This option enables support for the AMD ASF (Alert Standard Format)
I2C controller. The AMD ASF controller is an SMBus controller with
built-in ASF functionality, allowing it to issue generic SMBus
packets and communicate with the DASH controller using MCTP over
ASF.
If you have an AMD system with ASF support and want to enable this
functionality, say Y or M here. If unsure, say N.
To compile this driver as a module, choose M here: the module will
be called i2c_amd_asf_plat.
config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver"
depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
@ -160,6 +164,7 @@ config I2C_I801
Meteor Lake (SOC and PCH)
Birch Stream (SOC)
Arrow Lake (SOC)
Panther Lake (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@ -250,19 +255,6 @@ config I2C_NFORCE2
This driver can also be built as a module. If so, the module
will be called i2c-nforce2.
config I2C_NFORCE2_S4985
tristate "SMBus multiplexing on the Tyan S4985"
depends on I2C_NFORCE2 && X86
help
Enabling this option will add specific SMBus support for the Tyan
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
over 4 different channels, where the various memory module EEPROMs
live. Saying yes here will give you access to these in addition
to the trunk.
This driver can also be built as a module. If so, the module
will be called i2c-nforce2-s4985.
config I2C_NVIDIA_GPU
tristate "NVIDIA GPU I2C controller"
depends on PCI
@ -439,7 +431,7 @@ config I2C_AT91
are facing this situation, use the i2c-gpio driver.
config I2C_AT91_SLAVE_EXPERIMENTAL
tristate "Microchip AT91 I2C experimental slave mode"
bool "Microchip AT91 I2C experimental slave mode"
depends on I2C_AT91
select I2C_SLAVE
help
@ -448,7 +440,7 @@ config I2C_AT91_SLAVE_EXPERIMENTAL
been tested in a heavy way, help wanted.
There are known bugs:
- It can hang, on a SAMA5D4, after several transfers.
- There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as
- There are some mismatches with a SAMA5D4 as slave and a SAMA5D2 as
master.
config I2C_AU1550
@ -751,13 +743,14 @@ config I2C_IMG
config I2C_IMX
tristate "IMX I2C interface"
depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || COMPILE_TEST
depends on ARCH_MXC || ARCH_LAYERSCAPE || ARCH_S32 || COLDFIRE \
|| COMPILE_TEST
select I2C_SLAVE
help
Say Y here if you want to use the IIC bus controller on
the Freescale i.MX/MXC, Layerscape or ColdFire processors.
the Freescale i.MX/MXC/S32G, Layerscape or ColdFire processors.
This driver can also be built as a module. If so, the module
This driver can also be built as a module. If so, the module
will be called i2c-imx.
config I2C_IMX_LPI2C
@ -1070,6 +1063,16 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
config I2C_RTL9300
tristate "Realtek RTL9300 I2C controller"
depends on MACH_REALTEK_RTL || COMPILE_TEST
help
Say Y here to include support for the I2C controller in Realtek
RTL9300 SoCs.
This driver can also be built as a module. If so, the module will
be called i2c-rtl9300.
config I2C_RZV2M
tristate "Renesas RZ/V2M adapter"
depends on ARCH_RENESAS || COMPILE_TEST

View File

@ -14,14 +14,12 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o
obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
@ -38,12 +36,11 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
# Embedded system I2C/SMBus host controller drivers
obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o
obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o
obj-$(CONFIG_I2C_AMD_ASF) += i2c-amd-asf-plat.o
obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o
ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y)
i2c-at91-objs += i2c-at91-slave.o
endif
i2c-at91-y := i2c-at91-core.o i2c-at91-master.o
i2c-at91-$(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL) += i2c-at91-slave.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
@ -104,6 +101,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o
obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
@ -112,8 +110,8 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o
obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o
obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o
i2c-stm32f7-drv-y := i2c-stm32f7.o i2c-stm32.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
@ -122,10 +120,10 @@ obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o
i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
i2c-octeon-y := i2c-octeon-core.o i2c-octeon-platdrv.o
obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
i2c-thunderx-y := i2c-octeon-core.o i2c-thunderx-pcidrv.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o

View File

@ -482,7 +482,7 @@ MODULE_DEVICE_TABLE(of, altr_i2c_of_match);
static struct platform_driver altr_i2c_driver = {
.probe = altr_i2c_probe,
.remove_new = altr_i2c_remove,
.remove = altr_i2c_remove,
.driver = {
.name = "altera-i2c",
.of_match_table = altr_i2c_of_match,

View File

@ -0,0 +1,369 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD Alert Standard Format Platform Driver
*
* Copyright (c) 2024, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
* Sanket Goswami <Sanket.Goswami@amd.com>
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/devm-helpers.h>
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/sprintf.h>
#include "i2c-piix4.h"
/* ASF register bits */
#define ASF_SLV_LISTN 0
#define ASF_SLV_INTR 1
#define ASF_SLV_RST 4
#define ASF_PEC_SP 5
#define ASF_DATA_EN 7
#define ASF_MSTR_EN 16
#define ASF_CLK_EN 17
/* ASF address offsets */
#define ASFINDEX (0x07 + piix4_smba)
#define ASFLISADDR (0x09 + piix4_smba)
#define ASFSTA (0x0A + piix4_smba)
#define ASFSLVSTA (0x0D + piix4_smba)
#define ASFDATARWPTR (0x11 + piix4_smba)
#define ASFSETDATARDPTR (0x12 + piix4_smba)
#define ASFDATABNKSEL (0x13 + piix4_smba)
#define ASFSLVEN (0x15 + piix4_smba)
#define ASF_BLOCK_MAX_BYTES 72
#define ASF_ERROR_STATUS GENMASK(3, 1)
struct amd_asf_dev {
struct i2c_adapter adap;
void __iomem *eoi_base;
struct i2c_client *target;
struct delayed_work work_buf;
struct sb800_mmio_cfg mmio_cfg;
struct resource *port_addr;
};
static void amd_asf_process_target(struct work_struct *work)
{
struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work);
unsigned short piix4_smba = dev->port_addr->start;
u8 data[ASF_BLOCK_MAX_BYTES];
u8 bank, reg, cmd;
u8 len = 0, idx, val;
/* Read target status register */
reg = inb_p(ASFSLVSTA);
/* Check if no error bits are set in target status register */
if (reg & ASF_ERROR_STATUS) {
/* Set bank as full */
cmd = 0;
reg |= GENMASK(3, 2);
outb_p(reg, ASFDATABNKSEL);
} else {
/* Read data bank */
reg = inb_p(ASFDATABNKSEL);
bank = (reg & BIT(3)) ? 1 : 0;
/* Set read data bank */
if (bank) {
reg |= BIT(4);
reg &= ~BIT(3);
} else {
reg &= ~BIT(4);
reg &= ~BIT(2);
}
/* Read command register */
outb_p(reg, ASFDATABNKSEL);
cmd = inb_p(ASFINDEX);
len = inb_p(ASFDATARWPTR);
for (idx = 0; idx < len; idx++)
data[idx] = inb_p(ASFINDEX);
/* Clear data bank status */
if (bank) {
reg |= BIT(3);
outb_p(reg, ASFDATABNKSEL);
} else {
reg |= BIT(2);
outb_p(reg, ASFDATABNKSEL);
}
}
outb_p(0, ASFSETDATARDPTR);
if (cmd & BIT(0))
return;
/*
* Although i2c_slave_event() returns an appropriate error code, we
* don't check it here because we're operating in the workqueue context.
*/
i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val);
for (idx = 0; idx < len; idx++) {
val = data[idx];
i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val);
}
i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val);
}
static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit,
unsigned long offset, bool set)
{
unsigned long reg;
reg = inb_p(offset);
__assign_bit(bit, &reg, set);
outb_p(reg, offset);
}
static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set)
{
unsigned long reg;
reg = ioread32(dev->mmio_cfg.addr);
__assign_bit(bit, &reg, set);
iowrite32(reg, dev->mmio_cfg.addr);
}
static void amd_asf_setup_target(struct amd_asf_dev *dev)
{
unsigned short piix4_smba = dev->port_addr->start;
/* Reset both host and target before setting up */
outb_p(0, SMBHSTSTS);
outb_p(0, ASFSLVSTA);
outb_p(0, ASFSTA);
/* Update target address */
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true);
/* Enable target and set the clock */
amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false);
amd_asf_update_mmio_target(dev, ASF_CLK_EN, true);
/* Enable target interrupt */
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true);
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false);
/* Enable PEC and PEC append */
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
}
static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data)
{
struct amd_asf_dev *dev = i2c_get_adapdata(adap);
unsigned short piix4_smba = dev->port_addr->start;
u8 i, len;
outb_p((addr << 1), SMBHSTADD);
outb_p(command, SMBHSTCMD);
len = data[0];
if (len == 0 || len > ASF_BLOCK_MAX_BYTES)
return -EINVAL;
outb_p(len, SMBHSTDAT0);
/* Reset SMBBLKDAT */
inb_p(SMBHSTCNT);
for (i = 1; i <= len; i++)
outb_p(data[i], SMBBLKDAT);
outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT);
/* Enable PEC and PEC append */
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
return piix4_transaction(adap, piix4_smba);
}
static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct amd_asf_dev *dev = i2c_get_adapdata(adap);
unsigned short piix4_smba = dev->port_addr->start;
u8 asf_data[ASF_BLOCK_MAX_BYTES];
struct i2c_msg *dev_msgs = msgs;
u8 prev_port;
int ret;
if (msgs->flags & I2C_M_RD) {
dev_err(&adap->dev, "ASF: Read not supported\n");
return -EOPNOTSUPP;
}
/* Exclude the receive header and PEC */
if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) {
dev_warn(&adap->dev, "ASF: max message length exceeded\n");
return -EOPNOTSUPP;
}
asf_data[0] = dev_msgs->len;
memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len);
ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg);
if (ret)
return ret;
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false);
/* Clear ASF target status */
outb_p(0, ASFSLVSTA);
/* Enable ASF SMBus controller function */
amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true);
prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg);
ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data);
piix4_sb800_port_sel(prev_port, &dev->mmio_cfg);
amd_asf_setup_target(dev);
piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg);
return ret;
}
static int amd_asf_reg_target(struct i2c_client *target)
{
struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
unsigned short piix4_smba = dev->port_addr->start;
int ret;
u8 reg;
if (dev->target)
return -EBUSY;
ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg);
if (ret)
return ret;
reg = (target->addr << 1) | I2C_M_RD;
outb_p(reg, ASFLISADDR);
amd_asf_setup_target(dev);
dev->target = target;
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false);
piix4_sb800_region_release(&target->dev, &dev->mmio_cfg);
return 0;
}
static int amd_asf_unreg_target(struct i2c_client *target)
{
struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
unsigned short piix4_smba = dev->port_addr->start;
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false);
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
dev->target = NULL;
return 0;
}
static u32 amd_asf_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE;
}
static const struct i2c_algorithm amd_asf_smbus_algorithm = {
.master_xfer = amd_asf_xfer,
.reg_slave = amd_asf_reg_target,
.unreg_slave = amd_asf_unreg_target,
.functionality = amd_asf_func,
};
static irqreturn_t amd_asf_irq_handler(int irq, void *ptr)
{
struct amd_asf_dev *dev = ptr;
unsigned short piix4_smba = dev->port_addr->start;
u8 target_int = inb_p(ASFSTA);
if (target_int & BIT(6)) {
/* Target Interrupt */
outb_p(target_int | BIT(6), ASFSTA);
schedule_delayed_work(&dev->work_buf, HZ);
} else {
/* Controller Interrupt */
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true);
}
return IRQ_HANDLED;
}
static int amd_asf_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct amd_asf_dev *asf_dev;
struct resource *eoi_addr;
int ret, irq;
asf_dev = devm_kzalloc(dev, sizeof(*asf_dev), GFP_KERNEL);
if (!asf_dev)
return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n");
asf_dev->mmio_cfg.use_mmio = true;
asf_dev->port_addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!asf_dev->port_addr)
return dev_err_probe(dev, -EINVAL, "missing IO resources\n");
/*
* The resource obtained via ACPI might not belong to the ASF device address space. Instead,
* it could be within other IP blocks of the ASIC, which are crucial for generating
* subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and
* use platform_get_resource() and devm_ioremap() separately to prevent any address space
* conflicts.
*/
eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!eoi_addr)
return dev_err_probe(dev, -EINVAL, "missing MEM resources\n");
asf_dev->eoi_base = devm_ioremap(dev, eoi_addr->start, resource_size(eoi_addr));
if (!asf_dev->eoi_base)
return dev_err_probe(dev, -EBUSY, "failed mapping IO region\n");
ret = devm_delayed_work_autocancel(dev, &asf_dev->work_buf, amd_asf_process_target);
if (ret)
return dev_err_probe(dev, ret, "failed to create work queue\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return dev_err_probe(dev, irq, "missing IRQ resources\n");
ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev);
if (ret)
return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq);
asf_dev->adap.owner = THIS_MODULE;
asf_dev->adap.algo = &amd_asf_smbus_algorithm;
asf_dev->adap.dev.parent = dev;
i2c_set_adapdata(&asf_dev->adap, asf_dev);
snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name), "AMD ASF adapter");
return devm_i2c_add_adapter(dev, &asf_dev->adap);
}
static const struct acpi_device_id amd_asf_acpi_ids[] = {
{ "AMDI001A" },
{ }
};
MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids);
static struct platform_driver amd_asf_driver = {
.driver = {
.name = "i2c-amd-asf",
.acpi_match_table = amd_asf_acpi_ids,
},
.probe = amd_asf_probe,
};
module_platform_driver(amd_asf_driver);
MODULE_IMPORT_NS(PIIX4_SMBUS);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AMD Alert Standard Format Driver");

View File

@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
static struct platform_driver i2c_amd_plat_driver = {
.probe = i2c_amd_probe,
.remove_new = i2c_amd_remove,
.remove = i2c_amd_remove,
.driver = {
.name = "i2c_amd_mp2",
.acpi_match_table = ACPI_PTR(i2c_amd_acpi_match),

View File

@ -1,245 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
*
* Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de>
*/
/*
* We select the channels by sending commands to the Philips
* PCA9556 chip at I2C address 0x18. The main adapter is used for
* the non-multiplexed part of the bus, and 4 virtual adapters
* are defined for the multiplexed addresses: 0x50-0x53 (memory
* module EEPROM) located on channels 1-4, and 0x4c (LM63)
* located on multiplexed channels 0 and 5-7. We define one
* virtual adapter per CPU, which corresponds to two multiplexed
* channels:
* CPU0: virtual adapter 1, channels 1 and 0
* CPU1: virtual adapter 2, channels 2 and 5
* CPU2: virtual adapter 3, channels 3 and 6
* CPU3: virtual adapter 4, channels 4 and 7
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
extern struct i2c_adapter amd756_smbus;
static struct i2c_adapter *s4882_adapter;
static struct i2c_algorithm *s4882_algo;
/* Wrapper access functions for multiplexed SMBus */
static DEFINE_MUTEX(amd756_lock);
static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data)
{
int error;
/* We exclude the multiplexed addresses */
if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
|| addr == 0x18)
return -ENXIO;
mutex_lock(&amd756_lock);
error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
command, size, data);
mutex_unlock(&amd756_lock);
return error;
}
/* We remember the last used channels combination so as to only switch
channels when it is really needed. This greatly reduces the SMBus
overhead, but also assumes that nobody will be writing to the PCA9556
in our back. */
static u8 last_channels;
static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data,
u8 channels)
{
int error;
/* We exclude the non-multiplexed addresses */
if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
return -ENXIO;
mutex_lock(&amd756_lock);
if (last_channels != channels) {
union i2c_smbus_data mplxdata;
mplxdata.byte = channels;
error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
I2C_SMBUS_WRITE, 0x01,
I2C_SMBUS_BYTE_DATA,
&mplxdata);
if (error)
goto UNLOCK;
last_channels = channels;
}
error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
command, size, data);
UNLOCK:
mutex_unlock(&amd756_lock);
return error;
}
static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data)
{
/* CPU0: channels 1 and 0 enabled */
return amd756_access_channel(adap, addr, flags, read_write, command,
size, data, 0x03);
}
static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data)
{
/* CPU1: channels 2 and 5 enabled */
return amd756_access_channel(adap, addr, flags, read_write, command,
size, data, 0x24);
}
static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data)
{
/* CPU2: channels 3 and 6 enabled */
return amd756_access_channel(adap, addr, flags, read_write, command,
size, data, 0x48);
}
static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data * data)
{
/* CPU3: channels 4 and 7 enabled */
return amd756_access_channel(adap, addr, flags, read_write, command,
size, data, 0x90);
}
static int __init amd756_s4882_init(void)
{
int i, error;
union i2c_smbus_data ioconfig;
if (!amd756_smbus.dev.parent)
return -ENODEV;
/* Configure the PCA9556 multiplexer */
ioconfig.byte = 0x00; /* All I/O to output mode */
error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
I2C_SMBUS_BYTE_DATA, &ioconfig);
if (error) {
dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
error = -EIO;
goto ERROR0;
}
/* Unregister physical bus */
i2c_del_adapter(&amd756_smbus);
printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
/* Define the 5 virtual adapters and algorithms structures */
if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter),
GFP_KERNEL))) {
error = -ENOMEM;
goto ERROR1;
}
if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm),
GFP_KERNEL))) {
error = -ENOMEM;
goto ERROR2;
}
/* Fill in the new structures */
s4882_algo[0] = *(amd756_smbus.algo);
s4882_algo[0].smbus_xfer = amd756_access_virt0;
s4882_adapter[0] = amd756_smbus;
s4882_adapter[0].algo = s4882_algo;
s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
for (i = 1; i < 5; i++) {
s4882_algo[i] = *(amd756_smbus.algo);
s4882_adapter[i] = amd756_smbus;
snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
"SMBus 8111 adapter (CPU%d)", i-1);
s4882_adapter[i].algo = s4882_algo+i;
s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
}
s4882_algo[1].smbus_xfer = amd756_access_virt1;
s4882_algo[2].smbus_xfer = amd756_access_virt2;
s4882_algo[3].smbus_xfer = amd756_access_virt3;
s4882_algo[4].smbus_xfer = amd756_access_virt4;
/* Register virtual adapters */
for (i = 0; i < 5; i++) {
error = i2c_add_adapter(s4882_adapter+i);
if (error) {
printk(KERN_ERR "i2c-amd756-s4882: "
"Virtual adapter %d registration "
"failed, module not inserted\n", i);
for (i--; i >= 0; i--)
i2c_del_adapter(s4882_adapter+i);
goto ERROR3;
}
}
return 0;
ERROR3:
kfree(s4882_algo);
s4882_algo = NULL;
ERROR2:
kfree(s4882_adapter);
s4882_adapter = NULL;
ERROR1:
/* Restore physical bus */
i2c_add_adapter(&amd756_smbus);
ERROR0:
return error;
}
static void __exit amd756_s4882_exit(void)
{
if (s4882_adapter) {
int i;
for (i = 0; i < 5; i++)
i2c_del_adapter(s4882_adapter+i);
kfree(s4882_adapter);
s4882_adapter = NULL;
}
kfree(s4882_algo);
s4882_algo = NULL;
/* Restore physical bus */
if (i2c_add_adapter(&amd756_smbus))
printk(KERN_ERR "i2c-amd756-s4882: "
"Physical bus restoration failed\n");
}
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
MODULE_DESCRIPTION("S4882 SMBus multiplexing");
MODULE_LICENSE("GPL");
module_init(amd756_s4882_init);
module_exit(amd756_s4882_exit);

View File

@ -283,7 +283,7 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = amd756_func,
};
struct i2c_adapter amd756_smbus = {
static struct i2c_adapter amd756_smbus = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
@ -398,5 +398,3 @@ module_pci_driver(amd756_driver);
MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(amd756_smbus);

View File

@ -1102,7 +1102,7 @@ static void aspeed_i2c_remove_bus(struct platform_device *pdev)
static struct platform_driver aspeed_i2c_bus_driver = {
.probe = aspeed_i2c_probe_bus,
.remove_new = aspeed_i2c_remove_bus,
.remove = aspeed_i2c_remove_bus,
.driver = {
.name = "aspeed-i2c-bus",
.of_match_table = aspeed_i2c_bus_of_table,

View File

@ -330,7 +330,7 @@ static const struct dev_pm_ops __maybe_unused at91_twi_pm = {
static struct platform_driver at91_twi_driver = {
.probe = at91_twi_probe,
.remove_new = at91_twi_remove,
.remove = at91_twi_remove,
.id_table = at91_twi_devtypes,
.driver = {
.name = "at91_i2c",

View File

@ -368,7 +368,7 @@ static struct platform_driver au1xpsc_smbus_driver = {
.pm = pm_sleep_ptr(&i2c_au1550_pmops),
},
.probe = i2c_au1550_probe,
.remove_new = i2c_au1550_remove,
.remove = i2c_au1550_remove,
};
module_platform_driver(au1xpsc_smbus_driver);

View File

@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, axxia_i2c_of_match);
static struct platform_driver axxia_i2c_driver = {
.probe = axxia_i2c_probe,
.remove_new = axxia_i2c_remove,
.remove = axxia_i2c_remove,
.driver = {
.name = "axxia-i2c",
.of_match_table = axxia_i2c_of_match,

View File

@ -1264,7 +1264,7 @@ static struct platform_driver bcm_iproc_i2c_driver = {
.pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops),
},
.probe = bcm_iproc_i2c_probe,
.remove_new = bcm_iproc_i2c_remove,
.remove = bcm_iproc_i2c_remove,
};
module_platform_driver(bcm_iproc_i2c_driver);

View File

@ -877,7 +877,7 @@ static struct platform_driver bcm_kona_i2c_driver = {
.of_match_table = bcm_kona_i2c_of_match,
},
.probe = bcm_kona_i2c_probe,
.remove_new = bcm_kona_i2c_remove,
.remove = bcm_kona_i2c_remove,
};
module_platform_driver(bcm_kona_i2c_driver);

View File

@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match);
static struct platform_driver bcm2835_i2c_driver = {
.probe = bcm2835_i2c_probe,
.remove_new = bcm2835_i2c_remove,
.remove = bcm2835_i2c_remove,
.driver = {
.name = "i2c-bcm2835",
.of_match_table = bcm2835_i2c_of_match,

View File

@ -744,7 +744,7 @@ static struct platform_driver brcmstb_i2c_driver = {
.pm = pm_sleep_ptr(&brcmstb_i2c_pm),
},
.probe = brcmstb_i2c_probe,
.remove_new = brcmstb_i2c_remove,
.remove = brcmstb_i2c_remove,
};
module_platform_driver(brcmstb_i2c_driver);

View File

@ -129,6 +129,7 @@
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
#define CDNS_I2C_POLL_US 100000
#define CDNS_I2C_POLL_US_ATOMIC 10
#define CDNS_I2C_TIMEOUT_US 500000
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
@ -189,6 +190,8 @@ enum cdns_i2c_slave_state {
* @slave_state: I2C Slave state(idle/read/write).
* @fifo_depth: The depth of the transfer FIFO
* @transfer_size: The maximum number of bytes in one transfer
* @atomic: Mode of transfer
* @err_status_atomic: Error status in atomic mode
*/
struct cdns_i2c {
struct device *dev;
@ -219,6 +222,8 @@ struct cdns_i2c {
#endif
u32 fifo_depth;
unsigned int transfer_size;
bool atomic;
int err_status_atomic;
};
struct cdns_platform_data {
@ -228,6 +233,66 @@ struct cdns_platform_data {
#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
clk_rate_change_nb)
/**
* cdns_i2c_init - Controller initialisation
* @id: Device private data structure
*
* Initialise the i2c controller.
*
*/
static void cdns_i2c_init(struct cdns_i2c *id)
{
cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
/*
* Cadence I2C controller has a bug wherein it generates
* invalid read transaction after HW timeout in master receiver mode.
* HW timeout is not used by this driver and the interrupt is disabled.
* But the feature itself cannot be disabled. Hence maximum value
* is written to this register to reduce the chances of error.
*/
cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
}
/**
* cdns_i2c_runtime_suspend - Runtime suspend method for the driver
* @dev: Address of the platform_device structure
*
* Put the driver into low power mode.
*
* Return: 0 always
*/
static int cdns_i2c_runtime_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
clk_disable(xi2c->clk);
return 0;
}
/**
* cdns_i2c_runtime_resume - Runtime resume
* @dev: Address of the platform_device structure
*
* Runtime resume callback.
*
* Return: 0 on success and error value on error
*/
static int cdns_i2c_runtime_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
int ret;
ret = clk_enable(xi2c->clk);
if (ret) {
dev_err(dev, "Cannot enable clock.\n");
return ret;
}
cdns_i2c_init(xi2c);
return 0;
}
/**
* cdns_i2c_clear_bus_hold - Clear bus hold bit
* @id: Pointer to driver data struct
@ -561,6 +626,89 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
return cdns_i2c_master_isr(ptr);
}
static bool cdns_i2c_error_check(struct cdns_i2c *id)
{
unsigned int isr_status;
id->err_status = 0;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET);
id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
return !!id->err_status;
}
static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id)
{
while (id->recv_count > 0) {
bool updatetx;
/*
* Check if transfer size register needs to be updated again for a
* large data receive operation.
*/
updatetx = id->recv_count > id->curr_recv_count;
while (id->curr_recv_count > 0) {
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) {
*id->p_recv_buf = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
id->p_recv_buf++;
id->recv_count--;
id->curr_recv_count--;
/*
* Clear the hold bit that was set for FIFO control,
* if the remaining RX data is less than or equal to
* the FIFO depth, unless a repeated start is selected.
*/
if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
}
if (cdns_i2c_error_check(id))
return;
if (cdns_is_holdquirk(id, updatetx))
break;
}
/*
* The controller sends NACK to the slave/target when transfer size
* register reaches zero without considering the HOLD bit.
* This workaround is implemented for large data transfers to
* maintain transfer size non-zero while performing a large
* receive operation.
*/
if (cdns_is_holdquirk(id, updatetx)) {
/* wait while fifo is full */
while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
(id->curr_recv_count - id->fifo_depth))
;
/*
* Check number of bytes to be received against maximum
* transfer size and update register accordingly.
*/
if ((id->recv_count - id->fifo_depth) >
id->transfer_size) {
cdns_i2c_writereg(id->transfer_size,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = id->transfer_size +
id->fifo_depth;
} else {
cdns_i2c_writereg(id->recv_count -
id->fifo_depth,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = id->recv_count;
}
}
}
/* Clear hold (if not repeated start) */
if (!id->recv_count && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
}
/**
* cdns_i2c_mrecv - Prepare and start a master receive operation
* @id: pointer to the i2c device structure
@ -655,7 +803,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
}
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
if (!id->atomic)
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
else
cdns_i2c_mrecv_atomic(id);
}
static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id)
{
while (id->send_count) {
unsigned int avail_bytes;
unsigned int bytes_to_send;
avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
else
bytes_to_send = id->send_count;
while (bytes_to_send--) {
cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET);
id->send_count--;
}
if (cdns_i2c_error_check(id))
return;
}
if (!id->send_count && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
}
/**
@ -718,7 +893,10 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
if (!id->atomic)
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
else if (id->send_count > 0)
cdns_i2c_msend_rem_atomic(id);
}
/**
@ -758,7 +936,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
id->p_msg = msg;
id->err_status = 0;
reinit_completion(&id->xfer_done);
if (!id->atomic)
reinit_completion(&id->xfer_done);
/* Check for the TEN Bit mode on each msg */
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
@ -780,14 +959,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
/* Minimal time to execute this message */
msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
/* Plus some wiggle room */
msg_timeout += msecs_to_jiffies(500);
/*
* Plus some wiggle room.
* For non-atomic contexts, 500 ms is added to the timeout.
* For atomic contexts, 2000 ms is added because transfers happen in polled
* mode, requiring more time to account for the polling overhead.
*/
if (!id->atomic)
msg_timeout += msecs_to_jiffies(500);
else
msg_timeout += msecs_to_jiffies(2000);
if (msg_timeout < adap->timeout)
msg_timeout = adap->timeout;
/* Wait for the signal of completion */
time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
if (!id->atomic) {
/* Wait for the signal of completion */
time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
} else {
/* 0 is success, -ETIMEDOUT is error */
time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET,
reg, (reg & CDNS_I2C_IXR_COMP),
CDNS_I2C_POLL_US_ATOMIC, msg_timeout);
}
if (time_left == 0) {
cdns_i2c_master_reset(adap);
return -ETIMEDOUT;
@ -806,6 +1002,83 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
return 0;
}
static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
{
int ret, count;
u32 reg;
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
/* Check if the bus is free */
if (!id->atomic)
ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
reg,
!(reg & CDNS_I2C_SR_BA),
CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
else
ret = readl_poll_timeout_atomic(id->membase + CDNS_I2C_SR_OFFSET,
reg,
!(reg & CDNS_I2C_SR_BA),
CDNS_I2C_POLL_US_ATOMIC, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
i2c_recover_bus(adap);
return ret;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/*
* Set the flag to one when multiple messages are to be
* processed with a repeated start.
*/
if (num > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; (count < num - 1 && hold_quirk); count++) {
if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n");
return -EOPNOTSUPP;
}
}
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
} else {
id->bus_hold_flag = 0;
}
/* Process the msg one by one */
for (count = 0; count < num; count++, msgs++) {
if (count == (num - 1))
id->bus_hold_flag = 0;
ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret)
return ret;
/* Report the other error interrupts to application */
if (id->err_status || id->err_status_atomic) {
cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK)
return -ENXIO;
return -EIO;
}
}
return 0;
}
/**
* cdns_i2c_master_xfer - The main i2c transfer function
* @adap: pointer to the i2c adapter driver instance
@ -819,10 +1092,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
int ret, count;
u32 reg;
int ret;
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
bool change_role = false;
#endif
@ -847,75 +1118,11 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
}
#endif
/* Check if the bus is free */
ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
reg,
!(reg & CDNS_I2C_SR_BA),
CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
i2c_recover_bus(adap);
goto out;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/*
* Set the flag to one when multiple messages are to be
* processed with a repeated start.
*/
if (num > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; (count < num - 1 && hold_quirk); count++) {
if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n");
ret = -EOPNOTSUPP;
goto out;
}
}
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
} else {
id->bus_hold_flag = 0;
}
/* Process the msg one by one */
for (count = 0; count < num; count++, msgs++) {
if (count == (num - 1))
id->bus_hold_flag = 0;
ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret)
goto out;
/* Report the other error interrupts to application */
if (id->err_status) {
cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK) {
ret = -ENXIO;
goto out;
}
ret = -EIO;
goto out;
}
}
ret = num;
out:
ret = cdns_i2c_master_common_xfer(adap, msgs, num);
if (!ret)
ret = num;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
out:
/* Switch i2c mode to slave */
if (change_role)
cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
@ -926,6 +1133,41 @@ out:
return ret;
}
/**
* cdns_i2c_master_xfer_atomic - The i2c transfer function in atomic mode
* @adap: pointer to the i2c adapter driver instance
* @msgs: pointer to the i2c message structure
* @num: the number of messages to transfer
*
* Return: number of msgs processed on success, negative error otherwise
*/
static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
int ret;
struct cdns_i2c *id = adap->algo_data;
ret = cdns_i2c_runtime_resume(id->dev);
if (ret)
return ret;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) {
dev_warn(id->adap.dev.parent,
"Atomic xfer not supported for version 1.0\n");
return 0;
}
id->atomic = true;
ret = cdns_i2c_master_common_xfer(adap, msgs, num);
if (!ret)
ret = num;
id->atomic = false;
cdns_i2c_runtime_suspend(id->dev);
return ret;
}
/**
* cdns_i2c_func - Returns the supported features of the I2C driver
* @adap: pointer to the i2c adapter structure
@ -990,6 +1232,7 @@ static int cdns_unreg_slave(struct i2c_client *slave)
static const struct i2c_algorithm cdns_i2c_algo = {
.master_xfer = cdns_i2c_master_xfer,
.master_xfer_atomic = cdns_i2c_master_xfer_atomic,
.functionality = cdns_i2c_func,
#if IS_ENABLED(CONFIG_I2C_SLAVE)
.reg_slave = cdns_reg_slave,
@ -1158,23 +1401,6 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
}
}
/**
* cdns_i2c_runtime_suspend - Runtime suspend method for the driver
* @dev: Address of the platform_device structure
*
* Put the driver into low power mode.
*
* Return: 0 always
*/
static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
clk_disable(xi2c->clk);
return 0;
}
static int __maybe_unused cdns_i2c_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
@ -1187,49 +1413,6 @@ static int __maybe_unused cdns_i2c_suspend(struct device *dev)
return 0;
}
/**
* cdns_i2c_init - Controller initialisation
* @id: Device private data structure
*
* Initialise the i2c controller.
*
*/
static void cdns_i2c_init(struct cdns_i2c *id)
{
cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
/*
* Cadence I2C controller has a bug wherein it generates
* invalid read transaction after HW timeout in master receiver mode.
* HW timeout is not used by this driver and the interrupt is disabled.
* But the feature itself cannot be disabled. Hence maximum value
* is written to this register to reduce the chances of error.
*/
cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
}
/**
* cdns_i2c_runtime_resume - Runtime resume
* @dev: Address of the platform_device structure
*
* Runtime resume callback.
*
* Return: 0 on success and error value on error
*/
static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
int ret;
ret = clk_enable(xi2c->clk);
if (ret) {
dev_err(dev, "Cannot enable clock.\n");
return ret;
}
cdns_i2c_init(xi2c);
return 0;
}
static int __maybe_unused cdns_i2c_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
@ -1469,7 +1652,7 @@ static struct platform_driver cdns_i2c_drv = {
.pm = &cdns_i2c_dev_pm_ops,
},
.probe = cdns_i2c_probe,
.remove_new = cdns_i2c_remove,
.remove = cdns_i2c_remove,
};
module_platform_driver(cdns_i2c_drv);

View File

@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids);
static struct platform_driver cbus_i2c_driver = {
.probe = cbus_i2c_probe,
.remove_new = cbus_i2c_remove,
.remove = cbus_i2c_remove,
.driver = {
.name = "i2c-cbus-gpio",
.of_match_table = of_match_ptr(i2c_cbus_dt_ids),

View File

@ -546,7 +546,7 @@ MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table);
static struct platform_driver cht_wc_i2c_adap_driver = {
.probe = cht_wc_i2c_adap_i2c_probe,
.remove_new = cht_wc_i2c_adap_i2c_remove,
.remove = cht_wc_i2c_adap_i2c_remove,
.driver = {
.name = "cht_wcove_ext_chgr",
},

View File

@ -701,7 +701,7 @@ MODULE_DEVICE_TABLE(of, cpm_i2c_match);
static struct platform_driver cpm_i2c_driver = {
.probe = cpm_i2c_probe,
.remove_new = cpm_i2c_remove,
.remove = cpm_i2c_remove,
.driver = {
.name = "fsl-i2c-cpm",
.of_match_table = cpm_i2c_match,

View File

@ -304,7 +304,7 @@ MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id);
static struct platform_driver ec_i2c_tunnel_driver = {
.probe = ec_i2c_probe,
.remove_new = ec_i2c_remove,
.remove = ec_i2c_remove,
.driver = {
.name = "cros-ec-i2c-tunnel",
.acpi_match_table = ACPI_PTR(cros_ec_i2c_tunnel_acpi_id),

View File

@ -935,7 +935,7 @@ MODULE_DEVICE_TABLE(platform, davinci_i2c_driver_ids);
static struct platform_driver davinci_i2c_driver = {
.probe = davinci_i2c_probe,
.remove_new = davinci_i2c_remove,
.remove = davinci_i2c_remove,
.id_table = davinci_i2c_driver_ids,
.driver = {
.name = "i2c_davinci",

View File

@ -155,7 +155,7 @@ static void psp_release_i2c_bus_deferred(struct work_struct *work)
/*
* If there is any pending transaction, cannot release the bus here.
* psp_release_i2c_bus will take care of this later.
* psp_release_i2c_bus() will take care of this later.
*/
if (psp_i2c_access_count)
goto cleanup;
@ -210,12 +210,12 @@ static void psp_release_i2c_bus(void)
{
mutex_lock(&psp_i2c_access_mutex);
/* Return early if mailbox was malfunctional */
/* Return early if mailbox was malfunctioned */
if (psp_i2c_mbox_fail)
goto cleanup;
/*
* If we are last owner of PSP semaphore, need to release aribtration
* If we are last owner of PSP semaphore, need to release arbitration
* via mailbox.
*/
psp_i2c_access_count--;
@ -235,9 +235,9 @@ cleanup:
/*
* Locking methods are based on the default implementation from
* drivers/i2c/i2c-core-base.c, but with psp acquire and release operations
* drivers/i2c/i2c-core-base.c, but with PSP acquire and release operations
* added. With this in place we can ensure that i2c clients on the bus shared
* with psp are able to lock HW access to the bus for arbitrary number of
* with PSP are able to lock HW access to the bus for arbitrary number of
* operations - that is e.g. write-wait-read.
*/
static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter,

View File

@ -33,7 +33,7 @@
#include "i2c-designware-core.h"
static char *abort_sources[] = {
static const char *const abort_sources[] = {
[ABRT_7B_ADDR_NOACK] =
"slave address not acknowledged (7bit mode)",
[ABRT_10ADDR1_NOACK] =
@ -127,6 +127,8 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
* Autodetects needed register access mode and creates the regmap with
* corresponding read/write callbacks. This must be called before doing any
* other register access.
*
* Return: 0 on success, or negative errno otherwise.
*/
int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
{
@ -174,7 +176,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
/*
* Note we'll check the return value of the regmap IO accessors only
* at the probe stage. The rest of the code won't do this because
* basically we have MMIO-based regmap so non of the read/write methods
* basically we have MMIO-based regmap, so none of the read/write methods
* can fail.
*/
dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg);
@ -336,7 +338,7 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device)
acpi_speed = i2c_acpi_find_bus_speed(device);
/*
* Some DSTDs use a non standard speed, round down to the lowest
* Some DSDTs use a non standard speed, round down to the lowest
* standard speed.
*/
for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
@ -407,47 +409,26 @@ static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg)
}
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tSYMBOL, u32 tf, int cond, int offset)
u32 tSYMBOL, u32 tf, int offset)
{
if (!ic_clk)
return i2c_dw_read_scl_reg(dev, reg);
/*
* DesignWare I2C core doesn't seem to have solid strategy to meet
* the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
* will result in violation of the tHD;STA spec.
* Conditional expression:
*
* IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
*
* This is just experimental rule; the tHD;STA period turned
* out to be proportinal to (_HCNT + 3). With this setting,
* we could meet both tHIGH and tHD;STA timing specs.
*
* If unsure, you'd better to take this alternative.
*
* The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt().
*/
if (cond)
/*
* Conditional expression:
*
* IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
*
* This is based on the DW manuals, and represents an ideal
* configuration. The resulting I2C bus speed will be
* faster than any of the others.
*
* If your hardware is free from tHD;STA issue, try this one.
*/
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) -
8 + offset;
else
/*
* Conditional expression:
*
* IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
*
* This is just experimental rule; the tHD;STA period turned
* out to be proportinal to (_HCNT + 3). With this setting,
* we could meet both tHIGH and tHD;STA timing specs.
*
* If unsure, you'd better to take this alternative.
*
* The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt().
*/
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) -
3 + offset;
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset;
}
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
@ -467,8 +448,7 @@ u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
* account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety.
*/
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) -
1 + offset;
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset;
}
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
@ -571,7 +551,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
/*
* Wait 10 times the signaling period of the highest I2C
* transfer supported by the driver (for 400KHz this is
* transfer supported by the driver (for 400kHz this is
* 25us) as described in the DesignWare I2C databook.
*/
usleep_range(25, 250);
@ -678,10 +658,10 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
if (abort_source & DW_IC_TX_ARB_LOST)
return -EAGAIN;
else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
return -EINVAL; /* wrong msgs[] data */
else
return -EIO;
return -EIO;
}
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)

View File

@ -143,10 +143,10 @@
#define DW_IC_SLAVE 1
/*
* Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
* Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register.
*
* Only expected abort codes are listed here
* refer to the datasheet for the full list
* Only expected abort codes are listed here,
* refer to the datasheet for the full list.
*/
#define ABRT_7B_ADDR_NOACK 0
#define ABRT_10ADDR1_NOACK 1
@ -201,7 +201,7 @@ struct reset_control;
* @rst: optional reset for the controller
* @slave: represent an I2C slave device
* @get_clk_rate_khz: callback to retrieve IP specific bus speed
* @cmd_err: run time hadware error code
* @cmd_err: run time hardware error code
* @msgs: points to an array of messages currently being transferred
* @msgs_num: the number of elements in msgs
* @msg_write_idx: the element index of the current tx message in the msgs array
@ -237,7 +237,7 @@ struct reset_control;
* @release_lock: function to release a hardware lock on the bus
* @semaphore_idx: Index of table with semaphore type attached to the bus. It's
* -1 if there is no semaphore.
* @shared_with_punit: true if this bus is shared with the SoCs PUNIT
* @shared_with_punit: true if this bus is shared with the SoC's PUNIT
* @init: function to initialize the I2C hardware
* @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
@ -329,7 +329,7 @@ struct i2c_dw_semaphore_callbacks {
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tSYMBOL, u32 tf, int cond, int offset);
u32 tSYMBOL, u32 tf, int offset);
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tLOW, u32 tf, int offset);
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);

View File

@ -71,7 +71,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
ic_clk,
4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->ss_lcnt =
i2c_dw_scl_lcnt(dev,
@ -105,7 +104,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
ic_clk,
260, /* tHIGH = 260 ns */
sda_falling_time,
0, /* DW default */
0); /* No offset */
dev->fs_lcnt =
i2c_dw_scl_lcnt(dev,
@ -129,7 +127,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
ic_clk,
600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->fs_lcnt =
i2c_dw_scl_lcnt(dev,
@ -161,7 +158,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
ic_clk,
160, /* tHIGH = 160 ns */
sda_falling_time,
0, /* DW default */
0); /* No offset */
dev->hs_lcnt =
i2c_dw_scl_lcnt(dev,
@ -184,12 +180,14 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
}
/**
* i2c_dw_init_master() - Initialize the designware I2C master hardware
* i2c_dw_init_master() - Initialize the DesignWare I2C master hardware
* @dev: device private data
*
* This functions configures and enables the I2C master.
* This function is called during I2C init function, and in case of timeout at
* run time.
*
* Return: 0 on success, or negative errno otherwise.
*/
static int i2c_dw_init_master(struct dw_i2c_dev *dev)
{
@ -357,7 +355,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
/*
* Initiate the i2c read/write transaction of buffer length,
* and poll for bus busy status. For the last message transfer,
* update the command with stopbit enable.
* update the command with stop bit enable.
*/
for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) {
if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1)
@ -402,7 +400,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
/*
* Initiate (and continue) low level master read/write transaction.
* This function is only called from i2c_dw_isr, and pumping i2c_msg
* This function is only called from i2c_dw_isr(), and pumping i2c_msg
* messages into the tx buffer. Even if the size of i2c_msg data is
* longer than the size of the tx buffer, it handles everything.
*/
@ -440,7 +438,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
buf = msgs[dev->msg_write_idx].buf;
buf_len = msgs[dev->msg_write_idx].len;
/* If both IC_EMPTYFIFO_HOLD_MASTER_EN and
/*
* If both IC_EMPTYFIFO_HOLD_MASTER_EN and
* IC_RESTART_EN are set, we must manually
* set restart bit between messages.
*/
@ -971,7 +970,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
rinfo->unprepare_recovery = i2c_dw_unprepare_recovery;
adap->bus_recovery_info = rinfo;
dev_info(dev->dev, "running with gpio recovery mode! scl%s",
dev_info(dev->dev, "running with GPIO recovery mode! scl%s",
rinfo->sda_gpiod ? ",sda" : "");
return 0;

View File

@ -51,7 +51,7 @@ struct dw_scl_sda_cfg {
u16 fs_hcnt;
u16 ss_lcnt;
u16 fs_lcnt;
u32 sda_hold;
u32 sda_hold_time;
};
struct dw_pci_controller {
@ -76,7 +76,7 @@ static struct dw_scl_sda_cfg byt_config = {
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
.sda_hold_time = 0x6,
};
/* Haswell HCNT/LCNT/SDA hold time */
@ -85,14 +85,14 @@ static struct dw_scl_sda_cfg hsw_config = {
.fs_hcnt = 0x48,
.ss_lcnt = 0x01fb,
.fs_lcnt = 0xa0,
.sda_hold = 0x9,
.sda_hold_time = 0x9,
};
/* NAVI-AMD HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg navi_amd_config = {
.ss_hcnt = 0x1ae,
.ss_lcnt = 0x23a,
.sda_hold = 0x9,
.sda_hold_time = 0x9,
};
static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
@ -207,6 +207,7 @@ static const struct software_node dgpu_node = {
static int i2c_dw_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct device *device = &pdev->dev;
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
int r;
@ -214,25 +215,22 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
struct dw_scl_sda_cfg *cfg;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers))
return dev_err_probe(&pdev->dev, -EINVAL,
"Invalid driver data %ld\n",
return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n",
id->driver_data);
controller = &dw_pci_controllers[id->driver_data];
r = pcim_enable_device(pdev);
if (r)
return dev_err_probe(&pdev->dev, r,
"Failed to enable I2C PCI device\n");
return dev_err_probe(device, r, "Failed to enable I2C PCI device\n");
pci_set_master(pdev);
r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
if (r)
return dev_err_probe(&pdev->dev, r,
"I/O memory remapping failed\n");
return dev_err_probe(device, r, "I/O memory remapping failed\n");
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
@ -242,7 +240,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->get_clk_rate_khz = controller->get_clk_rate_khz;
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
dev->dev = device;
dev->irq = pci_irq_vector(pdev, 0);
dev->flags |= controller->flags;
@ -266,7 +264,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->fs_hcnt = cfg->fs_hcnt;
dev->ss_lcnt = cfg->ss_lcnt;
dev->fs_lcnt = cfg->fs_lcnt;
dev->sda_hold_time = cfg->sda_hold;
dev->sda_hold_time = cfg->sda_hold_time;
}
adap = &dev->adapter;
@ -281,14 +279,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node);
if (IS_ERR(dev->slave))
return dev_err_probe(dev->dev, PTR_ERR(dev->slave),
return dev_err_probe(device, PTR_ERR(dev->slave),
"register UCSI failed\n");
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
pm_runtime_allow(&pdev->dev);
pm_runtime_set_autosuspend_delay(device, 1000);
pm_runtime_use_autosuspend(device);
pm_runtime_put_autosuspend(device);
pm_runtime_allow(device);
return 0;
}
@ -296,11 +294,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
static void i2c_dw_pci_remove(struct pci_dev *pdev)
{
struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
struct device *device = &pdev->dev;
i2c_dw_disable(dev);
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_forbid(device);
pm_runtime_get_noresume(device);
i2c_del_adapter(&dev->adapter);
}

View File

@ -72,7 +72,7 @@ static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
return ret;
return regmap_write(dev->sysmap, BT1_I2C_CTL,
BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
}
static const struct regmap_config bt1_i2c_cfg = {
@ -205,6 +205,7 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct device *device = &pdev->dev;
struct i2c_adapter *adap;
struct dw_i2c_dev *dev;
int irq, ret;
@ -213,15 +214,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
dev->flags = (uintptr_t)device_get_match_data(device);
if (device_property_present(device, "wx,i2c-snps-model"))
dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING;
dev->dev = &pdev->dev;
dev->dev = device;
dev->irq = irq;
platform_set_drvdata(pdev, dev);
@ -229,7 +230,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
if (ret)
return ret;
dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
dev->rst = devm_reset_control_get_optional_exclusive(device, NULL);
if (IS_ERR(dev->rst))
return PTR_ERR(dev->rst);
@ -246,13 +247,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
i2c_dw_configure(dev);
/* Optional interface clock */
dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
dev->pclk = devm_clk_get_optional(device, "pclk");
if (IS_ERR(dev->pclk)) {
ret = PTR_ERR(dev->pclk);
goto exit_reset;
}
dev->clk = devm_clk_get_optional(&pdev->dev, NULL);
dev->clk = devm_clk_get_optional(device, NULL);
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
goto exit_reset;
@ -277,31 +278,27 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
adap = &dev->adapter;
adap->owner = THIS_MODULE;
adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?
I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
adap->nr = -1;
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
dev_pm_set_driver_flags(&pdev->dev,
DPM_FLAG_SMART_PREPARE);
} else {
dev_pm_set_driver_flags(&pdev->dev,
DPM_FLAG_SMART_PREPARE |
DPM_FLAG_SMART_SUSPEND);
}
if (dev->flags & ACCESS_NO_IRQ_SUSPEND)
dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE);
else
dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND);
device_enable_async_suspend(&pdev->dev);
device_enable_async_suspend(device);
/* The code below assumes runtime PM to be disabled. */
WARN_ON(pm_runtime_enabled(&pdev->dev));
WARN_ON(pm_runtime_enabled(device));
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(device, 1000);
pm_runtime_use_autosuspend(device);
pm_runtime_set_active(device);
if (dev->shared_with_punit)
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_get_noresume(device);
pm_runtime_enable(&pdev->dev);
pm_runtime_enable(device);
ret = i2c_dw_probe(dev);
if (ret)
@ -319,15 +316,16 @@ exit_reset:
static void dw_i2c_plat_remove(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
struct device *device = &pdev->dev;
pm_runtime_get_sync(&pdev->dev);
pm_runtime_get_sync(device);
i2c_del_adapter(&dev->adapter);
i2c_dw_disable(dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_dont_use_autosuspend(device);
pm_runtime_put_sync(device);
dw_i2c_plat_pm_cleanup(dev);
i2c_dw_remove_lock_support(dev);
@ -354,6 +352,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "HISI02A1", 0 },
{ "HISI02A2", 0 },
{ "HISI02A3", 0 },
{ "HJMC3001", 0 },
{ "HYGO0010", ACCESS_INTR_MASK },
{ "INT33C2", 0 },
{ "INT33C3", 0 },
@ -372,7 +371,7 @@ MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids);
static struct platform_driver dw_i2c_driver = {
.probe = dw_i2c_plat_probe,
.remove_new = dw_i2c_plat_remove,
.remove = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = dw_i2c_of_match,

View File

@ -32,12 +32,14 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
}
/**
* i2c_dw_init_slave() - Initialize the designware i2c slave hardware
* i2c_dw_init_slave() - Initialize the DesignWare i2c slave hardware
* @dev: device private data
*
* This function configures and enables the I2C in slave mode.
* This function is called during I2C init function, and in case of timeout at
* run time.
*
* Return: 0 on success, or negative errno otherwise.
*/
static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
{
@ -264,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
IRQF_SHARED, dev_name(dev->dev), dev);
if (ret) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",
dev_err(dev->dev, "failure requesting IRQ %i: %d\n",
dev->irq, ret);
return ret;
}

View File

@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, dc_i2c_match);
static struct platform_driver dc_i2c_driver = {
.probe = dc_i2c_probe,
.remove_new = dc_i2c_remove,
.remove = dc_i2c_remove,
.driver = {
.name = "digicolor-i2c",
.of_match_table = dc_i2c_match,

View File

@ -245,7 +245,7 @@ static void dln2_i2c_remove(struct platform_device *pdev)
static struct platform_driver dln2_i2c_driver = {
.driver.name = "dln2-i2c",
.probe = dln2_i2c_probe,
.remove_new = dln2_i2c_remove,
.remove = dln2_i2c_remove,
};
module_platform_driver(dln2_i2c_driver);

View File

@ -425,7 +425,7 @@ static const struct of_device_id em_i2c_ids[] = {
static struct platform_driver em_i2c_driver = {
.probe = em_i2c_probe,
.remove_new = em_i2c_remove,
.remove = em_i2c_remove,
.driver = {
.name = "em-i2c",
.of_match_table = em_i2c_ids,

View File

@ -1009,7 +1009,7 @@ static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
static struct platform_driver exynos5_i2c_driver = {
.probe = exynos5_i2c_probe,
.remove_new = exynos5_i2c_remove,
.remove = exynos5_i2c_remove,
.driver = {
.name = "exynos5-hsi2c",
.pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops),

View File

@ -481,7 +481,7 @@ static struct platform_driver i2c_gpio_driver = {
.acpi_match_table = i2c_gpio_acpi_match,
},
.probe = i2c_gpio_probe,
.remove_new = i2c_gpio_remove,
.remove = i2c_gpio_remove,
};
static int __init i2c_gpio_init(void)

View File

@ -595,7 +595,7 @@ MODULE_DEVICE_TABLE(of, gxp_i2c_of_match);
static struct platform_driver gxp_i2c_driver = {
.probe = gxp_i2c_probe,
.remove_new = gxp_i2c_remove,
.remove = gxp_i2c_remove,
.driver = {
.name = "gxp-i2c",
.of_match_table = gxp_i2c_of_match,

View File

@ -454,7 +454,7 @@ static struct platform_driver highlander_i2c_driver = {
},
.probe = highlander_i2c_probe,
.remove_new = highlander_i2c_remove,
.remove = highlander_i2c_remove,
};
module_platform_driver(highlander_i2c_driver);

View File

@ -508,7 +508,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match);
static struct platform_driver hix5hd2_i2c_driver = {
.probe = hix5hd2_i2c_probe,
.remove_new = hix5hd2_i2c_remove,
.remove = hix5hd2_i2c_remove,
.driver = {
.name = "hix5hd2-i2c",
.pm = pm_ptr(&hix5hd2_i2c_pm_ops),

View File

@ -81,6 +81,8 @@
* Meteor Lake PCH-S (PCH) 0x7f23 32 hard yes yes yes
* Birch Stream (SOC) 0x5796 32 hard yes yes yes
* Arrow Lake-H (SOC) 0x7722 32 hard yes yes yes
* Panther Lake-H (SOC) 0xe322 32 hard yes yes yes
* Panther Lake-P (SOC) 0xe422 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@ -261,6 +263,8 @@
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3
#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS 0xae22
#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_H_SMBUS 0xe322
#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_P_SMBUS 0xe422
struct i801_mux_config {
char *gpio_chip;
@ -1055,6 +1059,8 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ 0, }
};

View File

@ -790,7 +790,7 @@ static struct platform_driver ibm_iic_driver = {
.of_match_table = ibm_iic_match,
},
.probe = iic_probe,
.remove_new = iic_remove,
.remove = iic_remove,
};
module_platform_driver(ibm_iic_driver);

View File

@ -1497,7 +1497,7 @@ static struct platform_driver img_scb_i2c_driver = {
.pm = pm_ptr(&img_i2c_pm),
},
.probe = img_i2c_probe,
.remove_new = img_i2c_remove,
.remove = img_i2c_remove,
};
module_platform_driver(img_scb_i2c_driver);

View File

@ -703,7 +703,7 @@ static const struct dev_pm_ops lpi2c_pm_ops = {
static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe,
.remove_new = lpi2c_imx_remove,
.remove = lpi2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match,

View File

@ -17,7 +17,7 @@
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
*
* Copyright 2013 Freescale Semiconductor, Inc.
* Copyright 2020 NXP
* Copyright 2020, 2024 NXP
*
*/
@ -84,6 +84,7 @@
#define IMX_I2C_REGSHIFT 2
#define VF610_I2C_REGSHIFT 0
#define S32G_I2C_REGSHIFT 0
/* Bits of IMX I2C registers */
#define I2SR_RXAK 0x01
@ -165,9 +166,34 @@ static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = {
{ 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
};
/* S32G2/S32G3 clock divider, register value pairs */
static struct imx_i2c_clk_pair s32g2_i2c_clk_div[] = {
{ 34, 0x00 }, { 36, 0x01 }, { 38, 0x02 }, { 40, 0x03 },
{ 42, 0x04 }, { 44, 0x05 }, { 46, 0x06 }, { 48, 0x09 },
{ 52, 0x0A }, { 54, 0x07 }, { 56, 0x0B }, { 60, 0x0C },
{ 64, 0x0D }, { 68, 0x40 }, { 72, 0x0E }, { 76, 0x42 },
{ 80, 0x12 }, { 84, 0x0F }, { 88, 0x13 }, { 96, 0x14 },
{ 104, 0x15 }, { 108, 0x47 }, { 112, 0x19 }, { 120, 0x16 },
{ 128, 0x1A }, { 136, 0x80 }, { 144, 0x17 }, { 152, 0x82 },
{ 160, 0x1C }, { 168, 0x84 }, { 176, 0x1D }, { 192, 0x21 },
{ 208, 0x1E }, { 216, 0x87 }, { 224, 0x22 }, { 240, 0x56 },
{ 256, 0x1F }, { 288, 0x24 }, { 320, 0x25 }, { 336, 0x8F },
{ 352, 0x93 }, { 356, 0x5D }, { 358, 0x98 }, { 384, 0x26 },
{ 416, 0x56 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
{ 576, 0x2C }, { 640, 0x2D }, { 704, 0x9D }, { 768, 0x2E },
{ 832, 0x9D }, { 896, 0x32 }, { 960, 0x2F }, { 1024, 0x33 },
{ 1152, 0x34 }, { 1280, 0x35 }, { 1536, 0x36 }, { 1792, 0x3A },
{ 1920, 0x37 }, { 2048, 0x3B }, { 2304, 0x74 }, { 2560, 0x3D },
{ 3072, 0x3E }, { 3584, 0x7A }, { 3840, 0x3F }, { 4096, 0x7B },
{ 4608, 0x7C }, { 5120, 0x7D }, { 6144, 0x7E }, { 7168, 0xBA },
{ 7680, 0x7F }, { 8192, 0xBB }, { 9216, 0xBC }, { 10240, 0xBD },
{ 12288, 0xBE }, { 15360, 0xBF },
};
enum imx_i2c_type {
IMX1_I2C,
IMX21_I2C,
S32G_I2C,
VF610_I2C,
};
@ -197,6 +223,17 @@ struct imx_i2c_dma {
enum dma_data_direction dma_data_dir;
};
enum imx_i2c_state {
IMX_I2C_STATE_DONE,
IMX_I2C_STATE_FAILED,
IMX_I2C_STATE_WRITE,
IMX_I2C_STATE_DMA,
IMX_I2C_STATE_READ,
IMX_I2C_STATE_READ_CONTINUE,
IMX_I2C_STATE_READ_BLOCK_DATA,
IMX_I2C_STATE_READ_BLOCK_DATA_LEN,
};
struct imx_i2c_struct {
struct i2c_adapter adapter;
struct clk *clk;
@ -216,6 +253,14 @@ struct imx_i2c_struct {
struct i2c_client *slave;
enum i2c_slave_event last_slave_event;
struct i2c_msg *msg;
unsigned int msg_buf_idx;
int isr_result;
bool is_lastmsg;
enum imx_i2c_state state;
bool multi_master;
/* For checking slave events. */
spinlock_t slave_lock;
struct hrtimer slave_timer;
@ -258,7 +303,15 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
.ndivs = ARRAY_SIZE(vf610_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
};
static const struct imx_i2c_hwdata s32g2_i2c_hwdata = {
.devtype = S32G_I2C,
.regshift = S32G_I2C_REGSHIFT,
.clk_div = s32g2_i2c_clk_div,
.ndivs = ARRAY_SIZE(s32g2_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
};
static const struct platform_device_id imx_i2c_devtype[] = {
@ -288,6 +341,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ .compatible = "nxp,s32g2-i2c", .data = &s32g2_i2c_hwdata, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
@ -481,6 +535,9 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
unsigned long orig_jiffies = jiffies;
unsigned int temp;
if (!i2c_imx->multi_master)
return 0;
while (1) {
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
@ -540,8 +597,8 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
return -ETIMEDOUT;
}
/* check for arbitration lost */
if (i2c_imx->i2csr & I2SR_IAL) {
/* In multi-master mode check for arbitration lost */
if (i2c_imx->multi_master && (i2c_imx->i2csr & I2SR_IAL)) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__);
i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
@ -903,11 +960,156 @@ static int i2c_imx_unreg_slave(struct i2c_client *client)
return ret;
}
static inline int i2c_imx_isr_acked(struct imx_i2c_struct *i2c_imx)
{
i2c_imx->isr_result = 0;
if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
i2c_imx->state = IMX_I2C_STATE_FAILED;
i2c_imx->isr_result = -ENXIO;
wake_up(&i2c_imx->queue);
}
return i2c_imx->isr_result;
}
static inline int i2c_imx_isr_write(struct imx_i2c_struct *i2c_imx)
{
int result;
result = i2c_imx_isr_acked(i2c_imx);
if (result)
return result;
if (i2c_imx->msg->len == i2c_imx->msg_buf_idx)
return 0;
imx_i2c_write_reg(i2c_imx->msg->buf[i2c_imx->msg_buf_idx++], i2c_imx, IMX_I2C_I2DR);
return 1;
}
static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx)
{
int result;
unsigned int temp;
result = i2c_imx_isr_acked(i2c_imx);
if (result)
return result;
/* setup bus to read data */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
if (i2c_imx->msg->len - 1)
temp &= ~I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
return 0;
}
static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
{
unsigned int temp;
if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) {
if (i2c_imx->is_lastmsg) {
/*
* It must generate STOP before read I2DR to prevent
* controller from generating another clock cycle
*/
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(temp & I2CR_MSTA))
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
} else {
/*
* For i2c master receiver repeat restart operation like:
* read -> repeat MSTA -> read/write
* The controller must set MTX before read the last byte in
* the first read operation, otherwise the first read cost
* one extra clock cycle.
*/
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MTX;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
} else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) {
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
}
static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
{
u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
i2c_imx->isr_result = -EPROTO;
i2c_imx->state = IMX_I2C_STATE_FAILED;
wake_up(&i2c_imx->queue);
}
i2c_imx->msg->len += len;
}
static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status)
{
/* save status register */
i2c_imx->i2csr = status;
wake_up(&i2c_imx->queue);
/*
* This state machine handles I2C reception and transmission in non-DMA
* mode. We must process all the data in the ISR to reduce the delay
* between two consecutive messages. If the data is not processed in
* the ISR, SMBus devices may timeout, leading to a bus error.
*/
switch (i2c_imx->state) {
case IMX_I2C_STATE_DMA:
i2c_imx->i2csr = status;
wake_up(&i2c_imx->queue);
break;
case IMX_I2C_STATE_READ:
if (i2c_imx_isr_read(i2c_imx))
break;
i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
break;
case IMX_I2C_STATE_READ_CONTINUE:
i2c_imx_isr_read_continue(i2c_imx);
if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) {
i2c_imx->state = IMX_I2C_STATE_DONE;
wake_up(&i2c_imx->queue);
}
break;
case IMX_I2C_STATE_READ_BLOCK_DATA:
if (i2c_imx_isr_read(i2c_imx))
break;
i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA_LEN;
break;
case IMX_I2C_STATE_READ_BLOCK_DATA_LEN:
i2c_imx_isr_read_block_data_len(i2c_imx);
i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE;
break;
case IMX_I2C_STATE_WRITE:
if (i2c_imx_isr_write(i2c_imx))
break;
i2c_imx->state = IMX_I2C_STATE_DONE;
wake_up(&i2c_imx->queue);
break;
default:
i2c_imx->i2csr = status;
i2c_imx->state = IMX_I2C_STATE_FAILED;
i2c_imx->isr_result = -EINVAL;
wake_up(&i2c_imx->queue);
}
return IRQ_HANDLED;
}
@ -954,6 +1156,8 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
struct imx_i2c_dma *dma = i2c_imx->dma;
struct device *dev = &i2c_imx->adapter.dev;
i2c_imx->state = IMX_I2C_STATE_DMA;
dma->chan_using = dma->chan_tx;
dma->dma_transfer_dir = DMA_MEM_TO_DEV;
dma->dma_data_dir = DMA_TO_DEVICE;
@ -1006,6 +1210,42 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
return i2c_imx_acked(i2c_imx);
}
static int i2c_imx_prepare_read(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs, bool use_dma)
{
int result;
unsigned int temp = 0;
/* write slave address */
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx, !use_dma);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
if (result)
return result;
dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
/* setup bus to read data */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
/*
* Reset the I2CR_TXAK flag initially for SMBus block read since the
* length is unknown
*/
if (msgs->len - 1)
temp &= ~I2CR_TXAK;
if (use_dma)
temp |= I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
return 0;
}
static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs, bool is_lastmsg)
{
@ -1016,6 +1256,13 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
struct imx_i2c_dma *dma = i2c_imx->dma;
struct device *dev = &i2c_imx->adapter.dev;
i2c_imx->state = IMX_I2C_STATE_DMA;
result = i2c_imx_prepare_read(i2c_imx, msgs, true);
if (result)
return result;
dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
dma->chan_using = dma->chan_rx;
dma->dma_transfer_dir = DMA_DEV_TO_MEM;
@ -1092,8 +1339,8 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
return 0;
}
static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
bool atomic)
static int i2c_imx_atomic_write(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs)
{
int i, result;
@ -1102,7 +1349,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
/* write slave address */
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx, atomic);
result = i2c_imx_trx_complete(i2c_imx, true);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
@ -1116,7 +1363,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
"<%s> write byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx, atomic);
result = i2c_imx_trx_complete(i2c_imx, true);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
@ -1126,55 +1373,54 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
return 0;
}
static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
bool is_lastmsg, bool atomic)
static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
{
dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
__func__, i2c_8bit_addr_from_msg(msgs));
i2c_imx->state = IMX_I2C_STATE_WRITE;
i2c_imx->msg = msgs;
i2c_imx->msg_buf_idx = 0;
/*
* By writing the device address we start the state machine in the ISR.
* The ISR will report when it is done or when it fails.
*/
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
wait_event_timeout(i2c_imx->queue,
i2c_imx->state == IMX_I2C_STATE_DONE ||
i2c_imx->state == IMX_I2C_STATE_FAILED,
(msgs->len + 1) * HZ / 10);
if (i2c_imx->state == IMX_I2C_STATE_FAILED) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> write failed with %d\n",
__func__, i2c_imx->isr_result);
return i2c_imx->isr_result;
}
if (i2c_imx->state != IMX_I2C_STATE_DONE) {
dev_err(&i2c_imx->adapter.dev, "<%s> write timedout\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs, bool is_lastmsg)
{
int i, result;
unsigned int temp;
int block_data = msgs->flags & I2C_M_RECV_LEN;
int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE &&
msgs->len >= DMA_THRESHOLD && !block_data;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
__func__, i2c_8bit_addr_from_msg(msgs));
/* write slave address */
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx, atomic);
result = i2c_imx_prepare_read(i2c_imx, msgs, false);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
if (result)
return result;
dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
/* setup bus to read data */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
/*
* Reset the I2CR_TXAK flag initially for SMBus block read since the
* length is unknown
*/
if ((msgs->len - 1) || block_data)
temp &= ~I2CR_TXAK;
if (use_dma)
temp |= I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
if (use_dma)
return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);
/* read data */
for (i = 0; i < msgs->len; i++) {
u8 len = 0;
result = i2c_imx_trx_complete(i2c_imx, atomic);
result = i2c_imx_trx_complete(i2c_imx, true);
if (result)
return result;
/*
@ -1205,7 +1451,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
if (!i2c_imx->stopped)
i2c_imx_bus_busy(i2c_imx, 0, atomic);
i2c_imx_bus_busy(i2c_imx, 0, true);
} else {
/*
* For i2c master receiver repeat restart operation like:
@ -1236,6 +1482,48 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
return 0;
}
static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
bool is_lastmsg)
{
int block_data = msgs->flags & I2C_M_RECV_LEN;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
__func__, i2c_8bit_addr_from_msg(msgs));
i2c_imx->is_lastmsg = is_lastmsg;
if (block_data)
i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA;
else
i2c_imx->state = IMX_I2C_STATE_READ;
i2c_imx->msg = msgs;
i2c_imx->msg_buf_idx = 0;
/*
* By writing the device address we start the state machine in the ISR.
* The ISR will report when it is done or when it fails.
*/
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
wait_event_timeout(i2c_imx->queue,
i2c_imx->state == IMX_I2C_STATE_DONE ||
i2c_imx->state == IMX_I2C_STATE_FAILED,
(msgs->len + 1) * HZ / 10);
if (i2c_imx->state == IMX_I2C_STATE_FAILED) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> read failed with %d\n",
__func__, i2c_imx->isr_result);
return i2c_imx->isr_result;
}
if (i2c_imx->state != IMX_I2C_STATE_DONE) {
dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__);
return -ETIMEDOUT;
}
if (!i2c_imx->stopped)
return i2c_imx_bus_busy(i2c_imx, 0, false);
return 0;
}
static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num, bool atomic)
{
@ -1243,6 +1531,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
int result;
bool is_lastmsg = false;
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
int use_dma = 0;
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx, atomic);
@ -1295,15 +1584,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
(temp & I2SR_RXAK ? 1 : 0));
#endif
use_dma = i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD &&
msgs[i].flags & I2C_M_DMA_SAFE;
if (msgs[i].flags & I2C_M_RD) {
result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic);
int block_data = msgs->flags & I2C_M_RECV_LEN;
if (atomic)
result = i2c_imx_atomic_read(i2c_imx, &msgs[i], is_lastmsg);
else if (use_dma && !block_data)
result = i2c_imx_dma_read(i2c_imx, &msgs[i], is_lastmsg);
else
result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);
} else {
if (!atomic &&
i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD &&
msgs[i].flags & I2C_M_DMA_SAFE)
if (atomic)
result = i2c_imx_atomic_write(i2c_imx, &msgs[i]);
else if (use_dma)
result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
else
result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
result = i2c_imx_write(i2c_imx, &msgs[i]);
}
if (result)
goto fail0;
@ -1468,6 +1767,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
goto rpm_disable;
}
/*
* We use the single-master property for backward compatibility.
* By default multi master mode is enabled.
*/
i2c_imx->multi_master = !of_property_read_bool(pdev->dev.of_node, "single-master");
/* Set up clock divider */
i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
ret = of_property_read_u32(pdev->dev.of_node,
@ -1576,7 +1881,7 @@ static const struct dev_pm_ops i2c_imx_pm_ops = {
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove_new = i2c_imx_remove,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.pm = pm_ptr(&i2c_imx_pm_ops),

View File

@ -524,7 +524,7 @@ MODULE_DEVICE_TABLE(of, i2c_iop3xx_match);
static struct platform_driver iop3xx_i2c_driver = {
.probe = iop3xx_i2c_probe,
.remove_new = iop3xx_i2c_remove,
.remove = iop3xx_i2c_remove,
.driver = {
.name = "IOP3xx-I2C",
.of_match_table = i2c_iop3xx_match,

View File

@ -1,41 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
- Based on i2c-piix4.c
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
- Intel SCH support
Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com>
* Linux kernel driver for Intel SCH chipset SMBus
* - Based on i2c-piix4.c
* Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
* Philip Edelbrock <phil@netroedge.com>
* - Intel SCH support
* Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com>
*/
*/
/*
Supports:
Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
Note: we assume there can only be one device, with one SMBus interface.
*/
/* Supports: Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) */
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sprintf.h>
#include <linux/stddef.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/string_choices.h>
#include <linux/types.h>
/* SCH SMBus address offsets */
#define SMBHSTCNT (0 + sch_smba)
#define SMBHSTSTS (1 + sch_smba)
#define SMBHSTCLK (2 + sch_smba)
#define SMBHSTADD (4 + sch_smba) /* TSA */
#define SMBHSTCMD (5 + sch_smba)
#define SMBHSTDAT0 (6 + sch_smba)
#define SMBHSTDAT1 (7 + sch_smba)
#define SMBBLKDAT (0x20 + sch_smba)
/* Other settings */
#define MAX_RETRIES 5000
#define SMBHSTCNT 0x00
#define SMBHSTSTS 0x01
#define SMBHSTCLK 0x02
#define SMBHSTADD 0x04 /* TSA */
#define SMBHSTCMD 0x05
#define SMBHSTDAT0 0x06
#define SMBHSTDAT1 0x07
#define SMBBLKDAT 0x20
/* I2C constants */
#define SCH_QUICK 0x00
@ -44,109 +42,134 @@
#define SCH_WORD_DATA 0x03
#define SCH_BLOCK_DATA 0x05
static unsigned short sch_smba;
static struct i2c_adapter sch_adapter;
struct sch_i2c {
struct i2c_adapter adapter;
void __iomem *smba;
};
static int backbone_speed = 33000; /* backbone speed in kHz */
module_param(backbone_speed, int, S_IRUSR | S_IWUSR);
module_param(backbone_speed, int, 0600);
MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)");
/*
* Start the i2c transaction -- the i2c_access will prepare the transaction
* and this function will execute it.
* return 0 for success and others for failure.
*/
static int sch_transaction(void)
static inline u8 sch_io_rd8(struct sch_i2c *priv, unsigned int offset)
{
int temp;
int result = 0;
int retries = 0;
return ioread8(priv->smba + offset);
}
dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
inb(SMBHSTDAT1));
static inline void sch_io_wr8(struct sch_i2c *priv, unsigned int offset, u8 value)
{
iowrite8(value, priv->smba + offset);
}
static inline u16 sch_io_rd16(struct sch_i2c *priv, unsigned int offset)
{
return ioread16(priv->smba + offset);
}
static inline void sch_io_wr16(struct sch_i2c *priv, unsigned int offset, u16 value)
{
iowrite16(value, priv->smba + offset);
}
/**
* sch_transaction - Start the i2c transaction
* @adap: the i2c adapter pointer
*
* The sch_access() will prepare the transaction and
* this function will execute it.
*
* Return: 0 for success and others for failure.
*/
static int sch_transaction(struct i2c_adapter *adap)
{
struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter);
int temp;
int rc;
dev_dbg(&adap->dev,
"Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD),
sch_io_rd8(priv, SMBHSTADD),
sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1));
/* Make sure the SMBus host is ready to start transmitting */
temp = inb(SMBHSTSTS) & 0x0f;
temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
if (temp) {
/* Can not be busy since we checked it in sch_access */
if (temp & 0x01) {
dev_dbg(&sch_adapter.dev, "Completion (%02x). "
"Clear...\n", temp);
}
if (temp & 0x06) {
dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
"Resetting...\n", temp);
}
outb(temp, SMBHSTSTS);
temp = inb(SMBHSTSTS) & 0x0f;
if (temp & 0x01)
dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp);
if (temp & 0x06)
dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp);
sch_io_wr8(priv, SMBHSTSTS, temp);
temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
if (temp) {
dev_err(&sch_adapter.dev,
"SMBus is not ready: (%02x)\n", temp);
dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp);
return -EAGAIN;
}
}
/* start the transaction by setting bit 4 */
outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
do {
usleep_range(100, 200);
temp = inb(SMBHSTSTS) & 0x0f;
} while ((temp & 0x08) && (retries++ < MAX_RETRIES));
/* Start the transaction by setting bit 4 */
temp = sch_io_rd8(priv, SMBHSTCNT);
temp |= 0x10;
sch_io_wr8(priv, SMBHSTCNT, temp);
rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS);
/* If the SMBus is still busy, we give up */
if (retries > MAX_RETRIES) {
dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
if (rc) {
dev_err(&adap->dev, "SMBus Timeout!\n");
} else if (temp & 0x04) {
result = -EIO;
dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
"locked until next hard reset. (sorry!)\n");
rc = -EIO;
dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n");
/* Clock stops and target is stuck in mid-transmission */
} else if (temp & 0x02) {
result = -EIO;
dev_err(&sch_adapter.dev, "Error: no response!\n");
rc = -EIO;
dev_err(&adap->dev, "Error: no response!\n");
} else if (temp & 0x01) {
dev_dbg(&sch_adapter.dev, "Post complete!\n");
outb(temp, SMBHSTSTS);
temp = inb(SMBHSTSTS) & 0x07;
dev_dbg(&adap->dev, "Post complete!\n");
sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f);
temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07;
if (temp & 0x06) {
/* Completion clear failed */
dev_dbg(&sch_adapter.dev, "Failed reset at end of "
"transaction (%02x), Bus error!\n", temp);
dev_dbg(&adap->dev,
"Failed reset at end of transaction (%02x), Bus error!\n", temp);
}
} else {
result = -ENXIO;
dev_dbg(&sch_adapter.dev, "No such address.\n");
rc = -ENXIO;
dev_dbg(&adap->dev, "No such address.\n");
}
dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
inb(SMBHSTDAT1));
return result;
dev_dbg(&adap->dev, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD),
sch_io_rd8(priv, SMBHSTADD),
sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1));
return rc;
}
/*
* This is the main access entry for i2c-sch access
* adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
* (0 for read and 1 for write), size is i2c transaction type and data is the
* union of transaction for data to be transferred or data read from bus.
* return 0 for success and others for failure.
/**
* sch_access - the main access entry for i2c-sch access
* @adap: the i2c adapter pointer
* @addr: the i2c device bus address
* @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
* @read_write: 0 for read and 1 for write
* @command: Byte interpreted by slave, for protocols which use such bytes
* @size: the i2c transaction type
* @data: the union of transaction for data to be transferred or data read from bus
*
* Return: 0 for success and others for failure.
*/
static s32 sch_access(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{
struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter);
int i, len, temp, rc;
/* Make sure the SMBus host is not busy */
temp = inb(SMBHSTSTS) & 0x0f;
temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f;
if (temp & 0x08) {
dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
dev_dbg(&adap->dev, "SMBus busy (%02x)\n", temp);
return -EAGAIN;
}
temp = inw(SMBHSTCLK);
temp = sch_io_rd16(priv, SMBHSTCLK);
if (!temp) {
/*
* We can't determine if we have 33 or 25 MHz clock for
@ -154,50 +177,48 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
* 100 kHz. If we actually run at 25 MHz the bus will be
* run ~75 kHz instead which should do no harm.
*/
dev_notice(&sch_adapter.dev,
"Clock divider uninitialized. Setting defaults\n");
outw(backbone_speed / (4 * 100), SMBHSTCLK);
dev_notice(&adap->dev, "Clock divider uninitialized. Setting defaults\n");
sch_io_wr16(priv, SMBHSTCLK, backbone_speed / (4 * 100));
}
dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
(read_write)?"READ":"WRITE");
dev_dbg(&adap->dev, "access size: %d %s\n", size, str_read_write(read_write));
switch (size) {
case I2C_SMBUS_QUICK:
outb((addr << 1) | read_write, SMBHSTADD);
sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
size = SCH_QUICK;
break;
case I2C_SMBUS_BYTE:
outb((addr << 1) | read_write, SMBHSTADD);
sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
if (read_write == I2C_SMBUS_WRITE)
outb(command, SMBHSTCMD);
sch_io_wr8(priv, SMBHSTCMD, command);
size = SCH_BYTE;
break;
case I2C_SMBUS_BYTE_DATA:
outb((addr << 1) | read_write, SMBHSTADD);
outb(command, SMBHSTCMD);
sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
sch_io_wr8(priv, SMBHSTCMD, command);
if (read_write == I2C_SMBUS_WRITE)
outb(data->byte, SMBHSTDAT0);
sch_io_wr8(priv, SMBHSTDAT0, data->byte);
size = SCH_BYTE_DATA;
break;
case I2C_SMBUS_WORD_DATA:
outb((addr << 1) | read_write, SMBHSTADD);
outb(command, SMBHSTCMD);
sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
sch_io_wr8(priv, SMBHSTCMD, command);
if (read_write == I2C_SMBUS_WRITE) {
outb(data->word & 0xff, SMBHSTDAT0);
outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
sch_io_wr8(priv, SMBHSTDAT0, data->word >> 0);
sch_io_wr8(priv, SMBHSTDAT1, data->word >> 8);
}
size = SCH_WORD_DATA;
break;
case I2C_SMBUS_BLOCK_DATA:
outb((addr << 1) | read_write, SMBHSTADD);
outb(command, SMBHSTCMD);
sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write);
sch_io_wr8(priv, SMBHSTCMD, command);
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL;
outb(len, SMBHSTDAT0);
sch_io_wr8(priv, SMBHSTDAT0, len);
for (i = 1; i <= len; i++)
outb(data->block[i], SMBBLKDAT+i-1);
sch_io_wr8(priv, SMBBLKDAT + i - 1, data->block[i]);
}
size = SCH_BLOCK_DATA;
break;
@ -205,10 +226,13 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
dev_dbg(&adap->dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
rc = sch_transaction();
temp = sch_io_rd8(priv, SMBHSTCNT);
temp = (temp & 0xb0) | (size & 0x7);
sch_io_wr8(priv, SMBHSTCNT, temp);
rc = sch_transaction(adap);
if (rc) /* Error in transaction */
return rc;
@ -218,17 +242,18 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
switch (size) {
case SCH_BYTE:
case SCH_BYTE_DATA:
data->byte = inb(SMBHSTDAT0);
data->byte = sch_io_rd8(priv, SMBHSTDAT0);
break;
case SCH_WORD_DATA:
data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
data->word = (sch_io_rd8(priv, SMBHSTDAT0) << 0) +
(sch_io_rd8(priv, SMBHSTDAT1) << 8);
break;
case SCH_BLOCK_DATA:
data->block[0] = inb(SMBHSTDAT0);
data->block[0] = sch_io_rd8(priv, SMBHSTDAT0);
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb(SMBBLKDAT+i-1);
data->block[i] = sch_io_rd8(priv, SMBBLKDAT + i - 1);
break;
}
return 0;
@ -246,51 +271,34 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = sch_func,
};
static struct i2c_adapter sch_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
static int smbus_sch_probe(struct platform_device *dev)
static int smbus_sch_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sch_i2c *priv;
struct resource *res;
int retval;
res = platform_get_resource(dev, IORESOURCE_IO, 0);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EBUSY;
if (!devm_request_region(&dev->dev, res->start, resource_size(res),
dev->name)) {
dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
sch_smba);
return -EBUSY;
}
priv->smba = devm_ioport_map(dev, res->start, resource_size(res));
if (!priv->smba)
return dev_err_probe(dev, -EBUSY, "SMBus region %pR already in use!\n", res);
sch_smba = res->start;
/* Set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = dev;
priv->adapter.owner = THIS_MODULE,
priv->adapter.class = I2C_CLASS_HWMON,
priv->adapter.algo = &smbus_algorithm,
dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
"SMBus SCH adapter at %04x", (unsigned short)res->start);
/* set up the sysfs linkage to our parent device */
sch_adapter.dev.parent = &dev->dev;
snprintf(sch_adapter.name, sizeof(sch_adapter.name),
"SMBus SCH adapter at %04x", sch_smba);
retval = i2c_add_adapter(&sch_adapter);
if (retval)
sch_smba = 0;
return retval;
}
static void smbus_sch_remove(struct platform_device *pdev)
{
if (sch_smba) {
i2c_del_adapter(&sch_adapter);
sch_smba = 0;
}
return devm_i2c_add_adapter(dev, &priv->adapter);
}
static struct platform_driver smbus_sch_driver = {
@ -298,7 +306,6 @@ static struct platform_driver smbus_sch_driver = {
.name = "isch_smbus",
},
.probe = smbus_sch_probe,
.remove_new = smbus_sch_remove,
};
module_platform_driver(smbus_sch_driver);

View File

@ -847,7 +847,7 @@ static void jz4780_i2c_remove(struct platform_device *pdev)
static struct platform_driver jz4780_i2c_driver = {
.probe = jz4780_i2c_probe,
.remove_new = jz4780_i2c_remove,
.remove = jz4780_i2c_remove,
.driver = {
.name = "jz4780-i2c",
.of_match_table = jz4780_i2c_of_matches,

View File

@ -385,7 +385,7 @@ static struct platform_driver kempld_i2c_driver = {
.pm = pm_sleep_ptr(&kempld_i2c_pm_ops),
},
.probe = kempld_i2c_probe,
.remove_new = kempld_i2c_remove,
.remove = kempld_i2c_remove,
};
module_platform_driver(kempld_i2c_driver);

View File

@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, lpc2k_i2c_match);
static struct platform_driver i2c_lpc2k_driver = {
.probe = i2c_lpc2k_probe,
.remove_new = i2c_lpc2k_remove,
.remove = i2c_lpc2k_remove,
.driver = {
.name = "lpc2k-i2c",
.pm = pm_sleep_ptr(&i2c_lpc2k_dev_pm_ops),

View File

@ -565,7 +565,7 @@ MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = {
.probe = meson_i2c_probe,
.remove_new = meson_i2c_remove,
.remove = meson_i2c_remove,
.driver = {
.name = "meson-i2c",
.of_match_table = meson_i2c_match,

View File

@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match);
static struct platform_driver mchp_corei2c_driver = {
.probe = mchp_corei2c_probe,
.remove_new = mchp_corei2c_remove,
.remove = mchp_corei2c_remove,
.driver = {
.name = "microchip-corei2c",
.of_match_table = mchp_corei2c_of_match,

View File

@ -2456,7 +2456,7 @@ static void mlxbf_i2c_remove(struct platform_device *pdev)
static struct platform_driver mlxbf_i2c_driver = {
.probe = mlxbf_i2c_probe,
.remove_new = mlxbf_i2c_remove,
.remove = mlxbf_i2c_remove,
.driver = {
.name = "i2c-mlxbf",
.acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids),

View File

@ -591,7 +591,7 @@ static void mlxcpld_i2c_remove(struct platform_device *pdev)
static struct platform_driver mlxcpld_i2c_driver = {
.probe = mlxcpld_i2c_probe,
.remove_new = mlxcpld_i2c_remove,
.remove = mlxcpld_i2c_remove,
.driver = {
.name = MLXCPLD_I2C_DEVICE_NAME,
},

View File

@ -938,7 +938,7 @@ MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
/* Structure for a device driver */
static struct platform_driver mpc_i2c_driver = {
.probe = fsl_i2c_probe,
.remove_new = fsl_i2c_remove,
.remove = fsl_i2c_remove,
.driver = {
.name = "mpc-i2c",
.of_match_table = mpc_i2c_of_match,

View File

@ -1550,7 +1550,7 @@ static const struct dev_pm_ops mtk_i2c_pm = {
static struct platform_driver mtk_i2c_driver = {
.probe = mtk_i2c_probe,
.remove_new = mtk_i2c_remove,
.remove = mtk_i2c_remove,
.driver = {
.name = I2C_DRV_NAME,
.pm = pm_sleep_ptr(&mtk_i2c_pm),

View File

@ -331,7 +331,7 @@ static void mtk_i2c_remove(struct platform_device *pdev)
static struct platform_driver mtk_i2c_driver = {
.probe = mtk_i2c_probe,
.remove_new = mtk_i2c_remove,
.remove = mtk_i2c_remove,
.driver = {
.name = "i2c-mt7621",
.of_match_table = i2c_mtk_dt_ids,

View File

@ -1104,7 +1104,7 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove_new = mv64xxx_i2c_remove,
.remove = mv64xxx_i2c_remove,
.driver = {
.name = MV64XXX_I2C_CTLR_NAME,
.pm = &mv64xxx_i2c_pm_ops,

View File

@ -881,7 +881,7 @@ static struct platform_driver mxs_i2c_driver = {
.of_match_table = mxs_i2c_dt_ids,
},
.probe = mxs_i2c_probe,
.remove_new = mxs_i2c_remove,
.remove = mxs_i2c_remove,
};
static int __init mxs_i2c_init(void)

View File

@ -1,240 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
*
* Copyright (C) 2008 Jean Delvare <jdelvare@suse.de>
*/
/*
* We select the channels by sending commands to the Philips
* PCA9556 chip at I2C address 0x18. The main adapter is used for
* the non-multiplexed part of the bus, and 4 virtual adapters
* are defined for the multiplexed addresses: 0x50-0x53 (memory
* module EEPROM) located on channels 1-4. We define one virtual
* adapter per CPU, which corresponds to one multiplexed channel:
* CPU0: virtual adapter 1, channel 1
* CPU1: virtual adapter 2, channel 2
* CPU2: virtual adapter 3, channel 3
* CPU3: virtual adapter 4, channel 4
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
extern struct i2c_adapter *nforce2_smbus;
static struct i2c_adapter *s4985_adapter;
static struct i2c_algorithm *s4985_algo;
/* Wrapper access functions for multiplexed SMBus */
static DEFINE_MUTEX(nforce2_lock);
static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data)
{
int error;
/* We exclude the multiplexed addresses */
if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
|| addr == 0x18)
return -ENXIO;
mutex_lock(&nforce2_lock);
error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
command, size, data);
mutex_unlock(&nforce2_lock);
return error;
}
/* We remember the last used channels combination so as to only switch
channels when it is really needed. This greatly reduces the SMBus
overhead, but also assumes that nobody will be writing to the PCA9556
in our back. */
static u8 last_channels;
static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data,
u8 channels)
{
int error;
/* We exclude the non-multiplexed addresses */
if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
return -ENXIO;
mutex_lock(&nforce2_lock);
if (last_channels != channels) {
union i2c_smbus_data mplxdata;
mplxdata.byte = channels;
error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
I2C_SMBUS_WRITE, 0x01,
I2C_SMBUS_BYTE_DATA,
&mplxdata);
if (error)
goto UNLOCK;
last_channels = channels;
}
error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
command, size, data);
UNLOCK:
mutex_unlock(&nforce2_lock);
return error;
}
static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data)
{
/* CPU0: channel 1 enabled */
return nforce2_access_channel(adap, addr, flags, read_write, command,
size, data, 0x02);
}
static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data)
{
/* CPU1: channel 2 enabled */
return nforce2_access_channel(adap, addr, flags, read_write, command,
size, data, 0x04);
}
static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data)
{
/* CPU2: channel 3 enabled */
return nforce2_access_channel(adap, addr, flags, read_write, command,
size, data, 0x08);
}
static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size,
union i2c_smbus_data *data)
{
/* CPU3: channel 4 enabled */
return nforce2_access_channel(adap, addr, flags, read_write, command,
size, data, 0x10);
}
static int __init nforce2_s4985_init(void)
{
int i, error;
union i2c_smbus_data ioconfig;
if (!nforce2_smbus)
return -ENODEV;
/* Configure the PCA9556 multiplexer */
ioconfig.byte = 0x00; /* All I/O to output mode */
error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
I2C_SMBUS_BYTE_DATA, &ioconfig);
if (error) {
dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
error = -EIO;
goto ERROR0;
}
/* Unregister physical bus */
i2c_del_adapter(nforce2_smbus);
printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
/* Define the 5 virtual adapters and algorithms structures */
s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL);
if (!s4985_adapter) {
error = -ENOMEM;
goto ERROR1;
}
s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL);
if (!s4985_algo) {
error = -ENOMEM;
goto ERROR2;
}
/* Fill in the new structures */
s4985_algo[0] = *(nforce2_smbus->algo);
s4985_algo[0].smbus_xfer = nforce2_access_virt0;
s4985_adapter[0] = *nforce2_smbus;
s4985_adapter[0].algo = s4985_algo;
s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
for (i = 1; i < 5; i++) {
s4985_algo[i] = *(nforce2_smbus->algo);
s4985_adapter[i] = *nforce2_smbus;
snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
"SMBus nForce2 adapter (CPU%d)", i - 1);
s4985_adapter[i].algo = s4985_algo + i;
s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
}
s4985_algo[1].smbus_xfer = nforce2_access_virt1;
s4985_algo[2].smbus_xfer = nforce2_access_virt2;
s4985_algo[3].smbus_xfer = nforce2_access_virt3;
s4985_algo[4].smbus_xfer = nforce2_access_virt4;
/* Register virtual adapters */
for (i = 0; i < 5; i++) {
error = i2c_add_adapter(s4985_adapter + i);
if (error) {
printk(KERN_ERR "i2c-nforce2-s4985: "
"Virtual adapter %d registration "
"failed, module not inserted\n", i);
for (i--; i >= 0; i--)
i2c_del_adapter(s4985_adapter + i);
goto ERROR3;
}
}
return 0;
ERROR3:
kfree(s4985_algo);
s4985_algo = NULL;
ERROR2:
kfree(s4985_adapter);
s4985_adapter = NULL;
ERROR1:
/* Restore physical bus */
i2c_add_adapter(nforce2_smbus);
ERROR0:
return error;
}
static void __exit nforce2_s4985_exit(void)
{
if (s4985_adapter) {
int i;
for (i = 0; i < 5; i++)
i2c_del_adapter(s4985_adapter+i);
kfree(s4985_adapter);
s4985_adapter = NULL;
}
kfree(s4985_algo);
s4985_algo = NULL;
/* Restore physical bus */
if (i2c_add_adapter(nforce2_smbus))
printk(KERN_ERR "i2c-nforce2-s4985: "
"Physical bus restoration failed\n");
}
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
MODULE_DESCRIPTION("S4985 SMBus multiplexing");
MODULE_LICENSE("GPL");
module_init(nforce2_s4985_init);
module_exit(nforce2_s4985_exit);

View File

@ -117,20 +117,6 @@ static const struct dmi_system_id nforce2_dmi_blacklist2[] = {
static struct pci_driver nforce2_driver;
/* For multiplexing support, we need a global reference to the 1st
SMBus channel */
#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
struct i2c_adapter *nforce2_smbus;
EXPORT_SYMBOL_GPL(nforce2_smbus);
static void nforce2_set_reference(struct i2c_adapter *adap)
{
nforce2_smbus = adap;
}
#else
static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
#endif
static void nforce2_abort(struct i2c_adapter *adap)
{
struct nforce2_smbus *smbus = adap->algo_data;
@ -411,7 +397,6 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
nforce2_set_reference(&smbuses[0].adapter);
return 0;
}
@ -420,7 +405,6 @@ static void nforce2_remove(struct pci_dev *dev)
{
struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
nforce2_set_reference(NULL);
if (smbuses[0].base) {
i2c_del_adapter(&smbuses[0].adapter);
release_region(smbuses[0].base, smbuses[0].size);

View File

@ -334,6 +334,7 @@ struct npcm_i2c {
u64 nack_cnt;
u64 timeout_cnt;
u64 tx_complete_cnt;
bool ber_state; /* Indicate the bus error state */
};
static inline void npcm_i2c_select_bank(struct npcm_i2c *bus,
@ -1521,6 +1522,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus)
if (npcm_i2c_is_master(bus)) {
npcm_i2c_master_abort(bus);
} else {
bus->ber_state = true;
npcm_i2c_clear_master_status(bus);
/* Clear BB (BUS BUSY) bit */
@ -1628,13 +1630,10 @@ static void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst)
npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0));
/* SDA interrupt, after start\restart */
} else {
if (NPCM_I2CST_XMIT & i2cst) {
bus->operation = I2C_WRITE_OPER;
if (bus->operation == I2C_WRITE_OPER)
npcm_i2c_irq_master_handler_write(bus);
} else {
bus->operation = I2C_READ_OPER;
else if (bus->operation == I2C_READ_OPER)
npcm_i2c_irq_master_handler_read(bus);
}
}
}
@ -1702,6 +1701,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck",
bus->num, bus->dest_addr);
npcm_i2c_reset(bus);
bus->ber_state = false;
return 0;
}
@ -1766,6 +1766,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
if (bus->rec_succ_cnt < ULLONG_MAX)
bus->rec_succ_cnt++;
}
bus->ber_state = false;
return status;
}
@ -2161,7 +2162,16 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
} while (time_is_after_jiffies(time_left) && bus_busy);
if (bus_busy) {
/*
* Check the BER (bus error) state, when ber_state is true, it means that the module
* detects the bus error which is caused by some factor like that the electricity
* noise occurs on the bus. Under this condition, the module is reset and the bus
* gets recovered.
*
* While ber_state is false, the module reset and bus recovery also get done as the
* bus is busy.
*/
if (bus_busy || bus->ber_state) {
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
npcm_i2c_reset(bus);
i2c_recover_bus(adap);
@ -2363,7 +2373,7 @@ MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table);
static struct platform_driver npcm_i2c_bus_driver = {
.probe = npcm_i2c_probe_bus,
.remove_new = npcm_i2c_remove_bus,
.remove = npcm_i2c_remove_bus,
.driver = {
.name = "nuvoton-i2c",
.of_match_table = npcm_i2c_bus_of_table,

View File

@ -769,7 +769,7 @@ static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm,
static struct platform_driver ocores_i2c_driver = {
.probe = ocores_i2c_probe,
.remove_new = ocores_i2c_remove,
.remove = ocores_i2c_remove,
.driver = {
.name = "ocores-i2c",
.of_match_table = ocores_i2c_match,

View File

@ -269,7 +269,7 @@ MODULE_DEVICE_TABLE(of, octeon_i2c_match);
static struct platform_driver octeon_i2c_driver = {
.probe = octeon_i2c_probe,
.remove_new = octeon_i2c_remove,
.remove = octeon_i2c_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = octeon_i2c_match,

View File

@ -1605,7 +1605,7 @@ static const struct dev_pm_ops omap_i2c_pm_ops = {
static struct platform_driver omap_i2c_driver = {
.probe = omap_i2c_probe,
.remove_new = omap_i2c_remove,
.remove = omap_i2c_remove,
.driver = {
.name = "omap_i2c",
.pm = pm_ptr(&omap_i2c_pm_ops),

View File

@ -249,7 +249,7 @@ MODULE_DEVICE_TABLE(of, i2c_opal_of_match);
static struct platform_driver i2c_opal_driver = {
.probe = i2c_opal_probe,
.remove_new = i2c_opal_remove,
.remove = i2c_opal_remove,
.driver = {
.name = "i2c-opal",
.of_match_table = i2c_opal_of_match,

View File

@ -104,7 +104,7 @@ static struct platform_driver pasemi_platform_i2c_driver = {
.of_match_table = pasemi_platform_i2c_of_match,
},
.probe = pasemi_platform_i2c_probe,
.remove_new = pasemi_platform_i2c_remove,
.remove = pasemi_platform_i2c_remove,
};
module_platform_driver(pasemi_platform_i2c_driver);

View File

@ -238,7 +238,7 @@ MODULE_DEVICE_TABLE(of, i2c_pca_of_match_table);
static struct platform_driver i2c_pca_pf_driver = {
.probe = i2c_pca_pf_probe,
.remove_new = i2c_pca_pf_remove,
.remove = i2c_pca_pf_remove,
.driver = {
.name = "i2c-pca-platform",
.of_match_table = of_match_ptr(i2c_pca_of_match_table),

View File

@ -35,20 +35,7 @@
#include <linux/acpi.h>
#include <linux/io.h>
/* PIIX4 SMBus address offsets */
#define SMBHSTSTS (0 + piix4_smba)
#define SMBHSLVSTS (1 + piix4_smba)
#define SMBHSTCNT (2 + piix4_smba)
#define SMBHSTCMD (3 + piix4_smba)
#define SMBHSTADD (4 + piix4_smba)
#define SMBHSTDAT0 (5 + piix4_smba)
#define SMBHSTDAT1 (6 + piix4_smba)
#define SMBBLKDAT (7 + piix4_smba)
#define SMBSLVCNT (8 + piix4_smba)
#define SMBSHDWCMD (9 + piix4_smba)
#define SMBSLVEVT (0xA + piix4_smba)
#define SMBSLVDAT (0xC + piix4_smba)
#include "i2c-piix4.h"
/* count for request_region */
#define SMBIOSIZE 9
@ -70,7 +57,6 @@
#define PIIX4_BYTE 0x04
#define PIIX4_BYTE_DATA 0x08
#define PIIX4_WORD_DATA 0x0C
#define PIIX4_BLOCK_DATA 0x14
/* Multi-port constants */
#define PIIX4_MAX_ADAPTERS 4
@ -101,6 +87,7 @@
#define SB800_PIIX4_FCH_PM_ADDR 0xFED80300
#define SB800_PIIX4_FCH_PM_SIZE 8
#define SB800_ASF_ACPI_PATH "\\_SB.ASFC"
/* insmod parameters */
@ -160,11 +147,6 @@ static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
};
static const char *piix4_aux_port_name_sb800 = " port 1";
struct sb800_mmio_cfg {
void __iomem *addr;
bool use_mmio;
};
struct i2c_piix4_adapdata {
unsigned short smba;
@ -175,8 +157,7 @@ struct i2c_piix4_adapdata {
struct sb800_mmio_cfg mmio_cfg;
};
static int piix4_sb800_region_request(struct device *dev,
struct sb800_mmio_cfg *mmio_cfg)
int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg)
{
if (mmio_cfg->use_mmio) {
void __iomem *addr;
@ -214,9 +195,9 @@ static int piix4_sb800_region_request(struct device *dev,
return 0;
}
EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_request, PIIX4_SMBUS);
static void piix4_sb800_region_release(struct device *dev,
struct sb800_mmio_cfg *mmio_cfg)
void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg)
{
if (mmio_cfg->use_mmio) {
iounmap(mmio_cfg->addr);
@ -227,6 +208,7 @@ static void piix4_sb800_region_release(struct device *dev,
release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
}
EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_release, PIIX4_SMBUS);
static bool piix4_sb800_use_mmio(struct pci_dev *PIIX4_dev)
{
@ -536,10 +518,8 @@ static int piix4_setup_aux(struct pci_dev *PIIX4_dev,
return piix4_smba;
}
static int piix4_transaction(struct i2c_adapter *piix4_adapter)
int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba)
{
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
unsigned short piix4_smba = adapdata->smba;
int temp;
int result = 0;
int timeout = 0;
@ -611,6 +591,7 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter)
inb_p(SMBHSTDAT1));
return result;
}
EXPORT_SYMBOL_NS_GPL(piix4_transaction, PIIX4_SMBUS);
/* Return negative errno on error. */
static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
@ -675,7 +656,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
status = piix4_transaction(adap);
status = piix4_transaction(adap, piix4_smba);
if (status)
return status;
@ -764,7 +745,7 @@ static void piix4_imc_wakeup(void)
release_region(KERNCZ_IMC_IDX, 2);
}
static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg)
int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg)
{
u8 smba_en_lo, val;
@ -786,6 +767,7 @@ static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg)
return (smba_en_lo & piix4_port_mask_sb800);
}
EXPORT_SYMBOL_NS_GPL(piix4_sb800_port_sel, PIIX4_SMBUS);
/*
* Handles access to multiple SMBus ports on the SB800.
@ -1043,6 +1025,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
bool is_sb800 = false;
bool is_asf = false;
acpi_status status;
acpi_handle handle;
if ((dev->vendor == PCI_VENDOR_ID_ATI &&
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
@ -1105,10 +1090,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
}
status = acpi_get_handle(NULL, (acpi_string)SB800_ASF_ACPI_PATH, &handle);
if (ACPI_SUCCESS(status))
is_asf = true;
if (dev->vendor == PCI_VENDOR_ID_AMD &&
(dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS ||
dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) {
retval = piix4_setup_sb800(dev, id, 1);
/* Do not setup AUX port if ASF is enabled */
if (!is_asf)
retval = piix4_setup_sb800(dev, id, 1);
}
if (retval > 0) {

View File

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* PIIX4/SB800 SMBus Interfaces
*
* Copyright (c) 2024, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
* Sanket Goswami <Sanket.Goswami@amd.com>
*/
#ifndef I2C_PIIX4_H
#define I2C_PIIX4_H
#include <linux/types.h>
/* PIIX4 SMBus address offsets */
#define SMBHSTSTS (0x00 + piix4_smba)
#define SMBHSLVSTS (0x01 + piix4_smba)
#define SMBHSTCNT (0x02 + piix4_smba)
#define SMBHSTCMD (0x03 + piix4_smba)
#define SMBHSTADD (0x04 + piix4_smba)
#define SMBHSTDAT0 (0x05 + piix4_smba)
#define SMBHSTDAT1 (0x06 + piix4_smba)
#define SMBBLKDAT (0x07 + piix4_smba)
#define SMBSLVCNT (0x08 + piix4_smba)
#define SMBSHDWCMD (0x09 + piix4_smba)
#define SMBSLVEVT (0x0A + piix4_smba)
#define SMBSLVDAT (0x0C + piix4_smba)
/* PIIX4 constants */
#define PIIX4_BLOCK_DATA 0x14
struct sb800_mmio_cfg {
void __iomem *addr;
bool use_mmio;
};
int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg);
int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba);
int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg);
void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg);
#endif /* I2C_PIIX4_H */

View File

@ -733,7 +733,7 @@ static struct platform_driver i2c_pnx_driver = {
.pm = pm_sleep_ptr(&i2c_pnx_pm),
},
.probe = i2c_pnx_probe,
.remove_new = i2c_pnx_remove,
.remove = i2c_pnx_remove,
};
static int __init i2c_adap_pnx_init(void)

View File

@ -437,7 +437,7 @@ static int i2c_powermac_probe(struct platform_device *dev)
static struct platform_driver i2c_powermac_driver = {
.probe = i2c_powermac_probe,
.remove_new = i2c_powermac_remove,
.remove = i2c_powermac_remove,
.driver = {
.name = "i2c-powermac",
.bus = &platform_bus_type,

View File

@ -1574,7 +1574,7 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
.remove_new = i2c_pxa_remove,
.remove = i2c_pxa_remove,
.driver = {
.name = "pxa2xx-i2c",
.pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops),

View File

@ -120,7 +120,6 @@ struct cci_data {
unsigned int num_masters;
struct i2c_adapter_quirks quirks;
u16 queue_size[NUM_QUEUES];
unsigned long cci_clk_rate;
struct hw_params params[3];
};
@ -523,7 +522,6 @@ static const struct dev_pm_ops qcom_cci_pm = {
static int cci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
unsigned long cci_clk_rate = 0;
struct device_node *child;
struct resource *r;
struct cci *cci;
@ -594,22 +592,6 @@ static int cci_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n");
cci->nclocks = ret;
/* Retrieve CCI clock rate */
for (i = 0; i < cci->nclocks; i++) {
if (!strcmp(cci->clocks[i].id, "cci")) {
cci_clk_rate = clk_get_rate(cci->clocks[i].clk);
break;
}
}
if (cci_clk_rate != cci->data->cci_clk_rate) {
/* cci clock set by the bootloader or via assigned clock rate
* in DT.
*/
dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n",
cci_clk_rate, cci->data->cci_clk_rate);
}
ret = cci_enable_clocks(cci);
if (ret < 0)
return ret;
@ -699,7 +681,6 @@ static const struct cci_data cci_v1_data = {
.max_write_len = 10,
.max_read_len = 12,
},
.cci_clk_rate = 19200000,
.params[I2C_MODE_STANDARD] = {
.thigh = 78,
.tlow = 114,
@ -733,7 +714,6 @@ static const struct cci_data cci_v1_5_data = {
.max_write_len = 10,
.max_read_len = 12,
},
.cci_clk_rate = 19200000,
.params[I2C_MODE_STANDARD] = {
.thigh = 78,
.tlow = 114,
@ -767,7 +747,6 @@ static const struct cci_data cci_v2_data = {
.max_write_len = 11,
.max_read_len = 12,
},
.cci_clk_rate = 37500000,
.params[I2C_MODE_STANDARD] = {
.thigh = 201,
.tlow = 174,
@ -826,7 +805,7 @@ MODULE_DEVICE_TABLE(of, cci_dt_match);
static struct platform_driver qcom_cci_driver = {
.probe = cci_probe,
.remove_new = cci_remove,
.remove = cci_remove,
.driver = {
.name = "i2c-qcom-cci",
.of_match_table = cci_dt_match,

View File

@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/soc/qcom/geni-se.h>
#include <linux/spinlock.h>
#include <linux/units.h>
#define SE_I2C_TX_TRANS_LEN 0x26c
#define SE_I2C_RX_TRANS_LEN 0x270
@ -146,22 +147,36 @@ struct geni_i2c_clk_fld {
* clk_freq_out = t / t_cycle
* source_clock = 19.2 MHz
*/
static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
{KHZ(100), 7, 10, 11, 26},
{KHZ(400), 2, 5, 12, 24},
{KHZ(1000), 1, 3, 9, 18},
{},
};
/* source_clock = 32 MHz */
static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = {
{KHZ(100), 8, 14, 18, 40},
{KHZ(400), 4, 3, 11, 20},
{KHZ(1000), 2, 3, 6, 15},
{},
};
static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
{
int i;
const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;
const struct geni_i2c_clk_fld *itr;
for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
if (clk_get_rate(gi2c->se.clk) == 32 * HZ_PER_MHZ)
itr = geni_i2c_clk_map_32mhz;
else
itr = geni_i2c_clk_map_19p2mhz;
while (itr->clk_freq_out != 0) {
if (itr->clk_freq_out == gi2c->clk_freq_out) {
gi2c->clk_fld = itr;
return 0;
}
itr++;
}
return -EINVAL;
}
@ -818,6 +833,8 @@ static int geni_i2c_probe(struct platform_device *pdev)
init_completion(&gi2c->done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
/* Keep interrupts disabled initially to allow for low-power modes */
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
dev_name(dev), gi2c);
if (ret) {
@ -1049,7 +1066,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
static struct platform_driver geni_i2c_driver = {
.probe = geni_i2c_probe,
.remove_new = geni_i2c_remove,
.remove = geni_i2c_remove,
.shutdown = geni_i2c_shutdown,
.driver = {
.name = "geni_i2c",

View File

@ -1974,7 +1974,7 @@ MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
static struct platform_driver qup_i2c_driver = {
.probe = qup_i2c_probe,
.remove_new = qup_i2c_remove,
.remove = qup_i2c_remove,
.driver = {
.name = "i2c_qup",
.pm = pm_ptr(&qup_i2c_qup_pm_ops),

View File

@ -1271,7 +1271,7 @@ static struct platform_driver rcar_i2c_driver = {
.pm = pm_sleep_ptr(&rcar_i2c_pm_ops),
},
.probe = rcar_i2c_probe,
.remove_new = rcar_i2c_remove,
.remove = rcar_i2c_remove,
};
module_platform_driver(rcar_i2c_driver);

View File

@ -632,7 +632,7 @@ static const struct of_device_id riic_i2c_dt_ids[] = {
static struct platform_driver riic_i2c_driver = {
.probe = riic_i2c_probe,
.remove_new = riic_i2c_remove,
.remove = riic_i2c_remove,
.driver = {
.name = "i2c-riic",
.of_match_table = riic_i2c_dt_ids,

View File

@ -1398,7 +1398,7 @@ static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume);
static struct platform_driver rk3x_i2c_driver = {
.probe = rk3x_i2c_probe,
.remove_new = rk3x_i2c_remove,
.remove = rk3x_i2c_remove,
.driver = {
.name = "rk3x-i2c",
.of_match_table = rk3x_i2c_match,

View File

@ -0,0 +1,423 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/bits.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/mod_devicetable.h>
#include <linux/mfd/syscon.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
enum rtl9300_bus_freq {
RTL9300_I2C_STD_FREQ,
RTL9300_I2C_FAST_FREQ,
};
struct rtl9300_i2c;
struct rtl9300_i2c_chan {
struct i2c_adapter adap;
struct rtl9300_i2c *i2c;
enum rtl9300_bus_freq bus_freq;
u8 sda_pin;
};
#define RTL9300_I2C_MUX_NCHAN 8
struct rtl9300_i2c {
struct regmap *regmap;
struct device *dev;
struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN];
u32 reg_base;
u8 sda_pin;
struct mutex lock;
};
#define RTL9300_I2C_MST_CTRL1 0x0
#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8
#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8)
#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4
#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4)
#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3)
#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2)
#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1)
#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0)
#define RTL9300_I2C_MST_CTRL2 0x4
#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15)
#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8
#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8)
#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4
#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4)
#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2
#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2)
#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0
#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0)
#define RTL9300_I2C_MST_DATA_WORD0 0x8
#define RTL9300_I2C_MST_DATA_WORD1 0xc
#define RTL9300_I2C_MST_DATA_WORD2 0x10
#define RTL9300_I2C_MST_DATA_WORD3 0x14
#define RTL9300_I2C_MST_GLB_CTRL 0x384
static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
u32 val, mask;
int ret;
val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS;
mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK;
ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
if (ret)
return ret;
val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS;
mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK;
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
}
static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
{
int ret;
u32 val, mask;
ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin));
if (ret)
return ret;
val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) |
RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
}
static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
u16 addr, u16 len)
{
u32 val, mask;
val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS;
mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK;
val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS;
mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK;
val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS;
mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK;
mask |= RTL9300_I2C_MST_CTRL2_RD_MODE;
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
}
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
u32 vals[4] = {};
int i, ret;
if (len > 16)
return -EIO;
ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
vals, ARRAY_SIZE(vals));
if (ret)
return ret;
for (i = 0; i < len; i++) {
buf[i] = vals[i/4] & 0xff;
vals[i/4] >>= 8;
}
return 0;
}
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
u32 vals[4] = {};
int i;
if (len > 16)
return -EIO;
for (i = 0; i < len; i++) {
if (i % 4 == 0)
vals[i/4] = 0;
vals[i/4] <<= 8;
vals[i/4] |= buf[i];
}
return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
vals, ARRAY_SIZE(vals));
}
static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
{
return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data);
}
static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
int size, union i2c_smbus_data *data, int len)
{
u32 val, mask;
int ret;
val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0;
mask = RTL9300_I2C_MST_CTRL1_RWOP;
val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
if (ret)
return ret;
ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1,
val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 2000);
if (ret)
return ret;
if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL)
return -EIO;
if (read_write == I2C_SMBUS_READ) {
if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) {
ret = regmap_read(i2c->regmap,
i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
if (ret)
return ret;
data->byte = val & 0xff;
} else if (size == I2C_SMBUS_WORD_DATA) {
ret = regmap_read(i2c->regmap,
i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
if (ret)
return ret;
data->word = val & 0xffff;
} else {
ret = rtl9300_i2c_read(i2c, &data->block[0], len);
if (ret)
return ret;
}
}
return 0;
}
static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data *data)
{
struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
struct rtl9300_i2c *i2c = chan->i2c;
int len = 0, ret;
mutex_lock(&i2c->lock);
if (chan->sda_pin != i2c->sda_pin) {
ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
if (ret)
goto out_unlock;
i2c->sda_pin = chan->sda_pin;
}
switch (size) {
case I2C_SMBUS_QUICK:
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
if (ret)
goto out_unlock;
break;
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
if (ret)
goto out_unlock;
} else {
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
if (ret)
goto out_unlock;
}
break;
case I2C_SMBUS_BYTE_DATA:
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
if (ret)
goto out_unlock;
if (read_write == I2C_SMBUS_WRITE) {
ret = rtl9300_i2c_writel(i2c, data->byte);
if (ret)
goto out_unlock;
}
break;
case I2C_SMBUS_WORD_DATA:
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2);
if (ret)
goto out_unlock;
if (read_write == I2C_SMBUS_WRITE) {
ret = rtl9300_i2c_writel(i2c, data->word);
if (ret)
goto out_unlock;
}
break;
case I2C_SMBUS_BLOCK_DATA:
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
if (ret)
goto out_unlock;
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]);
if (ret)
goto out_unlock;
if (read_write == I2C_SMBUS_WRITE) {
ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]);
if (ret)
goto out_unlock;
}
len = data->block[0];
break;
default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
ret = -EOPNOTSUPP;
goto out_unlock;
}
ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len);
out_unlock:
mutex_unlock(&i2c->lock);
return ret;
}
static u32 rtl9300_i2c_func(struct i2c_adapter *a)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm rtl9300_i2c_algo = {
.smbus_xfer = rtl9300_i2c_smbus_xfer,
.functionality = rtl9300_i2c_func,
};
static struct i2c_adapter_quirks rtl9300_i2c_quirks = {
.flags = I2C_AQ_NO_CLK_STRETCH,
.max_read_len = 16,
.max_write_len = 16,
};
static int rtl9300_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtl9300_i2c *i2c;
u32 clock_freq, sda_pin;
int ret, i = 0;
struct fwnode_handle *child;
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->regmap = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(i2c->regmap))
return PTR_ERR(i2c->regmap);
i2c->dev = dev;
mutex_init(&i2c->lock);
ret = device_property_read_u32(dev, "reg", &i2c->reg_base);
if (ret)
return ret;
platform_set_drvdata(pdev, i2c);
if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN)
return dev_err_probe(dev, -EINVAL, "Too many channels\n");
device_for_each_child_node(dev, child) {
struct rtl9300_i2c_chan *chan = &i2c->chans[i];
struct i2c_adapter *adap = &chan->adap;
ret = fwnode_property_read_u32(child, "reg", &sda_pin);
if (ret)
return ret;
ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq);
if (ret)
clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
switch (clock_freq) {
case I2C_MAX_STANDARD_MODE_FREQ:
chan->bus_freq = RTL9300_I2C_STD_FREQ;
break;
case I2C_MAX_FAST_MODE_FREQ:
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
break;
default:
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
sda_pin, clock_freq);
break;
}
chan->sda_pin = sda_pin;
chan->i2c = i2c;
adap = &i2c->chans[i].adap;
adap->owner = THIS_MODULE;
adap->algo = &rtl9300_i2c_algo;
adap->quirks = &rtl9300_i2c_quirks;
adap->retries = 3;
adap->dev.parent = dev;
i2c_set_adapdata(adap, chan);
adap->dev.of_node = to_of_node(child);
snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin);
i++;
ret = devm_i2c_add_adapter(dev, adap);
if (ret)
return ret;
}
i2c->sda_pin = 0xff;
return 0;
}
static const struct of_device_id i2c_rtl9300_dt_ids[] = {
{ .compatible = "realtek,rtl9301-i2c" },
{ .compatible = "realtek,rtl9302b-i2c" },
{ .compatible = "realtek,rtl9302c-i2c" },
{ .compatible = "realtek,rtl9303-i2c" },
{}
};
MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
static struct platform_driver rtl9300_i2c_driver = {
.probe = rtl9300_i2c_probe,
.driver = {
.name = "i2c-rtl9300",
.of_match_table = i2c_rtl9300_dt_ids,
},
};
module_platform_driver(rtl9300_i2c_driver);
MODULE_DESCRIPTION("RTL9300 I2C controller driver");
MODULE_LICENSE("GPL");

View File

@ -536,7 +536,7 @@ static struct platform_driver rzv2m_i2c_driver = {
.pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops),
},
.probe = rzv2m_i2c_probe,
.remove_new = rzv2m_i2c_remove,
.remove = rzv2m_i2c_remove,
};
module_platform_driver(rzv2m_i2c_driver);

View File

@ -1176,7 +1176,7 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove_new = s3c24xx_i2c_remove,
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids,
.driver = {
.name = "s3c-i2c",

View File

@ -411,7 +411,7 @@ static void smbus_cmi_remove(struct platform_device *device)
static struct platform_driver smbus_cmi_driver = {
.probe = smbus_cmi_probe,
.remove_new = smbus_cmi_remove,
.remove = smbus_cmi_remove,
.driver = {
.name = "smbus_cmi",
.acpi_match_table = acpi_smbus_cmi_ids,

View File

@ -552,7 +552,7 @@ static struct platform_driver sh7760_i2c_drv = {
.name = SH7760_I2C_DEVNAME,
},
.probe = sh7760_i2c_probe,
.remove_new = sh7760_i2c_remove,
.remove = sh7760_i2c_remove,
};
module_platform_driver(sh7760_i2c_drv);

View File

@ -983,7 +983,7 @@ static struct platform_driver sh_mobile_i2c_driver = {
.pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops),
},
.probe = sh_mobile_i2c_probe,
.remove_new = sh_mobile_i2c_remove,
.remove = sh_mobile_i2c_remove,
};
static int __init sh_mobile_i2c_adap_init(void)

View File

@ -144,7 +144,7 @@ static struct platform_driver simtec_i2c_driver = {
.name = "simtec-i2c",
},
.probe = simtec_i2c_probe,
.remove_new = simtec_i2c_remove,
.remove = simtec_i2c_remove,
};
module_platform_driver(simtec_i2c_driver);

View File

@ -643,7 +643,7 @@ MODULE_DEVICE_TABLE(of, sprd_i2c_of_match);
static struct platform_driver sprd_i2c_driver = {
.probe = sprd_i2c_probe,
.remove_new = sprd_i2c_remove,
.remove = sprd_i2c_remove,
.driver = {
.name = "sprd-i2c",
.of_match_table = sprd_i2c_of_match,

View File

@ -893,7 +893,7 @@ static struct platform_driver st_i2c_driver = {
.pm = pm_sleep_ptr(&st_i2c_pm),
},
.probe = st_i2c_probe,
.remove_new = st_i2c_remove,
.remove = st_i2c_remove,
};
module_platform_driver(st_i2c_driver);

View File

@ -869,7 +869,7 @@ static struct platform_driver stm32f4_i2c_driver = {
.of_match_table = stm32f4_i2c_match,
},
.probe = stm32f4_i2c_probe,
.remove_new = stm32f4_i2c_remove,
.remove = stm32f4_i2c_remove,
};
module_platform_driver(stm32f4_i2c_driver);

View File

@ -2532,7 +2532,7 @@ static struct platform_driver stm32f7_i2c_driver = {
.pm = &stm32f7_i2c_pm_ops,
},
.probe = stm32f7_i2c_probe,
.remove_new = stm32f7_i2c_remove,
.remove = stm32f7_i2c_remove,
};
module_platform_driver(stm32f7_i2c_driver);

View File

@ -319,7 +319,7 @@ static void p2wi_remove(struct platform_device *dev)
static struct platform_driver p2wi_driver = {
.probe = p2wi_probe,
.remove_new = p2wi_remove,
.remove = p2wi_remove,
.driver = {
.name = "i2c-sunxi-p2wi",
.of_match_table = p2wi_of_match_table,

View File

@ -629,7 +629,7 @@ MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids);
static struct platform_driver synquacer_i2c_driver = {
.probe = synquacer_i2c_probe,
.remove_new = synquacer_i2c_remove,
.remove = synquacer_i2c_remove,
.driver = {
.name = "synquacer_i2c",
.of_match_table = of_match_ptr(synquacer_i2c_dt_ids),

View File

@ -335,7 +335,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = {
.of_match_table = tegra_bpmp_i2c_of_match,
},
.probe = tegra_bpmp_i2c_probe,
.remove_new = tegra_bpmp_i2c_remove,
.remove = tegra_bpmp_i2c_remove,
};
module_platform_driver(tegra_bpmp_i2c_driver);

View File

@ -1964,7 +1964,7 @@ MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match);
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove_new = tegra_i2c_remove,
.remove = tegra_i2c_remove,
.driver = {
.name = "tegra-i2c",
.of_match_table = tegra_i2c_of_match,

Some files were not shown because too many files have changed in this diff Show More