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

Pull i2c updates from Wolfram Sang:
 "Here is the pull request from the i2c subsystem.  It got a little
  delayed because I needed to wait for a dependency to be included
  (commit b424080a9e: "reset: Add optional resets and stubs").  Plus,
  I had some email problems.  All done now, the highlights are:

   - drivers can now deprecate their use of i2c classes.  That shouldn't
     be used on embedded platforms anyhow and was often blindly
     copy&pasted.  This mechanism gives users time to switch away and
     ultimately boot faster once the use of classes for those drivers is
     gone for good.

   - new drivers for QUP, Cadence, efm32

   - tracepoint support for I2C and SMBus

   - bigger cleanups for the mv64xxx, nomadik, and designware drivers

  And the usual bugfixes, cleanups, feature additions.  Most stuff has
  been in linux-next for a while.  Just some hot fixes and new drivers
  were added a bit more recently."

* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (63 commits)
  i2c: cadence: fix Kconfig dependency
  i2c: Add driver for Cadence I2C controller
  i2c: cadence: Document device tree bindings
  Documentation: i2c: improve section about flags mangling the protocol
  i2c: qup: use proper type fro clk_freq
  i2c: qup: off by ones in qup_i2c_probe()
  i2c: efm32: fix binding doc
  MAINTAINERS: update I2C web resources
  i2c: qup: New bus driver for the Qualcomm QUP I2C controller
  i2c: qup: Add device tree bindings information
  i2c: i2c-xiic: deprecate class based instantiation
  i2c: i2c-sirf: deprecate class based instantiation
  i2c: i2c-mv64xxx: deprecate class based instantiation
  i2c: i2c-designware-platdrv: deprecate class based instantiation
  i2c: i2c-davinci: deprecate class based instantiation
  i2c: i2c-bcm2835: deprecate class based instantiation
  i2c: mv64xxx: Fix reset controller handling
  i2c: omap: fix usage of IS_ERR_VALUE with pm_runtime_get_sync
  i2c: efm32: new bus driver
  i2c: exynos5: remove unnecessary cast of void pointer
  ...
This commit is contained in:
Linus Torvalds 2014-04-09 08:45:40 -07:00
commit 39de65aa2c
64 changed files with 3293 additions and 502 deletions

View file

@ -12,6 +12,7 @@ Required properties :
- clocks: phandles to input clocks. - clocks: phandles to input clocks.
Optional properties: Optional properties:
- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
- Child nodes conforming to i2c bus binding - Child nodes conforming to i2c bus binding
Examples : Examples :
@ -23,6 +24,7 @@ i2c0: i2c@fff84000 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&twi0_clk>; clocks = <&twi0_clk>;
clock-frequency = <400000>;
24c512@50 { 24c512@50 {
compatible = "24c512"; compatible = "24c512";

View file

@ -0,0 +1,24 @@
Binding for the Cadence I2C controller
Required properties:
- reg: Physical base address and size of the controller's register area.
- compatible: Compatibility string. Must be 'cdns,i2c-r1p10'.
- clocks: Input clock specifier. Refer to common clock bindings.
- interrupts: Interrupt specifier. Refer to interrupt bindings.
- #address-cells: Should be 1.
- #size-cells: Should be 0.
Optional properties:
- clock-frequency: Desired operating frequency, in Hz, of the bus.
- clock-names: Input clock name, should be 'pclk'.
Example:
i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
clocks = <&clkc 38>;
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xe0004000 0x1000>;
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
};

View file

@ -14,6 +14,12 @@ Optional properties :
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
This option is only supported in hardware blocks version 1.11a or newer. This option is only supported in hardware blocks version 1.11a or newer.
- i2c-scl-falling-time : should contain the SCL falling time in nanoseconds.
This value which is by default 300ns is used to compute the tLOW period.
- i2c-sda-falling-time : should contain the SDA falling time in nanoseconds.
This value which is by default 300ns is used to compute the tHIGH period.
Example : Example :
i2c@f0000 { i2c@f0000 {
@ -34,4 +40,6 @@ Example :
interrupts = <12 1>; interrupts = <12 1>;
clock-frequency = <400000>; clock-frequency = <400000>;
i2c-sda-hold-time-ns = <300>; i2c-sda-hold-time-ns = <300>;
i2c-sda-falling-time-ns = <300>;
i2c-scl-falling-time-ns = <300>;
}; };

View file

@ -0,0 +1,34 @@
* Energymicro efm32 i2c controller
Required properties :
- reg : Offset and length of the register set for the device
- compatible : should be "energymicro,efm32-i2c"
- interrupts : the interrupt number
- clocks : reference to the module clock
Recommended properties :
- clock-frequency : maximal I2C bus clock frequency in Hz.
- efm32,location : Decides the location of the USART I/O pins.
Allowed range : [0 .. 6]
Example:
i2c0: i2c@4000a000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "energymicro,efm32-i2c";
reg = <0x4000a000 0x400>;
interrupts = <9>;
clocks = <&cmu clk_HFPERCLKI2C0>;
clock-frequency = <100000>;
status = "ok";
efm32,location = <3>;
eeprom@50 {
compatible = "microchip,24c02";
reg = <0x50>;
pagesize = <16>;
};
};

View file

@ -4,12 +4,16 @@
Required properties : Required properties :
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c" - compatible : Should be either:
or "marvell,mv78230-i2c" or "marvell,mv78230-a0-i2c" - "allwinner,sun4i-i2c"
Note: Only use "marvell,mv78230-a0-i2c" for a very rare, - "allwinner,sun6i-a31-i2c"
initial version of the SoC which had broken offload - "marvell,mv64xxx-i2c"
support. Linux auto-detects this and sets it - "marvell,mv78230-i2c"
appropriately. - "marvell,mv78230-a0-i2c"
* Note: Only use "marvell,mv78230-a0-i2c" for a
very rare, initial version of the SoC which
had broken offload support. Linux
auto-detects this and sets it appropriately.
- interrupts : The interrupt number - interrupts : The interrupt number
Optional properties : Optional properties :
@ -17,6 +21,10 @@ Optional properties :
- clock-frequency : Desired I2C bus clock frequency in Hz. If not set the - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the
default frequency is 100kHz default frequency is 100kHz
- resets : phandle to the parent reset controller. Mandatory
whenever you're using the "allwinner,sun6i-a31-i2c"
compatible.
Examples: Examples:
i2c@11000 { i2c@11000 {

View file

@ -6,6 +6,7 @@ Required properties:
"renesas,i2c-r8a7778" "renesas,i2c-r8a7778"
"renesas,i2c-r8a7779" "renesas,i2c-r8a7779"
"renesas,i2c-r8a7790" "renesas,i2c-r8a7790"
"renesas,i2c-r8a7791"
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: interrupt specifier. - interrupts: interrupt specifier.
@ -13,11 +14,16 @@ Required properties:
Optional properties: Optional properties:
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
propoerty indicates the default frequency 100 kHz. propoerty indicates the default frequency 100 kHz.
- clocks: clock specifier.
Examples : Examples :
i2c0: i2c@e6500000 { i2c0: i2c@e6508000 {
compatible = "renesas,i2c-rcar-h2"; #address-cells = <1>;
reg = <0 0xe6500000 0 0x428>; #size-cells = <0>;
interrupts = <0 174 0x4>; compatible = "renesas,i2c-r8a7791";
reg = <0 0xe6508000 0 0x40>;
interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C0>;
clock-frequency = <400000>;
}; };

View file

@ -0,0 +1,40 @@
Qualcomm Universal Peripheral (QUP) I2C controller
Required properties:
- compatible: Should be:
* "qcom,i2c-qup-v1.1.1" for 8660, 8960 and 8064.
* "qcom,i2c-qup-v2.1.1" for 8974 v1.
* "qcom,i2c-qup-v2.2.1" for 8974 v2 and later.
- reg: Should contain QUP register address and length.
- interrupts: Should contain I2C interrupt.
- clocks: A list of phandles + clock-specifiers, one for each entry in
clock-names.
- clock-names: Should contain:
* "core" for the core clock
* "iface" for the AHB clock
- #address-cells: Should be <1> Address cells for i2c device address
- #size-cells: Should be <0> as i2c addresses have no size component
Optional properties:
- clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
defaults to 100kHz if omitted.
Child nodes should conform to i2c bus binding.
Example:
i2c@f9924000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
clock-frequency = <355000>;
#address-cells = <1>;
#size-cells = <0>;
};

View file

@ -26,6 +26,7 @@ Supported adapters:
* Intel Wellsburg (PCH) * Intel Wellsburg (PCH)
* Intel Coleto Creek (PCH) * Intel Coleto Creek (PCH)
* Intel Wildcat Point-LP (PCH) * Intel Wildcat Point-LP (PCH)
* Intel BayTrail (SOC)
Datasheets: Publicly available at the Intel website Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller On Intel Patsburg and later chipsets, both the normal host SMBus controller

View file

@ -46,7 +46,7 @@ A few combinations of the above flags are also defined for your convenience:
and write_block_data commands and write_block_data commands
I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data
and write_i2c_block_data commands and write_i2c_block_data commands
I2C_FUNC_SMBUS_EMUL Handles all SMBus commands than can be I2C_FUNC_SMBUS_EMUL Handles all SMBus commands that can be
emulated by a real I2C adapter (using emulated by a real I2C adapter (using
the transparent emulation layer) the transparent emulation layer)

View file

@ -49,11 +49,20 @@ a byte read, followed by a byte write:
Modified transactions Modified transactions
===================== =====================
The following modifications to the I2C protocol can also be generated, The following modifications to the I2C protocol can also be generated by
with the exception of I2C_M_NOSTART these are usually only needed to setting these flags for i2c messages. With the exception of I2C_M_NOSTART, they
work around device issues: are usually only needed to work around device issues:
Flag I2C_M_NOSTART: I2C_M_IGNORE_NAK:
Normally message is interrupted immediately if there is [NA] from the
client. Setting this flag treats any [NA] as [A], and all of
message is sent.
These messages may still fail to SCL lo->hi timeout.
I2C_M_NO_RD_ACK:
In a read message, master A/NA bit is skipped.
I2C_M_NOSTART:
In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some
point. For example, setting I2C_M_NOSTART on the second partial message point. For example, setting I2C_M_NOSTART on the second partial message
generates something like: generates something like:
@ -67,17 +76,13 @@ work around device issues:
I2C device but may also be used between direction changes by some I2C device but may also be used between direction changes by some
rare devices. rare devices.
Flags I2C_M_REV_DIR_ADDR I2C_M_REV_DIR_ADDR:
This toggles the Rd/Wr flag. That is, if you want to do a write, but This toggles the Rd/Wr flag. That is, if you want to do a write, but
need to emit an Rd instead of a Wr, or vice versa, you set this need to emit an Rd instead of a Wr, or vice versa, you set this
flag. For example: flag. For example:
S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P
Flags I2C_M_IGNORE_NAK I2C_M_STOP:
Normally message is interrupted immediately if there is [NA] from the Force a stop condition (P) after the message. Some I2C related protocols
client. Setting this flag treats any [NA] as [A], and all of like SCCB require that. Normally, you really don't want to get interrupted
message is sent. between the messages of one transfer.
These messages may still fail to SCL lo->hi timeout.
Flags I2C_M_NO_RD_ACK
In a read message, master A/NA bit is skipped.

View file

@ -1427,6 +1427,7 @@ F: drivers/cpuidle/cpuidle-zynq.c
N: zynq N: zynq
N: xilinx N: xilinx
F: drivers/clocksource/cadence_ttc_timer.c F: drivers/clocksource/cadence_ttc_timer.c
F: drivers/i2c/busses/i2c-cadence.c
F: drivers/mmc/host/sdhci-of-arasan.c F: drivers/mmc/host/sdhci-of-arasan.c
ARM SMMU DRIVER ARM SMMU DRIVER
@ -4308,7 +4309,8 @@ F: drivers/i2c/i2c-stub.c
I2C SUBSYSTEM I2C SUBSYSTEM
M: Wolfram Sang <wsa@the-dreams.de> M: Wolfram Sang <wsa@the-dreams.de>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/ W: https://i2c.wiki.kernel.org/
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
S: Maintained S: Maintained
F: Documentation/i2c/ F: Documentation/i2c/

View file

@ -9,60 +9,7 @@
#ifndef __ASM_BFIN_TWI_H__ #ifndef __ASM_BFIN_TWI_H__
#define __ASM_BFIN_TWI_H__ #define __ASM_BFIN_TWI_H__
#include <linux/types.h> #include <asm/blackfin.h>
#include <linux/i2c.h>
/*
* All Blackfin system MMRs are padded to 32bits even if the register
* itself is only 16bits. So use a helper macro to streamline this.
*/
#define __BFP(m) u16 m; u16 __pad_##m
/*
* bfin twi registers layout
*/
struct bfin_twi_regs {
__BFP(clkdiv);
__BFP(control);
__BFP(slave_ctl);
__BFP(slave_stat);
__BFP(slave_addr);
__BFP(master_ctl);
__BFP(master_stat);
__BFP(master_addr);
__BFP(int_stat);
__BFP(int_mask);
__BFP(fifo_ctl);
__BFP(fifo_stat);
u32 __pad[20];
__BFP(xmt_data8);
__BFP(xmt_data16);
__BFP(rcv_data8);
__BFP(rcv_data16);
};
#undef __BFP
struct bfin_twi_iface {
int irq;
spinlock_t lock;
char read_write;
u8 command;
u8 *transPtr;
int readNum;
int writeNum;
int cur_mode;
int manual_stop;
int result;
struct i2c_adapter adap;
struct completion complete;
struct i2c_msg *pmsg;
int msg_num;
int cur_msg;
u16 saved_clkdiv;
u16 saved_control;
struct bfin_twi_regs __iomem *regs_base;
};
#define DEFINE_TWI_REG(reg_name, reg) \ #define DEFINE_TWI_REG(reg_name, reg) \
static inline u16 read_##reg_name(struct bfin_twi_iface *iface) \ static inline u16 read_##reg_name(struct bfin_twi_iface *iface) \
@ -71,7 +18,6 @@ static inline void write_##reg_name(struct bfin_twi_iface *iface, u16 v) \
{ bfin_write16(&iface->regs_base->reg, v); } { bfin_write16(&iface->regs_base->reg, v); }
DEFINE_TWI_REG(CLKDIV, clkdiv) DEFINE_TWI_REG(CLKDIV, clkdiv)
DEFINE_TWI_REG(CONTROL, control)
DEFINE_TWI_REG(SLAVE_CTL, slave_ctl) DEFINE_TWI_REG(SLAVE_CTL, slave_ctl)
DEFINE_TWI_REG(SLAVE_STAT, slave_stat) DEFINE_TWI_REG(SLAVE_STAT, slave_stat)
DEFINE_TWI_REG(SLAVE_ADDR, slave_addr) DEFINE_TWI_REG(SLAVE_ADDR, slave_addr)
@ -80,7 +26,6 @@ DEFINE_TWI_REG(MASTER_STAT, master_stat)
DEFINE_TWI_REG(MASTER_ADDR, master_addr) DEFINE_TWI_REG(MASTER_ADDR, master_addr)
DEFINE_TWI_REG(INT_STAT, int_stat) DEFINE_TWI_REG(INT_STAT, int_stat)
DEFINE_TWI_REG(INT_MASK, int_mask) DEFINE_TWI_REG(INT_MASK, int_mask)
DEFINE_TWI_REG(FIFO_CTL, fifo_ctl)
DEFINE_TWI_REG(FIFO_STAT, fifo_stat) DEFINE_TWI_REG(FIFO_STAT, fifo_stat)
DEFINE_TWI_REG(XMT_DATA8, xmt_data8) DEFINE_TWI_REG(XMT_DATA8, xmt_data8)
DEFINE_TWI_REG(XMT_DATA16, xmt_data16) DEFINE_TWI_REG(XMT_DATA16, xmt_data16)
@ -113,75 +58,25 @@ static inline u16 read_RCV_DATA16(struct bfin_twi_iface *iface)
} }
#endif #endif
static inline u16 read_FIFO_CTL(struct bfin_twi_iface *iface)
{
return bfin_read16(&iface->regs_base->fifo_ctl);
}
/* ******************** TWO-WIRE INTERFACE (TWI) MASKS ***********************/ static inline void write_FIFO_CTL(struct bfin_twi_iface *iface, u16 v)
/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y); ) */ {
#define CLKLOW(x) ((x) & 0xFF) /* Periods Clock Is Held Low */ bfin_write16(&iface->regs_base->fifo_ctl, v);
#define CLKHI(y) (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */ SSYNC();
}
/* TWI_PRESCALE Masks */ static inline u16 read_CONTROL(struct bfin_twi_iface *iface)
#define PRESCALE 0x007F /* SCLKs Per Internal Time Reference (10MHz) */ {
#define TWI_ENA 0x0080 /* TWI Enable */ return bfin_read16(&iface->regs_base->control);
#define SCCB 0x0200 /* SCCB Compatibility Enable */ }
/* TWI_SLAVE_CTL Masks */
#define SEN 0x0001 /* Slave Enable */
#define SADD_LEN 0x0002 /* Slave Address Length */
#define STDVAL 0x0004 /* Slave Transmit Data Valid */
#define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */
#define GEN 0x0010 /* General Call Address Matching Enabled */
/* TWI_SLAVE_STAT Masks */
#define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */
#define GCALL 0x0002 /* General Call Indicator */
/* TWI_MASTER_CTL Masks */
#define MEN 0x0001 /* Master Mode Enable */
#define MADD_LEN 0x0002 /* Master Address Length */
#define MDIR 0x0004 /* Master Transmit Direction (RX/TX*) */
#define FAST 0x0008 /* Use Fast Mode Timing Specs */
#define STOP 0x0010 /* Issue Stop Condition */
#define RSTART 0x0020 /* Repeat Start or Stop* At End Of Transfer */
#define DCNT 0x3FC0 /* Data Bytes To Transfer */
#define SDAOVR 0x4000 /* Serial Data Override */
#define SCLOVR 0x8000 /* Serial Clock Override */
/* TWI_MASTER_STAT Masks */
#define MPROG 0x0001 /* Master Transfer In Progress */
#define LOSTARB 0x0002 /* Lost Arbitration Indicator (Xfer Aborted) */
#define ANAK 0x0004 /* Address Not Acknowledged */
#define DNAK 0x0008 /* Data Not Acknowledged */
#define BUFRDERR 0x0010 /* Buffer Read Error */
#define BUFWRERR 0x0020 /* Buffer Write Error */
#define SDASEN 0x0040 /* Serial Data Sense */
#define SCLSEN 0x0080 /* Serial Clock Sense */
#define BUSBUSY 0x0100 /* Bus Busy Indicator */
/* TWI_INT_SRC and TWI_INT_ENABLE Masks */
#define SINIT 0x0001 /* Slave Transfer Initiated */
#define SCOMP 0x0002 /* Slave Transfer Complete */
#define SERR 0x0004 /* Slave Transfer Error */
#define SOVF 0x0008 /* Slave Overflow */
#define MCOMP 0x0010 /* Master Transfer Complete */
#define MERR 0x0020 /* Master Transfer Error */
#define XMTSERV 0x0040 /* Transmit FIFO Service */
#define RCVSERV 0x0080 /* Receive FIFO Service */
/* TWI_FIFO_CTRL Masks */
#define XMTFLUSH 0x0001 /* Transmit Buffer Flush */
#define RCVFLUSH 0x0002 /* Receive Buffer Flush */
#define XMTINTLEN 0x0004 /* Transmit Buffer Interrupt Length */
#define RCVINTLEN 0x0008 /* Receive Buffer Interrupt Length */
/* TWI_FIFO_STAT Masks */
#define XMTSTAT 0x0003 /* Transmit FIFO Status */
#define XMT_EMPTY 0x0000 /* Transmit FIFO Empty */
#define XMT_HALF 0x0001 /* Transmit FIFO Has 1 Byte To Write */
#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */
#define RCVSTAT 0x000C /* Receive FIFO Status */
#define RCV_EMPTY 0x0000 /* Receive FIFO Empty */
#define RCV_HALF 0x0004 /* Receive FIFO Has 1 Byte To Read */
#define RCV_FULL 0x000C /* Receive FIFO Full (2 Bytes To Read) */
static inline void write_CONTROL(struct bfin_twi_iface *iface, u16 v)
{
SSYNC();
bfin_write16(&iface->regs_base->control, v);
}
#endif #endif

