- new drivers: Microchip CoreI2C, Renesas RZV2M

- quite some DT schema conversions and extensions
 - and a bunch of driver updates and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmLpLy8ACgkQFA3kzBSg
 KbbOzg/+MqZiU5PGxI++qWo7FaZ2Cs8ceclDFRChaO6DGK7YzmzJL+2vbyqgqVi5
 YwqPSgTXC4KjCzxrT4Gh05K/JI32gdp1iKG9kuNAJBQIxz+enKD5nWQ1IUK7dwp+
 8EWGJNOF7uO/zcKrZ0IsJUTrtX6Gm+eolgrtQIF1ol4h7c++PtQWWMV0LN4b1V/u
 QQ1NWgjXVMdYy8k8Js+4mBJFFF3+ODZt0/p10Ewi9M7u2LiJBOPOnv6ITkEbTNb+
 f1zUOPgYz5DQOvus/tphgaGVxyZOOyuXPCgK74qad1NOy7HMiA/YmBfT+Q0M9eZG
 ckAJFTDivZF+o+q2ImvPFKL3jb4YwlIYwbPRLs1qm0BzwNdewL2FK5ESCx+GkFJH
 K0RbdcNPATXi/uLYVye7bCh2iYcKI15bliWWpVenK0eE5DiGZNHOesy9UWImJ/Q6
 dxJhufWY6Ft74Kve6YQNT8w/sPbjnN2YwE1XZO7JoRLbZsgZwTFUn4N+RHey4fc0
 RkwAIckIptBlVqdD0QOergGHqg3nP5F0VrR5hYpzpfyrf/Cef+SOMkru0muX0jx4
 mhhUGq0jZJ43/187615C+HN5z0pFLs01DtTFfG76CGXgHgtd3OJIim/uGPiqR9mc
 cmX1hT/FpObjdF8/JVCLjOFr/Xgahw7VnPRw8vVzCoLRH+gsOLA=
 =6fXH
 -----END PGP SIGNATURE-----

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

Pull i2c updates from Wolfram Sang:

 - new drivers: Microchip CoreI2C, Renesas RZV2M

 - quite some DT schema conversions and extensions

 - and a bunch of driver updates and improvements

* tag 'i2c-for-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (37 commits)
  i2c: extend documentation about retvals of master_xfer functions
  i2c: mux-gpmux: Add of_node_put() when breaking out of loop
  dt-bindings: i2c: i2c-rk3x: Document Rockchip RV1126
  i2c: qcom-geni: Use the correct return value
  i2c: cadence: Support PEC for SMBus block read
  i2c: qcom-geni: Propagate GENI_ABORT_DONE to geni_i2c_abort_xfer()
  i2c: brcmstb: Use dev_name() for adapter name
  i2c: Add Renesas RZ/V2M controller
  dt-bindings: i2c: Document RZ/V2M I2C controller
  i2c: mlxcpld: Add callback to notify probing completion
  i2c: scmi: Replace open coded device_get_match_data()
  i2c: stm32: add support for the STM32MP13 soc
  dt-bindings: i2c: st,stm32-i2c: add entry for stm32mp13
  dt-bindings: i2c: i2c-rk3x: add rk3588 compatible
  i2c: add support for microchip fpga i2c controllers
  i2c: i801: Add support for Intel Meteor Lake-P
  dt-bindings: i2c: nomadik: Add power domain to binding
  dt-bindings: i2c: nomadik: Drop unused voltage supply from example
  i2c: Fix a potential use after free
  i2c: hisi: use HZ_PER_KHZ macro in units.h
  ...
This commit is contained in:
Linus Torvalds 2022-08-03 19:23:51 -07:00
commit 80dc75932f
33 changed files with 1655 additions and 262 deletions

View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/arm,i2c-versatile.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: I2C Controller on ARM Ltd development platforms
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: arm,versatile-i2c
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
...

View File

@ -1,23 +0,0 @@
I2C for Nomadik based systems
Required (non-standard) properties:
- Nil
Recommended (non-standard) properties:
- clock-frequency : Maximum bus clock frequency for the device
Optional (non-standard) properties:
- Nil
Example :
i2c@80004000 {
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x80004000 0x1000>;
interrupts = <0 21 0x4>;
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
clock-frequency = <400000>;
};

View File

@ -1,78 +0,0 @@
Device tree configuration for i2c-ocores
Required properties:
- compatible : "opencores,i2c-ocores"
"aeroflexgaisler,i2cmst"
"sifive,fu540-c000-i2c", "sifive,i2c0"
For Opencore based I2C IP block reimplemented in
FU540-C000 SoC.
"sifive,fu740-c000-i2c", "sifive,i2c0"
For Opencore based I2C IP block reimplemented in
FU740-C000 SoC.
Please refer to sifive-blocks-ip-versioning.txt for
additional details.
- reg : bus address start and address range size of device
- clocks : handle to the controller clock; see the note below.
Mutually exclusive with opencores,ip-clock-frequency
- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
see the note below. Mutually exclusive with clocks
- #address-cells : should be <1>
- #size-cells : should be <0>
Optional properties:
- interrupts : interrupt number.
- clock-frequency : frequency of bus clock in Hz; see the note below.
Defaults to 100 KHz when the property is not specified
- reg-shift : device register offsets are shifted by this value
- reg-io-width : io register width in bytes (1, 2 or 4)
- regstep : deprecated, use reg-shift above
Note
clock-frequency property is meant to control the bus frequency for i2c bus
drivers, but it was incorrectly used to specify i2c controller input clock
frequency. So the following rules are set to fix this situation:
- if clock-frequency is present and neither opencores,ip-clock-frequency nor
clocks are, then clock-frequency specifies i2c controller clock frequency.
This is to keep backwards compatibility with setups using old DTB. i2c bus
frequency is fixed at 100 KHz.
- if clocks is present it specifies i2c controller clock. clock-frequency
property specifies i2c bus frequency.
- if opencores,ip-clock-frequency is present it specifies i2c controller
clock frequency. clock-frequency property specifies i2c bus frequency.
Examples:
i2c0: ocores@a0000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
interrupts = <10>;
opencores,ip-clock-frequency = <20000000>;
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
dummy@60 {
compatible = "dummy";
reg = <0x60>;
};
};
or
i2c0: ocores@a0000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
interrupts = <10>;
clocks = <&osc>;
clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
dummy@60 {
compatible = "dummy";
reg = <0x60>;
};
};

View File

@ -7,6 +7,7 @@ PROPERTIES:
Value type: <string>
Definition: must be one of:
"qcom,msm8916-cci"
"qcom,msm8974-cci"
"qcom,msm8996-cci"
"qcom,sdm845-cci"
"qcom,sm8250-cci"
@ -43,9 +44,9 @@ PROPERTIES:
SUBNODES:
The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8996,
sdm845, sm8250 and sm8450), described as subdevices named "i2c-bus@0" and
"i2c-bus@1".
The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8974,
msm8996, sdm845, sm8250 and sm8450), described as subdevices named "i2c-bus@0"
and "i2c-bus@1".
PROPERTIES:

View File

@ -37,6 +37,8 @@ properties:
- rockchip,rk3308-i2c
- rockchip,rk3328-i2c
- rockchip,rk3568-i2c
- rockchip,rk3588-i2c
- rockchip,rv1126-i2c
- const: rockchip,rk3399-i2c
reg:

View File

@ -1,10 +0,0 @@
i2c Controller on ARM Versatile platform:
Required properties:
- compatible : Must be "arm,versatile-i2c";
- reg
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties:
- Child nodes conforming to i2c bus binding

View File

@ -7,17 +7,18 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: nuvoton NPCM7XX I2C Controller Device Tree Bindings
description: |
The NPCM750x includes sixteen I2C bus controllers. All Controllers support
both master and slave mode. Each controller can switch between master and slave
at run time (i.e. IPMB mode). Each controller has two 16 byte HW FIFO for TX and
RX.
I2C bus controllers of the NPCM series support both master and
slave mode. Each controller can switch between master and slave at run time
(i.e. IPMB mode). HW FIFO for TX and RX are supported.
maintainers:
- Tali Perry <tali.perry1@gmail.com>
properties:
compatible:
const: nuvoton,npcm750-i2c
enum:
- nuvoton,npcm750-i2c
- nuvoton,npcm845-i2c
reg:
maxItems: 1
@ -36,6 +37,10 @@ properties:
default: 100000
enum: [100000, 400000, 1000000]
nuvoton,sys-mgr:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of system manager register node.
required:
- compatible
- reg
@ -44,6 +49,15 @@ required:
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
- if:
properties:
compatible:
contains:
const: nuvoton,npcm845-i2c
then:
required:
- nuvoton,sys-mgr
unevaluatedProperties: false
@ -57,6 +71,7 @@ examples:
clock-frequency = <100000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
compatible = "nuvoton,npcm750-i2c";
nuvoton,sys-mgr = <&gcr>;
};
...

View File

@ -0,0 +1,113 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/opencores,i2c-ocores.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: OpenCores I2C controller
maintainers:
- Peter Korsgaard <peter@korsgaard.com>
- Andrew Lunn <andrew@lunn.ch>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- sifive,fu740-c000-i2c # Opencore based IP block FU740-C000 SoC
- sifive,fu540-c000-i2c # Opencore based IP block FU540-C000 SoC
- const: sifive,i2c0
- enum:
- opencores,i2c-ocores
- aeroflexgaisler,i2cmst
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-frequency:
description: |
clock-frequency property is meant to control the bus frequency for i2c bus
drivers, but it was incorrectly used to specify i2c controller input clock
frequency. So the following rules are set to fix this situation:
- if clock-frequency is present and neither opencores,ip-clock-frequency nor
clocks are, then clock-frequency specifies i2c controller clock frequency.
This is to keep backwards compatibility with setups using old DTB. i2c bus
frequency is fixed at 100 KHz.
- if clocks is present it specifies i2c controller clock. clock-frequency
property specifies i2c bus frequency.
- if opencores,ip-clock-frequency is present it specifies i2c controller
clock frequency. clock-frequency property specifies i2c bus frequency.
default: 100000
reg-io-width:
description: |
io register width in bytes
enum: [1, 2, 4]
reg-shift:
description: |
device register offsets are shifted by this value
default: 0
regstep:
description: |
deprecated, use reg-shift above
deprecated: true
opencores,ip-clock-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Frequency of the controller clock in Hz. Mutually exclusive with clocks.
See the note above.
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
oneOf:
- required:
- opencores,ip-clock-frequency
- required:
- clocks
unevaluatedProperties: false
examples:
- |
i2c@a0000000 {
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <10>;
opencores,ip-clock-frequency = <20000000>;
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
};
i2c@b0000000 {
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <10>;
clocks = <&osc>;
clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
};
...

View File

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/renesas,rzv2m.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/V2M I2C Bus Interface
maintainers:
- Phil Edworthy <phil.edworthy@renesas.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
items:
- enum:
- renesas,i2c-r9a09g011 # RZ/V2M
- const: renesas,rzv2m-i2c
reg:
maxItems: 1
interrupts:
items:
- description: Data transmission/reception interrupt
- description: Status interrupt
interrupt-names:
items:
- const: tia
- const: tis
clock-frequency:
default: 100000
enum: [ 100000, 400000 ]
description:
Desired I2C bus clock frequency in Hz.
clocks:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- power-domains
- resets
- '#address-cells'
- '#size-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/r9a09g011-cpg.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2c0: i2c@a4030000 {
compatible = "renesas,i2c-r9a09g011", "renesas,rzv2m-i2c";
reg = <0xa4030000 0x80>;
interrupts = <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 236 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "tia", "tis";
clocks = <&cpg CPG_MOD R9A09G011_IIC_PCLK0>;
resets = <&cpg R9A09G011_IIC_GPA_PRESETN>;
power-domains = <&cpg>;
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -0,0 +1,115 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/st,nomadik-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST Microelectronics Nomadik I2C Bindings
description: The Nomadik I2C host controller began its life in the ST
Microelectronics STn8800 SoC, and was then inherited into STn8810 and
STn8815. It was part of the prototype STn8500 which then became ST-Ericsson
DB8500 after the merge of these two companies wireless divisions.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
# Need a custom select here or 'arm,primecell' will match on lots of nodes
select:
properties:
compatible:
contains:
enum:
- st,nomadik-i2c
required:
- compatible
properties:
compatible:
oneOf:
# The variant found in STn8815
- items:
- const: st,nomadik-i2c
- const: arm,primecell
# The variant found in DB8500
- items:
- const: stericsson,db8500-i2c
- const: st,nomadik-i2c
- const: arm,primecell
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 2
clock-names:
oneOf:
# Clock name in STn8815
- items:
- const: mclk
- const: apb_pclk
# Clock name in DB8500
- items:
- const: i2cclk
- const: apb_pclk
power-domains:
maxItems: 1
resets:
maxItems: 1
clock-frequency:
minimum: 1
maximum: 400000
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/stericsson,db8500-prcc-reset.h>
#include <dt-bindings/arm/ux500_pm_domains.h>
i2c@80004000 {
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x80004000 0x1000>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>;
clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
resets = <&prcc_reset DB8500_PRCC_3 DB8500_PRCC_3_RESET_I2C0>;
};
i2c@101f8000 {
compatible = "st,nomadik-i2c", "arm,primecell";
reg = <0x101f8000 0x1000>;
interrupt-parent = <&vica>;
interrupts = <20>;
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&i2c0clk>, <&pclki2c0>;
clock-names = "mclk", "apb_pclk";
};
...

View File

@ -17,6 +17,7 @@ allOf:
contains:
enum:
- st,stm32f7-i2c
- st,stm32mp13-i2c
- st,stm32mp15-i2c
then:
properties:
@ -45,6 +46,7 @@ properties:
enum:
- st,stm32f4-i2c
- st,stm32f7-i2c
- st,stm32mp13-i2c
- st,stm32mp15-i2c
reg:

View File

@ -46,6 +46,7 @@ Supported adapters:
* Intel Emmitsburg (PCH)
* Intel Alder Lake (PCH)
* Intel Raptor Lake (PCH)
* Intel Meteor Lake (SOC)
Datasheets: Publicly available at the Intel website

View File

@ -1525,7 +1525,7 @@ F: Documentation/devicetree/bindings/arm/arm,versatile.yaml
F: Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
F: Documentation/devicetree/bindings/auxdisplay/arm,versatile-lcd.yaml
F: Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml
F: Documentation/devicetree/bindings/i2c/i2c-versatile.txt
F: Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml
F: Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
F: Documentation/devicetree/bindings/mtd/mtd-physmap.yaml
F: arch/arm/boot/dts/arm-realview-*
@ -2424,7 +2424,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
F: Documentation/devicetree/bindings/arm/ste-*
F: Documentation/devicetree/bindings/arm/ux500.yaml
F: Documentation/devicetree/bindings/arm/ux500/
F: Documentation/devicetree/bindings/i2c/i2c-nomadik.txt
F: Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
F: arch/arm/boot/dts/ste-*
F: arch/arm/mach-nomadik/
F: arch/arm/mach-ux500/
@ -15075,7 +15075,7 @@ M: Peter Korsgaard <peter@korsgaard.com>
M: Andrew Lunn <andrew@lunn.ch>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/i2c-ocores.txt
F: Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml
F: Documentation/i2c/busses/i2c-ocores.rst
F: drivers/i2c/busses/i2c-ocores.c
F: include/linux/platform_data/i2c-ocores.h

View File

@ -156,6 +156,7 @@ config I2C_I801
Emmitsburg (PCH)
Alder Lake (PCH)
Raptor Lake (PCH)
Meteor Lake (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@ -781,6 +782,17 @@ config I2C_MESON
If you say yes to this option, support will be included for the
I2C interface on the Amlogic Meson family of SoCs.
config I2C_MICROCHIP_CORE
tristate "Microchip FPGA I2C controller"
depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
depends on OF
help
If you say yes to this option, support will be included for the
I2C interface on Microchip FPGAs.
This driver can also be built as a module. If so, the module will be
called i2c-microchip-core.
config I2C_MPC
tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC
@ -838,13 +850,13 @@ config I2C_NOMADIK
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
as well as the STA2X11 PCIe I/O HUB.
config I2C_NPCM7XX
config I2C_NPCM
tristate "Nuvoton I2C Controller"
depends on ARCH_NPCM7XX || COMPILE_TEST
depends on ARCH_NPCM || COMPILE_TEST
help
If you say yes to this option, support will be included for the
Nuvoton I2C controller, which is available on the NPCM7xx BMC
controller.
Nuvoton I2C controller, which is available on the NPCM BMC
controllers.
Driver can also support slave mode (select I2C_SLAVE).
config I2C_OCORES
@ -984,6 +996,16 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
config I2C_RZV2M
tristate "Renesas RZ/V2M adapter"
depends on ARCH_RENESAS || COMPILE_TEST
help
If you say yes to this option, support will be included for the
Renesas RZ/V2M I2C interface.
This driver can also be built as a module. If so, the module
will be called i2c-rzv2m.
config I2C_S3C2410
tristate "S3C/Exynos I2C Driver"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || \

View File

@ -78,13 +78,14 @@ obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o
obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_NPCM7XX) += i2c-npcm7xx.o
obj-$(CONFIG_I2C_NPCM) += i2c-npcm7xx.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_OWL) += i2c-owl.o
@ -101,6 +102,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_RZV2M) += i2c-rzv2m.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o

View File

@ -684,9 +684,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
strlcpy(adap->name, "Broadcom STB : ", sizeof(adap->name));
if (int_name)
strlcat(adap->name, int_name, sizeof(adap->name));
strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
adap->algo = &brcmstb_i2c_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;

View File

@ -573,8 +573,13 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
/*
* Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length
* byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if
* PEC is enabled, otherwise 1.
*/
if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len;
id->curr_recv_count = id->recv_count;
@ -789,6 +794,9 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
return -EAGAIN;
if (msg->flags & I2C_M_RECV_LEN)
msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX);
return 0;
}

View File

@ -15,6 +15,7 @@
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
#define HISI_I2C_FRAME_CTRL 0x0000
#define HISI_I2C_FRAME_CTRL_SPEED_MODE GENMASK(1, 0)
@ -80,8 +81,6 @@
#define HISI_I2C_TX_F_AE_THRESH 1
#define HISI_I2C_RX_F_AF_THRESH 60
#define HZ_PER_KHZ 1000
#define NSEC_TO_CYCLES(ns, clk_rate_khz) \
DIV_ROUND_UP_ULL((clk_rate_khz) * (ns), NSEC_PER_MSEC)

View File

@ -76,6 +76,7 @@
* Alder Lake-P (PCH) 0x51a3 32 hard yes yes yes
* Alder Lake-M (PCH) 0x54a3 32 hard yes yes yes
* Raptor Lake-S (PCH) 0x7a23 32 hard yes yes yes
* Meteor Lake-P (SOC) 0x7e22 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@ -231,6 +232,7 @@
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3
#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_P_SMBUS 0x7e22
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
@ -1049,6 +1051,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, RAPTOR_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ 0, }
};

View File

