Merge branch 'i2c/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "I2C has quite some patches for you this time. I hope it is the move to per-driver-maintainers which is now showing results. We will see. The big news is two new drivers (Nuvoton NPCM and Qualcomm CCI), larger refactoring of the Designware, Tegra, and PXA drivers, the Cadence driver supports being a slave now, and there is support to instanciate SPD eeproms for well-known cases (which will be user-visible because the i801 driver supports it), and some devm_platform_ioremap_resource() conversions which blow up the diffstat. Note that I applied the Nuvoton driver quite late, so some minor fixup patches arrived during the merge window. I chose to apply them right away because they were trivial" * 'i2c/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (109 commits) i2c: Drop stray comma in MODULE_AUTHOR statements i2c: npcm7xx: npcm_i2caddr[] can be static MAINTAINERS: npcm7xx: Add maintainer for Nuvoton NPCM BMC i2c: npcm7xx: Fix a couple of error codes in probe i2c: icy: Fix build with CONFIG_AMIGA_PCMCIA=n i2c: npcm7xx: Remove unnecessary parentheses i2c: npcm7xx: Add support for slave mode for Nuvoton i2c: npcm7xx: Add Nuvoton NPCM I2C controller driver dt-bindings: i2c: npcm7xx: add NPCM I2C controller i2c: pxa: don't error out if there's no pinctrl i2c: add 'single-master' property to generic bindings i2c: designware: Add Baikal-T1 System I2C support i2c: designware: Move reg-space remapping into a dedicated function i2c: designware: Retrieve quirk flags as early as possible i2c: designware: Convert driver to using regmap API i2c: designware: Discard Cherry Trail model flag i2c: designware: Add Baytrail sem config DW I2C platform dependency i2c: designware: slave: Set DW I2C core module dependency i2c: designware: Use `-y` to build multi-object modules dt-bindings: i2c: dw: Add Baikal-T1 SoC I2C controller ...
This commit is contained in:
Коммит
91fa58840a
|
@ -1,73 +0,0 @@
|
|||
* Synopsys DesignWare I2C
|
||||
|
||||
Required properties :
|
||||
|
||||
- compatible : should be "snps,designware-i2c"
|
||||
or "mscc,ocelot-i2c" with "snps,designware-i2c" for fallback
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : <IRQ> where IRQ is the interrupt number.
|
||||
- clocks : phandles for the clocks, see the description of clock-names below.
|
||||
The phandle for the "ic_clk" clock is required. The phandle for the "pclk"
|
||||
clock is optional. If a single clock is specified but no clock-name, it is
|
||||
the "ic_clk" clock. If both clocks are listed, the "ic_clk" must be first.
|
||||
|
||||
Recommended properties :
|
||||
|
||||
- clock-frequency : desired I2C bus clock frequency in Hz.
|
||||
|
||||
Optional properties :
|
||||
|
||||
- clock-names : Contains the names of the clocks:
|
||||
"ic_clk", for the core clock used to generate the external I2C clock.
|
||||
"pclk", the interface clock, required for register access.
|
||||
|
||||
- reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
|
||||
time, named ICPU_CFG:TWI_DELAY in the datasheet.
|
||||
|
||||
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
|
||||
This option is only supported in hardware blocks version 1.11a or newer and
|
||||
on Microsemi SoCs ("mscc,ocelot-i2c" compatible).
|
||||
|
||||
- i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
|
||||
This value which is by default 300ns is used to compute the tLOW period.
|
||||
|
||||
- i2c-sda-falling-time-ns : should contain the SDA falling time in nanoseconds.
|
||||
This value which is by default 300ns is used to compute the tHIGH period.
|
||||
|
||||
Examples :
|
||||
|
||||
i2c@f0000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0xf0000 0x1000>;
|
||||
interrupts = <11>;
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
|
||||
i2c@1120000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x1120000 0x1000>;
|
||||
interrupt-parent = <&ictl>;
|
||||
interrupts = <12 1>;
|
||||
clock-frequency = <400000>;
|
||||
i2c-sda-hold-time-ns = <300>;
|
||||
i2c-sda-falling-time-ns = <300>;
|
||||
i2c-scl-falling-time-ns = <300>;
|
||||
};
|
||||
|
||||
i2c@1120000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x2000 0x100>;
|
||||
clock-frequency = <400000>;
|
||||
clocks = <&i2cclk>;
|
||||
interrupts = <0>;
|
||||
|
||||
eeprom@64 {
|
||||
compatible = "linux,slave-24c02";
|
||||
reg = <0x40000064>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,92 @@
|
|||
Qualcomm Camera Control Interface (CCI) I2C controller
|
||||
|
||||
PROPERTIES:
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,msm8916-cci"
|
||||
"qcom,msm8996-cci"
|
||||
"qcom,sdm845-cci"
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: base address CCI I2C controller and length of memory
|
||||
mapped region.
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: specifies the CCI I2C interrupt. The format of the
|
||||
specifier is defined by the binding document describing
|
||||
the node's interrupt parent.
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: a list of phandle, should contain an entry for each
|
||||
entries in clock-names.
|
||||
|
||||
- clock-names
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: a list of clock names, must include "cci" clock.
|
||||
|
||||
- power-domains
|
||||
Usage: required for "qcom,msm8996-cci"
|
||||
Value type: <prop-encoded-array>
|
||||
Definition:
|
||||
|
||||
SUBNODES:
|
||||
|
||||
The CCI provides I2C masters for one (msm8916) or two i2c busses (msm8996 and
|
||||
sdm845), described as subdevices named "i2c-bus@0" and "i2c-bus@1".
|
||||
|
||||
PROPERTIES:
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Index of the CCI bus/master
|
||||
|
||||
- clock-frequency:
|
||||
Usage: optional
|
||||
Value type: <u32>
|
||||
Definition: Desired I2C bus clock frequency in Hz, defaults to 100
|
||||
kHz if omitted.
|
||||
|
||||
Example:
|
||||
|
||||
cci@a0c000 {
|
||||
compatible = "qcom,msm8996-cci";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0xa0c000 0x1000>;
|
||||
interrupts = <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&mmcc MMSS_MMAGIC_AHB_CLK>,
|
||||
<&mmcc CAMSS_TOP_AHB_CLK>,
|
||||
<&mmcc CAMSS_CCI_AHB_CLK>,
|
||||
<&mmcc CAMSS_CCI_CLK>,
|
||||
<&mmcc CAMSS_AHB_CLK>;
|
||||
clock-names = "mmss_mmagic_ahb",
|
||||
"camss_top_ahb",
|
||||
"cci_ahb",
|
||||
"cci",
|
||||
"camss_ahb";
|
||||
|
||||
i2c-bus@0 {
|
||||
reg = <0>;
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
i2c-bus@1 {
|
||||
reg = <1>;
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
|
@ -2,32 +2,26 @@ Generic device tree bindings for I2C busses
|
|||
===========================================
|
||||
|
||||
This document describes generic bindings which can be used to describe I2C
|
||||
busses in a device tree.
|
||||
busses and their child devices in a device tree.
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
Required properties (per bus)
|
||||
-----------------------------
|
||||
|
||||
- #address-cells - should be <1>. Read more about addresses below.
|
||||
- #size-cells - should be <0>.
|
||||
- compatible - name of I2C bus controller following generic names
|
||||
recommended practice.
|
||||
- compatible - name of I2C bus controller
|
||||
|
||||
For other required properties e.g. to describe register sets,
|
||||
clocks, etc. check the binding documentation of the specific driver.
|
||||
|
||||
The cells properties above define that an address of children of an I2C bus
|
||||
are described by a single value. This is usually a 7 bit address. However,
|
||||
flags can be attached to the address. I2C_TEN_BIT_ADDRESS is used to mark a 10
|
||||
bit address. It is needed to avoid the ambiguity between e.g. a 7 bit address
|
||||
of 0x50 and a 10 bit address of 0x050 which, in theory, can be on the same bus.
|
||||
Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we listen to
|
||||
be devices ourselves.
|
||||
are described by a single value.
|
||||
|
||||
Optional properties
|
||||
-------------------
|
||||
Optional properties (per bus)
|
||||
-----------------------------
|
||||
|
||||
These properties may not be supported by all drivers. However, if a driver
|
||||
wants to support one of the below features, it should adapt the bindings below.
|
||||
wants to support one of the below features, it should adapt these bindings.
|
||||
|
||||
- clock-frequency
|
||||
frequency of bus clock in Hz.
|
||||
|
@ -73,6 +67,40 @@ wants to support one of the below features, it should adapt the bindings below.
|
|||
i2c bus clock frequency (clock-frequency).
|
||||
Specified in Hz.
|
||||
|
||||
- multi-master
|
||||
states that there is another master active on this bus. The OS can use
|
||||
this information to adapt power management to keep the arbitration awake
|
||||
all the time, for example. Can not be combined with 'single-master'.
|
||||
|
||||
- single-master
|
||||
states that there is no other master active on this bus. The OS can use
|
||||
this information to detect a stalled bus more reliably, for example.
|
||||
Can not be combined with 'multi-master'.
|
||||
|
||||
Required properties (per child device)
|
||||
--------------------------------------
|
||||
|
||||
- compatible
|
||||
name of I2C slave device
|
||||
|
||||
- reg
|
||||
One or many I2C slave addresses. These are usually a 7 bit addresses.
|
||||
However, flags can be attached to an address. I2C_TEN_BIT_ADDRESS is
|
||||
used to mark a 10 bit address. It is needed to avoid the ambiguity
|
||||
between e.g. a 7 bit address of 0x50 and a 10 bit address of 0x050
|
||||
which, in theory, can be on the same bus.
|
||||
Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we
|
||||
listen to be devices ourselves.
|
||||
|
||||
Optional properties (per child device)
|
||||
--------------------------------------
|
||||
|
||||
These properties may not be supported by all drivers. However, if a driver
|
||||
wants to support one of the below features, it should adapt these bindings.
|
||||
|
||||
- host-notify
|
||||
device uses SMBus host notify protocol instead of interrupt line.
|
||||
|
||||
- interrupts
|
||||
interrupts used by the device.
|
||||
|
||||
|
@ -80,24 +108,13 @@ wants to support one of the below features, it should adapt the bindings below.
|
|||
"irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
|
||||
other names are left to individual drivers.
|
||||
|
||||
- host-notify
|
||||
device uses SMBus host notify protocol instead of interrupt line.
|
||||
|
||||
- multi-master
|
||||
states that there is another master active on this bus. The OS can use
|
||||
this information to adapt power management to keep the arbitration awake
|
||||
all the time, for example.
|
||||
|
||||
- wakeup-source
|
||||
device can be used as a wakeup source.
|
||||
|
||||
- reg
|
||||
I2C slave addresses
|
||||
|
||||
- reg-names
|
||||
Names of map programmable addresses.
|
||||
It can contain any map needing another address than default one.
|
||||
|
||||
- wakeup-source
|
||||
device can be used as a wakeup source.
|
||||
|
||||
Binding may contain optional "interrupts" property, describing interrupts
|
||||
used by the device. I2C core will assign "irq" interrupt (or the very first
|
||||
interrupt if not using interrupt names) as primary interrupt for the slave.
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/nuvoton,npcm7xx-i2c.yaml#
|
||||
$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.
|
||||
|
||||
maintainers:
|
||||
- Tali Perry <tali.perry1@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nuvoton,npcm7xx-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description: Reference clock for the I2C bus
|
||||
|
||||
clock-frequency:
|
||||
description: Desired I2C bus clock frequency in Hz. If not specified,
|
||||
the default 100 kHz frequency will be used.
|
||||
possible values are 100000, 400000 and 1000000.
|
||||
default: 100000
|
||||
enum: [100000, 400000, 1000000]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/nuvoton,npcm7xx-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
i2c0: i2c@80000 {
|
||||
reg = <0x80000 0x1000>;
|
||||
clocks = <&clk NPCM7XX_CLK_APB2>;
|
||||
clock-frequency = <100000>;
|
||||
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
||||
compatible = "nuvoton,npcm750-i2c";
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,156 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/snps,designware-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Synopsys DesignWare APB I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
not:
|
||||
contains:
|
||||
const: mscc,ocelot-i2c
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: Generic Synopsys DesignWare I2C controller
|
||||
const: snps,designware-i2c
|
||||
- description: Microsemi Ocelot SoCs I2C controller
|
||||
items:
|
||||
- const: mscc,ocelot-i2c
|
||||
- const: snps,designware-i2c
|
||||
- description: Baikal-T1 SoC System I2C controller
|
||||
const: baikal,bt1-sys-i2c
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: DW APB I2C controller memory mapped registers
|
||||
- description: |
|
||||
ICPU_CFG:TWI_DELAY registers to setup the SDA hold time.
|
||||
This registers are specific to the Ocelot I2C-controller.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: I2C controller reference clock source
|
||||
- description: APB interface clock source
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: ref
|
||||
- const: pclk
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description: Desired I2C bus clock frequency in Hz
|
||||
enum: [100000, 400000, 1000000, 3400000]
|
||||
default: 400000
|
||||
|
||||
i2c-sda-hold-time-ns:
|
||||
maxItems: 1
|
||||
description: |
|
||||
The property should contain the SDA hold time in nanoseconds. This option
|
||||
is only supported in hardware blocks version 1.11a or newer or on
|
||||
Microsemi SoCs.
|
||||
|
||||
i2c-scl-falling-time-ns:
|
||||
maxItems: 1
|
||||
description: |
|
||||
The property should contain the SCL falling time in nanoseconds.
|
||||
This value is used to compute the tLOW period.
|
||||
default: 300
|
||||
|
||||
i2c-sda-falling-time-ns:
|
||||
maxItems: 1
|
||||
description: |
|
||||
The property should contain the SDA falling time in nanoseconds.
|
||||
This value is used to compute the tHIGH period.
|
||||
default: 300
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: TX DMA Channel
|
||||
- description: RX DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@f0000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0xf0000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <11>;
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
- |
|
||||
i2c@1120000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x1120000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <12 1>;
|
||||
clock-frequency = <400000>;
|
||||
i2c-sda-hold-time-ns = <300>;
|
||||
i2c-sda-falling-time-ns = <300>;
|
||||
i2c-scl-falling-time-ns = <300>;
|
||||
};
|
||||
- |
|
||||
i2c@2000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
reg = <0x2000 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clock-frequency = <400000>;
|
||||
clocks = <&i2cclk>;
|
||||
interrupts = <0>;
|
||||
|
||||
eeprom@64 {
|
||||
compatible = "atmel,24c02";
|
||||
reg = <0x64>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
i2c@100400 {
|
||||
compatible = "mscc,ocelot-i2c", "snps,designware-i2c";
|
||||
reg = <0x100400 0x100>, <0x198 0x8>;
|
||||
pinctrl-0 = <&i2c_pins>;
|
||||
pinctrl-names = "default";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <8>;
|
||||
clocks = <&ahb_clk>;
|
||||
};
|
||||
...
|
|
@ -81,11 +81,11 @@ properties:
|
|||
clock-frequency:
|
||||
description: Desired I2C bus clock frequency in Hz. If not specified,
|
||||
the default 100 kHz frequency will be used.
|
||||
For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode,
|
||||
Fast-mode and Fast-mode Plus are supported, possible
|
||||
values are 100000, 400000 and 1000000.
|
||||
For STM32F7, STM32H7 and STM32MP1 SoCs, if timing parameters
|
||||
match, the bus clock frequency can be from 1Hz to 1MHz.
|
||||
default: 100000
|
||||
enum: [100000, 400000, 1000000]
|
||||
minimum: 1
|
||||
maximum: 1000000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
@ -2174,6 +2174,7 @@ F: Documentation/devicetree/bindings/*/*npcm*
|
|||
F: arch/arm/boot/dts/nuvoton-npcm*
|
||||
F: arch/arm/mach-npcm/
|
||||
F: drivers/*/*npcm*
|
||||
F: drivers/*/*/*npcm*
|
||||
F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
|
||||
|
||||
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
|
||||
|
|
|
@ -475,8 +475,8 @@ config I2C_BCM_KONA
|
|||
|
||||
config I2C_BRCMSTB
|
||||
tristate "BRCM Settop/DSL I2C controller"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \
|
||||
COMPILE_TEST
|
||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC || \
|
||||
ARCH_BCM_63XX || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
@ -526,11 +526,24 @@ config I2C_DAVINCI
|
|||
|
||||
config I2C_DESIGNWARE_CORE
|
||||
tristate
|
||||
select REGMAP
|
||||
|
||||
config I2C_DESIGNWARE_SLAVE
|
||||
bool "Synopsys DesignWare Slave"
|
||||
depends on I2C_DESIGNWARE_CORE
|
||||
select I2C_SLAVE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Synopsys DesignWare I2C slave adapter.
|
||||
|
||||
This is not a standalone module, this module compiles together with
|
||||
i2c-designware-core.
|
||||
|
||||
config I2C_DESIGNWARE_PLATFORM
|
||||
tristate "Synopsys DesignWare Platform"
|
||||
select I2C_DESIGNWARE_CORE
|
||||
depends on (ACPI && COMMON_CLK) || !ACPI
|
||||
select I2C_DESIGNWARE_CORE
|
||||
select MFD_SYSCON if MIPS_BAIKAL_T1
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Synopsys DesignWare I2C adapter.
|
||||
|
@ -538,16 +551,18 @@ config I2C_DESIGNWARE_PLATFORM
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-designware-platform.
|
||||
|
||||
config I2C_DESIGNWARE_SLAVE
|
||||
bool "Synopsys DesignWare Slave"
|
||||
select I2C_SLAVE
|
||||
config I2C_DESIGNWARE_BAYTRAIL
|
||||
bool "Intel Baytrail I2C semaphore support"
|
||||
depends on ACPI
|
||||
depends on I2C_DESIGNWARE_PLATFORM
|
||||
depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \
|
||||
(I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Synopsys DesignWare I2C slave adapter.
|
||||
|
||||
This is not a standalone module, this module compiles together with
|
||||
i2c-designware-core.
|
||||
This driver enables managed host access to the PMIC I2C bus on select
|
||||
Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
|
||||
the host to request uninterrupted access to the PMIC's I2C bus from
|
||||
the platform firmware controlling it. You should say Y if running on
|
||||
a BayTrail system using the AXP288.
|
||||
|
||||
config I2C_DESIGNWARE_PCI
|
||||
tristate "Synopsys DesignWare PCI"
|
||||
|
@ -560,18 +575,6 @@ config I2C_DESIGNWARE_PCI
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-designware-pci.
|
||||
|
||||
config I2C_DESIGNWARE_BAYTRAIL
|
||||
bool "Intel Baytrail I2C semaphore support"
|
||||
depends on ACPI
|
||||
depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \
|
||||
(I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y)
|
||||
help
|
||||
This driver enables managed host access to the PMIC I2C bus on select
|
||||
Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
|
||||
the host to request uninterrupted access to the PMIC's I2C bus from
|
||||
the platform firmware controlling it. You should say Y if running on
|
||||
a BayTrail system using the AXP288.
|
||||
|
||||
config I2C_DIGICOLOR
|
||||
tristate "Conexant Digicolor I2C driver"
|
||||
depends on ARCH_DIGICOLOR || COMPILE_TEST
|
||||
|
@ -791,6 +794,15 @@ 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
|
||||
tristate "Nuvoton I2C Controller"
|
||||
depends on ARCH_NPCM7XX || 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.
|
||||
Driver can also support slave mode (select I2C_SLAVE).
|
||||
|
||||
config I2C_OCORES
|
||||
tristate "OpenCores I2C Controller"
|
||||
help
|
||||
|
@ -885,6 +897,16 @@ config I2C_PXA_SLAVE
|
|||
is necessary for systems where the PXA may be a target on the
|
||||
I2C bus.
|
||||
|
||||
config I2C_QCOM_CCI
|
||||
tristate "Qualcomm Camera Control Interface"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in camera control interface on the Qualcomm SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-qcom-cci.
|
||||
|
||||
config I2C_QCOM_GENI
|
||||
tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
|
|
|
@ -48,16 +48,15 @@ obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
|
|||
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
|
||||
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
|
||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
|
||||
i2c-designware-core-objs := i2c-designware-common.o i2c-designware-master.o
|
||||
ifeq ($(CONFIG_I2C_DESIGNWARE_SLAVE),y)
|
||||
i2c-designware-core-objs += i2c-designware-slave.o
|
||||
endif
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
|
||||
i2c-designware-platform-objs := i2c-designware-platdrv.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
|
||||
i2c-designware-core-y := i2c-designware-common.o
|
||||
i2c-designware-core-y += i2c-designware-master.o
|
||||
i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
|
||||
i2c-designware-platform-y := i2c-designware-platdrv.o
|
||||
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
|
||||
i2c-designware-pci-objs := i2c-designware-pcidrv.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
|
||||
i2c-designware-pci-y := i2c-designware-pcidrv.o
|
||||
obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
|
||||
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
|
||||
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
|
||||
|
@ -81,6 +80,7 @@ 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_OCORES) += i2c-ocores.o
|
||||
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
|
||||
obj-$(CONFIG_I2C_OWL) += i2c-owl.o
|
||||
|
@ -91,6 +91,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
|||
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
|
||||
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
|
||||
obj-$(CONFIG_I2C_QCOM_CCI) += i2c-qcom-cci.o
|
||||
obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
|
||||
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
|
||||
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
* @fifo_size: size of the FIFO passed in.
|
||||
* @isr_mask: cached copy of local ISR enables.
|
||||
* @isr_status: cached copy of local ISR status.
|
||||
* @lock: spinlock for IRQ synchronization.
|
||||
* @isr_mutex: mutex for IRQ thread.
|
||||
*/
|
||||
struct altr_i2c_dev {
|
||||
|
@ -86,18 +85,14 @@ struct altr_i2c_dev {
|
|||
u32 fifo_size;
|
||||
u32 isr_mask;
|
||||
u32 isr_status;
|
||||
spinlock_t lock; /* IRQ synchronization */
|
||||
struct mutex isr_mutex;
|
||||
};
|
||||
|
||||
static void
|
||||
altr_i2c_int_enable(struct altr_i2c_dev *idev, u32 mask, bool enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 int_en;
|
||||
|
||||
spin_lock_irqsave(&idev->lock, flags);
|
||||
|
||||
int_en = readl(idev->base + ALTR_I2C_ISER);
|
||||
if (enable)
|
||||
idev->isr_mask = int_en | mask;
|
||||
|
@ -105,8 +100,6 @@ altr_i2c_int_enable(struct altr_i2c_dev *idev, u32 mask, bool enable)
|
|||
idev->isr_mask = int_en & ~mask;
|
||||
|
||||
writel(idev->isr_mask, idev->base + ALTR_I2C_ISER);
|
||||
|
||||
spin_unlock_irqrestore(&idev->lock, flags);
|
||||
}
|
||||
|
||||
static void altr_i2c_int_clear(struct altr_i2c_dev *idev, u32 mask)
|
||||
|
@ -346,6 +339,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
|
|||
|
||||
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||
ALTR_I2C_XFER_TIMEOUT);
|
||||
mutex_lock(&idev->isr_mutex);
|
||||
altr_i2c_int_enable(idev, imask, false);
|
||||
|
||||
value = readl(idev->base + ALTR_I2C_STATUS) & ALTR_I2C_STAT_CORE;
|
||||
|
@ -358,6 +352,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
|
|||
}
|
||||
|
||||
altr_i2c_core_disable(idev);
|
||||
mutex_unlock(&idev->isr_mutex);
|
||||
|
||||
return idev->msg_err;
|
||||
}
|
||||
|
@ -389,23 +384,19 @@ static const struct i2c_algorithm altr_i2c_algo = {
|
|||
static int altr_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct altr_i2c_dev *idev = NULL;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
|
||||
idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
idev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
idev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(idev->base))
|
||||
return PTR_ERR(idev->base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "missing interrupt resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
idev->i2c_clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(idev->i2c_clk)) {
|
||||
|
@ -415,7 +406,6 @@ static int altr_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
idev->dev = &pdev->dev;
|
||||
init_completion(&idev->msg_complete);
|
||||
spin_lock_init(&idev->lock);
|
||||
mutex_init(&idev->isr_mutex);
|
||||
|
||||
ret = device_property_read_u32(idev->dev, "fifo-size",
|
||||
|
@ -453,7 +443,9 @@ static int altr_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&idev->isr_mutex);
|
||||
altr_i2c_init(idev);
|
||||
mutex_unlock(&idev->isr_mutex);
|
||||
|
||||
i2c_set_adapdata(&idev->adapter, idev);
|
||||
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
|
||||
|
|
|
@ -131,6 +131,7 @@ static struct at91_twi_pdata sama5d2_config = {
|
|||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = true,
|
||||
.has_ana_filtr = true,
|
||||
.has_clear_cmd = false, /* due to errata, CLEAR cmd is not working */
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sam9x60_config = {
|
||||
|
@ -142,6 +143,7 @@ static struct at91_twi_pdata sam9x60_config = {
|
|||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = true,
|
||||
.has_ana_filtr = true,
|
||||
.has_clear_cmd = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id atmel_twi_dt_ids[] = {
|
||||
|
|
|
@ -480,7 +480,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
|||
unsigned long time_left;
|
||||
bool has_unre_flag = dev->pdata->has_unre_flag;
|
||||
bool has_alt_cmd = dev->pdata->has_alt_cmd;
|
||||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||
|
||||
/*
|
||||
* WARNING: the TXCOMP bit in the Status Register is NOT a clear on
|
||||
|
@ -641,11 +640,12 @@ error:
|
|||
AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
|
||||
}
|
||||
|
||||
if (rinfo->get_sda && !(rinfo->get_sda(&dev->adapter))) {
|
||||
dev_dbg(dev->dev,
|
||||
"SDA is down; clear bus using gpio\n");
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
}
|
||||
/*
|
||||
* some faulty I2C slave devices might hold SDA down;
|
||||
* we can send a bus clear command, hoping that the pins will be
|
||||
* released
|
||||
*/
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ static void at91_unprepare_twi_recovery(struct i2c_adapter *adap)
|
|||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default);
|
||||
}
|
||||
|
||||
static int at91_init_twi_recovery_info(struct platform_device *pdev,
|
||||
static int at91_init_twi_recovery_gpio(struct platform_device *pdev,
|
||||
struct at91_twi_dev *dev)
|
||||
{
|
||||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||
|
@ -894,6 +894,41 @@ static int at91_init_twi_recovery_info(struct platform_device *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int at91_twi_recover_bus_cmd(struct i2c_adapter *adap)
|
||||
{
|
||||
struct at91_twi_dev *dev = i2c_get_adapdata(adap);
|
||||
|
||||
dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR);
|
||||
if (!(dev->transfer_status & AT91_TWI_SDA)) {
|
||||
dev_dbg(dev->dev, "SDA is down; sending bus clear command\n");
|
||||
if (dev->use_alt_cmd) {
|
||||
unsigned int acr;
|
||||
|
||||
acr = at91_twi_read(dev, AT91_TWI_ACR);
|
||||
acr &= ~AT91_TWI_ACR_DATAL_MASK;
|
||||
at91_twi_write(dev, AT91_TWI_ACR, acr);
|
||||
}
|
||||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_init_twi_recovery_info(struct platform_device *pdev,
|
||||
struct at91_twi_dev *dev)
|
||||
{
|
||||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||
bool has_clear_cmd = dev->pdata->has_clear_cmd;
|
||||
|
||||
if (!has_clear_cmd)
|
||||
return at91_init_twi_recovery_gpio(pdev, dev);
|
||||
|
||||
rinfo->recover_bus = at91_twi_recover_bus_cmd;
|
||||
dev->adapter.bus_recovery_info = rinfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91_twi_probe_master(struct platform_device *pdev,
|
||||
u32 phy_addr, struct at91_twi_dev *dev)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */
|
||||
#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */
|
||||
#define AT91_TWI_SWRST BIT(7) /* Software Reset */
|
||||
#define AT91_TWI_CLEAR BIT(15) /* Bus clear command */
|
||||
#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */
|
||||
#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */
|
||||
#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */
|
||||
|
@ -69,6 +70,8 @@
|
|||
#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */
|
||||
#define AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */
|
||||
#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */
|
||||
#define AT91_TWI_SCL BIT(24) /* TWI SCL status */
|
||||
#define AT91_TWI_SDA BIT(25) /* TWI SDA status */
|
||||
|
||||
#define AT91_TWI_INT_MASK \
|
||||
(AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
|
||||
|
@ -81,7 +84,8 @@
|
|||
#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
|
||||
|
||||
#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */
|
||||
#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
|
||||
#define AT91_TWI_ACR_DATAL_MASK GENMASK(15, 0)
|
||||
#define AT91_TWI_ACR_DATAL(len) ((len) & AT91_TWI_ACR_DATAL_MASK)
|
||||
#define AT91_TWI_ACR_DIR BIT(8)
|
||||
|
||||
#define AT91_TWI_FILTR 0x0044
|
||||
|
@ -118,6 +122,7 @@ struct at91_twi_pdata {
|
|||
bool has_dig_filtr;
|
||||
bool has_adv_dig_filtr;
|
||||
bool has_ana_filtr;
|
||||
bool has_clear_cmd;
|
||||
struct at_dma_slave dma_slave;
|
||||
};
|
||||
|
||||
|
|
|
@ -734,7 +734,6 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct axxia_i2c_dev *idev = NULL;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -742,16 +741,13 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
|||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
idev->irq = platform_get_irq(pdev, 0);
|
||||
if (idev->irq < 0) {
|
||||
dev_err(&pdev->dev, "missing interrupt resource\n");
|
||||
if (idev->irq < 0)
|
||||
return idev->irq;
|
||||
}
|
||||
|
||||
idev->i2c_clk = devm_clk_get(&pdev->dev, "i2c");
|
||||
if (IS_ERR(idev->i2c_clk)) {
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#define M_CMD_STATUS_RX_FIFO_FULL 0x6
|
||||
#define M_CMD_PROTOCOL_SHIFT 9
|
||||
#define M_CMD_PROTOCOL_MASK 0xf
|
||||
#define M_CMD_PROTOCOL_QUICK 0x0
|
||||
#define M_CMD_PROTOCOL_BLK_WR 0x7
|
||||
#define M_CMD_PROTOCOL_BLK_RD 0x8
|
||||
#define M_CMD_PROTOCOL_PROCESS 0xa
|
||||
|
@ -768,7 +769,11 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
* number of bytes to read
|
||||
*/
|
||||
val = BIT(M_CMD_START_BUSY_SHIFT);
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
|
||||
if (msg->len == 0) {
|
||||
/* SMBUS QUICK Command (Read/Write) */
|
||||
val |= (M_CMD_PROTOCOL_QUICK << M_CMD_PROTOCOL_SHIFT);
|
||||
} else if (msg->flags & I2C_M_RD) {
|
||||
u32 protocol;
|
||||
|
||||
iproc_i2c->rx_bytes = 0;
|
||||
|
@ -830,8 +835,7 @@ static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
|
|||
{
|
||||
u32 val;
|
||||
|
||||
/* We do not support the SMBUS Quick command */
|
||||
val = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
val = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
|
||||
if (adap->algo->reg_slave)
|
||||
val |= I2C_FUNC_SLAVE;
|
||||
|
|
|
@ -750,7 +750,6 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev)
|
|||
int rc = 0;
|
||||
struct bcm_kona_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *iomem;
|
||||
|
||||
/* Allocate memory for private data structure */
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
|
@ -762,8 +761,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev)
|
|||
init_completion(&dev->done);
|
||||
|
||||
/* Map hardware registers */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->base = devm_ioremap_resource(dev->device, iomem);
|
||||
dev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(dev->base))
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -823,8 +821,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev)
|
|||
/* Get the interrupt number */
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
if (dev->irq < 0) {
|
||||
dev_err(dev->device, "no irq resource\n");
|
||||
rc = -ENODEV;
|
||||
rc = dev->irq;
|
||||
goto probe_disable_clk;
|
||||
}
|
||||
|
||||
|
|
|
@ -647,20 +647,22 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
|
|||
int_name = NULL;
|
||||
|
||||
/* Get the interrupt number */
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
dev->irq = platform_get_irq_optional(pdev, 0);
|
||||
|
||||
/* disable the bsc interrupt line */
|
||||
brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
|
||||
|
||||
/* register the ISR handler */
|
||||
rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr,
|
||||
IRQF_SHARED,
|
||||
int_name ? int_name : pdev->name,
|
||||
dev);
|
||||
if (dev->irq >= 0) {
|
||||
rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr,
|
||||
IRQF_SHARED,
|
||||
int_name ? int_name : pdev->name,
|
||||
dev);
|
||||
|
||||
if (rc) {
|
||||
dev_dbg(dev->device, "falling back to polling mode");
|
||||
dev->irq = -1;
|
||||
if (rc) {
|
||||
dev_dbg(dev->device, "falling back to polling mode");
|
||||
dev->irq = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev->device->of_node,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
|
||||
#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
|
||||
#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
|
||||
#define CDNS_I2C_IMR_OFFSET 0x20 /* IRQ Mask Register, RO */
|
||||
#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
|
||||
#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
|
||||
|
||||
|
@ -40,9 +41,17 @@
|
|||
#define CDNS_I2C_CR_DIVB_SHIFT 8
|
||||
#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
|
||||
|
||||
#define CDNS_I2C_CR_MASTER_EN_MASK (CDNS_I2C_CR_NEA | \
|
||||
CDNS_I2C_CR_ACK_EN | \
|
||||
CDNS_I2C_CR_MS)
|
||||
|
||||
#define CDNS_I2C_CR_SLAVE_EN_MASK ~CDNS_I2C_CR_MASTER_EN_MASK
|
||||
|
||||
/* Status Register Bit mask definitions */
|
||||
#define CDNS_I2C_SR_BA BIT(8)
|
||||
#define CDNS_I2C_SR_TXDV BIT(6)
|
||||
#define CDNS_I2C_SR_RXDV BIT(5)
|
||||
#define CDNS_I2C_SR_RXRW BIT(3)
|
||||
|
||||
/*
|
||||
* I2C Address Register Bit mask definitions
|
||||
|
@ -91,6 +100,14 @@
|
|||
CDNS_I2C_IXR_DATA | \
|
||||
CDNS_I2C_IXR_COMP)
|
||||
|
||||
#define CDNS_I2C_IXR_SLAVE_INTR_MASK (CDNS_I2C_IXR_RX_UNF | \
|
||||
CDNS_I2C_IXR_TX_OVF | \
|
||||
CDNS_I2C_IXR_RX_OVF | \
|
||||
CDNS_I2C_IXR_TO | \
|
||||
CDNS_I2C_IXR_NACK | \
|
||||
CDNS_I2C_IXR_DATA | \
|
||||
CDNS_I2C_IXR_COMP)
|
||||
|
||||
#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
|
||||
/* timeout for pm runtime autosuspend */
|
||||
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
|
||||
|
@ -114,6 +131,32 @@
|
|||
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
|
||||
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
/**
|
||||
* enum cdns_i2c_mode - I2C Controller current operating mode
|
||||
*
|
||||
* @CDNS_I2C_MODE_SLAVE: I2C controller operating in slave mode
|
||||
* @CDNS_I2C_MODE_MASTER: I2C Controller operating in master mode
|
||||
*/
|
||||
enum cdns_i2c_mode {
|
||||
CDNS_I2C_MODE_SLAVE,
|
||||
CDNS_I2C_MODE_MASTER,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cdns_i2c_slave_mode - Slave state when I2C is operating in slave mode
|
||||
*
|
||||
* @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle
|
||||
* @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master
|
||||
* @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master
|
||||
*/
|
||||
enum cdns_i2c_slave_state {
|
||||
CDNS_I2C_SLAVE_STATE_IDLE,
|
||||
CDNS_I2C_SLAVE_STATE_SEND,
|
||||
CDNS_I2C_SLAVE_STATE_RECV,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct cdns_i2c - I2C device private data structure
|
||||
*
|
||||
|
@ -135,6 +178,10 @@
|
|||
* @clk: Pointer to struct clk
|
||||
* @clk_rate_change_nb: Notifier block for clock rate changes
|
||||
* @quirks: flag for broken hold bit usage in r1p10
|
||||
* @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
|
||||
* @slave: Registered slave instance.
|
||||
* @dev_mode: I2C operating role(master/slave).
|
||||
* @slave_state: I2C Slave state(idle/read/write).
|
||||
*/
|
||||
struct cdns_i2c {
|
||||
struct device *dev;
|
||||
|
@ -155,6 +202,12 @@ struct cdns_i2c {
|
|||
struct clk *clk;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
u32 quirks;
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
u16 ctrl_reg_diva_divb;
|
||||
struct i2c_client *slave;
|
||||
enum cdns_i2c_mode dev_mode;
|
||||
enum cdns_i2c_slave_state slave_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct cdns_platform_data {
|
||||
|
@ -183,17 +236,155 @@ static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
|
|||
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
static void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c *id)
|
||||
{
|
||||
/* Disable all interrupts */
|
||||
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
|
||||
|
||||
/* Clear FIFO and transfer size */
|
||||
cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
|
||||
|
||||
/* Update device mode and state */
|
||||
id->dev_mode = mode;
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||
|
||||
switch (mode) {
|
||||
case CDNS_I2C_MODE_MASTER:
|
||||
/* Enable i2c master */
|
||||
cdns_i2c_writereg(id->ctrl_reg_diva_divb |
|
||||
CDNS_I2C_CR_MASTER_EN_MASK,
|
||||
CDNS_I2C_CR_OFFSET);
|
||||
/*
|
||||
* This delay is needed to give the IP some time to switch to
|
||||
* the master mode. With lower values(like 110 us) i2cdetect
|
||||
* will not detect any slave and without this delay, the IP will
|
||||
* trigger a timeout interrupt.
|
||||
*/
|
||||
usleep_range(115, 125);
|
||||
break;
|
||||
case CDNS_I2C_MODE_SLAVE:
|
||||
/* Enable i2c slave */
|
||||
cdns_i2c_writereg(id->ctrl_reg_diva_divb &
|
||||
CDNS_I2C_CR_SLAVE_EN_MASK,
|
||||
CDNS_I2C_CR_OFFSET);
|
||||
|
||||
/* Setting slave address */
|
||||
cdns_i2c_writereg(id->slave->addr & CDNS_I2C_ADDR_MASK,
|
||||
CDNS_I2C_ADDR_OFFSET);
|
||||
|
||||
/* Enable slave send/receive interrupts */
|
||||
cdns_i2c_writereg(CDNS_I2C_IXR_SLAVE_INTR_MASK,
|
||||
CDNS_I2C_IER_OFFSET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdns_i2c_slave_rcv_data(struct cdns_i2c *id)
|
||||
{
|
||||
u8 bytes;
|
||||
unsigned char data;
|
||||
|
||||
/* Prepare backend for data reception */
|
||||
if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_RECV;
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_WRITE_REQUESTED, NULL);
|
||||
}
|
||||
|
||||
/* Fetch number of bytes to receive */
|
||||
bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
|
||||
/* Read data and send to backend */
|
||||
while (bytes--) {
|
||||
data = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_WRITE_RECEIVED, &data);
|
||||
}
|
||||
}
|
||||
|
||||
static void cdns_i2c_slave_send_data(struct cdns_i2c *id)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
/* Prepare backend for data transmission */
|
||||
if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_SEND;
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_READ_REQUESTED, &data);
|
||||
} else {
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_READ_PROCESSED, &data);
|
||||
}
|
||||
|
||||
/* Send data over bus */
|
||||
cdns_i2c_writereg(data, CDNS_I2C_DATA_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_i2c_isr - Interrupt handler for the I2C device
|
||||
* @irq: irq number for the I2C device
|
||||
* @ptr: void pointer to cdns_i2c structure
|
||||
* cdns_i2c_slave_isr - Interrupt handler for the I2C device in slave role
|
||||
* @ptr: Pointer to I2C device private data
|
||||
*
|
||||
* This function handles the data interrupt, transfer complete interrupt and
|
||||
* the error interrupts of the I2C device.
|
||||
* This function handles the data interrupt and transfer complete interrupt of
|
||||
* the I2C device in slave role.
|
||||
*
|
||||
* Return: IRQ_HANDLED always
|
||||
*/
|
||||
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
static irqreturn_t cdns_i2c_slave_isr(void *ptr)
|
||||
{
|
||||
struct cdns_i2c *id = ptr;
|
||||
unsigned int isr_status, i2c_status;
|
||||
|
||||
/* Fetch the interrupt status */
|
||||
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
|
||||
|
||||
/* Ignore masked interrupts */
|
||||
isr_status &= ~cdns_i2c_readreg(CDNS_I2C_IMR_OFFSET);
|
||||
|
||||
/* Fetch transfer mode (send/receive) */
|
||||
i2c_status = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
|
||||
|
||||
/* Handle data send/receive */
|
||||
if (i2c_status & CDNS_I2C_SR_RXRW) {
|
||||
/* Send data to master */
|
||||
if (isr_status & CDNS_I2C_IXR_DATA)
|
||||
cdns_i2c_slave_send_data(id);
|
||||
|
||||
if (isr_status & CDNS_I2C_IXR_COMP) {
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
|
||||
}
|
||||
} else {
|
||||
/* Receive data from master */
|
||||
if (isr_status & CDNS_I2C_IXR_DATA)
|
||||
cdns_i2c_slave_rcv_data(id);
|
||||
|
||||
if (isr_status & CDNS_I2C_IXR_COMP) {
|
||||
cdns_i2c_slave_rcv_data(id);
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Master indicated xfer stop or fifo underflow/overflow */
|
||||
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF |
|
||||
CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) {
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
|
||||
cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cdns_i2c_master_isr - Interrupt handler for the I2C device in master role
|
||||
* @ptr: Pointer to I2C device private data
|
||||
*
|
||||
* This function handles the data interrupt, transfer complete interrupt and
|
||||
* the error interrupts of the I2C device in master role.
|
||||
*
|
||||
* Return: IRQ_HANDLED always
|
||||
*/
|
||||
static irqreturn_t cdns_i2c_master_isr(void *ptr)
|
||||
{
|
||||
unsigned int isr_status, avail_bytes, updatetx;
|
||||
unsigned int bytes_to_send;
|
||||
|
@ -357,6 +548,27 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_i2c_isr - Interrupt handler for the I2C device
|
||||
* @irq: irq number for the I2C device
|
||||
* @ptr: void pointer to cdns_i2c structure
|
||||
*
|
||||
* This function passes the control to slave/master based on current role of
|
||||
* i2c controller.
|
||||
*
|
||||
* Return: IRQ_HANDLED always
|
||||
*/
|
||||
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
struct cdns_i2c *id = ptr;
|
||||
|
||||
if (id->dev_mode == CDNS_I2C_MODE_SLAVE)
|
||||
return cdns_i2c_slave_isr(ptr);
|
||||
#endif
|
||||
return cdns_i2c_master_isr(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_i2c_mrecv - Prepare and start a master receive operation
|
||||
* @id: pointer to the i2c device structure
|
||||
|
@ -577,10 +789,28 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
u32 reg;
|
||||
struct cdns_i2c *id = adap->algo_data;
|
||||
bool hold_quirk;
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
bool change_role = false;
|
||||
#endif
|
||||
|
||||
ret = pm_runtime_get_sync(id->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
/* Check i2c operating mode and switch if possible */
|
||||
if (id->dev_mode == CDNS_I2C_MODE_SLAVE) {
|
||||
if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Set mode to master */
|
||||
cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
|
||||
|
||||
/* Mark flag to change role once xfer is completed */
|
||||
change_role = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if the bus is free */
|
||||
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
|
||||
ret = -EAGAIN;
|
||||
|
@ -639,7 +869,15 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
}
|
||||
|
||||
ret = num;
|
||||
|
||||
out:
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
/* Switch i2c mode to slave */
|
||||
if (change_role)
|
||||
cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
|
||||
#endif
|
||||
|
||||
pm_runtime_mark_last_busy(id->dev);
|
||||
pm_runtime_put_autosuspend(id->dev);
|
||||
return ret;
|
||||
|
@ -653,14 +891,67 @@ out:
|
|||
*/
|
||||
static u32 cdns_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
|
||||
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
|
||||
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
func |= I2C_FUNC_SLAVE;
|
||||
#endif
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
static int cdns_reg_slave(struct i2c_client *slave)
|
||||
{
|
||||
int ret;
|
||||
struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c,
|
||||
adap);
|
||||
|
||||
if (id->slave)
|
||||
return -EBUSY;
|
||||
|
||||
if (slave->flags & I2C_CLIENT_TEN)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
ret = pm_runtime_get_sync(id->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Store slave information */
|
||||
id->slave = slave;
|
||||
|
||||
/* Enable I2C slave */
|
||||
cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_unreg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct cdns_i2c *id = container_of(slave->adapter, struct cdns_i2c,
|
||||
adap);
|
||||
|
||||
pm_runtime_put(id->dev);
|
||||
|
||||
/* Remove slave information */
|
||||
id->slave = NULL;
|
||||
|
||||
/* Enable I2C master */
|
||||
cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct i2c_algorithm cdns_i2c_algo = {
|
||||
.master_xfer = cdns_i2c_master_xfer,
|
||||
.functionality = cdns_i2c_func,
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
.reg_slave = cdns_reg_slave,
|
||||
.unreg_slave = cdns_unreg_slave,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -755,7 +1046,10 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
|
|||
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
|
||||
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
|
||||
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
|
||||
CDNS_I2C_CR_DIVB_MASK);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -906,8 +1200,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
id->quirks = data->quirks;
|
||||
}
|
||||
|
||||
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
|
||||
id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem);
|
||||
if (IS_ERR(id->membase))
|
||||
return PTR_ERR(id->membase);
|
||||
|
||||
|
@ -949,8 +1242,12 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
if (ret || (id->i2c_clk > I2C_MAX_FAST_MODE_FREQ))
|
||||
id->i2c_clk = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
|
||||
CDNS_I2C_CR_OFFSET);
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
/* Set initial mode to master */
|
||||
id->dev_mode = CDNS_I2C_MODE_MASTER;
|
||||
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
|
||||
#endif
|
||||
cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, CDNS_I2C_CR_OFFSET);
|
||||
|
||||
ret = cdns_i2c_setclk(id->input_clk, id);
|
||||
if (ret) {
|
||||
|
|
|
@ -314,10 +314,8 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
|||
int ret, reg, irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Error missing irq resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
|
||||
if (!adap)
|
||||
|
|
|
@ -761,7 +761,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct davinci_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *mem;
|
||||
struct i2c_bus_recovery_info *rinfo;
|
||||
int r, irq;
|
||||
|
||||
|
@ -814,8 +813,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(dev->clk))
|
||||
return PTR_ERR(dev->clk);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
dev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(dev->base)) {
|
||||
return PTR_ERR(dev->base);
|
||||
}
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
* Copyright (C) 2007 MontaVista Software Inc.
|
||||
* Copyright (C) 2009 Provigent Ltd.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/swab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
|
@ -53,69 +58,267 @@ static char *abort_sources[] = {
|
|||
"incorrect slave-transmitter mode configuration",
|
||||
};
|
||||
|
||||
u32 dw_readl(struct dw_i2c_dev *dev, int offset)
|
||||
static int dw_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
u32 value;
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
if (dev->flags & ACCESS_16BIT)
|
||||
value = readw_relaxed(dev->base + offset) |
|
||||
(readw_relaxed(dev->base + offset + 2) << 16);
|
||||
else
|
||||
value = readl_relaxed(dev->base + offset);
|
||||
*val = readl_relaxed(dev->base + reg);
|
||||
|
||||
if (dev->flags & ACCESS_SWAP)
|
||||
return swab32(value);
|
||||
else
|
||||
return value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
|
||||
static int dw_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
if (dev->flags & ACCESS_SWAP)
|
||||
b = swab32(b);
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
if (dev->flags & ACCESS_16BIT) {
|
||||
writew_relaxed((u16)b, dev->base + offset);
|
||||
writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
|
||||
} else {
|
||||
writel_relaxed(b, dev->base + offset);
|
||||
}
|
||||
writel_relaxed(val, dev->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_reg_read_swab(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
*val = swab32(readl_relaxed(dev->base + reg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_reg_write_swab(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
writel_relaxed(swab32(val), dev->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_reg_read_word(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
*val = readw_relaxed(dev->base + reg) |
|
||||
(readw_relaxed(dev->base + reg + 2) << 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
writew_relaxed(val, dev->base + reg);
|
||||
writew_relaxed(val >> 16, dev->base + reg + 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dw_set_reg_access() - Set register access flags
|
||||
* i2c_dw_init_regmap() - Initialize registers map
|
||||
* @dev: device private data
|
||||
*
|
||||
* Autodetects needed register access mode and sets access flags accordingly.
|
||||
* This must be called before doing any other register access.
|
||||
* Autodetects needed register access mode and creates the regmap with
|
||||
* corresponding read/write callbacks. This must be called before doing any
|
||||
* other register access.
|
||||
*/
|
||||
int i2c_dw_set_reg_access(struct dw_i2c_dev *dev)
|
||||
int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct regmap_config map_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.disable_locking = true,
|
||||
.reg_read = dw_reg_read,
|
||||
.reg_write = dw_reg_write,
|
||||
.max_register = DW_IC_COMP_TYPE,
|
||||
};
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Skip detecting the registers map configuration if the regmap has
|
||||
* already been provided by a higher code.
|
||||
*/
|
||||
if (dev->map)
|
||||
return 0;
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg = dw_readl(dev, DW_IC_COMP_TYPE);
|
||||
reg = readl(dev->base + DW_IC_COMP_TYPE);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
|
||||
/* Configure register endianness access */
|
||||
dev->flags |= ACCESS_SWAP;
|
||||
map_cfg.reg_read = dw_reg_read_swab;
|
||||
map_cfg.reg_write = dw_reg_write_swab;
|
||||
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
|
||||
/* Configure register access mode 16bit */
|
||||
dev->flags |= ACCESS_16BIT;
|
||||
map_cfg.reg_read = dw_reg_read_word;
|
||||
map_cfg.reg_write = dw_reg_write_word;
|
||||
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
|
||||
dev_err(dev->dev,
|
||||
"Unknown Synopsys component type: 0x%08x\n", reg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note we'll check the return value of the regmap IO accessors only
|
||||
* at the probe stage. The rest of the code won't do this because
|
||||
* basically we have MMIO-based regmap so non of the read/write methods
|
||||
* can fail.
|
||||
*/
|
||||
dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg);
|
||||
if (IS_ERR(dev->map)) {
|
||||
dev_err(dev->dev, "Failed to init the registers map\n");
|
||||
return PTR_ERR(dev->map);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u32 supported_speeds[] = {
|
||||
I2C_MAX_HIGH_SPEED_MODE_FREQ,
|
||||
I2C_MAX_FAST_MODE_PLUS_FREQ,
|
||||
I2C_MAX_FAST_MODE_FREQ,
|
||||
I2C_MAX_STANDARD_MODE_FREQ,
|
||||
};
|
||||
|
||||
int i2c_dw_validate_speed(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Only standard mode at 100kHz, fast mode at 400kHz,
|
||||
* fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
|
||||
if (t->bus_freq_hz == supported_speeds[i])
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(dev->dev,
|
||||
"%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n",
|
||||
t->bus_freq_hz);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_validate_speed);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
#include <linux/dmi.h>
|
||||
|
||||
/*
|
||||
* The HCNT/LCNT information coming from ACPI should be the most accurate
|
||||
* for given platform. However, some systems get it wrong. On such systems
|
||||
* we get better results by calculating those based on the input clock.
|
||||
*/
|
||||
static const struct dmi_system_id i2c_dw_no_acpi_params[] = {
|
||||
{
|
||||
.ident = "Dell Inspiron 7348",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7348"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static void i2c_dw_acpi_params(struct device *device, char method[],
|
||||
u16 *hcnt, u16 *lcnt, u32 *sda_hold)
|
||||
{
|
||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||
acpi_handle handle = ACPI_HANDLE(device);
|
||||
union acpi_object *obj;
|
||||
|
||||
if (dmi_check_system(i2c_dw_no_acpi_params))
|
||||
return;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
|
||||
return;
|
||||
|
||||
obj = (union acpi_object *)buf.pointer;
|
||||
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
|
||||
const union acpi_object *objs = obj->package.elements;
|
||||
|
||||
*hcnt = (u16)objs[0].integer.value;
|
||||
*lcnt = (u16)objs[1].integer.value;
|
||||
*sda_hold = (u32)objs[2].integer.value;
|
||||
}
|
||||
|
||||
kfree(buf.pointer);
|
||||
}
|
||||
|
||||
int i2c_dw_acpi_configure(struct device *device)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_get_drvdata(device);
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
|
||||
|
||||
/*
|
||||
* Try to get SDA hold time and *CNT values from an ACPI method for
|
||||
* selected speed modes.
|
||||
*/
|
||||
i2c_dw_acpi_params(device, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht);
|
||||
i2c_dw_acpi_params(device, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht);
|
||||
i2c_dw_acpi_params(device, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht);
|
||||
i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);
|
||||
|
||||
switch (t->bus_freq_hz) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
dev->sda_hold_time = ss_ht;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_PLUS_FREQ:
|
||||
dev->sda_hold_time = fp_ht;
|
||||
break;
|
||||
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
|
||||
dev->sda_hold_time = hs_ht;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_FREQ:
|
||||
default:
|
||||
dev->sda_hold_time = fs_ht;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_acpi_configure);
|
||||
|
||||
void i2c_dw_acpi_adjust_bus_speed(struct device *device)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_get_drvdata(device);
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
u32 acpi_speed;
|
||||
int i;
|
||||
|
||||
acpi_speed = i2c_acpi_find_bus_speed(device);
|
||||
/*
|
||||
* Some DSTDs use a non standard speed, round down to the lowest
|
||||
* standard speed.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
|
||||
if (acpi_speed >= supported_speeds[i])
|
||||
break;
|
||||
}
|
||||
acpi_speed = i < ARRAY_SIZE(supported_speeds) ? supported_speeds[i] : 0;
|
||||
|
||||
/*
|
||||
* Find bus speed from the "clock-frequency" device property, ACPI
|
||||
* or by using fast mode if neither is set.
|
||||
*/
|
||||
if (acpi_speed && t->bus_freq_hz)
|
||||
t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
|
||||
else if (acpi_speed || t->bus_freq_hz)
|
||||
t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
|
||||
else
|
||||
t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_acpi_adjust_bus_speed);
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
|
||||
{
|
||||
/*
|
||||
|
@ -181,11 +384,17 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
|
|||
return ret;
|
||||
|
||||
/* Configure SDA Hold Time if required */
|
||||
reg = dw_readl(dev, DW_IC_COMP_VERSION);
|
||||
ret = regmap_read(dev->map, DW_IC_COMP_VERSION, ®);
|
||||
if (ret)
|
||||
goto err_release_lock;
|
||||
|
||||
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
|
||||
if (!dev->sda_hold_time) {
|
||||
/* Keep previous hold time setting if no one set it */
|
||||
dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
|
||||
ret = regmap_read(dev->map, DW_IC_SDA_HOLD,
|
||||
&dev->sda_hold_time);
|
||||
if (ret)
|
||||
goto err_release_lock;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -209,14 +418,16 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
|
|||
dev->sda_hold_time = 0;
|
||||
}
|
||||
|
||||
err_release_lock:
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int timeout = 100;
|
||||
u32 status;
|
||||
|
||||
do {
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
|
@ -224,7 +435,8 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
|
|||
* The enable status register may be unimplemented, but
|
||||
* in that case this test reads zero and exits the loop.
|
||||
*/
|
||||
if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0)
|
||||
regmap_read(dev->map, DW_IC_ENABLE_STATUS, &status);
|
||||
if ((status & 1) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -303,22 +515,23 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev)
|
|||
*/
|
||||
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int timeout = TIMEOUT;
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
|
||||
if (timeout <= 0) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
|
||||
!(status & DW_IC_STATUS_ACTIVITY),
|
||||
1100, 20000);
|
||||
if (ret) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
|
||||
if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
timeout--;
|
||||
usleep_range(1000, 1100);
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
|
||||
regmap_read(dev->map, DW_IC_STATUS, &status);
|
||||
if (!(status & DW_IC_STATUS_ACTIVITY))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
|
||||
|
@ -344,15 +557,19 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
||||
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 param, tx_fifo_depth, rx_fifo_depth;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Try to detect the FIFO depth if not set by interface driver,
|
||||
* the depth could be from 2 to 256 from HW spec.
|
||||
*/
|
||||
param = dw_readl(dev, DW_IC_COMP_PARAM_1);
|
||||
ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, ¶m);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tx_fifo_depth = ((param >> 16) & 0xff) + 1;
|
||||
rx_fifo_depth = ((param >> 8) & 0xff) + 1;
|
||||
if (!dev->tx_fifo_depth) {
|
||||
|
@ -364,6 +581,8 @@ void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
|||
dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
|
||||
rx_fifo_depth);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 i2c_dw_func(struct i2c_adapter *adap)
|
||||
|
@ -375,17 +594,19 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
|
|||
|
||||
void i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 dummy;
|
||||
|
||||
/* Disable controller */
|
||||
__i2c_dw_disable(dev);
|
||||
|
||||
/* Disable all interrupts */
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
dw_readl(dev, DW_IC_CLR_INTR);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
|
||||
regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
|
||||
}
|
||||
|
||||
void i2c_dw_disable_int(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
|
||||
|
|
|
@ -9,7 +9,14 @@
|
|||
* Copyright (C) 2009 Provigent Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/compiler_types.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
|
||||
I2C_FUNC_SMBUS_BYTE | \
|
||||
|
@ -120,8 +127,6 @@
|
|||
#define STATUS_WRITE_IN_PROGRESS 0x1
|
||||
#define STATUS_READ_IN_PROGRESS 0x2
|
||||
|
||||
#define TIMEOUT 20 /* ms */
|
||||
|
||||
/*
|
||||
* operation modes
|
||||
*/
|
||||
|
@ -170,11 +175,17 @@
|
|||
DW_IC_TX_ABRT_TXDATA_NOACK | \
|
||||
DW_IC_TX_ABRT_GCALL_NOACK)
|
||||
|
||||
struct clk;
|
||||
struct device;
|
||||
struct reset_control;
|
||||
|
||||
/**
|
||||
* struct dw_i2c_dev - private i2c-designware data
|
||||
* @dev: driver model device node
|
||||
* @map: IO registers map
|
||||
* @sysmap: System controller registers map
|
||||
* @base: IO registers pointer
|
||||
* @ext: Extended IO registers pointer
|
||||
* @cmd_complete: tx completion indicator
|
||||
* @clk: input reference clock
|
||||
* @pclk: clock required to access the registers
|
||||
|
@ -224,6 +235,8 @@
|
|||
*/
|
||||
struct dw_i2c_dev {
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
struct regmap *sysmap;
|
||||
void __iomem *base;
|
||||
void __iomem *ext;
|
||||
struct completion cmd_complete;
|
||||
|
@ -232,7 +245,6 @@ struct dw_i2c_dev {
|
|||
struct reset_control *rst;
|
||||
struct i2c_client *slave;
|
||||
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
|
||||
struct dw_pci_controller *controller;
|
||||
int cmd_err;
|
||||
struct i2c_msg *msgs;
|
||||
int msgs_num;
|
||||
|
@ -276,18 +288,14 @@ struct dw_i2c_dev {
|
|||
bool suspended;
|
||||
};
|
||||
|
||||
#define ACCESS_SWAP 0x00000001
|
||||
#define ACCESS_16BIT 0x00000002
|
||||
#define ACCESS_INTR_MASK 0x00000004
|
||||
#define ACCESS_NO_IRQ_SUSPEND 0x00000008
|
||||
#define ACCESS_INTR_MASK 0x00000001
|
||||
#define ACCESS_NO_IRQ_SUSPEND 0x00000002
|
||||
|
||||
#define MODEL_CHERRYTRAIL 0x00000100
|
||||
#define MODEL_MSCC_OCELOT 0x00000200
|
||||
#define MODEL_MSCC_OCELOT 0x00000100
|
||||
#define MODEL_BAIKAL_BT1 0x00000200
|
||||
#define MODEL_MASK 0x00000f00
|
||||
|
||||
u32 dw_readl(struct dw_i2c_dev *dev, int offset);
|
||||
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
|
||||
int i2c_dw_set_reg_access(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
|
||||
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
|
||||
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
|
||||
|
@ -297,32 +305,67 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
|
|||
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_func(struct i2c_adapter *adap);
|
||||
void i2c_dw_disable(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_disable_int(struct dw_i2c_dev *dev);
|
||||
|
||||
static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dw_writel(dev, 1, DW_IC_ENABLE);
|
||||
regmap_write(dev->map, DW_IC_ENABLE, 1);
|
||||
}
|
||||
|
||||
static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dw_writel(dev, 0, DW_IC_ENABLE);
|
||||
regmap_write(dev->map, DW_IC_ENABLE, 0);
|
||||
}
|
||||
|
||||
void __i2c_dw_disable(struct dw_i2c_dev *dev);
|
||||
|
||||
extern int i2c_dw_probe(struct dw_i2c_dev *dev);
|
||||
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
|
||||
extern int i2c_dw_probe_master(struct dw_i2c_dev *dev);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE)
|
||||
extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev);
|
||||
extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
|
||||
#else
|
||||
static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { }
|
||||
static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
|
||||
#endif
|
||||
|
||||
static inline int i2c_dw_probe(struct dw_i2c_dev *dev)
|
||||
{
|
||||
switch (dev->mode) {
|
||||
case DW_IC_SLAVE:
|
||||
return i2c_dw_probe_slave(dev);
|
||||
case DW_IC_MASTER:
|
||||
return i2c_dw_probe_master(dev);
|
||||
default:
|
||||
dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
|
||||
{
|
||||
if (i2c_detect_slave_mode(dev->dev))
|
||||
i2c_dw_configure_slave(dev);
|
||||
else
|
||||
i2c_dw_configure_master(dev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
|
||||
extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev);
|
||||
#else
|
||||
static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; }
|
||||
#endif
|
||||
|
||||
int i2c_dw_validate_speed(struct dw_i2c_dev *dev);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
int i2c_dw_acpi_configure(struct device *device);
|
||||
void i2c_dw_acpi_adjust_bus_speed(struct device *device);
|
||||
#else
|
||||
static inline int i2c_dw_acpi_configure(struct device *device) { return -ENODEV; }
|
||||
static inline void i2c_dw_acpi_adjust_bus_speed(struct device *device) {}
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
|
@ -25,11 +26,11 @@
|
|||
static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
/* Configure Tx/Rx FIFO threshold levels */
|
||||
dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
|
||||
dw_writel(dev, 0, DW_IC_RX_TL);
|
||||
regmap_write(dev->map, DW_IC_TX_TL, dev->tx_fifo_depth / 2);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
|
||||
/* Configure the I2C master */
|
||||
dw_writel(dev, dev->master_cfg, DW_IC_CON);
|
||||
regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
|
||||
}
|
||||
|
||||
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
||||
|
@ -44,8 +45,11 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
|||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
|
||||
|
||||
ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, &comp_param1);
|
||||
i2c_dw_release_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set standard and fast speed dividers for high/low periods */
|
||||
sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
|
||||
|
@ -76,14 +80,27 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
|||
*/
|
||||
if (t->bus_freq_hz == 1000000) {
|
||||
/*
|
||||
* Check are fast mode plus parameters available and use
|
||||
* fast mode if not.
|
||||
* Check are Fast Mode Plus parameters available. Calculate
|
||||
* SCL timing parameters for Fast Mode Plus if not set.
|
||||
*/
|
||||
if (dev->fp_hcnt && dev->fp_lcnt) {
|
||||
dev->fs_hcnt = dev->fp_hcnt;
|
||||
dev->fs_lcnt = dev->fp_lcnt;
|
||||
fp_str = " Plus";
|
||||
} else {
|
||||
ic_clk = i2c_dw_clk_rate(dev);
|
||||
dev->fs_hcnt =
|
||||
i2c_dw_scl_hcnt(ic_clk,
|
||||
260, /* tHIGH = 260 ns */
|
||||
sda_falling_time,
|
||||
0, /* DW default */
|
||||
0); /* No offset */
|
||||
dev->fs_lcnt =
|
||||
i2c_dw_scl_lcnt(ic_clk,
|
||||
500, /* tLOW = 500 ns */
|
||||
scl_falling_time,
|
||||
0); /* No offset */
|
||||
}
|
||||
fp_str = " Plus";
|
||||
}
|
||||
/*
|
||||
* Calculate SCL timing parameters for fast mode if not set. They are
|
||||
|
@ -116,10 +133,22 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
|||
dev->master_cfg |= DW_IC_CON_SPEED_FAST;
|
||||
dev->hs_hcnt = 0;
|
||||
dev->hs_lcnt = 0;
|
||||
} else if (dev->hs_hcnt && dev->hs_lcnt) {
|
||||
dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
|
||||
dev->hs_hcnt, dev->hs_lcnt);
|
||||
} else if (!dev->hs_hcnt || !dev->hs_lcnt) {
|
||||
ic_clk = i2c_dw_clk_rate(dev);
|
||||
dev->hs_hcnt =
|
||||
i2c_dw_scl_hcnt(ic_clk,
|
||||
160, /* tHIGH = 160 ns */
|
||||
sda_falling_time,
|
||||
0, /* DW default */
|
||||
0); /* No offset */
|
||||
dev->hs_lcnt =
|
||||
i2c_dw_scl_lcnt(ic_clk,
|
||||
320, /* tLOW = 320 ns */
|
||||
scl_falling_time,
|
||||
0); /* No offset */
|
||||
}
|
||||
dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
|
||||
dev->hs_hcnt, dev->hs_lcnt);
|
||||
}
|
||||
|
||||
ret = i2c_dw_set_sda_hold(dev);
|
||||
|
@ -162,22 +191,22 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
|
|||
__i2c_dw_disable(dev);
|
||||
|
||||
/* Write standard speed timing parameters */
|
||||
dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
|
||||
dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt);
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);
|
||||
|
||||
/* Write fast mode/fast mode plus timing parameters */
|
||||
dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT);
|
||||
dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT);
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_HCNT, dev->fs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_LCNT, dev->fs_lcnt);
|
||||
|
||||
/* Write high speed timing parameters if supported */
|
||||
if (dev->hs_hcnt && dev->hs_lcnt) {
|
||||
dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT);
|
||||
dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT);
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_HCNT, dev->hs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_LCNT, dev->hs_lcnt);
|
||||
}
|
||||
|
||||
/* Write SDA hold time if supported */
|
||||
if (dev->sda_hold_time)
|
||||
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
|
||||
regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
|
||||
|
||||
i2c_dw_configure_fifo_master(dev);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
@ -188,15 +217,15 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
|
|||
static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
u32 ic_con, ic_tar = 0;
|
||||
u32 ic_con = 0, ic_tar = 0;
|
||||
u32 dummy;
|
||||
|
||||
/* Disable the adapter */
|
||||
__i2c_dw_disable(dev);
|
||||
|
||||
/* If the slave address is ten bit address, enable 10BITADDR */
|
||||
ic_con = dw_readl(dev, DW_IC_CON);
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
|
||||
ic_con |= DW_IC_CON_10BITADDR_MASTER;
|
||||
ic_con = DW_IC_CON_10BITADDR_MASTER;
|
||||
/*
|
||||
* If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
|
||||
* mode has to be enabled via bit 12 of IC_TAR register.
|
||||
|
@ -204,17 +233,17 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
|||
* detected from registers.
|
||||
*/
|
||||
ic_tar = DW_IC_TAR_10BITADDR_MASTER;
|
||||
} else {
|
||||
ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
|
||||
}
|
||||
|
||||
dw_writel(dev, ic_con, DW_IC_CON);
|
||||
regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER,
|
||||
ic_con);
|
||||
|
||||
/*
|
||||
* Set the slave (target) address and enable 10-bit addressing mode
|
||||
* if applicable.
|
||||
*/
|
||||
dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
|
||||
regmap_write(dev->map, DW_IC_TAR,
|
||||
msgs[dev->msg_write_idx].addr | ic_tar);
|
||||
|
||||
/* Enforce disabled interrupts (due to HW issues) */
|
||||
i2c_dw_disable_int(dev);
|
||||
|
@ -223,11 +252,11 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
|||
__i2c_dw_enable(dev);
|
||||
|
||||
/* Dummy read to avoid the register getting stuck on Bay Trail */
|
||||
dw_readl(dev, DW_IC_ENABLE_STATUS);
|
||||
regmap_read(dev->map, DW_IC_ENABLE_STATUS, &dummy);
|
||||
|
||||
/* Clear and enable interrupts */
|
||||
dw_readl(dev, DW_IC_CLR_INTR);
|
||||
dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
|
||||
regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -246,6 +275,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
u32 buf_len = dev->tx_buf_len;
|
||||
u8 *buf = dev->tx_buf;
|
||||
bool need_restart = false;
|
||||
unsigned int flr;
|
||||
|
||||
intr_mask = DW_IC_INTR_MASTER_MASK;
|
||||
|
||||
|
@ -278,8 +308,11 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
need_restart = true;
|
||||
}
|
||||
|
||||
tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
|
||||
rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
|
||||
regmap_read(dev->map, DW_IC_TXFLR, &flr);
|
||||
tx_limit = dev->tx_fifo_depth - flr;
|
||||
|
||||
regmap_read(dev->map, DW_IC_RXFLR, &flr);
|
||||
rx_limit = dev->rx_fifo_depth - flr;
|
||||
|
||||
while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
|
||||
u32 cmd = 0;
|
||||
|
@ -312,11 +345,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
if (dev->rx_outstanding >= dev->rx_fifo_depth)
|
||||
break;
|
||||
|
||||
dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
|
||||
regmap_write(dev->map, DW_IC_DATA_CMD,
|
||||
cmd | 0x100);
|
||||
rx_limit--;
|
||||
dev->rx_outstanding++;
|
||||
} else
|
||||
dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
|
||||
} else {
|
||||
regmap_write(dev->map, DW_IC_DATA_CMD,
|
||||
cmd | *buf++);
|
||||
}
|
||||
tx_limit--; buf_len--;
|
||||
}
|
||||
|
||||
|
@ -346,7 +382,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
if (dev->msg_err)
|
||||
intr_mask = 0;
|
||||
|
||||
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, intr_mask);
|
||||
}
|
||||
|
||||
static u8
|
||||
|
@ -371,10 +407,10 @@ static void
|
|||
i2c_dw_read(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
int rx_valid;
|
||||
unsigned int rx_valid;
|
||||
|
||||
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
|
||||
u32 len;
|
||||
u32 len, tmp;
|
||||
u8 *buf;
|
||||
|
||||
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
|
||||
|
@ -388,18 +424,18 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
|||
buf = dev->rx_buf;
|
||||
}
|
||||
|
||||
rx_valid = dw_readl(dev, DW_IC_RXFLR);
|
||||
regmap_read(dev->map, DW_IC_RXFLR, &rx_valid);
|
||||
|
||||
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
|
||||
u32 flags = msgs[dev->msg_read_idx].flags;
|
||||
|
||||
*buf = dw_readl(dev, DW_IC_DATA_CMD);
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
/* Ensure length byte is a valid value */
|
||||
if (flags & I2C_M_RECV_LEN &&
|
||||
*buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
|
||||
len = i2c_dw_recv_len(dev, *buf);
|
||||
tmp <= I2C_SMBUS_BLOCK_MAX && tmp > 0) {
|
||||
len = i2c_dw_recv_len(dev, tmp);
|
||||
}
|
||||
buf++;
|
||||
*buf++ = tmp;
|
||||
dev->rx_outstanding--;
|
||||
}
|
||||
|
||||
|
@ -517,7 +553,7 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
|
|||
|
||||
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 stat;
|
||||
u32 stat, dummy;
|
||||
|
||||
/*
|
||||
* The IC_INTR_STAT register just indicates "enabled" interrupts.
|
||||
|
@ -525,47 +561,47 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
|||
* in the IC_RAW_INTR_STAT register.
|
||||
*
|
||||
* That is,
|
||||
* stat = dw_readl(IC_INTR_STAT);
|
||||
* stat = readl(IC_INTR_STAT);
|
||||
* equals to,
|
||||
* stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
|
||||
* stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
|
||||
*
|
||||
* The raw version might be useful for debugging purposes.
|
||||
*/
|
||||
stat = dw_readl(dev, DW_IC_INTR_STAT);
|
||||
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
|
||||
|
||||
/*
|
||||
* Do not use the IC_CLR_INTR register to clear interrupts, or
|
||||
* you'll miss some interrupts, triggered during the period from
|
||||
* dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
|
||||
* readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
|
||||
*
|
||||
* Instead, use the separately-prepared IC_CLR_* registers.
|
||||
*/
|
||||
if (stat & DW_IC_INTR_RX_UNDER)
|
||||
dw_readl(dev, DW_IC_CLR_RX_UNDER);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
|
||||
if (stat & DW_IC_INTR_RX_OVER)
|
||||
dw_readl(dev, DW_IC_CLR_RX_OVER);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
|
||||
if (stat & DW_IC_INTR_TX_OVER)
|
||||
dw_readl(dev, DW_IC_CLR_TX_OVER);
|
||||
regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
|
||||
if (stat & DW_IC_INTR_RD_REQ)
|
||||
dw_readl(dev, DW_IC_CLR_RD_REQ);
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &dummy);
|
||||
if (stat & DW_IC_INTR_TX_ABRT) {
|
||||
/*
|
||||
* The IC_TX_ABRT_SOURCE register is cleared whenever
|
||||
* the IC_CLR_TX_ABRT is read. Preserve it beforehand.
|
||||
*/
|
||||
dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
|
||||
dw_readl(dev, DW_IC_CLR_TX_ABRT);
|
||||
regmap_read(dev->map, DW_IC_TX_ABRT_SOURCE, &dev->abort_source);
|
||||
regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
|
||||
}
|
||||
if (stat & DW_IC_INTR_RX_DONE)
|
||||
dw_readl(dev, DW_IC_CLR_RX_DONE);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
|
||||
if (stat & DW_IC_INTR_ACTIVITY)
|
||||
dw_readl(dev, DW_IC_CLR_ACTIVITY);
|
||||
regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
|
||||
if (stat & DW_IC_INTR_STOP_DET)
|
||||
dw_readl(dev, DW_IC_CLR_STOP_DET);
|
||||
regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
|
||||
if (stat & DW_IC_INTR_START_DET)
|
||||
dw_readl(dev, DW_IC_CLR_START_DET);
|
||||
regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
|
||||
if (stat & DW_IC_INTR_GEN_CALL)
|
||||
dw_readl(dev, DW_IC_CLR_GEN_CALL);
|
||||
regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
@ -587,7 +623,7 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
|
|||
* Anytime TX_ABRT is set, the contents of the tx/rx
|
||||
* buffers are flushed. Make sure to skip them.
|
||||
*/
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
|
||||
goto tx_aborted;
|
||||
}
|
||||
|
||||
|
@ -608,9 +644,9 @@ tx_aborted:
|
|||
complete(&dev->cmd_complete);
|
||||
else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
|
||||
/* Workaround to trigger pending interrupt */
|
||||
stat = dw_readl(dev, DW_IC_INTR_MASK);
|
||||
regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
|
||||
i2c_dw_disable_int(dev);
|
||||
dw_writel(dev, stat, DW_IC_INTR_MASK);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, stat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -621,8 +657,8 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
|||
struct dw_i2c_dev *dev = dev_id;
|
||||
u32 stat, enabled;
|
||||
|
||||
enabled = dw_readl(dev, DW_IC_ENABLE);
|
||||
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
|
||||
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
|
||||
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
|
||||
dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
|
||||
if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
|
||||
return IRQ_NONE;
|
||||
|
@ -632,6 +668,30 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void i2c_dw_configure_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
|
||||
dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
|
||||
DW_IC_CON_RESTART_EN;
|
||||
|
||||
dev->mode = DW_IC_MASTER;
|
||||
|
||||
switch (t->bus_freq_hz) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_STD;
|
||||
break;
|
||||
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
|
||||
break;
|
||||
default:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_FAST;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_configure_master);
|
||||
|
||||
static void i2c_dw_prepare_recovery(struct i2c_adapter *adap)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
|
@ -678,7 +738,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int i2c_dw_probe(struct dw_i2c_dev *dev)
|
||||
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
unsigned long irq_flags;
|
||||
|
@ -690,7 +750,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
dev->disable = i2c_dw_disable;
|
||||
dev->disable_int = i2c_dw_disable_int;
|
||||
|
||||
ret = i2c_dw_set_reg_access(dev);
|
||||
ret = i2c_dw_init_regmap(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -698,7 +758,9 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_dw_set_fifo_size(dev);
|
||||
ret = i2c_dw_set_fifo_size(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dev->init(dev);
|
||||
if (ret)
|
||||
|
@ -745,7 +807,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_probe);
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_probe_master);
|
||||
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -46,20 +46,12 @@ struct dw_scl_sda_cfg {
|
|||
|
||||
struct dw_pci_controller {
|
||||
u32 bus_num;
|
||||
u32 bus_cfg;
|
||||
u32 tx_fifo_depth;
|
||||
u32 rx_fifo_depth;
|
||||
u32 clk_khz;
|
||||
u32 functionality;
|
||||
u32 flags;
|
||||
struct dw_scl_sda_cfg *scl_sda_cfg;
|
||||
int (*setup)(struct pci_dev *pdev, struct dw_pci_controller *c);
|
||||
u32 (*get_clk_rate_khz)(struct dw_i2c_dev *dev);
|
||||
};
|
||||
|
||||
#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
|
||||
DW_IC_CON_SLAVE_DISABLE | \
|
||||
DW_IC_CON_RESTART_EN)
|
||||
|
||||
/* Merrifield HCNT/LCNT/SDA hold time */
|
||||
static struct dw_scl_sda_cfg mrfld_config = {
|
||||
.ss_hcnt = 0x2f8,
|
||||
|
@ -86,12 +78,18 @@ static struct dw_scl_sda_cfg hsw_config = {
|
|||
.sda_hold = 0x9,
|
||||
};
|
||||
|
||||
static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return 25000;
|
||||
}
|
||||
|
||||
static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
switch (pdev->device) {
|
||||
case 0x0817:
|
||||
c->bus_cfg &= ~DW_IC_CON_SPEED_MASK;
|
||||
c->bus_cfg |= DW_IC_CON_SPEED_STD;
|
||||
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
/* fall through */
|
||||
case 0x0818:
|
||||
case 0x0819:
|
||||
|
@ -125,57 +123,37 @@ static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static u32 ehl_get_clk_rate_khz(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return 100000;
|
||||
}
|
||||
|
||||
static struct dw_pci_controller dw_pci_controllers[] = {
|
||||
[medfield] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.clk_khz = 25000,
|
||||
.setup = mfld_setup,
|
||||
.get_clk_rate_khz = mfld_get_clk_rate_khz,
|
||||
},
|
||||
[merrifield] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 64,
|
||||
.rx_fifo_depth = 64,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.scl_sda_cfg = &mrfld_config,
|
||||
.setup = mrfld_setup,
|
||||
},
|
||||
[baytrail] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.scl_sda_cfg = &byt_config,
|
||||
},
|
||||
[haswell] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.scl_sda_cfg = &hsw_config,
|
||||
},
|
||||
[cherrytrail] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.flags = MODEL_CHERRYTRAIL,
|
||||
.scl_sda_cfg = &byt_config,
|
||||
},
|
||||
[elkhartlake] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.clk_khz = 100000,
|
||||
.get_clk_rate_khz = ehl_get_clk_rate_khz,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -205,11 +183,6 @@ static int i2c_dw_pci_resume(struct device *dev)
|
|||
static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend,
|
||||
i2c_dw_pci_resume, NULL);
|
||||
|
||||
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return dev->controller->clk_khz;
|
||||
}
|
||||
|
||||
static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
|
@ -250,14 +223,15 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
dev->clk = NULL;
|
||||
dev->controller = controller;
|
||||
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
|
||||
dev->get_clk_rate_khz = controller->get_clk_rate_khz;
|
||||
dev->timings.bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
|
||||
dev->base = pcim_iomap_table(pdev)[0];
|
||||
dev->dev = &pdev->dev;
|
||||
dev->irq = pci_irq_vector(pdev, 0);
|
||||
dev->flags |= controller->flags;
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
if (controller->setup) {
|
||||
r = controller->setup(pdev, controller);
|
||||
if (r) {
|
||||
|
@ -266,10 +240,19 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
dev->functionality = controller->functionality |
|
||||
DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
i2c_dw_acpi_adjust_bus_speed(&pdev->dev);
|
||||
|
||||
if (has_acpi_companion(&pdev->dev))
|
||||
i2c_dw_acpi_configure(&pdev->dev);
|
||||
|
||||
r = i2c_dw_validate_speed(dev);
|
||||
if (r) {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
i2c_dw_configure(dev);
|
||||
|
||||
dev->master_cfg = controller->bus_cfg;
|
||||
if (controller->scl_sda_cfg) {
|
||||
cfg = controller->scl_sda_cfg;
|
||||
dev->ss_hcnt = cfg->ss_hcnt;
|
||||
|
@ -279,11 +262,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
dev->sda_hold_time = cfg->sda_hold;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
dev->tx_fifo_depth = controller->tx_fifo_depth;
|
||||
dev->rx_fifo_depth = controller->rx_fifo_depth;
|
||||
|
||||
adap = &dev->adapter;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = 0;
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/i2c-designware.h>
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -39,91 +40,13 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/*
|
||||
* The HCNT/LCNT information coming from ACPI should be the most accurate
|
||||
* for given platform. However, some systems get it wrong. On such systems
|
||||
* we get better results by calculating those based on the input clock.
|
||||
*/
|
||||
static const struct dmi_system_id dw_i2c_no_acpi_params[] = {
|
||||
{
|
||||
.ident = "Dell Inspiron 7348",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7348"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
|
||||
u16 *hcnt, u16 *lcnt, u32 *sda_hold)
|
||||
{
|
||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
|
||||
union acpi_object *obj;
|
||||
|
||||
if (dmi_check_system(dw_i2c_no_acpi_params))
|
||||
return;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
|
||||
return;
|
||||
|
||||
obj = (union acpi_object *)buf.pointer;
|
||||
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
|
||||
const union acpi_object *objs = obj->package.elements;
|
||||
|
||||
*hcnt = (u16)objs[0].integer.value;
|
||||
*lcnt = (u16)objs[1].integer.value;
|
||||
*sda_hold = (u32)objs[2].integer.value;
|
||||
}
|
||||
|
||||
kfree(buf.pointer);
|
||||
}
|
||||
|
||||
static int dw_i2c_acpi_configure(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
|
||||
|
||||
dev->tx_fifo_depth = 32;
|
||||
dev->rx_fifo_depth = 32;
|
||||
|
||||
/*
|
||||
* Try to get SDA hold time and *CNT values from an ACPI method for
|
||||
* selected speed modes.
|
||||
*/
|
||||
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht);
|
||||
dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht);
|
||||
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht);
|
||||
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);
|
||||
|
||||
switch (t->bus_freq_hz) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
dev->sda_hold_time = ss_ht;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_PLUS_FREQ:
|
||||
dev->sda_hold_time = fp_ht;
|
||||
break;
|
||||
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
|
||||
dev->sda_hold_time = hs_ht;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_FREQ:
|
||||
default:
|
||||
dev->sda_hold_time = fs_ht;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
||||
{ "INT33C2", 0 },
|
||||
{ "INT33C3", 0 },
|
||||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
|
||||
{ "808622C1", ACCESS_NO_IRQ_SUSPEND | MODEL_CHERRYTRAIL },
|
||||
{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
|
||||
{ "AMD0010", ACCESS_INTR_MASK },
|
||||
{ "AMDI0010", ACCESS_INTR_MASK },
|
||||
{ "AMDI0510", 0 },
|
||||
|
@ -134,14 +57,66 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
|||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
|
||||
#else
|
||||
static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#define BT1_I2C_CTL 0x100
|
||||
#define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0)
|
||||
#define BT1_I2C_CTL_WR BIT(8)
|
||||
#define BT1_I2C_CTL_GO BIT(31)
|
||||
#define BT1_I2C_DI 0x104
|
||||
#define BT1_I2C_DO 0x108
|
||||
|
||||
static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note these methods shouldn't ever fail because the system controller
|
||||
* registers are memory mapped. We check the return value just in case.
|
||||
*/
|
||||
ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
|
||||
BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_read(dev->sysmap, BT1_I2C_DO, val);
|
||||
}
|
||||
|
||||
static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(dev->sysmap, BT1_I2C_CTL,
|
||||
BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
|
||||
}
|
||||
|
||||
static struct regmap_config bt1_i2c_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.fast_io = true,
|
||||
.reg_read = bt1_i2c_read,
|
||||
.reg_write = bt1_i2c_write,
|
||||
.max_register = DW_IC_COMP_TYPE,
|
||||
};
|
||||
|
||||
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
|
||||
if (IS_ERR(dev->sysmap))
|
||||
return PTR_ERR(dev->sysmap);
|
||||
|
||||
dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
|
||||
return PTR_ERR_OR_ZERO(dev->map);
|
||||
}
|
||||
|
||||
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
|
||||
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
|
||||
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
|
||||
|
@ -157,12 +132,10 @@ static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
|
|||
static int dw_i2c_of_configure(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_MSCC_OCELOT:
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
dev->ext = devm_ioremap_resource(&pdev->dev, mem);
|
||||
dev->ext = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (!IS_ERR(dev->ext))
|
||||
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
|
||||
break;
|
||||
|
@ -176,49 +149,22 @@ static int dw_i2c_of_configure(struct platform_device *pdev)
|
|||
static const struct of_device_id dw_i2c_of_match[] = {
|
||||
{ .compatible = "snps,designware-i2c", },
|
||||
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
|
||||
{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
|
||||
#else
|
||||
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int dw_i2c_of_configure(struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
|
||||
dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
|
||||
DW_IC_CON_RESTART_EN;
|
||||
|
||||
dev->mode = DW_IC_MASTER;
|
||||
|
||||
switch (t->bus_freq_hz) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_STD;
|
||||
break;
|
||||
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
|
||||
break;
|
||||
default:
|
||||
dev->master_cfg |= DW_IC_CON_SPEED_FAST;
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->functionality = I2C_FUNC_SLAVE | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
|
||||
DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
|
||||
|
||||
dev->mode = DW_IC_SLAVE;
|
||||
}
|
||||
|
||||
static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
|
||||
{
|
||||
pm_runtime_disable(dev->dev);
|
||||
|
@ -227,12 +173,23 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
|
|||
pm_runtime_put_noidle(dev->dev);
|
||||
}
|
||||
|
||||
static const u32 supported_speeds[] = {
|
||||
I2C_MAX_HIGH_SPEED_MODE_FREQ,
|
||||
I2C_MAX_FAST_MODE_PLUS_FREQ,
|
||||
I2C_MAX_FAST_MODE_FREQ,
|
||||
I2C_MAX_STANDARD_MODE_FREQ,
|
||||
};
|
||||
static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev->dev);
|
||||
int ret;
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_BAIKAL_BT1:
|
||||
ret = bt1_i2c_request_regs(dev);
|
||||
break;
|
||||
default:
|
||||
dev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
ret = PTR_ERR_OR_ZERO(dev->base);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_i2c_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -240,9 +197,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
struct i2c_adapter *adap;
|
||||
struct dw_i2c_dev *dev;
|
||||
struct i2c_timings *t;
|
||||
u32 acpi_speed;
|
||||
struct resource *mem;
|
||||
int i, irq, ret;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
@ -252,15 +207,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(dev->base))
|
||||
return PTR_ERR(dev->base);
|
||||
|
||||
dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
|
||||
dev->dev = &pdev->dev;
|
||||
dev->irq = irq;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
ret = dw_i2c_plat_request_regs(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(dev->rst))
|
||||
return PTR_ERR(dev->rst);
|
||||
|
@ -273,60 +228,23 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
else
|
||||
i2c_parse_fw_timings(&pdev->dev, t, false);
|
||||
|
||||
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
|
||||
/*
|
||||
* Some DSTDs use a non standard speed, round down to the lowest
|
||||
* standard speed.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
|
||||
if (acpi_speed >= supported_speeds[i])
|
||||
break;
|
||||
}
|
||||
acpi_speed = i < ARRAY_SIZE(supported_speeds) ? supported_speeds[i] : 0;
|
||||
|
||||
/*
|
||||
* Find bus speed from the "clock-frequency" device property, ACPI
|
||||
* or by using fast mode if neither is set.
|
||||
*/
|
||||
if (acpi_speed && t->bus_freq_hz)
|
||||
t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
|
||||
else if (acpi_speed || t->bus_freq_hz)
|
||||
t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
|
||||
else
|
||||
t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
|
||||
|
||||
dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
|
||||
i2c_dw_acpi_adjust_bus_speed(&pdev->dev);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
dw_i2c_of_configure(pdev);
|
||||
|
||||
if (has_acpi_companion(&pdev->dev))
|
||||
dw_i2c_acpi_configure(pdev);
|
||||
i2c_dw_acpi_configure(&pdev->dev);
|
||||
|
||||
/*
|
||||
* Only standard mode at 100kHz, fast mode at 400kHz,
|
||||
* fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
|
||||
if (t->bus_freq_hz == supported_speeds[i])
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(supported_speeds)) {
|
||||
dev_err(&pdev->dev,
|
||||
"%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n",
|
||||
t->bus_freq_hz);
|
||||
ret = -EINVAL;
|
||||
ret = i2c_dw_validate_speed(dev);
|
||||
if (ret)
|
||||
goto exit_reset;
|
||||
}
|
||||
|
||||
ret = i2c_dw_probe_lock_support(dev);
|
||||
if (ret)
|
||||
goto exit_reset;
|
||||
|
||||
if (i2c_detect_slave_mode(&pdev->dev))
|
||||
i2c_dw_configure_slave(dev);
|
||||
else
|
||||
i2c_dw_configure_master(dev);
|
||||
i2c_dw_configure(dev);
|
||||
|
||||
/* Optional interface clock */
|
||||
dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
|
||||
|
@ -377,11 +295,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
if (dev->mode == DW_IC_SLAVE)
|
||||
ret = i2c_dw_probe_slave(dev);
|
||||
else
|
||||
ret = i2c_dw_probe(dev);
|
||||
|
||||
ret = i2c_dw_probe(dev);
|
||||
if (ret)
|
||||
goto exit_probe;
|
||||
|
||||
|
|
|
@ -14,18 +14,19 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
/* Configure Tx/Rx FIFO threshold levels. */
|
||||
dw_writel(dev, 0, DW_IC_TX_TL);
|
||||
dw_writel(dev, 0, DW_IC_RX_TL);
|
||||
regmap_write(dev->map, DW_IC_TX_TL, 0);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
|
||||
/* Configure the I2C slave. */
|
||||
dw_writel(dev, dev->slave_cfg, DW_IC_CON);
|
||||
dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
|
||||
regmap_write(dev->map, DW_IC_CON, dev->slave_cfg);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_SLAVE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +50,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
|
|||
|
||||
/* Write SDA hold time if supported */
|
||||
if (dev->sda_hold_time)
|
||||
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
|
||||
regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
|
||||
|
||||
i2c_dw_configure_fifo_slave(dev);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
@ -72,7 +73,7 @@ static int i2c_dw_reg_slave(struct i2c_client *slave)
|
|||
* the address to which the DW_apb_i2c responds.
|
||||
*/
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
dw_writel(dev, slave->addr, DW_IC_SAR);
|
||||
regmap_write(dev->map, DW_IC_SAR, slave->addr);
|
||||
dev->slave = slave;
|
||||
|
||||
__i2c_dw_enable(dev);
|
||||
|
@ -103,7 +104,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
|
|||
|
||||
static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 stat;
|
||||
u32 stat, dummy;
|
||||
|
||||
/*
|
||||
* The IC_INTR_STAT register just indicates "enabled" interrupts.
|
||||
|
@ -111,39 +112,39 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
|
|||
* in the IC_RAW_INTR_STAT register.
|
||||
*
|
||||
* That is,
|
||||
* stat = dw_readl(IC_INTR_STAT);
|
||||
* stat = readl(IC_INTR_STAT);
|
||||
* equals to,
|
||||
* stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
|
||||
* stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
|
||||
*
|
||||
* The raw version might be useful for debugging purposes.
|
||||
*/
|
||||
stat = dw_readl(dev, DW_IC_INTR_STAT);
|
||||
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
|
||||
|
||||
/*
|
||||
* Do not use the IC_CLR_INTR register to clear interrupts, or
|
||||
* you'll miss some interrupts, triggered during the period from
|
||||
* dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
|
||||
* readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
|
||||
*
|
||||
* Instead, use the separately-prepared IC_CLR_* registers.
|
||||
*/
|
||||
if (stat & DW_IC_INTR_TX_ABRT)
|
||||
dw_readl(dev, DW_IC_CLR_TX_ABRT);
|
||||
regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
|
||||
if (stat & DW_IC_INTR_RX_UNDER)
|
||||
dw_readl(dev, DW_IC_CLR_RX_UNDER);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
|
||||
if (stat & DW_IC_INTR_RX_OVER)
|
||||
dw_readl(dev, DW_IC_CLR_RX_OVER);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
|
||||
if (stat & DW_IC_INTR_TX_OVER)
|
||||
dw_readl(dev, DW_IC_CLR_TX_OVER);
|
||||
regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
|
||||
if (stat & DW_IC_INTR_RX_DONE)
|
||||
dw_readl(dev, DW_IC_CLR_RX_DONE);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
|
||||
if (stat & DW_IC_INTR_ACTIVITY)
|
||||
dw_readl(dev, DW_IC_CLR_ACTIVITY);
|
||||
regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
|
||||
if (stat & DW_IC_INTR_STOP_DET)
|
||||
dw_readl(dev, DW_IC_CLR_STOP_DET);
|
||||
regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
|
||||
if (stat & DW_IC_INTR_START_DET)
|
||||
dw_readl(dev, DW_IC_CLR_START_DET);
|
||||
regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
|
||||
if (stat & DW_IC_INTR_GEN_CALL)
|
||||
dw_readl(dev, DW_IC_CLR_GEN_CALL);
|
||||
regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
@ -155,14 +156,14 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
|
|||
|
||||
static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 raw_stat, stat, enabled;
|
||||
u8 val, slave_activity;
|
||||
u32 raw_stat, stat, enabled, tmp;
|
||||
u8 val = 0, slave_activity;
|
||||
|
||||
stat = dw_readl(dev, DW_IC_INTR_STAT);
|
||||
enabled = dw_readl(dev, DW_IC_ENABLE);
|
||||
raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
|
||||
slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
|
||||
DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
|
||||
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
|
||||
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
|
||||
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
|
||||
regmap_read(dev->map, DW_IC_STATUS, &tmp);
|
||||
slave_activity = ((tmp & DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
|
||||
|
||||
if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
|
||||
return 0;
|
||||
|
@ -177,7 +178,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
if (stat & DW_IC_INTR_RD_REQ) {
|
||||
if (slave_activity) {
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
val = dw_readl(dev, DW_IC_DATA_CMD);
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_WRITE_RECEIVED,
|
||||
|
@ -185,24 +187,24 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
dev_vdbg(dev->dev, "Byte %X acked!",
|
||||
val);
|
||||
}
|
||||
dw_readl(dev, DW_IC_CLR_RD_REQ);
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
} else {
|
||||
dw_readl(dev, DW_IC_CLR_RD_REQ);
|
||||
dw_readl(dev, DW_IC_CLR_RX_UNDER);
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
}
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_READ_REQUESTED,
|
||||
&val))
|
||||
dw_writel(dev, val, DW_IC_DATA_CMD);
|
||||
regmap_write(dev->map, DW_IC_DATA_CMD, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RX_DONE) {
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
|
||||
&val))
|
||||
dw_readl(dev, DW_IC_CLR_RX_DONE);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
|
||||
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
|
@ -210,7 +212,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
|||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
val = dw_readl(dev, DW_IC_DATA_CMD);
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val))
|
||||
dev_vdbg(dev->dev, "Byte %X acked!", val);
|
||||
|
@ -241,6 +244,17 @@ static const struct i2c_algorithm i2c_dw_algo = {
|
|||
.unreg_slave = i2c_dw_unreg_slave,
|
||||
};
|
||||
|
||||
void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->functionality = I2C_FUNC_SLAVE | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
|
||||
DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
|
||||
|
||||
dev->mode = DW_IC_SLAVE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_configure_slave);
|
||||
|
||||
int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
|
@ -252,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
|
|||
dev->disable = i2c_dw_disable;
|
||||
dev->disable_int = i2c_dw_disable_int;
|
||||
|
||||
ret = i2c_dw_set_reg_access(dev);
|
||||
ret = i2c_dw_init_regmap(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -260,7 +274,9 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_dw_set_fifo_size(dev);
|
||||
ret = i2c_dw_set_fifo_size(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dev->init(dev);
|
||||
if (ret)
|
||||
|
|
|
@ -290,7 +290,6 @@ static int dc_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct dc_i2c *i2c;
|
||||
struct resource *r;
|
||||
int ret = 0, irq;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
|
||||
|
@ -311,8 +310,7 @@ static int dc_i2c_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(i2c->clk))
|
||||
return PTR_ERR(i2c->clk);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, r);
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
return PTR_ERR(i2c->regs);
|
||||
|
||||
|
|
|
@ -312,9 +312,6 @@ static int efm32_i2c_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
u32 clkdiv;
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
@ -352,7 +349,6 @@ static int efm32_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
|
||||
if (!ret)
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
|
|
|
@ -361,15 +361,13 @@ static const struct i2c_algorithm em_i2c_algo = {
|
|||
static int em_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct em_i2c_device *priv;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, r);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
|
|
|
@ -736,7 +736,6 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct exynos5_i2c *i2c;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
|
||||
|
@ -762,8 +761,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs)) {
|
||||
ret = PTR_ERR(i2c->regs);
|
||||
goto err_clk;
|
||||
|
@ -879,6 +877,6 @@ static struct platform_driver exynos5_i2c_driver = {
|
|||
module_platform_driver(exynos5_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Exynos5 HS-I2C Bus driver");
|
||||
MODULE_AUTHOR("Naveen Krishna Chatradhi, <ch.naveen@samsung.com>");
|
||||
MODULE_AUTHOR("Taekgyun Ko, <taeggyun.ko@samsung.com>");
|
||||
MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>");
|
||||
MODULE_AUTHOR("Taekgyun Ko <taeggyun.ko@samsung.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -388,7 +388,6 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct hix5hd2_i2c_priv *priv;
|
||||
struct resource *mem;
|
||||
unsigned int freq;
|
||||
int irq, ret;
|
||||
|
||||
|
@ -409,8 +408,7 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
priv->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
|
|
|
@ -1318,6 +1318,12 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
|
|||
|
||||
if (is_dell_system_with_lis3lv02d())
|
||||
register_dell_lis3lv02d_i2c_device(priv);
|
||||
|
||||
/* Instantiate SPD EEPROMs unless the SMBus is multiplexed */
|
||||
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO)
|
||||
if (!priv->mux_drvdata)
|
||||
#endif
|
||||
i2c_register_spd(&priv->adapter);
|
||||
}
|
||||
#else
|
||||
static void __init input_apanel_init(void) {}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-pcf.h>
|
||||
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <linux/zorro.h>
|
||||
|
||||
|
|
|
@ -1330,7 +1330,6 @@ static int img_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct img_i2c *i2c;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
u32 val;
|
||||
|
||||
|
@ -1338,16 +1337,13 @@ static int img_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
i2c->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->base))
|
||||
return PTR_ERR(i2c->base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "can't get irq number\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
i2c->sys_clk = devm_clk_get(&pdev->dev, "sys");
|
||||
if (IS_ERR(i2c->sys_clk)) {
|
||||
|
|
|
@ -551,10 +551,8 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(lpi2c_imx->base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "can't get irq number\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
lpi2c_imx->adapter.owner = THIS_MODULE;
|
||||
lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
|
||||
|
|
|
@ -763,7 +763,6 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
|||
int ret = 0;
|
||||
unsigned int clk_freq = 0;
|
||||
unsigned short tmp;
|
||||
struct resource *r;
|
||||
struct jz4780_i2c *i2c;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL);
|
||||
|
@ -787,8 +786,7 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
|||
init_completion(&i2c->trans_waitq);
|
||||
spin_lock_init(&i2c->lock);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->iomem = devm_ioremap_resource(&pdev->dev, r);
|
||||
i2c->iomem = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->iomem))
|
||||
return PTR_ERR(i2c->iomem);
|
||||
|
||||
|
|
|
@ -346,7 +346,6 @@ static const struct i2c_algorithm i2c_lpc2k_algorithm = {
|
|||
static int i2c_lpc2k_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc2k_i2c *i2c;
|
||||
struct resource *res;
|
||||
u32 bus_clk_rate;
|
||||
u32 scl_high;
|
||||
u32 clkrate;
|
||||
|
@ -356,16 +355,13 @@ static int i2c_lpc2k_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
i2c->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->base))
|
||||
return PTR_ERR(i2c->base);
|
||||
|
||||
i2c->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c->irq < 0) {
|
||||
dev_err(&pdev->dev, "can't get interrupt resource\n");
|
||||
if (i2c->irq < 0)
|
||||
return i2c->irq;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
|
|
|
@ -397,7 +397,6 @@ static int meson_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct meson_i2c *i2c;
|
||||
struct resource *mem;
|
||||
struct i2c_timings timings;
|
||||
int irq, ret = 0;
|
||||
|
||||
|
@ -422,16 +421,13 @@ static int meson_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(i2c->clk);
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
return PTR_ERR(i2c->regs);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "can't find IRQ\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -40,12 +40,11 @@
|
|||
#define I2C_SOFT_RST 0x0001
|
||||
#define I2C_FIFO_ADDR_CLR 0x0001
|
||||
#define I2C_DELAY_LEN 0x0002
|
||||
#define I2C_ST_START_CON 0x8001
|
||||
#define I2C_FS_START_CON 0x1800
|
||||
#define I2C_TIME_CLR_VALUE 0x0000
|
||||
#define I2C_TIME_DEFAULT_VALUE 0x0003
|
||||
#define I2C_WRRD_TRANAC_VALUE 0x0002
|
||||
#define I2C_RD_TRANAC_VALUE 0x0001
|
||||
#define I2C_SCL_MIS_COMP_VALUE 0x0000
|
||||
|
||||
#define I2C_DMA_CON_TX 0x0000
|
||||
#define I2C_DMA_CON_RX 0x0001
|
||||
|
@ -55,10 +54,13 @@
|
|||
#define I2C_DMA_HARD_RST 0x0002
|
||||
#define I2C_DMA_4G_MODE 0x0001
|
||||
|
||||
#define I2C_DEFAULT_CLK_DIV 5
|
||||
#define MAX_SAMPLE_CNT_DIV 8
|
||||
#define MAX_STEP_CNT_DIV 64
|
||||
#define MAX_CLOCK_DIV 256
|
||||
#define MAX_HS_STEP_CNT_DIV 8
|
||||
#define I2C_STANDARD_MODE_BUFFER (1000 / 2)
|
||||
#define I2C_FAST_MODE_BUFFER (300 / 2)
|
||||
#define I2C_FAST_MODE_PLUS_BUFFER (20 / 2)
|
||||
|
||||
#define I2C_CONTROL_RS (0x1 << 1)
|
||||
#define I2C_CONTROL_DMA_EN (0x1 << 2)
|
||||
|
@ -123,6 +125,12 @@ enum I2C_REGS_OFFSET {
|
|||
OFFSET_TRANSFER_LEN_AUX,
|
||||
OFFSET_CLOCK_DIV,
|
||||
OFFSET_LTIMING,
|
||||
OFFSET_SCL_HIGH_LOW_RATIO,
|
||||
OFFSET_HS_SCL_HIGH_LOW_RATIO,
|
||||
OFFSET_SCL_MIS_COMP_POINT,
|
||||
OFFSET_STA_STO_AC_TIMING,
|
||||
OFFSET_HS_STA_STO_AC_TIMING,
|
||||
OFFSET_SDA_TIMING,
|
||||
};
|
||||
|
||||
static const u16 mt_i2c_regs_v1[] = {
|
||||
|
@ -150,6 +158,12 @@ static const u16 mt_i2c_regs_v1[] = {
|
|||
[OFFSET_DEBUGCTRL] = 0x68,
|
||||
[OFFSET_TRANSFER_LEN_AUX] = 0x6c,
|
||||
[OFFSET_CLOCK_DIV] = 0x70,
|
||||
[OFFSET_SCL_HIGH_LOW_RATIO] = 0x74,
|
||||
[OFFSET_HS_SCL_HIGH_LOW_RATIO] = 0x78,
|
||||
[OFFSET_SCL_MIS_COMP_POINT] = 0x7C,
|
||||
[OFFSET_STA_STO_AC_TIMING] = 0x80,
|
||||
[OFFSET_HS_STA_STO_AC_TIMING] = 0x84,
|
||||
[OFFSET_SDA_TIMING] = 0x88,
|
||||
};
|
||||
|
||||
static const u16 mt_i2c_regs_v2[] = {
|
||||
|
@ -168,9 +182,11 @@ static const u16 mt_i2c_regs_v2[] = {
|
|||
[OFFSET_HS] = 0x30,
|
||||
[OFFSET_IO_CONFIG] = 0x34,
|
||||
[OFFSET_FIFO_ADDR_CLR] = 0x38,
|
||||
[OFFSET_SDA_TIMING] = 0x3c,
|
||||
[OFFSET_TRANSFER_LEN_AUX] = 0x44,
|
||||
[OFFSET_CLOCK_DIV] = 0x48,
|
||||
[OFFSET_SOFTRESET] = 0x50,
|
||||
[OFFSET_SCL_MIS_COMP_POINT] = 0x90,
|
||||
[OFFSET_DEBUGSTAT] = 0xe0,
|
||||
[OFFSET_DEBUGCTRL] = 0xe8,
|
||||
[OFFSET_FIFO_STAT] = 0xf4,
|
||||
|
@ -191,6 +207,19 @@ struct mtk_i2c_compatible {
|
|||
unsigned char ltiming_adjust: 1;
|
||||
};
|
||||
|
||||
struct mtk_i2c_ac_timing {
|
||||
u16 htiming;
|
||||
u16 ltiming;
|
||||
u16 hs;
|
||||
u16 ext;
|
||||
u16 inter_clk_div;
|
||||
u16 scl_hl_ratio;
|
||||
u16 hs_scl_hl_ratio;
|
||||
u16 sta_stop;
|
||||
u16 hs_sta_stop;
|
||||
u16 sda_timing;
|
||||
};
|
||||
|
||||
struct mtk_i2c {
|
||||
struct i2c_adapter adap; /* i2c host adapter */
|
||||
struct device *dev;
|
||||
|
@ -215,9 +244,46 @@ struct mtk_i2c {
|
|||
u16 ltiming_reg;
|
||||
unsigned char auto_restart;
|
||||
bool ignore_restart_irq;
|
||||
struct mtk_i2c_ac_timing ac_timing;
|
||||
const struct mtk_i2c_compatible *dev_comp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct i2c_spec_values:
|
||||
* min_low_ns: min LOW period of the SCL clock
|
||||
* min_su_sta_ns: min set-up time for a repeated START condition
|
||||
* max_hd_dat_ns: max data hold time
|
||||
* min_su_dat_ns: min data set-up time
|
||||
*/
|
||||
struct i2c_spec_values {
|
||||
unsigned int min_low_ns;
|
||||
unsigned int min_high_ns;
|
||||
unsigned int min_su_sta_ns;
|
||||
unsigned int max_hd_dat_ns;
|
||||
unsigned int min_su_dat_ns;
|
||||
};
|
||||
|
||||
static const struct i2c_spec_values standard_mode_spec = {
|
||||
.min_low_ns = 4700 + I2C_STANDARD_MODE_BUFFER,
|
||||
.min_su_sta_ns = 4700 + I2C_STANDARD_MODE_BUFFER,
|
||||
.max_hd_dat_ns = 3450 - I2C_STANDARD_MODE_BUFFER,
|
||||
.min_su_dat_ns = 250 + I2C_STANDARD_MODE_BUFFER,
|
||||
};
|
||||
|
||||
static const struct i2c_spec_values fast_mode_spec = {
|
||||
.min_low_ns = 1300 + I2C_FAST_MODE_BUFFER,
|
||||
.min_su_sta_ns = 600 + I2C_FAST_MODE_BUFFER,
|
||||
.max_hd_dat_ns = 900 - I2C_FAST_MODE_BUFFER,
|
||||
.min_su_dat_ns = 100 + I2C_FAST_MODE_BUFFER,
|
||||
};
|
||||
|
||||
static const struct i2c_spec_values fast_mode_plus_spec = {
|
||||
.min_low_ns = 500 + I2C_FAST_MODE_PLUS_BUFFER,
|
||||
.min_su_sta_ns = 260 + I2C_FAST_MODE_PLUS_BUFFER,
|
||||
.max_hd_dat_ns = 400 - I2C_FAST_MODE_PLUS_BUFFER,
|
||||
.min_su_dat_ns = 50 + I2C_FAST_MODE_PLUS_BUFFER,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks mt6577_i2c_quirks = {
|
||||
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
.max_num_msgs = 1,
|
||||
|
@ -397,14 +463,38 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
|||
if (i2c->dev_comp->dcm)
|
||||
mtk_i2c_writew(i2c, I2C_DCM_DISABLE, OFFSET_DCM_EN);
|
||||
|
||||
if (i2c->dev_comp->timing_adjust)
|
||||
mtk_i2c_writew(i2c, I2C_DEFAULT_CLK_DIV - 1, OFFSET_CLOCK_DIV);
|
||||
|
||||
mtk_i2c_writew(i2c, i2c->timing_reg, OFFSET_TIMING);
|
||||
mtk_i2c_writew(i2c, i2c->high_speed_reg, OFFSET_HS);
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
mtk_i2c_writew(i2c, i2c->ltiming_reg, OFFSET_LTIMING);
|
||||
|
||||
if (i2c->dev_comp->timing_adjust) {
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.ext, OFFSET_EXT_CONF);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.inter_clk_div,
|
||||
OFFSET_CLOCK_DIV);
|
||||
mtk_i2c_writew(i2c, I2C_SCL_MIS_COMP_VALUE,
|
||||
OFFSET_SCL_MIS_COMP_POINT);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.sda_timing,
|
||||
OFFSET_SDA_TIMING);
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust) {
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.htiming,
|
||||
OFFSET_TIMING);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.hs, OFFSET_HS);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.ltiming,
|
||||
OFFSET_LTIMING);
|
||||
} else {
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.scl_hl_ratio,
|
||||
OFFSET_SCL_HIGH_LOW_RATIO);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.hs_scl_hl_ratio,
|
||||
OFFSET_HS_SCL_HIGH_LOW_RATIO);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.sta_stop,
|
||||
OFFSET_STA_STO_AC_TIMING);
|
||||
mtk_i2c_writew(i2c, i2c->ac_timing.hs_sta_stop,
|
||||
OFFSET_HS_STA_STO_AC_TIMING);
|
||||
}
|
||||
}
|
||||
|
||||
/* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
|
||||
if (i2c->have_pmic)
|
||||
mtk_i2c_writew(i2c, I2C_CONTROL_WRAPPER, OFFSET_PATH_DIR);
|
||||
|
@ -422,6 +512,126 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
|||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
|
||||
}
|
||||
|
||||
static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed)
|
||||
{
|
||||
if (speed <= I2C_MAX_STANDARD_MODE_FREQ)
|
||||
return &standard_mode_spec;
|
||||
else if (speed <= I2C_MAX_FAST_MODE_FREQ)
|
||||
return &fast_mode_spec;
|
||||
else
|
||||
return &fast_mode_plus_spec;
|
||||
}
|
||||
|
||||
static int mtk_i2c_max_step_cnt(unsigned int target_speed)
|
||||
{
|
||||
if (target_speed > I2C_MAX_FAST_MODE_FREQ)
|
||||
return MAX_HS_STEP_CNT_DIV;
|
||||
else
|
||||
return MAX_STEP_CNT_DIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check and Calculate i2c ac-timing
|
||||
*
|
||||
* Hardware design:
|
||||
* sample_ns = (1000000000 * (sample_cnt + 1)) / clk_src
|
||||
* xxx_cnt_div = spec->min_xxx_ns / sample_ns
|
||||
*
|
||||
* Sample_ns is rounded down for xxx_cnt_div would be greater
|
||||
* than the smallest spec.
|
||||
* The sda_timing is chosen as the middle value between
|
||||
* the largest and smallest.
|
||||
*/
|
||||
static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
|
||||
unsigned int clk_src,
|
||||
unsigned int check_speed,
|
||||
unsigned int step_cnt,
|
||||
unsigned int sample_cnt)
|
||||
{
|
||||
const struct i2c_spec_values *spec;
|
||||
unsigned int su_sta_cnt, low_cnt, high_cnt, max_step_cnt;
|
||||
unsigned int sda_max, sda_min, clk_ns, max_sta_cnt = 0x3f;
|
||||
unsigned int sample_ns = div_u64(1000000000ULL * (sample_cnt + 1),
|
||||
clk_src);
|
||||
|
||||
if (!i2c->dev_comp->timing_adjust)
|
||||
return 0;
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
max_sta_cnt = 0x100;
|
||||
|
||||
spec = mtk_i2c_get_spec(check_speed);
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
clk_ns = 1000000000 / clk_src;
|
||||
else
|
||||
clk_ns = sample_ns / 2;
|
||||
|
||||
su_sta_cnt = DIV_ROUND_UP(spec->min_su_sta_ns, clk_ns);
|
||||
if (su_sta_cnt > max_sta_cnt)
|
||||
return -1;
|
||||
|
||||
low_cnt = DIV_ROUND_UP(spec->min_low_ns, sample_ns);
|
||||
max_step_cnt = mtk_i2c_max_step_cnt(check_speed);
|
||||
if ((2 * step_cnt) > low_cnt && low_cnt < max_step_cnt) {
|
||||
if (low_cnt > step_cnt) {
|
||||
high_cnt = 2 * step_cnt - low_cnt;
|
||||
} else {
|
||||
high_cnt = step_cnt;
|
||||
low_cnt = step_cnt;
|
||||
}
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
sda_max = spec->max_hd_dat_ns / sample_ns;
|
||||
if (sda_max > low_cnt)
|
||||
sda_max = 0;
|
||||
|
||||
sda_min = DIV_ROUND_UP(spec->min_su_dat_ns, sample_ns);
|
||||
if (sda_min < low_cnt)
|
||||
sda_min = 0;
|
||||
|
||||
if (sda_min > sda_max)
|
||||
return -3;
|
||||
|
||||
if (check_speed > I2C_MAX_FAST_MODE_FREQ) {
|
||||
if (i2c->dev_comp->ltiming_adjust) {
|
||||
i2c->ac_timing.hs = I2C_TIME_DEFAULT_VALUE |
|
||||
(sample_cnt << 12) | (high_cnt << 8);
|
||||
i2c->ac_timing.ltiming &= ~GENMASK(15, 9);
|
||||
i2c->ac_timing.ltiming |= (sample_cnt << 12) |
|
||||
(low_cnt << 9);
|
||||
i2c->ac_timing.ext &= ~GENMASK(7, 1);
|
||||
i2c->ac_timing.ext |= (su_sta_cnt << 1) | (1 << 0);
|
||||
} else {
|
||||
i2c->ac_timing.hs_scl_hl_ratio = (1 << 12) |
|
||||
(high_cnt << 6) | low_cnt;
|
||||
i2c->ac_timing.hs_sta_stop = (su_sta_cnt << 8) |
|
||||
su_sta_cnt;
|
||||
}
|
||||
i2c->ac_timing.sda_timing &= ~GENMASK(11, 6);
|
||||
i2c->ac_timing.sda_timing |= (1 << 12) |
|
||||
((sda_max + sda_min) / 2) << 6;
|
||||
} else {
|
||||
if (i2c->dev_comp->ltiming_adjust) {
|
||||
i2c->ac_timing.htiming = (sample_cnt << 8) | (high_cnt);
|
||||
i2c->ac_timing.ltiming = (sample_cnt << 6) | (low_cnt);
|
||||
i2c->ac_timing.ext = (su_sta_cnt << 8) | (1 << 0);
|
||||
} else {
|
||||
i2c->ac_timing.scl_hl_ratio = (1 << 12) |
|
||||
(high_cnt << 6) | low_cnt;
|
||||
i2c->ac_timing.sta_stop = (su_sta_cnt << 8) |
|
||||
su_sta_cnt;
|
||||
}
|
||||
|
||||
i2c->ac_timing.sda_timing = (1 << 12) |
|
||||
(sda_max + sda_min) / 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate i2c port speed
|
||||
*
|
||||
|
@ -446,15 +656,12 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
|
|||
unsigned int opt_div;
|
||||
unsigned int best_mul;
|
||||
unsigned int cnt_mul;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ)
|
||||
target_speed = I2C_MAX_FAST_MODE_PLUS_FREQ;
|
||||
|
||||
if (target_speed > I2C_MAX_FAST_MODE_FREQ)
|
||||
max_step_cnt = MAX_HS_STEP_CNT_DIV;
|
||||
else
|
||||
max_step_cnt = MAX_STEP_CNT_DIV;
|
||||
|
||||
max_step_cnt = mtk_i2c_max_step_cnt(target_speed);
|
||||
base_step_cnt = max_step_cnt;
|
||||
/* Find the best combination */
|
||||
opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed);
|
||||
|
@ -473,6 +680,11 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
|
|||
continue;
|
||||
|
||||
if (cnt_mul < best_mul) {
|
||||
ret = mtk_i2c_check_ac_timing(i2c, clk_src,
|
||||
target_speed, step_cnt - 1, sample_cnt - 1);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
best_mul = cnt_mul;
|
||||
base_sample_cnt = sample_cnt;
|
||||
base_step_cnt = step_cnt;
|
||||
|
@ -481,6 +693,9 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
|
|||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
sample_cnt = base_sample_cnt;
|
||||
step_cnt = base_step_cnt;
|
||||
|
||||
|
@ -506,47 +721,68 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
|||
unsigned int l_step_cnt;
|
||||
unsigned int l_sample_cnt;
|
||||
unsigned int target_speed;
|
||||
unsigned int clk_div;
|
||||
unsigned int max_clk_div;
|
||||
int ret;
|
||||
|
||||
clk_src = parent_clk / i2c->clk_src_div;
|
||||
target_speed = i2c->speed_hz;
|
||||
parent_clk /= i2c->clk_src_div;
|
||||
|
||||
if (target_speed > I2C_MAX_FAST_MODE_FREQ) {
|
||||
/* Set master code speed register */
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, I2C_MAX_FAST_MODE_FREQ,
|
||||
&l_step_cnt, &l_sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (i2c->dev_comp->timing_adjust)
|
||||
max_clk_div = MAX_CLOCK_DIV;
|
||||
else
|
||||
max_clk_div = 1;
|
||||
|
||||
i2c->timing_reg = (l_sample_cnt << 8) | l_step_cnt;
|
||||
for (clk_div = 1; clk_div <= max_clk_div; clk_div++) {
|
||||
clk_src = parent_clk / clk_div;
|
||||
|
||||
/* Set the high speed mode register */
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
|
||||
&step_cnt, &sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (target_speed > I2C_MAX_FAST_MODE_FREQ) {
|
||||
/* Set master code speed register */
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src,
|
||||
I2C_MAX_FAST_MODE_FREQ,
|
||||
&l_step_cnt,
|
||||
&l_sample_cnt);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
|
||||
(sample_cnt << 12) | (step_cnt << 8);
|
||||
i2c->timing_reg = (l_sample_cnt << 8) | l_step_cnt;
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
i2c->ltiming_reg = (l_sample_cnt << 6) | l_step_cnt |
|
||||
(sample_cnt << 12) | (step_cnt << 9);
|
||||
} else {
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
|
||||
&step_cnt, &sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Set the high speed mode register */
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src,
|
||||
target_speed, &step_cnt,
|
||||
&sample_cnt);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
i2c->timing_reg = (sample_cnt << 8) | step_cnt;
|
||||
i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
|
||||
(sample_cnt << 12) | (step_cnt << 8);
|
||||
|
||||
/* Disable the high speed transaction */
|
||||
i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
i2c->ltiming_reg =
|
||||
(l_sample_cnt << 6) | l_step_cnt |
|
||||
(sample_cnt << 12) | (step_cnt << 9);
|
||||
} else {
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src,
|
||||
target_speed, &l_step_cnt,
|
||||
&l_sample_cnt);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
i2c->ltiming_reg = (sample_cnt << 6) | step_cnt;
|
||||
i2c->timing_reg = (l_sample_cnt << 8) | l_step_cnt;
|
||||
|
||||
/* Disable the high speed transaction */
|
||||
i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
|
||||
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
i2c->ltiming_reg =
|
||||
(l_sample_cnt << 6) | l_step_cnt;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
i2c->ac_timing.inter_clk_div = clk_div - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -586,12 +822,6 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
|
||||
mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
|
||||
|
||||
/* set start condition */
|
||||
if (i2c->speed_hz <= I2C_MAX_STANDARD_MODE_FREQ)
|
||||
mtk_i2c_writew(i2c, I2C_ST_START_CON, OFFSET_EXT_CONF);
|
||||
else
|
||||
mtk_i2c_writew(i2c, I2C_FS_START_CON, OFFSET_EXT_CONF);
|
||||
|
||||
addr_reg = i2c_8bit_addr_from_msg(msgs);
|
||||
mtk_i2c_writew(i2c, addr_reg, OFFSET_SLAVE_ADDR);
|
||||
|
||||
|
@ -948,9 +1178,6 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (i2c->dev_comp->timing_adjust)
|
||||
i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV;
|
||||
|
||||
if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -877,7 +877,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
{
|
||||
struct mv64xxx_i2c_data *drv_data;
|
||||
struct mv64xxx_i2c_pdata *pdata = dev_get_platdata(&pd->dev);
|
||||
struct resource *r;
|
||||
int rc;
|
||||
|
||||
if ((!pdata && !pd->dev.of_node))
|
||||
|
@ -888,8 +887,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pd, IORESOURCE_MEM, 0);
|
||||
drv_data->reg_base = devm_ioremap_resource(&pd->dev, r);
|
||||
drv_data->reg_base = devm_platform_ioremap_resource(pd, 0);
|
||||
if (IS_ERR(drv_data->reg_base))
|
||||
return PTR_ERR(drv_data->reg_base);
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -277,10 +277,7 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
|
|||
i2cd->gpu_ccgx_ucsi->irq = irq;
|
||||
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
|
||||
i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||
if (IS_ERR(i2cd->ccgx_client))
|
||||
return PTR_ERR(i2cd->ccgx_client);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(i2cd->ccgx_client);
|
||||
}
|
||||
|
||||
static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
|
|
|
@ -136,7 +136,6 @@ static int octeon_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
int irq, result = 0, hlc_irq = 0;
|
||||
struct resource *res_mem;
|
||||
struct octeon_i2c *i2c;
|
||||
bool cn78xx_style;
|
||||
|
||||
|
@ -167,8 +166,7 @@ static int octeon_i2c_probe(struct platform_device *pdev)
|
|||
i2c->roff.twsi_int = 0x10;
|
||||
i2c->roff.sw_twsi_ext = 0x18;
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
|
||||
i2c->twsi_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->twsi_base)) {
|
||||
result = PTR_ERR(i2c->twsi_base);
|
||||
goto out;
|
||||
|
|
|
@ -1365,10 +1365,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
u16 minor, major;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource?\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
|
||||
if (!omap)
|
||||
|
|
|
@ -396,23 +396,19 @@ static int owl_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct owl_i2c_dev *i2c_dev;
|
||||
struct resource *res;
|
||||
int ret, irq;
|
||||
|
||||
i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c_dev->base = devm_ioremap_resource(dev, res);
|
||||
i2c_dev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "clock-frequency",
|
||||
&i2c_dev->bus_freq))
|
||||
|
|
|
@ -149,8 +149,7 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
i2c->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(i2c->reg_base))
|
||||
return PTR_ERR(i2c->reg_base);
|
||||
|
||||
|
|
|
@ -977,7 +977,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
}
|
||||
|
||||
if (dev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) {
|
||||
(dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS ||
|
||||
dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) {
|
||||
retval = piix4_setup_sb800(dev, id, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -720,7 +720,6 @@ static int i2c_pnx_probe(struct platform_device *pdev)
|
|||
|
||||
alg_data->irq = platform_get_irq(pdev, 0);
|
||||
if (alg_data->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
|
||||
ret = alg_data->irq;
|
||||
goto out_clock;
|
||||
}
|
||||
|
|
|
@ -207,18 +207,18 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
|
|||
struct pmac_i2c_bus *bus,
|
||||
struct device_node *node)
|
||||
{
|
||||
const __be32 *prop;
|
||||
int len;
|
||||
u32 prop;
|
||||
int ret;
|
||||
|
||||
/* First check for valid "reg" */
|
||||
prop = of_get_property(node, "reg", &len);
|
||||
if (prop && (len >= sizeof(int)))
|
||||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||
ret = of_property_read_u32(node, "reg", &prop);
|
||||
if (ret == 0)
|
||||
return (prop & 0xff) >> 1;
|
||||
|
||||
/* Then check old-style "i2c-address" */
|
||||
prop = of_get_property(node, "i2c-address", &len);
|
||||
if (prop && (len >= sizeof(int)))
|
||||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||
ret = of_property_read_u32(node, "i2c-address", &prop);
|
||||
if (ret == 0)
|
||||
return (prop & 0xff) >> 1;
|
||||
|
||||
/* Now handle some devices with missing "reg" properties */
|
||||
if (of_node_name_eq(node, "cereal"))
|
||||
|
@ -315,7 +315,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
|||
{
|
||||
struct i2c_client *newdev;
|
||||
struct device_node *node;
|
||||
bool found_onyx = 0;
|
||||
bool found_onyx = false;
|
||||
|
||||
/*
|
||||
* In some cases we end up with the via-pmu node itself, in this
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,791 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
// Copyright (c) 2017-20 Linaro Limited.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define CCI_HW_VERSION 0x0
|
||||
#define CCI_RESET_CMD 0x004
|
||||
#define CCI_RESET_CMD_MASK 0x0f73f3f7
|
||||
#define CCI_RESET_CMD_M0_MASK 0x000003f1
|
||||
#define CCI_RESET_CMD_M1_MASK 0x0003f001
|
||||
#define CCI_QUEUE_START 0x008
|
||||
#define CCI_HALT_REQ 0x034
|
||||
#define CCI_HALT_REQ_I2C_M0_Q0Q1 BIT(0)
|
||||
#define CCI_HALT_REQ_I2C_M1_Q0Q1 BIT(1)
|
||||
|
||||
#define CCI_I2C_Mm_SCL_CTL(m) (0x100 + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_SDA_CTL_0(m) (0x104 + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_SDA_CTL_1(m) (0x108 + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_SDA_CTL_2(m) (0x10c + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_MISC_CTL(m) (0x110 + 0x100 * (m))
|
||||
|
||||
#define CCI_I2C_Mm_READ_DATA(m) (0x118 + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_READ_BUF_LEVEL(m) (0x11c + 0x100 * (m))
|
||||
#define CCI_I2C_Mm_Qn_EXEC_WORD_CNT(m, n) (0x300 + 0x200 * (m) + 0x100 * (n))
|
||||
#define CCI_I2C_Mm_Qn_CUR_WORD_CNT(m, n) (0x304 + 0x200 * (m) + 0x100 * (n))
|
||||
#define CCI_I2C_Mm_Qn_CUR_CMD(m, n) (0x308 + 0x200 * (m) + 0x100 * (n))
|
||||
#define CCI_I2C_Mm_Qn_REPORT_STATUS(m, n) (0x30c + 0x200 * (m) + 0x100 * (n))
|
||||
#define CCI_I2C_Mm_Qn_LOAD_DATA(m, n) (0x310 + 0x200 * (m) + 0x100 * (n))
|
||||
|
||||
#define CCI_IRQ_GLOBAL_CLEAR_CMD 0xc00
|
||||
#define CCI_IRQ_MASK_0 0xc04
|
||||
#define CCI_IRQ_MASK_0_I2C_M0_RD_DONE BIT(0)
|
||||
#define CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT BIT(4)
|
||||
#define CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT BIT(8)
|
||||
#define CCI_IRQ_MASK_0_I2C_M1_RD_DONE BIT(12)
|
||||
#define CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT BIT(16)
|
||||
#define CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT BIT(20)
|
||||
#define CCI_IRQ_MASK_0_RST_DONE_ACK BIT(24)
|
||||
#define CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK BIT(25)
|
||||
#define CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK BIT(26)
|
||||
#define CCI_IRQ_MASK_0_I2C_M0_ERROR 0x18000ee6
|
||||
#define CCI_IRQ_MASK_0_I2C_M1_ERROR 0x60ee6000
|
||||
#define CCI_IRQ_CLEAR_0 0xc08
|
||||
#define CCI_IRQ_STATUS_0 0xc0c
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE BIT(0)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT BIT(4)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT BIT(8)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE BIT(12)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT BIT(16)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT BIT(20)
|
||||
#define CCI_IRQ_STATUS_0_RST_DONE_ACK BIT(24)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK BIT(25)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK BIT(26)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR BIT(27)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR BIT(28)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR BIT(29)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR BIT(30)
|
||||
#define CCI_IRQ_STATUS_0_I2C_M0_ERROR 0x18000ee6
|
||||
#define CCI_IRQ_STATUS_0_I2C_M1_ERROR 0x60ee6000
|
||||
|
||||
#define CCI_TIMEOUT (msecs_to_jiffies(100))
|
||||
#define NUM_MASTERS 2
|
||||
#define NUM_QUEUES 2
|
||||
|
||||
/* Max number of resources + 1 for a NULL terminator */
|
||||
#define CCI_RES_MAX 6
|
||||
|
||||
#define CCI_I2C_SET_PARAM 1
|
||||
#define CCI_I2C_REPORT 8
|
||||
#define CCI_I2C_WRITE 9
|
||||
#define CCI_I2C_READ 10
|
||||
|
||||
#define CCI_I2C_REPORT_IRQ_EN BIT(8)
|
||||
|
||||
enum {
|
||||
I2C_MODE_STANDARD,
|
||||
I2C_MODE_FAST,
|
||||
I2C_MODE_FAST_PLUS,
|
||||
};
|
||||
|
||||
enum cci_i2c_queue_t {
|
||||
QUEUE_0,
|
||||
QUEUE_1
|
||||
};
|
||||
|
||||
struct hw_params {
|
||||
u16 thigh; /* HIGH period of the SCL clock in clock ticks */
|
||||
u16 tlow; /* LOW period of the SCL clock */
|
||||
u16 tsu_sto; /* set-up time for STOP condition */
|
||||
u16 tsu_sta; /* set-up time for a repeated START condition */
|
||||
u16 thd_dat; /* data hold time */
|
||||
u16 thd_sta; /* hold time (repeated) START condition */
|
||||
u16 tbuf; /* bus free time between a STOP and START condition */
|
||||
u8 scl_stretch_en;
|
||||
u16 trdhld;
|
||||
u16 tsp; /* pulse width of spikes suppressed by the input filter */
|
||||
};
|
||||
|
||||
struct cci;
|
||||
|
||||
struct cci_master {
|
||||
struct i2c_adapter adap;
|
||||
u16 master;
|
||||
u8 mode;
|
||||
int status;
|
||||
struct completion irq_complete;
|
||||
struct cci *cci;
|
||||
};
|
||||
|
||||
struct cci_data {
|
||||
unsigned int num_masters;
|
||||
struct i2c_adapter_quirks quirks;
|
||||
u16 queue_size[NUM_QUEUES];
|
||||
unsigned long cci_clk_rate;
|
||||
struct hw_params params[3];
|
||||
};
|
||||
|
||||
struct cci {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
unsigned int irq;
|
||||
const struct cci_data *data;
|
||||
struct clk_bulk_data *clocks;
|
||||
int nclocks;
|
||||
struct cci_master master[NUM_MASTERS];
|
||||
};
|
||||
|
||||
static irqreturn_t cci_isr(int irq, void *dev)
|
||||
{
|
||||
struct cci *cci = dev;
|
||||
u32 val, reset = 0;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
val = readl(cci->base + CCI_IRQ_STATUS_0);
|
||||
writel(val, cci->base + CCI_IRQ_CLEAR_0);
|
||||
writel(0x1, cci->base + CCI_IRQ_GLOBAL_CLEAR_CMD);
|
||||
|
||||
if (val & CCI_IRQ_STATUS_0_RST_DONE_ACK) {
|
||||
complete(&cci->master[0].irq_complete);
|
||||
if (cci->master[1].master)
|
||||
complete(&cci->master[1].irq_complete);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (val & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT) {
|
||||
cci->master[0].status = 0;
|
||||
complete(&cci->master[0].irq_complete);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (val & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT) {
|
||||
cci->master[1].status = 0;
|
||||
complete(&cci->master[1].irq_complete);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK)) {
|
||||
reset = CCI_RESET_CMD_M0_MASK;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK)) {
|
||||
reset = CCI_RESET_CMD_M1_MASK;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (unlikely(reset))
|
||||
writel(reset, cci->base + CCI_RESET_CMD);
|
||||
|
||||
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_ERROR)) {
|
||||
if (val & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR)
|
||||
cci->master[0].status = -ENXIO;
|
||||
else
|
||||
cci->master[0].status = -EIO;
|
||||
|
||||
writel(CCI_HALT_REQ_I2C_M0_Q0Q1, cci->base + CCI_HALT_REQ);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) {
|
||||
if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR ||
|
||||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR)
|
||||
cci->master[0].status = -ENXIO;
|
||||
else
|
||||
cci->master[0].status = -EIO;
|
||||
|
||||
writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cci_halt(struct cci *cci, u8 master_num)
|
||||
{
|
||||
struct cci_master *master;
|
||||
u32 val;
|
||||
|
||||
if (master_num >= cci->data->num_masters) {
|
||||
dev_err(cci->dev, "Unsupported master idx (%u)\n", master_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = BIT(master_num);
|
||||
master = &cci->master[master_num];
|
||||
|
||||
reinit_completion(&master->irq_complete);
|
||||
writel(val, cci->base + CCI_HALT_REQ);
|
||||
|
||||
if (!wait_for_completion_timeout(&master->irq_complete, CCI_TIMEOUT)) {
|
||||
dev_err(cci->dev, "CCI halt timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_reset(struct cci *cci)
|
||||
{
|
||||
/*
|
||||
* we reset the whole controller, here and for implicity use
|
||||
* master[0].xxx for waiting on it.
|
||||
*/
|
||||
reinit_completion(&cci->master[0].irq_complete);
|
||||
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
|
||||
|
||||
if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
|
||||
CCI_TIMEOUT)) {
|
||||
dev_err(cci->dev, "CCI reset timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_init(struct cci *cci)
|
||||
{
|
||||
u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE |
|
||||
CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT |
|
||||
CCI_IRQ_MASK_0_I2C_M0_Q1_REPORT |
|
||||
CCI_IRQ_MASK_0_I2C_M1_RD_DONE |
|
||||
CCI_IRQ_MASK_0_I2C_M1_Q0_REPORT |
|
||||
CCI_IRQ_MASK_0_I2C_M1_Q1_REPORT |
|
||||
CCI_IRQ_MASK_0_RST_DONE_ACK |
|
||||
CCI_IRQ_MASK_0_I2C_M0_Q0Q1_HALT_ACK |
|
||||
CCI_IRQ_MASK_0_I2C_M1_Q0Q1_HALT_ACK |
|
||||
CCI_IRQ_MASK_0_I2C_M0_ERROR |
|
||||
CCI_IRQ_MASK_0_I2C_M1_ERROR;
|
||||
int i;
|
||||
|
||||
writel(val, cci->base + CCI_IRQ_MASK_0);
|
||||
|
||||
for (i = 0; i < cci->data->num_masters; i++) {
|
||||
int mode = cci->master[i].mode;
|
||||
const struct hw_params *hw;
|
||||
|
||||
if (!cci->master[i].cci)
|
||||
continue;
|
||||
|
||||
hw = &cci->data->params[mode];
|
||||
|
||||
val = hw->thigh << 16 | hw->tlow;
|
||||
writel(val, cci->base + CCI_I2C_Mm_SCL_CTL(i));
|
||||
|
||||
val = hw->tsu_sto << 16 | hw->tsu_sta;
|
||||
writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_0(i));
|
||||
|
||||
val = hw->thd_dat << 16 | hw->thd_sta;
|
||||
writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_1(i));
|
||||
|
||||
val = hw->tbuf;
|
||||
writel(val, cci->base + CCI_I2C_Mm_SDA_CTL_2(i));
|
||||
|
||||
val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp;
|
||||
writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_run_queue(struct cci *cci, u8 master, u8 queue)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue));
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_EXEC_WORD_CNT(master, queue));
|
||||
|
||||
reinit_completion(&cci->master[master].irq_complete);
|
||||
val = BIT(master * 2 + queue);
|
||||
writel(val, cci->base + CCI_QUEUE_START);
|
||||
|
||||
if (!wait_for_completion_timeout(&cci->master[master].irq_complete,
|
||||
CCI_TIMEOUT)) {
|
||||
dev_err(cci->dev, "master %d queue %d timeout\n",
|
||||
master, queue);
|
||||
cci_reset(cci);
|
||||
cci_init(cci);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return cci->master[master].status;
|
||||
}
|
||||
|
||||
static int cci_validate_queue(struct cci *cci, u8 master, u8 queue)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue));
|
||||
if (val == cci->data->queue_size[queue])
|
||||
return -EINVAL;
|
||||
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
|
||||
return cci_run_queue(cci, master, queue);
|
||||
}
|
||||
|
||||
static int cci_i2c_read(struct cci *cci, u16 master,
|
||||
u16 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u32 val, words_read, words_exp;
|
||||
u8 queue = QUEUE_1;
|
||||
int i, index = 0, ret;
|
||||
bool first = true;
|
||||
|
||||
/*
|
||||
* Call validate queue to make sure queue is empty before starting.
|
||||
* This is to avoid overflow / underflow of queue.
|
||||
*/
|
||||
ret = cci_validate_queue(cci, master, queue);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
|
||||
val = CCI_I2C_READ | len << 4;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
|
||||
ret = cci_run_queue(cci, master, queue);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
words_read = readl(cci->base + CCI_I2C_Mm_READ_BUF_LEVEL(master));
|
||||
words_exp = len / 4 + 1;
|
||||
if (words_read != words_exp) {
|
||||
dev_err(cci->dev, "words read = %d, words expected = %d\n",
|
||||
words_read, words_exp);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
do {
|
||||
val = readl(cci->base + CCI_I2C_Mm_READ_DATA(master));
|
||||
|
||||
for (i = 0; i < 4 && index < len; i++) {
|
||||
if (first) {
|
||||
/* The LS byte of this register represents the
|
||||
* first byte read from the slave during a read
|
||||
* access.
|
||||
*/
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
buf[index++] = (val >> (i * 8)) & 0xff;
|
||||
}
|
||||
} while (--words_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_i2c_write(struct cci *cci, u16 master,
|
||||
u16 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u8 queue = QUEUE_0;
|
||||
u8 load[12] = { 0 };
|
||||
int i = 0, j, ret;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Call validate queue to make sure queue is empty before starting.
|
||||
* This is to avoid overflow / underflow of queue.
|
||||
*/
|
||||
ret = cci_validate_queue(cci, master, queue);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = CCI_I2C_SET_PARAM | (addr & 0x7f) << 4;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
|
||||
load[i++] = CCI_I2C_WRITE | len << 4;
|
||||
|
||||
for (j = 0; j < len; j++)
|
||||
load[i++] = buf[j];
|
||||
|
||||
for (j = 0; j < i; j += 4) {
|
||||
val = load[j];
|
||||
val |= load[j + 1] << 8;
|
||||
val |= load[j + 2] << 16;
|
||||
val |= load[j + 3] << 24;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
}
|
||||
|
||||
val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN;
|
||||
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
|
||||
|
||||
return cci_run_queue(cci, master, queue);
|
||||
}
|
||||
|
||||
static int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct cci_master *cci_master = i2c_get_adapdata(adap);
|
||||
struct cci *cci = cci_master->cci;
|
||||
int i, ret;
|
||||
|
||||
ret = pm_runtime_get_sync(cci->dev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (msgs[i].flags & I2C_M_RD)
|
||||
ret = cci_i2c_read(cci, cci_master->master,
|
||||
msgs[i].addr, msgs[i].buf,
|
||||
msgs[i].len);
|
||||
else
|
||||
ret = cci_i2c_write(cci, cci_master->master,
|
||||
msgs[i].addr, msgs[i].buf,
|
||||
msgs[i].len);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = num;
|
||||
|
||||
err:
|
||||
pm_runtime_mark_last_busy(cci->dev);
|
||||
pm_runtime_put_autosuspend(cci->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 cci_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm cci_algo = {
|
||||
.master_xfer = cci_xfer,
|
||||
.functionality = cci_func,
|
||||
};
|
||||
|
||||
static int cci_enable_clocks(struct cci *cci)
|
||||
{
|
||||
return clk_bulk_prepare_enable(cci->nclocks, cci->clocks);
|
||||
}
|
||||
|
||||
static void cci_disable_clocks(struct cci *cci)
|
||||
{
|
||||
clk_bulk_disable_unprepare(cci->nclocks, cci->clocks);
|
||||
}
|
||||
|
||||
static int __maybe_unused cci_suspend_runtime(struct device *dev)
|
||||
{
|
||||
struct cci *cci = dev_get_drvdata(dev);
|
||||
|
||||
cci_disable_clocks(cci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cci_resume_runtime(struct device *dev)
|
||||
{
|
||||
struct cci *cci = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = cci_enable_clocks(cci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cci_init(cci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cci_suspend(struct device *dev)
|
||||
{
|
||||
if (!pm_runtime_suspended(dev))
|
||||
return cci_suspend_runtime(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cci_resume(struct device *dev)
|
||||
{
|
||||
cci_resume_runtime(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_request_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops qcom_cci_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume)
|
||||
SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL)
|
||||
};
|
||||
|
||||
static int cci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long cci_clk_rate = 0;
|
||||
struct device_node *child;
|
||||
struct resource *r;
|
||||
struct cci *cci;
|
||||
int ret, i;
|
||||
u32 val;
|
||||
|
||||
cci = devm_kzalloc(dev, sizeof(*cci), GFP_KERNEL);
|
||||
if (!cci)
|
||||
return -ENOMEM;
|
||||
|
||||
cci->dev = dev;
|
||||
platform_set_drvdata(pdev, cci);
|
||||
cci->data = device_get_match_data(dev);
|
||||
if (!cci->data)
|
||||
return -ENOENT;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
u32 idx;
|
||||
|
||||
ret = of_property_read_u32(child, "reg", &idx);
|
||||
if (ret) {
|
||||
dev_err(dev, "%pOF invalid 'reg' property", child);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (idx >= cci->data->num_masters) {
|
||||
dev_err(dev, "%pOF invalid 'reg' value: %u (max is %u)",
|
||||
child, idx, cci->data->num_masters - 1);
|
||||
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 = child;
|
||||
cci->master[idx].master = idx;
|
||||
cci->master[idx].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");
|
||||
|
||||
cci->master[idx].mode = I2C_MODE_STANDARD;
|
||||
ret = of_property_read_u32(child, "clock-frequency", &val);
|
||||
if (!ret) {
|
||||
if (val == 400000)
|
||||
cci->master[idx].mode = I2C_MODE_FAST;
|
||||
else if (val == 1000000)
|
||||
cci->master[idx].mode = I2C_MODE_FAST_PLUS;
|
||||
}
|
||||
|
||||
init_completion(&cci->master[idx].irq_complete);
|
||||
}
|
||||
|
||||
/* Memory */
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
cci->base = devm_ioremap_resource(dev, r);
|
||||
if (IS_ERR(cci->base))
|
||||
return PTR_ERR(cci->base);
|
||||
|
||||
/* Clocks */
|
||||
|
||||
ret = devm_clk_bulk_get_all(dev, &cci->clocks);
|
||||
if (ret < 1) {
|
||||
dev_err(dev, "failed to get clocks %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
cci->nclocks = ret;
|
||||
|
||||
/* Retrieve CCI clock rate */
|
||||
for (i = 0; i < cci->nclocks; i++) {
|
||||
if (!strcmp(cci->clocks[i].id, "cci")) {
|
||||
cci_clk_rate = clk_get_rate(cci->clocks[i].clk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cci_clk_rate != cci->data->cci_clk_rate) {
|
||||
/* cci clock set by the bootloader or via assigned clock rate
|
||||
* in DT.
|
||||
*/
|
||||
dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n",
|
||||
cci_clk_rate, cci->data->cci_clk_rate);
|
||||
}
|
||||
|
||||
ret = cci_enable_clocks(cci);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Interrupt */
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
goto disable_clocks;
|
||||
cci->irq = ret;
|
||||
|
||||
ret = devm_request_irq(dev, cci->irq, cci_isr, 0, dev_name(dev), cci);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "request_irq failed, ret: %d\n", ret);
|
||||
goto disable_clocks;
|
||||
}
|
||||
|
||||
val = readl(cci->base + CCI_HW_VERSION);
|
||||
dev_dbg(dev, "CCI HW version = 0x%08x", val);
|
||||
|
||||
ret = cci_reset(cci);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = cci_init(cci);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < cci->data->num_masters; i++) {
|
||||
if (!cci->master[i].cci)
|
||||
continue;
|
||||
|
||||
ret = i2c_add_adapter(&cci->master[i].adap);
|
||||
if (ret < 0)
|
||||
goto error_i2c;
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_i2c:
|
||||
for (; i >= 0; i--) {
|
||||
if (cci->master[i].cci)
|
||||
i2c_del_adapter(&cci->master[i].adap);
|
||||
}
|
||||
error:
|
||||
disable_irq(cci->irq);
|
||||
disable_clocks:
|
||||
cci_disable_clocks(cci);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cci *cci = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cci->data->num_masters; i++) {
|
||||
if (cci->master[i].cci)
|
||||
i2c_del_adapter(&cci->master[i].adap);
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
|
||||
disable_irq(cci->irq);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cci_data cci_v1_data = {
|
||||
.num_masters = 1,
|
||||
.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 },
|
||||
.quirks = {
|
||||
.max_write_len = 11,
|
||||
.max_read_len = 12,
|
||||
},
|
||||
.cci_clk_rate = 37500000,
|
||||
.params[I2C_MODE_STANDARD] = {
|
||||
.thigh = 201,
|
||||
.tlow = 174,
|
||||
.tsu_sto = 204,
|
||||
.tsu_sta = 231,
|
||||
.thd_dat = 22,
|
||||
.thd_sta = 162,
|
||||
.tbuf = 227,
|
||||
.scl_stretch_en = 0,
|
||||
.trdhld = 6,
|
||||
.tsp = 3
|
||||
},
|
||||
.params[I2C_MODE_FAST] = {
|
||||
.thigh = 38,
|
||||
.tlow = 56,
|
||||
.tsu_sto = 40,
|
||||
.tsu_sta = 40,
|
||||
.thd_dat = 22,
|
||||
.thd_sta = 35,
|
||||
.tbuf = 62,
|
||||
.scl_stretch_en = 0,
|
||||
.trdhld = 6,
|
||||
.tsp = 3
|
||||
},
|
||||
.params[I2C_MODE_FAST_PLUS] = {
|
||||
.thigh = 16,
|
||||
.tlow = 22,
|
||||
.tsu_sto = 17,
|
||||
.tsu_sta = 18,
|
||||
.thd_dat = 16,
|
||||
.thd_sta = 15,
|
||||
.tbuf = 24,
|
||||
.scl_stretch_en = 0,
|
||||
.trdhld = 3,
|
||||
.tsp = 3
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id cci_dt_match[] = {
|
||||
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
|
||||
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
|
||||
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cci_dt_match);
|
||||
|
||||
static struct platform_driver qcom_cci_driver = {
|
||||
.probe = cci_probe,
|
||||
.remove = cci_remove,
|
||||
.driver = {
|
||||
.name = "i2c-qcom-cci",
|
||||
.of_match_table = cci_dt_match,
|
||||
.pm = &qcom_cci_pm,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(qcom_cci_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Camera Control Interface driver");
|
||||
MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>");
|
||||
MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -956,10 +956,8 @@ static void qup_i2c_conf_v1(struct qup_i2c_dev *qup)
|
|||
u32 qup_config = I2C_MINI_CORE | I2C_N_VAL;
|
||||
u32 io_mode = QUP_REPACK_EN;
|
||||
|
||||
blk->is_tx_blk_mode =
|
||||
blk->total_tx_len > qup->out_fifo_sz ? true : false;
|
||||
blk->is_rx_blk_mode =
|
||||
blk->total_rx_len > qup->in_fifo_sz ? true : false;
|
||||
blk->is_tx_blk_mode = blk->total_tx_len > qup->out_fifo_sz;
|
||||
blk->is_rx_blk_mode = blk->total_rx_len > qup->in_fifo_sz;
|
||||
|
||||
if (blk->is_tx_blk_mode) {
|
||||
io_mode |= QUP_OUTPUT_BLK_MODE;
|
||||
|
@ -1528,9 +1526,9 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup,
|
|||
qup->use_dma = true;
|
||||
} else {
|
||||
qup->blk.is_tx_blk_mode = max_tx_len > qup->out_fifo_sz -
|
||||
QUP_MAX_TAGS_LEN ? true : false;
|
||||
QUP_MAX_TAGS_LEN;
|
||||
qup->blk.is_rx_blk_mode = max_rx_len > qup->in_fifo_sz -
|
||||
READ_RX_TAGS_LEN ? true : false;
|
||||
READ_RX_TAGS_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1660,7 +1658,6 @@ static int qup_i2c_probe(struct platform_device *pdev)
|
|||
static const int blk_sizes[] = {4, 16, 32};
|
||||
struct qup_i2c_dev *qup;
|
||||
unsigned long one_bit_t;
|
||||
struct resource *res;
|
||||
u32 io_mode, hw_ver, size;
|
||||
int ret, fs_div, hs_div;
|
||||
u32 src_clk_freq = DEFAULT_SRC_CLK;
|
||||
|
@ -1757,16 +1754,13 @@ nodma:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
qup->base = devm_ioremap_resource(qup->dev, res);
|
||||
qup->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(qup->base))
|
||||
return PTR_ERR(qup->base);
|
||||
|
||||
qup->irq = platform_get_irq(pdev, 0);
|
||||
if (qup->irq < 0) {
|
||||
dev_err(qup->dev, "No IRQ defined\n");
|
||||
if (qup->irq < 0)
|
||||
return qup->irq;
|
||||
}
|
||||
|
||||
if (has_acpi_companion(qup->dev)) {
|
||||
ret = device_property_read_u32(qup->dev,
|
||||
|
|
|
@ -938,9 +938,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
|
||||
priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
priv->io = devm_ioremap_resource(dev, priv->res);
|
||||
priv->io = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res);
|
||||
if (IS_ERR(priv->io))
|
||||
return PTR_ERR(priv->io);
|
||||
|
||||
|
|
|
@ -1193,7 +1193,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
|
|||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
struct rk3x_i2c *i2c;
|
||||
struct resource *mem;
|
||||
int ret = 0;
|
||||
int bus_nr;
|
||||
u32 value;
|
||||
|
@ -1223,8 +1222,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&i2c->lock);
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
return PTR_ERR(i2c->regs);
|
||||
|
||||
|
@ -1262,10 +1260,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
/* IRQ setup */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "cannot find rk3x IRQ\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq,
|
||||
0, dev_name(&pdev->dev), i2c);
|
||||
|
|
|
@ -1266,5 +1266,5 @@ static void __exit i2c_adap_s3c_exit(void)
|
|||
module_exit(i2c_adap_s3c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
|
||||
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
|
||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -366,7 +366,6 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
|
|||
|
||||
static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
|
||||
{
|
||||
unsigned char data;
|
||||
int real_pos;
|
||||
|
||||
/* switch from TX (address) to RX (data) adds two interrupts */
|
||||
|
@ -387,13 +386,11 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
|
|||
if (real_pos < 0)
|
||||
i2c_op(pd, OP_RX_STOP);
|
||||
else
|
||||
data = i2c_op(pd, OP_RX_STOP_DATA);
|
||||
pd->msg->buf[real_pos] = i2c_op(pd, OP_RX_STOP_DATA);
|
||||
} else if (real_pos >= 0) {
|
||||
data = i2c_op(pd, OP_RX);
|
||||
pd->msg->buf[real_pos] = i2c_op(pd, OP_RX);
|
||||
}
|
||||
|
||||
if (real_pos >= 0)
|
||||
pd->msg->buf[real_pos] = data;
|
||||
done:
|
||||
pd->pos++;
|
||||
return pd->pos == (pd->msg->len + 2);
|
||||
|
|
|
@ -271,7 +271,6 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct sirfsoc_i2c *siic;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *mem_res;
|
||||
struct clk *clk;
|
||||
int bitrate;
|
||||
int ctrl_speed;
|
||||
|
@ -309,8 +308,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
|
|||
adap = &siic->adapter;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
|
||||
siic->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(siic->base)) {
|
||||
err = PTR_ERR(siic->base);
|
||||
goto out;
|
||||
|
|
|
@ -492,10 +492,8 @@ static int sprd_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
i2c_dev->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c_dev->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get irq resource\n");
|
||||
if (i2c_dev->irq < 0)
|
||||
return i2c_dev->irq;
|
||||
}
|
||||
|
||||
i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
|
||||
init_completion(&i2c_dev->complete);
|
||||
|
|
|
@ -25,8 +25,9 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
/* Request and configure I2C TX dma channel */
|
||||
dma->chan_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
dev_dbg(dev, "can't request DMA tx channel\n");
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA tx channel\n");
|
||||
goto fail_al;
|
||||
}
|
||||
|
||||
|
@ -44,8 +45,10 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
/* Request and configure I2C RX dma channel */
|
||||
dma->chan_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
dev_err(dev, "can't request DMA rx channel\n");
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA rx channel\n");
|
||||
|
||||
goto fail_tx;
|
||||
}
|
||||
|
||||
|
@ -73,7 +76,8 @@ fail_tx:
|
|||
dma_release_channel(dma->chan_tx);
|
||||
fail_al:
|
||||
devm_kfree(dev, dma);
|
||||
dev_info(dev, "can't use DMA\n");
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_info(dev, "can't use DMA\n");
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
@ -797,8 +797,10 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(&pdev->dev, "Error: Missing controller reset\n");
|
||||
ret = PTR_ERR(rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Error: Missing reset ctrl\n");
|
||||
|
||||
goto clk_free;
|
||||
}
|
||||
reset_control_assert(rst);
|
||||
|
|
|
@ -189,8 +189,6 @@ struct stm32f7_i2c_regs {
|
|||
/**
|
||||
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||
* @rate: I2C bus speed (Hz)
|
||||
* @rate_min: 80% of I2C bus speed (Hz)
|
||||
* @rate_max: 100% of I2C bus speed (Hz)
|
||||
* @fall_max: Max fall time of both SDA and SCL signals (ns)
|
||||
* @rise_max: Max rise time of both SDA and SCL signals (ns)
|
||||
* @hddat_min: Min data hold time (ns)
|
||||
|
@ -201,8 +199,6 @@ struct stm32f7_i2c_regs {
|
|||
*/
|
||||
struct stm32f7_i2c_spec {
|
||||
u32 rate;
|
||||
u32 rate_min;
|
||||
u32 rate_max;
|
||||
u32 fall_max;
|
||||
u32 rise_max;
|
||||
u32 hddat_min;
|
||||
|
@ -214,7 +210,6 @@ struct stm32f7_i2c_spec {
|
|||
|
||||
/**
|
||||
* struct stm32f7_i2c_setup - private I2C timing setup parameters
|
||||
* @speed: I2C speed mode (standard, Fast Plus)
|
||||
* @speed_freq: I2C speed frequency (Hz)
|
||||
* @clock_src: I2C clock source frequency (Hz)
|
||||
* @rise_time: Rise time (ns)
|
||||
|
@ -224,7 +219,6 @@ struct stm32f7_i2c_spec {
|
|||
* @fmp_clr_offset: Fast Mode Plus clear register offset from set register
|
||||
*/
|
||||
struct stm32f7_i2c_setup {
|
||||
enum stm32_i2c_speed speed;
|
||||
u32 speed_freq;
|
||||
u32 clock_src;
|
||||
u32 rise_time;
|
||||
|
@ -287,7 +281,7 @@ struct stm32f7_i2c_msg {
|
|||
* @base: virtual memory area
|
||||
* @complete: completion of I2C message
|
||||
* @clk: hw i2c clock
|
||||
* @speed: I2C clock frequency of the controller. Standard, Fast or Fast+
|
||||
* @bus_rate: I2C clock frequency of the controller
|
||||
* @msg: Pointer to data to be written
|
||||
* @msg_num: number of I2C messages to be executed
|
||||
* @msg_id: message identifiant
|
||||
|
@ -314,7 +308,7 @@ struct stm32f7_i2c_dev {
|
|||
void __iomem *base;
|
||||
struct completion complete;
|
||||
struct clk *clk;
|
||||
int speed;
|
||||
unsigned int bus_rate;
|
||||
struct i2c_msg *msg;
|
||||
unsigned int msg_num;
|
||||
unsigned int msg_id;
|
||||
|
@ -342,11 +336,9 @@ struct stm32f7_i2c_dev {
|
|||
* Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,
|
||||
* and Fast-mode Plus I2C-bus devices
|
||||
*/
|
||||
static struct stm32f7_i2c_spec i2c_specs[] = {
|
||||
[STM32_I2C_SPEED_STANDARD] = {
|
||||
static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = {
|
||||
{
|
||||
.rate = I2C_MAX_STANDARD_MODE_FREQ,
|
||||
.rate_min = I2C_MAX_STANDARD_MODE_FREQ * 8 / 10, /* 80% */
|
||||
.rate_max = I2C_MAX_STANDARD_MODE_FREQ,
|
||||
.fall_max = 300,
|
||||
.rise_max = 1000,
|
||||
.hddat_min = 0,
|
||||
|
@ -355,10 +347,8 @@ static struct stm32f7_i2c_spec i2c_specs[] = {
|
|||
.l_min = 4700,
|
||||
.h_min = 4000,
|
||||
},
|
||||
[STM32_I2C_SPEED_FAST] = {
|
||||
{
|
||||
.rate = I2C_MAX_FAST_MODE_FREQ,
|
||||
.rate_min = I2C_MAX_FAST_MODE_FREQ * 8 / 10, /* 80% */
|
||||
.rate_max = I2C_MAX_FAST_MODE_FREQ,
|
||||
.fall_max = 300,
|
||||
.rise_max = 300,
|
||||
.hddat_min = 0,
|
||||
|
@ -367,10 +357,8 @@ static struct stm32f7_i2c_spec i2c_specs[] = {
|
|||
.l_min = 1300,
|
||||
.h_min = 600,
|
||||
},
|
||||
[STM32_I2C_SPEED_FAST_PLUS] = {
|
||||
{
|
||||
.rate = I2C_MAX_FAST_MODE_PLUS_FREQ,
|
||||
.rate_min = I2C_MAX_FAST_MODE_PLUS_FREQ * 8 / 10, /* 80% */
|
||||
.rate_max = I2C_MAX_FAST_MODE_PLUS_FREQ,
|
||||
.fall_max = 100,
|
||||
.rise_max = 120,
|
||||
.hddat_min = 0,
|
||||
|
@ -411,10 +399,23 @@ static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
|
|||
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
|
||||
}
|
||||
|
||||
static struct stm32f7_i2c_spec *stm32f7_get_specs(u32 rate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stm32f7_i2c_specs); i++)
|
||||
if (rate <= stm32f7_i2c_specs[i].rate)
|
||||
return &stm32f7_i2c_specs[i];
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
#define RATE_MIN(rate) ((rate) * 8 / 10)
|
||||
static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
||||
struct stm32f7_i2c_setup *setup,
|
||||
struct stm32f7_i2c_timings *output)
|
||||
{
|
||||
struct stm32f7_i2c_spec *specs;
|
||||
u32 p_prev = STM32F7_PRESC_MAX;
|
||||
u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
|
||||
setup->clock_src);
|
||||
|
@ -432,18 +433,19 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
u16 p, l, a, h;
|
||||
int ret = 0;
|
||||
|
||||
if (setup->speed >= STM32_I2C_SPEED_END) {
|
||||
dev_err(i2c_dev->dev, "speed out of bound {%d/%d}\n",
|
||||
setup->speed, STM32_I2C_SPEED_END - 1);
|
||||
specs = stm32f7_get_specs(setup->speed_freq);
|
||||
if (specs == ERR_PTR(-EINVAL)) {
|
||||
dev_err(i2c_dev->dev, "speed out of bound {%d}\n",
|
||||
setup->speed_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
|
||||
(setup->fall_time > i2c_specs[setup->speed].fall_max)) {
|
||||
if ((setup->rise_time > specs->rise_max) ||
|
||||
(setup->fall_time > specs->fall_max)) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
|
||||
setup->rise_time, i2c_specs[setup->speed].rise_max,
|
||||
setup->fall_time, i2c_specs[setup->speed].fall_max);
|
||||
setup->rise_time, specs->rise_max,
|
||||
setup->fall_time, specs->fall_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -454,12 +456,6 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (setup->speed_freq > i2c_specs[setup->speed].rate) {
|
||||
dev_err(i2c_dev->dev, "ERROR: Freq {%d/%d}\n",
|
||||
setup->speed_freq, i2c_specs[setup->speed].rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Analog and Digital Filters */
|
||||
af_delay_min =
|
||||
(setup->analog_filter ?
|
||||
|
@ -469,13 +465,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
|
||||
dnf_delay = setup->dnf * i2cclk;
|
||||
|
||||
sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
|
||||
sdadel_min = specs->hddat_min + setup->fall_time -
|
||||
af_delay_min - (setup->dnf + 3) * i2cclk;
|
||||
|
||||
sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
|
||||
sdadel_max = specs->vddat_max - setup->rise_time -
|
||||
af_delay_max - (setup->dnf + 4) * i2cclk;
|
||||
|
||||
scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
|
||||
scldel_min = setup->rise_time + specs->sudat_min;
|
||||
|
||||
if (sdadel_min < 0)
|
||||
sdadel_min = 0;
|
||||
|
@ -530,8 +526,8 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
|
||||
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
|
||||
s = NULL;
|
||||
clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
|
||||
clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
|
||||
clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq);
|
||||
clk_min = NSEC_PER_SEC / setup->speed_freq;
|
||||
|
||||
/*
|
||||
* Among Prescaler possibilities discovered above figures out SCL Low
|
||||
|
@ -549,7 +545,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
for (l = 0; l < STM32F7_SCLL_MAX; l++) {
|
||||
u32 tscl_l = (l + 1) * prescaler + tsync;
|
||||
|
||||
if ((tscl_l < i2c_specs[setup->speed].l_min) ||
|
||||
if ((tscl_l < specs->l_min) ||
|
||||
(i2cclk >=
|
||||
((tscl_l - af_delay_min - dnf_delay) / 4))) {
|
||||
continue;
|
||||
|
@ -561,7 +557,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
setup->rise_time + setup->fall_time;
|
||||
|
||||
if ((tscl >= clk_min) && (tscl <= clk_max) &&
|
||||
(tscl_h >= i2c_specs[setup->speed].h_min) &&
|
||||
(tscl_h >= specs->h_min) &&
|
||||
(i2cclk < tscl_h)) {
|
||||
int clk_error = tscl - i2cbus;
|
||||
|
||||
|
@ -607,6 +603,17 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 stm32f7_get_lower_rate(u32 rate)
|
||||
{
|
||||
int i = ARRAY_SIZE(stm32f7_i2c_specs);
|
||||
|
||||
while (--i)
|
||||
if (stm32f7_i2c_specs[i].rate < rate)
|
||||
break;
|
||||
|
||||
return stm32f7_i2c_specs[i].rate;
|
||||
}
|
||||
|
||||
static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
||||
struct stm32f7_i2c_setup *setup)
|
||||
{
|
||||
|
@ -619,18 +626,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
|
||||
i2c_parse_fw_timings(i2c_dev->dev, t, false);
|
||||
|
||||
if (t->bus_freq_hz >= I2C_MAX_FAST_MODE_PLUS_FREQ)
|
||||
i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
|
||||
else if (t->bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ)
|
||||
i2c_dev->speed = STM32_I2C_SPEED_FAST;
|
||||
else
|
||||
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
||||
if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) {
|
||||
dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n",
|
||||
t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
setup->speed_freq = t->bus_freq_hz;
|
||||
i2c_dev->setup.rise_time = t->scl_rise_ns;
|
||||
i2c_dev->setup.fall_time = t->scl_fall_ns;
|
||||
|
||||
setup->speed = i2c_dev->speed;
|
||||
setup->speed_freq = i2c_specs[setup->speed].rate;
|
||||
setup->clock_src = clk_get_rate(i2c_dev->clk);
|
||||
|
||||
if (!setup->clock_src) {
|
||||
|
@ -644,17 +648,13 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to compute I2C timings.\n");
|
||||
if (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) {
|
||||
i2c_dev->speed--;
|
||||
setup->speed = i2c_dev->speed;
|
||||
setup->speed_freq =
|
||||
i2c_specs[setup->speed].rate;
|
||||
dev_warn(i2c_dev->dev,
|
||||
"downgrade I2C Speed Freq to (%i)\n",
|
||||
i2c_specs[setup->speed].rate);
|
||||
} else {
|
||||
if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ)
|
||||
break;
|
||||
}
|
||||
setup->speed_freq =
|
||||
stm32f7_get_lower_rate(setup->speed_freq);
|
||||
dev_warn(i2c_dev->dev,
|
||||
"downgrade I2C Speed Freq to (%i)\n",
|
||||
setup->speed_freq);
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
|
@ -663,13 +663,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n",
|
||||
setup->speed, setup->speed_freq, setup->clock_src);
|
||||
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
|
||||
setup->speed_freq, setup->clock_src);
|
||||
dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
|
||||
setup->rise_time, setup->fall_time);
|
||||
dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
|
||||
(setup->analog_filter ? "On" : "Off"), setup->dnf);
|
||||
|
||||
i2c_dev->bus_rate = setup->speed_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1464,8 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
|
|||
|
||||
/* NACK received */
|
||||
if (status & STM32F7_I2C_ISR_NACKF) {
|
||||
dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
|
||||
dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n",
|
||||
__func__, f7_msg->addr);
|
||||
writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
|
||||
f7_msg->result = -ENXIO;
|
||||
}
|
||||
|
@ -1866,7 +1869,7 @@ static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (i2c_dev->speed != STM32_I2C_SPEED_FAST_PLUS ||
|
||||
if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ ||
|
||||
IS_ERR_OR_NULL(i2c_dev->regmap))
|
||||
/* Optional */
|
||||
return 0;
|
||||
|
@ -1940,8 +1943,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
phy_addr = (dma_addr_t)res->start;
|
||||
|
@ -1967,7 +1969,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(&pdev->dev, "Error: Missing controller clock\n");
|
||||
if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Failed to get controller clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
|
||||
|
@ -1979,8 +1982,10 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
rst = devm_reset_control_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(&pdev->dev, "Error: Missing controller reset\n");
|
||||
ret = PTR_ERR(rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Error: Missing reset ctrl\n");
|
||||
|
||||
goto clk_free;
|
||||
}
|
||||
reset_control_assert(rst);
|
||||
|
@ -2020,7 +2025,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto clk_free;
|
||||
|
||||
if (i2c_dev->speed == STM32_I2C_SPEED_FAST_PLUS) {
|
||||
/* Setup Fast mode plus if necessary */
|
||||
if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) {
|
||||
ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
|
|
|
@ -860,7 +860,6 @@ static int stu300_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct stu300_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
int bus_nr;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -876,8 +875,7 @@ static int stu300_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->virtbase = devm_ioremap_resource(&pdev->dev, res);
|
||||
dev->virtbase = devm_platform_ioremap_resource(pdev, 0);
|
||||
dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
|
||||
"base %p\n", bus_nr, dev->virtbase);
|
||||
if (IS_ERR(dev->virtbase))
|
||||
|
|
|
@ -187,7 +187,6 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
struct device_node *childnp;
|
||||
unsigned long parent_clk_freq;
|
||||
u32 clk_freq = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
struct resource *r;
|
||||
struct p2wi *p2wi;
|
||||
u32 slave_addr;
|
||||
int clk_div;
|
||||
|
@ -231,17 +230,14 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
p2wi->slave_addr = slave_addr;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
p2wi->regs = devm_ioremap_resource(dev, r);
|
||||
p2wi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p2wi->regs))
|
||||
return PTR_ERR(p2wi->regs);
|
||||
|
||||
strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to retrieve irq: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
p2wi->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(p2wi->clk)) {
|
||||
|
|
|
@ -536,7 +536,6 @@ static const struct i2c_adapter synquacer_i2c_ops = {
|
|||
static int synquacer_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct synquacer_i2c *i2c;
|
||||
struct resource *r;
|
||||
u32 bus_speed;
|
||||
int ret;
|
||||
|
||||
|
@ -574,16 +573,13 @@ static int synquacer_i2c_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->base = devm_ioremap_resource(&pdev->dev, r);
|
||||
i2c->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->base))
|
||||
return PTR_ERR(i2c->base);
|
||||
|
||||
i2c->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c->irq < 0) {
|
||||
dev_err(&pdev->dev, "no IRQ resource found\n");
|
||||
if (i2c->irq < 0)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr,
|
||||
0, dev_name(&pdev->dev), i2c);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Author: Colin Cross <ccross@android.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
@ -29,16 +30,17 @@
|
|||
#define BYTES_PER_FIFO_WORD 4
|
||||
|
||||
#define I2C_CNFG 0x000
|
||||
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
|
||||
#define I2C_CNFG_DEBOUNCE_CNT GENMASK(14, 12)
|
||||
#define I2C_CNFG_PACKET_MODE_EN BIT(10)
|
||||
#define I2C_CNFG_NEW_MASTER_FSM BIT(11)
|
||||
#define I2C_CNFG_MULTI_MASTER_MODE BIT(17)
|
||||
#define I2C_STATUS 0x01C
|
||||
#define I2C_STATUS 0x01c
|
||||
#define I2C_SL_CNFG 0x020
|
||||
#define I2C_SL_CNFG_NACK BIT(1)
|
||||
#define I2C_SL_CNFG_NEWSL BIT(2)
|
||||
#define I2C_SL_ADDR1 0x02c
|
||||
#define I2C_SL_ADDR2 0x030
|
||||
#define I2C_TLOW_SEXT 0x034
|
||||
#define I2C_TX_FIFO 0x050
|
||||
#define I2C_RX_FIFO 0x054
|
||||
#define I2C_PACKET_TRANSFER_STATUS 0x058
|
||||
|
@ -48,10 +50,8 @@
|
|||
#define I2C_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 5)
|
||||
#define I2C_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 2)
|
||||
#define I2C_FIFO_STATUS 0x060
|
||||
#define I2C_FIFO_STATUS_TX_MASK 0xF0
|
||||
#define I2C_FIFO_STATUS_TX_SHIFT 4
|
||||
#define I2C_FIFO_STATUS_RX_MASK 0x0F
|
||||
#define I2C_FIFO_STATUS_RX_SHIFT 0
|
||||
#define I2C_FIFO_STATUS_TX GENMASK(7, 4)
|
||||
#define I2C_FIFO_STATUS_RX GENMASK(3, 0)
|
||||
#define I2C_INT_MASK 0x064
|
||||
#define I2C_INT_STATUS 0x068
|
||||
#define I2C_INT_BUS_CLR_DONE BIT(11)
|
||||
|
@ -61,7 +61,8 @@
|
|||
#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
|
||||
#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
|
||||
#define I2C_CLK_DIVISOR 0x06c
|
||||
#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
|
||||
#define I2C_CLK_DIVISOR_STD_FAST_MODE GENMASK(31, 16)
|
||||
#define I2C_CLK_DIVISOR_HSMODE GENMASK(15, 0)
|
||||
|
||||
#define DVC_CTRL_REG1 0x000
|
||||
#define DVC_CTRL_REG1_INTR_EN BIT(10)
|
||||
|
@ -77,10 +78,11 @@
|
|||
#define I2C_ERR_UNKNOWN_INTERRUPT BIT(2)
|
||||
#define I2C_ERR_RX_BUFFER_OVERFLOW BIT(3)
|
||||
|
||||
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
|
||||
#define PACKET_HEADER0_PACKET_ID_SHIFT 16
|
||||
#define PACKET_HEADER0_CONT_ID_SHIFT 12
|
||||
#define PACKET_HEADER0_PROTOCOL_I2C BIT(4)
|
||||
#define PACKET_HEADER0_HEADER_SIZE GENMASK(29, 28)
|
||||
#define PACKET_HEADER0_PACKET_ID GENMASK(23, 16)
|
||||
#define PACKET_HEADER0_CONT_ID GENMASK(15, 12)
|
||||
#define PACKET_HEADER0_PROTOCOL GENMASK(7, 4)
|
||||
#define PACKET_HEADER0_PROTOCOL_I2C 1
|
||||
|
||||
#define I2C_HEADER_CONT_ON_NAK BIT(21)
|
||||
#define I2C_HEADER_READ BIT(19)
|
||||
|
@ -91,21 +93,35 @@
|
|||
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
|
||||
|
||||
#define I2C_BUS_CLEAR_CNFG 0x084
|
||||
#define I2C_BC_SCLK_THRESHOLD 9
|
||||
#define I2C_BC_SCLK_THRESHOLD_SHIFT 16
|
||||
#define I2C_BC_SCLK_THRESHOLD GENMASK(23, 16)
|
||||
#define I2C_BC_STOP_COND BIT(2)
|
||||
#define I2C_BC_TERMINATE BIT(1)
|
||||
#define I2C_BC_ENABLE BIT(0)
|
||||
#define I2C_BUS_CLEAR_STATUS 0x088
|
||||
#define I2C_BC_STATUS BIT(0)
|
||||
|
||||
#define I2C_CONFIG_LOAD 0x08C
|
||||
#define I2C_CONFIG_LOAD 0x08c
|
||||
#define I2C_MSTR_CONFIG_LOAD BIT(0)
|
||||
|
||||
#define I2C_CLKEN_OVERRIDE 0x090
|
||||
#define I2C_MST_CORE_CLKEN_OVR BIT(0)
|
||||
|
||||
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
|
||||
#define I2C_INTERFACE_TIMING_0 0x094
|
||||
#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8)
|
||||
#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0)
|
||||
#define I2C_INTERFACE_TIMING_1 0x098
|
||||
#define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24)
|
||||
#define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
|
||||
#define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
|
||||
#define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
|
||||
|
||||
#define I2C_HS_INTERFACE_TIMING_0 0x09c
|
||||
#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8)
|
||||
#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0)
|
||||
#define I2C_HS_INTERFACE_TIMING_1 0x0a0
|
||||
#define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
|
||||
#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
|
||||
#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
|
||||
|
||||
#define I2C_MST_FIFO_CONTROL 0x0b4
|
||||
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
|
||||
|
@ -114,14 +130,11 @@
|
|||
#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16)
|
||||
|
||||
#define I2C_MST_FIFO_STATUS 0x0b8
|
||||
#define I2C_MST_FIFO_STATUS_RX_MASK 0xff
|
||||
#define I2C_MST_FIFO_STATUS_RX_SHIFT 0
|
||||
#define I2C_MST_FIFO_STATUS_TX_MASK 0xff0000
|
||||
#define I2C_MST_FIFO_STATUS_TX_SHIFT 16
|
||||
#define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16)
|
||||
#define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0)
|
||||
|
||||
#define I2C_INTERFACE_TIMING_0 0x94
|
||||
#define I2C_THIGH_SHIFT 8
|
||||
#define I2C_INTERFACE_TIMING_1 0x98
|
||||
/* configuration load timeout in microseconds */
|
||||
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
|
||||
|
||||
/* Packet header size in bytes */
|
||||
#define I2C_PACKET_HEADER_SIZE 12
|
||||
|
@ -230,6 +243,7 @@ struct tegra_i2c_hw_feature {
|
|||
* @cont_id: I2C controller ID, used for packet header
|
||||
* @irq: IRQ number of transfer complete interrupt
|
||||
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||
* @is_vi: identifies the VI I2C controller, has a different register layout
|
||||
* @msg_complete: transfer completion notifier
|
||||
* @msg_err: error code for completed message
|
||||
* @msg_buf: pointer to current message data
|
||||
|
@ -253,12 +267,14 @@ struct tegra_i2c_dev {
|
|||
struct i2c_adapter adapter;
|
||||
struct clk *div_clk;
|
||||
struct clk *fast_clk;
|
||||
struct clk *slow_clk;
|
||||
struct reset_control *rst;
|
||||
void __iomem *base;
|
||||
phys_addr_t base_phys;
|
||||
int cont_id;
|
||||
int irq;
|
||||
int is_dvc;
|
||||
bool is_vi;
|
||||
struct completion msg_complete;
|
||||
int msg_err;
|
||||
u8 *msg_buf;
|
||||
|
@ -297,6 +313,8 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
|
|||
{
|
||||
if (i2c_dev->is_dvc)
|
||||
reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
|
||||
else if (i2c_dev->is_vi)
|
||||
reg = 0xc00 + (reg << 2);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
@ -495,12 +513,10 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
if (i2c_dev->hw->has_mst_fifo) {
|
||||
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
|
||||
rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
|
||||
I2C_MST_FIFO_STATUS_RX_SHIFT;
|
||||
rx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_RX, val);
|
||||
} else {
|
||||
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
|
||||
rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
|
||||
I2C_FIFO_STATUS_RX_SHIFT;
|
||||
rx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_RX, val);
|
||||
}
|
||||
|
||||
/* Rounds down to not include partial word at the end of buf */
|
||||
|
@ -551,12 +567,10 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
if (i2c_dev->hw->has_mst_fifo) {
|
||||
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
|
||||
tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >>
|
||||
I2C_MST_FIFO_STATUS_TX_SHIFT;
|
||||
tx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_TX, val);
|
||||
} else {
|
||||
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
|
||||
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
|
||||
I2C_FIFO_STATUS_TX_SHIFT;
|
||||
tx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_TX, val);
|
||||
}
|
||||
|
||||
/* Rounds down to not include partial word at the end of buf */
|
||||
|
@ -650,6 +664,14 @@ static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (i2c_dev->slow_clk) {
|
||||
ret = clk_enable(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable slow clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_enable(i2c_dev->div_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev,
|
||||
|
@ -666,6 +688,10 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
|||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(i2c_dev->div_clk);
|
||||
|
||||
if (i2c_dev->slow_clk)
|
||||
clk_disable(i2c_dev->slow_clk);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_disable(i2c_dev->fast_clk);
|
||||
|
||||
|
@ -703,6 +729,35 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
|
||||
|
||||
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
|
||||
i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
|
||||
|
||||
i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
|
||||
}
|
||||
|
||||
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
||||
{
|
||||
u32 val;
|
||||
|
@ -719,7 +774,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
tegra_dvc_init(i2c_dev);
|
||||
|
||||
val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
|
||||
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
|
||||
FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2);
|
||||
|
||||
if (i2c_dev->hw->has_multi_master_mode)
|
||||
val |= I2C_CNFG_MULTI_MASTER_MODE;
|
||||
|
@ -727,10 +782,14 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
i2c_writel(i2c_dev, val, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
|
||||
|
||||
if (i2c_dev->is_vi)
|
||||
tegra_i2c_vi_init(i2c_dev);
|
||||
|
||||
/* Make sure clock divisor programmed correctly */
|
||||
clk_divisor = i2c_dev->hw->clk_divisor_hs_mode;
|
||||
clk_divisor |= i2c_dev->clk_divisor_non_hs_mode <<
|
||||
I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT;
|
||||
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
|
||||
i2c_dev->hw->clk_divisor_hs_mode) |
|
||||
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE,
|
||||
i2c_dev->clk_divisor_non_hs_mode);
|
||||
i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
|
||||
|
||||
if (i2c_dev->bus_clk_rate > I2C_MAX_STANDARD_MODE_FREQ &&
|
||||
|
@ -745,7 +804,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
}
|
||||
|
||||
if (i2c_dev->hw->has_interface_timing_reg) {
|
||||
val = (thigh << I2C_THIGH_SHIFT) | tlow;
|
||||
val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
|
||||
i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
|
||||
}
|
||||
|
||||
|
@ -768,7 +828,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
}
|
||||
}
|
||||
|
||||
if (!i2c_dev->is_dvc) {
|
||||
if (!i2c_dev->is_dvc && !i2c_dev->is_vi) {
|
||||
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
|
||||
|
||||
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
|
||||
|
@ -996,14 +1056,13 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
|||
do {
|
||||
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
|
||||
if (status) {
|
||||
if (status)
|
||||
tegra_i2c_isr(i2c_dev->irq, i2c_dev);
|
||||
|
||||
if (completion_done(complete)) {
|
||||
s64 delta = ktime_ms_delta(ktimeout, ktime);
|
||||
if (completion_done(complete)) {
|
||||
s64 delta = ktime_ms_delta(ktimeout, ktime);
|
||||
|
||||
return msecs_to_jiffies(delta) ?: 1;
|
||||
}
|
||||
return msecs_to_jiffies(delta) ?: 1;
|
||||
}
|
||||
|
||||
ktime = ktime_get();
|
||||
|
@ -1030,14 +1089,18 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
|||
disable_irq(i2c_dev->irq);
|
||||
|
||||
/*
|
||||
* There is a chance that completion may happen after IRQ
|
||||
* synchronization, which is done by disable_irq().
|
||||
* Under some rare circumstances (like running KASAN +
|
||||
* NFS root) CPU, which handles interrupt, may stuck in
|
||||
* uninterruptible state for a significant time. In this
|
||||
* case we will get timeout if I2C transfer is running on
|
||||
* a sibling CPU, despite of IRQ being raised.
|
||||
*
|
||||
* In order to handle this rare condition, the IRQ status
|
||||
* needs to be checked after timeout.
|
||||
*/
|
||||
if (ret == 0 && completion_done(complete)) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"completion done after timeout\n");
|
||||
ret = 1;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = tegra_i2c_poll_completion_timeout(i2c_dev,
|
||||
complete, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1051,8 +1114,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
|||
u32 reg;
|
||||
|
||||
reinit_completion(&i2c_dev->msg_complete);
|
||||
reg = (I2C_BC_SCLK_THRESHOLD << I2C_BC_SCLK_THRESHOLD_SHIFT) |
|
||||
I2C_BC_STOP_COND | I2C_BC_TERMINATE;
|
||||
reg = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
|
||||
I2C_BC_TERMINATE;
|
||||
i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
|
||||
if (i2c_dev->hw->has_config_load_reg) {
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
|
@ -1145,10 +1208,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
}
|
||||
}
|
||||
|
||||
packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
|
||||
PACKET_HEADER0_PROTOCOL_I2C |
|
||||
(i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
|
||||
(1 << PACKET_HEADER0_PACKET_ID_SHIFT);
|
||||
packet_header = FIELD_PREP(PACKET_HEADER0_HEADER_SIZE, 0) |
|
||||
FIELD_PREP(PACKET_HEADER0_PROTOCOL,
|
||||
PACKET_HEADER0_PROTOCOL_I2C) |
|
||||
FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
|
||||
FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
|
||||
if (dma && !i2c_dev->msg_read)
|
||||
*buffer++ = packet_header;
|
||||
else
|
||||
|
@ -1216,6 +1280,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->dma_complete, xfer_time);
|
||||
|
||||
/*
|
||||
* Synchronize DMA first, since dmaengine_terminate_sync()
|
||||
* performs synchronization after the transfer's termination
|
||||
* and we want to get a completion if transfer succeeded.
|
||||
*/
|
||||
dmaengine_synchronize(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
|
||||
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
|
@ -1544,6 +1617,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
|
|||
static const struct of_device_id tegra_i2c_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
|
||||
|
@ -1556,6 +1630,7 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
|
|||
|
||||
static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tegra_i2c_dev *i2c_dev;
|
||||
struct resource *res;
|
||||
struct clk *div_clk;
|
||||
|
@ -1611,6 +1686,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
i2c_dev->hw = of_device_get_match_data(&pdev->dev);
|
||||
i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
|
||||
"nvidia,tegra20-i2c-dvc");
|
||||
i2c_dev->is_vi = of_device_is_compatible(dev->of_node,
|
||||
"nvidia,tegra210-i2c-vi");
|
||||
i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
|
||||
i2c_dev->dma_buf_size = i2c_dev->adapter.quirks->max_write_len +
|
||||
I2C_PACKET_HEADER_SIZE;
|
||||
|
@ -1626,6 +1703,17 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
i2c_dev->fast_clk = fast_clk;
|
||||
}
|
||||
|
||||
if (i2c_dev->is_vi) {
|
||||
i2c_dev->slow_clk = devm_clk_get(dev, "slow");
|
||||
if (IS_ERR(i2c_dev->slow_clk)) {
|
||||
if (PTR_ERR(i2c_dev->slow_clk) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get slow clock: %ld\n",
|
||||
PTR_ERR(i2c_dev->slow_clk));
|
||||
|
||||
return PTR_ERR(i2c_dev->slow_clk);
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source) {
|
||||
|
@ -1636,6 +1724,14 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (i2c_dev->slow_clk) {
|
||||
ret = clk_prepare(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
|
||||
goto unprepare_fast_clk;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ &&
|
||||
i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ)
|
||||
i2c_dev->clk_divisor_non_hs_mode =
|
||||
|
@ -1651,7 +1747,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
ret = clk_prepare(i2c_dev->div_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
|
||||
goto unprepare_fast_clk;
|
||||
goto unprepare_slow_clk;
|
||||
}
|
||||
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
|
@ -1694,8 +1790,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq, tegra_i2c_isr,
|
||||
IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
goto release_dma;
|
||||
|
@ -1738,6 +1834,10 @@ disable_rpm:
|
|||
unprepare_div_clk:
|
||||
clk_unprepare(i2c_dev->div_clk);
|
||||
|
||||
unprepare_slow_clk:
|
||||
if (i2c_dev->is_vi)
|
||||
clk_unprepare(i2c_dev->slow_clk);
|
||||
|
||||
unprepare_fast_clk:
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_unprepare(i2c_dev->fast_clk);
|
||||
|
@ -1759,6 +1859,10 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
|||
tegra_i2c_runtime_suspend(&pdev->dev);
|
||||
|
||||
clk_unprepare(i2c_dev->div_clk);
|
||||
|
||||
if (i2c_dev->slow_clk)
|
||||
clk_unprepare(i2c_dev->slow_clk);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_unprepare(i2c_dev->fast_clk);
|
||||
|
||||
|
@ -1769,15 +1873,14 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
|||
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
i2c_mark_adapter_suspended(&i2c_dev->adapter);
|
||||
|
||||
err = pm_runtime_force_suspend(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!pm_runtime_status_suspended(dev))
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
|
@ -1785,6 +1888,10 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
|||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
/*
|
||||
* We need to ensure that clocks are enabled so that registers can be
|
||||
* restored in tegra_i2c_init().
|
||||
*/
|
||||
err = tegra_i2c_runtime_resume(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1793,13 +1900,16 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = pm_runtime_force_resume(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/*
|
||||
* In case we are runtime suspended, disable clocks again so that we
|
||||
* don't unbalance the clock reference counts during the next runtime
|
||||
* resume transition.
|
||||
*/
|
||||
if (pm_runtime_status_suspended(dev)) {
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adapter);
|
||||
|
||||
|
|
|
@ -529,10 +529,8 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(priv->membase);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
|
||||
bus_speed = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
|
|
@ -324,10 +324,8 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(priv->membase);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
|
||||
bus_speed = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
|
|
@ -506,23 +506,19 @@ static int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv,
|
|||
static int xlp9xx_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct xlp9xx_i2c_dev *priv;
|
||||
struct resource *res;
|
||||
int err = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq <= 0) {
|
||||
dev_err(&pdev->dev, "invalid irq!\n");
|
||||
if (priv->irq <= 0)
|
||||
return priv->irq;
|
||||
}
|
||||
/* SMBAlert irq */
|
||||
priv->alert_data.irq = platform_get_irq(pdev, 1);
|
||||
if (priv->alert_data.irq <= 0)
|
||||
|
|
|
@ -362,7 +362,6 @@ static int xlr_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
const struct of_device_id *match;
|
||||
struct xlr_i2c_private *priv;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
unsigned long clk_rate;
|
||||
unsigned long clk_div;
|
||||
|
@ -380,8 +379,7 @@ static int xlr_i2c_probe(struct platform_device *pdev)
|
|||
else
|
||||
priv->cfg = &xlr_i2c_config_default;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->iobase = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->iobase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->iobase))
|
||||
return PTR_ERR(priv->iobase);
|
||||
|
||||
|
|
|
@ -502,7 +502,6 @@ static int zx2967_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct zx2967_i2c *i2c;
|
||||
void __iomem *reg_base;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
|
@ -510,8 +509,7 @@ static int zx2967_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg_base))
|
||||
return PTR_ERR(reg_base);
|
||||
|
||||
|
|
|
@ -468,16 +468,12 @@ struct notifier_block i2c_acpi_notifier = {
|
|||
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct i2c_acpi_lookup lookup;
|
||||
struct i2c_adapter *adapter;
|
||||
struct acpi_device *adev;
|
||||
LIST_HEAD(resource_list);
|
||||
int ret;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (!adev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
memset(&lookup, 0, sizeof(lookup));
|
||||
lookup.info = info;
|
||||
lookup.device_handle = acpi_device_handle(adev);
|
||||
|
|
|
@ -1598,6 +1598,18 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_del_adapter);
|
||||
|
||||
static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p,
|
||||
u32 def_val, bool use_def)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = device_property_read_u32(dev, prop_name, cur_val_p);
|
||||
if (ret && use_def)
|
||||
*cur_val_p = def_val;
|
||||
|
||||
dev_dbg(dev, "%s: %u\n", prop_name, *cur_val_p);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_parse_fw_timings - get I2C related timing parameters from firmware
|
||||
* @dev: The device to scan for I2C timing properties
|
||||
|
@ -1616,49 +1628,28 @@ EXPORT_SYMBOL(i2c_del_adapter);
|
|||
*/
|
||||
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults)
|
||||
{
|
||||
int ret;
|
||||
bool u = use_defaults;
|
||||
u32 d;
|
||||
|
||||
ret = device_property_read_u32(dev, "clock-frequency", &t->bus_freq_hz);
|
||||
if (ret && use_defaults)
|
||||
t->bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
i2c_parse_timing(dev, "clock-frequency", &t->bus_freq_hz,
|
||||
I2C_MAX_STANDARD_MODE_FREQ, u);
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns);
|
||||
if (ret && use_defaults) {
|
||||
if (t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ)
|
||||
t->scl_rise_ns = 1000;
|
||||
else if (t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ)
|
||||
t->scl_rise_ns = 300;
|
||||
else
|
||||
t->scl_rise_ns = 120;
|
||||
}
|
||||
d = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 :
|
||||
t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
|
||||
i2c_parse_timing(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns, d, u);
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns);
|
||||
if (ret && use_defaults) {
|
||||
if (t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ)
|
||||
t->scl_fall_ns = 300;
|
||||
else
|
||||
t->scl_fall_ns = 120;
|
||||
}
|
||||
d = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
|
||||
i2c_parse_timing(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns, d, u);
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns);
|
||||
if (ret && use_defaults)
|
||||
t->scl_int_delay_ns = 0;
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns);
|
||||
if (ret && use_defaults)
|
||||
t->sda_fall_ns = t->scl_fall_ns;
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns);
|
||||
if (ret && use_defaults)
|
||||
t->sda_hold_ns = 0;
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-digital-filter-width-ns", &t->digital_filter_width_ns);
|
||||
if (ret && use_defaults)
|
||||
t->digital_filter_width_ns = 0;
|
||||
|
||||
ret = device_property_read_u32(dev, "i2c-analog-filter-cutoff-frequency", &t->analog_filter_cutoff_freq_hz);
|
||||
if (ret && use_defaults)
|
||||
t->analog_filter_cutoff_freq_hz = 0;
|
||||
i2c_parse_timing(dev, "i2c-scl-internal-delay-ns",
|
||||
&t->scl_int_delay_ns, 0, u);
|
||||
i2c_parse_timing(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns,
|
||||
t->scl_fall_ns, u);
|
||||
i2c_parse_timing(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, u);
|
||||
i2c_parse_timing(dev, "i2c-digital-filter-width-ns",
|
||||
&t->digital_filter_width_ns, 0, u);
|
||||
i2c_parse_timing(dev, "i2c-analog-filter-cutoff-frequency",
|
||||
&t->analog_filter_cutoff_freq_hz, 0, u);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
|
||||
|
||||
|
@ -2195,7 +2186,6 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
|
|||
const unsigned short *address_list;
|
||||
struct i2c_client *temp_client;
|
||||
int i, err = 0;
|
||||
int adap_id = i2c_adapter_id(adapter);
|
||||
|
||||
address_list = driver->address_list;
|
||||
if (!driver->detect || !address_list)
|
||||
|
@ -2223,7 +2213,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
|
|||
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
|
||||
dev_dbg(&adapter->dev,
|
||||
"found normal entry for adapter %d, addr 0x%02x\n",
|
||||
adap_id, address_list[i]);
|
||||
i2c_adapter_id(adapter), address_list[i]);
|
||||
temp_client->addr = address_list[i];
|
||||
err = i2c_detect_address(temp_client, driver);
|
||||
if (unlikely(err))
|
||||
|
|
|
@ -23,9 +23,9 @@ int i2c_dev_irq_from_resources(const struct resource *resources,
|
|||
unsigned int num_resources);
|
||||
|
||||
/*
|
||||
* We only allow atomic transfers for very late communication, e.g. to send
|
||||
* the powerdown command to a PMIC. Atomic transfers are a corner case and not
|
||||
* for generic use!
|
||||
* We only allow atomic transfers for very late communication, e.g. to access a
|
||||
* PMIC when powering down. Atomic transfers are a corner case and not for
|
||||
* generic use!
|
||||
*/
|
||||
static inline bool i2c_in_atomic_xfer_mode(void)
|
||||
{
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
* Copyright (C) 2014 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
|
||||
* Copyright (C) 2014 by Renesas Electronics Corporation
|
||||
*
|
||||
* Because most IP blocks can only detect one I2C slave address anyhow, this
|
||||
* driver does not support simulating EEPROM types which take more than one
|
||||
* address. It is prepared to simulate bigger EEPROMs with an internal 16 bit
|
||||
* pointer, yet implementation is deferred until the need actually arises.
|
||||
* Because most slave IP cores can only detect one I2C slave address anyhow,
|
||||
* this driver does not support simulating EEPROM types which take more than
|
||||
* one address.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -18,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -40,7 +40,7 @@ struct eeprom_data {
|
|||
#define I2C_SLAVE_BYTELEN GENMASK(15, 0)
|
||||
#define I2C_SLAVE_FLAG_ADDR16 BIT(16)
|
||||
#define I2C_SLAVE_FLAG_RO BIT(17)
|
||||
#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | (_len))
|
||||
#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | ((_len) - 1))
|
||||
|
||||
static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
|
@ -120,24 +120,47 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
|
|||
return count;
|
||||
}
|
||||
|
||||
static int i2c_slave_init_eeprom_data(struct eeprom_data *eeprom, struct i2c_client *client,
|
||||
unsigned int size)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
const char *eeprom_data;
|
||||
int ret = device_property_read_string(&client->dev, "firmware-name", &eeprom_data);
|
||||
|
||||
if (!ret) {
|
||||
ret = request_firmware_into_buf(&fw, eeprom_data, &client->dev,
|
||||
eeprom->buffer, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
release_firmware(fw);
|
||||
} else {
|
||||
/* An empty eeprom typically has all bits set to 1 */
|
||||
memset(eeprom->buffer, 0xff, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct eeprom_data *eeprom;
|
||||
int ret;
|
||||
unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data);
|
||||
unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data) + 1;
|
||||
unsigned int flag_addr16 = FIELD_GET(I2C_SLAVE_FLAG_ADDR16, id->driver_data);
|
||||
|
||||
eeprom = devm_kzalloc(&client->dev, sizeof(struct eeprom_data) + size, GFP_KERNEL);
|
||||
if (!eeprom)
|
||||
return -ENOMEM;
|
||||
|
||||
eeprom->idx_write_cnt = 0;
|
||||
eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
|
||||
eeprom->address_mask = size - 1;
|
||||
eeprom->read_only = FIELD_GET(I2C_SLAVE_FLAG_RO, id->driver_data);
|
||||
spin_lock_init(&eeprom->buffer_lock);
|
||||
i2c_set_clientdata(client, eeprom);
|
||||
|
||||
ret = i2c_slave_init_eeprom_data(eeprom, client, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sysfs_bin_attr_init(&eeprom->bin);
|
||||
eeprom->bin.attr.name = "slave-eeprom";
|
||||
eeprom->bin.attr.mode = S_IRUSR | S_IWUSR;
|
||||
|
@ -175,6 +198,8 @@ static const struct i2c_device_id i2c_slave_eeprom_id[] = {
|
|||
{ "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ "slave-24c512", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c512ro", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
* i2c-smbus.c - SMBus extensions to the I2C protocol
|
||||
*
|
||||
* Copyright (C) 2008 David Brownell
|
||||
* Copyright (C) 2010 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2010-2019 Jean Delvare <jdelvare@suse.de>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -196,6 +197,107 @@ EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
|
|||
|
||||
module_i2c_driver(smbalert_driver);
|
||||
|
||||
/*
|
||||
* SPD is not part of SMBus but we include it here for convenience as the
|
||||
* target systems are the same.
|
||||
* Restrictions to automatic SPD instantiation:
|
||||
* - Only works if all filled slots have the same memory type
|
||||
* - Only works for DDR2, DDR3 and DDR4 for now
|
||||
* - Only works on systems with 1 to 4 memory slots
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_DMI)
|
||||
void i2c_register_spd(struct i2c_adapter *adap)
|
||||
{
|
||||
int n, slot_count = 0, dimm_count = 0;
|
||||
u16 handle;
|
||||
u8 common_mem_type = 0x0, mem_type;
|
||||
u64 mem_size;
|
||||
const char *name;
|
||||
|
||||
while ((handle = dmi_memdev_handle(slot_count)) != 0xffff) {
|
||||
slot_count++;
|
||||
|
||||
/* Skip empty slots */
|
||||
mem_size = dmi_memdev_size(handle);
|
||||
if (!mem_size)
|
||||
continue;
|
||||
|
||||
/* Skip undefined memory type */
|
||||
mem_type = dmi_memdev_type(handle);
|
||||
if (mem_type <= 0x02) /* Invalid, Other, Unknown */
|
||||
continue;
|
||||
|
||||
if (!common_mem_type) {
|
||||
/* First filled slot */
|
||||
common_mem_type = mem_type;
|
||||
} else {
|
||||
/* Check that all filled slots have the same type */
|
||||
if (mem_type != common_mem_type) {
|
||||
dev_warn(&adap->dev,
|
||||
"Different memory types mixed, not instantiating SPD\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
dimm_count++;
|
||||
}
|
||||
|
||||
/* No useful DMI data, bail out */
|
||||
if (!dimm_count)
|
||||
return;
|
||||
|
||||
dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n",
|
||||
dimm_count, slot_count);
|
||||
|
||||
if (slot_count > 4) {
|
||||
dev_warn(&adap->dev,
|
||||
"Systems with more than 4 memory slots not supported yet, not instantiating SPD\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (common_mem_type) {
|
||||
case 0x13: /* DDR2 */
|
||||
case 0x18: /* DDR3 */
|
||||
case 0x1C: /* LPDDR2 */
|
||||
case 0x1D: /* LPDDR3 */
|
||||
name = "spd";
|
||||
break;
|
||||
case 0x1A: /* DDR4 */
|
||||
case 0x1E: /* LPDDR4 */
|
||||
name = "ee1004";
|
||||
break;
|
||||
default:
|
||||
dev_info(&adap->dev,
|
||||
"Memory type 0x%02x not supported yet, not instantiating SPD\n",
|
||||
common_mem_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't know in which slots the memory modules are. We could
|
||||
* try to guess from the slot names, but that would be rather complex
|
||||
* and unreliable, so better probe all possible addresses until we
|
||||
* have found all memory modules.
|
||||
*/
|
||||
for (n = 0; n < slot_count && dimm_count; n++) {
|
||||
struct i2c_board_info info;
|
||||
unsigned short addr_list[2];
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
strlcpy(info.type, name, I2C_NAME_SIZE);
|
||||
addr_list[0] = 0x50 + n;
|
||||
addr_list[1] = I2C_CLIENT_END;
|
||||
|
||||
if (!IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL))) {
|
||||
dev_info(&adap->dev,
|
||||
"Successfully instantiated SPD at 0x%hx\n",
|
||||
addr_list[0]);
|
||||
dimm_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_register_spd);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("SMBus protocol extensions support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* I2C multiplexer
|
||||
*
|
||||
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
|
||||
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
|
||||
*
|
||||
* This module supports the PCA954x and PCA954x series of I2C multiplexer/switch
|
||||
* This module supports the PCA954x and PCA984x series of I2C multiplexer/switch
|
||||
* chips made by NXP Semiconductors.
|
||||
* This includes the:
|
||||
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
|
||||
|
@ -29,10 +30,6 @@
|
|||
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
|
||||
* and
|
||||
* pca9540.c from Jean Delvare <jdelvare@suse.de>.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
@ -43,10 +40,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <dt-bindings/mux/mux.h>
|
||||
|
@ -198,7 +193,6 @@ static const struct i2c_device_id pca954x_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca954x_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pca954x_of_match[] = {
|
||||
{ .compatible = "nxp,pca9540", .data = &chips[pca_9540] },
|
||||
{ .compatible = "nxp,pca9542", .data = &chips[pca_9542] },
|
||||
|
@ -215,7 +209,6 @@ static const struct of_device_id pca954x_of_match[] = {
|
|||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pca954x_of_match);
|
||||
#endif
|
||||
|
||||
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
|
||||
for this as they will try to lock adapter a second time */
|
||||
|
@ -327,21 +320,18 @@ static DEVICE_ATTR_RW(idle_state);
|
|||
static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct pca954x *data = dev_id;
|
||||
unsigned int child_irq;
|
||||
int ret, i, handled = 0;
|
||||
unsigned long pending;
|
||||
int ret, i;
|
||||
|
||||
ret = i2c_smbus_read_byte(data->client);
|
||||
if (ret < 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
for (i = 0; i < data->chip->nchans; i++) {
|
||||
if (ret & BIT(PCA954X_IRQ_OFFSET + i)) {
|
||||
child_irq = irq_linear_revmap(data->irq, i);
|
||||
handle_nested_irq(child_irq);
|
||||
handled++;
|
||||
}
|
||||
}
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1);
|
||||
for_each_set_bit(i, &pending, data->chip->nchans)
|
||||
handle_nested_irq(irq_linear_revmap(data->irq, i));
|
||||
|
||||
return IRQ_RETVAL(pending);
|
||||
}
|
||||
|
||||
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
|
||||
|
@ -390,11 +380,8 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
|
|||
static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
||||
{
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
int c, irq;
|
||||
|
||||
device_remove_file(&client->dev, &dev_attr_idle_state);
|
||||
|
||||
if (data->irq) {
|
||||
for (c = 0; c < data->chip->nchans; c++) {
|
||||
irq = irq_find_mapping(data->irq, c);
|
||||
|
@ -429,7 +416,6 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
{
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct gpio_desc *gpio;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct pca954x *data;
|
||||
|
@ -459,7 +445,7 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
udelay(1);
|
||||
}
|
||||
|
||||
data->chip = of_device_get_match_data(dev);
|
||||
data->chip = device_get_match_data(dev);
|
||||
if (!data->chip)
|
||||
data->chip = &chips[id->driver_data];
|
||||
|
||||
|
@ -481,8 +467,8 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
data->idle_state = MUX_IDLE_AS_IS;
|
||||
if (of_property_read_u32(np, "idle-state", &data->idle_state)) {
|
||||
if (np && of_property_read_bool(np, "i2c-mux-idle-disconnect"))
|
||||
if (device_property_read_u32(dev, "idle-state", &data->idle_state)) {
|
||||
if (device_property_read_bool(dev, "i2c-mux-idle-disconnect"))
|
||||
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||
}
|
||||
|
||||
|
@ -539,6 +525,8 @@ static int pca954x_remove(struct i2c_client *client)
|
|||
{
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
|
||||
device_remove_file(&client->dev, &dev_attr_idle_state);
|
||||
|
||||
pca954x_cleanup(muxc);
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,7 +553,7 @@ static struct i2c_driver pca954x_driver = {
|
|||
.driver = {
|
||||
.name = "pca954x",
|
||||
.pm = &pca954x_pm,
|
||||
.of_match_table = of_match_ptr(pca954x_of_match),
|
||||
.of_match_table = pca954x_of_match,
|
||||
},
|
||||
.probe = pca954x_probe,
|
||||
.remove = pca954x_remove,
|
||||
|
|
|
@ -101,6 +101,7 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
|
|||
struct mlxreg_core_data *data)
|
||||
{
|
||||
struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
struct i2c_client *client;
|
||||
|
||||
/* Notify user by sending hwmon uevent. */
|
||||
kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
|
||||
|
@ -121,18 +122,20 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
data->hpdev.client = i2c_new_device(data->hpdev.adapter,
|
||||
data->hpdev.brdinfo);
|
||||
if (!data->hpdev.client) {
|
||||
client = i2c_new_client_device(data->hpdev.adapter,
|
||||
data->hpdev.brdinfo);
|
||||
if (IS_ERR(client)) {
|
||||
dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
|
||||
data->hpdev.brdinfo->type, data->hpdev.nr +
|
||||
pdata->shift_nr, data->hpdev.brdinfo->addr);
|
||||
|
||||
i2c_put_adapter(data->hpdev.adapter);
|
||||
data->hpdev.adapter = NULL;
|
||||
return -EFAULT;
|
||||
return PTR_ERR(client);
|
||||
}
|
||||
|
||||
data->hpdev.client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* i2c-smbus.h - SMBus extensions to the I2C protocol
|
||||
*
|
||||
* Copyright (C) 2010 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2010-2019 Jean Delvare <jdelvare@suse.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_I2C_SMBUS_H
|
||||
|
@ -39,4 +39,10 @@ static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_DMI)
|
||||
void i2c_register_spd(struct i2c_adapter *adap);
|
||||
#else
|
||||
static inline void i2c_register_spd(struct i2c_adapter *adap) { }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_I2C_SMBUS_H */
|
||||
|
|
|
@ -351,14 +351,14 @@ static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
|
|||
return to_i2c_client(dev);
|
||||
}
|
||||
|
||||
static inline void *i2c_get_clientdata(const struct i2c_client *dev)
|
||||
static inline void *i2c_get_clientdata(const struct i2c_client *client)
|
||||
{
|
||||
return dev_get_drvdata(&dev->dev);
|
||||
return dev_get_drvdata(&client->dev);
|
||||
}
|
||||
|
||||
static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
|
||||
static inline void i2c_set_clientdata(struct i2c_client *client, void *data)
|
||||
{
|
||||
dev_set_drvdata(&dev->dev, data);
|
||||
dev_set_drvdata(&client->dev, data);
|
||||
}
|
||||
|
||||
/* I2C slave support */
|
||||
|
|
|
@ -7,54 +7,6 @@
|
|||
#ifndef _I2C_PXA_H_
|
||||
#define _I2C_PXA_H_
|
||||
|
||||
#if 0
|
||||
#define DEF_TIMEOUT 3
|
||||
#else
|
||||
/* need a longer timeout if we're dealing with the fact we may well be
|
||||
* looking at a multi-master environment
|
||||
*/
|
||||
#define DEF_TIMEOUT 32
|
||||
#endif
|
||||
|
||||
#define BUS_ERROR (-EREMOTEIO)
|
||||
#define XFER_NAKED (-ECONNREFUSED)
|
||||
#define I2C_RETRY (-2000) /* an error has occurred retry transmit */
|
||||
|
||||
/* ICR initialize bit values
|
||||
*
|
||||
* 15. FM 0 (100 Khz operation)
|
||||
* 14. UR 0 (No unit reset)
|
||||
* 13. SADIE 0 (Disables the unit from interrupting on slave addresses
|
||||
* matching its slave address)
|
||||
* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration
|
||||
* in master mode)
|
||||
* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode)
|
||||
* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent)
|
||||
* 9. IRFIE 1 (Enable interrupts from full buffer received)
|
||||
* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty)
|
||||
* 7. GCD 1 (Disables i2c unit response to general call messages as a slave)
|
||||
* 6. IUE 0 (Disable unit until we change settings)
|
||||
* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL)
|
||||
* 4. MA 0 (Only send stop with the ICR stop bit)
|
||||
* 3. TB 0 (We are not transmitting a byte initially)
|
||||
* 2. ACKNAK 0 (Send an ACK after the unit receives a byte)
|
||||
* 1. STOP 0 (Do not send a STOP)
|
||||
* 0. START 0 (Do not send a START)
|
||||
*
|
||||
*/
|
||||
#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
|
||||
|
||||
/* I2C status register init values
|
||||
*
|
||||
* 10. BED 1 (Clear bus error detected)
|
||||
* 9. SAD 1 (Clear slave address detected)
|
||||
* 7. IRF 1 (Clear IDBR Receive Full)
|
||||
* 6. ITE 1 (Clear IDBR Transmit Empty)
|
||||
* 5. ALD 1 (Clear Arbitration Loss Detected)
|
||||
* 4. SSD 1 (Clear Slave Stop Detected)
|
||||
*/
|
||||
#define I2C_ISR_INIT 0x7FF /* status register init */
|
||||
|
||||
struct i2c_pxa_platform_data {
|
||||
unsigned int class;
|
||||
unsigned int use_pio :1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче