Commit 45182e4e authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:

 - API for late atomic transfers (e.g. to shut down via PMIC). We have a
   seperate callback now which is called under clearly defined
   conditions. In-kernel users are converted, too.

 - new driver for the AMD PCIe MP2 I2C controller

 - large refactoring for at91 and bcm-iproc (both gain slave support due
   to this)

 - and a good share of various driver improvements anf fixes

* 'i2c/for-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (57 commits)
  dt-bindings: i2c: riic: document r7s9210 support
  i2c: imx-lpi2c: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
  i2c-piix4: Add Hygon Dhyana SMBus support
  i2c: core: apply 'is_suspended' check for SMBus, too
  i2c: core: ratelimit 'transfer when suspended' errors
  i2c: iproc: Change driver to use 'BIT' macro
  i2c: riic: Add Runtime PM support
  i2c: mux: demux-pinctrl: use struct_size() in devm_kzalloc()
  i2c: mux: pca954x: allow management of device idle state via sysfs
  i2c: mux: pca9541: remove support for unused platform data
  i2c: mux: pca954x: remove support for unused platform data
  dt-bindings: i2c: i2c-mtk: add support for MT8516
  i2c: axxia: use auto cmd for last message
  i2c: gpio: flag atomic capability if possible
  i2c: algo: bit: add flag to whitelist atomic transfers
  i2c: stu300: use xfer_atomic callback to bail out early
  i2c: ocores: enable atomic xfers
  i2c: ocores: refactor setup for polling
  i2c: tegra-bpmp: convert to use new atomic callbacks
  i2c: omap: Add the master_xfer_atomic hook
  ...
parents 06cbd26d e6ae3ca2
What: /sys/bus/i2c/.../idle_state
Date: January 2019
KernelVersion: 5.2
Contact: Robert Shearman <robert.shearman@att.com>
Description:
Value that exists only for mux devices that can be
written to control the behaviour of the multiplexer on
idle. Possible values:
-2 - disconnect on idle, i.e. deselect the last used
channel, which is useful when there is a device
with an address that conflicts with another
device on another mux on the same parent bus.
-1 - leave the mux as-is, which is the most optimal
setting in terms of I2C operations and is the
default mode.
0..<nchans> - set the mux to a predetermined channel,
which is useful if there is one channel that is
used almost always, and you want to reduce the
latency for normal operations after rare
transactions on other channels
...@@ -50,6 +50,7 @@ Required properties: ...@@ -50,6 +50,7 @@ Required properties:
"nxp,se97b" - the fallback is "atmel,24c02", "nxp,se97b" - the fallback is "atmel,24c02",
"renesas,r1ex24002" - the fallback is "atmel,24c02" "renesas,r1ex24002" - the fallback is "atmel,24c02"
"renesas,r1ex24016" - the fallback is "atmel,24c16"
"renesas,r1ex24128" - the fallback is "atmel,24c128" "renesas,r1ex24128" - the fallback is "atmel,24c128"
"rohm,br24t01" - the fallback is "atmel,24c01" "rohm,br24t01" - the fallback is "atmel,24c01"
......
...@@ -3,15 +3,12 @@ Broadcom iProc I2C controller ...@@ -3,15 +3,12 @@ Broadcom iProc I2C controller
Required properties: Required properties:
- compatible: - compatible:
Must be "brcm,iproc-i2c" Must be "brcm,iproc-i2c" or "brcm,iproc-nic-i2c"
- reg: - reg:
Define the base and range of the I/O address space that contain the iProc Define the base and range of the I/O address space that contain the iProc
I2C controller registers I2C controller registers
- interrupts:
Should contain the I2C interrupt
- clock-frequency: - clock-frequency:
This is the I2C bus clock. Need to be either 100000 or 400000 This is the I2C bus clock. Need to be either 100000 or 400000
...@@ -21,6 +18,18 @@ Required properties: ...@@ -21,6 +18,18 @@ Required properties:
- #size-cells: - #size-cells:
Always 0 Always 0
Optional properties:
- interrupts:
Should contain the I2C interrupt. For certain revisions of the I2C
controller, I2C interrupt is unwired to the interrupt controller. In such
case, this property should be left unspecified, and driver will fall back
to polling mode
- brcm,ape-hsls-addr-mask:
Required for "brcm,iproc-nic-i2c". Host view of address mask into the
'APE' co-processor. Value must be unsigned, 32-bit
Example: Example:
i2c0: i2c@18008000 { i2c0: i2c@18008000 {
compatible = "brcm,iproc-i2c"; compatible = "brcm,iproc-i2c";
......
...@@ -6,12 +6,21 @@ Required properties : ...@@ -6,12 +6,21 @@ Required properties :
or "mscc,ocelot-i2c" with "snps,designware-i2c" for fallback or "mscc,ocelot-i2c" with "snps,designware-i2c" for fallback
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number. - interrupts : <IRQ> where IRQ is the interrupt number.
- clocks : phandles for the clocks, see the description of clock-names below.
The phandle for the "ic_clk" clock is required. The phandle for the "pclk"
clock is optional. If a single clock is specified but no clock-name, it is
the "ic_clk" clock. If both clocks are listed, the "ic_clk" must be first.
Recommended properties : Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz. - clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties : Optional properties :
- clock-names : Contains the names of the clocks:
"ic_clk", for the core clock used to generate the external I2C clock.
"pclk", the interface clock, required for register access.
- reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold - reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
time, named ICPU_CFG:TWI_DELAY in the datasheet. time, named ICPU_CFG:TWI_DELAY in the datasheet.
......
...@@ -12,13 +12,16 @@ Required properties: ...@@ -12,13 +12,16 @@ Required properties:
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623 "mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629 "mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
"mediatek,mt8173-i2c": for MediaTek MT8173 "mediatek,mt8173-i2c": for MediaTek MT8173
"mediatek,mt8183-i2c": for MediaTek MT8183
"mediatek,mt8516-i2c", "mediatek,mt2712-i2c": for MediaTek MT8516
- reg: physical base address of the controller and dma base, length of memory - reg: physical base address of the controller and dma base, length of memory
mapped region. mapped region.
- interrupts: interrupt number to the cpu. - interrupts: interrupt number to the cpu.
- clock-div: the fixed value for frequency divider of clock source in i2c - clock-div: the fixed value for frequency divider of clock source in i2c
module. Each IC may be different. module. Each IC may be different.
- clocks: clock name from clock manager - clocks: clock name from clock manager
- clock-names: Must include "main" and "dma", if enable have-pmic need include - clock-names: Must include "main" and "dma", "arb" is for multi-master that
one bus has more than two i2c controllers, if enable have-pmic need include
"pmic" extra. "pmic" extra.
Optional properties: Optional properties:
......
Device tree configuration for Renesas RIIC driver Device tree configuration for Renesas RIIC driver
Required properties: Required properties:
- compatible : "renesas,riic-<soctype>". "renesas,riic-rz" as fallback - compatible :
"renesas,riic-r7s72100" if the device is a part of a R7S72100 SoC.
"renesas,riic-r7s9210" if the device is a part of a R7S9210 SoC.
"renesas,riic-rz" for a generic RZ/A compatible device.
- reg : address start and address range size of device - reg : address start and address range size of device
- interrupts : 8 interrupts (TEI, RI, TI, SPI, STI, NAKI, ALI, TMOI) - interrupts : 8 interrupts (TEI, RI, TI, SPI, STI, NAKI, ALI, TMOI)
- clock-frequency : frequency of bus clock in Hz - clock-frequency : frequency of bus clock in Hz
......
* I2C controller embedded in STMicroelectronics STM32 I2C platform * I2C controller embedded in STMicroelectronics STM32 I2C platform
Required properties : Required properties:
- compatible : Must be one of the following - compatible: Must be one of the following
- "st,stm32f4-i2c" - "st,stm32f4-i2c"
- "st,stm32f7-i2c" - "st,stm32f7-i2c"
- reg : Offset and length of the register set for the device - reg: Offset and length of the register set for the device
- interrupts : Must contain the interrupt id for I2C event and then the - interrupts: Must contain the interrupt id for I2C event and then the
interrupt id for I2C error. interrupt id for I2C error.
- resets: Must contain the phandle to the reset controller. - resets: Must contain the phandle to the reset controller.
- clocks: Must contain the input clock of the I2C instance. - clocks: Must contain the input clock of the I2C instance.
...@@ -14,25 +14,26 @@ Required properties : ...@@ -14,25 +14,26 @@ Required properties :
- #address-cells = <1>; - #address-cells = <1>;
- #size-cells = <0>; - #size-cells = <0>;
Optional properties : Optional properties:
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, - clock-frequency: Desired I2C bus clock frequency in Hz. If not specified,
the default 100 kHz frequency will be used. the default 100 kHz frequency will be used.
For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are
100000 and 400000. 100000 and 400000.
For STM32F7 SoC, Standard-mode, Fast-mode and Fast-mode Plus are supported, For STM32F7, STM32H7 and STM32MP1 SoCs, Standard-mode, Fast-mode and Fast-mode
possible values are 100000, 400000 and 1000000. Plus are supported, possible values are 100000, 400000 and 1000000.
- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board - i2c-scl-rising-time-ns: I2C SCL Rising time for the board (default: 25)
(default: 25) For STM32F7, STM32H7 and STM32MP1 only.
- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board - i2c-scl-falling-time-ns: I2C SCL Falling time for the board (default: 10)
(default: 10) For STM32F7, STM32H7 and STM32MP1 only.
I2C Timings are derived from these 2 values I2C Timings are derived from these 2 values
- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG - st,syscfg-fmp: Use to set Fast Mode Plus bit within SYSCFG when Fast Mode
whether Fast Mode Plus speed is selected by slave. Plus speed is selected by slave.
1st cell : phandle to syscfg 1st cell: phandle to syscfg
2nd cell : register offset within SYSCFG 2nd cell: register offset within SYSCFG
3rd cell : register bitmask for FMP bit 3rd cell: register bitmask for FMP bit
For STM32F7, STM32H7 and STM32MP1 only.
Example : Example:
i2c@40005400 { i2c@40005400 {
compatible = "st,stm32f4-i2c"; compatible = "st,stm32f4-i2c";
......
Kernel driver i2c-amd-mp2
Supported adapters:
* AMD MP2 PCIe interface
Datasheet: not publicly available.
Authors:
Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Nehal Shah <nehal-bakulchandra.shah@amd.com>
Elie Morisse <syniurge@gmail.com>
Description
-----------
The MP2 is an ARM processor programmed as an I2C controller and communicating
with the x86 host through PCI.
If you see something like this:
03:00.7 MP2 I2C controller: Advanced Micro Devices, Inc. [AMD] Device 15e6
in your 'lspci -v', then this driver is for your device.
...@@ -15,6 +15,8 @@ Supported adapters: ...@@ -15,6 +15,8 @@ Supported adapters:
http://support.amd.com/us/Embedded_TechDocs/44413.pdf http://support.amd.com/us/Embedded_TechDocs/44413.pdf
* AMD Hudson-2, ML, CZ * AMD Hudson-2, ML, CZ
Datasheet: Not publicly available Datasheet: Not publicly available
* Hygon CZ
Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com Datasheet: Publicly available at the SMSC website http://www.smsc.com
......
...@@ -826,6 +826,14 @@ F: drivers/gpu/drm/amd/include/vi_structs.h ...@@ -826,6 +826,14 @@ F: drivers/gpu/drm/amd/include/vi_structs.h
F: drivers/gpu/drm/amd/include/v9_structs.h F: drivers/gpu/drm/amd/include/v9_structs.h
F: include/uapi/linux/kfd_ioctl.h F: include/uapi/linux/kfd_ioctl.h
AMD MP2 I2C DRIVER
M: Elie Morisse <syniurge@gmail.com>
M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
M: Shyam Sundar S K <shyam-sundar.s-k@amd.com>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-amd-mp2*
AMD POWERPLAY AMD POWERPLAY
M: Rex Zhu <rex.zhu@amd.com> M: Rex Zhu <rex.zhu@amd.com>
M: Evan Quan <evan.quan@amd.com> M: Evan Quan <evan.quan@amd.com>
...@@ -2582,7 +2590,7 @@ F: include/linux/dmaengine.h ...@@ -2582,7 +2590,7 @@ F: include/linux/dmaengine.h
F: include/linux/async_tx.h F: include/linux/async_tx.h
AT24 EEPROM DRIVER AT24 EEPROM DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl> M: Bartosz Golaszewski <bgolaszewski@baylibre.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
S: Maintained S: Maintained
...@@ -10207,7 +10215,8 @@ MICROCHIP I2C DRIVER ...@@ -10207,7 +10215,8 @@ MICROCHIP I2C DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com> M: Ludovic Desroches <ludovic.desroches@microchip.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
S: Supported S: Supported
F: drivers/i2c/busses/i2c-at91.c F: drivers/i2c/busses/i2c-at91.h
F: drivers/i2c/busses/i2c-at91-*.c
MICROCHIP ISC DRIVER MICROCHIP ISC DRIVER
M: Eugen Hristev <eugen.hristev@microchip.com> M: Eugen Hristev <eugen.hristev@microchip.com>
......
...@@ -603,6 +603,23 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, ...@@ -603,6 +603,23 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
return ret; return ret;
} }
/*
* We print a warning when we are not flagged to support atomic transfers but
* will try anyhow. That's what the I2C core would do as well. Sadly, we can't
* modify the algorithm struct at probe time because this struct is exported
* 'const'.
*/
static int bit_xfer_atomic(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
int num)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
if (!adap->can_do_atomic)
dev_warn(&i2c_adap->dev, "not flagged for atomic transfers\n");
return bit_xfer(i2c_adap, msgs, num);
}
static u32 bit_func(struct i2c_adapter *adap) static u32 bit_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
...@@ -615,8 +632,9 @@ static u32 bit_func(struct i2c_adapter *adap) ...@@ -615,8 +632,9 @@ static u32 bit_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */ /* -----exported algorithm data: ------------------------------------- */
const struct i2c_algorithm i2c_bit_algo = { const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer, .master_xfer = bit_xfer,
.functionality = bit_func, .master_xfer_atomic = bit_xfer_atomic,
.functionality = bit_func,
}; };
EXPORT_SYMBOL(i2c_bit_algo); EXPORT_SYMBOL(i2c_bit_algo);
......
...@@ -77,6 +77,16 @@ config I2C_AMD8111 ...@@ -77,6 +77,16 @@ config I2C_AMD8111
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-amd8111. will be called i2c-amd8111.
config I2C_AMD_MP2
tristate "AMD MP2 PCIe"
depends on PCI && ACPI
help
If you say yes to this option, support will be included for the AMD
MP2 PCIe I2C adapter.
This driver can also be built as modules. If so, the modules will
be called i2c-amd-mp2-pci and i2c-amd-mp2-plat.
config I2C_HIX5HD2 config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver" tristate "Hix5hd2 high-speed I2C driver"
depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
...@@ -176,6 +186,7 @@ config I2C_PIIX4 ...@@ -176,6 +186,7 @@ config I2C_PIIX4
AMD Hudson-2 AMD Hudson-2
AMD ML AMD ML
AMD CZ AMD CZ
Hygon CZ
Serverworks OSB4 Serverworks OSB4
Serverworks CSB5 Serverworks CSB5
Serverworks CSB6 Serverworks CSB6
...@@ -388,6 +399,19 @@ config I2C_AT91 ...@@ -388,6 +399,19 @@ config I2C_AT91
the latency to fill the transmission register is too long. If you the latency to fill the transmission register is too long. If you
are facing this situation, use the i2c-gpio driver. are facing this situation, use the i2c-gpio driver.
config I2C_AT91_SLAVE_EXPERIMENTAL
tristate "Microchip AT91 I2C experimental slave mode"
depends on I2C_AT91
select I2C_SLAVE
help
If you say yes to this option, support for the slave mode will be
added. Caution: do not use it for production. This feature has not
been tested in a heavy way, help wanted.
There are known bugs:
- It can hang, on a SAMA5D4, after several transfers.
- There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as
master.
config I2C_AU1550 config I2C_AU1550
tristate "Au1550/Au1200/Au1300 SMBus interface" tristate "Au1550/Au1200/Au1300 SMBus interface"
depends on MIPS_ALCHEMY depends on MIPS_ALCHEMY
...@@ -425,6 +449,7 @@ config I2C_BCM_IPROC ...@@ -425,6 +449,7 @@ config I2C_BCM_IPROC
tristate "Broadcom iProc I2C controller" tristate "Broadcom iProc I2C controller"
depends on ARCH_BCM_IPROC || COMPILE_TEST depends on ARCH_BCM_IPROC || COMPILE_TEST
default ARCH_BCM_IPROC default ARCH_BCM_IPROC
select I2C_SLAVE
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
Broadcom iProc I2C controller. Broadcom iProc I2C controller.
......
...@@ -33,8 +33,13 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o ...@@ -33,8 +33,13 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
# Embedded system I2C/SMBus host controller drivers # Embedded system I2C/SMBus host controller drivers
obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o
obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o
obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o
i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o
ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y)
i2c-at91-objs += i2c-at91-slave.o
endif
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* AMD MP2 platform driver
*
* Setup the I2C adapters enumerated in the ACPI namespace.
* MP2 controllers have 2 separate busses, up to 2 I2C adapters may be listed.
*
* Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
* Elie Morisse <syniurge@gmail.com>
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "i2c-amd-mp2.h"
#define AMD_MP2_I2C_MAX_RW_LENGTH ((1 << 12) - 1)
#define AMD_I2C_TIMEOUT (msecs_to_jiffies(250))
/**
* struct amd_i2c_dev - MP2 bus/i2c adapter context
* @common: shared context with the MP2 PCI driver
* @pdev: platform driver node
* @adap: i2c adapter
* @cmd_complete: xfer completion object
*/
struct amd_i2c_dev {
struct amd_i2c_common common;
struct platform_device *pdev;
struct i2c_adapter adap;
struct completion cmd_complete;
};
#define amd_i2c_dev_common(__common) \
container_of(__common, struct amd_i2c_dev, common)
static int i2c_amd_dma_map(struct amd_i2c_common *i2c_common)
{
struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
enum dma_data_direction dma_direction =
i2c_common->msg->flags & I2C_M_RD ?
DMA_FROM_DEVICE : DMA_TO_DEVICE;
i2c_common->dma_buf = i2c_get_dma_safe_msg_buf(i2c_common->msg, 0);
i2c_common->dma_addr = dma_map_single(dev_pci, i2c_common->dma_buf,
i2c_common->msg->len,
dma_direction);
if (unlikely(dma_mapping_error(dev_pci, i2c_common->dma_addr))) {
dev_err(&i2c_dev->pdev->dev,
"Error while mapping dma buffer %p\n",
i2c_common->dma_buf);
return -EIO;
}
return 0;
}
static void i2c_amd_dma_unmap(struct amd_i2c_common *i2c_common)
{
struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
enum dma_data_direction dma_direction =
i2c_common->msg->flags & I2C_M_RD ?
DMA_FROM_DEVICE : DMA_TO_DEVICE;
dma_unmap_single(dev_pci, i2c_common->dma_addr,
i2c_common->msg->len, dma_direction);
i2c_put_dma_safe_msg_buf(i2c_common->dma_buf, i2c_common->msg, true);
}
static void i2c_amd_start_cmd(struct amd_i2c_dev *i2c_dev)
{
struct amd_i2c_common *i2c_common = &i2c_dev->common;
reinit_completion(&i2c_dev->cmd_complete);
i2c_common->cmd_success = false;
}
static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common)
{
struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
union i2c_event *event = &i2c_common->eventval;
if (event->r.status == i2c_readcomplete_event)
dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
__func__, event->r.length,
i2c_common->msg->buf);
complete(&i2c_dev->cmd_complete);
}
static int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev)
{
struct amd_i2c_common *i2c_common = &i2c_dev->common;
unsigned long timeout;
timeout = wait_for_completion_timeout(&i2c_dev->cmd_complete,
i2c_dev->adap.timeout);
if ((i2c_common->reqcmd == i2c_read ||
i2c_common->reqcmd == i2c_write) &&
i2c_common->msg->len > 32)
i2c_amd_dma_unmap(i2c_common);
if (timeout == 0) {
amd_mp2_rw_timeout(i2c_common);
return -ETIMEDOUT;
}
amd_mp2_process_event(i2c_common);
if (!i2c_common->cmd_success)
return -EIO;
return 0;
}
static int i2c_amd_enable_set(struct amd_i2c_dev *i2c_dev, bool enable)
{
struct amd_i2c_common *i2c_common = &i2c_dev->common;
i2c_amd_start_cmd(i2c_dev);
amd_mp2_bus_enable_set(i2c_common, enable);
return i2c_amd_check_cmd_completion(i2c_dev);
}
static int i2c_amd_xfer_msg(struct amd_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
{
struct amd_i2c_common *i2c_common = &i2c_dev->common;
i2c_amd_start_cmd(i2c_dev);
i2c_common->msg = pmsg;
if (pmsg->len > 32)
if (i2c_amd_dma_map(i2c_common))
return -EIO;
if (pmsg->flags & I2C_M_RD)
amd_mp2_rw(i2c_common, i2c_read);
else
amd_mp2_rw(i2c_common, i2c_write);
return i2c_amd_check_cmd_completion(i2c_dev);
}
static int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct amd_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
int i;
struct i2c_msg *pmsg;
int err;
/* the adapter might have been deleted while waiting for the bus lock */
if (unlikely(!i2c_dev->common.mp2_dev))
return -EINVAL;
amd_mp2_pm_runtime_get(i2c_dev->common.mp2_dev);
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
err = i2c_amd_xfer_msg(i2c_dev, pmsg);
if (err)
break;
}
amd_mp2_pm_runtime_put(i2c_dev->common.mp2_dev);
return err ? err : num;
}
static u32 i2c_amd_func(struct i2c_adapter *a)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm i2c_amd_algorithm = {
.master_xfer = i2c_amd_xfer,
.functionality = i2c_amd_func,
};
#ifdef CONFIG_PM
static int i2c_amd_suspend(struct amd_i2c_common *i2c_common)
{
struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
i2c_amd_enable_set(i2c_dev, false);
return 0;
}
static int i2c_amd_resume(struct amd_i2c_common *i2c_common)
{
struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
return i2c_amd_enable_set(i2c_dev, true);
}
#endif
static enum speed_enum i2c_amd_get_bus_speed(struct platform_device *pdev)
{
u32 acpi_speed;
int i;
static const u32 supported_speeds[] = {
0, 100000, 400000, 1000000, 1400000, 3400000
};
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
/* round down to the lowest standard speed */
for (i = 1; i < ARRAY_SIZE(supported_speeds); i++) {
if (acpi_speed < supported_speeds[i])
break;
}
acpi_speed = supported_speeds[i - 1];
switch (acpi_speed) {
case 100000:
return speed100k;
case 400000:
return speed400k;
case 1000000:
return speed1000k;
case 1400000:
return speed1400k;
case 3400000:
return speed3400k;
default:
return speed400k;
}
}
static const struct i2c_adapter_quirks amd_i2c_dev_quirks = {
.max_read_len = AMD_MP2_I2C_MAX_RW_LENGTH,
.max_write_len = AMD_MP2_I2C_MAX_RW_LENGTH,
};
static int i2c_amd_probe(struct platform_device *pdev)
{
int ret;
struct amd_i2c_dev *i2c_dev;
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
struct acpi_device *adev;
struct amd_mp2_dev *mp2_dev;
const char *uid;
if (acpi_bus_get_device(handle, &adev))
return -ENODEV;
/* The ACPI namespace doesn't contain information about which MP2 PCI
* device an AMDI0011 ACPI device is related to, so assume that there's
* only one MP2 PCI device per system.
*/
mp2_dev = amd_mp2_find_device();
if (!mp2_dev || !mp2_dev->probed)
/* The MP2 PCI device should get probed later */
return -EPROBE_DEFER;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return -ENOMEM;
i2c_dev->common.mp2_dev = mp2_dev;
i2c_dev->pdev = pdev;
platform_set_drvdata(pdev, i2c_dev);
i2c_dev->common.cmd_completion = &i2c_amd_cmd_completion;
#ifdef CONFIG_PM
i2c_dev->common.suspend = &i2c_amd_suspend;
i2c_dev->common.resume = &i2c_amd_resume;
#endif
uid = adev->pnp.unique_id;
if (!uid) {
dev_err(&pdev->dev, "missing UID/bus id!\n");
return -EINVAL;
} else if (strcmp(uid, "0") == 0) {
i2c_dev->common.bus_id = 0;
} else if (strcmp(uid, "1") == 0) {
i2c_dev->common.bus_id = 1;
} else {
dev_err(&pdev->dev, "incorrect UID/bus id \"%s\"!\n", uid);
return -EINVAL;
}
dev_dbg(&pdev->dev, "bus id is %u\n", i2c_dev->common.bus_id);
/* Register the adapter */
amd_mp2_pm_runtime_get(mp2_dev);
i2c_dev->common.reqcmd = i2c_none;
if (amd_mp2_register_cb(&i2c_dev->common))
return -EINVAL;
device_link_add(&i2c_dev->pdev->dev, &mp2_dev->pci_dev->dev,
DL_FLAG_AUTOREMOVE_CONSUMER);
i2c_dev->common.i2c_speed = i2c_amd_get_bus_speed(pdev);
/* Setup i2c adapter description */
i2c_dev->adap.owner = THIS_MODULE;
i2c_dev->adap.algo = &i2c_amd_algorithm;
i2c_dev->adap.quirks = &amd_i2c_dev_quirks;
i2c_dev->adap.dev.parent = &pdev->dev;
i2c_dev->adap.algo_data = i2c_dev;
i2c_dev->adap.timeout = AMD_I2C_TIMEOUT;
ACPI_COMPANION_SET(&i2c_dev->adap.dev, ACPI_COMPANION(&pdev->dev));
i2c_dev->adap.dev.of_node = pdev->dev.of_node;
snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
"AMD MP2 i2c bus %u", i2c_dev->common.bus_id);
i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
init_completion(&i2c_dev->cmd_complete);
/* Enable the bus */
if (i2c_amd_enable_set(i2c_dev, true))
dev_err(&pdev->dev, "initial bus enable failed\n");
/* Attach to the i2c layer */
ret = i2c_add_adapter(&i2c_dev->adap);
amd_mp2_pm_runtime_put(mp2_dev);
if (ret < 0)
dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
return ret;
}
static int i2c_amd_remove(struct platform_device *pdev)
{
struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
struct amd_i2c_common *i2c_common = &i2c_dev->common;
i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_amd_enable_set(i2c_dev, false);
amd_mp2_unregister_cb(i2c_common);
i2c_common->mp2_dev = NULL;
i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_del_adapter(&i2c_dev->adap);
return 0;
}
static const struct acpi_device_id i2c_amd_acpi_match[] = {
{ "AMDI0011" },
{ },
};
MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
static struct platform_driver i2c_amd_plat_driver = {
.probe = i2c_amd_probe,
.remove = i2c_amd_remove,
.driver = {
.name = "i2c_amd_mp2",
.acpi_match_table = ACPI_PTR(i2c_amd_acpi_match),
},
};
module_platform_driver(i2c_amd_plat_driver);
MODULE_DESCRIPTION("AMD(R) MP2 I2C Platform Driver");
MODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* AMD MP2 I2C adapter driver
*
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
* Elie Morisse <syniurge@gmail.com>
*/
#ifndef I2C_AMD_PCI_MP2_H
#define I2C_AMD_PCI_MP2_H
#include <linux/i2c.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#define PCI_DEVICE_ID_AMD_MP2 0x15E6
struct amd_i2c_common;
struct amd_mp2_dev;
enum {
/* MP2 C2P Message Registers */
AMD_C2P_MSG0 = 0x10500, /* MP2 Message for I2C0 */
AMD_C2P_MSG1 = 0x10504, /* MP2 Message for I2C1 */
AMD_C2P_MSG2 = 0x10508, /* DRAM Address Lo / Data 0 */
AMD_C2P_MSG3 = 0x1050c, /* DRAM Address HI / Data 1 */
AMD_C2P_MSG4 = 0x10510, /* Data 2 */
AMD_C2P_MSG5 = 0x10514, /* Data 3 */
AMD_C2P_MSG6 = 0x10518, /* Data 4 */
AMD_C2P_MSG7 = 0x1051c, /* Data 5 */
AMD_C2P_MSG8 = 0x10520, /* Data 6 */
AMD_C2P_MSG9 = 0x10524, /* Data 7 */
/* MP2 P2C Message Registers */
AMD_P2C_MSG0 = 0x10680, /* Do not use */
AMD_P2C_MSG1 = 0x10684, /* I2C0 interrupt register */
AMD_P2C_MSG2 = 0x10688, /* I2C1 interrupt register */
AMD_P2C_MSG3 = 0x1068C, /* MP2 debug info */
AMD_P2C_MSG_INTEN = 0x10690, /* MP2 interrupt gen register */
AMD_P2C_MSG_INTSTS = 0x10694, /* Interrupt status */
};
/* Command register data structures */
#define i2c_none (-1)
enum i2c_cmd {
i2c_read = 0,
i2c_write,
i2c_enable,
i2c_disable,
number_of_sensor_discovered,
is_mp2_active,
invalid_cmd = 0xF,
};
enum speed_enum {
speed100k = 0,
speed400k = 1,
speed1000k = 2,
speed1400k = 3,
speed3400k = 4
};
enum mem_type {
use_dram = 0,
use_c2pmsg = 1,
};
/**
* union i2c_cmd_base : bit access of C2P commands
* @i2c_cmd: bit 0..3 i2c R/W command
* @bus_id: bit 4..7 i2c bus index
* @slave_addr: bit 8..15 slave address
* @length: bit 16..27 read/write length
* @i2c_speed: bit 28..30 bus speed
* @mem_type: bit 31 0-DRAM; 1-C2P msg o/p
*/
union i2c_cmd_base {
u32 ul;
struct {
enum i2c_cmd i2c_cmd : 4;
u8 bus_id : 4;
u32 slave_addr : 8;
u32 length : 12;
enum speed_enum i2c_speed : 3;
enum mem_type mem_type : 1;
} s;
};
enum response_type {
invalid_response = 0,
command_success = 1,
command_failed = 2,
};
enum status_type {
i2c_readcomplete_event = 0,
i2c_readfail_event = 1,
i2c_writecomplete_event = 2,
i2c_writefail_event = 3,
i2c_busenable_complete = 4,
i2c_busenable_failed = 5,
i2c_busdisable_complete = 6,
i2c_busdisable_failed = 7,
invalid_data_length = 8,
invalid_slave_address = 9,
invalid_i2cbus_id = 10,
invalid_dram_addr = 11,
invalid_command = 12,
mp2_active = 13,
numberof_sensors_discovered_resp = 14,
i2c_bus_notinitialized
};
/**
* union i2c_event : bit access of P2C events
* @response: bit 0..1 i2c response type
* @status: bit 2..6 status_type
* @mem_type: bit 7 0-DRAM; 1-C2P msg o/p
* @bus_id: bit 8..11 i2c bus id
* @length: bit 12..23 message length
* @slave_addr: bit 24-31 slave address
*/
union i2c_event {
u32 ul;
struct {
enum response_type response : 2;
enum status_type status : 5;
enum mem_type mem_type : 1;
u8 bus_id : 4;
u32 length : 12;
u32 slave_addr : 8;
} r;
};
/**
* struct amd_i2c_common - per bus/i2c adapter context, shared
* between the pci and the platform driver
* @eventval: MP2 event value set by the IRQ handler
* @mp2_dev: MP2 pci device this adapter is part of
* @msg: i2c message
* @cmd_completion: function called by the IRQ handler to signal
* the platform driver
* @reqcmd: requested i2c command type
* @cmd_success: set to true if the MP2 responded to a command with
* the expected status and response type
* @bus_id: bus index
* @i2c_speed: i2c bus speed determined by the slowest slave
* @dma_buf: if msg length > 32, holds the DMA buffer virtual address
* @dma_addr: if msg length > 32, holds the DMA buffer address
*/
struct amd_i2c_common {
union i2c_event eventval;
struct amd_mp2_dev *mp2_dev;
struct i2c_msg *msg;
void (*cmd_completion)(struct amd_i2c_common *i2c_common);
enum i2c_cmd reqcmd;
u8 cmd_success;
u8 bus_id;
enum speed_enum i2c_speed;
u8 *dma_buf;
dma_addr_t dma_addr;
#ifdef CONFIG_PM
int (*suspend)(struct amd_i2c_common *i2c_common);
int (*resume)(struct amd_i2c_common *i2c_common);
#endif /* CONFIG_PM */
};
/**
* struct amd_mp2_dev - per PCI device context
* @pci_dev: PCI driver node
* @busses: MP2 devices may have up to two busses,
* each bus corresponding to an i2c adapter
* @mmio: iommapped registers
* @c2p_lock: controls access to the C2P mailbox shared between
* the two adapters
* @c2p_lock_busid: id of the adapter which locked c2p_lock
*/
struct amd_mp2_dev {
struct pci_dev *pci_dev;
struct amd_i2c_common *busses[2];
void __iomem *mmio;
struct mutex c2p_lock;
u8 c2p_lock_busid;
unsigned int probed;
};
#define ndev_pdev(ndev) ((ndev)->pci_dev)
#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
#define work_amd_i2c_common(__work) \
container_of(__work, struct amd_i2c_common, work.work)
/* PCIe communication driver */
int amd_mp2_rw(struct amd_i2c_common *i2c_common, enum i2c_cmd reqcmd);
int amd_mp2_bus_enable_set(struct amd_i2c_common *i2c_common, bool enable);
void amd_mp2_process_event(struct amd_i2c_common *i2c_common);
void amd_mp2_rw_timeout(struct amd_i2c_common *i2c_common);
int amd_mp2_register_cb(struct amd_i2c_common *i2c_common);
int amd_mp2_unregister_cb(struct amd_i2c_common *i2c_common);
struct amd_mp2_dev *amd_mp2_find_device(void);
static inline void amd_mp2_pm_runtime_get(struct amd_mp2_dev *mp2_dev)
{
pm_runtime_get_sync(&mp2_dev->pci_dev->dev);
}
static inline void amd_mp2_pm_runtime_put(struct amd_mp2_dev *mp2_dev)
{
pm_runtime_mark_last_busy(&mp2_dev->pci_dev->dev);
pm_runtime_put_autosuspend(&mp2_dev->pci_dev->dev);
}
#endif
// SPDX-License-Identifier: GPL-2.0
/*
* i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
*
* Copyright (C) 2011 Weinmann Medical GmbH
* Author: Nikolaus Voss <n.voss@weinmann.de>
*
* Evolved from original work by:
* Copyright (C) 2004 Rick Bronson
* Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
*
* Borrowed heavily from original work by:
* Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include "i2c-at91.h"
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
{
return readl_relaxed(dev->base + reg);
}
void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
{
writel_relaxed(val, dev->base + reg);
}
void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
{
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK);
}
void at91_twi_irq_save(struct at91_twi_dev *dev)
{
dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK;
at91_disable_twi_interrupts(dev);
}
void at91_twi_irq_restore(struct at91_twi_dev *dev)
{
at91_twi_write(dev, AT91_TWI_IER, dev->imr);
}
void at91_init_twi_bus(struct at91_twi_dev *dev)
{
at91_disable_twi_interrupts(dev);
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
if (dev->slave_detected)
at91_init_twi_bus_slave(dev);
else
at91_init_twi_bus_master(dev);
}
static struct at91_twi_pdata at91rm9200_config = {
.clk_max_div = 5,
.clk_offset = 3,
.has_unre_flag = true,
.has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata at91sam9261_config = {
.clk_max_div = 5,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata at91sam9260_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
};
static const struct platform_device_id at91_twi_devtypes[] = {
{
.name = "i2c-at91rm9200",
.driver_data = (unsigned long) &at91rm9200_config,
}, {
.name = "i2c-at91sam9261",
.driver_data = (unsigned long) &at91sam9261_config,
}, {
.name = "i2c-at91sam9260",
.driver_data = (unsigned long) &at91sam9260_config,
}, {
.name = "i2c-at91sam9g20",
.driver_data = (unsigned long) &at91sam9g20_config,
}, {
.name = "i2c-at91sam9g10",
.driver_data = (unsigned long) &at91sam9g10_config,
}, {
/* sentinel */
}
};
#if defined(CONFIG_OF)
static struct at91_twi_pdata at91sam9x5_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata sama5d4_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = true,
};
static struct at91_twi_pdata sama5d2_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = true,
.has_alt_cmd = true,
.has_hold_field = true,
};
static const struct of_device_id atmel_twi_dt_ids[] = {
{
.compatible = "atmel,at91rm9200-i2c",
.data = &at91rm9200_config,
}, {
.compatible = "atmel,at91sam9260-i2c",
.data = &at91sam9260_config,
}, {
.compatible = "atmel,at91sam9261-i2c",
.data = &at91sam9261_config,
}, {
.compatible = "atmel,at91sam9g20-i2c",
.data = &at91sam9g20_config,
}, {
.compatible = "atmel,at91sam9g10-i2c",
.data = &at91sam9g10_config,
}, {
.compatible = "atmel,at91sam9x5-i2c",
.data = &at91sam9x5_config,
}, {
.compatible = "atmel,sama5d4-i2c",
.data = &sama5d4_config,
}, {
.compatible = "atmel,sama5d2-i2c",
.data = &sama5d2_config,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
#endif
static struct at91_twi_pdata *at91_twi_get_driver_data(
struct platform_device *pdev)
{
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
if (!match)
return NULL;
return (struct at91_twi_pdata *)match->data;
}
return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
}
static int at91_twi_probe(struct platform_device *pdev)
{
struct at91_twi_dev *dev;
struct resource *mem;
int rc;
u32 phy_addr;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->dev = &pdev->dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
return -ENODEV;
phy_addr = mem->start;
dev->pdata = at91_twi_get_driver_data(pdev);
if (!dev->pdata)
return -ENODEV;
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0)
return dev->irq;
platform_set_drvdata(pdev, dev);
dev->clk = devm_clk_get(dev->dev, NULL);
if (IS_ERR(dev->clk)) {
dev_err(dev->dev, "no clock defined\n");
return -ENODEV;
}
clk_prepare_enable(dev->clk);
snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.owner = THIS_MODULE;
dev->adapter.class = I2C_CLASS_DEPRECATED;
dev->adapter.dev.parent = dev->dev;
dev->adapter.nr = pdev->id;
dev->adapter.timeout = AT91_I2C_TIMEOUT;
dev->adapter.dev.of_node = pdev->dev.of_node;
dev->slave_detected = i2c_detect_slave_mode(&pdev->dev);
if (dev->slave_detected)
rc = at91_twi_probe_slave(pdev, phy_addr, dev);
else
rc = at91_twi_probe_master(pdev, phy_addr, dev);
if (rc)
return rc;
at91_init_twi_bus(dev);
pm_runtime_set_autosuspend_delay(dev->dev, AUTOSUSPEND_TIMEOUT);
pm_runtime_use_autosuspend(dev->dev);
pm_runtime_set_active(dev->dev);
pm_runtime_enable(dev->dev);
rc = i2c_add_numbered_adapter(&dev->adapter);
if (rc) {
clk_disable_unprepare(dev->clk);
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
return rc;
}
dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n",
at91_twi_read(dev, AT91_TWI_VER));
return 0;
}
static int at91_twi_remove(struct platform_device *pdev)
{
struct at91_twi_dev *dev = platform_get_drvdata(pdev);
i2c_del_adapter(&dev->adapter);
clk_disable_unprepare(dev->clk);
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
return 0;
}
#ifdef CONFIG_PM
static int at91_twi_runtime_suspend(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
clk_disable_unprepare(twi_dev->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int at91_twi_runtime_resume(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
pinctrl_pm_select_default_state(dev);
return clk_prepare_enable(twi_dev->clk);
}
static int at91_twi_suspend_noirq(struct device *dev)
{
if (!pm_runtime_status_suspended(dev))
at91_twi_runtime_suspend(dev);
return 0;
}
static int at91_twi_resume_noirq(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
int ret;
if (!pm_runtime_status_suspended(dev)) {
ret = at91_twi_runtime_resume(dev);
if (ret)
return ret;
}
pm_runtime_mark_last_busy(dev);
pm_request_autosuspend(dev);
at91_init_twi_bus(twi_dev);
return 0;
}
static const struct dev_pm_ops at91_twi_pm = {
.suspend_noirq = at91_twi_suspend_noirq,
.resume_noirq = at91_twi_resume_noirq,
.runtime_suspend = at91_twi_runtime_suspend,
.runtime_resume = at91_twi_runtime_resume,
};
#define at91_twi_pm_ops (&at91_twi_pm)
#else
#define at91_twi_pm_ops NULL
#endif
static struct platform_driver at91_twi_driver = {
.probe = at91_twi_probe,
.remove = at91_twi_remove,
.id_table = at91_twi_devtypes,
.driver = {
.name = "at91_i2c",
.of_match_table = of_match_ptr(atmel_twi_dt_ids),
.pm = at91_twi_pm_ops,
},
};
static int __init at91_twi_init(void)
{
return platform_driver_register(&at91_twi_driver);
}
static void __exit at91_twi_exit(void)
{
platform_driver_unregister(&at91_twi_driver);
}
subsys_initcall(at91_twi_init);
module_exit(at91_twi_exit);
MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:at91_i2c");
// SPDX-License-Identifier: GPL-2.0
/*
* i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
*
* Copyright (C) 2017 Juergen Fitschen <me@jue.yt>
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include "i2c-at91.h"
static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
{
struct at91_twi_dev *dev = dev_id;
const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
u8 value;
if (!irqstatus)
return IRQ_NONE;
/* slave address has been detected on I2C bus */
if (irqstatus & AT91_TWI_SVACC) {
if (status & AT91_TWI_SVREAD) {
i2c_slave_event(dev->slave,
I2C_SLAVE_READ_REQUESTED, &value);
writeb_relaxed(value, dev->base + AT91_TWI_THR);
at91_twi_write(dev, AT91_TWI_IER,
AT91_TWI_TXRDY | AT91_TWI_EOSACC);
} else {
i2c_slave_event(dev->slave,
I2C_SLAVE_WRITE_REQUESTED, &value);
at91_twi_write(dev, AT91_TWI_IER,
AT91_TWI_RXRDY | AT91_TWI_EOSACC);
}
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
}
/* byte transmitted to remote master */
if (irqstatus & AT91_TWI_TXRDY) {
i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, &value);
writeb_relaxed(value, dev->base + AT91_TWI_THR);
}
/* byte received from remote master */
if (irqstatus & AT91_TWI_RXRDY) {
value = readb_relaxed(dev->base + AT91_TWI_RHR);
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
}
/* master sent stop */
if (irqstatus & AT91_TWI_EOSACC) {
at91_twi_write(dev, AT91_TWI_IDR,
AT91_TWI_TXRDY | AT91_TWI_RXRDY | AT91_TWI_EOSACC);
at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &value);
}
return IRQ_HANDLED;
}
static int at91_reg_slave(struct i2c_client *slave)
{
struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter);
if (dev->slave)
return -EBUSY;
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
/* Make sure twi_clk doesn't get turned off! */
pm_runtime_get_sync(dev->dev);
dev->slave = slave;
dev->smr = AT91_TWI_SMR_SADR(slave->addr);
at91_init_twi_bus(dev);
at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
dev_info(dev->dev, "entered slave mode (ADR=%d)\n", slave->addr);
return 0;
}
static int at91_unreg_slave(struct i2c_client *slave)
{
struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter);
WARN_ON(!dev->slave);
dev_info(dev->dev, "leaving slave mode\n");
dev->slave = NULL;
dev->smr = 0;
at91_init_twi_bus(dev);
pm_runtime_put(dev->dev);
return 0;
}
static u32 at91_twi_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SLAVE | I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
static const struct i2c_algorithm at91_twi_algorithm_slave = {
.reg_slave = at91_reg_slave,
.unreg_slave = at91_unreg_slave,
.functionality = at91_twi_func,
};
int at91_twi_probe_slave(struct platform_device *pdev,
u32 phy_addr, struct at91_twi_dev *dev)
{
int rc;
rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt_slave,
0, dev_name(dev->dev), dev);
if (rc) {
dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
return rc;
}
dev->adapter.algo = &at91_twi_algorithm_slave;
return 0;
}
void at91_init_twi_bus_slave(struct at91_twi_dev *dev)
{
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS);
if (dev->slave_detected && dev->smr) {
at91_twi_write(dev, AT91_TWI_SMR, dev->smr);
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVEN);
}
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
*
* Copyright (C) 2011 Weinmann Medical GmbH
* Author: Nikolaus Voss <n.voss@weinmann.de>
*
* Evolved from original work by:
* Copyright (C) 2004 Rick Bronson
* Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
*
* Borrowed heavily from original work by:
* Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
*/
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/i2c.h>
#include <linux/platform_data/dma-atmel.h>
#include <linux/platform_device.h>
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
#define AUTOSUSPEND_TIMEOUT 2000
#define AT91_I2C_MAX_ALT_CMD_DATA_SIZE 256
/* AT91 TWI register definitions */
#define AT91_TWI_CR 0x0000 /* Control Register */
#define AT91_TWI_START BIT(0) /* Send a Start Condition */
#define AT91_TWI_STOP BIT(1) /* Send a Stop Condition */
#define AT91_TWI_MSEN BIT(2) /* Master Transfer Enable */
#define AT91_TWI_MSDIS BIT(3) /* Master Transfer Disable */
#define AT91_TWI_SVEN BIT(4) /* Slave Transfer Enable */
#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */
#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */
#define AT91_TWI_SWRST BIT(7) /* Software Reset */
#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */
#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */
#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */
#define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */
#define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */
#define AT91_TWI_FIFOEN BIT(28) /* FIFO Enable */
#define AT91_TWI_FIFODIS BIT(29) /* FIFO Disable */
#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
#define AT91_TWI_MREAD BIT(12) /* Master Read Direction */
#define AT91_TWI_SMR 0x0008 /* Slave Mode Register */
#define AT91_TWI_SMR_SADR_MAX 0x007f
#define AT91_TWI_SMR_SADR(x) (((x) & AT91_TWI_SMR_SADR_MAX) << 16)
#define AT91_TWI_IADR 0x000c /* Internal Address Register */
#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
#define AT91_TWI_CWGR_HOLD_MAX 0x1f
#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
#define AT91_TWI_SR 0x0020 /* Status Register */
#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
#define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */
#define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */
#define AT91_TWI_SVREAD BIT(3) /* Slave Read */
#define AT91_TWI_SVACC BIT(4) /* Slave Access */
#define AT91_TWI_OVRE BIT(6) /* Overrun Error */
#define AT91_TWI_UNRE BIT(7) /* Underrun Error */
#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */
#define AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */
#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */
#define AT91_TWI_INT_MASK \
(AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
| AT91_TWI_SVACC | AT91_TWI_EOSACC)
#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */
#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
#define AT91_TWI_ACR_DIR BIT(8)
#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */
#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0)
#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0)
#define AT91_TWI_FMR_RXRDYM(mode) (((mode) & 0x3) << 4)
#define AT91_TWI_FMR_RXRDYM_MASK (0x3 << 4)
#define AT91_TWI_ONE_DATA 0x0
#define AT91_TWI_TWO_DATA 0x1
#define AT91_TWI_FOUR_DATA 0x2
#define AT91_TWI_FLR 0x0054 /* FIFO Level Register */
#define AT91_TWI_FSR 0x0060 /* FIFO Status Register */
#define AT91_TWI_FIER 0x0064 /* FIFO Interrupt Enable Register */
#define AT91_TWI_FIDR 0x0068 /* FIFO Interrupt Disable Register */
#define AT91_TWI_FIMR 0x006c /* FIFO Interrupt Mask Register */
#define AT91_TWI_VER 0x00fc /* Version Register */
struct at91_twi_pdata {
unsigned clk_max_div;
unsigned clk_offset;
bool has_unre_flag;
bool has_alt_cmd;
bool has_hold_field;
struct at_dma_slave dma_slave;
};
struct at91_twi_dma {
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct scatterlist sg[2];
struct dma_async_tx_descriptor *data_desc;
enum dma_data_direction direction;
bool buf_mapped;
bool xfer_in_progress;
};
struct at91_twi_dev {
struct device *dev;
void __iomem *base;
struct completion cmd_complete;
struct clk *clk;
u8 *buf;
size_t buf_len;
struct i2c_msg *msg;
int irq;
unsigned imr;
unsigned transfer_status;
struct i2c_adapter adapter;
unsigned twi_cwgr_reg;
struct at91_twi_pdata *pdata;
bool use_dma;
bool use_alt_cmd;
bool recv_len_abort;
u32 fifo_size;
struct at91_twi_dma dma;
bool slave_detected;
#ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL
unsigned smr;
struct i2c_client *slave;
#endif
};
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg);
void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val);
void at91_disable_twi_interrupts(struct at91_twi_dev *dev);
void at91_twi_irq_save(struct at91_twi_dev *dev);
void at91_twi_irq_restore(struct at91_twi_dev *dev);
void at91_init_twi_bus(struct at91_twi_dev *dev);
void at91_init_twi_bus_master(struct at91_twi_dev *dev);
int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr,
struct at91_twi_dev *dev);
#ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL
void at91_init_twi_bus_slave(struct at91_twi_dev *dev);
int at91_twi_probe_slave(struct platform_device *pdev, u32 phy_addr,
struct at91_twi_dev *dev);
#else
static inline void at91_init_twi_bus_slave(struct at91_twi_dev *dev) {}
static inline int at91_twi_probe_slave(struct platform_device *pdev,
u32 phy_addr, struct at91_twi_dev *dev)
{
return -EINVAL;
}
#endif
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
* @adapter: core i2c abstraction * @adapter: core i2c abstraction
* @i2c_clk: clock reference for i2c input clock * @i2c_clk: clock reference for i2c input clock
* @bus_clk_rate: current i2c bus clock rate * @bus_clk_rate: current i2c bus clock rate
* @last: a flag indicating is this is last message in transfer
*/ */
struct axxia_i2c_dev { struct axxia_i2c_dev {
void __iomem *base; void __iomem *base;
...@@ -112,6 +113,7 @@ struct axxia_i2c_dev { ...@@ -112,6 +113,7 @@ struct axxia_i2c_dev {
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct clk *i2c_clk; struct clk *i2c_clk;
u32 bus_clk_rate; u32 bus_clk_rate;
bool last;
}; };
static void i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask) static void i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask)
...@@ -324,15 +326,14 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev) ...@@ -324,15 +326,14 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
/* Stop completed */ /* Stop completed */
i2c_int_disable(idev, ~MST_STATUS_TSS); i2c_int_disable(idev, ~MST_STATUS_TSS);
complete(&idev->msg_complete); complete(&idev->msg_complete);
} else if (status & MST_STATUS_SNS) { } else if (status & (MST_STATUS_SNS | MST_STATUS_SS)) {
/* Transfer done */ /* Transfer done */
i2c_int_disable(idev, ~MST_STATUS_TSS); int mask = idev->last ? ~0 : ~MST_STATUS_TSS;
i2c_int_disable(idev, mask);
if (i2c_m_rd(idev->msg_r) && idev->msg_xfrd_r < idev->msg_r->len) if (i2c_m_rd(idev->msg_r) && idev->msg_xfrd_r < idev->msg_r->len)
axxia_i2c_empty_rx_fifo(idev); axxia_i2c_empty_rx_fifo(idev);
complete(&idev->msg_complete); complete(&idev->msg_complete);
} else if (status & MST_STATUS_SS) {
/* Auto/Sequence transfer done */
complete(&idev->msg_complete);
} else if (status & MST_STATUS_TSS) { } else if (status & MST_STATUS_TSS) {
/* Transfer timeout */ /* Transfer timeout */
idev->msg_err = -ETIMEDOUT; idev->msg_err = -ETIMEDOUT;
...@@ -405,6 +406,7 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[]) ...@@ -405,6 +406,7 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[])
idev->msg_r = &msgs[1]; idev->msg_r = &msgs[1];
idev->msg_xfrd = 0; idev->msg_xfrd = 0;
idev->msg_xfrd_r = 0; idev->msg_xfrd_r = 0;
idev->last = true;
axxia_i2c_fill_tx_fifo(idev); axxia_i2c_fill_tx_fifo(idev);
writel(CMD_SEQUENCE, idev->base + MST_COMMAND); writel(CMD_SEQUENCE, idev->base + MST_COMMAND);
...@@ -415,10 +417,6 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[]) ...@@ -415,10 +417,6 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[])
time_left = wait_for_completion_timeout(&idev->msg_complete, time_left = wait_for_completion_timeout(&idev->msg_complete,
I2C_XFER_TIMEOUT); I2C_XFER_TIMEOUT);
i2c_int_disable(idev, int_mask);
axxia_i2c_empty_rx_fifo(idev);
if (idev->msg_err == -ENXIO) { if (idev->msg_err == -ENXIO) {
if (axxia_i2c_handle_seq_nak(idev)) if (axxia_i2c_handle_seq_nak(idev))
axxia_i2c_init(idev); axxia_i2c_init(idev);
...@@ -438,9 +436,10 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[]) ...@@ -438,9 +436,10 @@ static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[])
return idev->msg_err; return idev->msg_err;
} }
static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg,
bool last)
{ {
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS; u32 int_mask = MST_STATUS_ERR;
u32 rx_xfer, tx_xfer; u32 rx_xfer, tx_xfer;
unsigned long time_left; unsigned long time_left;
unsigned int wt_value; unsigned int wt_value;
...@@ -449,6 +448,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) ...@@ -449,6 +448,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
idev->msg_r = msg; idev->msg_r = msg;
idev->msg_xfrd = 0; idev->msg_xfrd = 0;
idev->msg_xfrd_r = 0; idev->msg_xfrd_r = 0;
idev->last = last;
reinit_completion(&idev->msg_complete); reinit_completion(&idev->msg_complete);
axxia_i2c_set_addr(idev, msg); axxia_i2c_set_addr(idev, msg);
...@@ -478,8 +478,13 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) ...@@ -478,8 +478,13 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
if (idev->msg_err) if (idev->msg_err)
goto out; goto out;
/* Start manual mode */ if (!last) {
writel(CMD_MANUAL, idev->base + MST_COMMAND); writel(CMD_MANUAL, idev->base + MST_COMMAND);
int_mask |= MST_STATUS_SNS;
} else {
writel(CMD_AUTO, idev->base + MST_COMMAND);
int_mask |= MST_STATUS_SS;
}
writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL); writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL);
...@@ -507,28 +512,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) ...@@ -507,28 +512,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
return idev->msg_err; return idev->msg_err;
} }
static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
{
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC | MST_STATUS_TSS;
unsigned long time_left;
reinit_completion(&idev->msg_complete);
/* Issue stop */
writel(0xb, idev->base + MST_COMMAND);
i2c_int_enable(idev, int_mask);
time_left = wait_for_completion_timeout(&idev->msg_complete,
I2C_STOP_TIMEOUT);
i2c_int_disable(idev, int_mask);
if (time_left == 0)
return -ETIMEDOUT;
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
dev_warn(idev->dev, "busy after stop\n");
return 0;
}
/* This function checks if the msgs[] array contains messages compatible with /* This function checks if the msgs[] array contains messages compatible with
* Sequence mode of operation. This mode assumes there will be exactly one * Sequence mode of operation. This mode assumes there will be exactly one
* write of non-zero length followed by exactly one read of non-zero length, * write of non-zero length followed by exactly one read of non-zero length,
...@@ -558,9 +541,7 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -558,9 +541,7 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
i2c_int_enable(idev, MST_STATUS_TSS); i2c_int_enable(idev, MST_STATUS_TSS);
for (i = 0; ret == 0 && i < num; ++i) for (i = 0; ret == 0 && i < num; ++i)
ret = axxia_i2c_xfer_msg(idev, &msgs[i]); ret = axxia_i2c_xfer_msg(idev, &msgs[i], i == (num - 1));
axxia_i2c_stop(idev);
return ret ? : i; return ret ? : i;
} }
......
This diff is collapsed.
...@@ -165,7 +165,6 @@ static const struct bsc_clk_param bsc_clk[] = { ...@@ -165,7 +165,6 @@ static const struct bsc_clk_param bsc_clk[] = {
struct brcmstb_i2c_dev { struct brcmstb_i2c_dev {
struct device *device; struct device *device;
void __iomem *base; void __iomem *base;
void __iomem *irq_base;
int irq; int irq;
struct bsc_regs *bsc_regmap; struct bsc_regs *bsc_regmap;
struct i2c_adapter adapter; struct i2c_adapter adapter;
......
...@@ -251,13 +251,27 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) ...@@ -251,13 +251,27 @@ 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 ret;
if (IS_ERR(dev->clk)) if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk); return PTR_ERR(dev->clk);
if (prepare) if (prepare) {
return clk_prepare_enable(dev->clk); /* Optional interface clock */
ret = clk_prepare_enable(dev->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(dev->clk);
if (ret)
clk_disable_unprepare(dev->pclk);
return ret;
}
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
clk_disable_unprepare(dev->pclk);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk); EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk);
......
...@@ -177,6 +177,7 @@ ...@@ -177,6 +177,7 @@
* @base: IO registers pointer * @base: IO registers pointer
* @cmd_complete: tx completion indicator * @cmd_complete: tx completion indicator
* @clk: input reference clock * @clk: input reference clock
* @pclk: clock required to access the registers
* @slave: represent an I2C slave device * @slave: represent an I2C slave device
* @cmd_err: run time hadware error code * @cmd_err: run time hadware error code
* @msgs: points to an array of messages currently being transferred * @msgs: points to an array of messages currently being transferred
...@@ -227,6 +228,7 @@ struct dw_i2c_dev { ...@@ -227,6 +228,7 @@ struct dw_i2c_dev {
void __iomem *ext; void __iomem *ext;
struct completion cmd_complete; struct completion cmd_complete;
struct clk *clk; struct clk *clk;
struct clk *pclk;
struct reset_control *rst; struct reset_control *rst;
struct i2c_client *slave; struct i2c_client *slave;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
......
...@@ -344,6 +344,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -344,6 +344,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
else else
i2c_dw_configure_master(dev); i2c_dw_configure_master(dev);
/* Optional interface clock */
dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
if (IS_ERR(dev->pclk))
return PTR_ERR(dev->pclk);
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; u64 clk_khz;
......
...@@ -413,6 +413,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) ...@@ -413,6 +413,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
else
bit_data->can_do_atomic = true;
bit_data->setsda = i2c_gpio_setsda_val; bit_data->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val; bit_data->setscl = i2c_gpio_setscl_val;
......
...@@ -639,8 +639,7 @@ static int lpi2c_imx_remove(struct platform_device *pdev) ...@@ -639,8 +639,7 @@ static int lpi2c_imx_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
static int lpi2c_runtime_suspend(struct device *dev)
{ {
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
...@@ -650,7 +649,7 @@ static int lpi2c_runtime_suspend(struct device *dev) ...@@ -650,7 +649,7 @@ static int lpi2c_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int lpi2c_runtime_resume(struct device *dev) static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
{ {
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
int ret; int ret;
...@@ -671,10 +670,6 @@ static const struct dev_pm_ops lpi2c_pm_ops = { ...@@ -671,10 +670,6 @@ static const struct dev_pm_ops lpi2c_pm_ops = {
SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend, SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
lpi2c_runtime_resume, NULL) lpi2c_runtime_resume, NULL)
}; };
#define IMX_LPI2C_PM (&lpi2c_pm_ops)
#else
#define IMX_LPI2C_PM NULL
#endif
static struct platform_driver lpi2c_imx_driver = { static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe, .probe = lpi2c_imx_probe,
...@@ -682,7 +677,7 @@ static struct platform_driver lpi2c_imx_driver = { ...@@ -682,7 +677,7 @@ static struct platform_driver lpi2c_imx_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match, .of_match_table = lpi2c_imx_of_match,
.pm = IMX_LPI2C_PM, .pm = &lpi2c_pm_ops,
}, },
}; };
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/acpi.h>
/* SCH SMBus address offsets */ /* SCH SMBus address offsets */
#define SMBHSTCNT (0 + sch_smba) #define SMBHSTCNT (0 + sch_smba)
......
This diff is collapsed.
...@@ -1070,8 +1070,7 @@ static int nmk_i2c_remove(struct amba_device *adev) ...@@ -1070,8 +1070,7 @@ static int nmk_i2c_remove(struct amba_device *adev)
/* disable the controller */ /* disable the controller */
i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
if (res) release_mem_region(res->start, resource_size(res));
release_mem_region(res->start, resource_size(res));
return 0; return 0;
} }
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#define OCORES_FLAG_POLL BIT(0)
/* /*
* 'process_lock' exists because ocores_process() and ocores_process_timeout() * 'process_lock' exists because ocores_process() and ocores_process_timeout()
* can't run in parallel. * can't run in parallel.
...@@ -37,7 +35,6 @@ struct ocores_i2c { ...@@ -37,7 +35,6 @@ struct ocores_i2c {
int iobase; int iobase;
u32 reg_shift; u32 reg_shift;
u32 reg_io_width; u32 reg_io_width;
unsigned long flags;
wait_queue_head_t wait; wait_queue_head_t wait;
struct i2c_adapter adap; struct i2c_adapter adap;
struct i2c_msg *msg; struct i2c_msg *msg;
...@@ -403,11 +400,7 @@ static int ocores_xfer_polling(struct i2c_adapter *adap, ...@@ -403,11 +400,7 @@ static int ocores_xfer_polling(struct i2c_adapter *adap,
static int ocores_xfer(struct i2c_adapter *adap, static int ocores_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msgs, int num)
{ {
struct ocores_i2c *i2c = i2c_get_adapdata(adap); return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, false);
if (i2c->flags & OCORES_FLAG_POLL)
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
} }
static int ocores_init(struct device *dev, struct ocores_i2c *i2c) static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
...@@ -447,8 +440,9 @@ static u32 ocores_func(struct i2c_adapter *adap) ...@@ -447,8 +440,9 @@ static u32 ocores_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} }
static const struct i2c_algorithm ocores_algorithm = { static struct i2c_algorithm ocores_algorithm = {
.master_xfer = ocores_xfer, .master_xfer = ocores_xfer,
.master_xfer_atomic = ocores_xfer_polling,
.functionality = ocores_func, .functionality = ocores_func,
}; };
...@@ -673,13 +667,13 @@ static int ocores_i2c_probe(struct platform_device *pdev) ...@@ -673,13 +667,13 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) { if (irq == -ENXIO) {
i2c->flags |= OCORES_FLAG_POLL; ocores_algorithm.master_xfer = ocores_xfer_polling;
} else { } else {
if (irq < 0) if (irq < 0)
return irq; return irq;
} }
if (!(i2c->flags & OCORES_FLAG_POLL)) { if (ocores_algorithm.master_xfer != ocores_xfer_polling) {
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
pdev->name, i2c); pdev->name, i2c);
if (ret) { if (ret) {
......
...@@ -269,6 +269,8 @@ static const u8 reg_map_ip_v2[] = { ...@@ -269,6 +269,8 @@ static const u8 reg_map_ip_v2[] = {
[OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
}; };
static int omap_i2c_xfer_data(struct omap_i2c_dev *omap);
static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap,
int reg, u16 val) int reg, u16 val)
{ {
...@@ -648,15 +650,28 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx) ...@@ -648,15 +650,28 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx)
(1000 * omap->speed / 8); (1000 * omap->speed / 8);
} }
static void omap_i2c_wait(struct omap_i2c_dev *omap)
{
u16 stat;
u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
int count = 0;
do {
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
count++;
} while (!(stat & mask) && count < 5);
}
/* /*
* Low level master read/write transaction. * Low level master read/write transaction.
*/ */
static int omap_i2c_xfer_msg(struct i2c_adapter *adap, static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
struct i2c_msg *msg, int stop) struct i2c_msg *msg, int stop, bool polling)
{ {
struct omap_i2c_dev *omap = i2c_get_adapdata(adap); struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
unsigned long timeout; unsigned long timeout;
u16 w; u16 w;
int ret;
dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", dev_dbg(omap->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);
...@@ -680,7 +695,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -680,7 +695,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w);
reinit_completion(&omap->cmd_complete); if (!polling)
reinit_completion(&omap->cmd_complete);
omap->cmd_err = 0; omap->cmd_err = 0;
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
...@@ -732,8 +748,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -732,8 +748,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
* REVISIT: We should abort the transfer on signals, but the bus goes * REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it. * into arbitration and we're currently unable to recover from it.
*/ */
timeout = wait_for_completion_timeout(&omap->cmd_complete, if (!polling) {
OMAP_I2C_TIMEOUT); timeout = wait_for_completion_timeout(&omap->cmd_complete,
OMAP_I2C_TIMEOUT);
} else {
do {
omap_i2c_wait(omap);
ret = omap_i2c_xfer_data(omap);
} while (ret == -EAGAIN);
timeout = !ret;
}
if (timeout == 0) { if (timeout == 0) {
dev_err(omap->dev, "controller timed out\n"); dev_err(omap->dev, "controller timed out\n");
omap_i2c_reset(omap); omap_i2c_reset(omap);
...@@ -772,7 +798,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -772,7 +798,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
* to do the work during IRQ processing. * to do the work during IRQ processing.
*/ */
static int static int
omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num,
bool polling)
{ {
struct omap_i2c_dev *omap = i2c_get_adapdata(adap); struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
int i; int i;
...@@ -794,7 +821,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -794,7 +821,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
omap->set_mpu_wkup_lat(omap->dev, omap->latency); omap->set_mpu_wkup_lat(omap->dev, omap->latency);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)),
polling);
if (r != 0) if (r != 0)
break; break;
} }
...@@ -813,6 +841,18 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -813,6 +841,18 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return r; return r;
} }
static int
omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
return omap_i2c_xfer_common(adap, msgs, num, false);
}
static int
omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
return omap_i2c_xfer_common(adap, msgs, num, true);
}
static u32 static u32
omap_i2c_func(struct i2c_adapter *adap) omap_i2c_func(struct i2c_adapter *adap)
{ {
...@@ -1035,10 +1075,8 @@ omap_i2c_isr(int irq, void *dev_id) ...@@ -1035,10 +1075,8 @@ omap_i2c_isr(int irq, void *dev_id)
return ret; return ret;
} }
static irqreturn_t static int omap_i2c_xfer_data(struct omap_i2c_dev *omap)
omap_i2c_isr_thread(int this_irq, void *dev_id)
{ {
struct omap_i2c_dev *omap = dev_id;
u16 bits; u16 bits;
u16 stat; u16 stat;
int err = 0, count = 0; int err = 0, count = 0;
...@@ -1056,7 +1094,8 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) ...@@ -1056,7 +1094,8 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
if (!stat) { if (!stat) {
/* my work here is done */ /* my work here is done */
goto out; err = -EAGAIN;
break;
} }
dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat);
...@@ -1165,14 +1204,25 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) ...@@ -1165,14 +1204,25 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
} }
} while (stat); } while (stat);
omap_i2c_complete_cmd(omap, err); return err;
}
static irqreturn_t
omap_i2c_isr_thread(int this_irq, void *dev_id)
{
int ret;
struct omap_i2c_dev *omap = dev_id;
ret = omap_i2c_xfer_data(omap);
if (ret != -EAGAIN)
omap_i2c_complete_cmd(omap, ret);
out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static const struct i2c_algorithm omap_i2c_algo = { static const struct i2c_algorithm omap_i2c_algo = {
.master_xfer = omap_i2c_xfer, .master_xfer = omap_i2c_xfer_irq,
.master_xfer_atomic = omap_i2c_xfer_polling,
.functionality = omap_i2c_func, .functionality = omap_i2c_func,
}; };
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800 ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
AMD Hudson-2, ML, CZ AMD Hudson-2, ML, CZ
Hygon CZ
SMSC Victory66 SMSC Victory66
Note: we assume there can only be one device, with one or more Note: we assume there can only be one device, with one or more
...@@ -289,7 +290,9 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -289,7 +290,9 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
PIIX4_dev->revision >= 0x41) || PIIX4_dev->revision >= 0x41) ||
(PIIX4_dev->vendor == PCI_VENDOR_ID_AMD && (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS && PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
PIIX4_dev->revision >= 0x49)) PIIX4_dev->revision >= 0x49) ||
(PIIX4_dev->vendor == PCI_VENDOR_ID_HYGON &&
PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS))
smb_en = 0x00; smb_en = 0x00;
else else
smb_en = (aux) ? 0x28 : 0x2c; smb_en = (aux) ? 0x28 : 0x2c;
...@@ -361,7 +364,8 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -361,7 +364,8 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
piix4_smba, i2ccfg >> 4); piix4_smba, i2ccfg >> 4);
/* Find which register is used for port selection */ /* Find which register is used for port selection */
if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD) { if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD ||
PIIX4_dev->vendor == PCI_VENDOR_ID_HYGON) {
switch (PIIX4_dev->device) { switch (PIIX4_dev->device) {
case PCI_DEVICE_ID_AMD_KERNCZ_SMBUS: case PCI_DEVICE_ID_AMD_KERNCZ_SMBUS:
piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_KERNCZ; piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_KERNCZ;
...@@ -794,6 +798,7 @@ static const struct pci_device_id piix4_ids[] = { ...@@ -794,6 +798,7 @@ static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) }, PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
...@@ -904,11 +909,13 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -904,11 +909,13 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
if ((dev->vendor == PCI_VENDOR_ID_ATI && if ((dev->vendor == PCI_VENDOR_ID_ATI &&
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
dev->revision >= 0x40) || dev->revision >= 0x40) ||
dev->vendor == PCI_VENDOR_ID_AMD) { dev->vendor == PCI_VENDOR_ID_AMD ||
dev->vendor == PCI_VENDOR_ID_HYGON) {
bool notify_imc = false; bool notify_imc = false;
is_sb800 = true; is_sb800 = true;
if (dev->vendor == PCI_VENDOR_ID_AMD && if ((dev->vendor == PCI_VENDOR_ID_AMD ||
dev->vendor == PCI_VENDOR_ID_HYGON) &&
dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) { dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) {
u8 imc; u8 imc;
......
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
/* ICFBSCR */ /* ICFBSCR */
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */ #define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
#define RCAR_MIN_DMA_LEN 8
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_DATA (MDBS | MIE)
...@@ -398,7 +399,7 @@ static void rcar_i2c_dma_callback(void *data) ...@@ -398,7 +399,7 @@ static void rcar_i2c_dma_callback(void *data)
rcar_i2c_dma_unmap(priv); rcar_i2c_dma_unmap(priv);
} }
static void rcar_i2c_dma(struct rcar_i2c_priv *priv) static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
{ {
struct device *dev = rcar_i2c_priv_to_dev(priv); struct device *dev = rcar_i2c_priv_to_dev(priv);
struct i2c_msg *msg = priv->msg; struct i2c_msg *msg = priv->msg;
...@@ -412,9 +413,9 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) ...@@ -412,9 +413,9 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
int len; int len;
/* Do various checks to see if DMA is feasible at all */ /* Do various checks to see if DMA is feasible at all */
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) || if (IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
(read && priv->flags & ID_P_NO_RXDMA)) !(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA))
return; return false;
if (read) { if (read) {
/* /*
...@@ -434,7 +435,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) ...@@ -434,7 +435,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
dma_addr = dma_map_single(chan->device->dev, buf, len, dir); dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
if (dma_mapping_error(chan->device->dev, dma_addr)) { if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(dev, "dma map failed, using PIO\n"); dev_dbg(dev, "dma map failed, using PIO\n");
return; return false;
} }
sg_dma_len(&priv->sg) = len; sg_dma_len(&priv->sg) = len;
...@@ -448,7 +449,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) ...@@ -448,7 +449,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
if (!txdesc) { if (!txdesc) {
dev_dbg(dev, "dma prep slave sg failed, using PIO\n"); dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
rcar_i2c_cleanup_dma(priv); rcar_i2c_cleanup_dma(priv);
return; return false;
} }
txdesc->callback = rcar_i2c_dma_callback; txdesc->callback = rcar_i2c_dma_callback;
...@@ -458,7 +459,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) ...@@ -458,7 +459,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
if (dma_submit_error(cookie)) { if (dma_submit_error(cookie)) {
dev_dbg(dev, "submitting dma failed, using PIO\n"); dev_dbg(dev, "submitting dma failed, using PIO\n");
rcar_i2c_cleanup_dma(priv); rcar_i2c_cleanup_dma(priv);
return; return false;
} }
/* Enable DMA Master Received/Transmitted */ /* Enable DMA Master Received/Transmitted */
...@@ -468,6 +469,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) ...@@ -468,6 +469,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICDMAER, TMDMAE); rcar_i2c_write(priv, ICDMAER, TMDMAE);
dma_async_issue_pending(chan); dma_async_issue_pending(chan);
return true;
} }
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
...@@ -478,6 +480,10 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) ...@@ -478,6 +480,10 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
if (!(msr & MDE)) if (!(msr & MDE))
return; return;
/* Check if DMA can be enabled and take over */
if (priv->pos == 1 && rcar_i2c_dma(priv))
return;
if (priv->pos < msg->len) { if (priv->pos < msg->len) {
/* /*
* Prepare next data to ICRXTX register. * Prepare next data to ICRXTX register.
...@@ -488,13 +494,6 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) ...@@ -488,13 +494,6 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
*/ */
rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]); rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
priv->pos++; priv->pos++;
/*
* Try to use DMA to transmit the rest of the data if
* address transfer phase just finished.
*/
if (msr & MAT)
rcar_i2c_dma(priv);
} else { } else {
/* /*
* The last data was pushed to ICRXTX on _PREV_ empty irq. * The last data was pushed to ICRXTX on _PREV_ empty irq.
...@@ -921,6 +920,9 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -921,6 +920,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
struct i2c_timings i2c_t; struct i2c_timings i2c_t;
int irq, ret; int irq, ret;
/* Otherwise logic will break because some bytes must always use PIO */
BUILD_BUG_ON_MSG(RCAR_MIN_DMA_LEN < 3, "Invalid min DMA length");
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#define RIIC_ICCR1 0x00 #define RIIC_ICCR1 0x00
#define RIIC_ICCR2 0x04 #define RIIC_ICCR2 0x04
...@@ -112,12 +113,10 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -112,12 +113,10 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{ {
struct riic_dev *riic = i2c_get_adapdata(adap); struct riic_dev *riic = i2c_get_adapdata(adap);
unsigned long time_left; unsigned long time_left;
int i, ret; int i;
u8 start_bit; u8 start_bit;
ret = clk_prepare_enable(riic->clk); pm_runtime_get_sync(adap->dev.parent);
if (ret)
return ret;
if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) { if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) {
riic->err = -EBUSY; riic->err = -EBUSY;
...@@ -150,7 +149,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -150,7 +149,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
} }
out: out:
clk_disable_unprepare(riic->clk); pm_runtime_put(adap->dev.parent);
return riic->err ?: num; return riic->err ?: num;
} }
...@@ -281,20 +280,18 @@ static const struct i2c_algorithm riic_algo = { ...@@ -281,20 +280,18 @@ static const struct i2c_algorithm riic_algo = {
static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
{ {
int ret; int ret = 0;
unsigned long rate; unsigned long rate;
int total_ticks, cks, brl, brh; int total_ticks, cks, brl, brh;
ret = clk_prepare_enable(riic->clk); pm_runtime_get_sync(riic->adapter.dev.parent);
if (ret)
return ret;
if (t->bus_freq_hz > 400000) { if (t->bus_freq_hz > 400000) {
dev_err(&riic->adapter.dev, dev_err(&riic->adapter.dev,
"unsupported bus speed (%dHz). 400000 max\n", "unsupported bus speed (%dHz). 400000 max\n",
t->bus_freq_hz); t->bus_freq_hz);
clk_disable_unprepare(riic->clk); ret = -EINVAL;
return -EINVAL; goto out;
} }
rate = clk_get_rate(riic->clk); rate = clk_get_rate(riic->clk);
...@@ -332,8 +329,8 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) ...@@ -332,8 +329,8 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
if (brl > (0x1F + 3)) { if (brl > (0x1F + 3)) {
dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n", dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n",
(unsigned long)t->bus_freq_hz); (unsigned long)t->bus_freq_hz);
clk_disable_unprepare(riic->clk); ret = -EINVAL;
return -EINVAL; goto out;
} }
brh = total_ticks - brl; brh = total_ticks - brl;
...@@ -378,9 +375,9 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) ...@@ -378,9 +375,9 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1); riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
clk_disable_unprepare(riic->clk); out:
pm_runtime_put(riic->adapter.dev.parent);
return 0; return ret;
} }
static struct riic_irq_desc riic_irqs[] = { static struct riic_irq_desc riic_irqs[] = {
...@@ -439,28 +436,36 @@ static int riic_i2c_probe(struct platform_device *pdev) ...@@ -439,28 +436,36 @@ static int riic_i2c_probe(struct platform_device *pdev)
i2c_parse_fw_timings(&pdev->dev, &i2c_t, true); i2c_parse_fw_timings(&pdev->dev, &i2c_t, true);
pm_runtime_enable(&pdev->dev);
ret = riic_init_hw(riic, &i2c_t); ret = riic_init_hw(riic, &i2c_t);
if (ret) if (ret)
return ret; goto out;
ret = i2c_add_adapter(adap); ret = i2c_add_adapter(adap);
if (ret) if (ret)
return ret; goto out;
platform_set_drvdata(pdev, riic); platform_set_drvdata(pdev, riic);
dev_info(&pdev->dev, "registered with %dHz bus speed\n", dev_info(&pdev->dev, "registered with %dHz bus speed\n",
i2c_t.bus_freq_hz); i2c_t.bus_freq_hz);
return 0; return 0;
out:
pm_runtime_disable(&pdev->dev);
return ret;
} }
static int riic_i2c_remove(struct platform_device *pdev) static int riic_i2c_remove(struct platform_device *pdev)
{ {
struct riic_dev *riic = platform_get_drvdata(pdev); struct riic_dev *riic = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
writeb(0, riic->base + RIIC_ICIER); writeb(0, riic->base + RIIC_ICIER);
pm_runtime_put(&pdev->dev);
i2c_del_adapter(&riic->adapter); i2c_del_adapter(&riic->adapter);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
} }
......
...@@ -476,8 +476,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, ...@@ -476,8 +476,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
list_add_tail(&v->node, list_add_tail(&v->node,
&solutions); &solutions);
break;
} }
} }
if (p_prev == p)
break;
} }
} }
......
...@@ -328,12 +328,6 @@ static int stu300_start_and_await_event(struct stu300_dev *dev, ...@@ -328,12 +328,6 @@ static int stu300_start_and_await_event(struct stu300_dev *dev,
{ {
int ret; int ret;
if (unlikely(irqs_disabled())) {
/* TODO: implement polling for this case if need be. */
WARN(1, "irqs are disabled, cannot poll for event\n");
return -EIO;
}
/* Lock command issue, fill in an event we wait for */ /* Lock command issue, fill in an event we wait for */
spin_lock_irq(&dev->cmd_issue_lock); spin_lock_irq(&dev->cmd_issue_lock);
init_completion(&dev->cmd_complete); init_completion(&dev->cmd_complete);
...@@ -380,13 +374,6 @@ static int stu300_await_event(struct stu300_dev *dev, ...@@ -380,13 +374,6 @@ static int stu300_await_event(struct stu300_dev *dev,
{ {
int ret; int ret;
if (unlikely(irqs_disabled())) {
/* TODO: implement polling for this case if need be. */
dev_err(&dev->pdev->dev, "irqs are disabled on this "
"system!\n");
return -EIO;
}
/* Is it already here? */ /* Is it already here? */
spin_lock_irq(&dev->cmd_issue_lock); spin_lock_irq(&dev->cmd_issue_lock);
dev->cmd_err = STU300_ERROR_NONE; dev->cmd_err = STU300_ERROR_NONE;
...@@ -846,6 +833,13 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -846,6 +833,13 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return num; return num;
} }
static int stu300_xfer_todo(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
/* TODO: implement polling for this case if need be. */
WARN(1, "%s: atomic transfers not implemented\n", dev_name(&adap->dev));
return -EOPNOTSUPP;
}
static u32 stu300_func(struct i2c_adapter *adap) static u32 stu300_func(struct i2c_adapter *adap)
{ {
/* This is the simplest thing you can think of... */ /* This is the simplest thing you can think of... */
...@@ -853,8 +847,9 @@ static u32 stu300_func(struct i2c_adapter *adap) ...@@ -853,8 +847,9 @@ static u32 stu300_func(struct i2c_adapter *adap)
} }
static const struct i2c_algorithm stu300_algo = { static const struct i2c_algorithm stu300_algo = {
.master_xfer = stu300_xfer, .master_xfer = stu300_xfer,
.functionality = stu300_func, .master_xfer_atomic = stu300_xfer_todo,
.functionality = stu300_func,
}; };
static const struct i2c_adapter_quirks stu300_quirks = { static const struct i2c_adapter_quirks stu300_quirks = {
......
...@@ -207,7 +207,8 @@ static int tegra_bpmp_i2c_msg_len_check(struct i2c_msg *msgs, unsigned int num) ...@@ -207,7 +207,8 @@ static int tegra_bpmp_i2c_msg_len_check(struct i2c_msg *msgs, unsigned int num)
static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c, static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
struct mrq_i2c_request *request, struct mrq_i2c_request *request,
struct mrq_i2c_response *response) struct mrq_i2c_response *response,
bool atomic)
{ {
struct tegra_bpmp_message msg; struct tegra_bpmp_message msg;
int err; int err;
...@@ -222,7 +223,7 @@ static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c, ...@@ -222,7 +223,7 @@ static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
msg.rx.data = response; msg.rx.data = response;
msg.rx.size = sizeof(*response); msg.rx.size = sizeof(*response);
if (irqs_disabled()) if (atomic)
err = tegra_bpmp_transfer_atomic(i2c->bpmp, &msg); err = tegra_bpmp_transfer_atomic(i2c->bpmp, &msg);
else else
err = tegra_bpmp_transfer(i2c->bpmp, &msg); err = tegra_bpmp_transfer(i2c->bpmp, &msg);
...@@ -230,8 +231,9 @@ static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c, ...@@ -230,8 +231,9 @@ static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
return err; return err;
} }
static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter, static int tegra_bpmp_i2c_xfer_common(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num) struct i2c_msg *msgs, int num,
bool atomic)
{ {
struct tegra_bpmp_i2c *i2c = i2c_get_adapdata(adapter); struct tegra_bpmp_i2c *i2c = i2c_get_adapdata(adapter);
struct mrq_i2c_response response; struct mrq_i2c_response response;
...@@ -253,7 +255,7 @@ static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter, ...@@ -253,7 +255,7 @@ static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
return err; return err;
} }
err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response); err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response, atomic);
if (err < 0) { if (err < 0) {
dev_err(i2c->dev, "failed to transfer message: %d\n", err); dev_err(i2c->dev, "failed to transfer message: %d\n", err);
return err; return err;
...@@ -268,6 +270,18 @@ static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter, ...@@ -268,6 +270,18 @@ static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
return num; return num;
} }
static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
return tegra_bpmp_i2c_xfer_common(adapter, msgs, num, false);
}
static int tegra_bpmp_i2c_xfer_atomic(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
return tegra_bpmp_i2c_xfer_common(adapter, msgs, num, true);
}
static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter) static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
...@@ -276,6 +290,7 @@ static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter) ...@@ -276,6 +290,7 @@ static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter)
static const struct i2c_algorithm tegra_bpmp_i2c_algo = { static const struct i2c_algorithm tegra_bpmp_i2c_algo = {
.master_xfer = tegra_bpmp_i2c_xfer, .master_xfer = tegra_bpmp_i2c_xfer,
.master_xfer_atomic = tegra_bpmp_i2c_xfer_atomic,
.functionality = tegra_bpmp_i2c_func, .functionality = tegra_bpmp_i2c_func,
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -310,12 +310,18 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, ...@@ -310,12 +310,18 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
else else
priv->algo.master_xfer = __i2c_mux_master_xfer; priv->algo.master_xfer = __i2c_mux_master_xfer;
} }
if (parent->algo->master_xfer_atomic)
priv->algo.master_xfer_atomic = priv->algo.master_xfer;
if (parent->algo->smbus_xfer) { if (parent->algo->smbus_xfer) {
if (muxc->mux_locked) if (muxc->mux_locked)
priv->algo.smbus_xfer = i2c_mux_smbus_xfer; priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
else else
priv->algo.smbus_xfer = __i2c_mux_smbus_xfer; priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
} }
if (parent->algo->smbus_xfer_atomic)
priv->algo.smbus_xfer_atomic = priv->algo.smbus_xfer;
priv->algo.functionality = i2c_mux_functionality; priv->algo.functionality = i2c_mux_functionality;
/* Now fill out new adapter structure */ /* Now fill out new adapter structure */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -33,6 +33,7 @@ struct i2c_algo_bit_data { ...@@ -33,6 +33,7 @@ struct i2c_algo_bit_data {
minimum 5 us for standard-mode I2C and SMBus, minimum 5 us for standard-mode I2C and SMBus,
maximum 50 us for SMBus */ maximum 50 us for SMBus */
int timeout; /* in jiffies */ int timeout; /* in jiffies */
bool can_do_atomic; /* callbacks don't sleep, we can be atomic */
}; };
int i2c_bit_add_bus(struct i2c_adapter *); int i2c_bit_add_bus(struct i2c_adapter *);
......
This diff is collapsed.
This diff is collapsed.
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