mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
Merge branch 'i2c/for-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - new drivers for Spreadtrum I2C, Intel Cherry Trail Whiskey Cove SMBUS - quite some driver updates - cleanups for the i2c-mux subsystem - some subsystem-wide constification - further cleanup of include/linux/i2c * 'i2c/for-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (50 commits) i2c: sprd: Fix undefined reference errors i2c: nomadik: constify amba_id i2c: versatile: Make i2c_algo_bit_data const i2c: busses: make i2c_adapter_quirks const i2c: busses: make i2c_adapter const i2c: busses: make i2c_algorithm const i2c: Add Spreadtrum I2C controller driver dt-bindings: i2c: Add Spreadtrum I2C controller documentation i2c-cht-wc: make cht_wc_i2c_adap_driver static MAINTAINERS: Add entry for drivers/i2c/busses/i2c-cht-wc.c i2c: aspeed: Retain delay/setup/hold values when configuring bus frequency dt-bindings: i2c: eeprom: Document vendor to be used and deprecated ones i2c: i801: Restore the presence state of P2SB PCI device after reading BAR MAINTAINERS: drop entry for Blackfin I2C and Sonic's email blackfin: merge the two TWI header files i2c: davinci: Preserve return value of devm_clk_get i2c: mediatek: Add i2c compatible for MediaTek MT7622 dt-bindings: i2c: Add MediaTek MT7622 i2c binding dt-bindings: i2c: modify information formats i2c: mux: i2c-arb-gpio-challenge: allow compiling w/o OF support ...
This commit is contained in:
commit
d2d8f51e28
@ -16,8 +16,12 @@ Required properties:
|
||||
|
||||
"renesas,r1ex24002"
|
||||
|
||||
The following manufacturers values have been deprecated:
|
||||
"at", "at24"
|
||||
|
||||
If there is no specific driver for <manufacturer>, a generic
|
||||
driver based on <type> is selected. Possible types are:
|
||||
device with <type> and manufacturer "atmel" should be used.
|
||||
Possible types are:
|
||||
"24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
|
||||
"24c128", "24c256", "24c512", "24c1024", "spd"
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
* Mediatek's I2C controller
|
||||
* MediaTek's I2C controller
|
||||
|
||||
The Mediatek's I2C controller is used to interface with I2C devices.
|
||||
The MediaTek's I2C controller is used to interface with I2C devices.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be either of the following.
|
||||
"mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for Mediatek mt2701
|
||||
"mediatek,mt6577-i2c": for i2c compatible with mt6577.
|
||||
"mediatek,mt6589-i2c": for i2c compatible with mt6589.
|
||||
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for i2c compatible with mt7623.
|
||||
"mediatek,mt8173-i2c": for i2c compatible with mt8173.
|
||||
"mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701
|
||||
"mediatek,mt6577-i2c": for MediaTek MT6577
|
||||
"mediatek,mt6589-i2c": for MediaTek MT6589
|
||||
"mediatek,mt7622-i2c": for MediaTek MT7622
|
||||
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623
|
||||
"mediatek,mt8173-i2c": for MediaTek MT8173
|
||||
- reg: physical base address of the controller and dma base, length of memory
|
||||
mapped region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
@ -2,6 +2,8 @@ I2C for R-Car platforms
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
"renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC.
|
||||
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
||||
@ -12,7 +14,8 @@ Required properties:
|
||||
"renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC.
|
||||
"renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
|
||||
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 compatible device.
|
||||
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible
|
||||
device.
|
||||
"renesas,rcar-gen3-i2c" for a generic R-Car Gen3 compatible device.
|
||||
"renesas,i2c-rcar" (deprecated)
|
||||
|
||||
|
@ -7,6 +7,7 @@ Required properties :
|
||||
|
||||
- reg : Offset and length of the register set for the device
|
||||
- compatible: should be one of the following:
|
||||
- "rockchip,rv1108-i2c": for rv1108
|
||||
- "rockchip,rk3066-i2c": for rk3066
|
||||
- "rockchip,rk3188-i2c": for rk3188
|
||||
- "rockchip,rk3228-i2c": for rk3228
|
||||
|
@ -4,6 +4,8 @@ Required properties:
|
||||
- compatible :
|
||||
- "renesas,iic-r8a73a4" (R-Mobile APE6)
|
||||
- "renesas,iic-r8a7740" (R-Mobile A1)
|
||||
- "renesas,iic-r8a7743" (RZ/G1M)
|
||||
- "renesas,iic-r8a7745" (RZ/G1E)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||
@ -12,7 +14,8 @@ Required properties:
|
||||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device)
|
||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
|
||||
compatible device)
|
||||
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device)
|
||||
- "renesas,rmobile-iic" (generic device)
|
||||
|
||||
|
31
Documentation/devicetree/bindings/i2c/i2c-sprd.txt
Normal file
31
Documentation/devicetree/bindings/i2c/i2c-sprd.txt
Normal file
@ -0,0 +1,31 @@
|
||||
I2C for Spreadtrum platforms
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "sprd,sc9860-i2c".
|
||||
- reg: Specify the physical base address of the controller and length
|
||||
of memory mapped region.
|
||||
- interrupts: Should contain I2C interrupt.
|
||||
- clock-names: Should contain following entries:
|
||||
"i2c" for I2C clock,
|
||||
"source" for I2C source (parent) clock,
|
||||
"enable" for I2C module enable clock.
|
||||
- clocks: Should contain a clock specifier for each entry in clock-names.
|
||||
- clock-frequency: Constains desired I2C bus clock frequency in Hz.
|
||||
- #address-cells: Should be 1 to describe address cells for I2C device address.
|
||||
- #size-cells: Should be 0 means no size cell for I2C device address.
|
||||
|
||||
Optional properties:
|
||||
- Child nodes conforming to I2C bus binding
|
||||
|
||||
Examples:
|
||||
i2c0: i2c@70500000 {
|
||||
compatible = "sprd,sc9860-i2c";
|
||||
reg = <0 0x70500000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-names = "i2c", "source", "enable";
|
||||
clocks = <&clk_i2c3>, <&ext_26m>, <&clk_ap_apb_gates 11>;
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
@ -42,6 +42,10 @@ i2c-arb-gpio-challenge Parent-locked
|
||||
i2c-mux-gpio Normally parent-locked, mux-locked iff
|
||||
all involved gpio pins are controlled by the
|
||||
same i2c root adapter that they mux.
|
||||
i2c-mux-gpmux Normally parent-locked, mux-locked iff
|
||||
specified in device-tree.
|
||||
i2c-mux-ltc4306 Mux-locked
|
||||
i2c-mux-mlxcpld Parent-locked
|
||||
i2c-mux-pca9541 Parent-locked
|
||||
i2c-mux-pca954x Parent-locked
|
||||
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
|
||||
@ -50,9 +54,11 @@ i2c-mux-pinctrl Normally parent-locked, mux-locked iff
|
||||
i2c-mux-reg Parent-locked
|
||||
|
||||
In drivers/iio/
|
||||
gyro/mpu3050 Mux-locked
|
||||
imu/inv_mpu6050/ Mux-locked
|
||||
|
||||
In drivers/media/
|
||||
dvb-frontends/lgdt3306a Mux-locked
|
||||
dvb-frontends/m88ds3103 Parent-locked
|
||||
dvb-frontends/rtl2830 Parent-locked
|
||||
dvb-frontends/rtl2832 Mux-locked
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -2575,13 +2575,6 @@ W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/adi/
|
||||
|
||||
BLACKFIN I2C TWI DRIVER
|
||||
M: Sonic Zhang <sonic.zhang@analog.com>
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
W: http://blackfin.uclinux.org/
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-bfin-twi.c
|
||||
|
||||
BLACKFIN MEDIA DRIVER
|
||||
M: Scott Jiang <scott.jiang.linux@gmail.com>
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
@ -2598,14 +2591,12 @@ S: Supported
|
||||
F: drivers/rtc/rtc-bfin.c
|
||||
|
||||
BLACKFIN SDH DRIVER
|
||||
M: Sonic Zhang <sonic.zhang@analog.com>
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/bfin_sdh.c
|
||||
|
||||
BLACKFIN SERIAL DRIVER
|
||||
M: Sonic Zhang <sonic.zhang@analog.com>
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
@ -6441,6 +6432,12 @@ F: drivers/i2c/busses/i2c-sis96x.c
|
||||
F: drivers/i2c/busses/i2c-via.c
|
||||
F: drivers/i2c/busses/i2c-viapro.c
|
||||
|
||||
I2C/SMBUS INTEL CHT WHISKEY COVE PMIC DRIVER
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-cht-wc.c
|
||||
|
||||
I2C/SMBUS ISMT DRIVER
|
||||
M: Seth Heasley <seth.heasley@intel.com>
|
||||
M: Neil Horman <nhorman@tuxdriver.com>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* bfin_twi.h - interface to Blackfin TWIs
|
||||
*
|
||||
* Copyright 2005-2010 Analog Devices Inc.
|
||||
* Copyright 2005-2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
@ -10,6 +10,138 @@
|
||||
#define __ASM_BFIN_TWI_H__
|
||||
|
||||
#include <asm/blackfin.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) */
|
||||
|
||||
#define DEFINE_TWI_REG(reg_name, reg) \
|
||||
static inline u16 read_##reg_name(struct bfin_twi_iface *iface) \
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c/bfin_twi.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
|
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
#include <linux/platform_data/tc35876x.h>
|
||||
#include <asm/intel-mid.h>
|
||||
|
||||
/*tc35876x DSI_LVDS bridge chip and panel platform data*/
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
#include <linux/platform_data/tc35876x.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
@ -189,6 +189,14 @@ config I2C_PIIX4
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-piix4.
|
||||
|
||||
config I2C_CHT_WC
|
||||
tristate "Intel Cherry Trail Whiskey Cove PMIC smbus controller"
|
||||
depends on INTEL_SOC_PMIC_CHTWC
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC
|
||||
found on some Intel Cherry Trail systems.
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on PCI
|
||||
@ -900,6 +908,13 @@ config I2C_SIRF
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sirf.
|
||||
|
||||
config I2C_SPRD
|
||||
bool "Spreadtrum I2C interface"
|
||||
depends on I2C=y && ARCH_SPRD
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Spreadtrum I2C interface.
|
||||
|
||||
config I2C_ST
|
||||
tristate "STMicroelectronics SSC I2C support"
|
||||
depends on ARCH_STI
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
|
||||
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
|
||||
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
|
||||
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
|
||||
obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o
|
||||
obj-$(CONFIG_I2C_I801) += i2c-i801.o
|
||||
obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
|
||||
obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
|
||||
@ -89,6 +90,7 @@ obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
|
||||
obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o
|
||||
obj-$(CONFIG_I2C_ST) += i2c-st.o
|
||||
obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
|
||||
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
|
||||
|
@ -53,6 +53,9 @@
|
||||
#define ASPEED_I2CD_MASTER_EN BIT(0)
|
||||
|
||||
/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
|
||||
#define ASPEED_I2CD_TIME_TBUF_MASK GENMASK(31, 28)
|
||||
#define ASPEED_I2CD_TIME_THDSTA_MASK GENMASK(27, 24)
|
||||
#define ASPEED_I2CD_TIME_TACST_MASK GENMASK(23, 20)
|
||||
#define ASPEED_I2CD_TIME_SCL_HIGH_SHIFT 16
|
||||
#define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16)
|
||||
#define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12
|
||||
@ -132,6 +135,7 @@ struct aspeed_i2c_bus {
|
||||
/* Synchronizes I/O mem access to base. */
|
||||
spinlock_t lock;
|
||||
struct completion cmd_complete;
|
||||
u32 (*get_clk_reg_val)(u32 divisor);
|
||||
unsigned long parent_clk_frequency;
|
||||
u32 bus_frequency;
|
||||
/* Transaction state. */
|
||||
@ -675,7 +679,7 @@ static const struct i2c_algorithm aspeed_i2c_algo = {
|
||||
#endif /* CONFIG_I2C_SLAVE */
|
||||
};
|
||||
|
||||
static u32 aspeed_i2c_get_clk_reg_val(u32 divisor)
|
||||
static u32 aspeed_i2c_get_clk_reg_val(u32 clk_high_low_max, u32 divisor)
|
||||
{
|
||||
u32 base_clk, clk_high, clk_low, tmp;
|
||||
|
||||
@ -695,16 +699,22 @@ static u32 aspeed_i2c_get_clk_reg_val(u32 divisor)
|
||||
* Thus,
|
||||
* SCL_freq = APB_freq /
|
||||
* ((1 << base_clk) * (clk_high + 1 + clk_low + 1))
|
||||
* The documentation recommends clk_high >= 8 and clk_low >= 7 when
|
||||
* possible; this last constraint gives us the following solution:
|
||||
* The documentation recommends clk_high >= clk_high_max / 2 and
|
||||
* clk_low >= clk_low_max / 2 - 1 when possible; this last constraint
|
||||
* gives us the following solution:
|
||||
*/
|
||||
base_clk = divisor > 33 ? ilog2((divisor - 1) / 32) + 1 : 0;
|
||||
tmp = divisor / (1 << base_clk);
|
||||
clk_high = tmp / 2 + tmp % 2;
|
||||
clk_low = tmp - clk_high;
|
||||
base_clk = divisor > clk_high_low_max ?
|
||||
ilog2((divisor - 1) / clk_high_low_max) + 1 : 0;
|
||||
tmp = (divisor + (1 << base_clk) - 1) >> base_clk;
|
||||
clk_low = tmp / 2;
|
||||
clk_high = tmp - clk_low;
|
||||
|
||||
if (clk_high)
|
||||
clk_high--;
|
||||
|
||||
if (clk_low)
|
||||
clk_low--;
|
||||
|
||||
clk_high -= 1;
|
||||
clk_low -= 1;
|
||||
|
||||
return ((clk_high << ASPEED_I2CD_TIME_SCL_HIGH_SHIFT)
|
||||
& ASPEED_I2CD_TIME_SCL_HIGH_MASK)
|
||||
@ -713,13 +723,35 @@ static u32 aspeed_i2c_get_clk_reg_val(u32 divisor)
|
||||
| (base_clk & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
|
||||
}
|
||||
|
||||
static u32 aspeed_i2c_24xx_get_clk_reg_val(u32 divisor)
|
||||
{
|
||||
/*
|
||||
* clk_high and clk_low are each 3 bits wide, so each can hold a max
|
||||
* value of 8 giving a clk_high_low_max of 16.
|
||||
*/
|
||||
return aspeed_i2c_get_clk_reg_val(16, divisor);
|
||||
}
|
||||
|
||||
static u32 aspeed_i2c_25xx_get_clk_reg_val(u32 divisor)
|
||||
{
|
||||
/*
|
||||
* clk_high and clk_low are each 4 bits wide, so each can hold a max
|
||||
* value of 16 giving a clk_high_low_max of 32.
|
||||
*/
|
||||
return aspeed_i2c_get_clk_reg_val(32, divisor);
|
||||
}
|
||||
|
||||
/* precondition: bus.lock has been acquired. */
|
||||
static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
|
||||
{
|
||||
u32 divisor, clk_reg_val;
|
||||
|
||||
divisor = bus->parent_clk_frequency / bus->bus_frequency;
|
||||
clk_reg_val = aspeed_i2c_get_clk_reg_val(divisor);
|
||||
divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency);
|
||||
clk_reg_val = readl(bus->base + ASPEED_I2C_AC_TIMING_REG1);
|
||||
clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
|
||||
ASPEED_I2CD_TIME_THDSTA_MASK |
|
||||
ASPEED_I2CD_TIME_TACST_MASK);
|
||||
clk_reg_val |= bus->get_clk_reg_val(divisor);
|
||||
writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
|
||||
writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);
|
||||
|
||||
@ -778,8 +810,22 @@ static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_i2c_bus_of_table[] = {
|
||||
{
|
||||
.compatible = "aspeed,ast2400-i2c-bus",
|
||||
.data = aspeed_i2c_24xx_get_clk_reg_val,
|
||||
},
|
||||
{
|
||||
.compatible = "aspeed,ast2500-i2c-bus",
|
||||
.data = aspeed_i2c_25xx_get_clk_reg_val,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
|
||||
|
||||
static int aspeed_i2c_probe_bus(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct aspeed_i2c_bus *bus;
|
||||
struct clk *parent_clk;
|
||||
struct resource *res;
|
||||
@ -809,6 +855,12 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
|
||||
bus->bus_frequency = 100000;
|
||||
}
|
||||
|
||||
match = of_match_node(aspeed_i2c_bus_of_table, pdev->dev.of_node);
|
||||
if (!match)
|
||||
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
|
||||
else
|
||||
bus->get_clk_reg_val = match->data;
|
||||
|
||||
/* Initialize the I2C adapter */
|
||||
spin_lock_init(&bus->lock);
|
||||
init_completion(&bus->cmd_complete);
|
||||
@ -870,13 +922,6 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_i2c_bus_of_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-i2c-bus", },
|
||||
{ .compatible = "aspeed,ast2500-i2c-bus", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
|
||||
|
||||
static struct platform_driver aspeed_i2c_bus_driver = {
|
||||
.probe = aspeed_i2c_probe_bus,
|
||||
.remove = aspeed_i2c_remove_bus,
|
||||
|
@ -809,7 +809,7 @@ out:
|
||||
* The hardware can handle at most two messages concatenated by a
|
||||
* repeated start via it's internal address feature.
|
||||
*/
|
||||
static struct i2c_adapter_quirks at91_twi_quirks = {
|
||||
static const struct i2c_adapter_quirks at91_twi_quirks = {
|
||||
.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
|
||||
.max_comb_1st_msg_len = 3,
|
||||
};
|
||||
|
@ -510,8 +510,7 @@ static int bcm_iproc_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
static int bcm_iproc_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
|
||||
|
||||
/* make sure there's no pending interrupt when we go into suspend */
|
||||
writel(0, iproc_i2c->base + IE_OFFSET);
|
||||
@ -526,8 +525,7 @@ static int bcm_iproc_i2c_suspend(struct device *dev)
|
||||
|
||||
static int bcm_iproc_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c/bfin_twi.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/portmux.h>
|
||||
|
@ -826,8 +826,7 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
|
||||
*/
|
||||
static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
|
||||
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(xi2c->clk);
|
||||
|
||||
@ -844,8 +843,7 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
|
||||
*/
|
||||
static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
|
||||
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(xi2c->clk);
|
||||
|
363
drivers/i2c/busses/i2c-cht-wc.c
Normal file
363
drivers/i2c/busses/i2c-cht-wc.c
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Intel CHT Whiskey Cove PMIC I2C Master driver
|
||||
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
|
||||
* Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define CHT_WC_I2C_CTRL 0x5e24
|
||||
#define CHT_WC_I2C_CTRL_WR BIT(0)
|
||||
#define CHT_WC_I2C_CTRL_RD BIT(1)
|
||||
#define CHT_WC_I2C_CLIENT_ADDR 0x5e25
|
||||
#define CHT_WC_I2C_REG_OFFSET 0x5e26
|
||||
#define CHT_WC_I2C_WRDATA 0x5e27
|
||||
#define CHT_WC_I2C_RDDATA 0x5e28
|
||||
|
||||
#define CHT_WC_EXTCHGRIRQ 0x6e0a
|
||||
#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ BIT(0)
|
||||
#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ BIT(1)
|
||||
#define CHT_WC_EXTCHGRIRQ_READ_IRQ BIT(2)
|
||||
#define CHT_WC_EXTCHGRIRQ_NACK_IRQ BIT(3)
|
||||
#define CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK ((u8)GENMASK(3, 1))
|
||||
#define CHT_WC_EXTCHGRIRQ_MSK 0x6e17
|
||||
|
||||
struct cht_wc_i2c_adap {
|
||||
struct i2c_adapter adapter;
|
||||
wait_queue_head_t wait;
|
||||
struct irq_chip irqchip;
|
||||
struct mutex adap_lock;
|
||||
struct mutex irqchip_lock;
|
||||
struct regmap *regmap;
|
||||
struct irq_domain *irq_domain;
|
||||
struct i2c_client *client;
|
||||
int client_irq;
|
||||
u8 irq_mask;
|
||||
u8 old_irq_mask;
|
||||
int read_data;
|
||||
bool io_error;
|
||||
bool done;
|
||||
};
|
||||
|
||||
static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = data;
|
||||
int ret, reg;
|
||||
|
||||
mutex_lock(&adap->adap_lock);
|
||||
|
||||
/* Read IRQs */
|
||||
ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, ®);
|
||||
if (ret) {
|
||||
dev_err(&adap->adapter.dev, "Error reading extchgrirq reg\n");
|
||||
mutex_unlock(&adap->adap_lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
reg &= ~adap->irq_mask;
|
||||
|
||||
/* Reads must be acked after reading the received data. */
|
||||
ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &adap->read_data);
|
||||
if (ret)
|
||||
adap->io_error = true;
|
||||
|
||||
/*
|
||||
* Immediately ack IRQs, so that if new IRQs arrives while we're
|
||||
* handling the previous ones our irq will re-trigger when we're done.
|
||||
*/
|
||||
ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
|
||||
if (ret)
|
||||
dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n");
|
||||
|
||||
if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK) {
|
||||
adap->io_error |= !!(reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ);
|
||||
adap->done = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&adap->adap_lock);
|
||||
|
||||
if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK)
|
||||
wake_up(&adap->wait);
|
||||
|
||||
/*
|
||||
* Do NOT use handle_nested_irq here, the client irq handler will
|
||||
* likely want to do i2c transfers and the i2c controller uses this
|
||||
* interrupt handler as well, so running the client irq handler from
|
||||
* this thread will cause things to lock up.
|
||||
*/
|
||||
if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
|
||||
/*
|
||||
* generic_handle_irq expects local IRQs to be disabled
|
||||
* as normally it is called from interrupt context.
|
||||
*/
|
||||
local_irq_disable();
|
||||
generic_handle_irq(adap->client_irq);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
|
||||
{
|
||||
/* This i2c adapter only supports SMBUS byte transfers */
|
||||
return I2C_FUNC_SMBUS_BYTE_DATA;
|
||||
}
|
||||
|
||||
static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&adap->adap_lock);
|
||||
adap->io_error = false;
|
||||
adap->done = false;
|
||||
mutex_unlock(&adap->adap_lock);
|
||||
|
||||
ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL,
|
||||
(read_write == I2C_SMBUS_WRITE) ?
|
||||
CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_event_timeout(adap->wait, adap->done, msecs_to_jiffies(30));
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* The CHT GPIO controller serializes all IRQs, sometimes
|
||||
* causing significant delays, check status manually.
|
||||
*/
|
||||
cht_wc_i2c_adap_thread_handler(0, adap);
|
||||
if (!adap->done)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
mutex_lock(&adap->adap_lock);
|
||||
if (adap->io_error)
|
||||
ret = -EIO;
|
||||
else if (read_write == I2C_SMBUS_READ)
|
||||
data->byte = adap->read_data;
|
||||
mutex_unlock(&adap->adap_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm cht_wc_i2c_adap_algo = {
|
||||
.functionality = cht_wc_i2c_adap_master_func,
|
||||
.smbus_xfer = cht_wc_i2c_adap_smbus_xfer,
|
||||
};
|
||||
|
||||
/**** irqchip for the client connected to the extchgr i2c adapter ****/
|
||||
static void cht_wc_i2c_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&adap->irqchip_lock);
|
||||
}
|
||||
|
||||
static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
|
||||
int ret;
|
||||
|
||||
if (adap->irq_mask != adap->old_irq_mask) {
|
||||
ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK,
|
||||
adap->irq_mask);
|
||||
if (ret == 0)
|
||||
adap->old_irq_mask = adap->irq_mask;
|
||||
else
|
||||
dev_err(&adap->adapter.dev, "Error writing EXTCHGRIRQ_MSK\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&adap->irqchip_lock);
|
||||
}
|
||||
|
||||
static void cht_wc_i2c_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
|
||||
|
||||
adap->irq_mask &= ~CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
|
||||
}
|
||||
|
||||
static void cht_wc_i2c_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
|
||||
|
||||
adap->irq_mask |= CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
|
||||
}
|
||||
|
||||
static const struct irq_chip cht_wc_i2c_irq_chip = {
|
||||
.irq_bus_lock = cht_wc_i2c_irq_lock,
|
||||
.irq_bus_sync_unlock = cht_wc_i2c_irq_sync_unlock,
|
||||
.irq_disable = cht_wc_i2c_irq_disable,
|
||||
.irq_enable = cht_wc_i2c_irq_enable,
|
||||
.name = "cht_wc_ext_chrg_irq_chip",
|
||||
};
|
||||
|
||||
static const struct property_entry bq24190_props[] = {
|
||||
PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"),
|
||||
PROPERTY_ENTRY_BOOL("omit-battery-class"),
|
||||
PROPERTY_ENTRY_BOOL("disable-reset"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
|
||||
struct cht_wc_i2c_adap *adap;
|
||||
struct i2c_board_info board_info = {
|
||||
.type = "bq24190",
|
||||
.addr = 0x6b,
|
||||
.properties = bq24190_props,
|
||||
};
|
||||
int ret, reg, irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Error missing irq resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
|
||||
if (!adap)
|
||||
return -ENOMEM;
|
||||
|
||||
init_waitqueue_head(&adap->wait);
|
||||
mutex_init(&adap->adap_lock);
|
||||
mutex_init(&adap->irqchip_lock);
|
||||
adap->irqchip = cht_wc_i2c_irq_chip;
|
||||
adap->regmap = pmic->regmap;
|
||||
adap->adapter.owner = THIS_MODULE;
|
||||
adap->adapter.class = I2C_CLASS_HWMON;
|
||||
adap->adapter.algo = &cht_wc_i2c_adap_algo;
|
||||
strlcpy(adap->adapter.name, "PMIC I2C Adapter",
|
||||
sizeof(adap->adapter.name));
|
||||
adap->adapter.dev.parent = &pdev->dev;
|
||||
|
||||
/* Clear and activate i2c-adapter interrupts, disable client IRQ */
|
||||
adap->old_irq_mask = adap->irq_mask = ~CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK;
|
||||
|
||||
ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, ~adap->irq_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, adap->irq_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Alloc and register client IRQ */
|
||||
adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
|
||||
&irq_domain_simple_ops, NULL);
|
||||
if (!adap->irq_domain)
|
||||
return -ENOMEM;
|
||||
|
||||
adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
|
||||
if (!adap->client_irq) {
|
||||
ret = -ENOMEM;
|
||||
goto remove_irq_domain;
|
||||
}
|
||||
|
||||
irq_set_chip_data(adap->client_irq, adap);
|
||||
irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
|
||||
handle_simple_irq);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
cht_wc_i2c_adap_thread_handler,
|
||||
IRQF_ONESHOT, "PMIC I2C Adapter", adap);
|
||||
if (ret)
|
||||
goto remove_irq_domain;
|
||||
|
||||
i2c_set_adapdata(&adap->adapter, adap);
|
||||
ret = i2c_add_adapter(&adap->adapter);
|
||||
if (ret)
|
||||
goto remove_irq_domain;
|
||||
|
||||
board_info.irq = adap->client_irq;
|
||||
adap->client = i2c_new_device(&adap->adapter, &board_info);
|
||||
if (!adap->client) {
|
||||
ret = -ENOMEM;
|
||||
goto del_adapter;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, adap);
|
||||
return 0;
|
||||
|
||||
del_adapter:
|
||||
i2c_del_adapter(&adap->adapter);
|
||||
remove_irq_domain:
|
||||
irq_domain_remove(adap->irq_domain);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_unregister_device(adap->client);
|
||||
i2c_del_adapter(&adap->adapter);
|
||||
irq_domain_remove(adap->irq_domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id cht_wc_i2c_adap_id_table[] = {
|
||||
{ .name = "cht_wcove_ext_chgr" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table);
|
||||
|
||||
static struct platform_driver cht_wc_i2c_adap_driver = {
|
||||
.probe = cht_wc_i2c_adap_i2c_probe,
|
||||
.remove = cht_wc_i2c_adap_i2c_remove,
|
||||
.driver = {
|
||||
.name = "cht_wcove_ext_chgr",
|
||||
},
|
||||
.id_table = cht_wc_i2c_adap_id_table,
|
||||
};
|
||||
module_platform_driver(cht_wc_i2c_adap_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver");
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -413,7 +413,7 @@ static const struct i2c_algorithm cpm_i2c_algo = {
|
||||
};
|
||||
|
||||
/* CPM_MAX_READ is also limiting writes according to the code! */
|
||||
static struct i2c_adapter_quirks cpm_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks cpm_i2c_quirks = {
|
||||
.max_num_msgs = CPM_MAXBD,
|
||||
.max_read_len = CPM_MAX_READ,
|
||||
.max_write_len = CPM_MAX_READ,
|
||||
|
@ -733,7 +733,7 @@ static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct i2c_algorithm i2c_davinci_algo = {
|
||||
static const struct i2c_algorithm i2c_davinci_algo = {
|
||||
.master_xfer = i2c_davinci_xfer,
|
||||
.functionality = i2c_davinci_func,
|
||||
};
|
||||
@ -801,7 +801,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(dev->clk))
|
||||
return -ENODEV;
|
||||
return PTR_ERR(dev->clk);
|
||||
clk_prepare_enable(dev->clk);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -876,8 +876,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM
|
||||
static int davinci_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
/* put I2C into reset */
|
||||
davinci_i2c_reset_ctrl(i2c_dev, 0);
|
||||
@ -888,8 +887,7 @@ static int davinci_i2c_suspend(struct device *dev)
|
||||
|
||||
static int davinci_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
clk_prepare_enable(i2c_dev->clk);
|
||||
/* take I2C out of reset */
|
||||
|
@ -439,8 +439,7 @@ static void dw_i2c_plat_complete(struct device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int dw_i2c_plat_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
|
||||
i_dev->disable(i_dev);
|
||||
i2c_dw_plat_prepare_clk(i_dev, false);
|
||||
@ -450,8 +449,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev)
|
||||
|
||||
static int dw_i2c_plat_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
|
||||
i2c_dw_plat_prepare_clk(i_dev, true);
|
||||
i_dev->init(i_dev);
|
||||
|
@ -346,7 +346,7 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
|
||||
return IRQ_RETVAL(ret);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm i2c_dw_algo = {
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.functionality = i2c_dw_func,
|
||||
.reg_slave = i2c_dw_reg_slave,
|
||||
.unreg_slave = i2c_dw_unreg_slave,
|
||||
|
@ -803,8 +803,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int exynos5_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct exynos5_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
i2c->suspended = 1;
|
||||
|
||||
@ -815,8 +814,7 @@ static int exynos5_i2c_suspend_noirq(struct device *dev)
|
||||
|
||||
static int exynos5_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct exynos5_i2c *i2c = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
|
@ -98,8 +98,8 @@ static int of_i2c_gpio_get_pins(struct device_node *np,
|
||||
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);
|
||||
pr_err("%pOF: invalid GPIO pins, sda=%d/scl=%d\n",
|
||||
np, *sda_pin, *scl_pin);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -505,8 +505,7 @@ static int hix5hd2_i2c_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM
|
||||
static int hix5hd2_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
|
||||
struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
@ -515,8 +514,7 @@ static int hix5hd2_i2c_runtime_suspend(struct device *dev)
|
||||
|
||||
static int hix5hd2_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
|
||||
struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_prepare_enable(priv->clk);
|
||||
hix5hd2_i2c_init(priv);
|
||||
|
@ -1332,6 +1332,7 @@ static void i801_add_tco(struct i801_priv *priv)
|
||||
u32 tco_base, tco_ctl;
|
||||
u32 base_addr, ctrl_val;
|
||||
u64 base64_addr;
|
||||
u8 hidden;
|
||||
|
||||
if (!(priv->features & FEATURE_TCO))
|
||||
return;
|
||||
@ -1376,8 +1377,10 @@ static void i801_add_tco(struct i801_priv *priv)
|
||||
|
||||
devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1);
|
||||
|
||||
/* Unhide the P2SB device */
|
||||
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0);
|
||||
/* Unhide the P2SB device, if it is hidden */
|
||||
pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden);
|
||||
if (hidden)
|
||||
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0);
|
||||
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr);
|
||||
base64_addr = base_addr & 0xfffffff0;
|
||||
@ -1385,8 +1388,9 @@ static void i801_add_tco(struct i801_priv *priv)
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr);
|
||||
base64_addr |= (u64)base_addr << 32;
|
||||
|
||||
/* Hide the P2SB device */
|
||||
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x1);
|
||||
/* Hide the P2SB device, if it was hidden before */
|
||||
if (hidden)
|
||||
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
|
||||
spin_unlock(&p2sb_spinlock);
|
||||
|
||||
res = &tco_res[ICH_RES_MEM_OFF];
|
||||
|
@ -289,7 +289,7 @@ static const struct i2c_algorithm kempld_i2c_algorithm = {
|
||||
.functionality = kempld_i2c_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter kempld_i2c_adapter = {
|
||||
static const struct i2c_adapter kempld_i2c_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-kempld",
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
|
@ -457,8 +457,7 @@ static int i2c_lpc2k_remove(struct platform_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_lpc2k_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc2k_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct lpc2k_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
|
||||
@ -467,8 +466,7 @@ static int i2c_lpc2k_suspend(struct device *dev)
|
||||
|
||||
static int i2c_lpc2k_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc2k_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct lpc2k_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_enable(i2c->clk);
|
||||
i2c_lpc2k_reset(i2c);
|
||||
|
@ -433,7 +433,7 @@ static const struct i2c_algorithm mlxcpld_i2c_algo = {
|
||||
.functionality = mlxcpld_i2c_func
|
||||
};
|
||||
|
||||
static struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
|
||||
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
.max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN,
|
||||
.max_write_len = MLXCPLD_I2C_DATA_REG_SZ,
|
||||
|
@ -50,7 +50,6 @@
|
||||
#define I2C_FS_START_CON 0x1800
|
||||
#define I2C_TIME_CLR_VALUE 0x0000
|
||||
#define I2C_TIME_DEFAULT_VALUE 0x0003
|
||||
#define I2C_FS_TIME_INIT_VALUE 0x1303
|
||||
#define I2C_WRRD_TRANAC_VALUE 0x0002
|
||||
#define I2C_RD_TRANAC_VALUE 0x0001
|
||||
|
||||
@ -154,6 +153,7 @@ struct mtk_i2c {
|
||||
bool use_push_pull; /* IO config push-pull mode */
|
||||
|
||||
u16 irq_stat; /* interrupt status */
|
||||
unsigned int clk_src_div;
|
||||
unsigned int speed_hz; /* The speed in transfer */
|
||||
enum mtk_trans_op op;
|
||||
u16 timing_reg;
|
||||
@ -172,6 +172,10 @@ static const struct i2c_adapter_quirks mt6577_i2c_quirks = {
|
||||
.max_comb_2nd_msg_len = 31,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
|
||||
.max_num_msgs = 255,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt6577_compat = {
|
||||
.quirks = &mt6577_i2c_quirks,
|
||||
.pmic_i2c = 0,
|
||||
@ -190,6 +194,15 @@ static const struct mtk_i2c_compatible mt6589_compat = {
|
||||
.support_33bits = 0,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt7622_compat = {
|
||||
.quirks = &mt7622_i2c_quirks,
|
||||
.pmic_i2c = 0,
|
||||
.dcm = 1,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
.support_33bits = 0,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt8173_compat = {
|
||||
.pmic_i2c = 0,
|
||||
.dcm = 1,
|
||||
@ -201,6 +214,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
|
||||
static const struct of_device_id mtk_i2c_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
|
||||
{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
|
||||
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
|
||||
{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
|
||||
{}
|
||||
};
|
||||
@ -285,23 +299,20 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
||||
* less than or equal to i2c->speed_hz. The calculation try to get
|
||||
* sample_cnt and step_cn
|
||||
*/
|
||||
static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
|
||||
unsigned int clock_div)
|
||||
static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
|
||||
unsigned int target_speed,
|
||||
unsigned int *timing_step_cnt,
|
||||
unsigned int *timing_sample_cnt)
|
||||
{
|
||||
unsigned int clk_src;
|
||||
unsigned int step_cnt;
|
||||
unsigned int sample_cnt;
|
||||
unsigned int max_step_cnt;
|
||||
unsigned int target_speed;
|
||||
unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV;
|
||||
unsigned int base_step_cnt;
|
||||
unsigned int opt_div;
|
||||
unsigned int best_mul;
|
||||
unsigned int cnt_mul;
|
||||
|
||||
clk_src = parent_clk / clock_div;
|
||||
target_speed = i2c->speed_hz;
|
||||
|
||||
if (target_speed > MAX_HS_MODE_SPEED)
|
||||
target_speed = MAX_HS_MODE_SPEED;
|
||||
|
||||
@ -347,16 +358,48 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
step_cnt--;
|
||||
sample_cnt--;
|
||||
*timing_step_cnt = step_cnt - 1;
|
||||
*timing_sample_cnt = sample_cnt - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
||||
{
|
||||
unsigned int clk_src;
|
||||
unsigned int step_cnt;
|
||||
unsigned int sample_cnt;
|
||||
unsigned int target_speed;
|
||||
int ret;
|
||||
|
||||
clk_src = parent_clk / i2c->clk_src_div;
|
||||
target_speed = i2c->speed_hz;
|
||||
|
||||
if (target_speed > MAX_FS_MODE_SPEED) {
|
||||
/* Set master code speed register */
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, MAX_FS_MODE_SPEED,
|
||||
&step_cnt, &sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c->timing_reg = (sample_cnt << 8) | step_cnt;
|
||||
|
||||
/* Set the high speed mode register */
|
||||
i2c->timing_reg = I2C_FS_TIME_INIT_VALUE;
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
|
||||
&step_cnt, &sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
|
||||
(sample_cnt << 12) | (step_cnt << 8);
|
||||
} else {
|
||||
i2c->timing_reg = (sample_cnt << 8) | (step_cnt << 0);
|
||||
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
|
||||
&step_cnt, &sample_cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c->timing_reg = (sample_cnt << 8) | step_cnt;
|
||||
|
||||
/* Disable the high speed transaction */
|
||||
i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
|
||||
}
|
||||
@ -647,8 +690,7 @@ static const struct i2c_algorithm mtk_i2c_algorithm = {
|
||||
.functionality = mtk_i2c_functionality,
|
||||
};
|
||||
|
||||
static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c,
|
||||
unsigned int *clk_src_div)
|
||||
static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -656,11 +698,11 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c,
|
||||
if (ret < 0)
|
||||
i2c->speed_hz = I2C_DEFAULT_SPEED;
|
||||
|
||||
ret = of_property_read_u32(np, "clock-div", clk_src_div);
|
||||
ret = of_property_read_u32(np, "clock-div", &i2c->clk_src_div);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (*clk_src_div == 0)
|
||||
if (i2c->clk_src_div == 0)
|
||||
return -EINVAL;
|
||||
|
||||
i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic");
|
||||
@ -676,7 +718,6 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
||||
int ret = 0;
|
||||
struct mtk_i2c *i2c;
|
||||
struct clk *clk;
|
||||
unsigned int clk_src_div;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
|
||||
@ -684,7 +725,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c, &clk_src_div);
|
||||
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
@ -745,7 +786,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name));
|
||||
|
||||
ret = mtk_i2c_set_speed(i2c, clk_get_rate(clk), clk_src_div);
|
||||
ret = mtk_i2c_set_speed(i2c, clk_get_rate(clk));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to set the speed.\n");
|
||||
return -EINVAL;
|
||||
|
@ -820,7 +820,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
goto out;
|
||||
}
|
||||
|
||||
drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
|
||||
drv_data->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (IS_ERR(drv_data->rstc)) {
|
||||
rc = PTR_ERR(drv_data->rstc);
|
||||
goto out;
|
||||
@ -975,8 +975,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int mv64xxx_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(pdev);
|
||||
struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev);
|
||||
|
||||
mv64xxx_i2c_hw_init(drv_data);
|
||||
|
||||
|
@ -1088,7 +1088,7 @@ static struct i2c_vendor_data vendor_db8500 = {
|
||||
.fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */
|
||||
};
|
||||
|
||||
static struct amba_id nmk_i2c_ids[] = {
|
||||
static const struct amba_id nmk_i2c_ids[] = {
|
||||
{
|
||||
.id = 0x00180024,
|
||||
.mask = 0x00ffffff,
|
||||
|
@ -276,7 +276,7 @@ static const struct i2c_algorithm ocores_algorithm = {
|
||||
.functionality = ocores_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter ocores_adapter = {
|
||||
static const struct i2c_adapter ocores_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-ocores",
|
||||
.class = I2C_CLASS_DEPRECATED,
|
||||
|
@ -126,7 +126,7 @@ static const struct i2c_algorithm octeon_i2c_algo = {
|
||||
.functionality = octeon_i2c_functionality,
|
||||
};
|
||||
|
||||
static struct i2c_adapter octeon_i2c_ops = {
|
||||
static const struct i2c_adapter octeon_i2c_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "OCTEON adapter",
|
||||
.algo = &octeon_i2c_algo,
|
||||
|
@ -204,7 +204,7 @@ static const struct i2c_algorithm i2c_opal_algo = {
|
||||
* For two messages, we basically support simple smbus transactions of a
|
||||
* write-then-anything.
|
||||
*/
|
||||
static struct i2c_adapter_quirks i2c_opal_quirks = {
|
||||
static const struct i2c_adapter_quirks i2c_opal_quirks = {
|
||||
.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
|
||||
.max_comb_1st_msg_len = 4,
|
||||
};
|
||||
|
@ -577,7 +577,7 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
|
||||
}
|
||||
|
||||
static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
|
||||
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
.max_write_len = MSP_MAX_BYTES_PER_RW,
|
||||
.max_read_len = MSP_MAX_BYTES_PER_RW,
|
||||
@ -587,7 +587,7 @@ static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
|
||||
|
||||
/* -- Initialization -- */
|
||||
|
||||
static struct i2c_algorithm pmcmsptwi_algo = {
|
||||
static const struct i2c_algorithm pmcmsptwi_algo = {
|
||||
.master_xfer = pmcmsptwi_master_xfer,
|
||||
.functionality = pmcmsptwi_i2c_func,
|
||||
};
|
||||
|
@ -590,7 +590,7 @@ static u32 i2c_pnx_func(struct i2c_adapter *adapter)
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm pnx_algorithm = {
|
||||
static const struct i2c_algorithm pnx_algorithm = {
|
||||
.master_xfer = i2c_pnx_xfer,
|
||||
.functionality = i2c_pnx_func,
|
||||
};
|
||||
|
@ -197,7 +197,7 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
|
||||
.functionality = i2c_powermac_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter_quirks i2c_powermac_quirks = {
|
||||
static const struct i2c_adapter_quirks i2c_powermac_quirks = {
|
||||
.max_num_msgs = 1,
|
||||
};
|
||||
|
||||
@ -234,7 +234,7 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
|
||||
else if (!strcmp(node->name, "deq"))
|
||||
return 0x34;
|
||||
|
||||
dev_warn(&adap->dev, "No i2c address for %s\n", node->full_name);
|
||||
dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
@ -315,8 +315,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap,
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(&adap->dev, "i2c-powermac: modalias failure"
|
||||
" on %s\n", node->full_name);
|
||||
dev_err(&adap->dev, "i2c-powermac: modalias failure on %pOF\n", node);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -348,8 +347,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
if (!pmac_i2c_match_adapter(node, adap))
|
||||
continue;
|
||||
|
||||
dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
|
||||
node->full_name);
|
||||
dev_dbg(&adap->dev, "i2c-powermac: register %pOF\n", node);
|
||||
|
||||
/*
|
||||
* Keep track of some device existence to handle
|
||||
@ -372,7 +370,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev) {
|
||||
dev_err(&adap->dev, "i2c-powermac: Failure to register"
|
||||
" %s\n", node->full_name);
|
||||
" %pOF\n", node);
|
||||
of_node_put(node);
|
||||
/* We do not dispose of the interrupt mapping on
|
||||
* purpose. It's not necessary (interrupt cannot be
|
||||
|
@ -175,7 +175,7 @@ static u32 puv3_i2c_func(struct i2c_adapter *adapter)
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm puv3_i2c_algorithm = {
|
||||
static const struct i2c_algorithm puv3_i2c_algorithm = {
|
||||
.master_xfer = puv3_i2c_xfer,
|
||||
.functionality = puv3_i2c_func,
|
||||
};
|
||||
|
@ -1346,8 +1346,7 @@ static int i2c_pxa_remove(struct platform_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_pxa_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pxa_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct pxa_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
|
||||
@ -1356,8 +1355,7 @@ static int i2c_pxa_suspend_noirq(struct device *dev)
|
||||
|
||||
static int i2c_pxa_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pxa_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct pxa_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_enable(i2c->clk);
|
||||
i2c_pxa_reset(i2c);
|
||||
|
@ -1396,7 +1396,7 @@ static const struct i2c_algorithm qup_i2c_algo_v2 = {
|
||||
* 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.
|
||||
*/
|
||||
static struct i2c_adapter_quirks qup_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks qup_i2c_quirks = {
|
||||
.max_read_len = QUP_READ_LIMIT,
|
||||
};
|
||||
|
||||
|
@ -625,9 +625,8 @@ static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
|
||||
|
||||
chan = dma_request_chan(dev, chan_name);
|
||||
if (IS_ERR(chan)) {
|
||||
ret = PTR_ERR(chan);
|
||||
dev_dbg(dev, "request_channel failed for %s (%d)\n",
|
||||
chan_name, ret);
|
||||
dev_dbg(dev, "request_channel failed for %s (%ld)\n",
|
||||
chan_name, PTR_ERR(chan));
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
@ -1131,6 +1131,11 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
|
||||
.functionality = rk3x_i2c_func,
|
||||
};
|
||||
|
||||
static const struct rk3x_i2c_soc_data rv1108_soc_data = {
|
||||
.grf_offset = -1,
|
||||
.calc_timings = rk3x_i2c_v1_calc_timings,
|
||||
};
|
||||
|
||||
static const struct rk3x_i2c_soc_data rk3066_soc_data = {
|
||||
.grf_offset = 0x154,
|
||||
.calc_timings = rk3x_i2c_v0_calc_timings,
|
||||
@ -1157,6 +1162,10 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rk3x_i2c_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rv1108-i2c",
|
||||
.data = (void *)&rv1108_soc_data
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3066-i2c",
|
||||
.data = (void *)&rk3066_soc_data
|
||||
|
@ -1246,8 +1246,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int s3c24xx_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
i2c->suspended = 1;
|
||||
|
||||
@ -1259,8 +1258,7 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
|
||||
|
||||
static int s3c24xx_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!IS_ERR(i2c->sysreg))
|
||||
|
@ -561,8 +561,8 @@ static struct dma_chan *sh_mobile_i2c_request_dma_chan(struct device *dev,
|
||||
|
||||
chan = dma_request_slave_channel_reason(dev, chan_name);
|
||||
if (IS_ERR(chan)) {
|
||||
ret = PTR_ERR(chan);
|
||||
dev_dbg(dev, "request_channel failed for %s (%d)\n", chan_name, ret);
|
||||
dev_dbg(dev, "request_channel failed for %s (%ld)\n", chan_name,
|
||||
PTR_ERR(chan));
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
@ -421,8 +421,7 @@ static int i2c_sirfsoc_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_sirfsoc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct i2c_adapter *adapter = platform_get_drvdata(pdev);
|
||||
struct i2c_adapter *adapter = dev_get_drvdata(dev);
|
||||
struct sirfsoc_i2c *siic = adapter->algo_data;
|
||||
|
||||
clk_enable(siic->clk);
|
||||
@ -434,8 +433,7 @@ static int i2c_sirfsoc_suspend(struct device *dev)
|
||||
|
||||
static int i2c_sirfsoc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct i2c_adapter *adapter = platform_get_drvdata(pdev);
|
||||
struct i2c_adapter *adapter = dev_get_drvdata(dev);
|
||||
struct sirfsoc_i2c *siic = adapter->algo_data;
|
||||
|
||||
clk_enable(siic->clk);
|
||||
|
646
drivers/i2c/busses/i2c-sprd.c
Normal file
646
drivers/i2c/busses/i2c-sprd.c
Normal file
@ -0,0 +1,646 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Spreadtrum Communications Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define I2C_CTL 0x00
|
||||
#define I2C_ADDR_CFG 0x04
|
||||
#define I2C_COUNT 0x08
|
||||
#define I2C_RX 0x0c
|
||||
#define I2C_TX 0x10
|
||||
#define I2C_STATUS 0x14
|
||||
#define I2C_HSMODE_CFG 0x18
|
||||
#define I2C_VERSION 0x1c
|
||||
#define ADDR_DVD0 0x20
|
||||
#define ADDR_DVD1 0x24
|
||||
#define ADDR_STA0_DVD 0x28
|
||||
#define ADDR_RST 0x2c
|
||||
|
||||
/* I2C_CTL */
|
||||
#define STP_EN BIT(20)
|
||||
#define FIFO_AF_LVL_MASK GENMASK(19, 16)
|
||||
#define FIFO_AF_LVL 16
|
||||
#define FIFO_AE_LVL_MASK GENMASK(15, 12)
|
||||
#define FIFO_AE_LVL 12
|
||||
#define I2C_DMA_EN BIT(11)
|
||||
#define FULL_INTEN BIT(10)
|
||||
#define EMPTY_INTEN BIT(9)
|
||||
#define I2C_DVD_OPT BIT(8)
|
||||
#define I2C_OUT_OPT BIT(7)
|
||||
#define I2C_TRIM_OPT BIT(6)
|
||||
#define I2C_HS_MODE BIT(4)
|
||||
#define I2C_MODE BIT(3)
|
||||
#define I2C_EN BIT(2)
|
||||
#define I2C_INT_EN BIT(1)
|
||||
#define I2C_START BIT(0)
|
||||
|
||||
/* I2C_STATUS */
|
||||
#define SDA_IN BIT(21)
|
||||
#define SCL_IN BIT(20)
|
||||
#define FIFO_FULL BIT(4)
|
||||
#define FIFO_EMPTY BIT(3)
|
||||
#define I2C_INT BIT(2)
|
||||
#define I2C_RX_ACK BIT(1)
|
||||
#define I2C_BUSY BIT(0)
|
||||
|
||||
/* ADDR_RST */
|
||||
#define I2C_RST BIT(0)
|
||||
|
||||
#define I2C_FIFO_DEEP 12
|
||||
#define I2C_FIFO_FULL_THLD 15
|
||||
#define I2C_FIFO_EMPTY_THLD 4
|
||||
#define I2C_DATA_STEP 8
|
||||
#define I2C_ADDR_DVD0_CALC(high, low) \
|
||||
((((high) & GENMASK(15, 0)) << 16) | ((low) & GENMASK(15, 0)))
|
||||
#define I2C_ADDR_DVD1_CALC(high, low) \
|
||||
(((high) & GENMASK(31, 16)) | (((low) & GENMASK(31, 16)) >> 16))
|
||||
|
||||
/* timeout (ms) for pm runtime autosuspend */
|
||||
#define SPRD_I2C_PM_TIMEOUT 1000
|
||||
|
||||
/* SPRD i2c data structure */
|
||||
struct sprd_i2c {
|
||||
struct i2c_adapter adap;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct i2c_msg *msg;
|
||||
struct clk *clk;
|
||||
u32 src_clk;
|
||||
u32 bus_freq;
|
||||
struct completion complete;
|
||||
u8 *buf;
|
||||
u32 count;
|
||||
int irq;
|
||||
int err;
|
||||
};
|
||||
|
||||
static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count)
|
||||
{
|
||||
writel(count, i2c_dev->base + I2C_COUNT);
|
||||
}
|
||||
|
||||
static void sprd_i2c_send_stop(struct sprd_i2c *i2c_dev, int stop)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
if (stop)
|
||||
writel(tmp & ~STP_EN, i2c_dev->base + I2C_CTL);
|
||||
else
|
||||
writel(tmp | STP_EN, i2c_dev->base + I2C_CTL);
|
||||
}
|
||||
|
||||
static void sprd_i2c_clear_start(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
writel(tmp & ~I2C_START, i2c_dev->base + I2C_CTL);
|
||||
}
|
||||
|
||||
static void sprd_i2c_clear_ack(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_STATUS);
|
||||
|
||||
writel(tmp & ~I2C_RX_ACK, i2c_dev->base + I2C_STATUS);
|
||||
}
|
||||
|
||||
static void sprd_i2c_clear_irq(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_STATUS);
|
||||
|
||||
writel(tmp & ~I2C_INT, i2c_dev->base + I2C_STATUS);
|
||||
}
|
||||
|
||||
static void sprd_i2c_reset_fifo(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
writel(I2C_RST, i2c_dev->base + ADDR_RST);
|
||||
}
|
||||
|
||||
static void sprd_i2c_set_devaddr(struct sprd_i2c *i2c_dev, struct i2c_msg *m)
|
||||
{
|
||||
writel(m->addr << 1, i2c_dev->base + I2C_ADDR_CFG);
|
||||
}
|
||||
|
||||
static void sprd_i2c_write_bytes(struct sprd_i2c *i2c_dev, u8 *buf, u32 len)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
writeb(buf[i], i2c_dev->base + I2C_TX);
|
||||
}
|
||||
|
||||
static void sprd_i2c_read_bytes(struct sprd_i2c *i2c_dev, u8 *buf, u32 len)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = readb(i2c_dev->base + I2C_RX);
|
||||
}
|
||||
|
||||
static void sprd_i2c_set_full_thld(struct sprd_i2c *i2c_dev, u32 full_thld)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
tmp &= ~FIFO_AF_LVL_MASK;
|
||||
tmp |= full_thld << FIFO_AF_LVL;
|
||||
writel(tmp, i2c_dev->base + I2C_CTL);
|
||||
};
|
||||
|
||||
static void sprd_i2c_set_empty_thld(struct sprd_i2c *i2c_dev, u32 empty_thld)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
tmp &= ~FIFO_AE_LVL_MASK;
|
||||
tmp |= empty_thld << FIFO_AE_LVL;
|
||||
writel(tmp, i2c_dev->base + I2C_CTL);
|
||||
};
|
||||
|
||||
static void sprd_i2c_set_fifo_full_int(struct sprd_i2c *i2c_dev, int enable)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
if (enable)
|
||||
tmp |= FULL_INTEN;
|
||||
else
|
||||
tmp &= ~FULL_INTEN;
|
||||
|
||||
writel(tmp, i2c_dev->base + I2C_CTL);
|
||||
};
|
||||
|
||||
static void sprd_i2c_set_fifo_empty_int(struct sprd_i2c *i2c_dev, int enable)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
if (enable)
|
||||
tmp |= EMPTY_INTEN;
|
||||
else
|
||||
tmp &= ~EMPTY_INTEN;
|
||||
|
||||
writel(tmp, i2c_dev->base + I2C_CTL);
|
||||
};
|
||||
|
||||
static void sprd_i2c_opt_start(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
|
||||
writel(tmp | I2C_START, i2c_dev->base + I2C_CTL);
|
||||
}
|
||||
|
||||
static void sprd_i2c_opt_mode(struct sprd_i2c *i2c_dev, int rw)
|
||||
{
|
||||
u32 cmd = readl(i2c_dev->base + I2C_CTL) & ~I2C_MODE;
|
||||
|
||||
writel(cmd | rw << 3, i2c_dev->base + I2C_CTL);
|
||||
}
|
||||
|
||||
static void sprd_i2c_data_transfer(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 i2c_count = i2c_dev->count;
|
||||
u32 need_tran = i2c_count <= I2C_FIFO_DEEP ? i2c_count : I2C_FIFO_DEEP;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
sprd_i2c_read_bytes(i2c_dev, i2c_dev->buf, I2C_FIFO_FULL_THLD);
|
||||
i2c_dev->count -= I2C_FIFO_FULL_THLD;
|
||||
i2c_dev->buf += I2C_FIFO_FULL_THLD;
|
||||
|
||||
/*
|
||||
* If the read data count is larger than rx fifo full threshold,
|
||||
* we should enable the rx fifo full interrupt to read data
|
||||
* again.
|
||||
*/
|
||||
if (i2c_dev->count >= I2C_FIFO_FULL_THLD)
|
||||
sprd_i2c_set_fifo_full_int(i2c_dev, 1);
|
||||
} else {
|
||||
sprd_i2c_write_bytes(i2c_dev, i2c_dev->buf, need_tran);
|
||||
i2c_dev->buf += need_tran;
|
||||
i2c_dev->count -= need_tran;
|
||||
|
||||
/*
|
||||
* If the write data count is arger than tx fifo depth which
|
||||
* means we can not write all data in one time, then we should
|
||||
* enable the tx fifo empty interrupt to write again.
|
||||
*/
|
||||
if (i2c_count > I2C_FIFO_DEEP)
|
||||
sprd_i2c_set_fifo_empty_int(i2c_dev, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int sprd_i2c_handle_msg(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msg, bool is_last_msg)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
|
||||
|
||||
i2c_dev->msg = msg;
|
||||
i2c_dev->buf = msg->buf;
|
||||
i2c_dev->count = msg->len;
|
||||
|
||||
reinit_completion(&i2c_dev->complete);
|
||||
sprd_i2c_reset_fifo(i2c_dev);
|
||||
sprd_i2c_set_devaddr(i2c_dev, msg);
|
||||
sprd_i2c_set_count(i2c_dev, msg->len);
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
sprd_i2c_opt_mode(i2c_dev, 1);
|
||||
sprd_i2c_send_stop(i2c_dev, 1);
|
||||
} else {
|
||||
sprd_i2c_opt_mode(i2c_dev, 0);
|
||||
sprd_i2c_send_stop(i2c_dev, !!is_last_msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* We should enable rx fifo full interrupt to get data when receiving
|
||||
* full data.
|
||||
*/
|
||||
if (msg->flags & I2C_M_RD)
|
||||
sprd_i2c_set_fifo_full_int(i2c_dev, 1);
|
||||
else
|
||||
sprd_i2c_data_transfer(i2c_dev);
|
||||
|
||||
sprd_i2c_opt_start(i2c_dev);
|
||||
|
||||
wait_for_completion(&i2c_dev->complete);
|
||||
|
||||
return i2c_dev->err;
|
||||
}
|
||||
|
||||
static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
|
||||
int im, ret;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (im = 0; im < num - 1; im++) {
|
||||
ret = sprd_i2c_handle_msg(i2c_adap, &msgs[im], 0);
|
||||
if (ret)
|
||||
goto err_msg;
|
||||
}
|
||||
|
||||
ret = sprd_i2c_handle_msg(i2c_adap, &msgs[im++], 1);
|
||||
|
||||
err_msg:
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||
|
||||
return ret < 0 ? ret : im;
|
||||
}
|
||||
|
||||
static u32 sprd_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sprd_i2c_algo = {
|
||||
.master_xfer = sprd_i2c_master_xfer,
|
||||
.functionality = sprd_i2c_func,
|
||||
};
|
||||
|
||||
static void sprd_i2c_set_clk(struct sprd_i2c *i2c_dev, u32 freq)
|
||||
{
|
||||
u32 apb_clk = i2c_dev->src_clk;
|
||||
/*
|
||||
* From I2C databook, the prescale calculation formula:
|
||||
* prescale = freq_i2c / (4 * freq_scl) - 1;
|
||||
*/
|
||||
u32 i2c_dvd = apb_clk / (4 * freq) - 1;
|
||||
/*
|
||||
* From I2C databook, the high period of SCL clock is recommended as
|
||||
* 40% (2/5), and the low period of SCL clock is recommended as 60%
|
||||
* (3/5), then the formula should be:
|
||||
* high = (prescale * 2 * 2) / 5
|
||||
* low = (prescale * 2 * 3) / 5
|
||||
*/
|
||||
u32 high = ((i2c_dvd << 1) * 2) / 5;
|
||||
u32 low = ((i2c_dvd << 1) * 3) / 5;
|
||||
u32 div0 = I2C_ADDR_DVD0_CALC(high, low);
|
||||
u32 div1 = I2C_ADDR_DVD1_CALC(high, low);
|
||||
|
||||
writel(div0, i2c_dev->base + ADDR_DVD0);
|
||||
writel(div1, i2c_dev->base + ADDR_DVD1);
|
||||
|
||||
/* Start hold timing = hold time(us) * source clock */
|
||||
if (freq == 400000)
|
||||
writel((6 * apb_clk) / 10000000, i2c_dev->base + ADDR_STA0_DVD);
|
||||
else if (freq == 100000)
|
||||
writel((4 * apb_clk) / 1000000, i2c_dev->base + ADDR_STA0_DVD);
|
||||
}
|
||||
|
||||
static void sprd_i2c_enable(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
u32 tmp = I2C_DVD_OPT;
|
||||
|
||||
writel(tmp, i2c_dev->base + I2C_CTL);
|
||||
|
||||
sprd_i2c_set_full_thld(i2c_dev, I2C_FIFO_FULL_THLD);
|
||||
sprd_i2c_set_empty_thld(i2c_dev, I2C_FIFO_EMPTY_THLD);
|
||||
|
||||
sprd_i2c_set_clk(i2c_dev, i2c_dev->bus_freq);
|
||||
sprd_i2c_reset_fifo(i2c_dev);
|
||||
sprd_i2c_clear_irq(i2c_dev);
|
||||
|
||||
tmp = readl(i2c_dev->base + I2C_CTL);
|
||||
writel(tmp | I2C_EN | I2C_INT_EN, i2c_dev->base + I2C_CTL);
|
||||
}
|
||||
|
||||
static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = dev_id;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
|
||||
u32 i2c_count = readl(i2c_dev->base + I2C_COUNT);
|
||||
u32 i2c_tran;
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
|
||||
else
|
||||
i2c_tran = i2c_count;
|
||||
|
||||
/*
|
||||
* If we got one ACK from slave when writing data, and we did not
|
||||
* finish this transmission (i2c_tran is not zero), then we should
|
||||
* continue to write data.
|
||||
*
|
||||
* For reading data, ack is always true, if i2c_tran is not 0 which
|
||||
* means we still need to contine to read data from slave.
|
||||
*/
|
||||
if (i2c_tran && ack) {
|
||||
sprd_i2c_data_transfer(i2c_dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
i2c_dev->err = 0;
|
||||
|
||||
/*
|
||||
* If we did not get one ACK from slave when writing data, we should
|
||||
* return -EIO to notify users.
|
||||
*/
|
||||
if (!ack)
|
||||
i2c_dev->err = -EIO;
|
||||
else if (msg->flags & I2C_M_RD && i2c_dev->count)
|
||||
sprd_i2c_read_bytes(i2c_dev, i2c_dev->buf, i2c_dev->count);
|
||||
|
||||
/* Transmission is done and clear ack and start operation */
|
||||
sprd_i2c_clear_ack(i2c_dev);
|
||||
sprd_i2c_clear_start(i2c_dev);
|
||||
complete(&i2c_dev->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sprd_i2c_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = dev_id;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
u32 i2c_count = readl(i2c_dev->base + I2C_COUNT);
|
||||
bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
|
||||
u32 i2c_tran;
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
|
||||
else
|
||||
i2c_tran = i2c_count;
|
||||
|
||||
/*
|
||||
* If we did not get one ACK from slave when writing data, then we
|
||||
* should finish this transmission since we got some errors.
|
||||
*
|
||||
* When writing data, if i2c_tran == 0 which means we have writen
|
||||
* done all data, then we can finish this transmission.
|
||||
*
|
||||
* When reading data, if conut < rx fifo full threshold, which
|
||||
* means we can read all data in one time, then we can finish this
|
||||
* transmission too.
|
||||
*/
|
||||
if (!i2c_tran || !ack) {
|
||||
sprd_i2c_clear_start(i2c_dev);
|
||||
sprd_i2c_clear_irq(i2c_dev);
|
||||
}
|
||||
|
||||
sprd_i2c_set_fifo_empty_int(i2c_dev, 0);
|
||||
sprd_i2c_set_fifo_full_int(i2c_dev, 0);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static int sprd_i2c_clk_init(struct sprd_i2c *i2c_dev)
|
||||
{
|
||||
struct clk *clk_i2c, *clk_parent;
|
||||
|
||||
clk_i2c = devm_clk_get(i2c_dev->dev, "i2c");
|
||||
if (IS_ERR(clk_i2c)) {
|
||||
dev_warn(i2c_dev->dev, "i2c%d can't get the i2c clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
clk_i2c = NULL;
|
||||
}
|
||||
|
||||
clk_parent = devm_clk_get(i2c_dev->dev, "source");
|
||||
if (IS_ERR(clk_parent)) {
|
||||
dev_warn(i2c_dev->dev, "i2c%d can't get the source clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
clk_parent = NULL;
|
||||
}
|
||||
|
||||
if (clk_set_parent(clk_i2c, clk_parent))
|
||||
i2c_dev->src_clk = clk_get_rate(clk_i2c);
|
||||
else
|
||||
i2c_dev->src_clk = 26000000;
|
||||
|
||||
dev_dbg(i2c_dev->dev, "i2c%d set source clock is %d\n",
|
||||
i2c_dev->adap.nr, i2c_dev->src_clk);
|
||||
|
||||
i2c_dev->clk = devm_clk_get(i2c_dev->dev, "enable");
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_warn(i2c_dev->dev, "i2c%d can't get the enable clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
i2c_dev->clk = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sprd_i2c *i2c_dev;
|
||||
struct resource *res;
|
||||
u32 prop;
|
||||
int ret;
|
||||
|
||||
pdev->id = of_alias_get_id(dev->of_node, "i2c");
|
||||
|
||||
i2c_dev = devm_kzalloc(dev, sizeof(struct sprd_i2c), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c_dev->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
i2c_dev->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c_dev->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get irq resource\n");
|
||||
return i2c_dev->irq;
|
||||
}
|
||||
|
||||
i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
|
||||
init_completion(&i2c_dev->complete);
|
||||
snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
|
||||
"%s", "sprd-i2c");
|
||||
|
||||
i2c_dev->bus_freq = 100000;
|
||||
i2c_dev->adap.owner = THIS_MODULE;
|
||||
i2c_dev->dev = dev;
|
||||
i2c_dev->adap.retries = 3;
|
||||
i2c_dev->adap.algo = &sprd_i2c_algo;
|
||||
i2c_dev->adap.algo_data = i2c_dev;
|
||||
i2c_dev->adap.dev.parent = dev;
|
||||
i2c_dev->adap.nr = pdev->id;
|
||||
i2c_dev->adap.dev.of_node = dev->of_node;
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "clock-frequency", &prop))
|
||||
i2c_dev->bus_freq = prop;
|
||||
|
||||
/* We only support 100k and 400k now, otherwise will return error. */
|
||||
if (i2c_dev->bus_freq != 100000 && i2c_dev->bus_freq != 400000)
|
||||
return -EINVAL;
|
||||
|
||||
sprd_i2c_clk_init(i2c_dev);
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sprd_i2c_enable(i2c_dev);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(i2c_dev->dev, SPRD_I2C_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(i2c_dev->dev);
|
||||
pm_runtime_set_active(i2c_dev->dev);
|
||||
pm_runtime_enable(i2c_dev->dev);
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
goto err_rpm_put;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, i2c_dev->irq,
|
||||
sprd_i2c_isr, sprd_i2c_isr_thread,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request irq %d\n", i2c_dev->irq);
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
ret = i2c_add_numbered_adapter(&i2c_dev->adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "add adapter failed\n");
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||
return 0;
|
||||
|
||||
err_rpm_put:
|
||||
pm_runtime_put_noidle(i2c_dev->dev);
|
||||
pm_runtime_disable(i2c_dev->dev);
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sprd_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c_del_adapter(&i2c_dev->adap);
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
pm_runtime_put_noidle(i2c_dev->dev);
|
||||
pm_runtime_disable(i2c_dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)
|
||||
{
|
||||
return pm_runtime_force_suspend(pdev);
|
||||
}
|
||||
|
||||
static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)
|
||||
{
|
||||
return pm_runtime_force_resume(pdev);
|
||||
}
|
||||
|
||||
static int __maybe_unused sprd_i2c_runtime_suspend(struct device *pdev)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sprd_i2c_runtime_resume(struct device *pdev)
|
||||
{
|
||||
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sprd_i2c_enable(i2c_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sprd_i2c_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sprd_i2c_runtime_suspend,
|
||||
sprd_i2c_runtime_resume, NULL)
|
||||
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sprd_i2c_suspend_noirq,
|
||||
sprd_i2c_resume_noirq)
|
||||
};
|
||||
|
||||
static const struct of_device_id sprd_i2c_of_match[] = {
|
||||
{ .compatible = "sprd,sc9860-i2c", },
|
||||
};
|
||||
|
||||
static struct platform_driver sprd_i2c_driver = {
|
||||
.probe = sprd_i2c_probe,
|
||||
.remove = sprd_i2c_remove,
|
||||
.driver = {
|
||||
.name = "sprd-i2c",
|
||||
.of_match_table = sprd_i2c_of_match,
|
||||
.pm = &sprd_i2c_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int sprd_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&sprd_i2c_driver);
|
||||
}
|
||||
arch_initcall_sync(sprd_i2c_init);
|
@ -745,8 +745,7 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int st_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct st_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (i2c_dev->busy)
|
||||
return -EBUSY;
|
||||
|
@ -751,7 +751,7 @@ static u32 stm32f4_i2c_func(struct i2c_adapter *adap)
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm stm32f4_i2c_algo = {
|
||||
static const struct i2c_algorithm stm32f4_i2c_algo = {
|
||||
.master_xfer = stm32f4_i2c_xfer,
|
||||
.functionality = stm32f4_i2c_func,
|
||||
};
|
||||
@ -798,7 +798,7 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rst = devm_reset_control_get(&pdev->dev, NULL);
|
||||
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(&pdev->dev, "Error: Missing controller reset\n");
|
||||
ret = PTR_ERR(rst);
|
||||
|
@ -223,8 +223,8 @@ static int p2wi_probe(struct platform_device *pdev)
|
||||
if (childnp) {
|
||||
ret = of_property_read_u32(childnp, "reg", &slave_addr);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid slave address on node %s\n",
|
||||
childnp->full_name);
|
||||
dev_err(dev, "invalid slave address on node %pOF\n",
|
||||
childnp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@ static int p2wi_probe(struct platform_device *pdev)
|
||||
|
||||
parent_clk_freq = clk_get_rate(p2wi->clk);
|
||||
|
||||
p2wi->rstc = devm_reset_control_get(dev, NULL);
|
||||
p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);
|
||||
if (IS_ERR(p2wi->rstc)) {
|
||||
ret = PTR_ERR(p2wi->rstc);
|
||||
dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
|
||||
|
@ -291,7 +291,7 @@ static void taos_disconnect(struct serio *serio)
|
||||
dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
|
||||
}
|
||||
|
||||
static struct serio_device_id taos_serio_ids[] = {
|
||||
static const struct serio_device_id taos_serio_ids[] = {
|
||||
{
|
||||
.type = SERIO_RS232,
|
||||
.proto = SERIO_TAOSEVM,
|
||||
|
@ -793,7 +793,7 @@ static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
};
|
||||
|
||||
/* payload size is only 12 bit */
|
||||
static struct i2c_adapter_quirks tegra_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks tegra_i2c_quirks = {
|
||||
.max_read_len = 4096,
|
||||
.max_write_len = 4096,
|
||||
};
|
||||
@ -911,7 +911,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
i2c_dev->cont_id = pdev->id;
|
||||
i2c_dev->dev = &pdev->dev;
|
||||
|
||||
i2c_dev->rst = devm_reset_control_get(&pdev->dev, "i2c");
|
||||
i2c_dev->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c");
|
||||
if (IS_ERR(i2c_dev->rst)) {
|
||||
dev_err(&pdev->dev, "missing controller reset\n");
|
||||
return PTR_ERR(i2c_dev->rst);
|
||||
|
@ -75,7 +75,7 @@ static const struct i2c_algorithm thunderx_i2c_algo = {
|
||||
.functionality = thunderx_i2c_functionality,
|
||||
};
|
||||
|
||||
static struct i2c_adapter thunderx_i2c_ops = {
|
||||
static const struct i2c_adapter thunderx_i2c_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ThunderX adapter",
|
||||
.algo = &thunderx_i2c_algo,
|
||||
|
@ -97,6 +97,7 @@ struct uniphier_fi2c_priv {
|
||||
int error;
|
||||
unsigned int flags;
|
||||
unsigned int busy_cnt;
|
||||
unsigned int clk_cycle;
|
||||
};
|
||||
|
||||
static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
|
||||
@ -461,9 +462,9 @@ static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
|
||||
.unprepare_recovery = uniphier_fi2c_unprepare_recovery,
|
||||
};
|
||||
|
||||
static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv,
|
||||
u32 bus_speed, unsigned long clk_rate)
|
||||
static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv)
|
||||
{
|
||||
unsigned int cyc = priv->clk_cycle;
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(priv->membase + UNIPHIER_FI2C_CR);
|
||||
@ -472,12 +473,10 @@ static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv,
|
||||
|
||||
uniphier_fi2c_reset(priv);
|
||||
|
||||
tmp = clk_rate / bus_speed;
|
||||
|
||||
writel(tmp, priv->membase + UNIPHIER_FI2C_CYC);
|
||||
writel(tmp / 2, priv->membase + UNIPHIER_FI2C_LCTL);
|
||||
writel(tmp / 2, priv->membase + UNIPHIER_FI2C_SSUT);
|
||||
writel(tmp / 16, priv->membase + UNIPHIER_FI2C_DSUT);
|
||||
writel(cyc, priv->membase + UNIPHIER_FI2C_CYC);
|
||||
writel(cyc / 2, priv->membase + UNIPHIER_FI2C_LCTL);
|
||||
writel(cyc / 2, priv->membase + UNIPHIER_FI2C_SSUT);
|
||||
writel(cyc / 16, priv->membase + UNIPHIER_FI2C_DSUT);
|
||||
|
||||
uniphier_fi2c_prepare_operation(priv);
|
||||
}
|
||||
@ -531,6 +530,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
priv->clk_cycle = clk_rate / bus_speed;
|
||||
init_completion(&priv->comp);
|
||||
priv->adap.owner = THIS_MODULE;
|
||||
priv->adap.algo = &uniphier_fi2c_algo;
|
||||
@ -541,7 +541,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
||||
i2c_set_adapdata(&priv->adap, priv);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
uniphier_fi2c_hw_init(priv, bus_speed, clk_rate);
|
||||
uniphier_fi2c_hw_init(priv);
|
||||
|
||||
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
|
||||
pdev->name, priv);
|
||||
@ -568,6 +568,33 @@ static int uniphier_fi2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_fi2c_suspend(struct device *dev)
|
||||
{
|
||||
struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_fi2c_resume(struct device *dev)
|
||||
{
|
||||
struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uniphier_fi2c_hw_init(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops uniphier_fi2c_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(uniphier_fi2c_suspend, uniphier_fi2c_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_fi2c_match[] = {
|
||||
{ .compatible = "socionext,uniphier-fi2c" },
|
||||
{ /* sentinel */ }
|
||||
@ -580,6 +607,7 @@ static struct platform_driver uniphier_fi2c_drv = {
|
||||
.driver = {
|
||||
.name = "uniphier-fi2c",
|
||||
.of_match_table = uniphier_fi2c_match,
|
||||
.pm = &uniphier_fi2c_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_fi2c_drv);
|
||||
|
@ -53,6 +53,7 @@ struct uniphier_i2c_priv {
|
||||
void __iomem *membase;
|
||||
struct clk *clk;
|
||||
unsigned int busy_cnt;
|
||||
unsigned int clk_cycle;
|
||||
};
|
||||
|
||||
static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
|
||||
@ -316,13 +317,13 @@ static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
|
||||
.unprepare_recovery = uniphier_i2c_unprepare_recovery,
|
||||
};
|
||||
|
||||
static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv,
|
||||
u32 bus_speed, unsigned long clk_rate)
|
||||
static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv)
|
||||
{
|
||||
unsigned int cyc = priv->clk_cycle;
|
||||
|
||||
uniphier_i2c_reset(priv, true);
|
||||
|
||||
writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed),
|
||||
priv->membase + UNIPHIER_I2C_CLK);
|
||||
writel((cyc / 2 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK);
|
||||
|
||||
uniphier_i2c_reset(priv, false);
|
||||
}
|
||||
@ -376,6 +377,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
priv->clk_cycle = clk_rate / bus_speed;
|
||||
init_completion(&priv->comp);
|
||||
priv->adap.owner = THIS_MODULE;
|
||||
priv->adap.algo = &uniphier_i2c_algo;
|
||||
@ -386,7 +388,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
||||
i2c_set_adapdata(&priv->adap, priv);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
uniphier_i2c_hw_init(priv, bus_speed, clk_rate);
|
||||
uniphier_i2c_hw_init(priv);
|
||||
|
||||
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
|
||||
priv);
|
||||
@ -413,6 +415,33 @@ static int uniphier_i2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused uniphier_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uniphier_i2c_hw_init(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops uniphier_i2c_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(uniphier_i2c_suspend, uniphier_i2c_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_i2c_match[] = {
|
||||
{ .compatible = "socionext,uniphier-i2c" },
|
||||
{ /* sentinel */ }
|
||||
@ -425,6 +454,7 @@ static struct platform_driver uniphier_i2c_drv = {
|
||||
.driver = {
|
||||
.name = "uniphier-i2c",
|
||||
.of_match_table = uniphier_i2c_match,
|
||||
.pm = &uniphier_i2c_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_i2c_drv);
|
||||
|
@ -55,7 +55,7 @@ static int i2c_versatile_getscl(void *data)
|
||||
return !!(readl(i2c->base + I2C_CONTROL) & SCL);
|
||||
}
|
||||
|
||||
static struct i2c_algo_bit_data i2c_versatile_algo = {
|
||||
static const struct i2c_algo_bit_data i2c_versatile_algo = {
|
||||
.setsda = i2c_versatile_setsda,
|
||||
.setscl = i2c_versatile_setscl,
|
||||
.getsda = i2c_versatile_getsda,
|
||||
|
@ -721,7 +721,7 @@ static const struct i2c_algorithm xiic_algorithm = {
|
||||
.functionality = xiic_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter xiic_adapter = {
|
||||
static const struct i2c_adapter xiic_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.class = I2C_CLASS_DEPRECATED,
|
||||
@ -853,8 +853,7 @@ MODULE_DEVICE_TABLE(of, xiic_of_match);
|
||||
|
||||
static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct xiic_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
|
||||
@ -863,8 +862,7 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
|
||||
|
||||
static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct xiic_i2c *i2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(i2c->clk);
|
||||
|
@ -32,18 +32,17 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
|
||||
u32 addr;
|
||||
int len;
|
||||
|
||||
dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
|
||||
dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node);
|
||||
|
||||
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
|
||||
dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
|
||||
node->full_name);
|
||||
dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n",
|
||||
node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
addr_be = of_get_property(node, "reg", &len);
|
||||
if (!addr_be || (len < sizeof(*addr_be))) {
|
||||
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
|
||||
node->full_name);
|
||||
dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
@ -59,8 +58,8 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
|
||||
}
|
||||
|
||||
if (i2c_check_addr_validity(addr, info.flags)) {
|
||||
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
|
||||
addr, node->full_name);
|
||||
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %pOF\n",
|
||||
addr, node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
@ -76,8 +75,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
|
||||
|
||||
result = i2c_new_device(adap, &info);
|
||||
if (result == NULL) {
|
||||
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
|
||||
node->full_name);
|
||||
dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
|
||||
of_node_put(node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -106,8 +104,8 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
|
||||
client = of_i2c_register_device(adap, node);
|
||||
if (IS_ERR(client)) {
|
||||
dev_warn(&adap->dev,
|
||||
"Failed to create I2C device for %s\n",
|
||||
node->full_name);
|
||||
"Failed to create I2C device for %pOF\n",
|
||||
node);
|
||||
of_node_clear_flag(node, OF_POPULATED);
|
||||
}
|
||||
}
|
||||
@ -243,8 +241,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
|
||||
put_device(&adap->dev);
|
||||
|
||||
if (IS_ERR(client)) {
|
||||
dev_err(&adap->dev, "failed to create client for '%s'\n",
|
||||
rd->dn->full_name);
|
||||
dev_err(&adap->dev, "failed to create client for '%pOF'\n",
|
||||
rd->dn);
|
||||
of_node_clear_flag(rd->dn, OF_POPULATED);
|
||||
return notifier_from_errno(PTR_ERR(client));
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ menu "Multiplexer I2C Chip support"
|
||||
config I2C_ARB_GPIO_CHALLENGE
|
||||
tristate "GPIO-based I2C arbitration"
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for an
|
||||
I2C multimaster arbitration scheme using GPIOs and a challenge &
|
||||
@ -76,6 +76,7 @@ config I2C_MUX_PCA954x
|
||||
config I2C_MUX_PINCTRL
|
||||
tristate "pinctrl-based I2C multiplexer"
|
||||
depends on PINCTRL
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for an I2C
|
||||
multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing.
|
||||
|
@ -167,8 +167,8 @@ static ssize_t available_masters_show(struct device *dev,
|
||||
int count = 0, i;
|
||||
|
||||
for (i = 0; i < priv->num_chan && count < PAGE_SIZE; i++)
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count, "%d:%s%c",
|
||||
i, priv->chan[i].parent_np->full_name,
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count, "%d:%pOF%c",
|
||||
i, priv->chan[i].parent_np,
|
||||
i == priv->num_chan - 1 ? '\n' : ' ');
|
||||
|
||||
return count;
|
||||
|
@ -38,9 +38,9 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/x86/mlxcpld.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c/mlxcpld.h>
|
||||
|
||||
#define CPLD_MUX_MAX_NCHANS 8
|
||||
|
||||
|
@ -16,15 +16,14 @@
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/pca954x.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* The PCA9541 is a bus master selector. It supports two I2C masters connected
|
||||
|
@ -39,13 +39,13 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_data/pca954x.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -20,17 +20,14 @@
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/i2c-mux-pinctrl.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include "../../pinctrl/core.h"
|
||||
|
||||
struct i2c_mux_pinctrl {
|
||||
struct i2c_mux_pinctrl_platform_data *pdata;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state **states;
|
||||
struct pinctrl_state *state_idle;
|
||||
};
|
||||
|
||||
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
@ -42,85 +39,9 @@ static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
|
||||
static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
|
||||
|
||||
return pinctrl_select_state(mux->pinctrl, mux->state_idle);
|
||||
return i2c_mux_pinctrl_select(muxc, muxc->num_adapters);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int num_names, i, ret;
|
||||
struct device_node *adapter_np;
|
||||
struct i2c_adapter *adapter;
|
||||
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
|
||||
if (!mux->pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
num_names = of_property_count_strings(np, "pinctrl-names");
|
||||
if (num_names < 0) {
|
||||
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
num_names);
|
||||
return num_names;
|
||||
}
|
||||
|
||||
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->pdata->pinctrl_states) * num_names,
|
||||
GFP_KERNEL);
|
||||
if (!mux->pdata->pinctrl_states)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_names; i++) {
|
||||
ret = of_property_read_string_index(np, "pinctrl-names", i,
|
||||
&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
|
||||
"idle")) {
|
||||
if (i != num_names - 1) {
|
||||
dev_err(&pdev->dev,
|
||||
"idle state must be last\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mux->pdata->pinctrl_state_idle = "idle";
|
||||
} else {
|
||||
mux->pdata->bus_count++;
|
||||
}
|
||||
}
|
||||
|
||||
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
|
||||
if (!adapter_np) {
|
||||
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
adapter = of_find_i2c_adapter_by_node(adapter_np);
|
||||
of_node_put(adapter_np);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "Cannot find parent bus\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
|
||||
put_device(&adapter->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
|
||||
struct pinctrl_state *state)
|
||||
{
|
||||
@ -141,110 +62,108 @@ static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
|
||||
return root;
|
||||
}
|
||||
|
||||
static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *parent_np;
|
||||
struct i2c_adapter *parent;
|
||||
|
||||
parent_np = of_parse_phandle(np, "i2c-parent", 0);
|
||||
if (!parent_np) {
|
||||
dev_err(dev, "Cannot parse i2c-parent\n");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
parent = of_find_i2c_adapter_by_node(parent_np);
|
||||
of_node_put(parent_np);
|
||||
if (!parent)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_mux_pinctrl *mux;
|
||||
struct i2c_adapter *parent;
|
||||
struct i2c_adapter *root;
|
||||
int i, ret;
|
||||
int num_names, i, ret;
|
||||
const char *name;
|
||||
|
||||
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
num_names = of_property_count_strings(np, "pinctrl-names");
|
||||
if (num_names < 0) {
|
||||
dev_err(dev, "Cannot parse pinctrl-names: %d\n",
|
||||
num_names);
|
||||
return num_names;
|
||||
}
|
||||
|
||||
mux->pdata = dev_get_platdata(&pdev->dev);
|
||||
if (!mux->pdata) {
|
||||
ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
if (!mux->pdata) {
|
||||
dev_err(&pdev->dev, "Missing platform data\n");
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
parent = i2c_mux_pinctrl_parent_adapter(dev);
|
||||
if (IS_ERR(parent))
|
||||
return PTR_ERR(parent);
|
||||
|
||||
mux->states = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->states) * mux->pdata->bus_count,
|
||||
GFP_KERNEL);
|
||||
if (!mux->states) {
|
||||
dev_err(&pdev->dev, "Cannot allocate states\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
muxc = i2c_mux_alloc(NULL, &pdev->dev, mux->pdata->bus_count, 0, 0,
|
||||
i2c_mux_pinctrl_select, NULL);
|
||||
muxc = i2c_mux_alloc(parent, dev, num_names,
|
||||
sizeof(*mux) + num_names * sizeof(*mux->states),
|
||||
0, i2c_mux_pinctrl_select, NULL);
|
||||
if (!muxc) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
goto err_put_parent;
|
||||
}
|
||||
muxc->priv = mux;
|
||||
mux = i2c_mux_priv(muxc);
|
||||
mux->states = (struct pinctrl_state **)(mux + 1);
|
||||
|
||||
platform_set_drvdata(pdev, muxc);
|
||||
|
||||
mux->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
mux->pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(mux->pinctrl)) {
|
||||
ret = PTR_ERR(mux->pinctrl);
|
||||
dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret);
|
||||
goto err;
|
||||
dev_err(dev, "Cannot get pinctrl: %d\n", ret);
|
||||
goto err_put_parent;
|
||||
}
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
|
||||
mux->pdata->pinctrl_states[i]);
|
||||
|
||||
for (i = 0; i < num_names; i++) {
|
||||
ret = of_property_read_string_index(np, "pinctrl-names", i,
|
||||
&name);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Cannot parse pinctrl-names: %d\n", ret);
|
||||
goto err_put_parent;
|
||||
}
|
||||
|
||||
mux->states[i] = pinctrl_lookup_state(mux->pinctrl, name);
|
||||
if (IS_ERR(mux->states[i])) {
|
||||
ret = PTR_ERR(mux->states[i]);
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot look up pinctrl state %s: %d\n",
|
||||
mux->pdata->pinctrl_states[i], ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (mux->pdata->pinctrl_state_idle) {
|
||||
mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
|
||||
mux->pdata->pinctrl_state_idle);
|
||||
if (IS_ERR(mux->state_idle)) {
|
||||
ret = PTR_ERR(mux->state_idle);
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot look up pinctrl state %s: %d\n",
|
||||
mux->pdata->pinctrl_state_idle, ret);
|
||||
goto err;
|
||||
dev_err(dev, "Cannot look up pinctrl state %s: %d\n",
|
||||
name, ret);
|
||||
goto err_put_parent;
|
||||
}
|
||||
|
||||
if (strcmp(name, "idle"))
|
||||
continue;
|
||||
|
||||
if (i != num_names - 1) {
|
||||
dev_err(dev, "idle state must be last\n");
|
||||
ret = -EINVAL;
|
||||
goto err_put_parent;
|
||||
}
|
||||
muxc->deselect = i2c_mux_pinctrl_deselect;
|
||||
}
|
||||
|
||||
muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
|
||||
if (!muxc->parent) {
|
||||
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
|
||||
mux->pdata->parent_bus_num);
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
root = i2c_root_adapter(&muxc->parent->dev);
|
||||
|
||||
muxc->mux_locked = true;
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
for (i = 0; i < num_names; i++) {
|
||||
if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
|
||||
muxc->mux_locked = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (muxc->mux_locked && mux->pdata->pinctrl_state_idle &&
|
||||
root != i2c_mux_pinctrl_root_adapter(mux->state_idle))
|
||||
muxc->mux_locked = false;
|
||||
|
||||
if (muxc->mux_locked)
|
||||
dev_info(&pdev->dev, "mux-locked i2c mux\n");
|
||||
dev_info(dev, "mux-locked i2c mux\n");
|
||||
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
u32 bus = mux->pdata->base_bus_num ?
|
||||
(mux->pdata->base_bus_num + i) : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, bus, i, 0);
|
||||
/* Do not add any adapter for the idle state (if it's there at all). */
|
||||
for (i = 0; i < num_names - !!muxc->deselect; i++) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, i, 0);
|
||||
if (ret)
|
||||
goto err_del_adapter;
|
||||
}
|
||||
@ -253,8 +172,9 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
|
||||
err_del_adapter:
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
err:
|
||||
err_put_parent:
|
||||
i2c_put_adapter(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -264,16 +184,15 @@ static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id i2c_mux_pinctrl_of_match[] = {
|
||||
{ .compatible = "i2c-mux-pinctrl", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver i2c_mux_pinctrl_driver = {
|
||||
.driver = {
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* i2c-mux-pinctrl platform data
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_I2C_MUX_PINCTRL_H
|
||||
#define _LINUX_I2C_MUX_PINCTRL_H
|
||||
|
||||
/**
|
||||
* struct i2c_mux_pinctrl_platform_data - Platform data for i2c-mux-pinctrl
|
||||
* @parent_bus_num: Parent I2C bus number
|
||||
* @base_bus_num: Base I2C bus number for the child busses. 0 for dynamic.
|
||||
* @bus_count: Number of child busses. Also the number of elements in
|
||||
* @pinctrl_states
|
||||
* @pinctrl_states: The names of the pinctrl state to select for each child bus
|
||||
* @pinctrl_state_idle: The pinctrl state to select when no child bus is being
|
||||
* accessed. If NULL, the most recently used pinctrl state will be left
|
||||
* selected.
|
||||
*/
|
||||
struct i2c_mux_pinctrl_platform_data {
|
||||
int parent_bus_num;
|
||||
int base_bus_num;
|
||||
int bus_count;
|
||||
const char **pinctrl_states;
|
||||
const char *pinctrl_state_idle;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* 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
|
Loading…
Reference in New Issue
Block a user