Commit 99cc7ad4 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:

 - the core has now a lockless variant of i2c_smbus_xfer. Some open
   coded versions of this got removed in drivers. This also enables
   proper SCCB support in regmap.

 - locking got a more precise naming. i2c_{un}lock_adapter() had to go,
   and we know use i2c_lock_bus() consistently with flags like
   I2C_LOCK_ROOT_ADAPTER and I2C_LOCK_SEGMENT to avoid ambiguity.

 - the gpio fault injector got a new delicate testcase

 - the bus recovery procedure got fixed to handle the new testcase
   correctly

 - a new quirk flag for controllers not able to handle zero length
   messages together with driver updates to use it

 - new drivers: FSI bus attached I2C masters, GENI I2C controller, Owl
   family S900

 - and a good set of driver improvements and bugfixes

* 'i2c/for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (77 commits)
  i2c: rcar: implement STOP and REP_START according to docs
  i2c: rcar: refactor private flags
  i2c: core: ACPI: Make acpi_gsb_i2c_read_bytes() check i2c_transfer return value
  i2c: core: ACPI: Properly set status byte to 0 for multi-byte writes
  dt-bindings: i2c: rcar: Add r8a774a1 support
  dt-bindings: i2c: sh_mobile: Add r8a774a1 support
  i2c: imx: Simplify stopped state tracking
  i2c: imx: Fix race condition in dma read
  i2c: pasemi: remove hardcoded bus numbers on smbus
  i2c: designware: Add SPDX license tag
  i2c: designware: Convert to use struct i2c_timings
  i2c: core: Parse SDA hold time from firmware
  i2c: designware-pcidrv: Mark expected switch fall-through
  i2c: amd8111: Mark expected switch fall-through
  i2c: sh_mobile: use core to detect 'no zero length read' quirk
  i2c: xlr: use core to detect 'no zero length' quirk
  i2c: rcar: use core to detect 'no zero length' quirk
  i2c: stu300: use core to detect 'no zero length' quirk
  i2c: pmcmsp: use core to detect 'no zero length' quirk
  i2c: mxs: use core to detect 'no zero length' quirk
  ...