@ -0,0 +1,480 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Microchip CoreI2C I2C controller driver
*
* Copyright (c) 2018-2022 Microchip Corporation. All rights reserved.
*
* Author: Daire McNamara <daire.mcnamara@microchip.com>
* Author: Conor Dooley <conor.dooley@microchip.com>
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define CORE_I2C_CTRL (0x00)
#define CTRL_CR0 BIT(0)
#define CTRL_CR1 BIT(1)
#define CTRL_AA BIT(2)
#define CTRL_SI BIT(3)
#define CTRL_STO BIT(4)
#define CTRL_STA BIT(5)
#define CTRL_ENS1 BIT(6)
#define CTRL_CR2 BIT(7)
#define STATUS_BUS_ERROR (0x00)
#define STATUS_M_START_SENT (0x08)
#define STATUS_M_REPEATED_START_SENT (0x10)
#define STATUS_M_SLAW_ACK (0x18)
#define STATUS_M_SLAW_NACK (0x20)
#define STATUS_M_TX_DATA_ACK (0x28)
#define STATUS_M_TX_DATA_NACK (0x30)
#define STATUS_M_ARB_LOST (0x38)
#define STATUS_M_SLAR_ACK (0x40)
#define STATUS_M_SLAR_NACK (0x48)
#define STATUS_M_RX_DATA_ACKED (0x50)
#define STATUS_M_RX_DATA_NACKED (0x58)
#define STATUS_S_SLAW_ACKED (0x60)
#define STATUS_S_ARB_LOST_SLAW_ACKED (0x68)
#define STATUS_S_GENERAL_CALL_ACKED (0x70)
#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED (0x78)
#define STATUS_S_RX_DATA_ACKED (0x80)
#define STATUS_S_RX_DATA_NACKED (0x88)
#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED (0x90)
#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED (0x98)
#define STATUS_S_RX_STOP (0xA0)
#define STATUS_S_SLAR_ACKED (0xA8)
#define STATUS_S_ARB_LOST_SLAR_ACKED (0xB0)
#define STATUS_S_TX_DATA_ACK (0xB8)
#define STATUS_S_TX_DATA_NACK (0xC0)
#define STATUS_LAST_DATA_ACK (0xC8)
#define STATUS_M_SMB_MASTER_RESET (0xD0)
#define STATUS_S_SCL_LOW_TIMEOUT (0xD8) /* 25 ms */
#define STATUS_NO_STATE_INFO (0xF8)
#define CORE_I2C_STATUS (0x04)
#define CORE_I2C_DATA (0x08)
#define WRITE_BIT (0x0)
#define READ_BIT (0x1)
#define SLAVE_ADDR_SHIFT (1)
#define CORE_I2C_SLAVE0_ADDR (0x0c)
#define GENERAL_CALL_BIT (0x0)
#define CORE_I2C_SMBUS (0x10)
#define SMBALERT_INT_ENB (0x0)
#define SMBSUS_INT_ENB (0x1)
#define SMBUS_ENB (0x2)
#define SMBALERT_NI_STATUS (0x3)
#define SMBALERT_NO_CTRL (0x4)
#define SMBSUS_NI_STATUS (0x5)
#define SMBSUS_NO_CTRL (0x6)
#define SMBUS_RESET (0x7)
#define CORE_I2C_FREQ (0x14)
#define CORE_I2C_GLITCHREG (0x18)
#define CORE_I2C_SLAVE1_ADDR (0x1c)
#define PCLK_DIV_960 (CTRL_CR2)
#define PCLK_DIV_256 (0)
#define PCLK_DIV_224 (CTRL_CR0)
#define PCLK_DIV_192 (CTRL_CR1)
#define PCLK_DIV_160 (CTRL_CR0 | CTRL_CR1)
#define PCLK_DIV_120 (CTRL_CR0 | CTRL_CR2)
#define PCLK_DIV_60 (CTRL_CR1 | CTRL_CR2)
#define BCLK_DIV_8 (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)
#define CLK_MASK (CTRL_CR0 | CTRL_CR1 | CTRL_CR2)
/**
* struct mchp_corei2c_dev - Microchip CoreI2C device private data
*
* @base: pointer to register struct
* @dev: device reference
* @i2c_clk: clock reference for i2c input clock
* @buf: pointer to msg buffer for easier use
* @msg_complete: xfer completion object
* @adapter: core i2c abstraction
* @msg_err: error code for completed message
* @bus_clk_rate: current i2c bus clock rate
* @isr_status: cached copy of local ISR status
* @msg_len: number of bytes transferred in msg
* @addr: address of the current slave
*/
struct mchp_corei2c_dev {
void __iomem *base;
struct device *dev;
struct clk *i2c_clk;
u8 *buf;
struct completion msg_complete;
struct i2c_adapter adapter;
int msg_err;
u32 bus_clk_rate;
u32 isr_status;
u16 msg_len;
u8 addr;
};
static void mchp_corei2c_core_disable(struct mchp_corei2c_dev *idev)
{
u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl &= ~CTRL_ENS1;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
}
static void mchp_corei2c_core_enable(struct mchp_corei2c_dev *idev)
{
u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl |= CTRL_ENS1;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
}
static void mchp_corei2c_reset(struct mchp_corei2c_dev *idev)
{
mchp_corei2c_core_disable(idev);
mchp_corei2c_core_enable(idev);
}
static inline void mchp_corei2c_stop(struct mchp_corei2c_dev *idev)
{
u8 ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl |= CTRL_STO;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
}
static inline int mchp_corei2c_set_divisor(u32 rate,
struct mchp_corei2c_dev *idev)
{
u8 clkval, ctrl;
if (rate >= 960)
clkval = PCLK_DIV_960;
else if (rate >= 256)
clkval = PCLK_DIV_256;
else if (rate >= 224)
clkval = PCLK_DIV_224;
else if (rate >= 192)
clkval = PCLK_DIV_192;
else if (rate >= 160)
clkval = PCLK_DIV_160;
else if (rate >= 120)
clkval = PCLK_DIV_120;
else if (rate >= 60)
clkval = PCLK_DIV_60;
else if (rate >= 8)
clkval = BCLK_DIV_8;
else
return -EINVAL;
ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl &= ~CLK_MASK;
ctrl |= clkval;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
ctrl = readb(idev->base + CORE_I2C_CTRL);
if ((ctrl & CLK_MASK) != clkval)
return -EIO;
return 0;
}
static int mchp_corei2c_init(struct mchp_corei2c_dev *idev)
{
u32 clk_rate = clk_get_rate(idev->i2c_clk);
u32 divisor = clk_rate / idev->bus_clk_rate;
int ret;
ret = mchp_corei2c_set_divisor(divisor, idev);
if (ret)
return ret;
mchp_corei2c_reset(idev);
return 0;
}
static void mchp_corei2c_empty_rx(struct mchp_corei2c_dev *idev)
{
u8 ctrl;
if (idev->msg_len > 0) {
*idev->buf++ = readb(idev->base + CORE_I2C_DATA);
idev->msg_len--;
}
if (idev->msg_len == 0) {
ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl &= ~CTRL_AA;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
}
}
static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev)
{
if (idev->msg_len > 0)
writeb(*idev->buf++, idev->base + CORE_I2C_DATA);
idev->msg_len--;
return 0;
}
static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
{
u32 status = idev->isr_status;
u8 ctrl;
bool last_byte = false, finished = false;
if (!idev->buf)
return IRQ_NONE;
switch (status) {
case STATUS_M_START_SENT:
case STATUS_M_REPEATED_START_SENT:
ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl &= ~CTRL_STA;
writeb(idev->addr, idev->base + CORE_I2C_DATA);
writeb(ctrl, idev->base + CORE_I2C_CTRL);
if (idev->msg_len == 0)
finished = true;
break;
case STATUS_M_ARB_LOST:
idev->msg_err = -EAGAIN;
finished = true;
break;
case STATUS_M_SLAW_ACK:
case STATUS_M_TX_DATA_ACK:
if (idev->msg_len > 0)
mchp_corei2c_fill_tx(idev);
else
last_byte = true;
break;
case STATUS_M_TX_DATA_NACK:
case STATUS_M_SLAR_NACK:
case STATUS_M_SLAW_NACK:
idev->msg_err = -ENXIO;
last_byte = true;
break;
case STATUS_M_SLAR_ACK:
ctrl = readb(idev->base + CORE_I2C_CTRL);
if (idev->msg_len == 1u) {
ctrl &= ~CTRL_AA;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
} else {
ctrl |= CTRL_AA;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
}
if (idev->msg_len < 1u)
last_byte = true;
break;
case STATUS_M_RX_DATA_ACKED:
mchp_corei2c_empty_rx(idev);
break;
case STATUS_M_RX_DATA_NACKED:
mchp_corei2c_empty_rx(idev);
if (idev->msg_len == 0)
last_byte = true;
break;
default:
break;
}
/* On the last byte to be transmitted, send STOP */
if (last_byte)
mchp_corei2c_stop(idev);
if (last_byte || finished)
complete(&idev->msg_complete);
return IRQ_HANDLED;
}
static irqreturn_t mchp_corei2c_isr(int irq, void *_dev)
{
struct mchp_corei2c_dev *idev = _dev;
irqreturn_t ret = IRQ_NONE;
u8 ctrl;
ctrl = readb(idev->base + CORE_I2C_CTRL);
if (ctrl & CTRL_SI) {
idev->isr_status = readb(idev->base + CORE_I2C_STATUS);
ret = mchp_corei2c_handle_isr(idev);
}
ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl &= ~CTRL_SI;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
return ret;
}
static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,
struct i2c_msg *msg)
{
u8 ctrl;
unsigned long time_left;
idev->addr = i2c_8bit_addr_from_msg(msg);
idev->msg_len = msg->len;
idev->buf = msg->buf;
idev->msg_err = 0;
reinit_completion(&idev->msg_complete);
mchp_corei2c_core_enable(idev);
ctrl = readb(idev->base + CORE_I2C_CTRL);
ctrl |= CTRL_STA;
writeb(ctrl, idev->base + CORE_I2C_CTRL);
time_left = wait_for_completion_timeout(&idev->msg_complete,
idev->adapter.timeout);
if (!time_left)
return -ETIMEDOUT;
return idev->msg_err;
}
static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);
int i, ret;
for (i = 0; i < num; i++) {
ret = mchp_corei2c_xfer_msg(idev, msgs++);
if (ret)
return ret;
}
return num;
}
static u32 mchp_corei2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm mchp_corei2c_algo = {
.master_xfer = mchp_corei2c_xfer,
.functionality = mchp_corei2c_func,
};
static int mchp_corei2c_probe(struct platform_device *pdev)
{
struct mchp_corei2c_dev *idev;
struct resource *res;
int irq, ret;
idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
if (!idev)
return -ENOMEM;
idev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(idev->base))
return PTR_ERR(idev->base);
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return dev_err_probe(&pdev->dev, -ENXIO,
"invalid IRQ %d for I2C controller\n", irq);
idev->i2c_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(idev->i2c_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(idev->i2c_clk),
"missing clock\n");
idev->dev = &pdev->dev;
init_completion(&idev->msg_complete);
ret = device_property_read_u32(idev->dev, "clock-frequency",
&idev->bus_clk_rate);
if (ret || !idev->bus_clk_rate) {
dev_info(&pdev->dev, "default to 100kHz\n");
idev->bus_clk_rate = 100000;
}
if (idev->bus_clk_rate > 400000)
return dev_err_probe(&pdev->dev, -EINVAL,
"clock-frequency too high: %d\n",
idev->bus_clk_rate);
/*
* This driver supports both the hard peripherals & soft FPGA cores.
* The hard peripherals do not have shared IRQs, but we don't have
* control over what way the interrupts are wired for the soft cores.
*/
ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED,
pdev->name, idev);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to claim irq %d\n", irq);
ret = clk_prepare_enable(idev->i2c_clk);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to enable clock\n");
ret = mchp_corei2c_init(idev);
if (ret) {
clk_disable_unprepare(idev->i2c_clk);
return dev_err_probe(&pdev->dev, ret, "failed to program clock divider\n");
}
i2c_set_adapdata(&idev->adapter, idev);
snprintf(idev->adapter.name, sizeof(idev->adapter.name),
"Microchip I2C hw bus at %08lx", (unsigned long)res->start);
idev->adapter.owner = THIS_MODULE;
idev->adapter.algo = &mchp_corei2c_algo;
idev->adapter.dev.parent = &pdev->dev;
idev->adapter.dev.of_node = pdev->dev.of_node;
idev->adapter.timeout = HZ;
platform_set_drvdata(pdev, idev);
ret = i2c_add_adapter(&idev->adapter);
if (ret) {
clk_disable_unprepare(idev->i2c_clk);
return ret;
}
dev_info(&pdev->dev, "registered CoreI2C bus driver\n");
return 0;
}
static int mchp_corei2c_remove(struct platform_device *pdev)
{
struct mchp_corei2c_dev *idev = platform_get_drvdata(pdev);
clk_disable_unprepare(idev->i2c_clk);
i2c_del_adapter(&idev->adapter);
return 0;
}
static const struct of_device_id mchp_corei2c_of_match[] = {
{ .compatible = "microchip,mpfs-i2c" },
{ .compatible = "microchip,corei2c-rtl-v7" },
{},
};
MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match);
static struct platform_driver mchp_corei2c_driver = {
.probe = mchp_corei2c_probe,
.remove = mchp_corei2c_remove,
.driver = {
.name = "microchip-corei2c",
.of_match_table = mchp_corei2c_of_match,
},
};
module_platform_driver(mchp_corei2c_driver);
MODULE_DESCRIPTION("Microchip CoreI2C bus driver");
MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
MODULE_LICENSE("GPL");