View file

@ -10,6 +10,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c/bfin_twi.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/gpio.h> #include <asm/gpio.h>

View file

@ -110,6 +110,7 @@ config I2C_I801
Wellsburg (PCH) Wellsburg (PCH)
Coleto Creek (PCH) Coleto Creek (PCH)
Wildcat Point-LP (PCH) Wildcat Point-LP (PCH)
BayTrail (SOC)
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-i801. will be called i2c-i801.
@ -375,6 +376,13 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
help help
The unit of the TWI clock is kHz. The unit of the TWI clock is kHz.
config I2C_CADENCE
tristate "Cadence I2C Controller"
depends on ARCH_ZYNQ
help
Say yes here to select Cadence I2C Host Controller. This controller is
e.g. used by Xilinx Zynq.
config I2C_CBUS_GPIO config I2C_CBUS_GPIO
tristate "CBUS I2C driver" tristate "CBUS I2C driver"
depends on GPIOLIB depends on GPIOLIB
@ -432,6 +440,13 @@ config I2C_DESIGNWARE_PCI
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-designware-pci. will be called i2c-designware-pci.
config I2C_EFM32
tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST
help
This driver supports the i2c block found in Energy Micro's EFM32
SoCs.
config I2C_EG20T config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
depends on PCI depends on PCI
@ -527,7 +542,7 @@ config I2C_MPC
config I2C_MV64XXX config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller" tristate "Marvell mv64xxx I2C Controller"
depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
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
built-in I2C interface on the Marvell 64xxx line of host bridges. built-in I2C interface on the Marvell 64xxx line of host bridges.
@ -648,6 +663,16 @@ config I2C_PXA_SLAVE
is necessary for systems where the PXA may be a target on the is necessary for systems where the PXA may be a target on the
I2C bus. I2C bus.
config I2C_QUP
tristate "Qualcomm QUP based I2C controller"
depends on ARCH_QCOM
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Qualcomm SoCs.
This driver can also be built as a module. If so, the module
will be called i2c-qup.
config I2C_RIIC config I2C_RIIC
tristate "Renesas RIIC adapter" tristate "Renesas RIIC adapter"
depends on ARCH_SHMOBILE || COMPILE_TEST depends on ARCH_SHMOBILE || COMPILE_TEST

View file

@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-platform-objs := i2c-designware-platdrv.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
@ -63,6 +65,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o

View file

@ -494,7 +494,7 @@ static struct i2c_adapter ali1535_adapter = {
.algo = &smbus_algorithm, .algo = &smbus_algorithm,
}; };
static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = { static const struct pci_device_id ali1535_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }, { },
}; };

View file

@ -416,7 +416,7 @@ static void ali1563_remove(struct pci_dev *dev)
ali1563_shutdown(dev); ali1563_shutdown(dev);
} }
static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = { static const struct pci_device_id ali1563_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
{}, {},
}; };

View file

@ -476,7 +476,7 @@ static struct i2c_adapter ali15x3_adapter = {
.algo = &smbus_algorithm, .algo = &smbus_algorithm,
}; };
static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = { static const struct pci_device_id ali15x3_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ 0, } { 0, }
}; };

View file

@ -307,7 +307,7 @@ static const char* chipname[] = {
"nVidia nForce", "AMD8111", "nVidia nForce", "AMD8111",
}; };
static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = { static const struct pci_device_id amd756_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
.driver_data = AMD756 }, .driver_data = AMD756 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),

View file

@ -414,7 +414,7 @@ static const struct i2c_algorithm smbus_algorithm = {
}; };
static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = { static const struct pci_device_id amd8111_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
{ 0, } { 0, }
}; };

View file

@ -32,7 +32,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_data/dma-atmel.h> #include <linux/platform_data/dma-atmel.h>
#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ #define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ #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 AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
@ -711,6 +711,7 @@ static int at91_twi_probe(struct platform_device *pdev)
struct resource *mem; struct resource *mem;
int rc; int rc;
u32 phy_addr; u32 phy_addr;
u32 bus_clk_rate;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) if (!dev)
@ -756,13 +757,18 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->use_dma = true; dev->use_dma = true;
} }
at91_calc_twi_clock(dev, TWI_CLK_HZ); rc = of_property_read_u32(dev->dev->of_node, "clock-frequency",
&bus_clk_rate);
if (rc)
bus_clk_rate = DEFAULT_TWI_CLK_HZ;
at91_calc_twi_clock(dev, bus_clk_rate);
at91_init_twi_bus(dev); at91_init_twi_bus(dev);
snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
i2c_set_adapdata(&dev->adapter, dev); i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.owner = THIS_MODULE; dev->adapter.owner = THIS_MODULE;
dev->adapter.class = I2C_CLASS_HWMON; dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
dev->adapter.algo = &at91_twi_algorithm; dev->adapter.algo = &at91_twi_algorithm;
dev->adapter.dev.parent = dev->dev; dev->adapter.dev.parent = dev->dev;
dev->adapter.nr = pdev->id; dev->adapter.nr = pdev->id;

View file

@ -219,7 +219,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
static int bcm2835_i2c_probe(struct platform_device *pdev) static int bcm2835_i2c_probe(struct platform_device *pdev)
{ {
struct bcm2835_i2c_dev *i2c_dev; struct bcm2835_i2c_dev *i2c_dev;
struct resource *mem, *requested, *irq; struct resource *mem, *irq;
u32 bus_clk_rate, divider; u32 bus_clk_rate, divider;
int ret; int ret;
struct i2c_adapter *adap; struct i2c_adapter *adap;
@ -234,25 +234,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
init_completion(&i2c_dev->completion); init_completion(&i2c_dev->completion);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) { i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
dev_err(&pdev->dev, "No mem resource\n"); if (IS_ERR(i2c_dev->regs))
return -ENODEV; return PTR_ERR(i2c_dev->regs);
}
requested = devm_request_mem_region(&pdev->dev, mem->start,
resource_size(mem),
dev_name(&pdev->dev));
if (!requested) {
dev_err(&pdev->dev, "Could not claim register region\n");
return -EBUSY;
}
i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start,
resource_size(mem));
if (!i2c_dev->regs) {
dev_err(&pdev->dev, "Could not map registers\n");
return -ENOMEM;
}
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_dev->clk)) { if (IS_ERR(i2c_dev->clk)) {
@ -295,7 +279,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
adap = &i2c_dev->adapter; adap = &i2c_dev->adapter;
i2c_set_adapdata(adap, i2c_dev); i2c_set_adapdata(adap, i2c_dev);
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name)); strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
adap->algo = &bcm2835_i2c_algo; adap->algo = &bcm2835_i2c_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;

View file

@ -21,10 +21,10 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c/bfin_twi.h>
#include <asm/blackfin.h>
#include <asm/portmux.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/portmux.h>
#include <asm/bfin_twi.h> #include <asm/bfin_twi.h>
/* SMBus mode*/ /* SMBus mode*/
@ -65,7 +65,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
/* Transmit next data */ /* Transmit next data */
while (iface->writeNum > 0 && while (iface->writeNum > 0 &&
(read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) { (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) {
SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++)); write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--; iface->writeNum--;
} }
@ -248,7 +247,6 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
/* Clear interrupt status */ /* Clear interrupt status */
write_INT_STAT(iface, twi_int_status); write_INT_STAT(iface, twi_int_status);
bfin_twi_handle_interrupt(iface, twi_int_status); bfin_twi_handle_interrupt(iface, twi_int_status);
SSYNC();
} }
spin_unlock_irqrestore(&iface->lock, flags); spin_unlock_irqrestore(&iface->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
@ -294,9 +292,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
* discarded before start a new operation. * discarded before start a new operation.
*/ */
write_FIFO_CTL(iface, 0x3); write_FIFO_CTL(iface, 0x3);
SSYNC();
write_FIFO_CTL(iface, 0); write_FIFO_CTL(iface, 0);
SSYNC();
if (pmsg->flags & I2C_M_RD) if (pmsg->flags & I2C_M_RD)
iface->read_write = I2C_SMBUS_READ; iface->read_write = I2C_SMBUS_READ;
@ -306,7 +302,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
if (iface->writeNum > 0) { if (iface->writeNum > 0) {
write_XMT_DATA8(iface, *(iface->transPtr++)); write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--; iface->writeNum--;
SSYNC();
} }
} }
@ -315,7 +310,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
/* Interrupt mask . Enable XMT, RCV interrupt */ /* Interrupt mask . Enable XMT, RCV interrupt */
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
SSYNC();
if (pmsg->len <= 255) if (pmsg->len <= 255)
write_MASTER_CTL(iface, pmsg->len << 6); write_MASTER_CTL(iface, pmsg->len << 6);
@ -329,7 +323,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
(iface->msg_num > 1 ? RSTART : 0) | (iface->msg_num > 1 ? RSTART : 0) |
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
SSYNC();
while (!iface->result) { while (!iface->result) {
if (!wait_for_completion_timeout(&iface->complete, if (!wait_for_completion_timeout(&iface->complete,
@ -453,7 +446,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
* start a new operation. * start a new operation.
*/ */
write_FIFO_CTL(iface, 0x3); write_FIFO_CTL(iface, 0x3);
SSYNC();
write_FIFO_CTL(iface, 0); write_FIFO_CTL(iface, 0);
/* clear int stat */ /* clear int stat */
@ -461,7 +453,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
/* Set Transmit device address */ /* Set Transmit device address */
write_MASTER_ADDR(iface, addr); write_MASTER_ADDR(iface, addr);
SSYNC();
switch (iface->cur_mode) { switch (iface->cur_mode) {
case TWI_I2C_MODE_STANDARDSUB: case TWI_I2C_MODE_STANDARDSUB:
@ -469,7 +460,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
write_INT_MASK(iface, MCOMP | MERR | write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ? ((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV)); RCVSERV : XMTSERV));
SSYNC();
if (iface->writeNum + 1 <= 255) if (iface->writeNum + 1 <= 255)
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@ -484,7 +474,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
case TWI_I2C_MODE_COMBINED: case TWI_I2C_MODE_COMBINED:
write_XMT_DATA8(iface, iface->command); write_XMT_DATA8(iface, iface->command);
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
SSYNC();
if (iface->writeNum > 0) if (iface->writeNum > 0)
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@ -531,7 +520,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
write_INT_MASK(iface, MCOMP | MERR | write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ? ((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV)); RCVSERV : XMTSERV));
SSYNC();
/* Master enable */ /* Master enable */
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
@ -539,7 +527,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
break; break;
} }
SSYNC();
while (!iface->result) { while (!iface->result) {
if (!wait_for_completion_timeout(&iface->complete, if (!wait_for_completion_timeout(&iface->complete,
@ -669,7 +656,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name)); strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
p_adap->algo = &bfin_twi_algorithm; p_adap->algo = &bfin_twi_algorithm;
p_adap->algo_data = iface; p_adap->algo_data = iface;
p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
p_adap->dev.parent = &pdev->dev; p_adap->dev.parent = &pdev->dev;
p_adap->timeout = 5 * HZ; p_adap->timeout = 5 * HZ;
p_adap->retries = 3; p_adap->retries = 3;
@ -704,7 +691,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
/* Enable TWI */ /* Enable TWI */
write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
SSYNC();
rc = i2c_add_numbered_adapter(p_adap); rc = i2c_add_numbered_adapter(p_adap);
if (rc < 0) { if (rc < 0) {

View file

@ -0,0 +1,905 @@
/*
* I2C bus driver for the Cadence I2C controller.
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
* either version 2 of the License, or (at your option) any
* later version.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
/* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
#define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */
#define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
#define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */
#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
/* Control Register Bit mask definitions */
#define CDNS_I2C_CR_HOLD BIT(4) /* Hold Bus bit */
#define CDNS_I2C_CR_ACK_EN BIT(3)
#define CDNS_I2C_CR_NEA BIT(2)
#define CDNS_I2C_CR_MS BIT(1)
/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
#define CDNS_I2C_CR_RW BIT(0)
/* 1 = Auto init FIFO to zeroes */
#define CDNS_I2C_CR_CLR_FIFO BIT(6)
#define CDNS_I2C_CR_DIVA_SHIFT 14
#define CDNS_I2C_CR_DIVA_MASK (3 << CDNS_I2C_CR_DIVA_SHIFT)
#define CDNS_I2C_CR_DIVB_SHIFT 8
#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
/* Status Register Bit mask definitions */
#define CDNS_I2C_SR_BA BIT(8)
#define CDNS_I2C_SR_RXDV BIT(5)
/*
* I2C Address Register Bit mask definitions
* Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
* bits. A write access to this register always initiates a transfer if the I2C
* is in master mode.
*/
#define CDNS_I2C_ADDR_MASK 0x000003FF /* I2C Address Mask */
/*
* I2C Interrupt Registers Bit mask definitions
* All the four interrupt registers (Status/Mask/Enable/Disable) have the same
* bit definitions.
*/
#define CDNS_I2C_IXR_ARB_LOST BIT(9)
#define CDNS_I2C_IXR_RX_UNF BIT(7)
#define CDNS_I2C_IXR_TX_OVF BIT(6)
#define CDNS_I2C_IXR_RX_OVF BIT(5)
#define CDNS_I2C_IXR_SLV_RDY BIT(4)
#define CDNS_I2C_IXR_TO BIT(3)
#define CDNS_I2C_IXR_NACK BIT(2)
#define CDNS_I2C_IXR_DATA BIT(1)
#define CDNS_I2C_IXR_COMP BIT(0)
#define CDNS_I2C_IXR_ALL_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
CDNS_I2C_IXR_RX_UNF | \
CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | \
CDNS_I2C_IXR_SLV_RDY | \
CDNS_I2C_IXR_TO | \
CDNS_I2C_IXR_NACK | \
CDNS_I2C_IXR_DATA | \
CDNS_I2C_IXR_COMP)
#define CDNS_I2C_IXR_ERR_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
CDNS_I2C_IXR_RX_UNF | \
CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | \
CDNS_I2C_IXR_NACK)
#define CDNS_I2C_ENABLED_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
CDNS_I2C_IXR_RX_UNF | \
CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | \
CDNS_I2C_IXR_NACK | \
CDNS_I2C_IXR_DATA | \
CDNS_I2C_IXR_COMP)
#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
#define CDNS_I2C_FIFO_DEPTH 16
/* FIFO depth at which the DATA interrupt occurs */
#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
#define DRIVER_NAME "cdns-i2c"
#define CDNS_I2C_SPEED_MAX 400000
#define CDNS_I2C_SPEED_DEFAULT 100000
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
/**
* struct cdns_i2c - I2C device private data structure
* @membase: Base address of the I2C device
* @adap: I2C adapter instance
* @p_msg: Message pointer
* @err_status: Error status in Interrupt Status Register
* @xfer_done: Transfer complete status
* @p_send_buf: Pointer to transmit buffer
* @p_recv_buf: Pointer to receive buffer
* @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
* @clk: Pointer to struct clk
* @clk_rate_change_nb: Notifier block for clock rate changes
*/
struct cdns_i2c {
void __iomem *membase;
struct i2c_adapter adap;
struct i2c_msg *p_msg;
int err_status;
struct completion xfer_done;
unsigned char *p_send_buf;
unsigned char *p_recv_buf;
u8 suspended;
unsigned int send_count;
unsigned int recv_count;
int irq;
unsigned long input_clk;
unsigned int i2c_clk;
unsigned int bus_hold_flag;
struct clk *clk;
struct notifier_block clk_rate_change_nb;
};
#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
clk_rate_change_nb)
/**
* cdns_i2c_clear_bus_hold() - Clear bus hold bit
* @id: Pointer to driver data struct
*
* Helper to clear the controller's bus hold bit.
*/
static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
{
u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
if (reg & CDNS_I2C_CR_HOLD)
cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
}
/**
* cdns_i2c_isr - Interrupt handler for the I2C device
* @irq: irq number for the I2C device
* @ptr: void pointer to cdns_i2c structure
*
* This function handles the data interrupt, transfer complete interrupt and
* the error interrupts of the I2C device.
*
* Return: IRQ_HANDLED always
*/
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
{
unsigned int isr_status, avail_bytes;
unsigned int bytes_to_recv, bytes_to_send;
struct cdns_i2c *id = ptr;
/* Signal completion only after everything is updated */
int done_flag = 0;
irqreturn_t status = IRQ_NONE;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
/* Handling nack and arbitration lost interrupt */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
done_flag = 1;
status = IRQ_HANDLED;
}
/* Handling Data interrupt */
if ((isr_status & CDNS_I2C_IXR_DATA) &&
(id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
/* Always read data interrupt threshold bytes */
bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
/*
* if the tranfer size register value is zero, then
* check for the remaining bytes and update the
* transfer size register.
*/
if (!avail_bytes) {
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
else
cdns_i2c_writereg(id->recv_count,
CDNS_I2C_XFER_SIZE_OFFSET);
}
/* Process the data received */
while (bytes_to_recv--)
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
if (!id->bus_hold_flag &&
(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
cdns_i2c_clear_bus_hold(id);
status = IRQ_HANDLED;
}
/* Handling Transfer Complete interrupt */
if (isr_status & CDNS_I2C_IXR_COMP) {
if (!id->p_recv_buf) {
/*
* If the device is sending data If there is further
* data to be sent. Calculate the available space
* in FIFO and fill the FIFO with that many bytes.
*/
if (id->send_count) {
avail_bytes = CDNS_I2C_FIFO_DEPTH -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
else
bytes_to_send = id->send_count;
while (bytes_to_send--) {
cdns_i2c_writereg(
(*(id->p_send_buf)++),
CDNS_I2C_DATA_OFFSET);
id->send_count--;
}
} else {
/*
* Signal the completion of transaction and
* clear the hold bus bit if there are no
* further messages to be processed.
*/
done_flag = 1;
}
if (!id->send_count && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
} else {
if (!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
/*
* If the device is receiving data, then signal
* the completion of transaction and read the data
* present in the FIFO. Signal the completion of
* transaction.
*/
while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
CDNS_I2C_SR_RXDV) {
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
id->recv_count--;
}
done_flag = 1;
}
status = IRQ_HANDLED;
}
/* Update the status for errors */
id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
if (id->err_status)
status = IRQ_HANDLED;
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
if (done_flag)
complete(&id->xfer_done);
return status;
}
/**
* cdns_i2c_mrecv - Prepare and start a master receive operation
* @id: pointer to the i2c device structure
*/
static void cdns_i2c_mrecv(struct cdns_i2c *id)
{
unsigned int ctrl_reg;
unsigned int isr_status;
id->p_recv_buf = id->p_msg->buf;
id->recv_count = id->p_msg->len;
/* Put the controller in master receive mode and clear the FIFO */
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Clear the interrupts in interrupt status register */
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/*
* The no. of bytes to receive is checked against the limit of
* max transfer size. Set transfer size register with no of bytes
* receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts.
*/
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
else
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
/* Clear the bus hold flag if bytes to receive is less than FIFO size */
if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
cdns_i2c_clear_bus_hold(id);
/* Set the slave address in address register - triggers operation */
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
}
/**
* cdns_i2c_msend - Prepare and start a master send operation
* @id: pointer to the i2c device
*/
static void cdns_i2c_msend(struct cdns_i2c *id)
{
unsigned int avail_bytes;
unsigned int bytes_to_send;
unsigned int ctrl_reg;
unsigned int isr_status;
id->p_recv_buf = NULL;
id->p_send_buf = id->p_msg->buf;
id->send_count = id->p_msg->len;
/* Set the controller in Master transmit mode and clear the FIFO. */
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg &= ~CDNS_I2C_CR_RW;
ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
if (id->send_count > CDNS_I2C_FIFO_DEPTH)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Clear the interrupts in interrupt status register. */
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/*
* Calculate the space available in FIFO. Check the message length
* against the space available, and fill the FIFO accordingly.
* Enable the interrupts.
*/
avail_bytes = CDNS_I2C_FIFO_DEPTH -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
else
bytes_to_send = id->send_count;
while (bytes_to_send--) {
cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
id->send_count--;
}
/*
* Clear the bus hold flag if there is no more data
* and if it is the last message.
*/
if (!id->bus_hold_flag && !id->send_count)
cdns_i2c_clear_bus_hold(id);
/* Set the slave address in address register - triggers operation. */
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
}
/**
* cdns_i2c_master_reset - Reset the interface
* @adap: pointer to the i2c adapter driver instance
*
* This function cleanup the fifos, clear the hold bit and status
* and disable the interrupts.
*/
static void cdns_i2c_master_reset(struct i2c_adapter *adap)
{
struct cdns_i2c *id = adap->algo_data;
u32 regval;
/* Disable the interrupts */
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
/* Clear the hold bit and fifos */
regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
regval &= ~CDNS_I2C_CR_HOLD;
regval |= CDNS_I2C_CR_CLR_FIFO;
cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
/* Update the transfercount register to zero */
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
/* Clear the interupt status register */
regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
/* Clear the status register */
regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
}
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
struct i2c_adapter *adap)
{
int ret;
u32 reg;
id->p_msg = msg;
id->err_status = 0;
reinit_completion(&id->xfer_done);
/* Check for the TEN Bit mode on each msg */
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
if (msg->flags & I2C_M_TEN) {
if (reg & CDNS_I2C_CR_NEA)
cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
CDNS_I2C_CR_OFFSET);
} else {
if (!(reg & CDNS_I2C_CR_NEA))
cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
CDNS_I2C_CR_OFFSET);
}
/* Check for the R/W flag on each msg */
if (msg->flags & I2C_M_RD)
cdns_i2c_mrecv(id);
else
cdns_i2c_msend(id);
/* Wait for the signal of completion */
ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
if (!ret) {
cdns_i2c_master_reset(adap);
dev_err(id->adap.dev.parent,
"timeout waiting on completion\n");
return -ETIMEDOUT;
}
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,
CDNS_I2C_IDR_OFFSET);
/* If it is bus arbitration error, try again */
if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
return -EAGAIN;
return 0;
}
/**
* cdns_i2c_master_xfer - The main i2c transfer function
* @adap: pointer to the i2c adapter driver instance
* @msgs: pointer to the i2c message structure
* @num: the number of messages to transfer
*
* Initiates the send/recv activity based on the transfer message received.
*
* Return: number of msgs processed on success, negative error otherwise
*/
static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
int ret, count;
u32 reg;
struct cdns_i2c *id = adap->algo_data;
/* Check if the bus is free */
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
return -EAGAIN;
/*
* Set the flag to one when multiple messages are to be
* processed with a repeated start.
*/
if (num > 1) {
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
} else {
id->bus_hold_flag = 0;
}
/* Process the msg one by one */
for (count = 0; count < num; count++, msgs++) {
if (count == (num - 1))
id->bus_hold_flag = 0;
ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret)
return ret;
/* Report the other error interrupts to application */
if (id->err_status) {
cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK)
return -ENXIO;
return -EIO;
}
}
return num;
}
/**
* cdns_i2c_func - Returns the supported features of the I2C driver
* @adap: pointer to the i2c adapter structure
*
* Return: 32 bit value, each bit corresponding to a feature
*/
static u32 cdns_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm cdns_i2c_algo = {
.master_xfer = cdns_i2c_master_xfer,
.functionality = cdns_i2c_func,
};
/**
* cdns_i2c_calc_divs - Calculate clock dividers
* @f: I2C clock frequency
* @input_clk: Input clock frequency
* @a: First divider (return value)
* @b: Second divider (return value)
*
* f is used as input and output variable. As input it is used as target I2C
* frequency. On function exit f holds the actually resulting I2C frequency.
*
* Return: 0 on success, negative errno otherwise.
*/
static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
unsigned int *a, unsigned int *b)
{
unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
unsigned int last_error, current_error;
/* calculate (divisor_a+1) x (divisor_b+1) */
temp = input_clk / (22 * fscl);
/*
* If the calculated value is negative or 0, the fscl input is out of
* range. Return error.
*/
if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
return -EINVAL;
last_error = -1;
for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
continue;
div_b--;
actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
if (actual_fscl > fscl)
continue;
current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
(fscl - actual_fscl));
if (last_error > current_error) {
calc_div_a = div_a;
calc_div_b = div_b;
best_fscl = actual_fscl;
last_error = current_error;
}
}
*a = calc_div_a;
*b = calc_div_b;
*f = best_fscl;
return 0;
}
/**
* cdns_i2c_setclk - This function sets the serial clock rate for the I2C device
* @clk_in: I2C clock input frequency in Hz
* @id: Pointer to the I2C device structure
*
* The device must be idle rather than busy transferring data before setting
* these device options.
* The data rate is set by values in the control register.
* The formula for determining the correct register values is
* Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
* See the hardware data sheet for a full explanation of setting the serial
* clock rate. The clock can not be faster than the input clock divide by 22.
* The two most common clock rates are 100KHz and 400KHz.
*
* Return: 0 on success, negative error otherwise
*/
static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
{
unsigned int div_a, div_b;
unsigned int ctrl_reg;
int ret = 0;
unsigned long fscl = id->i2c_clk;
ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
if (ret)
return ret;
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
return 0;
}
/**
* cdns_i2c_clk_notifier_cb - Clock rate change callback
* @nb: Pointer to notifier block
* @event: Notification reason
* @data: Pointer to notification data object
*
* This function is called when the cdns_i2c input clock frequency changes.
* The callback checks whether a valid bus frequency can be generated after the
* change. If so, the change is acknowledged, otherwise the change is aborted.
* New dividers are written to the HW in the pre- or post change notification
* depending on the scaling direction.
*
* Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
* to acknowedge the change, NOTIFY_DONE if the notification is
* considered irrelevant.
*/
static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
event, void *data)
{
struct clk_notifier_data *ndata = data;
struct cdns_i2c *id = to_cdns_i2c(nb);
if (id->suspended)
return NOTIFY_OK;
switch (event) {
case PRE_RATE_CHANGE:
{
unsigned long input_clk = ndata->new_rate;
unsigned long fscl = id->i2c_clk;
unsigned int div_a, div_b;
int ret;
ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b);
if (ret) {
dev_warn(id->adap.dev.parent,
"clock rate change rejected\n");
return NOTIFY_STOP;
}
/* scale up */
if (ndata->new_rate > ndata->old_rate)
cdns_i2c_setclk(ndata->new_rate, id);
return NOTIFY_OK;
}
case POST_RATE_CHANGE:
id->input_clk = ndata->new_rate;
/* scale down */
if (ndata->new_rate < ndata->old_rate)
cdns_i2c_setclk(ndata->new_rate, id);
return NOTIFY_OK;
case ABORT_RATE_CHANGE:
/* scale up */
if (ndata->new_rate > ndata->old_rate)
cdns_i2c_setclk(ndata->old_rate, id);
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
/**
* cdns_i2c_suspend - Suspend method for the driver
* @_dev: Address of the platform_device structure
*
* Put the driver into low power mode.
*
* Return: 0 always
*/
static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
{
struct platform_device *pdev = container_of(_dev,
struct platform_device, dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
clk_disable(xi2c->clk);
xi2c->suspended = 1;
return 0;
}
/**
* cdns_i2c_resume - Resume from suspend
* @_dev: Address of the platform_device structure
*
* Resume operation after suspend.
*
* Return: 0 on success and error value on error
*/
static int __maybe_unused cdns_i2c_resume(struct device *_dev)
{
struct platform_device *pdev = container_of(_dev,
struct platform_device, dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(xi2c->clk);
if (ret) {
dev_err(_dev, "Cannot enable clock.\n");
return ret;
}
xi2c->suspended = 0;
return 0;
}
static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
cdns_i2c_resume);
/**
* cdns_i2c_probe - Platform registration call
* @pdev: Handle to the platform device structure
*
* This function does all the memory allocation and registration for the i2c
* device. User can modify the address mode to 10 bit address mode using the
* ioctl call with option I2C_TENBIT.
*
* Return: 0 on success, negative error otherwise
*/
static int cdns_i2c_probe(struct platform_device *pdev)
{
struct resource *r_mem;
struct cdns_i2c *id;
int ret;
id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
if (!id)
return -ENOMEM;
platform_set_drvdata(pdev, id);
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
id->irq = platform_get_irq(pdev, 0);
id->adap.dev.of_node = pdev->dev.of_node;
id->adap.algo = &cdns_i2c_algo;
id->adap.timeout = CDNS_I2C_TIMEOUT;
id->adap.retries = 3; /* Default retry value. */
id->adap.algo_data = id;
id->adap.dev.parent = &pdev->dev;
init_completion(&id->xfer_done);
snprintf(id->adap.name, sizeof(id->adap.name),
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
id->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(id->clk)) {
dev_err(&pdev->dev, "input clock not found.\n");
return PTR_ERR(id->clk);
}
ret = clk_prepare_enable(id->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable clock.\n");
return ret;
}
id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
id->input_clk = clk_get_rate(id->clk);
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&id->i2c_clk);
if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;
cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
CDNS_I2C_CR_OFFSET);
ret = cdns_i2c_setclk(id->input_clk, id);
if (ret) {
dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
ret = -EINVAL;
goto err_clk_dis;
}
ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
DRIVER_NAME, id);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
goto err_clk_dis;
}
ret = i2c_add_adapter(&id->adap);
if (ret < 0) {
dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
goto err_clk_dis;
}
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
return 0;
err_clk_dis:
clk_disable_unprepare(id->clk);
return ret;
}
/**
* cdns_i2c_remove - Unregister the device after releasing the resources
* @pdev: Handle to the platform device structure
*
* This function frees all the resources allocated to the device.
*
* Return: 0 always
*/
static int cdns_i2c_remove(struct platform_device *pdev)
{
struct cdns_i2c *id = platform_get_drvdata(pdev);
i2c_del_adapter(&id->adap);
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
clk_disable_unprepare(id->clk);
return 0;
}
static const struct of_device_id cdns_i2c_of_match[] = {
{ .compatible = "cdns,i2c-r1p10", },
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
static struct platform_driver cdns_i2c_drv = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = cdns_i2c_of_match,
.pm = &cdns_i2c_dev_pm_ops,
},
.probe = cdns_i2c_probe,
.remove = cdns_i2c_remove,
};
module_platform_driver(cdns_i2c_drv);
MODULE_AUTHOR("Xilinx Inc.");
MODULE_DESCRIPTION("Cadence I2C bus driver");
MODULE_LICENSE("GPL");

View file

@ -712,7 +712,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter; adap = &dev->adapter;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name)); strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
adap->algo = &i2c_davinci_algo; adap->algo = &i2c_davinci_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;

View file

@ -218,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
* *
* If your hardware is free from tHD;STA issue, try this one. * If your hardware is free from tHD;STA issue, try this one.
*/ */
return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
else else
/* /*
* Conditional expression: * Conditional expression:
@ -234,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
* The reason why we need to take into account "tf" here, * The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt(). * is the same as described in i2c_dw_scl_lcnt().
*/ */
return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset; return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
- 3 + offset;
} }
static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@ -250,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
* account the fall time of SCL signal (tf). Default tf value * account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety. * should be 0.3 us, for safety.
*/ */
return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
} }
static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
u32 input_clock_khz; u32 input_clock_khz;
u32 hcnt, lcnt; u32 hcnt, lcnt;
u32 reg; u32 reg;
u32 sda_falling_time, scl_falling_time;
input_clock_khz = dev->get_clk_rate_khz(dev); input_clock_khz = dev->get_clk_rate_khz(dev);
@ -308,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* set standard and fast speed deviders for high/low periods */ /* set standard and fast speed deviders for high/low periods */
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
/* Standard-mode */ /* Standard-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(input_clock_khz,
40, /* tHD;STA = tHIGH = 4.0 us */ 4000, /* tHD;STA = tHIGH = 4.0 us */
3, /* tf = 0.3 us */ sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz, lcnt = i2c_dw_scl_lcnt(input_clock_khz,
47, /* tLOW = 4.7 us */ 4700, /* tLOW = 4.7 us */
3, /* tf = 0.3 us */ scl_falling_time,
0); /* No offset */ 0); /* No offset */
/* Allow platforms to specify the ideal HCNT and LCNT values */ /* Allow platforms to specify the ideal HCNT and LCNT values */
@ -330,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* Fast-mode */ /* Fast-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(input_clock_khz,
6, /* tHD;STA = tHIGH = 0.6 us */ 600, /* tHD;STA = tHIGH = 0.6 us */
3, /* tf = 0.3 us */ sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz, lcnt = i2c_dw_scl_lcnt(input_clock_khz,
13, /* tLOW = 1.3 us */ 1300, /* tLOW = 1.3 us */
3, /* tf = 0.3 us */ scl_falling_time,
0); /* No offset */ 0); /* No offset */
if (dev->fs_hcnt && dev->fs_lcnt) { if (dev->fs_hcnt && dev->fs_lcnt) {

View file

@ -99,6 +99,8 @@ struct dw_i2c_dev {
unsigned int rx_fifo_depth; unsigned int rx_fifo_depth;
int rx_outstanding; int rx_outstanding;
u32 sda_hold_time; u32 sda_hold_time;
u32 sda_falling_time;
u32 scl_falling_time;
u16 ss_hcnt; u16 ss_hcnt;
u16 ss_lcnt; u16 ss_lcnt;
u16 fs_hcnt; u16 fs_hcnt;

View file

@ -54,6 +54,16 @@ enum dw_pci_ctl_id_t {
medfield_3, medfield_3,
medfield_4, medfield_4,
medfield_5, medfield_5,
baytrail,
};
struct dw_scl_sda_cfg {
u32 ss_hcnt;
u32 fs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
u32 sda_hold;
}; };
struct dw_pci_controller { struct dw_pci_controller {
@ -62,12 +72,29 @@ struct dw_pci_controller {
u32 tx_fifo_depth; u32 tx_fifo_depth;
u32 rx_fifo_depth; u32 rx_fifo_depth;
u32 clk_khz; u32 clk_khz;
u32 functionality;
struct dw_scl_sda_cfg *scl_sda_cfg;
}; };
#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
DW_IC_CON_SLAVE_DISABLE | \ DW_IC_CON_SLAVE_DISABLE | \
DW_IC_CON_RESTART_EN) DW_IC_CON_RESTART_EN)
#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
};
static struct dw_pci_controller dw_pci_controllers[] = { static struct dw_pci_controller dw_pci_controllers[] = {
[moorestown_0] = { [moorestown_0] = {
.bus_num = 0, .bus_num = 0,
@ -132,75 +159,40 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.rx_fifo_depth = 32, .rx_fifo_depth = 32,
.clk_khz = 25000, .clk_khz = 25000,
}, },
[baytrail] = {
.bus_num = -1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &byt_config,
},
}; };
static struct i2c_algorithm i2c_dw_algo = { static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer, .master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func, .functionality = i2c_dw_func,
}; };
#ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev) static int i2c_dw_pci_suspend(struct device *dev)
{ {
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
int err;
i2c_dw_disable(i2c);
err = pci_save_state(pdev);
if (err) {
dev_err(&pdev->dev, "pci_save_state failed\n");
return err;
}
err = pci_set_power_state(pdev, PCI_D3hot);
if (err) {
dev_err(&pdev->dev, "pci_set_power_state failed\n");
return err;
}
i2c_dw_disable(pci_get_drvdata(pdev));
return 0; return 0;
} }
static int i2c_dw_pci_resume(struct device *dev) static int i2c_dw_pci_resume(struct device *dev)
{ {
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
int err;
u32 enabled;
enabled = i2c_dw_is_enabled(i2c); return i2c_dw_init(pci_get_drvdata(pdev));
if (enabled)
return 0;
err = pci_set_power_state(pdev, PCI_D0);
if (err) {
dev_err(&pdev->dev, "pci_set_power_state() failed\n");
return err;
}
pci_restore_state(pdev);
i2c_dw_init(i2c);
return 0;
} }
#endif
static int i2c_dw_pci_runtime_idle(struct device *dev) static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend,
{ i2c_dw_pci_resume, NULL);
int err = pm_schedule_suspend(dev, 500);
dev_dbg(dev, "runtime_idle called\n");
if (err != 0)
return 0;
return -EBUSY;
}
static const struct dev_pm_ops i2c_dw_pm_ops = {
.resume = i2c_dw_pci_resume,
.suspend = i2c_dw_pci_suspend,
SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
i2c_dw_pci_runtime_idle)
};
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{ {
@ -214,6 +206,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
struct i2c_adapter *adap; struct i2c_adapter *adap;
int r; int r;
struct dw_pci_controller *controller; struct dw_pci_controller *controller;
struct dw_scl_sda_cfg *cfg;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
@ -247,13 +240,18 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
dev->base = pcim_iomap_table(pdev)[0]; dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->functionality = dev->functionality = controller->functionality |
I2C_FUNC_I2C | DW_DEFAULT_FUNCTIONALITY;
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = controller->bus_cfg; dev->master_cfg = controller->bus_cfg;
if (controller->scl_sda_cfg) {
cfg = controller->scl_sda_cfg;
dev->ss_hcnt = cfg->ss_hcnt;
dev->fs_hcnt = cfg->fs_hcnt;
dev->ss_lcnt = cfg->ss_lcnt;
dev->fs_lcnt = cfg->fs_lcnt;
dev->sda_hold_time = cfg->sda_hold;
}
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
@ -270,8 +268,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
adap->algo = &i2c_dw_algo; adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
adap->nr = controller->bus_num; adap->nr = controller->bus_num;
snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
adap->nr); snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED, r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
adap->name, dev); adap->name, dev);
@ -290,6 +288,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
pm_runtime_allow(&pdev->dev); pm_runtime_allow(&pdev->dev);
return 0; return 0;
@ -309,7 +308,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
/* work with hotplug and coldplug */ /* work with hotplug and coldplug */
MODULE_ALIAS("i2c_designware-pci"); MODULE_ALIAS("i2c_designware-pci");
static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { static const struct pci_device_id i2_designware_pci_ids[] = {
/* Moorestown */ /* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
@ -321,6 +320,14 @@ static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
/* Baytrail */
{ PCI_VDEVICE(INTEL, 0x0F41), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F42), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F43), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F44), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F45), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F46), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F47), baytrail },
{ 0,} { 0,}
}; };
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);

View file

@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev)
"i2c-sda-hold-time-ns", &ht); "i2c-sda-hold-time-ns", &ht);
dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
1000000); 1000000);
of_property_read_u32(pdev->dev.of_node,
"i2c-sda-falling-time-ns",
&dev->sda_falling_time);
of_property_read_u32(pdev->dev.of_node,
"i2c-scl-falling-time-ns",
&dev->scl_falling_time);
} }
dev->functionality = dev->functionality =
@ -195,7 +202,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter; adap = &dev->adapter;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "Synopsys DesignWare I2C adapter", strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
sizeof(adap->name)); sizeof(adap->name));
adap->algo = &i2c_dw_algo; adap->algo = &i2c_dw_algo;

View file

@ -0,0 +1,481 @@
/*
* Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/clk.h>
#define DRIVER_NAME "efm32-i2c"
#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
#define REG_CTRL 0x00
#define REG_CTRL_EN 0x00001
#define REG_CTRL_SLAVE 0x00002
#define REG_CTRL_AUTOACK 0x00004
#define REG_CTRL_AUTOSE 0x00008
#define REG_CTRL_AUTOSN 0x00010
#define REG_CTRL_ARBDIS 0x00020
#define REG_CTRL_GCAMEN 0x00040
#define REG_CTRL_CLHR__MASK 0x00300
#define REG_CTRL_BITO__MASK 0x03000
#define REG_CTRL_BITO_OFF 0x00000
#define REG_CTRL_BITO_40PCC 0x01000
#define REG_CTRL_BITO_80PCC 0x02000
#define REG_CTRL_BITO_160PCC 0x03000
#define REG_CTRL_GIBITO 0x08000
#define REG_CTRL_CLTO__MASK 0x70000
#define REG_CTRL_CLTO_OFF 0x00000
#define REG_CMD 0x04
#define REG_CMD_START 0x00001
#define REG_CMD_STOP 0x00002
#define REG_CMD_ACK 0x00004
#define REG_CMD_NACK 0x00008
#define REG_CMD_CONT 0x00010
#define REG_CMD_ABORT 0x00020
#define REG_CMD_CLEARTX 0x00040
#define REG_CMD_CLEARPC 0x00080
#define REG_STATE 0x08
#define REG_STATE_BUSY 0x00001
#define REG_STATE_MASTER 0x00002
#define REG_STATE_TRANSMITTER 0x00004
#define REG_STATE_NACKED 0x00008
#define REG_STATE_BUSHOLD 0x00010
#define REG_STATE_STATE__MASK 0x000e0
#define REG_STATE_STATE_IDLE 0x00000
#define REG_STATE_STATE_WAIT 0x00020
#define REG_STATE_STATE_START 0x00040
#define REG_STATE_STATE_ADDR 0x00060
#define REG_STATE_STATE_ADDRACK 0x00080
#define REG_STATE_STATE_DATA 0x000a0
#define REG_STATE_STATE_DATAACK 0x000c0
#define REG_STATUS 0x0c
#define REG_STATUS_PSTART 0x00001
#define REG_STATUS_PSTOP 0x00002
#define REG_STATUS_PACK 0x00004
#define REG_STATUS_PNACK 0x00008
#define REG_STATUS_PCONT 0x00010
#define REG_STATUS_PABORT 0x00020
#define REG_STATUS_TXC 0x00040
#define REG_STATUS_TXBL 0x00080
#define REG_STATUS_RXDATAV 0x00100
#define REG_CLKDIV 0x10
#define REG_CLKDIV_DIV__MASK 0x001ff
#define REG_CLKDIV_DIV(div) MASK_VAL(REG_CLKDIV_DIV__MASK, (div))
#define REG_SADDR 0x14
#define REG_SADDRMASK 0x18
#define REG_RXDATA 0x1c
#define REG_RXDATAP 0x20
#define REG_TXDATA 0x24
#define REG_IF 0x28
#define REG_IF_START 0x00001
#define REG_IF_RSTART 0x00002
#define REG_IF_ADDR 0x00004
#define REG_IF_TXC 0x00008
#define REG_IF_TXBL 0x00010
#define REG_IF_RXDATAV 0x00020
#define REG_IF_ACK 0x00040
#define REG_IF_NACK 0x00080
#define REG_IF_MSTOP 0x00100
#define REG_IF_ARBLOST 0x00200
#define REG_IF_BUSERR 0x00400
#define REG_IF_BUSHOLD 0x00800
#define REG_IF_TXOF 0x01000
#define REG_IF_RXUF 0x02000
#define REG_IF_BITO 0x04000
#define REG_IF_CLTO 0x08000
#define REG_IF_SSTOP 0x10000
#define REG_IFS 0x2c
#define REG_IFC 0x30
#define REG_IFC__MASK 0x1ffcf
#define REG_IEN 0x34
#define REG_ROUTE 0x38
#define REG_ROUTE_SDAPEN 0x00001
#define REG_ROUTE_SCLPEN 0x00002
#define REG_ROUTE_LOCATION__MASK 0x00700
#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
struct efm32_i2c_ddata {
struct i2c_adapter adapter;
struct clk *clk;
void __iomem *base;
unsigned int irq;
u8 location;
unsigned long frequency;
/* transfer data */
struct completion done;
struct i2c_msg *msgs;
size_t num_msgs;
size_t current_word, current_msg;
int retval;
};
static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset)
{
return readl(ddata->base + offset);
}
static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata,
unsigned offset, u32 value)
{
writel(value, ddata->base + offset);
}
static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 |
(cur_msg->flags & I2C_M_RD ? 1 : 0));
}
static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
if (ddata->current_word >= cur_msg->len) {
/* cur_msg completely transferred */
ddata->current_word = 0;
ddata->current_msg += 1;
if (ddata->current_msg >= ddata->num_msgs) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_msg(ddata);
}
} else {
efm32_i2c_write32(ddata, REG_TXDATA,
cur_msg->buf[ddata->current_word++]);
}
}
static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA);
ddata->current_word += 1;
if (ddata->current_word >= cur_msg->len) {
/* cur_msg completely transferred */
ddata->current_word = 0;
ddata->current_msg += 1;
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK);
if (ddata->current_msg >= ddata->num_msgs) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_msg(ddata);
}
} else {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK);
}
}
static irqreturn_t efm32_i2c_irq(int irq, void *dev_id)
{
struct efm32_i2c_ddata *ddata = dev_id;
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
u32 irqflag = efm32_i2c_read32(ddata, REG_IF);
u32 state = efm32_i2c_read32(ddata, REG_STATE);
efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK);
switch (state & REG_STATE_STATE__MASK) {
case REG_STATE_STATE_IDLE:
/* arbitration lost? */
ddata->retval = -EAGAIN;
complete(&ddata->done);
break;
case REG_STATE_STATE_WAIT:
/*
* huh, this shouldn't happen.
* Reset hardware state and get out
*/
ddata->retval = -EIO;
efm32_i2c_write32(ddata, REG_CMD,
REG_CMD_STOP | REG_CMD_ABORT |
REG_CMD_CLEARTX | REG_CMD_CLEARPC);
complete(&ddata->done);
break;
case REG_STATE_STATE_START:
/* "caller" is expected to send an address */
break;
case REG_STATE_STATE_ADDR:
/* wait for Ack or NAck of slave */
break;
case REG_STATE_STATE_ADDRACK:
if (state & REG_STATE_NACKED) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
ddata->retval = -ENXIO;
complete(&ddata->done);
} else if (cur_msg->flags & I2C_M_RD) {
/* wait for slave to send first data byte */
} else {
efm32_i2c_send_next_byte(ddata);
}
break;
case REG_STATE_STATE_DATA:
if (cur_msg->flags & I2C_M_RD) {
efm32_i2c_recv_next_byte(ddata);
} else {
/* wait for Ack or Nack of slave */
}
break;
case REG_STATE_STATE_DATAACK:
if (state & REG_STATE_NACKED) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_byte(ddata);
}
}
return IRQ_HANDLED;
}
static int efm32_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap);
int ret;
if (ddata->msgs)
return -EBUSY;
ddata->msgs = msgs;
ddata->num_msgs = num;
ddata->current_word = 0;
ddata->current_msg = 0;
ddata->retval = -EIO;
reinit_completion(&ddata->done);
dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n",
efm32_i2c_read32(ddata, REG_STATE),
efm32_i2c_read32(ddata, REG_STATUS));
efm32_i2c_send_next_msg(ddata);
wait_for_completion(&ddata->done);
if (ddata->current_msg >= ddata->num_msgs)
ret = ddata->num_msgs;
else
ret = ddata->retval;
return ret;
}
static u32 efm32_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm efm32_i2c_algo = {
.master_xfer = efm32_i2c_master_xfer,
.functionality = efm32_i2c_functionality,
};
static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata)
{
u32 reg = efm32_i2c_read32(ddata, REG_ROUTE);
return (reg & REG_ROUTE_LOCATION__MASK) >>
__ffs(REG_ROUTE_LOCATION__MASK);
}
static int efm32_i2c_probe(struct platform_device *pdev)
{
struct efm32_i2c_ddata *ddata;
struct resource *res;
unsigned long rate;
struct device_node *np = pdev->dev.of_node;
u32 location, frequency;
int ret;
u32 clkdiv;
if (!np)
return -EINVAL;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata) {
dev_dbg(&pdev->dev, "failed to allocate private data\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, ddata);
init_completion(&ddata->done);
strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name));
ddata->adapter.owner = THIS_MODULE;
ddata->adapter.algo = &efm32_i2c_algo;
ddata->adapter.dev.parent = &pdev->dev;
ddata->adapter.dev.of_node = pdev->dev.of_node;
i2c_set_adapdata(&ddata->adapter, ddata);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
ret = PTR_ERR(ddata->clk);
dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to determine base address\n");
return -ENODEV;
}
if (resource_size(res) < 0x42) {
dev_err(&pdev->dev, "memory resource too small\n");
return -EINVAL;
}
ddata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ddata->base))
return PTR_ERR(ddata->base);
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
if (!ret)
ret = -EINVAL;
return ret;
}
ddata->irq = ret;
ret = clk_prepare_enable(ddata->clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
return ret;
}
ret = of_property_read_u32(np, "efm32,location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
/* default to location configured in hardware */
location = efm32_i2c_get_configured_location(ddata);
dev_info(&pdev->dev, "fall back to location %u\n", location);
}
ddata->location = location;
ret = of_property_read_u32(np, "clock-frequency", &frequency);
if (!ret) {
dev_dbg(&pdev->dev, "using frequency %u\n", frequency);
} else {
frequency = 100000;
dev_info(&pdev->dev, "defaulting to 100 kHz\n");
}
ddata->frequency = frequency;
rate = clk_get_rate(ddata->clk);
if (!rate) {
dev_err(&pdev->dev, "there is no input clock available\n");
ret = -EINVAL;
goto err_disable_clk;
}
clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1;
if (clkdiv >= 0x200) {
dev_err(&pdev->dev,
"input clock too fast (%lu) to divide down to bus freq (%lu)",
rate, ddata->frequency);
ret = -EINVAL;
goto err_disable_clk;
}
dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n",
rate, ddata->frequency, (unsigned long)clkdiv);
efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv));
efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN |
REG_ROUTE_SCLPEN |
REG_ROUTE_LOCATION(ddata->location));
efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN |
REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO);
efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK);
efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK
| REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV);
/* to make bus idle */
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT);
ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
return ret;
}
ret = i2c_add_adapter(&ddata->adapter);
if (ret) {
dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret);
free_irq(ddata->irq, ddata);
err_disable_clk:
clk_disable_unprepare(ddata->clk);
}
return ret;
}
static int efm32_i2c_remove(struct platform_device *pdev)
{
struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev);
i2c_del_adapter(&ddata->adapter);
free_irq(ddata->irq, ddata);
clk_disable_unprepare(ddata->clk);
return 0;
}
static const struct of_device_id efm32_i2c_dt_ids[] = {
{
.compatible = "energymicro,efm32-i2c",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids);
static struct platform_driver efm32_i2c_driver = {
.probe = efm32_i2c_probe,
.remove = efm32_i2c_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = efm32_i2c_dt_ids,
},
};
module_platform_driver(efm32_i2c_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View file

@ -186,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex);
#define PCI_DEVICE_ID_ML7223_I2C 0x8010 #define PCI_DEVICE_ID_ML7223_I2C 0x8010
#define PCI_DEVICE_ID_ML7831_I2C 0x8817 #define PCI_DEVICE_ID_ML7831_I2C 0x8817
static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { static const struct pci_device_id pch_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },

View file

@ -566,7 +566,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
static int exynos5_i2c_xfer(struct i2c_adapter *adap, static int exynos5_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msgs, int num)
{ {
struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data; struct exynos5_i2c *i2c = adap->algo_data;
int i = 0, ret = 0, stop = 0; int i = 0, ret = 0, stop = 0;
if (i2c->suspended) { if (i2c->suspended) {
@ -715,6 +715,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int exynos5_i2c_suspend_noirq(struct device *dev) static int exynos5_i2c_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
@ -745,6 +746,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
return 0; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq, static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
exynos5_i2c_resume_noirq); exynos5_i2c_resume_noirq);

View file

@ -94,6 +94,9 @@ static int of_i2c_gpio_get_pins(struct device_node *np,
*sda_pin = of_get_gpio(np, 0); *sda_pin = of_get_gpio(np, 0);
*scl_pin = of_get_gpio(np, 1); *scl_pin = of_get_gpio(np, 1);
if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) {
pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
np->full_name, *sda_pin, *scl_pin); np->full_name, *sda_pin, *scl_pin);

View file

@ -104,7 +104,7 @@ static struct i2c_adapter hydra_adap = {
.algo_data = &hydra_bit_data, .algo_data = &hydra_bit_data,
}; };
static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = { static const struct pci_device_id hydra_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
{ 0, } { 0, }
}; };

View file

@ -60,6 +60,7 @@
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
Coleto Creek (PCH) 0x23b0 32 hard yes yes yes Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
BayTrail (SOC) 0x0f12 32 hard yes yes yes
Features supported by this driver: Features supported by this driver:
Software PEC no Software PEC no
@ -161,6 +162,7 @@
STATUS_ERROR_FLAGS) STATUS_ERROR_FLAGS)
/* Older devices have their ID defined in <linux/pci_ids.h> */ /* Older devices have their ID defined in <linux/pci_ids.h> */
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
@ -789,7 +791,7 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = i801_func, .functionality = i801_func,
}; };
static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
@ -822,6 +824,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
{ 0, } { 0, }
}; };

View file

@ -182,7 +182,7 @@ struct ismt_priv {
/** /**
* ismt_ids - PCI device IDs supported by this driver * ismt_ids - PCI device IDs supported by this driver
*/ */
static DEFINE_PCI_DEVICE_TABLE(ismt_ids) = { static const struct pci_device_id ismt_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },

View file

@ -17,6 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mv643xx_i2c.h> #include <linux/mv643xx_i2c.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
@ -97,7 +98,6 @@ enum {
enum { enum {
MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_OFFLOAD_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_1,
@ -148,6 +148,8 @@ struct mv64xxx_i2c_data {
bool offload_enabled; bool offload_enabled;
/* 5us delay in order to avoid repeated start timing violation */ /* 5us delay in order to avoid repeated start timing violation */
bool errata_delay; bool errata_delay;
struct reset_control *rstc;
bool irq_clear_inverted;
}; };
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@ -176,11 +178,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
{ {
u32 dir = 0; u32 dir = 0;
drv_data->msg = msg;
drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len;
drv_data->aborting = 0;
drv_data->rc = 0;
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
@ -206,11 +203,6 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
if (!drv_data->offload_enabled) if (!drv_data->offload_enabled)
return -EOPNOTSUPP; return -EOPNOTSUPP;
drv_data->msg = msg;
drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len;
drv_data->aborting = 0;
drv_data->rc = 0;
/* Only regular transactions can be offloaded */ /* Only regular transactions can be offloaded */
if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0) if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
return -EINVAL; return -EINVAL;
@ -419,6 +411,23 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
} }
} }
static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
{
drv_data->msg = drv_data->msgs;
drv_data->byte_posn = 0;
drv_data->bytes_left = drv_data->msg->len;
drv_data->aborting = 0;
drv_data->rc = 0;
/* Can we offload this msg ? */
if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
/* No, switch to standard path */
mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
drv_data->reg_base + drv_data->reg_offsets.control);
}
}
static void static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{ {
@ -435,14 +444,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->msgs++; drv_data->msgs++;
drv_data->num_msgs--; drv_data->num_msgs--;
if (mv64xxx_i2c_offload_msg(drv_data) < 0) { mv64xxx_i2c_send_start(drv_data);
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
writel(drv_data->cntl_bits,
drv_data->reg_base + drv_data->reg_offsets.control);
/* Setup for the next message */
mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
}
if (drv_data->errata_delay) if (drv_data->errata_delay)
udelay(5); udelay(5);
@ -459,16 +462,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->reg_base + drv_data->reg_offsets.control); drv_data->reg_base + drv_data->reg_offsets.control);
break; break;
case MV64XXX_I2C_ACTION_SEND_START:
/* Can we offload this msg ? */
if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
/* No, switch to standard path */
mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
drv_data->reg_base + drv_data->reg_offsets.control);
}
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_1: case MV64XXX_I2C_ACTION_SEND_ADDR_1:
writel(drv_data->addr1, writel(drv_data->addr1,
drv_data->reg_base + drv_data->reg_offsets.data); drv_data->reg_base + drv_data->reg_offsets.data);
@ -566,6 +559,11 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
status = readl(drv_data->reg_base + drv_data->reg_offsets.status); status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
mv64xxx_i2c_fsm(drv_data, status); mv64xxx_i2c_fsm(drv_data, status);
mv64xxx_i2c_do_action(drv_data); mv64xxx_i2c_do_action(drv_data);
if (drv_data->irq_clear_inverted)
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_IFLG,
drv_data->reg_base + drv_data->reg_offsets.control);
rc = IRQ_HANDLED; rc = IRQ_HANDLED;
} }
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
@ -626,12 +624,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
spin_lock_irqsave(&drv_data->lock, flags); spin_lock_irqsave(&drv_data->lock, flags);
drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
drv_data->send_stop = is_last; drv_data->send_stop = is_last;
drv_data->block = 1; drv_data->block = 1;
mv64xxx_i2c_do_action(drv_data); mv64xxx_i2c_send_start(drv_data);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
mv64xxx_i2c_wait_for_completion(drv_data); mv64xxx_i2c_wait_for_completion(drv_data);
@ -685,6 +682,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
*/ */
static const struct of_device_id mv64xxx_i2c_of_match_table[] = { static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
@ -759,6 +757,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
} }
drv_data->irq = irq_of_parse_and_map(np, 0); drv_data->irq = irq_of_parse_and_map(np, 0);
drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
if (IS_ERR(drv_data->rstc)) {
if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) {
rc = -EPROBE_DEFER;
goto out;
}
} else {
reset_control_deassert(drv_data->rstc);
}
/* Its not yet defined how timeouts will be specified in device tree. /* Its not yet defined how timeouts will be specified in device tree.
* So hard code the value to 1 second. * So hard code the value to 1 second.
*/ */
@ -783,6 +791,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
drv_data->offload_enabled = false; drv_data->offload_enabled = false;
drv_data->errata_delay = true; drv_data->errata_delay = true;
} }
if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
drv_data->irq_clear_inverted = true;
out: out:
return rc; return rc;
#endif #endif
@ -845,13 +857,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
} }
if (drv_data->irq < 0) { if (drv_data->irq < 0) {
rc = -ENXIO; rc = -ENXIO;
goto exit_clk; goto exit_reset;
} }
drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.owner = THIS_MODULE;
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
drv_data->adapter.nr = pd->id; drv_data->adapter.nr = pd->id;
drv_data->adapter.dev.of_node = pd->dev.of_node; drv_data->adapter.dev.of_node = pd->dev.of_node;
platform_set_drvdata(pd, drv_data); platform_set_drvdata(pd, drv_data);
@ -865,7 +877,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
dev_err(&drv_data->adapter.dev, dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't register intr handler irq%d: %d\n", "mv64xxx: Can't register intr handler irq%d: %d\n",
drv_data->irq, rc); drv_data->irq, rc);
goto exit_clk; goto exit_reset;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev, dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
@ -876,6 +888,9 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_free_irq: exit_free_irq:
free_irq(drv_data->irq, drv_data); free_irq(drv_data->irq, drv_data);
exit_reset:
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
exit_clk: exit_clk:
#if defined(CONFIG_HAVE_CLK) #if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */ /* Not all platforms have a clk */
@ -894,6 +909,8 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter); i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data); free_irq(drv_data->irq, drv_data);
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
#if defined(CONFIG_HAVE_CLK) #if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */ /* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) { if (!IS_ERR(drv_data->clk)) {

View file

@ -806,7 +806,6 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct mxs_i2c_dev *i2c; struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *res; struct resource *res;
resource_size_t res_size;
int err, irq; int err, irq;
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL); i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
@ -819,18 +818,13 @@ static int mxs_i2c_probe(struct platform_device *pdev)
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->regs))
return PTR_ERR(i2c->regs);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0)
if (!res || irq < 0) return irq;
return -ENOENT;
res_size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, res_size, res->name))
return -EBUSY;
i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
if (!i2c->regs)
return -EBUSY;
err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
if (err) if (err)

View file

@ -306,7 +306,7 @@ static struct i2c_algorithm smbus_algorithm = {
}; };
static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { static const struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },

View file

@ -110,22 +110,6 @@ enum i2c_freq_mode {
I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */
}; };
/**
* struct nmk_i2c_controller - client specific controller configuration
* @clk_freq: clock frequency for the operation mode
* @tft: Tx FIFO Threshold in bytes
* @rft: Rx FIFO Threshold in bytes
* @timeout Slave response timeout(ms)
* @sm: speed mode
*/
struct nmk_i2c_controller {
u32 clk_freq;
unsigned char tft;
unsigned char rft;
int timeout;
enum i2c_freq_mode sm;
};
/** /**
* struct i2c_vendor_data - per-vendor variations * struct i2c_vendor_data - per-vendor variations
* @has_mtdws: variant has the MTDWS bit * @has_mtdws: variant has the MTDWS bit
@ -174,12 +158,15 @@ struct i2c_nmk_client {
* @irq: interrupt line for the controller. * @irq: interrupt line for the controller.
* @virtbase: virtual io memory area. * @virtbase: virtual io memory area.
* @clk: hardware i2c block clock. * @clk: hardware i2c block clock.
* @cfg: machine provided controller configuration.
* @cli: holder of client specific data. * @cli: holder of client specific data.
* @clk_freq: clock frequency for the operation mode
* @tft: Tx FIFO Threshold in bytes
* @rft: Rx FIFO Threshold in bytes
* @timeout Slave response timeout (ms)
* @sm: speed mode
* @stop: stop condition. * @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message. * @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result. * @result: controller propogated result.
* @busy: Busy doing transfer.
*/ */
struct nmk_i2c_dev { struct nmk_i2c_dev {
struct i2c_vendor_data *vendor; struct i2c_vendor_data *vendor;
@ -188,12 +175,15 @@ struct nmk_i2c_dev {
int irq; int irq;
void __iomem *virtbase; void __iomem *virtbase;
struct clk *clk; struct clk *clk;
struct nmk_i2c_controller cfg;
struct i2c_nmk_client cli; struct i2c_nmk_client cli;
u32 clk_freq;
unsigned char tft;
unsigned char rft;
int timeout;
enum i2c_freq_mode sm;
int stop; int stop;
struct completion xfer_complete; struct completion xfer_complete;
int result; int result;
bool busy;
}; };
/* controller's abort causes */ /* controller's abort causes */
@ -386,7 +376,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* slsu = cycles / (1000000000 / f) + 1 * slsu = cycles / (1000000000 / f) + 1
*/ */
ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk); ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
switch (dev->cfg.sm) { switch (dev->sm) {
case I2C_FREQ_MODE_FAST: case I2C_FREQ_MODE_FAST:
case I2C_FREQ_MODE_FAST_PLUS: case I2C_FREQ_MODE_FAST_PLUS:
slsu = DIV_ROUND_UP(100, ns); /* Fast */ slsu = DIV_ROUND_UP(100, ns); /* Fast */
@ -409,7 +399,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* 2 whereas it is 3 for fast and fastplus mode of * 2 whereas it is 3 for fast and fastplus mode of
* operation. TODO - high speed support. * operation. TODO - high speed support.
*/ */
div = (dev->cfg.clk_freq > 100000) ? 3 : 2; div = (dev->clk_freq > 100000) ? 3 : 2;
/* /*
* generate the mask for baud rate counters. The controller * generate the mask for baud rate counters. The controller
@ -419,7 +409,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* so set brcr1 to 0. * so set brcr1 to 0.
*/ */
brcr1 = 0 << 16; brcr1 = 0 << 16;
brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff; brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff;
/* set the baud rate counter register */ /* set the baud rate counter register */
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
@ -430,7 +420,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* TODO - support for fast mode plus (up to 1Mb/s) * TODO - support for fast mode plus (up to 1Mb/s)
* and high speed (up to 3.4 Mb/s) * and high speed (up to 3.4 Mb/s)
*/ */
if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { if (dev->sm > I2C_FREQ_MODE_FAST) {
dev_err(&dev->adev->dev, dev_err(&dev->adev->dev,
"do not support this mode defaulting to std. mode\n"); "do not support this mode defaulting to std. mode\n");
brcr2 = i2c_clk/(100000 * 2) & 0xffff; brcr2 = i2c_clk/(100000 * 2) & 0xffff;
@ -438,11 +428,11 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
writel(I2C_FREQ_MODE_STANDARD << 4, writel(I2C_FREQ_MODE_STANDARD << 4,
dev->virtbase + I2C_CR); dev->virtbase + I2C_CR);
} }
writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR); writel(dev->sm << 4, dev->virtbase + I2C_CR);
/* set the Tx and Rx FIFO threshold */ /* set the Tx and Rx FIFO threshold */
writel(dev->cfg.tft, dev->virtbase + I2C_TFTR); writel(dev->tft, dev->virtbase + I2C_TFTR);
writel(dev->cfg.rft, dev->virtbase + I2C_RFTR); writel(dev->rft, dev->virtbase + I2C_RFTR);
} }
/** /**
@ -674,28 +664,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num_msgs) struct i2c_msg msgs[], int num_msgs)
{ {
int status; int status = 0;
int i; int i;
struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
int j; int j;
dev->busy = true;
pm_runtime_get_sync(&dev->adev->dev); pm_runtime_get_sync(&dev->adev->dev);
status = clk_prepare_enable(dev->clk);
if (status) {
dev_err(&dev->adev->dev, "can't prepare_enable clock\n");
goto out_clk;
}
/* Optionaly enable pins to be muxed in and configured */
pinctrl_pm_select_default_state(&dev->adev->dev);
status = init_hw(dev);
if (status)
goto out;
/* Attempt three times to send the message queue */ /* Attempt three times to send the message queue */
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
/* setup the i2c controller */ /* setup the i2c controller */
@ -716,16 +691,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
break; break;
} }
out:
clk_disable_unprepare(dev->clk);
out_clk:
/* Optionally let pins go into idle state */
pinctrl_pm_select_idle_state(&dev->adev->dev);
pm_runtime_put_sync(&dev->adev->dev); pm_runtime_put_sync(&dev->adev->dev);
dev->busy = false;
/* return the no. messages processed */ /* return the no. messages processed */
if (status) if (status)
return status; return status;
@ -909,22 +876,15 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM static int nmk_i2c_suspend_late(struct device *dev)
static int nmk_i2c_suspend(struct device *dev)
{ {
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
if (nmk_i2c->busy)
return -EBUSY;
pinctrl_pm_select_sleep_state(dev); pinctrl_pm_select_sleep_state(dev);
return 0; return 0;
} }
static int nmk_i2c_resume(struct device *dev) static int nmk_i2c_resume_early(struct device *dev)
{ {
/* First go to the default state */ /* First go to the default state */
pinctrl_pm_select_default_state(dev); pinctrl_pm_select_default_state(dev);
@ -933,19 +893,48 @@ static int nmk_i2c_resume(struct device *dev)
return 0; return 0;
} }
#else
#define nmk_i2c_suspend NULL
#define nmk_i2c_resume NULL
#endif #endif
/* #ifdef CONFIG_PM
* We use noirq so that we suspend late and resume before the wakeup interrupt static int nmk_i2c_runtime_suspend(struct device *dev)
* to ensure that we do the !pm_runtime_suspended() check in resume before {
* there has been a regular pm runtime resume (via pm_runtime_get_sync()). struct amba_device *adev = to_amba_device(dev);
*/ struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
clk_disable_unprepare(nmk_i2c->clk);
pinctrl_pm_select_idle_state(dev);
return 0;
}
static int nmk_i2c_runtime_resume(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
int ret;
ret = clk_prepare_enable(nmk_i2c->clk);
if (ret) {
dev_err(dev, "can't prepare_enable clock\n");
return ret;
}
pinctrl_pm_select_default_state(dev);
ret = init_hw(nmk_i2c);
if (ret) {
clk_disable_unprepare(nmk_i2c->clk);
pinctrl_pm_select_idle_state(dev);
}
return ret;
}
#endif
static const struct dev_pm_ops nmk_i2c_pm = { static const struct dev_pm_ops nmk_i2c_pm = {
.suspend_noirq = nmk_i2c_suspend, SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early)
.resume_noirq = nmk_i2c_resume, SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
nmk_i2c_runtime_resume,
NULL)
}; };
static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
@ -958,118 +947,98 @@ static const struct i2c_algorithm nmk_i2c_algo = {
.functionality = nmk_i2c_functionality .functionality = nmk_i2c_functionality
}; };
static struct nmk_i2c_controller u8500_i2c = {
.tft = 1, /* Tx FIFO threshold */
.rft = 8, /* Rx FIFO threshold */
.clk_freq = 400000, /* fast mode operation */
.timeout = 200, /* Slave response timeout(ms) */
.sm = I2C_FREQ_MODE_FAST,
};
static void nmk_i2c_of_probe(struct device_node *np, static void nmk_i2c_of_probe(struct device_node *np,
struct nmk_i2c_controller *pdata) struct nmk_i2c_dev *nmk)
{ {
of_property_read_u32(np, "clock-frequency", &pdata->clk_freq); /* Default to 100 kHz if no frequency is given in the node */
if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq))
nmk->clk_freq = 100000;
/* This driver only supports 'standard' and 'fast' modes of operation. */ /* This driver only supports 'standard' and 'fast' modes of operation. */
if (pdata->clk_freq <= 100000) if (nmk->clk_freq <= 100000)
pdata->sm = I2C_FREQ_MODE_STANDARD; nmk->sm = I2C_FREQ_MODE_STANDARD;
else else
pdata->sm = I2C_FREQ_MODE_FAST; nmk->sm = I2C_FREQ_MODE_FAST;
nmk->tft = 1; /* Tx FIFO threshold */
nmk->rft = 8; /* Rx FIFO threshold */
nmk->timeout = 200; /* Slave response timeout(ms) */
} }
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{ {
int ret = 0; int ret = 0;
struct nmk_i2c_controller *pdata = dev_get_platdata(&adev->dev);
struct device_node *np = adev->dev.of_node; struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev; struct nmk_i2c_dev *dev;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct i2c_vendor_data *vendor = id->data; struct i2c_vendor_data *vendor = id->data;
u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
if (!pdata) { dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
if (np) {
pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto err_no_mem;
}
/* Provide the default configuration as a base. */
memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller));
nmk_i2c_of_probe(np, pdata);
} else
/* No i2c configuration found, using the default. */
pdata = &u8500_i2c;
}
if (pdata->tft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
pdata->tft, max_fifo_threshold);
pdata->tft = max_fifo_threshold;
}
if (pdata->rft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
pdata->rft, max_fifo_threshold);
pdata->rft = max_fifo_threshold;
}
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
if (!dev) { if (!dev) {
dev_err(&adev->dev, "cannot allocate memory\n"); dev_err(&adev->dev, "cannot allocate memory\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_no_mem; goto err_no_mem;
} }
dev->vendor = vendor; dev->vendor = vendor;
dev->busy = false;
dev->adev = adev; dev->adev = adev;
nmk_i2c_of_probe(np, dev);
if (dev->tft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
dev->tft, max_fifo_threshold);
dev->tft = max_fifo_threshold;
}
if (dev->rft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
dev->rft, max_fifo_threshold);
dev->rft = max_fifo_threshold;
}
amba_set_drvdata(adev, dev); amba_set_drvdata(adev, dev);
/* Select default pin state */ dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
pinctrl_pm_select_default_state(&adev->dev); resource_size(&adev->res));
/* If possible, let's go to idle until the first transfer */ if (IS_ERR(dev->virtbase)) {
pinctrl_pm_select_idle_state(&adev->dev);
dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
if (!dev->virtbase) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_no_ioremap; goto err_no_mem;
} }
dev->irq = adev->irq[0]; dev->irq = adev->irq[0];
ret = request_irq(dev->irq, i2c_irq_handler, 0, ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
DRIVER_NAME, dev); DRIVER_NAME, dev);
if (ret) { if (ret) {
dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq); dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
goto err_irq; goto err_no_mem;
} }
pm_suspend_ignore_children(&adev->dev, true); pm_suspend_ignore_children(&adev->dev, true);
dev->clk = clk_get(&adev->dev, NULL); dev->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(dev->clk)) { if (IS_ERR(dev->clk)) {
dev_err(&adev->dev, "could not get i2c clock\n"); dev_err(&adev->dev, "could not get i2c clock\n");
ret = PTR_ERR(dev->clk); ret = PTR_ERR(dev->clk);
goto err_no_clk; goto err_no_mem;
} }
ret = clk_prepare_enable(dev->clk);
if (ret) {
dev_err(&adev->dev, "can't prepare_enable clock\n");
goto err_no_mem;
}
init_hw(dev);
adap = &dev->adap; adap = &dev->adap;
adap->dev.of_node = np; adap->dev.of_node = np;
adap->dev.parent = &adev->dev; adap->dev.parent = &adev->dev;
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
adap->algo = &nmk_i2c_algo; adap->algo = &nmk_i2c_algo;
adap->timeout = msecs_to_jiffies(pdata->timeout); adap->timeout = msecs_to_jiffies(dev->timeout);
snprintf(adap->name, sizeof(adap->name), snprintf(adap->name, sizeof(adap->name),
"Nomadik I2C at %pR", &adev->res); "Nomadik I2C at %pR", &adev->res);
/* fetch the controller configuration from machine */
dev->cfg.clk_freq = pdata->clk_freq;
dev->cfg.tft = pdata->tft;
dev->cfg.rft = pdata->rft;
dev->cfg.sm = pdata->sm;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
dev_info(&adev->dev, dev_info(&adev->dev,
@ -1079,21 +1048,15 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
ret = i2c_add_adapter(adap); ret = i2c_add_adapter(adap);
if (ret) { if (ret) {
dev_err(&adev->dev, "failed to add adapter\n"); dev_err(&adev->dev, "failed to add adapter\n");
goto err_add_adap; goto err_no_adap;
} }
pm_runtime_put(&adev->dev); pm_runtime_put(&adev->dev);
return 0; return 0;
err_add_adap: err_no_adap:
clk_put(dev->clk); clk_disable_unprepare(dev->clk);
err_no_clk:
free_irq(dev->irq, dev);
err_irq:
iounmap(dev->virtbase);
err_no_ioremap:
kfree(dev);
err_no_mem: err_no_mem:
return ret; return ret;
@ -1110,13 +1073,9 @@ static int nmk_i2c_remove(struct amba_device *adev)
clear_all_interrupts(dev); clear_all_interrupts(dev);
/* 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);
free_irq(dev->irq, dev); clk_disable_unprepare(dev->clk);
iounmap(dev->virtbase);
if (res) if (res)
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
clk_put(dev->clk);
pm_runtime_disable(&adev->dev);
kfree(dev);
return 0; return 0;
} }

View file

@ -246,7 +246,7 @@ static const struct i2c_algorithm ocores_algorithm = {
static struct i2c_adapter ocores_adapter = { static struct i2c_adapter ocores_adapter = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "i2c-ocores", .name = "i2c-ocores",
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
.algo = &ocores_algorithm, .algo = &ocores_algorithm,
}; };

View file

@ -636,7 +636,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
int r; int r;
r = pm_runtime_get_sync(dev->dev); r = pm_runtime_get_sync(dev->dev);
if (IS_ERR_VALUE(r)) if (r < 0)
goto out; goto out;
r = omap_i2c_wait_for_bb(dev); r = omap_i2c_wait_for_bb(dev);
@ -1155,7 +1155,7 @@ omap_i2c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev->dev); pm_runtime_use_autosuspend(dev->dev);
r = pm_runtime_get_sync(dev->dev); r = pm_runtime_get_sync(dev->dev);
if (IS_ERR_VALUE(r)) if (r < 0)
goto err_free_mem; goto err_free_mem;
/* /*
@ -1238,7 +1238,7 @@ omap_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter; adap = &dev->adapter;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
adap->algo = &omap_i2c_algo; adap->algo = &omap_i2c_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
@ -1276,7 +1276,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter); i2c_del_adapter(&dev->adapter);
ret = pm_runtime_get_sync(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (IS_ERR_VALUE(ret)) if (ret < 0)
return ret; return ret;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);

View file

@ -401,7 +401,7 @@ static void pasemi_smb_remove(struct pci_dev *dev)
kfree(smbus); kfree(smbus);
} }
static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { static const struct pci_device_id pasemi_smb_ids[] = {
{ PCI_DEVICE(0x1959, 0xa003) }, { PCI_DEVICE(0x1959, 0xa003) },
{ 0, } { 0, }
}; };

View file

@ -540,7 +540,7 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = piix4_func, .functionality = piix4_func,
}; };
static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },

View file

@ -148,7 +148,7 @@ static void ce4100_i2c_remove(struct pci_dev *dev)
kfree(sds); kfree(sds);
} }
static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = { static const struct pci_device_id ce4100_i2c_devices[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
{ }, { },
}; };

View file

@ -0,0 +1,768 @@
/*
* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2014, Sony Mobile Communications AB.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
/* QUP Registers */
#define QUP_CONFIG 0x000
#define QUP_STATE 0x004
#define QUP_IO_MODE 0x008
#define QUP_SW_RESET 0x00c
#define QUP_OPERATIONAL 0x018
#define QUP_ERROR_FLAGS 0x01c
#define QUP_ERROR_FLAGS_EN 0x020
#define QUP_HW_VERSION 0x030
#define QUP_MX_OUTPUT_CNT 0x100
#define QUP_OUT_FIFO_BASE 0x110
#define QUP_MX_WRITE_CNT 0x150
#define QUP_MX_INPUT_CNT 0x200
#define QUP_MX_READ_CNT 0x208
#define QUP_IN_FIFO_BASE 0x218
#define QUP_I2C_CLK_CTL 0x400
#define QUP_I2C_STATUS 0x404
/* QUP States and reset values */
#define QUP_RESET_STATE 0
#define QUP_RUN_STATE 1
#define QUP_PAUSE_STATE 3
#define QUP_STATE_MASK 3
#define QUP_STATE_VALID BIT(2)
#define QUP_I2C_MAST_GEN BIT(4)
#define QUP_OPERATIONAL_RESET 0x000ff0
#define QUP_I2C_STATUS_RESET 0xfffffc
/* QUP OPERATIONAL FLAGS */
#define QUP_I2C_NACK_FLAG BIT(3)
#define QUP_OUT_NOT_EMPTY BIT(4)
#define QUP_IN_NOT_EMPTY BIT(5)
#define QUP_OUT_FULL BIT(6)
#define QUP_OUT_SVC_FLAG BIT(8)
#define QUP_IN_SVC_FLAG BIT(9)
#define QUP_MX_OUTPUT_DONE BIT(10)
#define QUP_MX_INPUT_DONE BIT(11)
/* I2C mini core related values */
#define QUP_CLOCK_AUTO_GATE BIT(13)
#define I2C_MINI_CORE (2 << 8)
#define I2C_N_VAL 15
/* Most significant word offset in FIFO port */
#define QUP_MSW_SHIFT (I2C_N_VAL + 1)
/* Packing/Unpacking words in FIFOs, and IO modes */
#define QUP_OUTPUT_BLK_MODE (1 << 10)
#define QUP_INPUT_BLK_MODE (1 << 12)
#define QUP_UNPACK_EN BIT(14)
#define QUP_PACK_EN BIT(15)
#define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN)
#define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
#define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07)
#define QUP_INPUT_BLOCK_SIZE(x) (((x) >> 5) & 0x03)
#define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07)
/* QUP tags */
#define QUP_TAG_START (1 << 8)
#define QUP_TAG_DATA (2 << 8)
#define QUP_TAG_STOP (3 << 8)
#define QUP_TAG_REC (4 << 8)
/* Status, Error flags */
#define I2C_STATUS_WR_BUFFER_FULL BIT(0)
#define I2C_STATUS_BUS_ACTIVE BIT(8)
#define I2C_STATUS_ERROR_MASK 0x38000fc
#define QUP_STATUS_ERROR_FLAGS 0x7c
#define QUP_READ_LIMIT 256
struct qup_i2c_dev {
struct device *dev;
void __iomem *base;
int irq;
struct clk *clk;
struct clk *pclk;
struct i2c_adapter adap;
int clk_ctl;
int out_fifo_sz;
int in_fifo_sz;
int out_blk_sz;
int in_blk_sz;
unsigned long one_byte_t;
struct i2c_msg *msg;
/* Current posion in user message buffer */
int pos;
/* I2C protocol errors */
u32 bus_err;
/* QUP core errors */
u32 qup_err;
struct completion xfer;
};
static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
{
struct qup_i2c_dev *qup = dev;
u32 bus_err;
u32 qup_err;
u32 opflags;
bus_err = readl(qup->base + QUP_I2C_STATUS);
qup_err = readl(qup->base + QUP_ERROR_FLAGS);
opflags = readl(qup->base + QUP_OPERATIONAL);
if (!qup->msg) {
/* Clear Error interrupt */
writel(QUP_RESET_STATE, qup->base + QUP_STATE);
return IRQ_HANDLED;
}
bus_err &= I2C_STATUS_ERROR_MASK;
qup_err &= QUP_STATUS_ERROR_FLAGS;
if (qup_err) {
/* Clear Error interrupt */
writel(qup_err, qup->base + QUP_ERROR_FLAGS);
goto done;
}
if (bus_err) {
/* Clear Error interrupt */
writel(QUP_RESET_STATE, qup->base + QUP_STATE);
goto done;
}
if (opflags & QUP_IN_SVC_FLAG)
writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
if (opflags & QUP_OUT_SVC_FLAG)
writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
done:
qup->qup_err = qup_err;
qup->bus_err = bus_err;
complete(&qup->xfer);
return IRQ_HANDLED;
}
static int qup_i2c_poll_state_mask(struct qup_i2c_dev *qup,
u32 req_state, u32 req_mask)
{
int retries = 1;
u32 state;
/*
* State transition takes 3 AHB clocks cycles + 3 I2C master clock
* cycles. So retry once after a 1uS delay.
*/
do {
state = readl(qup->base + QUP_STATE);
if (state & QUP_STATE_VALID &&
(state & req_mask) == req_state)
return 0;
udelay(1);
} while (retries--);
return -ETIMEDOUT;
}
static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
{
return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
}
static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
{
return qup_i2c_poll_state_mask(qup, 0, 0);
}
static int qup_i2c_poll_state_i2c_master(struct qup_i2c_dev *qup)
{
return qup_i2c_poll_state_mask(qup, QUP_I2C_MAST_GEN, QUP_I2C_MAST_GEN);
}
static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
{
if (qup_i2c_poll_state_valid(qup) != 0)
return -EIO;
writel(state, qup->base + QUP_STATE);
if (qup_i2c_poll_state(qup, state) != 0)
return -EIO;
return 0;
}
static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
{
unsigned long timeout;
u32 opflags;
u32 status;
timeout = jiffies + HZ;
for (;;) {
opflags = readl(qup->base + QUP_OPERATIONAL);
status = readl(qup->base + QUP_I2C_STATUS);
if (!(opflags & QUP_OUT_NOT_EMPTY) &&
!(status & I2C_STATUS_BUS_ACTIVE))
return 0;
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
}
}
static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
/* Number of entries to shift out, including the start */
int total = msg->len + 1;
if (total < qup->out_fifo_sz) {
/* FIFO mode */
writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
writel(total, qup->base + QUP_MX_WRITE_CNT);
} else {
/* BLOCK mode (transfer data on chunks) */
writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
qup->base + QUP_IO_MODE);
writel(total, qup->base + QUP_MX_OUTPUT_CNT);
}
}
static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
u32 addr = msg->addr << 1;
u32 qup_tag;
u32 opflags;
int idx;
u32 val;
if (qup->pos == 0) {
val = QUP_TAG_START | addr;
idx = 1;
} else {
val = 0;
idx = 0;
}
while (qup->pos < msg->len) {
/* Check that there's space in the FIFO for our pair */
opflags = readl(qup->base + QUP_OPERATIONAL);
if (opflags & QUP_OUT_FULL)
break;
if (qup->pos == msg->len - 1)
qup_tag = QUP_TAG_STOP;
else
qup_tag = QUP_TAG_DATA;
if (idx & 1)
val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
else
val = qup_tag | msg->buf[qup->pos];
/* Write out the pair and the last odd value */
if (idx & 1 || qup->pos == msg->len - 1)
writel(val, qup->base + QUP_OUT_FIFO_BASE);
qup->pos++;
idx++;
}
}
static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
unsigned long left;
int ret;
qup->msg = msg;
qup->pos = 0;
enable_irq(qup->irq);
qup_i2c_set_write_mode(qup, msg);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
do {
ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
if (ret)
goto err;
qup_i2c_issue_write(qup, msg);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
left = wait_for_completion_timeout(&qup->xfer, HZ);
if (!left) {
writel(1, qup->base + QUP_SW_RESET);
ret = -ETIMEDOUT;
goto err;
}
if (qup->bus_err || qup->qup_err) {
if (qup->bus_err & QUP_I2C_NACK_FLAG)
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
goto err;
}
} while (qup->pos < msg->len);
/* Wait for the outstanding data in the fifo to drain */
ret = qup_i2c_wait_writeready(qup);
err:
disable_irq(qup->irq);
qup->msg = NULL;
return ret;
}
static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
{
if (len < qup->in_fifo_sz) {
/* FIFO mode */
writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
writel(len, qup->base + QUP_MX_READ_CNT);
} else {
/* BLOCK mode (transfer data on chunks) */
writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
qup->base + QUP_IO_MODE);
writel(len, qup->base + QUP_MX_INPUT_CNT);
}
}
static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
u32 addr, len, val;
addr = (msg->addr << 1) | 1;
/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
writel(val, qup->base + QUP_OUT_FIFO_BASE);
}
static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
u32 opflags;
u32 val = 0;
int idx;
for (idx = 0; qup->pos < msg->len; idx++) {
if ((idx & 1) == 0) {
/* Check that FIFO have data */
opflags = readl(qup->base + QUP_OPERATIONAL);
if (!(opflags & QUP_IN_NOT_EMPTY))
break;
/* Reading 2 words at time */
val = readl(qup->base + QUP_IN_FIFO_BASE);
msg->buf[qup->pos++] = val & 0xFF;
} else {
msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
}
}
}
static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
unsigned long left;
int ret;
/*
* The QUP block will issue a NACK and STOP on the bus when reaching
* the end of the read, the length of the read is specified as one byte
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
*/
if (msg->len > QUP_READ_LIMIT) {
dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
QUP_READ_LIMIT);
return -EINVAL;
}
qup->msg = msg;
qup->pos = 0;
enable_irq(qup->irq);
qup_i2c_set_read_mode(qup, msg->len);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
if (ret)
goto err;
qup_i2c_issue_read(qup, msg);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
do {
left = wait_for_completion_timeout(&qup->xfer, HZ);
if (!left) {
writel(1, qup->base + QUP_SW_RESET);
ret = -ETIMEDOUT;
goto err;
}
if (qup->bus_err || qup->qup_err) {
if (qup->bus_err & QUP_I2C_NACK_FLAG)
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
goto err;
}
qup_i2c_read_fifo(qup, msg);
} while (qup->pos < msg->len);
err:
disable_irq(qup->irq);
qup->msg = NULL;
return ret;
}
static int qup_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[],
int num)
{
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
int ret, idx;
ret = pm_runtime_get_sync(qup->dev);
if (ret)
goto out;
writel(1, qup->base + QUP_SW_RESET);
ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
if (ret)
goto out;
/* Configure QUP as I2C mini core */
writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
for (idx = 0; idx < num; idx++) {
if (msgs[idx].len == 0) {
ret = -EINVAL;
goto out;
}
if (qup_i2c_poll_state_i2c_master(qup)) {
ret = -EIO;
goto out;
}
if (msgs[idx].flags & I2C_M_RD)
ret = qup_i2c_read_one(qup, &msgs[idx]);
else
ret = qup_i2c_write_one(qup, &msgs[idx]);
if (ret)
break;
ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
if (ret)
break;
}
if (ret == 0)
ret = num;
out:
pm_runtime_mark_last_busy(qup->dev);
pm_runtime_put_autosuspend(qup->dev);
return ret;
}
static u32 qup_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}
static const struct i2c_algorithm qup_i2c_algo = {
.master_xfer = qup_i2c_xfer,
.functionality = qup_i2c_func,
};
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
clk_prepare_enable(qup->clk);
clk_prepare_enable(qup->pclk);
}
static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
{
u32 config;
qup_i2c_change_state(qup, QUP_RESET_STATE);
clk_disable_unprepare(qup->clk);
config = readl(qup->base + QUP_CONFIG);
config |= QUP_CLOCK_AUTO_GATE;
writel(config, qup->base + QUP_CONFIG);
clk_disable_unprepare(qup->pclk);
}
static int qup_i2c_probe(struct platform_device *pdev)
{
static const int blk_sizes[] = {4, 16, 32};
struct device_node *node = pdev->dev.of_node;
struct qup_i2c_dev *qup;
unsigned long one_bit_t;
struct resource *res;
u32 io_mode, hw_ver, size;
int ret, fs_div, hs_div;
int src_clk_freq;
u32 clk_freq = 100000;
qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
if (!qup)
return -ENOMEM;
qup->dev = &pdev->dev;
init_completion(&qup->xfer);
platform_set_drvdata(pdev, qup);
of_property_read_u32(node, "clock-frequency", &clk_freq);
/* We support frequencies up to FAST Mode (400KHz) */
if (!clk_freq || clk_freq > 400000) {
dev_err(qup->dev, "clock frequency not supported %d\n",
clk_freq);
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
qup->base = devm_ioremap_resource(qup->dev, res);
if (IS_ERR(qup->base))
return PTR_ERR(qup->base);
qup->irq = platform_get_irq(pdev, 0);
if (qup->irq < 0) {
dev_err(qup->dev, "No IRQ defined\n");
return qup->irq;
}
qup->clk = devm_clk_get(qup->dev, "core");
if (IS_ERR(qup->clk)) {
dev_err(qup->dev, "Could not get core clock\n");
return PTR_ERR(qup->clk);
}
qup->pclk = devm_clk_get(qup->dev, "iface");
if (IS_ERR(qup->pclk)) {
dev_err(qup->dev, "Could not get iface clock\n");
return PTR_ERR(qup->pclk);
}
qup_i2c_enable_clocks(qup);
/*
* Bootloaders might leave a pending interrupt on certain QUP's,
* so we reset the core before registering for interrupts.
*/
writel(1, qup->base + QUP_SW_RESET);
ret = qup_i2c_poll_state_valid(qup);
if (ret)
goto fail;
ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt,
IRQF_TRIGGER_HIGH, "i2c_qup", qup);
if (ret) {
dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq);
goto fail;
}
disable_irq(qup->irq);
hw_ver = readl(qup->base + QUP_HW_VERSION);
dev_dbg(qup->dev, "Revision %x\n", hw_ver);
io_mode = readl(qup->base + QUP_IO_MODE);
/*
* The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
* associated with each byte written/received
*/
size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
if (size >= ARRAY_SIZE(blk_sizes))
return -EIO;
qup->out_blk_sz = blk_sizes[size] / 2;
size = QUP_INPUT_BLOCK_SIZE(io_mode);
if (size >= ARRAY_SIZE(blk_sizes))
return -EIO;
qup->in_blk_sz = blk_sizes[size] / 2;
size = QUP_OUTPUT_FIFO_SIZE(io_mode);
qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
size = QUP_INPUT_FIFO_SIZE(io_mode);
qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
src_clk_freq = clk_get_rate(qup->clk);
fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
hs_div = 3;
qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
/*
* Time it takes for a byte to be clocked out on the bus.
* Each byte takes 9 clock cycles (8 bits + 1 ack).
*/
one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
qup->one_byte_t = one_bit_t * 9;
dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
qup->in_blk_sz, qup->in_fifo_sz,
qup->out_blk_sz, qup->out_fifo_sz);
i2c_set_adapdata(&qup->adap, qup);
qup->adap.algo = &qup_i2c_algo;
qup->adap.dev.parent = qup->dev;
qup->adap.dev.of_node = pdev->dev.of_node;
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
ret = i2c_add_adapter(&qup->adap);
if (ret)
goto fail;
pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(qup->dev);
pm_runtime_set_active(qup->dev);
pm_runtime_enable(qup->dev);
return 0;
fail:
qup_i2c_disable_clocks(qup);
return ret;
}
static int qup_i2c_remove(struct platform_device *pdev)
{
struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
disable_irq(qup->irq);
qup_i2c_disable_clocks(qup);
i2c_del_adapter(&qup->adap);
pm_runtime_disable(qup->dev);
pm_runtime_set_suspended(qup->dev);
return 0;
}
#ifdef CONFIG_PM
static int qup_i2c_pm_suspend_runtime(struct device *device)
{
struct qup_i2c_dev *qup = dev_get_drvdata(device);
dev_dbg(device, "pm_runtime: suspending...\n");
qup_i2c_disable_clocks(qup);
return 0;
}
static int qup_i2c_pm_resume_runtime(struct device *device)
{
struct qup_i2c_dev *qup = dev_get_drvdata(device);
dev_dbg(device, "pm_runtime: resuming...\n");
qup_i2c_enable_clocks(qup);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int qup_i2c_suspend(struct device *device)
{
qup_i2c_pm_suspend_runtime(device);
return 0;
}
static int qup_i2c_resume(struct device *device)
{
qup_i2c_pm_resume_runtime(device);
pm_runtime_mark_last_busy(device);
pm_request_autosuspend(device);
return 0;
}
#endif
static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(
qup_i2c_suspend,
qup_i2c_resume)
SET_RUNTIME_PM_OPS(
qup_i2c_pm_suspend_runtime,
qup_i2c_pm_resume_runtime,
NULL)
};
static const struct of_device_id qup_i2c_dt_match[] = {
{ .compatible = "qcom,i2c-qup-v1.1.1" },
{ .compatible = "qcom,i2c-qup-v2.1.1" },
{ .compatible = "qcom,i2c-qup-v2.2.1" },
{}
};
MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
static struct platform_driver qup_i2c_driver = {
.probe = qup_i2c_probe,
.remove = qup_i2c_remove,
.driver = {
.name = "i2c_qup",
.owner = THIS_MODULE,
.pm = &qup_i2c_qup_pm_ops,
.of_match_table = qup_i2c_dt_match,
},
};
module_platform_driver(qup_i2c_driver);
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c_qup");