parents 0214f46b 19358d44
...@@ -72,6 +72,8 @@ Optional properties: ...@@ -72,6 +72,8 @@ Optional properties:
- wp-gpios: GPIO to which the write-protect pin of the chip is connected. - wp-gpios: GPIO to which the write-protect pin of the chip is connected.
- address-width: number of address bits (one of 8, 16).
Example: Example:
eeprom@52 { eeprom@52 {
......
Device-tree bindings for FSI-attached I2C master and busses
-----------------------------------------------------------
Required properties:
- compatible = "ibm,i2c-fsi";
- reg = < address size >; : The FSI CFAM address and address
space size.
- #address-cells = <1>; : Number of address cells in child
nodes.
- #size-cells = <0>; : Number of size cells in child nodes.
- child nodes : Nodes to describe busses off the I2C
master.
Child node required properties:
- reg = < port number > : The port number on the I2C master.
Child node optional properties:
- child nodes : Nodes to describe devices on the I2C
bus.
Examples:
i2c@1800 {
compatible = "ibm,i2c-fsi";
reg = < 0x1800 0x400 >;
#address-cells = <1>;
#size-cells = <0>;
i2c-bus@0 {
reg = <0>;
};
i2c-bus@1 {
reg = <1>;
eeprom@50 {
compatible = "vendor,dev-name";
};
};
};
Actions Semiconductor Owl I2C controller
Required properties:
- compatible : Should be "actions,s900-i2c".
- reg : Offset and length of the register set for the device.
- #address-cells : Should be 1.
- #size-cells : Should be 0.
- interrupts : A single interrupt specifier.
- clocks : Phandle of the clock feeding the I2C controller.
Optional properties:
- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and
Fast modes are supported, possible values are 100000 and
400000.
Examples:
i2c0: i2c@e0170000 {
compatible = "actions,s900-i2c";
reg = <0 0xe0170000 0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clock CLK_I2C0>;
clock-frequency = <100000>;
};
...@@ -4,6 +4,7 @@ Required properties: ...@@ -4,6 +4,7 @@ Required properties:
- compatible: - compatible:
"renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC. "renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC.
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC. "renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC. "renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC. "renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC. "renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
...@@ -16,11 +17,13 @@ Required properties: ...@@ -16,11 +17,13 @@ Required properties:
"renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC. "renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC.
"renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC. "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC.
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC. "renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
"renesas,i2c-r8a77990" if the device is a part of a R8A77990 SoC.
"renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC. "renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC.
"renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible
device. device.
"renesas,rcar-gen3-i2c" for a generic R-Car Gen3 compatible device. "renesas,rcar-gen3-i2c" for a generic R-Car Gen3 or RZ/G2 compatible
device.
"renesas,i2c-rcar" (deprecated) "renesas,i2c-rcar" (deprecated)
When compatible with the generic version, nodes must list the When compatible with the generic version, nodes must list the
......
...@@ -6,6 +6,7 @@ Required properties: ...@@ -6,6 +6,7 @@ Required properties:
- "renesas,iic-r8a7740" (R-Mobile A1) - "renesas,iic-r8a7740" (R-Mobile A1)
- "renesas,iic-r8a7743" (RZ/G1M) - "renesas,iic-r8a7743" (RZ/G1M)
- "renesas,iic-r8a7745" (RZ/G1E) - "renesas,iic-r8a7745" (RZ/G1E)
- "renesas,iic-r8a774a1" (RZ/G2M)
- "renesas,iic-r8a7790" (R-Car H2) - "renesas,iic-r8a7790" (R-Car H2)
- "renesas,iic-r8a7791" (R-Car M2-W) - "renesas,iic-r8a7791" (R-Car M2-W)
- "renesas,iic-r8a7792" (R-Car V2H) - "renesas,iic-r8a7792" (R-Car V2H)
...@@ -17,7 +18,8 @@ Required properties: ...@@ -17,7 +18,8 @@ Required properties:
- "renesas,iic-sh73a0" (SH-Mobile AG5) - "renesas,iic-sh73a0" (SH-Mobile AG5)
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1 - "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
compatible device) compatible device)
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device) - "renesas,rcar-gen3-iic" (generic R-Car Gen3 or RZ/G2
compatible device)
- "renesas,rmobile-iic" (generic device) - "renesas,rmobile-iic" (generic device)
When compatible with a generic R-Car version, nodes When compatible with a generic R-Car version, nodes
......
...@@ -21,24 +21,21 @@ Supported adapters: ...@@ -21,24 +21,21 @@ Supported adapters:
* Intel DH89xxCC (PCH) * Intel DH89xxCC (PCH)
* Intel Panther Point (PCH) * Intel Panther Point (PCH)
* Intel Lynx Point (PCH) * Intel Lynx Point (PCH)
* Intel Lynx Point-LP (PCH)
* Intel Avoton (SOC) * Intel Avoton (SOC)
* Intel Wellsburg (PCH) * Intel Wellsburg (PCH)
* Intel Coleto Creek (PCH) * Intel Coleto Creek (PCH)
* Intel Wildcat Point (PCH) * Intel Wildcat Point (PCH)
* Intel Wildcat Point-LP (PCH)
* Intel BayTrail (SOC) * Intel BayTrail (SOC)
* Intel Braswell (SOC) * Intel Braswell (SOC)
* Intel Sunrise Point-H (PCH) * Intel Sunrise Point (PCH)
* Intel Sunrise Point-LP (PCH) * Intel Kaby Lake (PCH)
* Intel Kaby Lake-H (PCH)
* Intel DNV (SOC) * Intel DNV (SOC)
* Intel Broxton (SOC) * Intel Broxton (SOC)
* Intel Lewisburg (PCH) * Intel Lewisburg (PCH)
* Intel Gemini Lake (SOC) * Intel Gemini Lake (SOC)
* Intel Cannon Lake-H (PCH) * Intel Cannon Lake (PCH)
* Intel Cannon Lake-LP (PCH)
* Intel Cedar Fork (PCH) * Intel Cedar Fork (PCH)
* Intel Ice Lake (PCH)
Datasheets: Publicly available at the Intel website Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller On Intel Patsburg and later chipsets, both the normal host SMBus controller
......
...@@ -34,21 +34,48 @@ I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C ...@@ -34,21 +34,48 @@ I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C
core (see 'struct bus_recovery_info'). However, the bus recovery will not core (see 'struct bus_recovery_info'). However, the bus recovery will not
succeed because SDA is still pinned low until you manually release it again succeed because SDA is still pinned low until you manually release it again
with "echo 1 > sda". A test with an automatic release can be done with the with "echo 1 > sda". A test with an automatic release can be done with the
'incomplete_transfer' file. following class of fault injectors.
"incomplete_transfer" Introduction to incomplete transfers
--------------------- ------------------------------------
The following fault injectors create situations where SDA will be held low by a
device. Bus recovery should be able to fix these situations. But please note:
there are I2C client devices which detect a stuck SDA on their side and release
it on their own after a few milliseconds. Also, there might be an external
device deglitching and monitoring the I2C bus. It could also detect a stuck SDA
and will init a bus recovery on its own. If you want to implement bus recovery
in a bus master driver, make sure you checked your hardware setup for such
devices before. And always verify with a scope or logic analyzer!
"incomplete_address_phase"
--------------------------
This file is write only and you need to write the address of an existing I2C This file is write only and you need to write the address of an existing I2C
client device to it. Then, a transfer to this device will be started, but it client device to it. Then, a read transfer to this device will be started, but
will stop at the ACK phase after the address of the client has been it will stop at the ACK phase after the address of the client has been
transmitted. Because the device will ACK its presence, this results in SDA transmitted. Because the device will ACK its presence, this results in SDA
being pulled low by the device while SCL is high. So, similar to the "sda" file being pulled low by the device while SCL is high. So, similar to the "sda" file
above, the bus master under test should detect this condition and try a bus above, the bus master under test should detect this condition and try a bus
recovery. This time, however, it should succeed and the device should release recovery. This time, however, it should succeed and the device should release
SDA after toggling SCL. Please note: there are I2C client devices which detect SDA after toggling SCL.
a stuck SDA on their side and release it on their own after a few milliseconds.
Also, there are external devices deglitching and monitoring the I2C bus. They "incomplete_write_byte"
can also detect a stuck SDA and will init a bus recovery on their own. If you -----------------------
want to implement bus recovery in a bus master driver, make sure you checked
your hardware setup carefully before. Similar to above, this file is write only and you need to write the address of
an existing I2C client device to it.
The injector will again stop at one ACK phase, so the device will keep SDA low
because it acknowledges data. However, there are two differences compared to
'incomplete_address_phase':
a) the message sent out will be a write message
b) after the address byte, a 0x00 byte will be transferred. Then, stop at ACK.
This is a highly delicate state, the device is set up to write any data to
register 0x00 (if it has registers) when further clock pulses happen on SCL.
This is why bus recovery (up to 9 clock pulses) must either check SDA or send
additional STOP conditions to ensure the bus has been released. Otherwise
random data will be written to a device!
...@@ -5961,6 +5961,14 @@ F: fs/crypto/ ...@@ -5961,6 +5961,14 @@ F: fs/crypto/
F: include/linux/fscrypt*.h F: include/linux/fscrypt*.h
F: Documentation/filesystems/fscrypt.rst F: Documentation/filesystems/fscrypt.rst
FSI-ATTACHED I2C DRIVER
M: Eddie James <eajames@linux.vnet.ibm.com>
L: linux-i2c@vger.kernel.org
L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
S: Maintained
F: drivers/i2c/busses/i2c-fsi.c
F: Documentation/devicetree/bindings/i2c/i2c-fsi.txt
FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE
M: Jan Kara <jack@suse.cz> M: Jan Kara <jack@suse.cz>
R: Amir Goldstein <amir73il@gmail.com> R: Amir Goldstein <amir73il@gmail.com>
...@@ -12014,6 +12022,14 @@ L: netdev@vger.kernel.org ...@@ -12014,6 +12022,14 @@ L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/ethernet/qualcomm/emac/ F: drivers/net/ethernet/qualcomm/emac/
QUALCOMM GENERIC INTERFACE I2C DRIVER
M: Alok Chauhan <alokc@codeaurora.org>
M: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
L: linux-i2c@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Supported
F: drivers/i2c/busses/i2c-qcom-geni.c
QUALCOMM HEXAGON ARCHITECTURE QUALCOMM HEXAGON ARCHITECTURE
M: Richard Kuo <rkuo@codeaurora.org> M: Richard Kuo <rkuo@codeaurora.org>
L: linux-hexagon@vger.kernel.org L: linux-hexagon@vger.kernel.org
......
...@@ -116,24 +116,21 @@ config I2C_I801 ...@@ -116,24 +116,21 @@ config I2C_I801
DH89xxCC (PCH) DH89xxCC (PCH)
Panther Point (PCH) Panther Point (PCH)
Lynx Point (PCH) Lynx Point (PCH)
Lynx Point-LP (PCH)
Avoton (SOC) Avoton (SOC)
Wellsburg (PCH) Wellsburg (PCH)
Coleto Creek (PCH) Coleto Creek (PCH)
Wildcat Point (PCH) Wildcat Point (PCH)
Wildcat Point-LP (PCH)
BayTrail (SOC) BayTrail (SOC)
Braswell (SOC) Braswell (SOC)
Sunrise Point-H (PCH) Sunrise Point (PCH)
Sunrise Point-LP (PCH) Kaby Lake (PCH)
Kaby Lake-H (PCH)
DNV (SOC) DNV (SOC)
Broxton (SOC) Broxton (SOC)
Lewisburg (PCH) Lewisburg (PCH)
Gemini Lake (SOC) Gemini Lake (SOC)
Cannon Lake-H (PCH) Cannon Lake (PCH)
Cannon Lake-LP (PCH)
Cedar Fork (PCH) Cedar Fork (PCH)
Ice Lake (PCH)
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-i801. will be called i2c-i801.
...@@ -762,6 +759,13 @@ config I2C_OMAP ...@@ -762,6 +759,13 @@ config I2C_OMAP
Like OMAP1510/1610/1710/5912 and OMAP242x. Like OMAP1510/1610/1710/5912 and OMAP242x.
For details see http://www.ti.com/omap. For details see http://www.ti.com/omap.
config I2C_OWL
tristate "Actions Semiconductor Owl I2C Controller"
depends on ARCH_ACTIONS || COMPILE_TEST
help
Say Y here if you want to use the I2C bus controller on
the Actions Semiconductor Owl SoC's.
config I2C_PASEMI config I2C_PASEMI
tristate "PA Semi SMBus interface" tristate "PA Semi SMBus interface"
depends on PPC_PASEMI && PCI depends on PPC_PASEMI && PCI
...@@ -828,6 +832,19 @@ config I2C_PXA_SLAVE ...@@ -828,6 +832,19 @@ config I2C_PXA_SLAVE
is necessary for systems where the PXA may be a target on the is necessary for systems where the PXA may be a target on the
I2C bus. I2C bus.
config I2C_QCOM_GENI
tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
depends on ARCH_QCOM || COMPILE_TEST
depends on QCOM_GENI_SE
help
This driver supports GENI serial engine based I2C controller in
master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
yes to this option, support will be included for the built-in I2C
interface on the Qualcomm Technologies Inc.'s SoCs.
This driver can also be built as a module. If so, the module
will be called i2c-qcom-geni.
config I2C_QUP config I2C_QUP
tristate "Qualcomm QUP based I2C controller" tristate "Qualcomm QUP based I2C controller"
depends on ARCH_QCOM depends on ARCH_QCOM
...@@ -1330,4 +1347,15 @@ config I2C_ZX2967 ...@@ -1330,4 +1347,15 @@ config I2C_ZX2967
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called i2c-zx2967. called i2c-zx2967.
config I2C_FSI
tristate "FSI I2C driver"
depends on FSI
help
Driver for FSI bus attached I2C masters. These are I2C masters that
are connected to the system over an FSI bus, instead of the more
common PCI or MMIO interface.
This driver can also be built as a module. If so, the module will be
called as i2c-fsi.
endmenu endmenu
...@@ -76,6 +76,7 @@ obj-$(CONFIG_I2C_MXS) += i2c-mxs.o ...@@ -76,6 +76,7 @@ obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_OWL) += i2c-owl.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
...@@ -83,6 +84,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o ...@@ -83,6 +84,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
...@@ -137,5 +139,6 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o ...@@ -137,5 +139,6 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_I2C_FSI) += i2c-fsi.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
...@@ -384,6 +384,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, ...@@ -384,6 +384,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
if (status) if (status)
return status; return status;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
/* fall through */
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
status = amd_ec_read(smbus, AMD_SMB_DATA + i, status = amd_ec_read(smbus, AMD_SMB_DATA + i,
......
...@@ -111,22 +111,22 @@ ...@@ -111,22 +111,22 @@
#define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0)
enum aspeed_i2c_master_state { enum aspeed_i2c_master_state {
ASPEED_I2C_MASTER_INACTIVE,
ASPEED_I2C_MASTER_START, ASPEED_I2C_MASTER_START,
ASPEED_I2C_MASTER_TX_FIRST, ASPEED_I2C_MASTER_TX_FIRST,
ASPEED_I2C_MASTER_TX, ASPEED_I2C_MASTER_TX,
ASPEED_I2C_MASTER_RX_FIRST, ASPEED_I2C_MASTER_RX_FIRST,
ASPEED_I2C_MASTER_RX, ASPEED_I2C_MASTER_RX,
ASPEED_I2C_MASTER_STOP, ASPEED_I2C_MASTER_STOP,
ASPEED_I2C_MASTER_INACTIVE,
}; };
enum aspeed_i2c_slave_state { enum aspeed_i2c_slave_state {
ASPEED_I2C_SLAVE_STOP,
ASPEED_I2C_SLAVE_START, ASPEED_I2C_SLAVE_START,
ASPEED_I2C_SLAVE_READ_REQUESTED, ASPEED_I2C_SLAVE_READ_REQUESTED,
ASPEED_I2C_SLAVE_READ_PROCESSED, ASPEED_I2C_SLAVE_READ_PROCESSED,
ASPEED_I2C_SLAVE_WRITE_REQUESTED, ASPEED_I2C_SLAVE_WRITE_REQUESTED,
ASPEED_I2C_SLAVE_WRITE_RECEIVED, ASPEED_I2C_SLAVE_WRITE_RECEIVED,
ASPEED_I2C_SLAVE_STOP,
}; };
struct aspeed_i2c_bus { struct aspeed_i2c_bus {
...@@ -234,7 +234,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus) ...@@ -234,7 +234,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
bool irq_handled = true; bool irq_handled = true;
u8 value; u8 value;
spin_lock(&bus->lock);
if (!slave) { if (!slave) {
irq_handled = false; irq_handled = false;
goto out; goto out;
...@@ -325,7 +324,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus) ...@@ -325,7 +324,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG); writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
out: out:
spin_unlock(&bus->lock);
return irq_handled; return irq_handled;
} }
#endif /* CONFIG_I2C_SLAVE */ #endif /* CONFIG_I2C_SLAVE */
...@@ -389,7 +387,6 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -389,7 +387,6 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
u8 recv_byte; u8 recv_byte;
int ret; int ret;
spin_lock(&bus->lock);
irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG); irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
/* Ack all interrupt bits. */ /* Ack all interrupt bits. */
writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG); writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
...@@ -407,7 +404,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -407,7 +404,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
*/ */
ret = aspeed_i2c_is_irq_error(irq_status); ret = aspeed_i2c_is_irq_error(irq_status);
if (ret < 0) { if (ret < 0) {
dev_dbg(bus->dev, "received error interrupt: 0x%08x", dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
irq_status); irq_status);
bus->cmd_err = ret; bus->cmd_err = ret;
bus->master_state = ASPEED_I2C_MASTER_INACTIVE; bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
...@@ -416,7 +413,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -416,7 +413,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
/* We are in an invalid state; reset bus to a known state. */ /* We are in an invalid state; reset bus to a known state. */
if (!bus->msgs) { if (!bus->msgs) {
dev_err(bus->dev, "bus in unknown state"); dev_err(bus->dev, "bus in unknown state\n");
bus->cmd_err = -EIO; bus->cmd_err = -EIO;
if (bus->master_state != ASPEED_I2C_MASTER_STOP) if (bus->master_state != ASPEED_I2C_MASTER_STOP)
aspeed_i2c_do_stop(bus); aspeed_i2c_do_stop(bus);
...@@ -431,7 +428,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -431,7 +428,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
*/ */
if (bus->master_state == ASPEED_I2C_MASTER_START) { if (bus->master_state == ASPEED_I2C_MASTER_START) {
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
pr_devel("no slave present at %02x", msg->addr); pr_devel("no slave present at %02x\n", msg->addr);
status_ack |= ASPEED_I2CD_INTR_TX_NAK; status_ack |= ASPEED_I2CD_INTR_TX_NAK;
bus->cmd_err = -ENXIO; bus->cmd_err = -ENXIO;
aspeed_i2c_do_stop(bus); aspeed_i2c_do_stop(bus);
...@@ -451,11 +448,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -451,11 +448,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
switch (bus->master_state) { switch (bus->master_state) {
case ASPEED_I2C_MASTER_TX: case ASPEED_I2C_MASTER_TX:
if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) { if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
dev_dbg(bus->dev, "slave NACKed TX"); dev_dbg(bus->dev, "slave NACKed TX\n");
status_ack |= ASPEED_I2CD_INTR_TX_NAK; status_ack |= ASPEED_I2CD_INTR_TX_NAK;
goto error_and_stop; goto error_and_stop;
} else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
dev_err(bus->dev, "slave failed to ACK TX"); dev_err(bus->dev, "slave failed to ACK TX\n");
goto error_and_stop; goto error_and_stop;
} }
status_ack |= ASPEED_I2CD_INTR_TX_ACK; status_ack |= ASPEED_I2CD_INTR_TX_ACK;
...@@ -478,7 +475,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -478,7 +475,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
/* fallthrough intended */ /* fallthrough intended */
case ASPEED_I2C_MASTER_RX: case ASPEED_I2C_MASTER_RX:
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) { if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
dev_err(bus->dev, "master failed to RX"); dev_err(bus->dev, "master failed to RX\n");
goto error_and_stop; goto error_and_stop;
} }
status_ack |= ASPEED_I2CD_INTR_RX_DONE; status_ack |= ASPEED_I2CD_INTR_RX_DONE;
...@@ -509,7 +506,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -509,7 +506,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
goto out_no_complete; goto out_no_complete;
case ASPEED_I2C_MASTER_STOP: case ASPEED_I2C_MASTER_STOP:
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) { if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
dev_err(bus->dev, "master failed to STOP"); dev_err(bus->dev, "master failed to STOP\n");
bus->cmd_err = -EIO; bus->cmd_err = -EIO;
/* Do not STOP as we have already tried. */ /* Do not STOP as we have already tried. */
} else { } else {
...@@ -520,7 +517,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -520,7 +517,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
goto out_complete; goto out_complete;
case ASPEED_I2C_MASTER_INACTIVE: case ASPEED_I2C_MASTER_INACTIVE:
dev_err(bus->dev, dev_err(bus->dev,
"master received interrupt 0x%08x, but is inactive", "master received interrupt 0x%08x, but is inactive\n",
irq_status); irq_status);
bus->cmd_err = -EIO; bus->cmd_err = -EIO;
/* Do not STOP as we should be inactive. */ /* Do not STOP as we should be inactive. */
...@@ -547,22 +544,29 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) ...@@ -547,22 +544,29 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
dev_err(bus->dev, dev_err(bus->dev,
"irq handled != irq. expected 0x%08x, but was 0x%08x\n", "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
irq_status, status_ack); irq_status, status_ack);
spin_unlock(&bus->lock);
return !!irq_status; return !!irq_status;
} }
static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
{ {
struct aspeed_i2c_bus *bus = dev_id; struct aspeed_i2c_bus *bus = dev_id;
bool ret;
spin_lock(&bus->lock);
#if IS_ENABLED(CONFIG_I2C_SLAVE) #if IS_ENABLED(CONFIG_I2C_SLAVE)
if (aspeed_i2c_slave_irq(bus)) { if (aspeed_i2c_slave_irq(bus)) {
dev_dbg(bus->dev, "irq handled by slave.\n"); dev_dbg(bus->dev, "irq handled by slave.\n");
return IRQ_HANDLED; ret = true;
goto out;
} }
#endif /* CONFIG_I2C_SLAVE */ #endif /* CONFIG_I2C_SLAVE */
return aspeed_i2c_master_irq(bus) ? IRQ_HANDLED : IRQ_NONE; ret = aspeed_i2c_master_irq(bus);
out:
spin_unlock(&bus->lock);
return ret ? IRQ_HANDLED : IRQ_NONE;
} }
static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
...@@ -851,7 +855,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) ...@@ -851,7 +855,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL); bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
if (IS_ERR(bus->rst)) { if (IS_ERR(bus->rst)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"missing or invalid reset controller device tree entry"); "missing or invalid reset controller device tree entry\n");
return PTR_ERR(bus->rst); return PTR_ERR(bus->rst);
} }
reset_control_deassert(bus->rst); reset_control_deassert(bus->rst);
...@@ -868,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) ...@@ -868,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
if (!match) if (!match)
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val; bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
else else
bus->get_clk_reg_val = match->data; bus->get_clk_reg_val = (u32 (*)(u32))match->data;
/* Initialize the I2C adapter */ /* Initialize the I2C adapter */
spin_lock_init(&bus->lock); spin_lock_init(&bus->lock);
......
...@@ -689,9 +689,9 @@ static int brcmstb_i2c_suspend(struct device *dev) ...@@ -689,9 +689,9 @@ static int brcmstb_i2c_suspend(struct device *dev)
{ {
struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
i2c_lock_adapter(&i2c_dev->adapter); i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = true; i2c_dev->is_suspended = true;
i2c_unlock_adapter(&i2c_dev->adapter); i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
return 0; return 0;
} }
...@@ -700,10 +700,10 @@ static int brcmstb_i2c_resume(struct device *dev) ...@@ -700,10 +700,10 @@ static int brcmstb_i2c_resume(struct device *dev)
{ {
struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
i2c_lock_adapter(&i2c_dev->adapter); i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
brcmstb_i2c_set_bsc_reg_defaults(i2c_dev); brcmstb_i2c_set_bsc_reg_defaults(i2c_dev);
i2c_dev->is_suspended = false; i2c_dev->is_suspended = false;
i2c_unlock_adapter(&i2c_dev->adapter); i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
return 0; return 0;
} }
......
...@@ -718,14 +718,14 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, ...@@ -718,14 +718,14 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
dev = container_of(nb, struct davinci_i2c_dev, freq_transition); dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
i2c_lock_adapter(&dev->adapter); i2c_lock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);
if (val == CPUFREQ_PRECHANGE) { if (val == CPUFREQ_PRECHANGE) {
davinci_i2c_reset_ctrl(dev, 0); davinci_i2c_reset_ctrl(dev, 0);
} else if (val == CPUFREQ_POSTCHANGE) { } else if (val == CPUFREQ_POSTCHANGE) {
i2c_davinci_calc_clk_dividers(dev); i2c_davinci_calc_clk_dividers(dev);
davinci_i2c_reset_ctrl(dev, 1); davinci_i2c_reset_ctrl(dev, 1);
} }
i2c_unlock_adapter(&dev->adapter); i2c_unlock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);
return 0; return 0;
} }
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Intel BayTrail PMIC I2C bus semaphore implementaion * Intel BayTrail PMIC I2C bus semaphore implementaion
* Copyright (c) 2014, Intel Corporation. * Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Synopsys DesignWare I2C adapter driver. * Synopsys DesignWare I2C adapter driver.
* *
...@@ -6,20 +7,6 @@ ...@@ -6,20 +7,6 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -31,6 +18,7 @@ ...@@ -31,6 +18,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/swab.h>
#include "i2c-designware-core.h" #include "i2c-designware-core.h"
...@@ -94,6 +82,40 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) ...@@ -94,6 +82,40 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
} }
} }
/**
* i2c_dw_set_reg_access() - Set register access flags
* @dev: device private data
*
* Autodetects needed register access mode and sets access flags accordingly.
* This must be called before doing any other register access.
*/
int i2c_dw_set_reg_access(struct dw_i2c_dev *dev)
{
u32 reg;
int ret;
ret = i2c_dw_acquire_lock(dev);
if (ret)
return ret;
reg = dw_readl(dev, DW_IC_COMP_TYPE);
i2c_dw_release_lock(dev);
if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianess access */
dev->flags |= ACCESS_SWAP;
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
/* Configure register access mode 16bit */
dev->flags |= ACCESS_16BIT;
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev,
"Unknown Synopsys component type: 0x%08x\n", reg);
return -ENODEV;
}
return 0;
}
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
{ {
/* /*
...@@ -149,6 +171,47 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) ...@@ -149,6 +171,47 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset; return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
} }
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
{
u32 reg;
int ret;
ret = i2c_dw_acquire_lock(dev);
if (ret)
return ret;
/* Configure SDA Hold Time if required */
reg = dw_readl(dev, DW_IC_COMP_VERSION);
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);
}
/*
* Workaround for avoiding TX arbitration lost in case I2C
* slave pulls SDA down "too quickly" after falling egde of
* SCL by enabling non-zero SDA RX hold. Specification says it
* extends incoming SDA low to high transition while SCL is
* high but it apprears to help also above issue.
*/
if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
} else if (dev->sda_hold_time) {
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n");
dev->sda_hold_time = 0;
}
i2c_dw_release_lock(dev);
return 0;
}
void __i2c_dw_disable(struct dw_i2c_dev *dev) void __i2c_dw_disable(struct dw_i2c_dev *dev)
{ {
int timeout = 100; int timeout = 100;
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* /*
* Synopsys DesignWare I2C adapter driver. * Synopsys DesignWare I2C adapter driver.
* *
...@@ -6,20 +7,6 @@ ...@@ -6,20 +7,6 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -212,7 +199,8 @@ ...@@ -212,7 +199,8 @@
* @tx_fifo_depth: depth of the hardware tx fifo * @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo * @rx_fifo_depth: depth of the hardware rx fifo
* @rx_outstanding: current master-rx elements in tx fifo * @rx_outstanding: current master-rx elements in tx fifo
* @clk_freq: bus clock frequency * @timings: bus clock frequency, SDA hold and other timings
* @sda_hold_time: SDA hold value
* @ss_hcnt: standard speed HCNT value * @ss_hcnt: standard speed HCNT value
* @ss_lcnt: standard speed LCNT value * @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value * @fs_hcnt: fast speed HCNT value
...@@ -264,10 +252,8 @@ struct dw_i2c_dev { ...@@ -264,10 +252,8 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth; unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth; unsigned int rx_fifo_depth;
int rx_outstanding; int rx_outstanding;
u32 clk_freq; struct i2c_timings timings;
u32 sda_hold_time; u32 sda_hold_time;
u32 sda_falling_time;
u32 scl_falling_time;
u16 ss_hcnt; u16 ss_hcnt;
u16 ss_lcnt; u16 ss_lcnt;
u16 fs_hcnt; u16 fs_hcnt;
...@@ -295,8 +281,10 @@ struct dw_i2c_dev { ...@@ -295,8 +281,10 @@ struct dw_i2c_dev {
u32 dw_readl(struct dw_i2c_dev *dev, int offset); u32 dw_readl(struct dw_i2c_dev *dev, int offset);
void dw_writel(struct dw_i2c_dev *dev, u32 b, 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);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); 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); 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);
unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Synopsys DesignWare I2C adapter driver (master only). * Synopsys DesignWare I2C adapter driver (master only).
* *
...@@ -6,20 +7,6 @@ ...@@ -6,20 +7,6 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -45,90 +32,79 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev) ...@@ -45,90 +32,79 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
dw_writel(dev, dev->master_cfg, DW_IC_CON); dw_writel(dev, dev->master_cfg, DW_IC_CON);
} }
/** static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
* i2c_dw_init() - Initialize the designware I2C master hardware
* @dev: device private data
*
* This functions configures and enables the I2C master.
* This function is called during I2C init function, and in case of timeout at
* run time.
*/
static int i2c_dw_init_master(struct dw_i2c_dev *dev)
{ {
u32 hcnt, lcnt; u32 ic_clk = i2c_dw_clk_rate(dev);
u32 reg, comp_param1; const char *mode_str, *fp_str = "";
u32 comp_param1;
u32 sda_falling_time, scl_falling_time; u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
int ret; int ret;
ret = i2c_dw_acquire_lock(dev); ret = i2c_dw_acquire_lock(dev);
if (ret) if (ret)
return ret; return ret;
reg = dw_readl(dev, DW_IC_COMP_TYPE);
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianess access */
dev->flags |= ACCESS_SWAP;
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
/* Configure register access mode 16bit */
dev->flags |= ACCESS_16BIT;
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev,
"Unknown Synopsys component type: 0x%08x\n", reg);
i2c_dw_release_lock(dev);
return -ENODEV;
}
comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
i2c_dw_release_lock(dev);
/* Disable the adapter */ /* Set standard and fast speed dividers for high/low periods */
__i2c_dw_disable(dev); sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
scl_falling_time = t->scl_fall_ns ?: 300; /* ns */
/* Set standard and fast speed deviders for high/low periods */
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
/* Set SCL timing parameters for standard-mode */ /* Calculate SCL timing parameters for standard mode if not set */
if (dev->ss_hcnt && dev->ss_lcnt) { if (!dev->ss_hcnt || !dev->ss_lcnt) {
hcnt = dev->ss_hcnt; dev->ss_hcnt =
lcnt = dev->ss_lcnt; i2c_dw_scl_hcnt(ic_clk,
} else {
hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
4000, /* tHD;STA = tHIGH = 4.0 us */ 4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time, sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), dev->ss_lcnt =
i2c_dw_scl_lcnt(ic_clk,
4700, /* tLOW = 4.7 us */ 4700, /* tLOW = 4.7 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
} }
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n",
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); dev->ss_hcnt, dev->ss_lcnt);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
/*
/* Set SCL timing parameters for fast-mode or fast-mode plus */ * Set SCL timing parameters for fast mode or fast mode plus. Only
if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { * difference is the timing parameter values since the registers are
hcnt = dev->fp_hcnt; * the same.
lcnt = dev->fp_lcnt; */
} else if (dev->fs_hcnt && dev->fs_lcnt) { if (t->bus_freq_hz == 1000000) {
hcnt = dev->fs_hcnt; /*
lcnt = dev->fs_lcnt; * Check are fast mode plus parameters available and use
} else { * fast mode if not.
hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), */
if (dev->fp_hcnt && dev->fp_lcnt) {
dev->fs_hcnt = dev->fp_hcnt;
dev->fs_lcnt = dev->fp_lcnt;
fp_str = " Plus";
}
}
/*
* Calculate SCL timing parameters for fast mode if not set. They are
* needed also in high speed mode.
*/
if (!dev->fs_hcnt || !dev->fs_lcnt) {
dev->fs_hcnt =
i2c_dw_scl_hcnt(ic_clk,
600, /* tHD;STA = tHIGH = 0.6 us */ 600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time, sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), dev->fs_lcnt =
i2c_dw_scl_lcnt(ic_clk,
1300, /* tLOW = 1.3 us */ 1300, /* tLOW = 1.3 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
} }
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n",
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); fp_str, dev->fs_hcnt, dev->fs_lcnt);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
/* Check is high speed possible and fall back to fast mode if not */
if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) == if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
DW_IC_CON_SPEED_HIGH) { DW_IC_CON_SPEED_HIGH) {
if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
...@@ -136,37 +112,70 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) ...@@ -136,37 +112,70 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
dev_err(dev->dev, "High Speed not supported!\n"); dev_err(dev->dev, "High Speed not supported!\n");
dev->master_cfg &= ~DW_IC_CON_SPEED_MASK; dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
dev->master_cfg |= DW_IC_CON_SPEED_FAST; dev->master_cfg |= DW_IC_CON_SPEED_FAST;
dev->hs_hcnt = 0;
dev->hs_lcnt = 0;
} else if (dev->hs_hcnt && dev->hs_lcnt) { } else if (dev->hs_hcnt && dev->hs_lcnt) {
hcnt = dev->hs_hcnt; dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
lcnt = dev->hs_lcnt; dev->hs_hcnt, dev->hs_lcnt);
dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
hcnt, lcnt);
} }
} }
/* Configure SDA Hold Time if required */ ret = i2c_dw_set_sda_hold(dev);
reg = dw_readl(dev, DW_IC_COMP_VERSION); if (ret)
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { goto out;
if (!dev->sda_hold_time) {
/* Keep previous hold time setting if no one set it */ switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) {
dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); case DW_IC_CON_SPEED_STD:
} mode_str = "Standard Mode";
/* break;
* Workaround for avoiding TX arbitration lost in case I2C case DW_IC_CON_SPEED_HIGH:
* slave pulls SDA down "too quickly" after falling egde of mode_str = "High Speed Mode";
* SCL by enabling non-zero SDA RX hold. Specification says it break;
* extends incoming SDA low to high transition while SCL is default:
* high but it apprears to help also above issue. mode_str = "Fast Mode";
*/
if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
} else if (dev->sda_hold_time) {
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n");
} }
dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str);
out:
return ret;
}
/**
* i2c_dw_init() - Initialize the designware I2C master hardware
* @dev: device private data
*
* This functions configures and enables the I2C master.
* This function is called during I2C init function, and in case of timeout at
* run time.
*/
static int i2c_dw_init_master(struct dw_i2c_dev *dev)
{
int ret;
ret = i2c_dw_acquire_lock(dev);
if (ret)
return ret;
/* Disable the adapter */
__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);
/* 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);
/* 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);
}
/* Write SDA hold time if supported */
if (dev->sda_hold_time)
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
i2c_dw_configure_fifo_master(dev); i2c_dw_configure_fifo_master(dev);
i2c_dw_release_lock(dev); i2c_dw_release_lock(dev);
...@@ -253,13 +262,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) ...@@ -253,13 +262,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
break; break;
} }
if (msgs[dev->msg_write_idx].len == 0) {
dev_err(dev->dev,
"%s: invalid message length\n", __func__);
dev->msg_err = -EINVAL;
break;
}
if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
/* new i2c_msg */ /* new i2c_msg */
buf = msgs[dev->msg_write_idx].buf; buf = msgs[dev->msg_write_idx].buf;
...@@ -502,6 +504,10 @@ static const struct i2c_algorithm i2c_dw_algo = { ...@@ -502,6 +504,10 @@ static const struct i2c_algorithm i2c_dw_algo = {
.functionality = i2c_dw_func, .functionality = i2c_dw_func,
}; };
static const struct i2c_adapter_quirks i2c_dw_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{ {
u32 stat; u32 stat;
...@@ -681,6 +687,14 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -681,6 +687,14 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
dev->disable = i2c_dw_disable; dev->disable = i2c_dw_disable;
dev->disable_int = i2c_dw_disable_int; dev->disable_int = i2c_dw_disable_int;
ret = i2c_dw_set_reg_access(dev);
if (ret)
return ret;
ret = i2c_dw_set_timings_master(dev);
if (ret)
return ret;
ret = dev->init(dev); ret = dev->init(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -689,6 +703,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -689,6 +703,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
"Synopsys DesignWare I2C adapter"); "Synopsys DesignWare I2C adapter");
adap->retries = 3; adap->retries = 3;
adap->algo = &i2c_dw_algo; adap->algo = &i2c_dw_algo;
adap->quirks = &i2c_dw_quirks;
adap->dev.parent = dev->dev; adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Synopsys DesignWare I2C adapter driver (master only). * Synopsys DesignWare I2C adapter driver (master only).
* *
...@@ -7,22 +8,7 @@ ...@@ -7,22 +8,7 @@
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
* Copyright (C) 2011, 2015, 2016 Intel Corporation. * Copyright (C) 2011, 2015, 2016 Intel Corporation.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -105,6 +91,7 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) ...@@ -105,6 +91,7 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
case 0x0817: case 0x0817:
c->bus_cfg &= ~DW_IC_CON_SPEED_MASK; c->bus_cfg &= ~DW_IC_CON_SPEED_MASK;
c->bus_cfg |= DW_IC_CON_SPEED_STD; c->bus_cfg |= DW_IC_CON_SPEED_STD;
/* fall through */
case 0x0818: case 0x0818:
case 0x0819: case 0x0819:
c->bus_num = pdev->device - 0x817 + 3; c->bus_num = pdev->device - 0x817 + 3;
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Synopsys DesignWare I2C adapter driver. * Synopsys DesignWare I2C adapter driver.
* *
...@@ -6,20 +7,6 @@ ...@@ -6,20 +7,6 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
...@@ -96,6 +83,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], ...@@ -96,6 +83,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
static int dw_i2c_acpi_configure(struct platform_device *pdev) static int dw_i2c_acpi_configure(struct platform_device *pdev)
{ {
struct dw_i2c_dev *dev = platform_get_drvdata(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; u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
acpi_handle handle = ACPI_HANDLE(&pdev->dev); acpi_handle handle = ACPI_HANDLE(&pdev->dev);
const struct acpi_device_id *id; const struct acpi_device_id *id;
...@@ -115,7 +103,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -115,7 +103,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_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); dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);
switch (dev->clk_freq) { switch (t->bus_freq_hz) {
case 100000: case 100000:
dev->sda_hold_time = ss_ht; dev->sda_hold_time = ss_ht;
break; break;
...@@ -175,6 +163,8 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -175,6 +163,8 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
static void i2c_dw_configure_master(struct dw_i2c_dev *dev) 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->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
...@@ -182,7 +172,7 @@ static void i2c_dw_configure_master(struct dw_i2c_dev *dev) ...@@ -182,7 +172,7 @@ static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
dev->mode = DW_IC_MASTER; dev->mode = DW_IC_MASTER;
switch (dev->clk_freq) { switch (t->bus_freq_hz) {
case 100000: case 100000:
dev->master_cfg |= DW_IC_CON_SPEED_STD; dev->master_cfg |= DW_IC_CON_SPEED_STD;
break; break;
...@@ -240,7 +230,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -240,7 +230,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct dw_i2c_dev *dev; struct dw_i2c_dev *dev;
u32 acpi_speed, ht = 0; struct i2c_timings *t;
u32 acpi_speed;
struct resource *mem; struct resource *mem;
int i, irq, ret; int i, irq, ret;
static const int supported_speeds[] = { static const int supported_speeds[] = {
...@@ -272,18 +263,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -272,18 +263,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
reset_control_deassert(dev->rst); reset_control_deassert(dev->rst);
} }
if (pdata) { t = &dev->timings;
dev->clk_freq = pdata->i2c_scl_freq; if (pdata)
} else { t->bus_freq_hz = pdata->i2c_scl_freq;
device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", else
&ht); i2c_parse_fw_timings(&pdev->dev, t, false);
device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
&dev->sda_falling_time);
device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
&dev->scl_falling_time);
device_property_read_u32(&pdev->dev, "clock-frequency",
&dev->clk_freq);
}
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev); acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
/* /*
...@@ -300,12 +284,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -300,12 +284,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
* Find bus speed from the "clock-frequency" device property, ACPI * Find bus speed from the "clock-frequency" device property, ACPI
* or by using fast mode if neither is set. * or by using fast mode if neither is set.
*/ */
if (acpi_speed && dev->clk_freq) if (acpi_speed && t->bus_freq_hz)
dev->clk_freq = min(dev->clk_freq, acpi_speed); t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
else if (acpi_speed || dev->clk_freq) else if (acpi_speed || t->bus_freq_hz)
dev->clk_freq = max(dev->clk_freq, acpi_speed); t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
else else
dev->clk_freq = 400000; t->bus_freq_hz = 400000;
if (has_acpi_companion(&pdev->dev)) if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev); dw_i2c_acpi_configure(pdev);
...@@ -314,11 +298,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -314,11 +298,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
* Only standard mode at 100kHz, fast mode at 400kHz, * Only standard mode at 100kHz, fast mode at 400kHz,
* fast mode plus at 1MHz and high speed mode at 3.4MHz are supported. * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
*/ */
if (dev->clk_freq != 100000 && dev->clk_freq != 400000 if (t->bus_freq_hz != 100000 && t->bus_freq_hz != 400000 &&
&& dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { t->bus_freq_hz != 1000000 && t->bus_freq_hz != 3400000) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n", "%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n",
dev->clk_freq); t->bus_freq_hz);
ret = -EINVAL; ret = -EINVAL;
goto exit_reset; goto exit_reset;
} }
...@@ -334,12 +318,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -334,12 +318,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->clk = devm_clk_get(&pdev->dev, NULL); dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_prepare_clk(dev, true)) { if (!i2c_dw_prepare_clk(dev, true)) {
u64 clk_khz;
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
clk_khz = dev->get_clk_rate_khz(dev);
if (!dev->sda_hold_time && ht) if (!dev->sda_hold_time && t->sda_hold_ns)
dev->sda_hold_time = div_u64( dev->sda_hold_time =
(u64)dev->get_clk_rate_khz(dev) * ht + 500000, div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000);
1000000);
} }
dw_i2c_set_fifo_size(dev, pdev->id); dw_i2c_set_fifo_size(dev, pdev->id);
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Synopsys DesignWare I2C adapter driver (slave only). * Synopsys DesignWare I2C adapter driver (slave only).
* *
* Based on the Synopsys DesignWare I2C adapter driver (master). * Based on the Synopsys DesignWare I2C adapter driver (master).
* *
* Copyright (C) 2016 Synopsys Inc. * Copyright (C) 2016 Synopsys Inc.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ----------------------------------------------------------------------------
*
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -51,53 +38,18 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) ...@@ -51,53 +38,18 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
*/ */
static int i2c_dw_init_slave(struct dw_i2c_dev *dev) static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
{ {
u32 reg, comp_param1;
int ret; int ret;
ret = i2c_dw_acquire_lock(dev); ret = i2c_dw_acquire_lock(dev);
if (ret) if (ret)
return ret; return ret;
reg = dw_readl(dev, DW_IC_COMP_TYPE);
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianness access. */
dev->flags |= ACCESS_SWAP;
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
/* Configure register access mode 16bit. */
dev->flags |= ACCESS_16BIT;
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev,
"Unknown Synopsys component type: 0x%08x\n", reg);
i2c_dw_release_lock(dev);
return -ENODEV;
}
comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
/* Disable the adapter. */ /* Disable the adapter. */
__i2c_dw_disable(dev); __i2c_dw_disable(dev);
/* Configure SDA Hold Time if required. */ /* Write SDA hold time if supported */
reg = dw_readl(dev, DW_IC_COMP_VERSION); if (dev->sda_hold_time)
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);
}
/*
* Workaround for avoiding TX arbitration lost in case I2C
* slave pulls SDA down "too quickly" after falling egde of
* SCL by enabling non-zero SDA RX hold. Specification says it
* extends incoming SDA low to high transition while SCL is
* high but it apprears to help also above issue.
*/
if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
} else {
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n");
}
i2c_dw_configure_fifo_slave(dev); i2c_dw_configure_fifo_slave(dev);
i2c_dw_release_lock(dev); i2c_dw_release_lock(dev);
...@@ -299,6 +251,14 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) ...@@ -299,6 +251,14 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
dev->disable = i2c_dw_disable; dev->disable = i2c_dw_disable;
dev->disable_int = i2c_dw_disable_int; dev->disable_int = i2c_dw_disable_int;
ret = i2c_dw_set_reg_access(dev);
if (ret)
return ret;
ret = i2c_dw_set_sda_hold(dev);
if (ret)
return ret;
ret = dev->init(dev); ret = dev->init(dev);
if (ret) if (ret)
return ret; return ret;
......
...@@ -176,7 +176,10 @@ ...@@ -176,7 +176,10 @@
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100))
#define HSI2C_EXYNOS7 BIT(0) enum i2c_type_exynos {
I2C_TYPE_EXYNOS5,
I2C_TYPE_EXYNOS7,
};
struct exynos5_i2c { struct exynos5_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
...@@ -212,27 +215,30 @@ struct exynos5_i2c { ...@@ -212,27 +215,30 @@ struct exynos5_i2c {
/** /**
* struct exynos_hsi2c_variant - platform specific HSI2C driver data * struct exynos_hsi2c_variant - platform specific HSI2C driver data
* @fifo_depth: the fifo depth supported by the HSI2C module * @fifo_depth: the fifo depth supported by the HSI2C module
* @hw: the hardware variant of Exynos I2C controller
* *
* Specifies platform specific configuration of HSI2C module. * Specifies platform specific configuration of HSI2C module.
* Note: A structure for driver specific platform data is used for future * Note: A structure for driver specific platform data is used for future
* expansion of its usage. * expansion of its usage.
*/ */
struct exynos_hsi2c_variant { struct exynos_hsi2c_variant {
unsigned int fifo_depth; unsigned int fifo_depth;
unsigned int hw; enum i2c_type_exynos hw;
}; };
static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
.fifo_depth = 64, .fifo_depth = 64,
.hw = I2C_TYPE_EXYNOS5,
}; };
static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
.fifo_depth = 16, .fifo_depth = 16,
.hw = I2C_TYPE_EXYNOS5,
}; };
static const struct exynos_hsi2c_variant exynos7_hsi2c_data = { static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {
.fifo_depth = 16, .fifo_depth = 16,
.hw = HSI2C_EXYNOS7, .hw = I2C_TYPE_EXYNOS7,
}; };
static const struct of_device_id exynos5_i2c_match[] = { static const struct of_device_id exynos5_i2c_match[] = {
...@@ -300,7 +306,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) ...@@ -300,7 +306,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
*/ */
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
temp = clkin / op_clk - 8 - t_ftl_cycle; temp = clkin / op_clk - 8 - t_ftl_cycle;
if (i2c->variant->hw != HSI2C_EXYNOS7) if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
temp -= t_ftl_cycle; temp -= t_ftl_cycle;
div = temp / 512; div = temp / 512;
clk_cycle = temp / (div + 1) - 2; clk_cycle = temp / (div + 1) - 2;
...@@ -424,7 +430,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -424,7 +430,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
writel(int_status, i2c->regs + HSI2C_INT_STATUS); writel(int_status, i2c->regs + HSI2C_INT_STATUS);
/* handle interrupt related to the transfer status */ /* handle interrupt related to the transfer status */
if (i2c->variant->hw == HSI2C_EXYNOS7) { if (i2c->variant->hw == I2C_TYPE_EXYNOS7) {
if (int_status & HSI2C_INT_TRANS_DONE) { if (int_status & HSI2C_INT_TRANS_DONE) {
i2c->trans_done = 1; i2c->trans_done = 1;
i2c->state = 0; i2c->state = 0;
...@@ -571,7 +577,7 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) ...@@ -571,7 +577,7 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c)
{ {
unsigned long timeout; unsigned long timeout;
if (i2c->variant->hw != HSI2C_EXYNOS7) if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
return; return;
/* /*
...@@ -612,7 +618,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) ...@@ -612,7 +618,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
unsigned long flags; unsigned long flags;
unsigned short trig_lvl; unsigned short trig_lvl;
if (i2c->variant->hw == HSI2C_EXYNOS7) if (i2c->variant->hw == I2C_TYPE_EXYNOS7)
int_en |= HSI2C_INT_I2C_TRANS; int_en |= HSI2C_INT_I2C_TRANS;
else else
int_en |= HSI2C_INT_I2C; int_en |= HSI2C_INT_I2C;
......
This diff is collapsed.
...@@ -78,49 +78,43 @@ static struct dentry *i2c_gpio_debug_dir; ...@@ -78,49 +78,43 @@ static struct dentry *i2c_gpio_debug_dir;
#define getscl(bd) ((bd)->getscl((bd)->data)) #define getscl(bd) ((bd)->getscl((bd)->data))
#define WIRE_ATTRIBUTE(wire) \ #define WIRE_ATTRIBUTE(wire) \
static int fops_##wire##_get(void *data, u64 *val) \ static int fops_##wire##_get(void *data, u64 *val) \
{ \ { \
struct i2c_gpio_private_data *priv = data; \ struct i2c_gpio_private_data *priv = data; \
\ \
i2c_lock_adapter(&priv->adap); \ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
*val = get##wire(&priv->bit_data); \ *val = get##wire(&priv->bit_data); \
i2c_unlock_adapter(&priv->adap); \ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
return 0; \ return 0; \
} \ } \
static int fops_##wire##_set(void *data, u64 val) \ static int fops_##wire##_set(void *data, u64 val) \
{ \ { \
struct i2c_gpio_private_data *priv = data; \ struct i2c_gpio_private_data *priv = data; \
\ \
i2c_lock_adapter(&priv->adap); \ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
set##wire(&priv->bit_data, val); \ set##wire(&priv->bit_data, val); \
i2c_unlock_adapter(&priv->adap); \ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
return 0; \ return 0; \
} \ } \
DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n")
WIRE_ATTRIBUTE(scl); WIRE_ATTRIBUTE(scl);
WIRE_ATTRIBUTE(sda); WIRE_ATTRIBUTE(sda);
static int fops_incomplete_transfer_set(void *data, u64 addr) static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv,
u32 pattern, u8 pattern_size)
{ {
struct i2c_gpio_private_data *priv = data;
struct i2c_algo_bit_data *bit_data = &priv->bit_data; struct i2c_algo_bit_data *bit_data = &priv->bit_data;
int i, pattern; int i;
if (addr > 0x7f) i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
return -EINVAL;
/* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */
pattern = (addr << 2) | 3;
i2c_lock_adapter(&priv->adap);
/* START condition */ /* START condition */
setsda(bit_data, 0); setsda(bit_data, 0);
udelay(bit_data->udelay); udelay(bit_data->udelay);
/* Send ADDR+RD, request ACK, don't send STOP */ /* Send pattern, request ACK, don't send STOP */
for (i = 8; i >= 0; i--) { for (i = pattern_size - 1; i >= 0; i--) {
setscl(bit_data, 0); setscl(bit_data, 0);
udelay(bit_data->udelay / 2); udelay(bit_data->udelay / 2);
setsda(bit_data, (pattern >> i) & 1); setsda(bit_data, (pattern >> i) & 1);
...@@ -129,11 +123,44 @@ static int fops_incomplete_transfer_set(void *data, u64 addr) ...@@ -129,11 +123,44 @@ static int fops_incomplete_transfer_set(void *data, u64 addr)
udelay(bit_data->udelay); udelay(bit_data->udelay);
} }
i2c_unlock_adapter(&priv->adap); i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
}
static int fops_incomplete_addr_phase_set(void *data, u64 addr)
{
struct i2c_gpio_private_data *priv = data;
u32 pattern;
if (addr > 0x7f)
return -EINVAL;
/* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */
pattern = (addr << 2) | 3;
i2c_gpio_incomplete_transfer(priv, pattern, 9);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n");
static int fops_incomplete_write_byte_set(void *data, u64 addr)
{
struct i2c_gpio_private_data *priv = data;
u32 pattern;
if (addr > 0x7f)
return -EINVAL;
/* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */
pattern = (addr << 2) | 1;
/* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */
pattern = (pattern << 9) | 1;
i2c_gpio_incomplete_transfer(priv, pattern, 18);
return 0; return 0;
} }
DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n");
static void i2c_gpio_fault_injector_init(struct platform_device *pdev) static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
{ {
...@@ -156,8 +183,10 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) ...@@ -156,8 +183,10 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);
debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda);
debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir,
priv, &fops_incomplete_transfer); priv, &fops_incomplete_addr_phase);
debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir,
priv, &fops_incomplete_write_byte);
} }
static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) static void i2c_gpio_fault_injector_exit(struct platform_device *pdev)
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
* Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes
* Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes
* Cedar Fork (PCH) 0x18df 32 hard yes yes yes * Cedar Fork (PCH) 0x18df 32 hard yes yes yes
* Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes
* *
* Features supported by this driver: * Features supported by this driver:
* Software PEC no * Software PEC no
...@@ -220,6 +221,7 @@ ...@@ -220,6 +221,7 @@
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
...@@ -1034,6 +1036,7 @@ static const struct pci_device_id i801_ids[] = { ...@@ -1034,6 +1036,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
{ 0, } { 0, }
}; };
...@@ -1518,6 +1521,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1518,6 +1521,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_CDF_SMBUS: case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
case PCI_DEVICE_ID_INTEL_DNV_SMBUS: case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ; priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC; priv->features |= FEATURE_SMBUS_PEC;
......
...@@ -421,10 +421,14 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) ...@@ -421,10 +421,14 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
return -EAGAIN; return -EAGAIN;
} }
if (for_busy && (temp & I2SR_IBB)) if (for_busy && (temp & I2SR_IBB)) {
i2c_imx->stopped = 0;
break; break;
if (!for_busy && !(temp & I2SR_IBB)) }
if (!for_busy && !(temp & I2SR_IBB)) {
i2c_imx->stopped = 1;
break; break;
}
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&i2c_imx->adapter.dev, dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C bus is busy\n", __func__); "<%s> I2C bus is busy\n", __func__);
...@@ -538,7 +542,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) ...@@ -538,7 +542,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
result = i2c_imx_bus_busy(i2c_imx, 1); result = i2c_imx_bus_busy(i2c_imx, 1);
if (result) if (result)
return result; return result;
i2c_imx->stopped = 0;
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN; temp &= ~I2CR_DMAEN;
...@@ -567,10 +570,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) ...@@ -567,10 +570,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
udelay(i2c_imx->disable_delay); udelay(i2c_imx->disable_delay);
} }
if (!i2c_imx->stopped) { if (!i2c_imx->stopped)
i2c_imx_bus_busy(i2c_imx, 0); i2c_imx_bus_busy(i2c_imx, 0);
i2c_imx->stopped = 1;
}
/* Disable I2C controller */ /* Disable I2C controller */
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
...@@ -668,9 +669,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, ...@@ -668,9 +669,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
struct imx_i2c_dma *dma = i2c_imx->dma; struct imx_i2c_dma *dma = i2c_imx->dma;
struct device *dev = &i2c_imx->adapter.dev; struct device *dev = &i2c_imx->adapter.dev;
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
dma->chan_using = dma->chan_rx; dma->chan_using = dma->chan_rx;
dma->dma_transfer_dir = DMA_DEV_TO_MEM; dma->dma_transfer_dir = DMA_DEV_TO_MEM;
...@@ -727,7 +725,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, ...@@ -727,7 +725,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
temp &= ~(I2CR_MSTA | I2CR_MTX); temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0); i2c_imx_bus_busy(i2c_imx, 0);
i2c_imx->stopped = 1;
} else { } else {
/* /*
* For i2c master receiver repeat restart operation like: * For i2c master receiver repeat restart operation like:
...@@ -783,6 +780,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo ...@@ -783,6 +780,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
int i, result; int i, result;
unsigned int temp; unsigned int temp;
int block_data = msgs->flags & I2C_M_RECV_LEN; int block_data = msgs->flags & I2C_M_RECV_LEN;
int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data;
dev_dbg(&i2c_imx->adapter.dev, dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n", "<%s> write slave address: addr=0x%x\n",
...@@ -809,12 +807,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo ...@@ -809,12 +807,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
*/ */
if ((msgs->len - 1) || block_data) if ((msgs->len - 1) || block_data)
temp &= ~I2CR_TXAK; temp &= ~I2CR_TXAK;
if (use_dma)
temp |= I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) if (use_dma)
return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);
/* read data */ /* read data */
...@@ -850,7 +850,6 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo ...@@ -850,7 +850,6 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
temp &= ~(I2CR_MSTA | I2CR_MTX); temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0); i2c_imx_bus_busy(i2c_imx, 0);
i2c_imx->stopped = 1;
} else { } else {
/* /*
* For i2c master receiver repeat restart operation like: * For i2c master receiver repeat restart operation like:
......
...@@ -567,9 +567,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, ...@@ -567,9 +567,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop); msg->addr, msg->len, msg->flags, stop);
if (msg->len == 0)
return -EINVAL;
/* /*
* The MX28 I2C IP block can only do PIO READ for transfer of to up * The MX28 I2C IP block can only do PIO READ for transfer of to up
* 4 bytes of length. The write transfer is not limited as it can use * 4 bytes of length. The write transfer is not limited as it can use
...@@ -683,6 +680,10 @@ static const struct i2c_algorithm mxs_i2c_algo = { ...@@ -683,6 +680,10 @@ static const struct i2c_algorithm mxs_i2c_algo = {
.functionality = mxs_i2c_func, .functionality = mxs_i2c_func,
}; };
static const struct i2c_adapter_quirks mxs_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed) static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed)
{ {
/* The I2C block clock runs at 24MHz */ /* The I2C block clock runs at 24MHz */
...@@ -854,6 +855,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) ...@@ -854,6 +855,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->algo = &mxs_i2c_algo; adap->algo = &mxs_i2c_algo;
adap->quirks = &mxs_i2c_quirks;
adap->dev.parent = dev; adap->dev.parent = dev;
adap->nr = pdev->id; adap->nr = pdev->id;
adap->dev.of_node = pdev->dev.of_node; adap->dev.of_node = pdev->dev.of_node;
......
This diff is collapsed.
...@@ -365,7 +365,6 @@ static int pasemi_smb_probe(struct pci_dev *dev, ...@@ -365,7 +365,6 @@ static int pasemi_smb_probe(struct pci_dev *dev,
smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus; smbus->adapter.algo_data = smbus;
smbus->adapter.nr = PCI_FUNC(dev->devfn);
/* set up the sysfs linkage to our parent device */ /* set up the sysfs linkage to our parent device */
smbus->adapter.dev.parent = &dev->dev; smbus->adapter.dev.parent = &dev->dev;
...@@ -373,7 +372,7 @@ static int pasemi_smb_probe(struct pci_dev *dev, ...@@ -373,7 +372,7 @@ static int pasemi_smb_probe(struct pci_dev *dev,
reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
(CLK_100K_DIV & CTL_CLK_M))); (CLK_100K_DIV & CTL_CLK_M)));
error = i2c_add_numbered_adapter(&smbus->adapter); error = i2c_add_adapter(&smbus->adapter);
if (error) if (error)
goto out_release_region; goto out_release_region;
......
...@@ -444,16 +444,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd( ...@@ -444,16 +444,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
{ {
enum pmcmsptwi_xfer_result retval; enum pmcmsptwi_xfer_result retval;
if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
(cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
(cmd->type == MSP_TWI_CMD_WRITE_READ &&
(cmd->read_len == 0 || cmd->write_len == 0))) {
dev_err(&pmcmsptwi_adapter.dev,
"%s: Cannot transfer less than 1 byte\n",
__func__);
return -EINVAL;
}
mutex_lock(&data->lock); mutex_lock(&data->lock);
dev_dbg(&pmcmsptwi_adapter.dev, dev_dbg(&pmcmsptwi_adapter.dev,
"Setting address to 0x%04x\n", cmd->addr); "Setting address to 0x%04x\n", cmd->addr);
...@@ -532,11 +522,6 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, ...@@ -532,11 +522,6 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
cmd.write_data = msg->buf; cmd.write_data = msg->buf;
} }
if (msg->len == 0) {
dev_err(&adap->dev, "Zero-byte messages unsupported\n");
return -EINVAL;
}
cmd.addr = msg->addr; cmd.addr = msg->addr;
if (msg->flags & I2C_M_TEN) { if (msg->flags & I2C_M_TEN) {
...@@ -578,7 +563,7 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) ...@@ -578,7 +563,7 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
} }
static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = { static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
.flags = I2C_AQ_COMB_WRITE_THEN_READ, .flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN,
.max_write_len = MSP_MAX_BYTES_PER_RW, .max_write_len = MSP_MAX_BYTES_PER_RW,
.max_read_len = MSP_MAX_BYTES_PER_RW, .max_read_len = MSP_MAX_BYTES_PER_RW,
.max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW, .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
......
This diff is collapsed.
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
...@@ -112,9 +113,10 @@ ...@@ -112,9 +113,10 @@
#define ID_ARBLOST (1 << 3) #define ID_ARBLOST (1 << 3)
#define ID_NACK (1 << 4) #define ID_NACK (1 << 4)
/* persistent flags */ /* persistent flags */
#define ID_P_NO_RXDMA (1 << 30) /* HW forbids RXDMA sometimes */ #define ID_P_REP_AFTER_RD BIT(29)
#define ID_P_PM_BLOCKED (1 << 31) #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
#define ID_P_MASK (ID_P_PM_BLOCKED | ID_P_NO_RXDMA) #define ID_P_PM_BLOCKED BIT(31)
#define ID_P_MASK GENMASK(31, 29)
enum rcar_i2c_type { enum rcar_i2c_type {
I2C_RCAR_GEN1, I2C_RCAR_GEN1,
...@@ -183,8 +185,6 @@ static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) ...@@ -183,8 +185,6 @@ static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
}; };
/* No get_sda, because the HW only reports its bus free logic, not SDA itself */
static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
{ {
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
...@@ -197,10 +197,19 @@ static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) ...@@ -197,10 +197,19 @@ static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
}; };
static int rcar_i2c_get_bus_free(struct i2c_adapter *adap)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
return !(rcar_i2c_read(priv, ICMCR) & FSDA);
};
static struct i2c_bus_recovery_info rcar_i2c_bri = { static struct i2c_bus_recovery_info rcar_i2c_bri = {
.get_scl = rcar_i2c_get_scl, .get_scl = rcar_i2c_get_scl,
.set_scl = rcar_i2c_set_scl, .set_scl = rcar_i2c_set_scl,
.set_sda = rcar_i2c_set_sda, .set_sda = rcar_i2c_set_sda,
.get_bus_free = rcar_i2c_get_bus_free,
.recover_bus = i2c_generic_scl_recovery, .recover_bus = i2c_generic_scl_recovery,
}; };
static void rcar_i2c_init(struct rcar_i2c_priv *priv) static void rcar_i2c_init(struct rcar_i2c_priv *priv)
...@@ -215,7 +224,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) ...@@ -215,7 +224,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{ {
int i, ret; int i;
for (i = 0; i < LOOP_TIMEOUT; i++) { for (i = 0; i < LOOP_TIMEOUT; i++) {
/* make sure that bus is not busy */ /* make sure that bus is not busy */
...@@ -226,13 +235,7 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) ...@@ -226,13 +235,7 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
/* Waiting did not help, try to recover */ /* Waiting did not help, try to recover */
priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
ret = i2c_recover_bus(&priv->adap); return i2c_recover_bus(&priv->adap);
/* No failure when recovering, so check bus busy bit again */
if (ret == 0)
ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0;
return ret;
} }
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
...@@ -343,7 +346,10 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) ...@@ -343,7 +346,10 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMSR, 0); rcar_i2c_write(priv, ICMSR, 0);
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
} else { } else {
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); if (priv->flags & ID_P_REP_AFTER_RD)
priv->flags &= ~ID_P_REP_AFTER_RD;
else
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
rcar_i2c_write(priv, ICMSR, 0); rcar_i2c_write(priv, ICMSR, 0);
} }
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
...@@ -548,15 +554,15 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) ...@@ -548,15 +554,15 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
priv->pos++; priv->pos++;
} }
/* /* If next received data is the _LAST_, go to new phase. */
* If next received data is the _LAST_, go to STOP phase. Might be if (priv->pos + 1 == msg->len) {
* overwritten by REP START when setting up a new msg. Not elegant if (priv->flags & ID_LAST_MSG) {
* but the only stable sequence for REP START I have found so far. rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
* If you want to change this code, make sure sending one transfer with } else {
* four messages (WR-RD-WR-RD) works! rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
*/ priv->flags |= ID_P_REP_AFTER_RD;
if (priv->pos + 1 >= msg->len) }
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); }
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG)) if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
rcar_i2c_next_msg(priv); rcar_i2c_next_msg(priv);
...@@ -624,9 +630,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) ...@@ -624,9 +630,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
struct rcar_i2c_priv *priv = ptr; struct rcar_i2c_priv *priv = ptr;
u32 msr, val; u32 msr, val;
/* Clear START or STOP as soon as we can */ /* Clear START or STOP immediately, except for REPSTART after read */
val = rcar_i2c_read(priv, ICMCR); if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) {
rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); val = rcar_i2c_read(priv, ICMCR);
rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
}
msr = rcar_i2c_read(priv, ICMSR); msr = rcar_i2c_read(priv, ICMSR);
...@@ -795,14 +803,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -795,14 +803,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
if (ret < 0) if (ret < 0)
goto out; goto out;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++)
/* This HW can't send STOP after address phase */
if (msgs[i].len == 0) {
ret = -EOPNOTSUPP;
goto out;
}
rcar_i2c_request_dma(priv, msgs + i); rcar_i2c_request_dma(priv, msgs + i);
}
/* init first message */ /* init first message */
priv->msg = msgs; priv->msg = msgs;
...@@ -889,6 +891,10 @@ static const struct i2c_algorithm rcar_i2c_algo = { ...@@ -889,6 +891,10 @@ static const struct i2c_algorithm rcar_i2c_algo = {
.unreg_slave = rcar_unreg_slave, .unreg_slave = rcar_unreg_slave,
}; };
static const struct i2c_adapter_quirks rcar_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static const struct of_device_id rcar_i2c_dt_ids[] = { static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 },
...@@ -942,6 +948,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -942,6 +948,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
adap->dev.parent = dev; adap->dev.parent = dev;
adap->dev.of_node = dev->of_node; adap->dev.of_node = dev->of_node;
adap->bus_recovery_info = &rcar_i2c_bri; adap->bus_recovery_info = &rcar_i2c_bri;
adap->quirks = &rcar_i2c_quirks;
i2c_set_adapdata(adap, priv); i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name)); strlcpy(adap->name, pdev->name, sizeof(adap->name));
......
...@@ -919,9 +919,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, ...@@ -919,9 +919,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
(val == CPUFREQ_PRECHANGE && delta_f > 0)) { (val == CPUFREQ_PRECHANGE && delta_f > 0)) {
i2c_lock_adapter(&i2c->adap); i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);
ret = s3c24xx_i2c_clockrate(i2c, &got); ret = s3c24xx_i2c_clockrate(i2c, &got);
i2c_unlock_adapter(&i2c->adap); i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);
if (ret < 0) if (ret < 0)
dev_err(i2c->dev, "cannot find frequency (%d)\n", ret); dev_err(i2c->dev, "cannot find frequency (%d)\n", ret);
......
...@@ -613,11 +613,6 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) ...@@ -613,11 +613,6 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
bool do_init) bool do_init)
{ {
if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
dev_err(pd->dev, "Unsupported zero length i2c read\n");
return -EOPNOTSUPP;
}
if (do_init) { if (do_init) {
/* Initialize channel registers */ /* Initialize channel registers */
iic_wr(pd, ICCR, ICCR_SCP); iic_wr(pd, ICCR, ICCR_SCP);
...@@ -758,6 +753,10 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = { ...@@ -758,6 +753,10 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
.master_xfer = sh_mobile_i2c_xfer, .master_xfer = sh_mobile_i2c_xfer,
}; };
static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN_READ,
};
/* /*
* r8a7740 chip has lasting errata on I2C I/O pad reset. * r8a7740 chip has lasting errata on I2C I/O pad reset.
* this is work-around for it. * this is work-around for it.
...@@ -925,6 +924,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -925,6 +924,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->algo = &sh_mobile_i2c_algorithm; adap->algo = &sh_mobile_i2c_algorithm;
adap->quirks = &sh_mobile_i2c_quirks;
adap->dev.parent = &dev->dev; adap->dev.parent = &dev->dev;
adap->retries = 5; adap->retries = 5;
adap->nr = dev->id; adap->nr = dev->id;
......
...@@ -590,9 +590,9 @@ static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev) ...@@ -590,9 +590,9 @@ static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)
{ {
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
i2c_lock_adapter(&i2c_dev->adap); i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = true; i2c_dev->is_suspended = true;
i2c_unlock_adapter(&i2c_dev->adap); i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
return pm_runtime_force_suspend(pdev); return pm_runtime_force_suspend(pdev);
} }
...@@ -601,9 +601,9 @@ static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev) ...@@ -601,9 +601,9 @@ static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)
{ {
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
i2c_lock_adapter(&i2c_dev->adap); i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = false; i2c_dev->is_suspended = false;
i2c_unlock_adapter(&i2c_dev->adap); i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
return pm_runtime_force_resume(pdev); return pm_runtime_force_resume(pdev);
} }
......
...@@ -673,12 +673,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap, ...@@ -673,12 +673,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,
msg->addr, msg->len, msg->flags, stop); msg->addr, msg->len, msg->flags, stop);
} }
/* Zero-length messages are not supported by this hardware */
if (msg->len == 0) {
ret = -EINVAL;
goto exit_disable;
}
/* /*
* For some reason, sending the address sometimes fails when running * For some reason, sending the address sometimes fails when running
* on the 13 MHz clock. No interrupt arrives. This is a work around, * on the 13 MHz clock. No interrupt arrives. This is a work around,
...@@ -863,6 +857,10 @@ static const struct i2c_algorithm stu300_algo = { ...@@ -863,6 +857,10 @@ static const struct i2c_algorithm stu300_algo = {
.functionality = stu300_func, .functionality = stu300_func,
}; };
static const struct i2c_adapter_quirks stu300_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static int stu300_probe(struct platform_device *pdev) static int stu300_probe(struct platform_device *pdev)
{ {
struct stu300_dev *dev; struct stu300_dev *dev;
...@@ -920,6 +918,8 @@ static int stu300_probe(struct platform_device *pdev) ...@@ -920,6 +918,8 @@ static int stu300_probe(struct platform_device *pdev)
adap->algo = &stu300_algo; adap->algo = &stu300_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node; adap->dev.of_node = pdev->dev.of_node;
adap->quirks = &stu300_quirks;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
/* i2c device drivers may be active on return from add_adapter() */ /* i2c device drivers may be active on return from add_adapter() */
......
...@@ -115,6 +115,18 @@ ...@@ -115,6 +115,18 @@
#define I2C_CONFIG_LOAD_TIMEOUT 1000000 #define I2C_CONFIG_LOAD_TIMEOUT 1000000
#define I2C_MST_FIFO_CONTROL 0x0b4
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1)
#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4)
#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
/* /*
* msg_end_type: The bus control which need to be send at end of transfer. * msg_end_type: The bus control which need to be send at end of transfer.
* @MSG_END_STOP: Send stop pulse at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer.
...@@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature { ...@@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature {
u16 clk_divisor_fast_plus_mode; u16 clk_divisor_fast_plus_mode;
bool has_multi_master_mode; bool has_multi_master_mode;
bool has_slcg_override_reg; bool has_slcg_override_reg;
bool has_mst_fifo;
}; };
/** /**
...@@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) ...@@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
{ {
unsigned long timeout = jiffies + HZ; unsigned long timeout = jiffies + HZ;
u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); unsigned int offset;
u32 mask, val;
if (i2c_dev->hw->has_mst_fifo) {
mask = I2C_MST_FIFO_CONTROL_TX_FLUSH |
I2C_MST_FIFO_CONTROL_RX_FLUSH;
offset = I2C_MST_FIFO_CONTROL;
} else {
mask = I2C_FIFO_CONTROL_TX_FLUSH |
I2C_FIFO_CONTROL_RX_FLUSH;
offset = I2C_FIFO_CONTROL;
}
val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; val = i2c_readl(i2c_dev, offset);
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); val |= mask;
i2c_writel(i2c_dev, val, offset);
while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & while (i2c_readl(i2c_dev, offset) & mask) {
(I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) ...@@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
size_t buf_remaining = i2c_dev->msg_buf_remaining; size_t buf_remaining = i2c_dev->msg_buf_remaining;
int words_to_transfer; int words_to_transfer;
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); if (i2c_dev->hw->has_mst_fifo) {
rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
I2C_FIFO_STATUS_RX_SHIFT; rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
I2C_MST_FIFO_STATUS_RX_SHIFT;
} else {
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
I2C_FIFO_STATUS_RX_SHIFT;
}
/* Rounds down to not include partial word at the end of buf */ /* Rounds down to not include partial word at the end of buf */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
...@@ -321,6 +351,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) ...@@ -321,6 +351,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0); BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
i2c_dev->msg_buf_remaining = buf_remaining; i2c_dev->msg_buf_remaining = buf_remaining;
i2c_dev->msg_buf = buf; i2c_dev->msg_buf = buf;
return 0; return 0;
} }
...@@ -332,9 +363,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) ...@@ -332,9 +363,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
size_t buf_remaining = i2c_dev->msg_buf_remaining; size_t buf_remaining = i2c_dev->msg_buf_remaining;
int words_to_transfer; int words_to_transfer;
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); if (i2c_dev->hw->has_mst_fifo) {
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
I2C_FIFO_STATUS_TX_SHIFT; tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >>
I2C_MST_FIFO_STATUS_TX_SHIFT;
} else {
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
I2C_FIFO_STATUS_TX_SHIFT;
}
/* Rounds down to not include partial word at the end of buf */ /* Rounds down to not include partial word at the end of buf */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
...@@ -516,9 +553,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) ...@@ -516,9 +553,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
} }
val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | if (i2c_dev->hw->has_mst_fifo) {
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) |
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); I2C_MST_FIFO_CONTROL_RX_TRIG(1);
i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL);
} else {
val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
}
err = tegra_i2c_flush_fifos(i2c_dev); err = tegra_i2c_flush_fifos(i2c_dev);
if (err) if (err)
...@@ -802,6 +845,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { ...@@ -802,6 +845,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_config_load_reg = false, .has_config_load_reg = false,
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false,
}; };
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
...@@ -814,6 +858,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { ...@@ -814,6 +858,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_config_load_reg = false, .has_config_load_reg = false,
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false,
}; };
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
...@@ -826,6 +871,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { ...@@ -826,6 +871,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_config_load_reg = false, .has_config_load_reg = false,
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = false, .has_slcg_override_reg = false,
.has_mst_fifo = false,
}; };
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
...@@ -838,6 +884,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { ...@@ -838,6 +884,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_config_load_reg = true, .has_config_load_reg = true,
.has_multi_master_mode = false, .has_multi_master_mode = false,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = false,
}; };
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
...@@ -850,10 +897,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { ...@@ -850,10 +897,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_config_load_reg = true, .has_config_load_reg = true,
.has_multi_master_mode = true, .has_multi_master_mode = true,
.has_slcg_override_reg = true, .has_slcg_override_reg = true,
.has_mst_fifo = false,
};
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
.clk_divisor_hs_mode = 1,
.clk_divisor_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = true,
.has_multi_master_mode = true,
.has_slcg_override_reg = true,
.has_mst_fifo = true,
}; };
/* Match table for of_platform binding */ /* Match table for of_platform binding */
static const struct of_device_id tegra_i2c_of_match[] = { static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, }, { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
......
...@@ -173,9 +173,6 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, ...@@ -173,9 +173,6 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
u8 offset; u8 offset;
u32 xfer; u32 xfer;
if (!len)
return -EOPNOTSUPP;
offset = buf[0]; offset = buf[0];
xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
...@@ -241,9 +238,6 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) ...@@ -241,9 +238,6 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
unsigned long timeout, stoptime, checktime; unsigned long timeout, stoptime, checktime;
int nbytes, timedout; int nbytes, timedout;
if (!len)
return -EOPNOTSUPP;
xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra); XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra);
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
...@@ -340,6 +334,10 @@ static const struct i2c_algorithm xlr_i2c_algo = { ...@@ -340,6 +334,10 @@ static const struct i2c_algorithm xlr_i2c_algo = {
.functionality = xlr_func, .functionality = xlr_func,
}; };
static const struct i2c_adapter_quirks xlr_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static const struct xlr_i2c_config xlr_i2c_config_default = { static const struct xlr_i2c_config xlr_i2c_config_default = {
.status_busy = XLR_I2C_BUS_BUSY, .status_busy = XLR_I2C_BUS_BUSY,
.cfg_extra = 0, .cfg_extra = 0,
...@@ -427,6 +425,7 @@ static int xlr_i2c_probe(struct platform_device *pdev) ...@@ -427,6 +425,7 @@ static int xlr_i2c_probe(struct platform_device *pdev)
priv->adap.owner = THIS_MODULE; priv->adap.owner = THIS_MODULE;
priv->adap.algo_data = priv; priv->adap.algo_data = priv;
priv->adap.algo = &xlr_i2c_algo; priv->adap.algo = &xlr_i2c_algo;
priv->adap.quirks = &xlr_i2c_quirks;
priv->adap.nr = pdev->id; priv->adap.nr = pdev->id;
priv->adap.class = I2C_CLASS_HWMON; priv->adap.class = I2C_CLASS_HWMON;
snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c");
......
...@@ -453,8 +453,12 @@ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, ...@@ -453,8 +453,12 @@ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
else else
dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",
data_len, client->addr, cmd, ret); data_len, client->addr, cmd, ret);
} else { /* 2 transfers must have completed successfully */
} else if (ret == 2) {
memcpy(data, buffer, data_len); memcpy(data, buffer, data_len);
ret = 0;
} else {
ret = -EIO;
} }
kfree(buffer); kfree(buffer);
...@@ -482,11 +486,16 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, ...@@ -482,11 +486,16 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
msgs[0].buf = buffer; msgs[0].buf = buffer;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
dev_err(&client->adapter->dev, "i2c write failed\n");
kfree(buffer); kfree(buffer);
return ret;
if (ret < 0) {
dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret);
return ret;
}
/* 1 transfer must have completed successfully */
return (ret == 1) ? 0 : -EIO;
} }
static acpi_status static acpi_status
...@@ -590,8 +599,6 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, ...@@ -590,8 +599,6 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
if (action == ACPI_READ) { if (action == ACPI_READ) {
status = acpi_gsb_i2c_read_bytes(client, command, status = acpi_gsb_i2c_read_bytes(client, command,
gsb->data, info->access_length); gsb->data, info->access_length);
if (status > 0)
status = 0;
} else { } else {
status = acpi_gsb_i2c_write_bytes(client, command, status = acpi_gsb_i2c_write_bytes(client, command,
gsb->data, info->access_length); gsb->data, info->access_length);
......
...@@ -158,6 +158,22 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val) ...@@ -158,6 +158,22 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
} }
static int i2c_generic_bus_free(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
int ret = -EOPNOTSUPP;
if (bri->get_bus_free)
ret = bri->get_bus_free(adap);
else if (bri->get_sda)
ret = bri->get_sda(adap);
if (ret < 0)
return ret;
return ret ? 0 : -EBUSY;
}
/* /*
* We are generating clock pulses. ndelay() determines durating of clk pulses. * We are generating clock pulses. ndelay() determines durating of clk pulses.
* We will generate clock with rate 100 KHz and so duration of both clock levels * We will generate clock with rate 100 KHz and so duration of both clock levels
...@@ -169,21 +185,28 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val) ...@@ -169,21 +185,28 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
int i2c_generic_scl_recovery(struct i2c_adapter *adap) int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{ {
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
int i = 0, val = 1, ret = 0; int i = 0, scl = 1, ret;
if (bri->prepare_recovery) if (bri->prepare_recovery)
bri->prepare_recovery(adap); bri->prepare_recovery(adap);
bri->set_scl(adap, val); /*
* If we can set SDA, we will always create a STOP to ensure additional
* pulses will do no harm. This is achieved by letting SDA follow SCL
* half a cycle later. Check the 'incomplete_write_byte' fault injector
* for details.
*/
bri->set_scl(adap, scl);
ndelay(RECOVERY_NDELAY / 2);
if (bri->set_sda) if (bri->set_sda)
bri->set_sda(adap, 1); bri->set_sda(adap, scl);
ndelay(RECOVERY_NDELAY); ndelay(RECOVERY_NDELAY / 2);
/* /*
* By this time SCL is high, as we need to give 9 falling-rising edges * By this time SCL is high, as we need to give 9 falling-rising edges
*/ */
while (i++ < RECOVERY_CLK_CNT * 2) { while (i++ < RECOVERY_CLK_CNT * 2) {
if (val) { if (scl) {
/* SCL shouldn't be low here */ /* SCL shouldn't be low here */
if (!bri->get_scl(adap)) { if (!bri->get_scl(adap)) {
dev_err(&adap->dev, dev_err(&adap->dev,
...@@ -191,41 +214,27 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap) ...@@ -191,41 +214,27 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
ret = -EBUSY; ret = -EBUSY;
break; break;
} }
/* Break if SDA is high */
if (bri->get_sda && bri->get_sda(adap))
break;
} }
val = !val; scl = !scl;
bri->set_scl(adap, val); bri->set_scl(adap, scl);
/* Creating STOP again, see above */
/*
* If we can set SDA, we will always create STOP here to ensure
* the additional pulses will do no harm. This is achieved by
* letting SDA follow SCL half a cycle later.
*/
ndelay(RECOVERY_NDELAY / 2); ndelay(RECOVERY_NDELAY / 2);
if (bri->set_sda) if (bri->set_sda)
bri->set_sda(adap, val); bri->set_sda(adap, scl);
ndelay(RECOVERY_NDELAY / 2); ndelay(RECOVERY_NDELAY / 2);
}
/* check if recovery actually succeeded */ if (scl) {
if (bri->get_sda && !bri->get_sda(adap)) ret = i2c_generic_bus_free(adap);
ret = -EBUSY; if (ret == 0)
break;
/* If all went well, send STOP for a sane bus state. */ }
if (ret == 0 && bri->set_sda) {
bri->set_scl(adap, 0);
ndelay(RECOVERY_NDELAY / 2);
bri->set_sda(adap, 0);
ndelay(RECOVERY_NDELAY / 2);
bri->set_scl(adap, 1);
ndelay(RECOVERY_NDELAY / 2);
bri->set_sda(adap, 1);
ndelay(RECOVERY_NDELAY / 2);
} }
/* If we can't check bus status, assume recovery worked */
if (ret == -EOPNOTSUPP)
ret = 0;
if (bri->unprepare_recovery) if (bri->unprepare_recovery)
bri->unprepare_recovery(adap); bri->unprepare_recovery(adap);
...@@ -274,6 +283,10 @@ static void i2c_init_recovery(struct i2c_adapter *adap) ...@@ -274,6 +283,10 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
err_str = "no {get|set}_scl() found"; err_str = "no {get|set}_scl() found";
goto err; goto err;
} }
if (!bri->set_sda && !bri->get_sda) {
err_str = "either get_sda() or set_sda() needed";
goto err;
}
} }
return; return;
...@@ -1563,6 +1576,8 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de ...@@ -1563,6 +1576,8 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de
ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns); ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns);
if (ret && use_defaults) if (ret && use_defaults)
t->sda_fall_ns = t->scl_fall_ns; t->sda_fall_ns = t->scl_fall_ns;
device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns);
} }
EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
...@@ -1826,9 +1841,15 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -1826,9 +1841,15 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (msgs[i].flags & I2C_M_RD) { if (msgs[i].flags & I2C_M_RD) {
if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len)) if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len))
return i2c_quirk_error(adap, &msgs[i], "msg too long"); return i2c_quirk_error(adap, &msgs[i], "msg too long");
if (q->flags & I2C_AQ_NO_ZERO_LEN_READ && len == 0)
return i2c_quirk_error(adap, &msgs[i], "no zero length");
} else { } else {
if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len)) if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len))
return i2c_quirk_error(adap, &msgs[i], "msg too long"); return i2c_quirk_error(adap, &msgs[i], "msg too long");
if (q->flags & I2C_AQ_NO_ZERO_LEN_WRITE && len == 0)
return i2c_quirk_error(adap, &msgs[i], "no zero length");
} }
} }
......
...@@ -47,9 +47,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) ...@@ -47,9 +47,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
client->slave_cb = slave_cb; client->slave_cb = slave_cb;
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
ret = client->adapter->algo->reg_slave(client); ret = client->adapter->algo->reg_slave(client);
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
if (ret) { if (ret) {
client->slave_cb = NULL; client->slave_cb = NULL;
...@@ -69,9 +69,9 @@ int i2c_slave_unregister(struct i2c_client *client) ...@@ -69,9 +69,9 @@ int i2c_slave_unregister(struct i2c_client *client)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
ret = client->adapter->algo->unreg_slave(client); ret = client->adapter->algo->unreg_slave(client);
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER);
if (ret == 0) if (ret == 0)
client->slave_cb = NULL; client->slave_cb = NULL;
......
...@@ -87,8 +87,8 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, ...@@ -87,8 +87,8 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
ret = muxc->select(muxc, priv->chan_id); ret = muxc->select(muxc, priv->chan_id);
if (ret >= 0) if (ret >= 0)
ret = parent->algo->smbus_xfer(parent, addr, flags, ret = __i2c_smbus_xfer(parent, addr, flags,
read_write, command, size, data); read_write, command, size, data);
if (muxc->deselect) if (muxc->deselect)
muxc->deselect(muxc, priv->chan_id); muxc->deselect(muxc, priv->chan_id);
......
...@@ -94,31 +94,11 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, ...@@ -94,31 +94,11 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val) struct i2c_client *client, u8 val)
{ {
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
int ret = -ENODEV; union i2c_smbus_data data = { .byte = val };
if (adap->algo->master_xfer) {
struct i2c_msg msg;
u8 msgbuf[] = {pdata->sel_reg_addr, val};
msg.addr = client->addr;
msg.flags = 0;
msg.len = 2;
msg.buf = msgbuf;
ret = __i2c_transfer(adap, &msg, 1);
if (ret >= 0 && ret != 1)
ret = -EREMOTEIO;
} else if (adap->algo->smbus_xfer) {
union i2c_smbus_data data;
data.byte = val;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags, I2C_SMBUS_WRITE,
pdata->sel_reg_addr,
I2C_SMBUS_BYTE_DATA, &data);
}
return ret; return __i2c_smbus_xfer(adap, client->addr, client->flags,
I2C_SMBUS_WRITE, pdata->sel_reg_addr,
I2C_SMBUS_BYTE_DATA, &data);
} }
static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
......
...@@ -99,31 +99,11 @@ MODULE_DEVICE_TABLE(of, pca9541_of_match); ...@@ -99,31 +99,11 @@ MODULE_DEVICE_TABLE(of, pca9541_of_match);
static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
{ {
struct i2c_adapter *adap = client->adapter; struct i2c_adapter *adap = client->adapter;
int ret; union i2c_smbus_data data = { .byte = val };
if (adap->algo->master_xfer) {
struct i2c_msg msg;
char buf[2];
msg.addr = client->addr;
msg.flags = 0;
msg.len = 2;
buf[0] = command;
buf[1] = val;
msg.buf = buf;
ret = __i2c_transfer(adap, &msg, 1);
} else {
union i2c_smbus_data data;
data.byte = val;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_WRITE,
command,
I2C_SMBUS_BYTE_DATA, &data);
}
return ret; return __i2c_smbus_xfer(adap, client->addr, client->flags,
I2C_SMBUS_WRITE, command,
I2C_SMBUS_BYTE_DATA, &data);
} }
/* /*
...@@ -133,41 +113,14 @@ static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) ...@@ -133,41 +113,14 @@ static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
static int pca9541_reg_read(struct i2c_client *client, u8 command) static int pca9541_reg_read(struct i2c_client *client, u8 command)
{ {
struct i2c_adapter *adap = client->adapter; struct i2c_adapter *adap = client->adapter;
union i2c_smbus_data data;
int ret; int ret;
u8 val;
ret = __i2c_smbus_xfer(adap, client->addr, client->flags,
if (adap->algo->master_xfer) { I2C_SMBUS_READ, command,
struct i2c_msg msg[2] = { I2C_SMBUS_BYTE_DATA, &data);
{
.addr = client->addr, return ret ?: data.byte;
.flags = 0,
.len = 1,
.buf = &command
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &val
}
};
ret = __i2c_transfer(adap, msg, 2);
if (ret == 2)
ret = val;
else if (ret >= 0)
ret = -EIO;
} else {
union i2c_smbus_data data;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_READ,
command,
I2C_SMBUS_BYTE_DATA, &data);
if (!ret)
ret = data.byte;
}
return ret;
} }
/* /*
...@@ -345,11 +298,11 @@ static int pca9541_probe(struct i2c_client *client, ...@@ -345,11 +298,11 @@ static int pca9541_probe(struct i2c_client *client,
/* /*
* I2C accesses are unprotected here. * I2C accesses are unprotected here.
* We have to lock the adapter before releasing the bus. * We have to lock the I2C segment before releasing the bus.
*/ */
i2c_lock_adapter(adap); i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
pca9541_release_bus(client); pca9541_release_bus(client);
i2c_unlock_adapter(adap); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
/* Create mux adapter */ /* Create mux adapter */
......
...@@ -220,30 +220,11 @@ MODULE_DEVICE_TABLE(of, pca954x_of_match); ...@@ -220,30 +220,11 @@ MODULE_DEVICE_TABLE(of, pca954x_of_match);
static int pca954x_reg_write(struct i2c_adapter *adap, static int pca954x_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val) struct i2c_client *client, u8 val)
{ {
int ret = -ENODEV; union i2c_smbus_data dummy;
if (adap->algo->master_xfer) {
struct i2c_msg msg;
char buf[1];
msg.addr = client->addr;
msg.flags = 0;
msg.len = 1;
buf[0] = val;
msg.buf = buf;
ret = __i2c_transfer(adap, &msg, 1);
if (ret >= 0 && ret != 1)
ret = -EREMOTEIO;
} else {
union i2c_smbus_data data;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_WRITE,
val, I2C_SMBUS_BYTE, &data);
}
return ret; return __i2c_smbus_xfer(adap, client->addr, client->flags,
I2C_SMBUS_WRITE, val,
I2C_SMBUS_BYTE, &dummy);
} }
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
...@@ -368,7 +349,8 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -368,7 +349,8 @@ static int pca954x_probe(struct i2c_client *client,
{ {
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *of_node = client->dev.of_node; struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
bool idle_disconnect_dt; bool idle_disconnect_dt;
struct gpio_desc *gpio; struct gpio_desc *gpio;
int num, force, class; int num, force, class;
...@@ -379,8 +361,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -379,8 +361,7 @@ static int pca954x_probe(struct i2c_client *client,
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV; return -ENODEV;
muxc = i2c_mux_alloc(adap, &client->dev, muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0,
PCA954X_MAX_NCHANS, sizeof(*data), 0,
pca954x_select_chan, pca954x_deselect_mux); pca954x_select_chan, pca954x_deselect_mux);
if (!muxc) if (!muxc)
return -ENOMEM; return -ENOMEM;
...@@ -390,7 +371,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -390,7 +371,7 @@ static int pca954x_probe(struct i2c_client *client,
data->client = client; data->client = client;
/* Reset the mux if a reset GPIO is specified. */ /* Reset the mux if a reset GPIO is specified. */
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio)) if (IS_ERR(gpio))
return PTR_ERR(gpio); return PTR_ERR(gpio);
if (gpio) { if (gpio) {
...@@ -400,7 +381,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -400,7 +381,7 @@ static int pca954x_probe(struct i2c_client *client,
udelay(1); udelay(1);
} }
data->chip = of_device_get_match_data(&client->dev); data->chip = of_device_get_match_data(dev);
if (!data->chip) if (!data->chip)
data->chip = &chips[id->driver_data]; data->chip = &chips[id->driver_data];
...@@ -414,8 +395,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -414,8 +395,7 @@ static int pca954x_probe(struct i2c_client *client,
if (!ret && if (!ret &&
(id.manufacturer_id != data->chip->id.manufacturer_id || (id.manufacturer_id != data->chip->id.manufacturer_id ||
id.part_id != data->chip->id.part_id)) { id.part_id != data->chip->id.part_id)) {
dev_warn(&client->dev, dev_warn(dev, "unexpected device id %03x-%03x-%x\n",
"unexpected device id %03x-%03x-%x\n",
id.manufacturer_id, id.part_id, id.manufacturer_id, id.part_id,
id.die_revision); id.die_revision);
return -ENODEV; return -ENODEV;
...@@ -427,14 +407,14 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -427,14 +407,14 @@ static int pca954x_probe(struct i2c_client *client,
* initializes the mux to disconnected state. * initializes the mux to disconnected state.
*/ */
if (i2c_smbus_write_byte(client, 0) < 0) { if (i2c_smbus_write_byte(client, 0) < 0) {
dev_warn(&client->dev, "probe failed\n"); dev_warn(dev, "probe failed\n");
return -ENODEV; return -ENODEV;
} }
data->last_chan = 0; /* force the first selection */ data->last_chan = 0; /* force the first selection */
idle_disconnect_dt = of_node && idle_disconnect_dt = np &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); of_property_read_bool(np, "i2c-mux-idle-disconnect");
ret = pca954x_irq_setup(muxc); ret = pca954x_irq_setup(muxc);
if (ret) if (ret)
...@@ -465,7 +445,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -465,7 +445,7 @@ static int pca954x_probe(struct i2c_client *client,
} }
if (data->irq) { if (data->irq) {
ret = devm_request_threaded_irq(&client->dev, data->client->irq, ret = devm_request_threaded_irq(dev, data->client->irq,
NULL, pca954x_irq_handler, NULL, pca954x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED, IRQF_ONESHOT | IRQF_SHARED,
"pca954x", data); "pca954x", data);
...@@ -473,8 +453,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -473,8 +453,7 @@ static int pca954x_probe(struct i2c_client *client,
goto fail_cleanup; goto fail_cleanup;
} }
dev_info(&client->dev, dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n",
"registered %d multiplexed busses for I2C %s %s\n",
num, data->chip->muxtype == pca954x_ismux num, data->chip->muxtype == pca954x_ismux
? "mux" : "switch", client->name); ? "mux" : "switch", client->name);
......
...@@ -433,11 +433,11 @@ static int mlx90614_wakeup(struct mlx90614_data *data) ...@@ -433,11 +433,11 @@ static int mlx90614_wakeup(struct mlx90614_data *data)
dev_dbg(&data->client->dev, "Requesting wake-up"); dev_dbg(&data->client->dev, "Requesting wake-up");
i2c_lock_adapter(data->client->adapter); i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
gpiod_direction_output(data->wakeup_gpio, 0); gpiod_direction_output(data->wakeup_gpio, 0);
msleep(MLX90614_TIMING_WAKEUP); msleep(MLX90614_TIMING_WAKEUP);
gpiod_direction_input(data->wakeup_gpio); gpiod_direction_input(data->wakeup_gpio);
i2c_unlock_adapter(data->client->adapter); i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
data->ready_timestamp = jiffies + data->ready_timestamp = jiffies +
msecs_to_jiffies(MLX90614_TIMING_STARTUP); msecs_to_jiffies(MLX90614_TIMING_STARTUP);
......
...@@ -304,7 +304,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, ...@@ -304,7 +304,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf,
msg[1].len = len; msg[1].len = len;
msg[1].buf = buf; msg[1].buf = buf;
i2c_lock_adapter(adap); i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (__i2c_transfer(adap, &msg[i], 1) < 0) { if (__i2c_transfer(adap, &msg[i], 1) < 0) {
...@@ -313,7 +313,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, ...@@ -313,7 +313,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf,
} }
} }
i2c_unlock_adapter(adap); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
......
...@@ -1311,10 +1311,10 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, ...@@ -1311,10 +1311,10 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg,
memcpy(&buf[3], val, len); memcpy(&buf[3], val, len);
if (lock) if (lock)
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = __i2c_transfer(client->adapter, msg, 1); ret = __i2c_transfer(client->adapter, msg, 1);
if (lock) if (lock)
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
if (ret < 0) { if (ret < 0) {
goto err; goto err;
} else if (ret != 1) { } else if (ret != 1) {
...@@ -1352,10 +1352,10 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, ...@@ -1352,10 +1352,10 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg,
buf[2] = cmd; buf[2] = cmd;
if (lock) if (lock)
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = __i2c_transfer(client->adapter, msg, 2); ret = __i2c_transfer(client->adapter, msg, 2);
if (lock) if (lock)
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
if (ret < 0) { if (ret < 0) {
goto err; goto err;
} else if (ret != 2) { } else if (ret != 2) {
......
...@@ -213,7 +213,7 @@ static inline u32 log10times100(u32 value) ...@@ -213,7 +213,7 @@ static inline u32 log10times100(u32 value)
static int drxk_i2c_lock(struct drxk_state *state) static int drxk_i2c_lock(struct drxk_state *state)
{ {
i2c_lock_adapter(state->i2c); i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT);
state->drxk_i2c_exclusive_lock = true; state->drxk_i2c_exclusive_lock = true;
return 0; return 0;
...@@ -224,7 +224,7 @@ static void drxk_i2c_unlock(struct drxk_state *state) ...@@ -224,7 +224,7 @@ static void drxk_i2c_unlock(struct drxk_state *state)
if (!state->drxk_i2c_exclusive_lock) if (!state->drxk_i2c_exclusive_lock)
return; return;
i2c_unlock_adapter(state->i2c); i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
state->drxk_i2c_exclusive_lock = false; state->drxk_i2c_exclusive_lock = false;
} }
......
...@@ -24,9 +24,9 @@ static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg, ...@@ -24,9 +24,9 @@ static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg,
struct rtl2830_dev *dev = i2c_get_clientdata(client); struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_bulk_write(dev->regmap, reg, val, val_count); ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
...@@ -36,9 +36,9 @@ static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg, ...@@ -36,9 +36,9 @@ static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg,
struct rtl2830_dev *dev = i2c_get_clientdata(client); struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_update_bits(dev->regmap, reg, mask, val); ret = regmap_update_bits(dev->regmap, reg, mask, val);
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
...@@ -48,9 +48,9 @@ static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg, ...@@ -48,9 +48,9 @@ static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg,
struct rtl2830_dev *dev = i2c_get_clientdata(client); struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
i2c_lock_adapter(client->adapter); i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = regmap_bulk_read(dev->regmap, reg, val, val_count); ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
i2c_unlock_adapter(client->adapter); i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
......
...@@ -329,7 +329,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state, ...@@ -329,7 +329,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
tda1004x_write_byteI(state, dspCodeCounterReg, 0); tda1004x_write_byteI(state, dspCodeCounterReg, 0);
fw_msg.addr = state->config->demod_address; fw_msg.addr = state->config->demod_address;
i2c_lock_adapter(state->i2c); i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT);
buf[0] = dspCodeInReg; buf[0] = dspCodeInReg;
while (pos != len) { while (pos != len) {
// work out how much to send this time // work out how much to send this time
...@@ -342,14 +342,14 @@ static int tda1004x_do_upload(struct tda1004x_state *state, ...@@ -342,14 +342,14 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
fw_msg.len = tx_size + 1; fw_msg.len = tx_size + 1;
if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) { if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
printk(KERN_ERR "tda1004x: Error during firmware upload\n"); printk(KERN_ERR "tda1004x: Error during firmware upload\n");
i2c_unlock_adapter(state->i2c); i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
return -EIO; return -EIO;
} }
pos += tx_size; pos += tx_size;
dprintk("%s: fw_pos=0x%x\n", __func__, pos); dprintk("%s: fw_pos=0x%x\n", __func__, pos);
} }
i2c_unlock_adapter(state->i2c); i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
/* give the DSP a chance to settle 03/10/05 Hac */ /* give the DSP a chance to settle 03/10/05 Hac */
msleep(100); msleep(100);
......
...@@ -225,7 +225,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, ...@@ -225,7 +225,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len,
*/ */
if (lock_i2c) { if (lock_i2c) {
tda18271_i2c_gate_ctrl(fe, 1); tda18271_i2c_gate_ctrl(fe, 1);
i2c_lock_adapter(priv->i2c_props.adap); i2c_lock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT);
} }
while (len) { while (len) {
if (max > len) if (max > len)
...@@ -246,7 +246,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, ...@@ -246,7 +246,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len,
len -= max; len -= max;
} }
if (lock_i2c) { if (lock_i2c) {
i2c_unlock_adapter(priv->i2c_props.adap); i2c_unlock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT);
tda18271_i2c_gate_ctrl(fe, 0); tda18271_i2c_gate_ctrl(fe, 0);
} }
...@@ -300,7 +300,7 @@ int tda18271_init_regs(struct dvb_frontend *fe) ...@@ -300,7 +300,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
* as those could cause bad things * as those could cause bad things
*/ */
tda18271_i2c_gate_ctrl(fe, 1); tda18271_i2c_gate_ctrl(fe, 1);
i2c_lock_adapter(priv->i2c_props.adap); i2c_lock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT);
/* initialize registers */ /* initialize registers */
switch (priv->id) { switch (priv->id) {
...@@ -516,7 +516,7 @@ int tda18271_init_regs(struct dvb_frontend *fe) ...@@ -516,7 +516,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
/* synchronize */ /* synchronize */
__tda18271_write_regs(fe, R_EP1, 1, false); __tda18271_write_regs(fe, R_EP1, 1, false);
i2c_unlock_adapter(priv->i2c_props.adap); i2c_unlock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT);
tda18271_i2c_gate_ctrl(fe, 0); tda18271_i2c_gate_ctrl(fe, 0);
return 0; return 0;
......
...@@ -146,14 +146,14 @@ int pm860x_page_reg_write(struct i2c_client *i2c, int reg, ...@@ -146,14 +146,14 @@ int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
unsigned char zero; unsigned char zero;
int ret; int ret;
i2c_lock_adapter(i2c->adapter); i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
read_device(i2c, 0xFA, 0, &zero); read_device(i2c, 0xFA, 0, &zero);
read_device(i2c, 0xFB, 0, &zero); read_device(i2c, 0xFB, 0, &zero);
read_device(i2c, 0xFF, 0, &zero); read_device(i2c, 0xFF, 0, &zero);
ret = write_device(i2c, reg, 1, &data); ret = write_device(i2c, reg, 1, &data);
read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero); read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter); i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
EXPORT_SYMBOL(pm860x_page_reg_write); EXPORT_SYMBOL(pm860x_page_reg_write);
...@@ -164,14 +164,14 @@ int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, ...@@ -164,14 +164,14 @@ int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
unsigned char zero = 0; unsigned char zero = 0;
int ret; int ret;
i2c_lock_adapter(i2c->adapter); i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
read_device(i2c, 0xfa, 0, &zero); read_device(i2c, 0xfa, 0, &zero);
read_device(i2c, 0xfb, 0, &zero); read_device(i2c, 0xfb, 0, &zero);
read_device(i2c, 0xff, 0, &zero); read_device(i2c, 0xff, 0, &zero);
ret = read_device(i2c, reg, count, buf); ret = read_device(i2c, reg, count, buf);
read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero); read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter); i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
return ret; return ret;
} }
EXPORT_SYMBOL(pm860x_page_bulk_read); EXPORT_SYMBOL(pm860x_page_bulk_read);
...@@ -478,6 +478,23 @@ static void at24_properties_to_pdata(struct device *dev, ...@@ -478,6 +478,23 @@ static void at24_properties_to_pdata(struct device *dev,
if (device_property_present(dev, "no-read-rollover")) if (device_property_present(dev, "no-read-rollover"))
chip->flags |= AT24_FLAG_NO_RDROL; chip->flags |= AT24_FLAG_NO_RDROL;
err = device_property_read_u32(dev, "address-width", &val);
if (!err) {
switch (val) {
case 8:
if (chip->flags & AT24_FLAG_ADDR16)
dev_warn(dev, "Override address width to be 8, while default is 16\n");
chip->flags &= ~AT24_FLAG_ADDR16;
break;
case 16:
chip->flags |= AT24_FLAG_ADDR16;
break;
default:
dev_warn(dev, "Bad \"address-width\" property: %u\n",
val);
}
}
err = device_property_read_u32(dev, "size", &val); err = device_property_read_u32(dev, "size", &val);
if (!err) if (!err)
chip->byte_len = val; chip->byte_len = val;
......
...@@ -564,6 +564,7 @@ struct i2c_lock_operations { ...@@ -564,6 +564,7 @@ struct i2c_lock_operations {
* @scl_fall_ns: time SCL signal takes to fall in ns; t(f) in the I2C specification * @scl_fall_ns: time SCL signal takes to fall in ns; t(f) in the I2C specification
* @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns * @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns
* @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification * @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification
* @sda_hold_ns: time IP core additionally needs to hold SDA in ns
*/ */
struct i2c_timings { struct i2c_timings {
u32 bus_freq_hz; u32 bus_freq_hz;
...@@ -571,6 +572,7 @@ struct i2c_timings { ...@@ -571,6 +572,7 @@ struct i2c_timings {
u32 scl_fall_ns; u32 scl_fall_ns;
u32 scl_int_delay_ns; u32 scl_int_delay_ns;
u32 sda_fall_ns; u32 sda_fall_ns;
u32 sda_hold_ns;
}; };
/** /**
...@@ -581,12 +583,14 @@ struct i2c_timings { ...@@ -581,12 +583,14 @@ struct i2c_timings {
* recovery. Populated internally for generic GPIO recovery. * recovery. Populated internally for generic GPIO recovery.
* @set_scl: This sets/clears the SCL line. Mandatory for generic SCL recovery. * @set_scl: This sets/clears the SCL line. Mandatory for generic SCL recovery.
* Populated internally for generic GPIO recovery. * Populated internally for generic GPIO recovery.
* @get_sda: This gets current value of SDA line. Optional for generic SCL * @get_sda: This gets current value of SDA line. This or set_sda() is mandatory
* recovery. Populated internally, if sda_gpio is a valid GPIO, for generic * for generic SCL recovery. Populated internally, if sda_gpio is a valid
* GPIO recovery. * GPIO, for generic GPIO recovery.
* @set_sda: This sets/clears the SDA line. Optional for generic SCL recovery. * @set_sda: This sets/clears the SDA line. This or get_sda() is mandatory for
* Populated internally, if sda_gpio is a valid GPIO, for generic GPIO * generic SCL recovery. Populated internally, if sda_gpio is a valid GPIO,
* recovery. * for generic GPIO recovery.
* @get_bus_free: Returns the bus free state as seen from the IP core in case it
* has a more complex internal logic than just reading SDA. Optional.
* @prepare_recovery: This will be called before starting recovery. Platform may * @prepare_recovery: This will be called before starting recovery. Platform may
* configure padmux here for SDA/SCL line or something else they want. * configure padmux here for SDA/SCL line or something else they want.
* @unprepare_recovery: This will be called after completing recovery. Platform * @unprepare_recovery: This will be called after completing recovery. Platform
...@@ -601,6 +605,7 @@ struct i2c_bus_recovery_info { ...@@ -601,6 +605,7 @@ struct i2c_bus_recovery_info {
void (*set_scl)(struct i2c_adapter *adap, int val); void (*set_scl)(struct i2c_adapter *adap, int val);
int (*get_sda)(struct i2c_adapter *adap); int (*get_sda)(struct i2c_adapter *adap);
void (*set_sda)(struct i2c_adapter *adap, int val); void (*set_sda)(struct i2c_adapter *adap, int val);
int (*get_bus_free)(struct i2c_adapter *adap);
void (*prepare_recovery)(struct i2c_adapter *adap); void (*prepare_recovery)(struct i2c_adapter *adap);
void (*unprepare_recovery)(struct i2c_adapter *adap); void (*unprepare_recovery)(struct i2c_adapter *adap);
...@@ -658,6 +663,10 @@ struct i2c_adapter_quirks { ...@@ -658,6 +663,10 @@ struct i2c_adapter_quirks {
I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR) I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
/* clock stretching is not supported */ /* clock stretching is not supported */
#define I2C_AQ_NO_CLK_STRETCH BIT(4) #define I2C_AQ_NO_CLK_STRETCH BIT(4)
/* message cannot have length of 0 */
#define I2C_AQ_NO_ZERO_LEN_READ BIT(5)
#define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6)
#define I2C_AQ_NO_ZERO_LEN (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE)
/* /*
* i2c_adapter is the structure used to identify a physical i2c bus along * i2c_adapter is the structure used to identify a physical i2c bus along
...@@ -759,18 +768,6 @@ i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) ...@@ -759,18 +768,6 @@ i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
adapter->lock_ops->unlock_bus(adapter, flags); adapter->lock_ops->unlock_bus(adapter, flags);
} }
static inline void
i2c_lock_adapter(struct i2c_adapter *adapter)
{
i2c_lock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
}
static inline void
i2c_unlock_adapter(struct i2c_adapter *adapter)
{
i2c_unlock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
}
/*flags for the client struct: */ /*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ #define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ #define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment