diff options
64 files changed, 3292 insertions, 501 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt index 4fade84bea16..388f0a275fba 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt @@ -12,6 +12,7 @@ Required properties : - clocks: phandles to input clocks. Optional properties: +- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000 - Child nodes conforming to i2c bus binding Examples : @@ -23,6 +24,7 @@ i2c0: i2c@fff84000 { #address-cells = <1>; #size-cells = <0>; clocks = <&twi0_clk>; + clock-frequency = <400000>; 24c512@50 { compatible = "24c512"; diff --git a/Documentation/devicetree/bindings/i2c/i2c-cadence.txt b/Documentation/devicetree/bindings/i2c/i2c-cadence.txt new file mode 100644 index 000000000000..7cb0b5608f49 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-cadence.txt @@ -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>; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt index 7fd7fa25e9b0..5199b0c8cf7a 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt @@ -14,6 +14,12 @@ Optional properties : - 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. + - 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 : i2c@f0000 { @@ -34,4 +40,6 @@ Example : interrupts = <12 1>; clock-frequency = <400000>; i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <300>; + i2c-scl-falling-time-ns = <300>; }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt b/Documentation/devicetree/bindings/i2c/i2c-efm32.txt new file mode 100644 index 000000000000..fc15ac519437 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-efm32.txt @@ -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>; + }; + }; + diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index 582b4652a82a..befd4fb4764f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -4,12 +4,16 @@ Required properties : - reg : Offset and length of the register set for the device - - compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c" - or "marvell,mv78230-i2c" or "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. + - compatible : Should be either: + - "allwinner,sun4i-i2c" + - "allwinner,sun6i-a31-i2c" + - "marvell,mv64xxx-i2c" + - "marvell,mv78230-i2c" + - "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 Optional properties : @@ -17,6 +21,10 @@ Optional properties : - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the default frequency is 100kHz + - resets : phandle to the parent reset controller. Mandatory + whenever you're using the "allwinner,sun6i-a31-i2c" + compatible. + Examples: i2c@11000 { diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index 897cfcd5ce92..dd8b2dd1edeb 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -6,6 +6,7 @@ Required properties: "renesas,i2c-r8a7778" "renesas,i2c-r8a7779" "renesas,i2c-r8a7790" + "renesas,i2c-r8a7791" - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier. @@ -13,11 +14,16 @@ Required properties: Optional properties: - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this propoerty indicates the default frequency 100 kHz. +- clocks: clock specifier. Examples : -i2c0: i2c@e6500000 { - compatible = "renesas,i2c-rcar-h2"; - reg = <0 0xe6500000 0 0x428>; - interrupts = <0 174 0x4>; +i2c0: i2c@e6508000 { + #address-cells = <1>; + #size-cells = <0>; + 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>; }; diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt b/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt new file mode 100644 index 000000000000..dc71754a56af --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt @@ -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>; + }; diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index aaaf069306a3..adf5e33e8312 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -26,6 +26,7 @@ Supported adapters: * Intel Wellsburg (PCH) * Intel Coleto Creek (PCH) * Intel Wildcat Point-LP (PCH) + * Intel BayTrail (SOC) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality index b0ff2ab596ce..4556a3eb87c4 100644 --- a/Documentation/i2c/functionality +++ b/Documentation/i2c/functionality @@ -46,7 +46,7 @@ A few combinations of the above flags are also defined for your convenience: and write_block_data commands I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data 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 the transparent emulation layer) diff --git a/Documentation/i2c/i2c-protocol b/Documentation/i2c/i2c-protocol index 0b3e62d1f77a..ff6d6cee6c7e 100644 --- a/Documentation/i2c/i2c-protocol +++ b/Documentation/i2c/i2c-protocol @@ -6,8 +6,8 @@ Key to symbols S (1 bit) : Start bit P (1 bit) : Stop bit Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. -A, NA (1 bit) : Accept and reverse accept bit. -Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to +A, NA (1 bit) : Accept and reverse accept bit. +Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to get a 10 bit I2C address. Comm (8 bits): Command byte, a data byte which often selects a register on the device. @@ -49,11 +49,20 @@ a byte read, followed by a byte write: Modified transactions ===================== -The following modifications to the I2C protocol can also be generated, -with the exception of I2C_M_NOSTART these are usually only needed to -work around device issues: +The following modifications to the I2C protocol can also be generated by +setting these flags for i2c messages. With the exception of I2C_M_NOSTART, they +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 point. For example, setting I2C_M_NOSTART on the second partial message generates something like: @@ -67,17 +76,13 @@ work around device issues: I2C device but may also be used between direction changes by some 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 need to emit an Rd instead of a Wr, or vice versa, you set this flag. For example: S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P - Flags 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. - - Flags I2C_M_NO_RD_ACK - In a read message, master A/NA bit is skipped. +I2C_M_STOP: + Force a stop condition (P) after the message. Some I2C related protocols + like SCCB require that. Normally, you really don't want to get interrupted + between the messages of one transfer. diff --git a/MAINTAINERS b/MAINTAINERS index a769432bddbe..beaa87a6e7fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1427,6 +1427,7 @@ F: drivers/cpuidle/cpuidle-zynq.c N: zynq N: xilinx F: drivers/clocksource/cadence_ttc_timer.c +F: drivers/i2c/busses/i2c-cadence.c F: drivers/mmc/host/sdhci-of-arasan.c ARM SMMU DRIVER @@ -4308,7 +4309,8 @@ F: drivers/i2c/i2c-stub.c I2C SUBSYSTEM M: Wolfram Sang <wsa@the-dreams.de> 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 S: Maintained F: Documentation/i2c/ diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h index 90c3c006557d..aaa0834d34aa 100644 --- a/arch/blackfin/include/asm/bfin_twi.h +++ b/arch/blackfin/include/asm/bfin_twi.h @@ -9,60 +9,7 @@ #ifndef __ASM_BFIN_TWI_H__ #define __ASM_BFIN_TWI_H__ -#include <linux/types.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; -}; +#include <asm/blackfin.h> #define DEFINE_TWI_REG(reg_name, reg) \ 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); } DEFINE_TWI_REG(CLKDIV, clkdiv) -DEFINE_TWI_REG(CONTROL, control) DEFINE_TWI_REG(SLAVE_CTL, slave_ctl) DEFINE_TWI_REG(SLAVE_STAT, slave_stat) 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(INT_STAT, int_stat) DEFINE_TWI_REG(INT_MASK, int_mask) -DEFINE_TWI_REG(FIFO_CTL, fifo_ctl) DEFINE_TWI_REG(FIFO_STAT, fifo_stat) DEFINE_TWI_REG(XMT_DATA8, xmt_data8) DEFINE_TWI_REG(XMT_DATA16, xmt_data16) @@ -113,75 +58,25 @@ static inline u16 read_RCV_DATA16(struct bfin_twi_iface *iface) } #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 ***********************/ -/* 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/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) */ +static inline void write_FIFO_CTL(struct bfin_twi_iface *iface, u16 v) +{ + bfin_write16(&iface->regs_base->fifo_ctl, v); + SSYNC(); +} -#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 u16 read_CONTROL(struct bfin_twi_iface *iface) +{ + return bfin_read16(&iface->regs_base->control); +} +static inline void write_CONTROL(struct bfin_twi_iface *iface, u16 v) +{ + SSYNC(); + bfin_write16(&iface->regs_base->control, v); +} #endif diff --git a/arch/blackfin/kernel/debug-mmrs.c b/arch/blackfin/kernel/debug-mmrs.c index 01232a13470d..947ad0832338 100644 --- a/arch/blackfin/kernel/debug-mmrs.c +++ b/arch/blackfin/kernel/debug-mmrs.c @@ -10,6 +10,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/i2c/bfin_twi.h> #include <asm/blackfin.h> #include <asm/gpio.h> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 014afab1d551..c94db1c5e353 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -110,6 +110,7 @@ config I2C_I801 Wellsburg (PCH) Coleto Creek (PCH) Wildcat Point-LP (PCH) + BayTrail (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -375,6 +376,13 @@ config I2C_BLACKFIN_TWI_CLK_KHZ help 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 tristate "CBUS I2C driver" depends on GPIOLIB @@ -432,6 +440,13 @@ config I2C_DESIGNWARE_PCI This driver can also be built as a module. If so, the module will be called i2c-designware-pci. +config I2C_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 tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" depends on PCI @@ -527,7 +542,7 @@ config I2C_MPC config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) + depends on MV64X60 || PLAT_ORION || ARCH_SUNXI help 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. @@ -648,6 +663,16 @@ config I2C_PXA_SLAVE is necessary for systems where the PXA may be a target on the 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 tristate "Renesas RIIC adapter" depends on ARCH_SHMOBILE || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index a08931fe73e1..18d18ff9db93 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.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_CPM) += i2c-cpm.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 obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.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_EXYNOS5) += i2c-exynos5.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_PXA) += i2c-pxa.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_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 7d60d3a1f621..451e305f7971 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -494,7 +494,7 @@ static struct i2c_adapter ali1535_adapter = { .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) }, { }, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 4611e4754a67..98a1c97739ba 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -416,7 +416,7 @@ static void ali1563_remove(struct pci_dev *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) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 4823206a4870..2fa21ce9682b 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -476,7 +476,7 @@ static struct i2c_adapter ali15x3_adapter = { .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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 819d3c1062a7..a16f72891358 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -307,7 +307,7 @@ static const char* chipname[] = { "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), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index f3d4d79855b5..95a80a8f81b5 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 843d01268ae9..e95f9ba96790 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -32,7 +32,7 @@ #include <linux/slab.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_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; int rc; u32 phy_addr; + u32 bus_clk_rate; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -756,13 +757,18 @@ static int at91_twi_probe(struct platform_device *pdev) 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); snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); i2c_set_adapdata(&dev->adapter, dev); dev->adapter.owner = THIS_MODULE; - dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED; dev->adapter.algo = &at91_twi_algorithm; dev->adapter.dev.parent = dev->dev; dev->adapter.nr = pdev->id; diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 77df97b932af..c60719577fc3 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -219,7 +219,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = { static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; - struct resource *mem, *requested, *irq; + struct resource *mem, *irq; u32 bus_clk_rate, divider; int ret; struct i2c_adapter *adap; @@ -234,25 +234,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->completion); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No mem resource\n"); - return -ENODEV; - } - - 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->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c_dev->regs)) + return PTR_ERR(i2c_dev->regs); i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) { @@ -295,7 +279,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) adap = &i2c_dev->adapter; i2c_set_adapdata(adap, i2c_dev); 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)); adap->algo = &bcm2835_i2c_algo; adap->dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 3b9bd9a3f2b0..e6d5162b6379 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -21,10 +21,10 @@ #include <linux/interrupt.h> #include <linux/platform_device.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/portmux.h> #include <asm/bfin_twi.h> /* SMBus mode*/ @@ -65,7 +65,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, /* Transmit next data */ while (iface->writeNum > 0 && (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) { - SSYNC(); write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; } @@ -248,7 +247,6 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) /* Clear interrupt status */ write_INT_STAT(iface, twi_int_status); bfin_twi_handle_interrupt(iface, twi_int_status); - SSYNC(); } spin_unlock_irqrestore(&iface->lock, flags); return IRQ_HANDLED; @@ -294,9 +292,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, * discarded before start a new operation. */ write_FIFO_CTL(iface, 0x3); - SSYNC(); write_FIFO_CTL(iface, 0); - SSYNC(); if (pmsg->flags & I2C_M_RD) 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) { write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; - SSYNC(); } } @@ -315,7 +310,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, /* Interrupt mask . Enable XMT, RCV interrupt */ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); - SSYNC(); if (pmsg->len <= 255) 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->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); - SSYNC(); while (!iface->result) { 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. */ write_FIFO_CTL(iface, 0x3); - SSYNC(); write_FIFO_CTL(iface, 0); /* clear int stat */ @@ -461,7 +453,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, /* Set Transmit device address */ write_MASTER_ADDR(iface, addr); - SSYNC(); switch (iface->cur_mode) { 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 | ((iface->read_write == I2C_SMBUS_READ) ? RCVSERV : XMTSERV)); - SSYNC(); if (iface->writeNum + 1 <= 255) 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: write_XMT_DATA8(iface, iface->command); write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); - SSYNC(); if (iface->writeNum > 0) 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 | ((iface->read_write == I2C_SMBUS_READ) ? RCVSERV : XMTSERV)); - SSYNC(); /* Master enable */ 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)); break; } - SSYNC(); while (!iface->result) { 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)); p_adap->algo = &bfin_twi_algorithm; 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->timeout = 5 * HZ; p_adap->retries = 3; @@ -704,7 +691,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) /* Enable TWI */ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); - SSYNC(); rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) { diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c new file mode 100644 index 000000000000..63f3f03ecc9b --- /dev/null +++ b/drivers/i2c/busses/i2c-cadence.c @@ -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"); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index af0b5830303d..389bc68c55ad 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -712,7 +712,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap = &dev->adapter; i2c_set_adapdata(adap, dev); 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)); adap->algo = &i2c_davinci_algo; adap->dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 14c4b30d4ccc..22e92c3d3d07 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -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. */ - return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; + return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset; else /* * 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, * 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) @@ -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 * 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) @@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) u32 input_clock_khz; u32 hcnt, lcnt; u32 reg; + u32 sda_falling_time, scl_falling_time; 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 */ + sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ + scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ + /* Standard-mode */ hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 40, /* tHD;STA = tHIGH = 4.0 us */ - 3, /* tf = 0.3 us */ + 4000, /* tHD;STA = tHIGH = 4.0 us */ + sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 47, /* tLOW = 4.7 us */ - 3, /* tf = 0.3 us */ + 4700, /* tLOW = 4.7 us */ + scl_falling_time, 0); /* No offset */ /* 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 */ hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 6, /* tHD;STA = tHIGH = 0.6 us */ - 3, /* tf = 0.3 us */ + 600, /* tHD;STA = tHIGH = 0.6 us */ + sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 13, /* tLOW = 1.3 us */ - 3, /* tf = 0.3 us */ + 1300, /* tLOW = 1.3 us */ + scl_falling_time, 0); /* No offset */ if (dev->fs_hcnt && dev->fs_lcnt) { diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e8a756537ed0..d66b6cbc9edc 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -99,6 +99,8 @@ struct dw_i2c_dev { unsigned int rx_fifo_depth; int rx_outstanding; u32 sda_hold_time; + u32 sda_falling_time; + u32 scl_falling_time; u16 ss_hcnt; u16 ss_lcnt; u16 fs_hcnt; diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index f6ed06c966ee..85056c22d21e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -54,6 +54,16 @@ enum dw_pci_ctl_id_t { medfield_3, medfield_4, 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 { @@ -62,12 +72,29 @@ struct dw_pci_controller { u32 tx_fifo_depth; u32 rx_fifo_depth; u32 clk_khz; + u32 functionality; + struct dw_scl_sda_cfg *scl_sda_cfg; }; #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ DW_IC_CON_SLAVE_DISABLE | \ 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[] = { [moorestown_0] = { .bus_num = 0, @@ -132,75 +159,40 @@ static struct dw_pci_controller dw_pci_controllers[] = { .rx_fifo_depth = 32, .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 = { .master_xfer = i2c_dw_xfer, .functionality = i2c_dw_func, }; +#ifdef CONFIG_PM static int i2c_dw_pci_suspend(struct device *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; } static int i2c_dw_pci_resume(struct device *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); - 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; -} -static int i2c_dw_pci_runtime_idle(struct device *dev) -{ - int err = pm_schedule_suspend(dev, 500); - dev_dbg(dev, "runtime_idle called\n"); - - if (err != 0) - return 0; - return -EBUSY; + return i2c_dw_init(pci_get_drvdata(pdev)); } +#endif -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 UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend, + i2c_dw_pci_resume, NULL); static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) { @@ -214,6 +206,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct i2c_adapter *adap; int r; struct dw_pci_controller *controller; + struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { 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->base = pcim_iomap_table(pdev)[0]; dev->dev = &pdev->dev; - dev->functionality = - I2C_FUNC_I2C | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK; + dev->functionality = controller->functionality | + DW_DEFAULT_FUNCTIONALITY; + 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); @@ -270,8 +268,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, adap->algo = &i2c_dw_algo; adap->dev.parent = &pdev->dev; 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, 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_use_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_allow(&pdev->dev); return 0; @@ -309,7 +308,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) /* work with hotplug and coldplug */ 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 */ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { 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, 0x082D), medfield_1 }, { 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,} }; MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d0bdac0498ce..9c7802614342 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev) "i2c-sda-hold-time-ns", &ht); dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, 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 = @@ -195,7 +202,7 @@ static int dw_i2c_probe(struct platform_device *pdev) adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; - adap->class = I2C_CLASS_HWMON; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED; strlcpy(adap->name, "Synopsys DesignWare I2C adapter", sizeof(adap->name)); adap->algo = &i2c_dw_algo; diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c new file mode 100644 index 000000000000..777ed409a24a --- /dev/null +++ b/drivers/i2c/busses/i2c-efm32.c @@ -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); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index e08e458bab02..ff775ac29e49 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -186,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex); #define PCI_DEVICE_ID_ML7223_I2C 0x8010 #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(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 9fd711c03dd2..00af0a0a3361 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -566,7 +566,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, static int exynos5_i2c_xfer(struct i2c_adapter *adap, 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; if (i2c->suspended) { @@ -715,6 +715,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP static int exynos5_i2c_suspend_noirq(struct 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; } +#endif static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq, exynos5_i2c_resume_noirq); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d9f7e186a4c7..02d2d4abb9dd 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -94,6 +94,9 @@ static int of_i2c_gpio_get_pins(struct device_node *np, *sda_pin = of_get_gpio(np, 0); *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)) { pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", np->full_name, *sda_pin, *scl_pin); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index e248257fe517..14d2b76de25f 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -104,7 +104,7 @@ static struct i2c_adapter hydra_adap = { .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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 349c2d35e792..6777cd6f8776 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -60,6 +60,7 @@ Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes Coleto Creek (PCH) 0x23b0 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: Software PEC no @@ -161,6 +162,7 @@ STATUS_ERROR_FLAGS) /* 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_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ @@ -789,7 +791,7 @@ static const struct i2c_algorithm smbus_algorithm = { .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_82801AB_3) }, { 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_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_BAYTRAIL_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 8ce4f517fc56..984492553e95 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -182,7 +182,7 @@ struct ismt_priv { /** * 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_SMT1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d52d84937ad3..540ea692bf79 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/mv643xx_i2c.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> @@ -97,7 +98,6 @@ enum { enum { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, - MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART, MV64XXX_I2C_ACTION_SEND_ADDR_1, @@ -148,6 +148,8 @@ struct mv64xxx_i2c_data { bool offload_enabled; /* 5us delay in order to avoid repeated start timing violation */ bool errata_delay; + struct reset_control *rstc; + bool irq_clear_inverted; }; 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; - 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 | 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) 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 */ if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0) 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 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->num_msgs--; - if (mv64xxx_i2c_offload_msg(drv_data) < 0) { - drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; - writel(drv_data->cntl_bits, - drv_data->reg_base + drv_data->reg_offsets.control); + mv64xxx_i2c_send_start(drv_data); - /* Setup for the next message */ - mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); - } if (drv_data->errata_delay) 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); 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: writel(drv_data->addr1, 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); mv64xxx_i2c_fsm(drv_data, status); 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; } 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); - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->send_stop = is_last; drv_data->block = 1; - mv64xxx_i2c_do_action(drv_data); + mv64xxx_i2c_send_start(drv_data); spin_unlock_irqrestore(&drv_data->lock, flags); 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[] = { { .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,mv78230-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->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. * 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->errata_delay = true; } + + if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) + drv_data->irq_clear_inverted = true; + out: return rc; #endif @@ -845,13 +857,13 @@ mv64xxx_i2c_probe(struct platform_device *pd) } if (drv_data->irq < 0) { rc = -ENXIO; - goto exit_clk; + goto exit_reset; } drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.algo = &mv64xxx_i2c_algo; 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.dev.of_node = pd->dev.of_node; platform_set_drvdata(pd, drv_data); @@ -865,7 +877,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) dev_err(&drv_data->adapter.dev, "mv64xxx: Can't register intr handler irq%d: %d\n", drv_data->irq, rc); - goto exit_clk; + goto exit_reset; } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { dev_err(&drv_data->adapter.dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); @@ -876,6 +888,9 @@ mv64xxx_i2c_probe(struct platform_device *pd) exit_free_irq: 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: #if defined(CONFIG_HAVE_CLK) /* Not all platforms have a clk */ @@ -894,6 +909,8 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); 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) /* Not all platforms have a clk */ if (!IS_ERR(drv_data->clk)) { diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 0cde4e6ab2b2..7170fc892829 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -806,7 +806,6 @@ static int mxs_i2c_probe(struct platform_device *pdev) struct mxs_i2c_dev *i2c; struct i2c_adapter *adap; struct resource *res; - resource_size_t res_size; int err, irq; 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); - irq = platform_get_irq(pdev, 0); - - if (!res || irq < 0) - return -ENOENT; + i2c->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); - 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; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); if (err) diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 0038c451095c..ee3a76c7ae97 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -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_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 4443613514ee..28cbe1b2a2ec 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -111,22 +111,6 @@ enum i2c_freq_mode { }; /** - * 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 * @has_mtdws: variant has the MTDWS bit * @fifodepth: variant FIFO depth @@ -174,12 +158,15 @@ struct i2c_nmk_client { * @irq: interrupt line for the controller. * @virtbase: virtual io memory area. * @clk: hardware i2c block clock. - * @cfg: machine provided controller configuration. * @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. * @xfer_complete: acknowledge completion for a I2C message. * @result: controller propogated result. - * @busy: Busy doing transfer. */ struct nmk_i2c_dev { struct i2c_vendor_data *vendor; @@ -188,12 +175,15 @@ struct nmk_i2c_dev { int irq; void __iomem *virtbase; struct clk *clk; - struct nmk_i2c_controller cfg; struct i2c_nmk_client cli; + u32 clk_freq; + unsigned char tft; + unsigned char rft; + int timeout; + enum i2c_freq_mode sm; int stop; struct completion xfer_complete; int result; - bool busy; }; /* controller's abort causes */ @@ -386,7 +376,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * slsu = cycles / (1000000000 / f) + 1 */ 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_PLUS: 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 * 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 @@ -419,7 +409,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * so set brcr1 to 0. */ 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 */ 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) * 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, "do not support this mode defaulting to std. mode\n"); 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, 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 */ - writel(dev->cfg.tft, dev->virtbase + I2C_TFTR); - writel(dev->cfg.rft, dev->virtbase + I2C_RFTR); + writel(dev->tft, dev->virtbase + I2C_TFTR); + 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, struct i2c_msg msgs[], int num_msgs) { - int status; + int status = 0; int i; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); int j; - dev->busy = true; - 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 */ for (j = 0; j < 3; j++) { /* setup the i2c controller */ @@ -716,16 +691,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, 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); - dev->busy = false; - /* return the no. messages processed */ if (status) return status; @@ -909,22 +876,15 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) return IRQ_HANDLED; } - -#ifdef CONFIG_PM -static int nmk_i2c_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int nmk_i2c_suspend_late(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); 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 */ pinctrl_pm_select_default_state(dev); @@ -933,19 +893,48 @@ static int nmk_i2c_resume(struct device *dev) return 0; } -#else -#define nmk_i2c_suspend NULL -#define nmk_i2c_resume NULL #endif -/* - * We use noirq so that we suspend late and resume before the wakeup interrupt - * 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()). - */ +#ifdef CONFIG_PM +static int nmk_i2c_runtime_suspend(struct device *dev) +{ + 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 = { - .suspend_noirq = nmk_i2c_suspend, - .resume_noirq = nmk_i2c_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) + SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, + nmk_i2c_runtime_resume, + NULL) }; 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 }; -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, - 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. */ - if (pdata->clk_freq <= 100000) - pdata->sm = I2C_FREQ_MODE_STANDARD; + if (nmk->clk_freq <= 100000) + nmk->sm = I2C_FREQ_MODE_STANDARD; 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) { int ret = 0; - struct nmk_i2c_controller *pdata = dev_get_platdata(&adev->dev); struct device_node *np = adev->dev.of_node; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; struct i2c_vendor_data *vendor = id->data; u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; - if (!pdata) { - 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; + dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&adev->dev, "cannot allocate memory\n"); + ret = -ENOMEM; + goto err_no_mem; } + dev->vendor = vendor; + dev->adev = adev; + nmk_i2c_of_probe(np, dev); - if (pdata->tft > max_fifo_threshold) { + if (dev->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; + dev->tft, max_fifo_threshold); + dev->tft = max_fifo_threshold; } - if (pdata->rft > max_fifo_threshold) { + if (dev->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->rft, max_fifo_threshold); + dev->rft = max_fifo_threshold; } - dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); - if (!dev) { - dev_err(&adev->dev, "cannot allocate memory\n"); - ret = -ENOMEM; - goto err_no_mem; - } - dev->vendor = vendor; - dev->busy = false; - dev->adev = adev; amba_set_drvdata(adev, dev); - /* Select default pin state */ - pinctrl_pm_select_default_state(&adev->dev); - /* If possible, let's go to idle until the first transfer */ - pinctrl_pm_select_idle_state(&adev->dev); - - dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); - if (!dev->virtbase) { + dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, + resource_size(&adev->res)); + if (IS_ERR(dev->virtbase)) { ret = -ENOMEM; - goto err_no_ioremap; + goto err_no_mem; } 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); if (ret) { 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); - dev->clk = clk_get(&adev->dev, NULL); + dev->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&adev->dev, "could not get i2c clock\n"); 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.of_node = np; adap->dev.parent = &adev->dev; 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->timeout = msecs_to_jiffies(pdata->timeout); + adap->timeout = msecs_to_jiffies(dev->timeout); snprintf(adap->name, sizeof(adap->name), "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); 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); if (ret) { dev_err(&adev->dev, "failed to add adapter\n"); - goto err_add_adap; + goto err_no_adap; } pm_runtime_put(&adev->dev); return 0; - err_add_adap: - clk_put(dev->clk); - err_no_clk: - free_irq(dev->irq, dev); - err_irq: - iounmap(dev->virtbase); - err_no_ioremap: - kfree(dev); + err_no_adap: + clk_disable_unprepare(dev->clk); err_no_mem: return ret; @@ -1110,13 +1073,9 @@ static int nmk_i2c_remove(struct amba_device *adev) clear_all_interrupts(dev); /* disable the controller */ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); - free_irq(dev->irq, dev); - iounmap(dev->virtbase); + clk_disable_unprepare(dev->clk); if (res) release_mem_region(res->start, resource_size(res)); - clk_put(dev->clk); - pm_runtime_disable(&adev->dev); - kfree(dev); return 0; } diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 80e06fa45720..1f6369f14fb6 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -246,7 +246,7 @@ static const struct i2c_algorithm ocores_algorithm = { static struct i2c_adapter ocores_adapter = { .owner = THIS_MODULE, .name = "i2c-ocores", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED, .algo = &ocores_algorithm, }; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 90dcc2eaac5f..85f8eac9ba18 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -636,7 +636,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int r; r = pm_runtime_get_sync(dev->dev); - if (IS_ERR_VALUE(r)) + if (r < 0) goto out; r = omap_i2c_wait_for_bb(dev); @@ -1155,7 +1155,7 @@ omap_i2c_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(dev->dev); r = pm_runtime_get_sync(dev->dev); - if (IS_ERR_VALUE(r)) + if (r < 0) goto err_free_mem; /* @@ -1238,7 +1238,7 @@ omap_i2c_probe(struct platform_device *pdev) adap = &dev->adapter; i2c_set_adapdata(adap, dev); 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)); adap->algo = &omap_i2c_algo; adap->dev.parent = &pdev->dev; @@ -1276,7 +1276,7 @@ static int omap_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 615f632c846f..7a9dce43e115 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -401,7 +401,7 @@ static void pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { +static const struct pci_device_id pasemi_smb_ids[] = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 39dd8ec60dfd..a6f54ba27e2a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -540,7 +540,7 @@ static const struct i2c_algorithm smbus_algorithm = { .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_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 9639be86e53f..417464e9ea2a 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -148,7 +148,7 @@ static void ce4100_i2c_remove(struct pci_dev *dev) 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)}, { }, }; diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c new file mode 100644 index 000000000000..1b4cf14f1106 --- /dev/null +++ b/drivers/i2c/busses/i2c-qup.c @@ -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"); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 0282d4d42805..d4fa8eba6e9d 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -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-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .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); @@ -691,7 +692,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap = &priv->adap; adap->nr = pdev->id; 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->dev.parent = dev; adap->dev.of_node = dev->of_node; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 684d21e71e4a..ae4491062e41 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) 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 * @@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_wait_idle(i2c); + s3c24xx_i2c_disable_bus(i2c); + out: + i2c->state = STATE_IDLE; + 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) { - unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN; struct s3c2410_platform_i2c *pdata; 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); - 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... */ if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { - writel(0, i2c->regs + S3C2410_IICCON); dev_err(i2c->dev, "cannot meet bus frequency required\n"); 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 */ 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; } @@ -1106,7 +1135,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; 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; init_waitqueue_head(&i2c->wait); diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 6784f7f527a4..8e3be7ed0586 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -312,7 +312,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) goto out; } 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); siic->base = devm_ioremap_resource(&pdev->dev, mem_res); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 79fd96a04386..ac9bc33acef4 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 19b8505d0cdd..c6366733008d 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -510,7 +510,7 @@ static struct i2c_adapter sis630_adapter = { .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_LPC) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) }, diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index f8aa0c29f02b..8dc2fc5f74ff 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -244,7 +244,7 @@ static struct i2c_adapter sis96x_adapter = { .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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 9cf715d69551..872016196ef3 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -574,7 +574,7 @@ static irqreturn_t st_i2c_isr_thread(int irq, void *data) writel_relaxed(it, i2c_dev->base + SSC_IEN); st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); - c->result = -EIO; + c->result = -EAGAIN; break; default: diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 5b80ef310841..29b1fb778943 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -911,7 +911,7 @@ static int stu300_probe(struct platform_device *pdev) adap = &dev->adapter; adap->owner = THIS_MODULE; /* 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", sizeof(adap->name)); adap->nr = bus_nr; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 9704537aee3c..00f04cb5b4eb 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -794,7 +794,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); 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", sizeof(i2c_dev->adapter.name)); i2c_dev->adapter.algo = &tegra_i2c_algo; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 49d7f14b9d27..f4a1ed757612 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 40d36df678de..6841200b6e50 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -442,7 +442,7 @@ release_region: 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), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 28107502517f..7731f1795869 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -684,7 +684,7 @@ static const struct i2c_algorithm xiic_algorithm = { static struct i2c_adapter xiic_adapter = { .owner = THIS_MODULE, .name = DRIVER_NAME, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED, .algo = &xiic_algorithm, }; diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 2d1d2c5653fb..cb66f9586f76 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -556,7 +556,7 @@ static struct platform_driver scx200_pci_driver = { .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_SC1100_BRIDGE) }, { 0, } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5fb80b8962a2..7c7f4b856bad 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,10 +48,13 @@ #include <linux/rwsem.h> #include <linux/pm_runtime.h> #include <linux/acpi.h> +#include <linux/jump_label.h> #include <asm/uaccess.h> #include "i2c-core.h" +#define CREATE_TRACE_POINTS +#include <trace/events/i2c.h> /* core_lock protects i2c_adapter_idr, and guarantees 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 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, @@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void) class_compat_unregister(i2c_adapter_compat_class); #endif bus_unregister(&i2c_bus_type); + tracepoint_synchronize_unregister(); } /* 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; 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 */ orig_jiffies = jiffies; 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; } + 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; } EXPORT_SYMBOL(__i2c_transfer); @@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_client *client; /* 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", info.type, info.addr); 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; 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; 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); if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) - return res; + goto trace; /* * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't * implement native support for the SMBus operation. */ } - return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, - command, protocol, data); + res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, + 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); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index deddeb8c337c..b556e0ab946f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -487,6 +487,7 @@ void i2c_unlock_adapter(struct i2c_adapter *); #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ #define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */ #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 */ #define I2C_CLIENT_END 0xfffeU diff --git a/include/linux/i2c/bfin_twi.h b/include/linux/i2c/bfin_twi.h new file mode 100644 index 000000000000..135a4e0876ae --- /dev/null +++ b/include/linux/i2c/bfin_twi.h @@ -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 diff --git a/include/linux/platform_data/i2c-s3c2410.h b/include/linux/platform_data/i2c-s3c2410.h index 2a50048c1c44..05af66b840b9 100644 --- a/include/linux/platform_data/i2c-s3c2410.h +++ b/include/linux/platform_data/i2c-s3c2410.h @@ -1,5 +1,4 @@ -/* arch/arm/plat-s3c/include/plat/iic.h - * +/* * Copyright 2004-2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * @@ -10,8 +9,8 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_ARCH_IIC_H -#define __ASM_ARCH_IIC_H __FILE__ +#ifndef __I2C_S3C2410_H +#define __I2C_S3C2410_H __FILE__ #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; -#endif /* __ASM_ARCH_IIC_H */ +#endif /* __I2C_S3C2410_H */ diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h new file mode 100644 index 000000000000..fe17187df65d --- /dev/null +++ b/include/trace/events/i2c.h @@ -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> |