mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
- 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:
commit
80dc75932f
29
Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml
Normal file
29
Documentation/devicetree/bindings/i2c/arm,i2c-versatile.yaml
Normal 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
|
||||
|
||||
...
|
||||
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
@ -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>;
|
||||
};
|
||||
|
||||
...
|
||||
|
113
Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml
Normal file
113
Documentation/devicetree/bindings/i2c/opencores,i2c-ocores.yaml
Normal 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 */
|
||||
};
|
||||
...
|
80
Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
Normal file
80
Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
Normal 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>;
|
||||
};
|
115
Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
Normal file
115
Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
Normal 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";
|
||||
};
|
||||
|
||||
...
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 || \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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, }
|
||||
};
|
||||
|
||||
|
480
drivers/i2c/busses/i2c-microchip-corei2c.c
Normal file
480
drivers/i2c/busses/i2c-microchip-corei2c.c
Normal 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");
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
|
@ -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)
|
||||
|
532
drivers/i2c/busses/i2c-rzv2m.c
Normal file
532
drivers/i2c/busses/i2c-rzv2m.c
Normal 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");
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user