View File

@ -560,6 +560,10 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
if (err)
goto mlxcpld_i2_probe_failed;
/* Notify caller when adapter is added. */
if (pdata && pdata->completion_notify)
pdata->completion_notify(pdata->handle, mlxcpld_i2c_adapter.nr);
return 0;
mlxcpld_i2_probe_failed:

View File

@ -150,6 +150,7 @@ struct mv64xxx_i2c_data {
/* Clk div is 2 to the power n, not 2 to the power n + 1 */
bool clk_n_base_0;
struct i2c_bus_recovery_info rinfo;
bool atomic;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@ -179,7 +180,10 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
u32 dir = 0;
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
MV64XXX_I2C_REG_CONTROL_TWSIEN;
if (!drv_data->atomic)
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN;
if (msg->flags & I2C_M_RD)
dir = 1;
@ -409,7 +413,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
drv_data->msg->buf[drv_data->byte_posn++] =
readl(drv_data->reg_base + drv_data->reg_offsets.data);
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
if (!drv_data->atomic)
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
@ -427,7 +432,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->rc = -EIO;
fallthrough;
case MV64XXX_I2C_ACTION_SEND_STOP:
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
if (!drv_data->atomic)
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
@ -575,6 +581,17 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
spin_unlock_irqrestore(&drv_data->lock, flags);
}
static void mv64xxx_i2c_wait_polling(struct mv64xxx_i2c_data *drv_data)
{
ktime_t timeout = ktime_add_ms(ktime_get(), drv_data->adapter.timeout);
while (READ_ONCE(drv_data->block) &&
ktime_compare(ktime_get(), timeout) < 0) {
udelay(5);
mv64xxx_i2c_intr(0, drv_data);
}
}
static int
mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
int is_last)
@ -590,7 +607,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
mv64xxx_i2c_send_start(drv_data);
spin_unlock_irqrestore(&drv_data->lock, flags);
mv64xxx_i2c_wait_for_completion(drv_data);
if (!drv_data->atomic)
mv64xxx_i2c_wait_for_completion(drv_data);
else
mv64xxx_i2c_wait_polling(drv_data);
return drv_data->rc;
}
@ -717,7 +738,7 @@ mv64xxx_i2c_functionality(struct i2c_adapter *adap)
}
static int
mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
int rc, ret = num;
@ -730,7 +751,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
drv_data->msgs = msgs;
drv_data->num_msgs = num;
if (mv64xxx_i2c_can_offload(drv_data))
if (mv64xxx_i2c_can_offload(drv_data) && !drv_data->atomic)
rc = mv64xxx_i2c_offload_xfer(drv_data);
else
rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
@ -747,8 +768,27 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return ret;
}
static int
mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
drv_data->atomic = 0;
return mv64xxx_i2c_xfer_core(adap, msgs, num);
}
static int mv64xxx_i2c_xfer_atomic(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
drv_data->atomic = 1;
return mv64xxx_i2c_xfer_core(adap, msgs, num);
}
static const struct i2c_algorithm mv64xxx_i2c_algo = {
.master_xfer = mv64xxx_i2c_xfer,
.master_xfer_atomic = mv64xxx_i2c_xfer_atomic,
.functionality = mv64xxx_i2c_functionality,
};
@ -1047,14 +1087,6 @@ mv64xxx_i2c_remove(struct platform_device *pd)
return 0;
}
static void
mv64xxx_i2c_shutdown(struct platform_device *pd)
{
pm_runtime_disable(&pd->dev);
if (!pm_runtime_status_suspended(&pd->dev))
mv64xxx_i2c_runtime_suspend(&pd->dev);
}
static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend,
mv64xxx_i2c_runtime_resume, NULL)
@ -1065,7 +1097,6 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove = mv64xxx_i2c_remove,
.shutdown = mv64xxx_i2c_shutdown,
.driver = {
.name = MV64XXX_I2C_CTLR_NAME,
.pm = &mv64xxx_i2c_pm_ops,

View File

@ -799,7 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
i2c->dev_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(i2c->regs))

View File

@ -17,6 +17,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@ -91,7 +92,6 @@ enum i2c_addr {
/* init register and default value required to enable module */
#define NPCM_I2CSEGCTL 0xE4
#define NPCM_I2CSEGCTL_INIT_VAL 0x0333F000
/* Common regs */
#define NPCM_I2CSDA 0x00
@ -123,11 +123,11 @@ enum i2c_addr {
* Since the addr regs are sprinkled all over the address space,
* use this array to get the address or each register.
*/
#define I2C_NUM_OWN_ADDR 10
#define I2C_NUM_OWN_ADDR 2
#define I2C_NUM_OWN_ADDR_SUPPORTED 2
static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
NPCM_I2CADDR1, NPCM_I2CADDR2, NPCM_I2CADDR3, NPCM_I2CADDR4,
NPCM_I2CADDR5, NPCM_I2CADDR6, NPCM_I2CADDR7, NPCM_I2CADDR8,
NPCM_I2CADDR9, NPCM_I2CADDR10,
NPCM_I2CADDR1, NPCM_I2CADDR2,
};
#endif
@ -226,8 +226,7 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
#define NPCM_I2CFIF_CTS_CLR_FIFO BIT(6)
#define NPCM_I2CFIF_CTS_SLVRSTR BIT(7)
/* NPCM_I2CTXF_CTL reg fields */
#define NPCM_I2CTXF_CTL_TX_THR GENMASK(4, 0)
/* NPCM_I2CTXF_CTL reg field */
#define NPCM_I2CTXF_CTL_THR_TXIE BIT(6)
/* NPCM_I2CT_OUT reg fields */
@ -236,22 +235,18 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
#define NPCM_I2CT_OUT_T_OUTST BIT(7)
/* NPCM_I2CTXF_STS reg fields */
#define NPCM_I2CTXF_STS_TX_BYTES GENMASK(4, 0)
#define NPCM_I2CTXF_STS_TX_THST BIT(6)
/* NPCM_I2CRXF_STS reg fields */
#define NPCM_I2CRXF_STS_RX_BYTES GENMASK(4, 0)
#define NPCM_I2CRXF_STS_RX_THST BIT(6)
/* NPCM_I2CFIF_CTL reg fields */
#define NPCM_I2CFIF_CTL_FIFO_EN BIT(4)
/* NPCM_I2CRXF_CTL reg fields */
#define NPCM_I2CRXF_CTL_RX_THR GENMASK(4, 0)
#define NPCM_I2CRXF_CTL_LAST_PEC BIT(5)
#define NPCM_I2CRXF_CTL_THR_RXIE BIT(6)
#define I2C_HW_FIFO_SIZE 16
#define MAX_I2C_HW_FIFO_SIZE 32
/* I2C_VER reg fields */
#define I2C_VER_VERSION GENMASK(6, 0)
@ -268,11 +263,36 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
#define I2C_FREQ_MIN_HZ 10000
#define I2C_FREQ_MAX_HZ I2C_MAX_FAST_MODE_PLUS_FREQ
struct npcm_i2c_data {
u8 fifo_size;
u32 segctl_init_val;
u8 txf_sts_tx_bytes;
u8 rxf_sts_rx_bytes;
u8 rxf_ctl_last_pec;
};
static const struct npcm_i2c_data npxm7xx_i2c_data = {
.fifo_size = 16,
.segctl_init_val = 0x0333F000,
.txf_sts_tx_bytes = GENMASK(4, 0),
.rxf_sts_rx_bytes = GENMASK(4, 0),
.rxf_ctl_last_pec = BIT(5),
};
static const struct npcm_i2c_data npxm8xx_i2c_data = {
.fifo_size = 32,
.segctl_init_val = 0x9333F000,
.txf_sts_tx_bytes = GENMASK(5, 0),
.rxf_sts_rx_bytes = GENMASK(5, 0),
.rxf_ctl_last_pec = BIT(7),
};
/* Status of one I2C module */
struct npcm_i2c {
struct i2c_adapter adap;
struct device *dev;
unsigned char __iomem *reg;
const struct npcm_i2c_data *data;
spinlock_t lock; /* IRQ synchronization */
struct completion cmd_complete;
int cmd_err;
@ -305,8 +325,8 @@ struct npcm_i2c {
int slv_rd_ind;
int slv_wr_size;
int slv_wr_ind;
u8 slv_rd_buf[I2C_HW_FIFO_SIZE];
u8 slv_wr_buf[I2C_HW_FIFO_SIZE];
u8 slv_rd_buf[MAX_I2C_HW_FIFO_SIZE];
u8 slv_wr_buf[MAX_I2C_HW_FIFO_SIZE];
#endif
struct dentry *debugfs; /* debugfs device directory */
u64 ber_cnt;
@ -392,14 +412,10 @@ static void npcm_i2c_disable(struct npcm_i2c *bus)
#if IS_ENABLED(CONFIG_I2C_SLAVE)
int i;
/* select bank 0 for I2C addresses */
npcm_i2c_select_bank(bus, I2C_BANK_0);
/* Slave addresses removal */
for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++)
for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++)
iowrite8(0, bus->reg + npcm_i2caddr[i]);
npcm_i2c_select_bank(bus, I2C_BANK_1);
#endif
/* Disable module */
i2cctl2 = ioread8(bus->reg + NPCM_I2CCTL2);
@ -443,7 +459,7 @@ static inline bool npcm_i2c_tx_fifo_empty(struct npcm_i2c *bus)
tx_fifo_sts = ioread8(bus->reg + NPCM_I2CTXF_STS);
/* check if TX FIFO is not empty */
if ((tx_fifo_sts & NPCM_I2CTXF_STS_TX_BYTES) == 0)
if ((tx_fifo_sts & bus->data->txf_sts_tx_bytes) == 0)
return false;
/* check if TX FIFO status bit is set: */
@ -456,7 +472,7 @@ static inline bool npcm_i2c_rx_fifo_full(struct npcm_i2c *bus)
rx_fifo_sts = ioread8(bus->reg + NPCM_I2CRXF_STS);
/* check if RX FIFO is not empty: */
if ((rx_fifo_sts & NPCM_I2CRXF_STS_RX_BYTES) == 0)
if ((rx_fifo_sts & bus->data->rxf_sts_rx_bytes) == 0)
return false;
/* check if rx fifo full status is set: */
@ -604,8 +620,7 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type,
i2cctl1 &= ~NPCM_I2CCTL1_GCMEN;
iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1);
return 0;
}
if (addr_type == I2C_ARP_ADDR) {
} else if (addr_type == I2C_ARP_ADDR) {
i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3);
if (enable)
i2cctl3 |= I2CCTL3_ARPMEN;
@ -614,16 +629,16 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type,
iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3);
return 0;
}
if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
dev_err(bus->dev, "try to enable more than 2 SA not supported\n");
if (addr_type >= I2C_ARP_ADDR)
return -EFAULT;
/* select bank 0 for address 3 to 10 */
if (addr_type > I2C_SLAVE_ADDR2)
npcm_i2c_select_bank(bus, I2C_BANK_0);
/* Set and enable the address */
iowrite8(sa_reg, bus->reg + npcm_i2caddr[addr_type]);
npcm_i2c_slave_int_enable(bus, enable);
if (addr_type > I2C_SLAVE_ADDR2)
npcm_i2c_select_bank(bus, I2C_BANK_1);
return 0;
}
#endif
@ -665,7 +680,7 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
}
#endif
/* clear status bits for spurious interrupts */
/* Clear status bits for spurious interrupts */
npcm_i2c_clear_master_status(bus);
bus->state = I2C_IDLE;
@ -744,11 +759,11 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
static u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus)
{
if (bus->operation == I2C_WRITE_OPER)
return FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES,
ioread8(bus->reg + NPCM_I2CTXF_STS));
return (bus->data->txf_sts_tx_bytes &
ioread8(bus->reg + NPCM_I2CTXF_STS));
if (bus->operation == I2C_READ_OPER)
return FIELD_GET(NPCM_I2CRXF_STS_RX_BYTES,
ioread8(bus->reg + NPCM_I2CRXF_STS));
return (bus->data->rxf_sts_rx_bytes &
ioread8(bus->reg + NPCM_I2CRXF_STS));
return 0;
}
@ -760,13 +775,13 @@ static void npcm_i2c_write_to_fifo_master(struct npcm_i2c *bus, u16 max_bytes)
* Fill the FIFO, while the FIFO is not full and there are more bytes
* to write
*/
size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus);
size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus);
while (max_bytes-- && size_free_fifo) {
if (bus->wr_ind < bus->wr_size)
npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]);
else
npcm_i2c_wr_byte(bus, 0xFF);
size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus);
size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus);
}
}
@ -787,11 +802,11 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
/* configure RX FIFO */
if (nread > 0) {
rxf_ctl = min_t(int, nread, I2C_HW_FIFO_SIZE);
rxf_ctl = min_t(int, nread, bus->data->fifo_size);
/* set LAST bit. if LAST is set next FIFO packet is nacked */
if (nread <= I2C_HW_FIFO_SIZE)
rxf_ctl |= NPCM_I2CRXF_CTL_LAST_PEC;
if (nread <= bus->data->fifo_size)
rxf_ctl |= bus->data->rxf_ctl_last_pec;
/*
* if we are about to read the first byte in blk rd mode,
@ -809,9 +824,9 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
/* configure TX FIFO */
if (nwrite > 0) {
if (nwrite > I2C_HW_FIFO_SIZE)
if (nwrite > bus->data->fifo_size)
/* data to send is more then FIFO size. */
iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CTXF_CTL);
iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CTXF_CTL);
else
iowrite8(nwrite, bus->reg + NPCM_I2CTXF_CTL);
@ -846,15 +861,11 @@ static u8 npcm_i2c_get_slave_addr(struct npcm_i2c *bus, enum i2c_addr addr_type)
{
u8 slave_add;
/* select bank 0 for address 3 to 10 */
if (addr_type > I2C_SLAVE_ADDR2)
npcm_i2c_select_bank(bus, I2C_BANK_0);
if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
dev_err(bus->dev, "get slave: try to use more than 2 SA not supported\n");
slave_add = ioread8(bus->reg + npcm_i2caddr[(int)addr_type]);
if (addr_type > I2C_SLAVE_ADDR2)
npcm_i2c_select_bank(bus, I2C_BANK_1);
return slave_add;
}
@ -864,12 +875,12 @@ static int npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add)
/* Set the enable bit */
slave_add |= 0x80;
npcm_i2c_select_bank(bus, I2C_BANK_0);
for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++) {
for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) {
if (ioread8(bus->reg + npcm_i2caddr[i]) == slave_add)
iowrite8(0, bus->reg + npcm_i2caddr[i]);
}
npcm_i2c_select_bank(bus, I2C_BANK_1);
return 0;
}
@ -882,13 +893,13 @@ static void npcm_i2c_write_fifo_slave(struct npcm_i2c *bus, u16 max_bytes)
npcm_i2c_clear_fifo_int(bus);
npcm_i2c_clear_tx_fifo(bus);
iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
while (max_bytes-- && I2C_HW_FIFO_SIZE != npcm_i2c_fifo_usage(bus)) {
while (max_bytes-- && bus->data->fifo_size != npcm_i2c_fifo_usage(bus)) {
if (bus->slv_wr_size <= 0)
break;
bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE;
bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
npcm_i2c_wr_byte(bus, bus->slv_wr_buf[bus->slv_wr_ind]);
bus->slv_wr_ind++;
bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE;
bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
bus->slv_wr_size--;
}
}
@ -903,7 +914,7 @@ static void npcm_i2c_read_fifo_slave(struct npcm_i2c *bus, u8 bytes_in_fifo)
while (bytes_in_fifo--) {
data = npcm_i2c_rd_byte(bus);
bus->slv_rd_ind = bus->slv_rd_ind % I2C_HW_FIFO_SIZE;
bus->slv_rd_ind = bus->slv_rd_ind & (bus->data->fifo_size - 1);
bus->slv_rd_buf[bus->slv_rd_ind] = data;
bus->slv_rd_ind++;
@ -921,16 +932,20 @@ static int npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus)
int ret = bus->slv_wr_ind;
/* fill a cyclic buffer */
for (i = 0; i < I2C_HW_FIFO_SIZE; i++) {
if (bus->slv_wr_size >= I2C_HW_FIFO_SIZE)
for (i = 0; i < bus->data->fifo_size; i++) {
if (bus->slv_wr_size >= bus->data->fifo_size)
break;
i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
ind = (bus->slv_wr_ind + bus->slv_wr_size) % I2C_HW_FIFO_SIZE;
if (bus->state == I2C_SLAVE_MATCH) {
i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
bus->state = I2C_OPER_STARTED;
} else {
i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
}
ind = (bus->slv_wr_ind + bus->slv_wr_size) & (bus->data->fifo_size - 1);
bus->slv_wr_buf[ind] = value;
bus->slv_wr_size++;
i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
}
return I2C_HW_FIFO_SIZE - ret;
return bus->data->fifo_size - ret;
}
static void npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus)
@ -965,7 +980,7 @@ static void npcm_i2c_slave_receive(struct npcm_i2c *bus, u16 nread,
bus->slv_rd_ind = 0;
iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL);
npcm_i2c_clear_tx_fifo(bus);
npcm_i2c_clear_rx_fifo(bus);
}
@ -976,7 +991,6 @@ static void npcm_i2c_slave_xmit(struct npcm_i2c *bus, u16 nwrite,
if (nwrite == 0)
return;
bus->state = I2C_OPER_STARTED;
bus->operation = I2C_WRITE_OPER;
/* get the next buffer */
@ -999,12 +1013,12 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
{
int left_in_fifo;
left_in_fifo = FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES,
ioread8(bus->reg + NPCM_I2CTXF_STS));
left_in_fifo = bus->data->txf_sts_tx_bytes &
ioread8(bus->reg + NPCM_I2CTXF_STS);
/* fifo already full: */
if (left_in_fifo >= I2C_HW_FIFO_SIZE ||
bus->slv_wr_size >= I2C_HW_FIFO_SIZE)
if (left_in_fifo >= bus->data->fifo_size ||
bus->slv_wr_size >= bus->data->fifo_size)
return;
/* update the wr fifo index back to the untransmitted bytes: */
@ -1012,7 +1026,7 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
bus->slv_wr_size = bus->slv_wr_size + left_in_fifo;
if (bus->slv_wr_ind < 0)
bus->slv_wr_ind += I2C_HW_FIFO_SIZE;
bus->slv_wr_ind += bus->data->fifo_size;
}
static void npcm_i2c_slave_rd_wr(struct npcm_i2c *bus)
@ -1158,7 +1172,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
npcm_i2c_clear_rx_fifo(bus);
npcm_i2c_clear_tx_fifo(bus);
iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL);
if (NPCM_I2CST_XMIT & i2cst) {
bus->operation = I2C_WRITE_OPER;
} else {
@ -1238,7 +1252,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
} /* SDAST */
/*
* if irq is not one of the above, make sure EOB is disabled and all
* If irq is not one of the above, make sure EOB is disabled and all
* status bits are cleared.
*/
if (ret == IRQ_NONE) {
@ -1319,8 +1333,8 @@ static void npcm_i2c_master_fifo_read(struct npcm_i2c *bus)
* read == FIFO Size + C (where C < FIFO Size)then first read C bytes
* and in the next int we read rest of the data.
*/
if (rcount < (2 * I2C_HW_FIFO_SIZE) && rcount > I2C_HW_FIFO_SIZE)
fifo_bytes = rcount - I2C_HW_FIFO_SIZE;
if (rcount < (2 * bus->data->fifo_size) && rcount > bus->data->fifo_size)
fifo_bytes = rcount - bus->data->fifo_size;
if (rcount <= fifo_bytes) {
/* last bytes are about to be read - end of tx */
@ -1492,7 +1506,7 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
npcm_i2c_clear_master_status(bus);
readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
!(val & NPCM_I2CCST_BUSY), 10, 200);
/* verify no status bits are still set after bus is released */
/* Verify no status bits are still set after bus is released */
npcm_i2c_clear_master_status(bus);
}
bus->state = I2C_IDLE;
@ -1960,7 +1974,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
npcm_i2c_reset(bus);
/* check HW is OK: SDA and SCL should be high at this point. */
/* Check HW is OK: SDA and SCL should be high at this point. */
if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) {
dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num);
dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap),
@ -2020,7 +2034,7 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
#endif
/* clear status bits for spurious interrupts */
/* Clear status bits for spurious interrupts */
npcm_i2c_clear_master_status(bus);
return IRQ_HANDLED;
@ -2199,10 +2213,10 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
* It cannot be cleared without resetting the module.
*/
else if (bus->cmd_err &&
(NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
(bus->data->rxf_ctl_last_pec & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
npcm_i2c_reset(bus);
/* after any xfer, successful or not, stall and EOB must be disabled */
/* After any xfer, successful or not, stall and EOB must be disabled */
npcm_i2c_stall_after_start(bus, false);
npcm_i2c_eob_int(bus, false);
@ -2268,6 +2282,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
static struct regmap *gcr_regmap;
struct device *dev = &pdev->dev;
struct i2c_adapter *adap;
struct npcm_i2c *bus;
struct clk *i2c_clk;
@ -2280,6 +2295,12 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
bus->dev = &pdev->dev;
bus->data = of_device_get_match_data(dev);
if (!bus->data) {
dev_err(dev, "OF data missing\n");
return -EINVAL;
}
bus->num = of_alias_get_id(pdev->dev.of_node, "i2c");
/* core clk must be acquired to calculate module timing settings */
i2c_clk = devm_clk_get(&pdev->dev, NULL);
@ -2293,7 +2314,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
if (IS_ERR(gcr_regmap))
return PTR_ERR(gcr_regmap);
regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL);
regmap_write(gcr_regmap, NPCM_I2CSEGCTL, bus->data->segctl_init_val);
bus->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bus->reg))
@ -2355,7 +2376,8 @@ static int npcm_i2c_remove_bus(struct platform_device *pdev)
}
static const struct of_device_id npcm_i2c_bus_of_table[] = {
{ .compatible = "nuvoton,npcm750-i2c", },
{ .compatible = "nuvoton,npcm750-i2c", .data = &npxm7xx_i2c_data },
{ .compatible = "nuvoton,npcm845-i2c", .data = &npxm8xx_i2c_data },
{}
};
MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table);

View File

@ -541,6 +541,7 @@ static int cci_probe(struct platform_device *pdev)
return -ENOENT;
for_each_available_child_of_node(dev->of_node, child) {
struct cci_master *master;
u32 idx;
ret = of_property_read_u32(child, "reg", &idx);
@ -555,27 +556,27 @@ static int cci_probe(struct platform_device *pdev)
continue;
}
cci->master[idx].adap.quirks = &cci->data->quirks;
cci->master[idx].adap.algo = &cci_algo;
cci->master[idx].adap.dev.parent = dev;
cci->master[idx].adap.dev.of_node = of_node_get(child);
cci->master[idx].master = idx;
cci->master[idx].cci = cci;
master = &cci->master[idx];
master->adap.quirks = &cci->data->quirks;
master->adap.algo = &cci_algo;
master->adap.dev.parent = dev;
master->adap.dev.of_node = of_node_get(child);
master->master = idx;
master->cci = cci;
i2c_set_adapdata(&cci->master[idx].adap, &cci->master[idx]);
snprintf(cci->master[idx].adap.name,
sizeof(cci->master[idx].adap.name), "Qualcomm-CCI");
i2c_set_adapdata(&master->adap, master);
snprintf(master->adap.name, sizeof(master->adap.name), "Qualcomm-CCI");
cci->master[idx].mode = I2C_MODE_STANDARD;
master->mode = I2C_MODE_STANDARD;
ret = of_property_read_u32(child, "clock-frequency", &val);
if (!ret) {
if (val == I2C_MAX_FAST_MODE_FREQ)
cci->master[idx].mode = I2C_MODE_FAST;
master->mode = I2C_MODE_FAST;
else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ)
cci->master[idx].mode = I2C_MODE_FAST_PLUS;
master->mode = I2C_MODE_FAST_PLUS;
}
init_completion(&cci->master[idx].irq_complete);
init_completion(&master->irq_complete);
}
/* Memory */
@ -725,6 +726,40 @@ static const struct cci_data cci_v1_data = {
},
};
static const struct cci_data cci_v1_5_data = {
.num_masters = 2,
.queue_size = { 64, 16 },
.quirks = {
.max_write_len = 10,
.max_read_len = 12,
},
.cci_clk_rate = 19200000,
.params[I2C_MODE_STANDARD] = {
.thigh = 78,
.tlow = 114,
.tsu_sto = 28,
.tsu_sta = 28,
.thd_dat = 10,
.thd_sta = 77,
.tbuf = 118,
.scl_stretch_en = 0,
.trdhld = 6,
.tsp = 1
},
.params[I2C_MODE_FAST] = {
.thigh = 20,
.tlow = 28,
.tsu_sto = 21,
.tsu_sta = 21,
.thd_dat = 13,
.thd_sta = 18,
.tbuf = 32,
.scl_stretch_en = 0,
.trdhld = 6,
.tsp = 3
},
};
static const struct cci_data cci_v2_data = {
.num_masters = 2,
.queue_size = { 64, 16 },
@ -773,6 +808,7 @@ static const struct cci_data cci_v2_data = {
static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},

View File

@ -97,6 +97,7 @@ struct geni_i2c_dev {
struct dma_chan *tx_c;
struct dma_chan *rx_c;
bool gpi_mode;
bool abort_done;
};
struct geni_i2c_err_log {
@ -203,9 +204,18 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
if (err != NACK && err != GENI_ABORT_DONE) {
switch (err) {
case GENI_ABORT_DONE:
gi2c->abort_done = true;
break;
case NACK:
case GENI_TIMEOUT:
dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
break;
default:
dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
geni_i2c_err_misc(gi2c);
break;
}
}
@ -311,21 +321,21 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
{
u32 val;
unsigned long time_left = ABORT_TIMEOUT;
unsigned long flags;
spin_lock_irqsave(&gi2c->lock, flags);
geni_i2c_err(gi2c, GENI_TIMEOUT);
gi2c->cur = NULL;
gi2c->abort_done = false;
geni_se_abort_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
do {
time_left = wait_for_completion_timeout(&gi2c->done, time_left);
val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
} while (!(val & M_CMD_ABORT_EN) && time_left);
} while (!gi2c->abort_done && time_left);
if (!(val & M_CMD_ABORT_EN))
if (!time_left)
dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
}
@ -688,7 +698,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
pm_runtime_put_autosuspend(gi2c->se.dev);
gi2c->cur = NULL;
gi2c->err = 0;
return num;
return ret;
}
static u32 geni_i2c_func(struct i2c_adapter *adap)

View File

@ -0,0 +1,532 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Renesas RZ/V2M I2C unit
*
* Copyright (C) 2016-2022 Renesas Electronics Corporation
*/
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/i2c.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
/* Register offsets */
#define IICB0DAT 0x00 /* Data Register */
#define IICB0CTL0 0x08 /* Control Register 0 */
#define IICB0TRG 0x0C /* Trigger Register */
#define IICB0STR0 0x10 /* Status Register 0 */
#define IICB0CTL1 0x20 /* Control Register 1 */
#define IICB0WL 0x24 /* Low Level Width Setting Reg */
#define IICB0WH 0x28 /* How Level Width Setting Reg */
/* IICB0CTL0 */
#define IICB0IICE BIT(7) /* I2C Enable */
#define IICB0SLWT BIT(1) /* Interrupt Request Timing */
#define IICB0SLAC BIT(0) /* Acknowledge */
/* IICB0TRG */
#define IICB0WRET BIT(2) /* Quit Wait Trigger */
#define IICB0STT BIT(1) /* Create Start Condition Trigger */
#define IICB0SPT BIT(0) /* Create Stop Condition Trigger */
/* IICB0STR0 */
#define IICB0SSAC BIT(8) /* Ack Flag */
#define IICB0SSBS BIT(6) /* Bus Flag */
#define IICB0SSSP BIT(4) /* Stop Condition Flag */
/* IICB0CTL1 */
#define IICB0MDSC BIT(7) /* Bus Mode */
#define IICB0SLSE BIT(1) /* Start condition output */
#define bit_setl(addr, val) writel(readl(addr) | (val), (addr))
#define bit_clrl(addr, val) writel(readl(addr) & ~(val), (addr))
struct rzv2m_i2c_priv {
void __iomem *base;
struct i2c_adapter adap;
struct clk *clk;
int bus_mode;
struct completion msg_tia_done;
u32 iicb0wl;
u32 iicb0wh;
};
enum bcr_index {
RZV2M_I2C_100K = 0,
RZV2M_I2C_400K,
};
struct bitrate_config {
unsigned int percent_low;
unsigned int min_hold_time_ns;
};
static const struct bitrate_config bitrate_configs[] = {
[RZV2M_I2C_100K] = { 47, 3450 },
[RZV2M_I2C_400K] = { 52, 900 },
};
static irqreturn_t rzv2m_i2c_tia_irq_handler(int this_irq, void *dev_id)
{
struct rzv2m_i2c_priv *priv = dev_id;
complete(&priv->msg_tia_done);
return IRQ_HANDLED;
}
/* Calculate IICB0WL and IICB0WH */
static int rzv2m_i2c_clock_calculate(struct device *dev,
struct rzv2m_i2c_priv *priv)
{
const struct bitrate_config *config;
unsigned int hold_time_ns;
unsigned int total_pclks;
unsigned int trf_pclks;
unsigned long pclk_hz;
struct i2c_timings t;
u32 trf_ns;
i2c_parse_fw_timings(dev, &t, true);
pclk_hz = clk_get_rate(priv->clk);
total_pclks = pclk_hz / t.bus_freq_hz;
trf_ns = t.scl_rise_ns + t.scl_fall_ns;
trf_pclks = mul_u64_u32_div(pclk_hz, trf_ns, NSEC_PER_SEC);
/* Config setting */
switch (t.bus_freq_hz) {
case I2C_MAX_FAST_MODE_FREQ:
priv->bus_mode = RZV2M_I2C_400K;
break;
case I2C_MAX_STANDARD_MODE_FREQ:
priv->bus_mode = RZV2M_I2C_100K;
break;
default:
dev_err(dev, "transfer speed is invalid\n");
return -EINVAL;
}
config = &bitrate_configs[priv->bus_mode];
/* IICB0WL = (percent_low / Transfer clock) x PCLK */
priv->iicb0wl = total_pclks * config->percent_low / 100;
if (priv->iicb0wl > (BIT(10) - 1))
return -EINVAL;
/* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */
priv->iicb0wh = total_pclks - priv->iicb0wl - trf_pclks;
if (priv->iicb0wh > (BIT(10) - 1))
return -EINVAL;
/*
* Data hold time must be less than 0.9us in fast mode and
* 3.45us in standard mode.
* Data hold time = IICB0WL[9:2] / PCLK
*/
hold_time_ns = div64_ul((u64)(priv->iicb0wl >> 2) * NSEC_PER_SEC, pclk_hz);
if (hold_time_ns > config->min_hold_time_ns) {
dev_err(dev, "data hold time %dns is over %dns\n",
hold_time_ns, config->min_hold_time_ns);
return -EINVAL;
}
return 0;
}
static void rzv2m_i2c_init(struct rzv2m_i2c_priv *priv)
{
u32 i2c_ctl0;
u32 i2c_ctl1;
/* i2c disable */
writel(0, priv->base + IICB0CTL0);
/* IICB0CTL1 setting */
i2c_ctl1 = IICB0SLSE;
if (priv->bus_mode == RZV2M_I2C_400K)
i2c_ctl1 |= IICB0MDSC;
writel(i2c_ctl1, priv->base + IICB0CTL1);
/* IICB0WL IICB0WH setting */
writel(priv->iicb0wl, priv->base + IICB0WL);
writel(priv->iicb0wh, priv->base + IICB0WH);
/* i2c enable after setting */
i2c_ctl0 = IICB0SLWT | IICB0SLAC | IICB0IICE;
writel(i2c_ctl0, priv->base + IICB0CTL0);
}
static int rzv2m_i2c_write_with_ack(struct rzv2m_i2c_priv *priv, u32 data)
{
unsigned long time_left;
reinit_completion(&priv->msg_tia_done);
writel(data, priv->base + IICB0DAT);
time_left = wait_for_completion_timeout(&priv->msg_tia_done,
priv->adap.timeout);
if (!time_left)
return -ETIMEDOUT;
/* Confirm ACK */
if ((readl(priv->base + IICB0STR0) & IICB0SSAC) != IICB0SSAC)
return -ENXIO;
return 0;
}
static int rzv2m_i2c_read_with_ack(struct rzv2m_i2c_priv *priv, u8 *data,
bool last)
{
unsigned long time_left;
u32 data_tmp;
reinit_completion(&priv->msg_tia_done);
/* Interrupt request timing : 8th clock */
bit_clrl(priv->base + IICB0CTL0, IICB0SLWT);
/* Exit the wait state */
writel(IICB0WRET, priv->base + IICB0TRG);
/* Wait for transaction */
time_left = wait_for_completion_timeout(&priv->msg_tia_done,
priv->adap.timeout);
if (!time_left)
return -ETIMEDOUT;
if (last) {
/* Disable ACK */
bit_clrl(priv->base + IICB0CTL0, IICB0SLAC);
/* Read data*/
data_tmp = readl(priv->base + IICB0DAT);
/* Interrupt request timing : 9th clock */
bit_setl(priv->base + IICB0CTL0, IICB0SLWT);
/* Exit the wait state */
writel(IICB0WRET, priv->base + IICB0TRG);
/* Wait for transaction */
time_left = wait_for_completion_timeout(&priv->msg_tia_done,
priv->adap.timeout);
if (!time_left)
return -ETIMEDOUT;
/* Enable ACK */
bit_setl(priv->base + IICB0CTL0, IICB0SLAC);
} else {
/* Read data */
data_tmp = readl(priv->base + IICB0DAT);
}
*data = data_tmp;
return 0;
}
static int rzv2m_i2c_send(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
unsigned int *count)
{
unsigned int i;
int ret;
for (i = 0; i < msg->len; i++) {
ret = rzv2m_i2c_write_with_ack(priv, msg->buf[i]);
if (ret < 0)
return ret;
}
*count = i;
return 0;
}
static int rzv2m_i2c_receive(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg,
unsigned int *count)
{
unsigned int i;
int ret;
for (i = 0; i < msg->len; i++) {
ret = rzv2m_i2c_read_with_ack(priv, &msg->buf[i],
(msg->len - 1) == i);
if (ret < 0)
return ret;
}
*count = i;
return 0;
}
static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv,
struct i2c_msg *msg)
{
u32 addr;
int ret;
if (msg->flags & I2C_M_TEN) {
/*
* 10-bit address
* addr_1: 5'b11110 | addr[9:8] | (R/nW)
* addr_2: addr[7:0]
*/
addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7);
addr |= !!(msg->flags & I2C_M_RD);
/* Send 1st address(extend code) */
ret = rzv2m_i2c_write_with_ack(priv, addr);
if (ret)
return ret;
/* Send 2nd address */
ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff);
} else {
/* 7-bit address */
addr = i2c_8bit_addr_from_msg(msg);
ret = rzv2m_i2c_write_with_ack(priv, addr);
}
return ret;
}
static int rzv2m_i2c_stop_condition(struct rzv2m_i2c_priv *priv)
{
u32 value;
/* Send stop condition */
writel(IICB0SPT, priv->base + IICB0TRG);
return readl_poll_timeout(priv->base + IICB0STR0,
value, value & IICB0SSSP,
100, jiffies_to_usecs(priv->adap.timeout));
}
static int rzv2m_i2c_master_xfer_msg(struct rzv2m_i2c_priv *priv,
struct i2c_msg *msg, int stop)
{
unsigned int count = 0;
int ret, read = !!(msg->flags & I2C_M_RD);
/* Send start condition */
writel(IICB0STT, priv->base + IICB0TRG);
ret = rzv2m_i2c_send_address(priv, msg);
if (!ret) {
if (read)
ret = rzv2m_i2c_receive(priv, msg, &count);
else
ret = rzv2m_i2c_send(priv, msg, &count);
if (!ret && stop)
ret = rzv2m_i2c_stop_condition(priv);
}
if (ret == -ENXIO)
rzv2m_i2c_stop_condition(priv);
else if (ret < 0)
rzv2m_i2c_init(priv);
else
ret = count;
return ret;
}
static int rzv2m_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct rzv2m_i2c_priv *priv = i2c_get_adapdata(adap);
struct device *dev = priv->adap.dev.parent;
unsigned int i;
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
if (readl(priv->base + IICB0STR0) & IICB0SSBS) {
ret = -EAGAIN;
goto out;
}
/* I2C main transfer */
for (i = 0; i < num; i++) {
ret = rzv2m_i2c_master_xfer_msg(priv, &msgs[i], i == (num - 1));
if (ret < 0)
goto out;
}
ret = num;
out:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static u32 rzv2m_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
I2C_FUNC_10BIT_ADDR;
}
static const struct i2c_adapter_quirks rzv2m_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static struct i2c_algorithm rzv2m_i2c_algo = {
.master_xfer = rzv2m_i2c_master_xfer,
.functionality = rzv2m_i2c_func,
};
static int rzv2m_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rzv2m_i2c_priv *priv;
struct reset_control *rstc;
struct i2c_adapter *adap;
struct resource *res;
int irq, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk))
return dev_err_probe(dev, PTR_ERR(priv->clk), "Can't get clock\n");
rstc = devm_reset_control_get_shared(dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(dev, PTR_ERR(rstc), "Missing reset ctrl\n");
/*
* The reset also affects other HW that is not under the control
* of Linux. Therefore, all we can do is deassert the reset.
*/
reset_control_deassert(rstc);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0,
dev_name(dev), priv);
if (ret < 0)
return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
adap = &priv->adap;
adap->nr = pdev->id;
adap->algo = &rzv2m_i2c_algo;
adap->quirks = &rzv2m_i2c_quirks;
adap->dev.parent = dev;
adap->owner = THIS_MODULE;
device_set_node(&adap->dev, dev_fwnode(dev));
i2c_set_adapdata(adap, priv);
strscpy(adap->name, pdev->name, sizeof(adap->name));
init_completion(&priv->msg_tia_done);
ret = rzv2m_i2c_clock_calculate(dev, priv);
if (ret < 0)
return ret;
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
rzv2m_i2c_init(priv);
pm_runtime_put(dev);
platform_set_drvdata(pdev, priv);
ret = i2c_add_numbered_adapter(adap);
if (ret < 0)
pm_runtime_disable(dev);
return ret;
}
static int rzv2m_i2c_remove(struct platform_device *pdev)
{
struct rzv2m_i2c_priv *priv = platform_get_drvdata(pdev);
struct device *dev = priv->adap.dev.parent;
i2c_del_adapter(&priv->adap);
bit_clrl(priv->base + IICB0CTL0, IICB0IICE);
pm_runtime_disable(dev);
return 0;
}
static int rzv2m_i2c_suspend(struct device *dev)
{
struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
bit_clrl(priv->base + IICB0CTL0, IICB0IICE);
pm_runtime_put(dev);
return 0;
}
static int rzv2m_i2c_resume(struct device *dev)
{
struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev);
int ret;
ret = rzv2m_i2c_clock_calculate(dev, priv);
if (ret < 0)
return ret;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
rzv2m_i2c_init(priv);
pm_runtime_put(dev);
return 0;
}
static const struct of_device_id rzv2m_i2c_ids[] = {
{ .compatible = "renesas,rzv2m-i2c" },
{ }
};
MODULE_DEVICE_TABLE(of, rzv2m_i2c_ids);
static const struct dev_pm_ops rzv2m_i2c_pm_ops = {
SYSTEM_SLEEP_PM_OPS(rzv2m_i2c_suspend, rzv2m_i2c_resume)
};
static struct platform_driver rzv2m_i2c_driver = {
.driver = {
.name = "rzv2m-i2c",
.of_match_table = rzv2m_i2c_ids,
.pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops),
},
.probe = rzv2m_i2c_probe,
.remove = rzv2m_i2c_remove,
};
module_platform_driver(rzv2m_i2c_driver);
MODULE_DESCRIPTION("RZ/V2M I2C bus driver");
MODULE_AUTHOR("Renesas Electronics Corporation");
MODULE_LICENSE("GPL");

View File

@ -30,7 +30,7 @@ struct acpi_smbus_cmi {
u8 cap_info:1;
u8 cap_read:1;
u8 cap_write:1;
struct smbus_methods_t *methods;
const struct smbus_methods_t *methods;
};
static const struct smbus_methods_t smbus_methods = {
@ -361,7 +361,6 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
static int acpi_smbus_cmi_add(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi;
const struct acpi_device_id *id;
int ret;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
@ -369,6 +368,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
return -ENOMEM;
smbus_cmi->handle = device->handle;
smbus_cmi->methods = device_get_match_data(&device->dev);
strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
device->driver_data = smbus_cmi;
@ -376,11 +376,6 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 0;
for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
if (!strcmp(id->id, acpi_device_hid(device)))
smbus_cmi->methods =
(struct smbus_methods_t *) id->driver_data;
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);

View File

@ -410,6 +410,12 @@ static const struct stm32f7_i2c_setup stm32mp15_setup = {
.fmp_clr_offset = 0x40,
};
static const struct stm32f7_i2c_setup stm32mp13_setup = {
.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
.fmp_clr_offset = 0x4,
};
static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)
{
writel_relaxed(readl_relaxed(reg) | mask, reg);
@ -2468,6 +2474,7 @@ static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
static const struct of_device_id stm32f7_i2c_match[] = {
{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
{ .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup},
{ .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup},
{},
};
MODULE_DEVICE_TABLE(of, stm32f7_i2c_match);

View File

@ -367,7 +367,7 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
}
}
static void xiic_wakeup(struct xiic_i2c *i2c, int code)
static void xiic_wakeup(struct xiic_i2c *i2c, enum xilinx_i2c_state code)
{
i2c->tx_msg = NULL;
i2c->rx_msg = NULL;
@ -383,7 +383,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
u32 clr = 0;
int xfer_more = 0;
int wakeup_req = 0;
int wakeup_code = 0;
enum xilinx_i2c_state wakeup_code = STATE_DONE;
int ret;
/* Get the interrupt Status from the IPIF. There is no clearing of

View File

@ -1023,15 +1023,9 @@ static int dummy_probe(struct i2c_client *client,
return 0;
}
static int dummy_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
.probe = dummy_probe,
.remove = dummy_remove,
.id_table = dummy_id,
};
@ -2467,8 +2461,9 @@ void i2c_put_adapter(struct i2c_adapter *adap)
if (!adap)
return;
put_device(&adap->dev);
module_put(adap->owner);
/* Should be last, otherwise we risk use-after-free with 'adap' */
put_device(&adap->dev);
}
EXPORT_SYMBOL(i2c_put_adapter);

View File

@ -134,6 +134,7 @@ static int i2c_mux_probe(struct platform_device *pdev)
return 0;
err_children:
of_node_put(child);
i2c_mux_del_adapters(muxc);
err_parent:
i2c_put_adapter(parent);

View File

@ -537,7 +537,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
*
* The return codes from the ``master_xfer{_atomic}`` fields should indicate the
* type of error code that occurred during the transfer, as documented in the
* Kernel Documentation file Documentation/i2c/fault-codes.rst.
* Kernel Documentation file Documentation/i2c/fault-codes.rst. Otherwise, the
* number of messages executed should be returned.
*/
struct i2c_algorithm {
/*