View file

@ -638,6 +638,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@ -691,7 +692,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
adap = &priv->adap; adap = &priv->adap;
adap->nr = pdev->id; adap->nr = pdev->id;
adap->algo = &rcar_i2c_algo; adap->algo = &rcar_i2c_algo;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
adap->retries = 3; adap->retries = 3;
adap->dev.parent = dev; adap->dev.parent = dev;
adap->dev.of_node = dev->of_node; adap->dev.of_node = dev->of_node;

View file

@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/*
* Disable the bus so that we won't get any interrupts from now on, or try
* to drive any lines. This is the default state when we don't have
* anything to send/receive.
*
* If there is an event on the bus, or we have a pre-existing event at
* kernel boot time, we may not notice the event and the I2C controller
* will lock the bus with the I2C clock line low indefinitely.
*/
static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
/* Stop driving the I2C pins */
tmp = readl(i2c->regs + S3C2410_IICSTAT);
tmp &= ~S3C2410_IICSTAT_TXRXEN;
writel(tmp, i2c->regs + S3C2410_IICSTAT);
/* We don't expect any interrupts now, and don't want send acks */
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND |
S3C2410_IICCON_ACKEN);
writel(tmp, i2c->regs + S3C2410_IICCON);
}
/* s3c24xx_i2c_set_master /* s3c24xx_i2c_set_master
* *
@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
s3c24xx_i2c_wait_idle(i2c); s3c24xx_i2c_wait_idle(i2c);
s3c24xx_i2c_disable_bus(i2c);
out: out:
i2c->state = STATE_IDLE;
return ret; return ret;
} }
@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{ {
unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
struct s3c2410_platform_i2c *pdata; struct s3c2410_platform_i2c *pdata;
unsigned int freq; unsigned int freq;
@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
writel(iicon, i2c->regs + S3C2410_IICCON); writel(0, i2c->regs + S3C2410_IICCON);
writel(0, i2c->regs + S3C2410_IICSTAT);
/* we need to work out the divisors for the clock... */ /* we need to work out the divisors for the clock... */
if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
writel(0, i2c->regs + S3C2410_IICCON);
dev_err(i2c->dev, "cannot meet bus frequency required\n"); dev_err(i2c->dev, "cannot meet bus frequency required\n");
return -EINVAL; return -EINVAL;
} }
@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* todo - check that the i2c lines aren't being dragged anywhere */ /* todo - check that the i2c lines aren't being dragged anywhere */
dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
readl(i2c->regs + S3C2410_IICCON));
return 0; return 0;
} }
@ -1106,7 +1135,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
i2c->adap.owner = THIS_MODULE; i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.algo = &s3c24xx_i2c_algorithm;
i2c->adap.retries = 2; i2c->adap.retries = 2;
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
i2c->tx_setup = 50; i2c->tx_setup = 50;
init_waitqueue_head(&i2c->wait); init_waitqueue_head(&i2c->wait);

View file

@ -312,7 +312,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
goto out; goto out;
} }
adap = &siic->adapter; adap = &siic->adapter;
adap->class = I2C_CLASS_HWMON; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
siic->base = devm_ioremap_resource(&pdev->dev, mem_res); siic->base = devm_ioremap_resource(&pdev->dev, mem_res);

View file

@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
.algo = &smbus_algorithm, .algo = &smbus_algorithm,
}; };
static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = { static const struct pci_device_id sis5595_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ 0, } { 0, }
}; };

View file

@ -510,7 +510,7 @@ static struct i2c_adapter sis630_adapter = {
.retries = 3 .retries = 3
}; };
static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { static const struct pci_device_id sis630_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },

View file

@ -244,7 +244,7 @@ static struct i2c_adapter sis96x_adapter = {
.algo = &smbus_algorithm, .algo = &smbus_algorithm,
}; };
static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = { static const struct pci_device_id sis96x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
{ 0, } { 0, }
}; };

View file

@ -574,7 +574,7 @@ static irqreturn_t st_i2c_isr_thread(int irq, void *data)
writel_relaxed(it, i2c_dev->base + SSC_IEN); writel_relaxed(it, i2c_dev->base + SSC_IEN);
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
c->result = -EIO; c->result = -EAGAIN;
break; break;
default: default:

View file

@ -911,7 +911,7 @@ static int stu300_probe(struct platform_device *pdev)
adap = &dev->adapter; adap = &dev->adapter;
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
/* DDC class but actually often used for more generic I2C */ /* DDC class but actually often used for more generic I2C */
adap->class = I2C_CLASS_DDC; adap->class = I2C_CLASS_DDC | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "ST Microelectronics DDC I2C adapter", strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
sizeof(adap->name)); sizeof(adap->name));
adap->nr = bus_nr; adap->nr = bus_nr;

View file

@ -794,7 +794,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
i2c_dev->adapter.owner = THIS_MODULE; i2c_dev->adapter.owner = THIS_MODULE;
i2c_dev->adapter.class = I2C_CLASS_HWMON; i2c_dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter", strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
sizeof(i2c_dev->adapter.name)); sizeof(i2c_dev->adapter.name));
i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.algo = &tegra_i2c_algo;

View file

@ -88,7 +88,7 @@ static struct i2c_adapter vt586b_adapter = {
}; };
static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = { static const struct pci_device_id vt586b_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
{ 0, } { 0, }
}; };

View file

@ -442,7 +442,7 @@ release_region:
return error; return error;
} }
static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = { static const struct pci_device_id vt596_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
.driver_data = SMBBA1 }, .driver_data = SMBBA1 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),

View file

@ -684,7 +684,7 @@ static const struct i2c_algorithm xiic_algorithm = {
static struct i2c_adapter xiic_adapter = { static struct i2c_adapter xiic_adapter = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DRIVER_NAME, .name = DRIVER_NAME,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
.algo = &xiic_algorithm, .algo = &xiic_algorithm,
}; };

View file

@ -556,7 +556,7 @@ static struct platform_driver scx200_pci_driver = {
.remove = scx200_remove, .remove = scx200_remove,
}; };
static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = { static const struct pci_device_id scx200_isa[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
{ 0, } { 0, }

View file

@ -48,10 +48,13 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/jump_label.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "i2c-core.h" #include "i2c-core.h"
#define CREATE_TRACE_POINTS
#include <trace/events/i2c.h>
/* core_lock protects i2c_adapter_idr, and guarantees /* core_lock protects i2c_adapter_idr, and guarantees
that device detection, deletion of detected devices, and attach_adapter that device detection, deletion of detected devices, and attach_adapter
@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr);
static struct device_type i2c_client_type; static struct device_type i2c_client_type;
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
void i2c_transfer_trace_reg(void)
{
static_key_slow_inc(&i2c_trace_msg);
}
void i2c_transfer_trace_unreg(void)
{
static_key_slow_dec(&i2c_trace_msg);
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void)
class_compat_unregister(i2c_adapter_compat_class); class_compat_unregister(i2c_adapter_compat_class);
#endif #endif
bus_unregister(&i2c_bus_type); bus_unregister(&i2c_bus_type);
tracepoint_synchronize_unregister();
} }
/* We must initialize early, because some subsystems register i2c drivers /* We must initialize early, because some subsystems register i2c drivers
@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
unsigned long orig_jiffies; unsigned long orig_jiffies;
int ret, try; int ret, try;
/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
* enabled. This is an efficient way of keeping the for-loop from
* being executed when not needed.
*/
if (static_key_false(&i2c_trace_msg)) {
int i;
for (i = 0; i < num; i++)
if (msgs[i].flags & I2C_M_RD)
trace_i2c_read(adap, &msgs[i], i);
else
trace_i2c_write(adap, &msgs[i], i);
}
/* Retry automatically on arbitration loss */ /* Retry automatically on arbitration loss */
orig_jiffies = jiffies; orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) { for (ret = 0, try = 0; try <= adap->retries; try++) {
@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
break; break;
} }
if (static_key_false(&i2c_trace_msg)) {
int i;
for (i = 0; i < ret; i++)
if (msgs[i].flags & I2C_M_RD)
trace_i2c_reply(adap, &msgs[i], i);
trace_i2c_result(adap, i, ret);
}
return ret; return ret;
} }
EXPORT_SYMBOL(__i2c_transfer); EXPORT_SYMBOL(__i2c_transfer);
@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_client *client; struct i2c_client *client;
/* Detection succeeded, instantiate the device */ /* Detection succeeded, instantiate the device */
if (adapter->class & I2C_CLASS_DEPRECATED)
dev_warn(&adapter->dev,
"This adapter will soon drop class based instantiation of devices. "
"Please make sure client 0x%02x gets instantiated by other means. "
"Check 'Documentation/i2c/instantiating-devices' for details.\n",
info.addr);
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
info.type, info.addr); info.type, info.addr);
client = i2c_new_device(adapter, &info); client = i2c_new_device(adapter, &info);
@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
int try; int try;
s32 res; s32 res;
/* If enabled, the following two tracepoints are conditional on
* read_write and protocol.
*/
trace_smbus_write(adapter, addr, flags, read_write,
command, protocol, data);
trace_smbus_read(adapter, addr, flags, read_write,
command, protocol);
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) { if (adapter->algo->smbus_xfer) {
@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
i2c_unlock_adapter(adapter); i2c_unlock_adapter(adapter);
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
return res; goto trace;
/* /*
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn't * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
* implement native support for the SMBus operation. * implement native support for the SMBus operation.
*/ */
} }
return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
command, protocol, data); command, protocol, data);
trace:
/* If enabled, the reply tracepoint is conditional on read_write. */
trace_smbus_reply(adapter, addr, flags, read_write,
command, protocol, data);
trace_smbus_result(adapter, addr, flags, read_write,
command, protocol, res);
return res;
} }
EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_xfer);

View file

@ -487,6 +487,7 @@ void i2c_unlock_adapter(struct i2c_adapter *);
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
#define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */ #define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */
#define I2C_CLASS_SPD (1<<7) /* Memory modules */ #define I2C_CLASS_SPD (1<<7) /* Memory modules */
#define I2C_CLASS_DEPRECATED (1<<8) /* Warn users that adapter will stop using classes */
/* Internal numbers to terminate lists */ /* Internal numbers to terminate lists */
#define I2C_CLIENT_END 0xfffeU #define I2C_CLIENT_END 0xfffeU

View file

@ -0,0 +1,145 @@
/*
* i2c-bfin-twi.h - interface to ADI TWI controller
*
* Copyright 2005-2014 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __I2C_BFIN_TWI_H__
#define __I2C_BFIN_TWI_H__
#include <linux/types.h>
#include <linux/i2c.h>
/*
* ADI twi registers layout
*/
struct bfin_twi_regs {
u16 clkdiv;
u16 dummy1;
u16 control;
u16 dummy2;
u16 slave_ctl;
u16 dummy3;
u16 slave_stat;
u16 dummy4;
u16 slave_addr;
u16 dummy5;
u16 master_ctl;
u16 dummy6;
u16 master_stat;
u16 dummy7;
u16 master_addr;
u16 dummy8;
u16 int_stat;
u16 dummy9;
u16 int_mask;
u16 dummy10;
u16 fifo_ctl;
u16 dummy11;
u16 fifo_stat;
u16 dummy12;
u32 __pad[20];
u16 xmt_data8;
u16 dummy13;
u16 xmt_data16;
u16 dummy14;
u16 rcv_data8;
u16 dummy15;
u16 rcv_data16;
u16 dummy16;
};
struct bfin_twi_iface {
int irq;
spinlock_t lock;
char read_write;
u8 command;
u8 *transPtr;
int readNum;
int writeNum;
int cur_mode;
int manual_stop;
int result;
struct i2c_adapter adap;
struct completion complete;
struct i2c_msg *pmsg;
int msg_num;
int cur_msg;
u16 saved_clkdiv;
u16 saved_control;
struct bfin_twi_regs __iomem *regs_base;
};
/* ******************** TWO-WIRE INTERFACE (TWI) MASKS ********************/
/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y); ) */
#define CLKLOW(x) ((x) & 0xFF) /* Periods Clock Is Held Low */
#define CLKHI(y) (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */
/* TWI_PRESCALE Masks */
#define PRESCALE 0x007F /* SCLKs Per Internal Time Reference (10MHz) */
#define TWI_ENA 0x0080 /* TWI Enable */
#define SCCB 0x0200 /* SCCB Compatibility Enable */
/* TWI_SLAVE_CTL Masks */
#define SEN 0x0001 /* Slave Enable */
#define SADD_LEN 0x0002 /* Slave Address Length */
#define STDVAL 0x0004 /* Slave Transmit Data Valid */
#define NAK 0x0008 /* NAK Generated At Conclusion Of Transfer */
#define GEN 0x0010 /* General Call Address Matching Enabled */
/* TWI_SLAVE_STAT Masks */
#define SDIR 0x0001 /* Slave Transfer Direction (RX/TX*) */
#define GCALL 0x0002 /* General Call Indicator */
/* TWI_MASTER_CTL Masks */
#define MEN 0x0001 /* Master Mode Enable */
#define MADD_LEN 0x0002 /* Master Address Length */
#define MDIR 0x0004 /* Master Transmit Direction (RX/TX*) */
#define FAST 0x0008 /* Use Fast Mode Timing Specs */
#define STOP 0x0010 /* Issue Stop Condition */
#define RSTART 0x0020 /* Repeat Start or Stop* At End Of Transfer */
#define DCNT 0x3FC0 /* Data Bytes To Transfer */
#define SDAOVR 0x4000 /* Serial Data Override */
#define SCLOVR 0x8000 /* Serial Clock Override */
/* TWI_MASTER_STAT Masks */
#define MPROG 0x0001 /* Master Transfer In Progress */
#define LOSTARB 0x0002 /* Lost Arbitration Indicator (Xfer Aborted) */
#define ANAK 0x0004 /* Address Not Acknowledged */
#define DNAK 0x0008 /* Data Not Acknowledged */
#define BUFRDERR 0x0010 /* Buffer Read Error */
#define BUFWRERR 0x0020 /* Buffer Write Error */
#define SDASEN 0x0040 /* Serial Data Sense */
#define SCLSEN 0x0080 /* Serial Clock Sense */
#define BUSBUSY 0x0100 /* Bus Busy Indicator */
/* TWI_INT_SRC and TWI_INT_ENABLE Masks */
#define SINIT 0x0001 /* Slave Transfer Initiated */
#define SCOMP 0x0002 /* Slave Transfer Complete */
#define SERR 0x0004 /* Slave Transfer Error */
#define SOVF 0x0008 /* Slave Overflow */
#define MCOMP 0x0010 /* Master Transfer Complete */
#define MERR 0x0020 /* Master Transfer Error */
#define XMTSERV 0x0040 /* Transmit FIFO Service */
#define RCVSERV 0x0080 /* Receive FIFO Service */
/* TWI_FIFO_CTRL Masks */
#define XMTFLUSH 0x0001 /* Transmit Buffer Flush */
#define RCVFLUSH 0x0002 /* Receive Buffer Flush */
#define XMTINTLEN 0x0004 /* Transmit Buffer Interrupt Length */
#define RCVINTLEN 0x0008 /* Receive Buffer Interrupt Length */
/* TWI_FIFO_STAT Masks */
#define XMTSTAT 0x0003 /* Transmit FIFO Status */
#define XMT_EMPTY 0x0000 /* Transmit FIFO Empty */
#define XMT_HALF 0x0001 /* Transmit FIFO Has 1 Byte To Write */
#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */
#define RCVSTAT 0x000C /* Receive FIFO Status */
#define RCV_EMPTY 0x0000 /* Receive FIFO Empty */
#define RCV_HALF 0x0004 /* Receive FIFO Has 1 Byte To Read */
#define RCV_FULL 0x000C /* Receive FIFO Full (2 Bytes To Read) */
#endif

View file

@ -1,5 +1,4 @@
/* arch/arm/plat-s3c/include/plat/iic.h /*
*
* Copyright 2004-2009 Simtec Electronics * Copyright 2004-2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
@ -10,8 +9,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef __ASM_ARCH_IIC_H #ifndef __I2C_S3C2410_H
#define __ASM_ARCH_IIC_H __FILE__ #define __I2C_S3C2410_H __FILE__
#define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */ #define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */
@ -76,4 +75,4 @@ extern void s3c_i2c7_cfg_gpio(struct platform_device *dev);
extern struct s3c2410_platform_i2c default_i2c_data; extern struct s3c2410_platform_i2c default_i2c_data;
#endif /* __ASM_ARCH_IIC_H */ #endif /* __I2C_S3C2410_H */

372
include/trace/events/i2c.h Normal file
View file

@ -0,0 +1,372 @@
/* I2C and SMBUS message transfer tracepoints
*
* Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM i2c
#if !defined(_TRACE_I2C_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_I2C_H
#include <linux/i2c.h>
#include <linux/tracepoint.h>
/*
* drivers/i2c/i2c-core.c
*/
extern void i2c_transfer_trace_reg(void);
extern void i2c_transfer_trace_unreg(void);
/*
* __i2c_transfer() write request
*/
TRACE_EVENT_FN(i2c_write,
TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
int num),
TP_ARGS(adap, msg, num),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, msg_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u16, len )
__dynamic_array(__u8, buf, msg->len) ),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->msg_nr = num;
__entry->addr = msg->addr;
__entry->flags = msg->flags;
__entry->len = msg->len;
memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
),
TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
__entry->adapter_nr,
__entry->msg_nr,
__entry->addr,
__entry->flags,
__entry->len,
__entry->len, __get_dynamic_array(buf)
),
i2c_transfer_trace_reg,
i2c_transfer_trace_unreg);
/*
* __i2c_transfer() read request
*/
TRACE_EVENT_FN(i2c_read,
TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
int num),
TP_ARGS(adap, msg, num),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, msg_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u16, len )
),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->msg_nr = num;
__entry->addr = msg->addr;
__entry->flags = msg->flags;
__entry->len = msg->len;
),
TP_printk("i2c-%d #%u a=%03x f=%04x l=%u",
__entry->adapter_nr,
__entry->msg_nr,
__entry->addr,
__entry->flags,
__entry->len
),
i2c_transfer_trace_reg,
i2c_transfer_trace_unreg);
/*
* __i2c_transfer() read reply
*/
TRACE_EVENT_FN(i2c_reply,
TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
int num),
TP_ARGS(adap, msg, num),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, msg_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u16, len )
__dynamic_array(__u8, buf, msg->len) ),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->msg_nr = num;
__entry->addr = msg->addr;
__entry->flags = msg->flags;
__entry->len = msg->len;
memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
),
TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
__entry->adapter_nr,
__entry->msg_nr,
__entry->addr,
__entry->flags,
__entry->len,
__entry->len, __get_dynamic_array(buf)
),
i2c_transfer_trace_reg,
i2c_transfer_trace_unreg);
/*
* __i2c_transfer() result
*/
TRACE_EVENT_FN(i2c_result,
TP_PROTO(const struct i2c_adapter *adap, int num, int ret),
TP_ARGS(adap, num, ret),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, nr_msgs )
__field(__s16, ret )
),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->nr_msgs = num;
__entry->ret = ret;
),
TP_printk("i2c-%d n=%u ret=%d",
__entry->adapter_nr,
__entry->nr_msgs,
__entry->ret
),
i2c_transfer_trace_reg,
i2c_transfer_trace_unreg);
/*
* i2c_smbus_xfer() write data or procedure call request
*/
TRACE_EVENT_CONDITION(smbus_write,
TP_PROTO(const struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
const union i2c_smbus_data *data),
TP_ARGS(adap, addr, flags, read_write, command, protocol, data),
TP_CONDITION(read_write == I2C_SMBUS_WRITE ||
protocol == I2C_SMBUS_PROC_CALL ||
protocol == I2C_SMBUS_BLOCK_PROC_CALL),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u8, command )
__field(__u8, len )
__field(__u32, protocol )
__array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->addr = addr;
__entry->flags = flags;
__entry->command = command;
__entry->protocol = protocol;
switch (protocol) {
case I2C_SMBUS_BYTE_DATA:
__entry->len = 1;
goto copy;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
__entry->len = 2;
goto copy;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
case I2C_SMBUS_I2C_BLOCK_DATA:
__entry->len = data->block[0] + 1;
copy:
memcpy(__entry->buf, data->block, __entry->len);
break;
case I2C_SMBUS_QUICK:
case I2C_SMBUS_BYTE:
case I2C_SMBUS_I2C_BLOCK_BROKEN:
default:
__entry->len = 0;
}
),
TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]",
__entry->adapter_nr,
__entry->addr,
__entry->flags,
__entry->command,
__print_symbolic(__entry->protocol,
{ I2C_SMBUS_QUICK, "QUICK" },
{ I2C_SMBUS_BYTE, "BYTE" },
{ I2C_SMBUS_BYTE_DATA, "BYTE_DATA" },
{ I2C_SMBUS_WORD_DATA, "WORD_DATA" },
{ I2C_SMBUS_PROC_CALL, "PROC_CALL" },
{ I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" },
{ I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" },
{ I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
{ I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }),
__entry->len,
__entry->len, __entry->buf
));
/*
* i2c_smbus_xfer() read data request
*/
TRACE_EVENT_CONDITION(smbus_read,
TP_PROTO(const struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command, int protocol),
TP_ARGS(adap, addr, flags, read_write, command, protocol),
TP_CONDITION(!(read_write == I2C_SMBUS_WRITE ||
protocol == I2C_SMBUS_PROC_CALL ||
protocol == I2C_SMBUS_BLOCK_PROC_CALL)),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, flags )
__field(__u16, addr )
__field(__u8, command )
__field(__u32, protocol )
__array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->addr = addr;
__entry->flags = flags;
__entry->command = command;
__entry->protocol = protocol;
),
TP_printk("i2c-%d a=%03x f=%04x c=%x %s",
__entry->adapter_nr,
__entry->addr,
__entry->flags,
__entry->command,
__print_symbolic(__entry->protocol,
{ I2C_SMBUS_QUICK, "QUICK" },
{ I2C_SMBUS_BYTE, "BYTE" },
{ I2C_SMBUS_BYTE_DATA, "BYTE_DATA" },
{ I2C_SMBUS_WORD_DATA, "WORD_DATA" },
{ I2C_SMBUS_PROC_CALL, "PROC_CALL" },
{ I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" },
{ I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" },
{ I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
{ I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" })
));
/*
* i2c_smbus_xfer() read data or procedure call reply
*/
TRACE_EVENT_CONDITION(smbus_reply,
TP_PROTO(const struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
const union i2c_smbus_data *data),
TP_ARGS(adap, addr, flags, read_write, command, protocol, data),
TP_CONDITION(read_write == I2C_SMBUS_READ),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u8, command )
__field(__u8, len )
__field(__u32, protocol )
__array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->addr = addr;
__entry->flags = flags;
__entry->command = command;
__entry->protocol = protocol;
switch (protocol) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
__entry->len = 1;
goto copy;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
__entry->len = 2;
goto copy;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
case I2C_SMBUS_I2C_BLOCK_DATA:
__entry->len = data->block[0] + 1;
copy:
memcpy(__entry->buf, data->block, __entry->len);
break;
case I2C_SMBUS_QUICK:
case I2C_SMBUS_I2C_BLOCK_BROKEN:
default:
__entry->len = 0;
}
),
TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]",
__entry->adapter_nr,
__entry->addr,
__entry->flags,
__entry->command,
__print_symbolic(__entry->protocol,
{ I2C_SMBUS_QUICK, "QUICK" },
{ I2C_SMBUS_BYTE, "BYTE" },
{ I2C_SMBUS_BYTE_DATA, "BYTE_DATA" },
{ I2C_SMBUS_WORD_DATA, "WORD_DATA" },
{ I2C_SMBUS_PROC_CALL, "PROC_CALL" },
{ I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" },
{ I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" },
{ I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
{ I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }),
__entry->len,
__entry->len, __entry->buf
));
/*
* i2c_smbus_xfer() result
*/
TRACE_EVENT(smbus_result,
TP_PROTO(const struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
int res),
TP_ARGS(adap, addr, flags, read_write, command, protocol, res),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, addr )
__field(__u16, flags )
__field(__u8, read_write )
__field(__u8, command )
__field(__s16, res )
__field(__u32, protocol )
),
TP_fast_assign(
__entry->adapter_nr = adap->nr;
__entry->addr = addr;
__entry->flags = flags;
__entry->read_write = read_write;
__entry->command = command;
__entry->protocol = protocol;
__entry->res = res;
),
TP_printk("i2c-%d a=%03x f=%04x c=%x %s %s res=%d",
__entry->adapter_nr,
__entry->addr,
__entry->flags,
__entry->command,
__print_symbolic(__entry->protocol,
{ I2C_SMBUS_QUICK, "QUICK" },
{ I2C_SMBUS_BYTE, "BYTE" },
{ I2C_SMBUS_BYTE_DATA, "BYTE_DATA" },
{ I2C_SMBUS_WORD_DATA, "WORD_DATA" },
{ I2C_SMBUS_PROC_CALL, "PROC_CALL" },
{ I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" },
{ I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" },
{ I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
{ I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }),
__entry->read_write == I2C_SMBUS_WRITE ? "wr" : "rd",
__entry->res
));
#endif /* _TRACE_I2C_H */
/* This part must be outside protection */
#include <trace/define_trace.h>