aboutsummaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig72
-rw-r--r--drivers/i2c/busses/Makefile7
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c84
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-at91.c12
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c30
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c64
-rw-r--r--drivers/i2c/busses/i2c-cadence.c905
-rw-r--r--drivers/i2c/busses/i2c-cpm.c2
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c318
-rw-r--r--drivers/i2c/busses/i2c-davinci.c2
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c30
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c147
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c22
-rw-r--r--drivers/i2c/busses/i2c-diolan-u2c.c1
-rw-r--r--drivers/i2c/busses/i2c-efm32.c479
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c6
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c75
-rw-r--r--drivers/i2c/busses/i2c-gpio.c28
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c5
-rw-r--r--drivers/i2c/busses/i2c-imx.c169
-rw-r--r--drivers/i2c/busses/i2c-ismt.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c2
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c100
-rw-r--r--drivers/i2c/busses/i2c-mxs.c18
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c253
-rw-r--r--drivers/i2c/busses/i2c-nuc900.c709
-rw-r--r--drivers/i2c/busses/i2c-ocores.c4
-rw-r--r--drivers/i2c/busses/i2c-omap.c12
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c2
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c2
-rw-r--r--drivers/i2c/busses/i2c-qup.c768
-rw-r--r--drivers/i2c/busses/i2c-rcar.c269
-rw-r--r--drivers/i2c/busses/i2c-riic.c2
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c763
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c49
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c225
-rw-r--r--drivers/i2c/busses/i2c-simtec.c4
-rw-r--r--drivers/i2c/busses/i2c-sirf.c3
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-st.c4
-rw-r--r--drivers/i2c/busses/i2c-stu300.c6
-rw-r--r--drivers/i2c/busses/i2c-sun6i-p2wi.c344
-rw-r--r--drivers/i2c/busses/i2c-tegra.c6
-rw-r--r--drivers/i2c/busses/i2c-via.c2
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/busses/i2c-wmt.c6
-rw-r--r--drivers/i2c/busses/i2c-xiic.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c6
-rw-r--r--drivers/i2c/i2c-core.c67
-rw-r--r--drivers/i2c/muxes/Kconfig1
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c24
62 files changed, 4511 insertions, 1628 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index f5ed03164d8..9f7d5859cf6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -110,6 +110,7 @@ config I2C_I801
Wellsburg (PCH)
Coleto Creek (PCH)
Wildcat Point-LP (PCH)
+ BayTrail (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -375,6 +376,13 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
help
The unit of the TWI clock is kHz.
+config I2C_CADENCE
+ tristate "Cadence I2C Controller"
+ depends on ARCH_ZYNQ
+ help
+ Say yes here to select Cadence I2C Host Controller. This controller is
+ e.g. used by Xilinx Zynq.
+
config I2C_CBUS_GPIO
tristate "CBUS I2C driver"
depends on GPIOLIB
@@ -387,7 +395,7 @@ config I2C_CBUS_GPIO
config I2C_CPM
tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
- depends on (CPM1 || CPM2) && OF_I2C
+ depends on CPM1 || CPM2
help
This supports the use of the I2C interface on Freescale
processors with CPM1 or CPM2.
@@ -432,9 +440,16 @@ config I2C_DESIGNWARE_PCI
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
+config I2C_EFM32
+ tristate "EFM32 I2C controller"
+ depends on ARCH_EFM32 || COMPILE_TEST
+ help
+ This driver supports the i2c block found in Energy Micro's EFM32
+ SoCs.
+
config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This driver is for PCH(Platform controller Hub) I2C of EG20T which
is an IOH(Input/Output Hub) for x86 embedded processor.
@@ -527,7 +542,7 @@ config I2C_MPC
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
- depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI)
+ depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -555,13 +570,6 @@ config I2C_NOMADIK
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
as well as the STA2X11 PCIe I/O HUB.
-config I2C_NUC900
- tristate "NUC900 I2C Driver"
- depends on ARCH_W90X900
- help
- Say Y here to include support for I2C controller in the
- Winbond/Nuvoton NUC900 based System-on-Chip devices.
-
config I2C_OCORES
tristate "OpenCores I2C Controller"
help
@@ -648,6 +656,16 @@ config I2C_PXA_SLAVE
is necessary for systems where the PXA may be a target on the
I2C bus.
+config I2C_QUP
+ tristate "Qualcomm QUP based I2C controller"
+ depends on ARCH_QCOM
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Qualcomm SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-qup.
+
config I2C_RIIC
tristate "Renesas RIIC adapter"
depends on ARCH_SHMOBILE || COMPILE_TEST
@@ -658,6 +676,16 @@ config I2C_RIIC
This driver can also be built as a module. If so, the module
will be called i2c-riic.
+config I2C_RK3X
+ tristate "Rockchip RK3xxx I2C adapter"
+ depends on OF
+ help
+ Say Y here to include support for the I2C adapter in Rockchip RK3xxx
+ SoCs.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-rk3x.
+
config HAVE_S3C2410_I2C
bool
help
@@ -746,6 +774,19 @@ config I2C_STU300
This driver can also be built as a module. If so, the module
will be called i2c-stu300.
+config I2C_SUN6I_P2WI
+ tristate "Allwinner sun6i internal P2WI controller"
+ depends on RESET_CONTROLLER
+ depends on MACH_SUN6I || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ P2WI (Push/Pull 2 Wire Interface) controller embedded in some sunxi
+ SOCs.
+ The P2WI looks like an SMBus controller (which supports only byte
+ accesses), except that it only supports one slave device.
+ This interface is used to connect to specific PMIC devices (like the
+ AXP221).
+
config I2C_TEGRA
tristate "NVIDIA Tegra internal I2C controller"
depends on ARCH_TEGRA
@@ -936,7 +977,7 @@ config I2C_ACORN
config I2C_ELEKTOR
tristate "Elektor ISA card"
- depends on ISA && HAS_IOPORT && BROKEN_ON_SMP
+ depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP
select I2C_ALGOPCF
help
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
@@ -968,6 +1009,15 @@ config I2C_SIBYTE
help
Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+config I2C_CROS_EC_TUNNEL
+ tristate "ChromeOS EC tunnel I2C bus"
+ depends on MFD_CROS_EC
+ help
+ If you say yes here you get an I2C bus that will tunnel i2c commands
+ through to the other side of the ChromeOS EC to the i2c bus
+ connected there. This will work whatever the interface used to
+ talk to the EC (SPI, I2C or LPC).
+
config SCx200_I2C
tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
depends on SCx200_GPIO
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a08931fe73e..dd9a7f8e873 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
@@ -53,7 +55,6 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
-obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
@@ -63,7 +64,9 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
+obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
@@ -72,6 +75,7 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
+obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
@@ -92,6 +96,7 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o
# Other I2C/SMBus bus drivers
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o
+obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 7d60d3a1f62..451e305f797 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -494,7 +494,7 @@ static struct i2c_adapter ali1535_adapter = {
.algo = &smbus_algorithm,
};
-static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
+static const struct pci_device_id ali1535_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ },
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index 4611e4754a6..15517d78d5f 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -63,7 +63,7 @@
static struct pci_driver ali1563_pci_driver;
static unsigned short ali1563_smba;
-static int ali1563_transaction(struct i2c_adapter * a, int size)
+static int ali1563_transaction(struct i2c_adapter *a, int size)
{
u32 data;
int timeout;
@@ -78,7 +78,7 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) {
dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
- outb_p(data | HST_STS_BAD,SMB_HST_STS);
+ outb_p(data | HST_STS_BAD, SMB_HST_STS);
data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD)
return -EBUSY;
@@ -102,10 +102,10 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
if (!timeout) {
dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
/* Issue 'kill' to host controller */
- outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
+ outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2);
data = inb_p(SMB_HST_STS);
status = -ETIMEDOUT;
- }
+ }
/* device error - no response, ignore the autodetection case */
if (data & HST_STS_DEVERR) {
@@ -117,18 +117,18 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
if (data & HST_STS_BUSERR) {
dev_err(&a->dev, "Bus collision!\n");
/* Issue timeout, hoping it helps */
- outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
+ outb_p(HST_CNTL1_TIMEOUT, SMB_HST_CNTL1);
}
if (data & HST_STS_FAIL) {
dev_err(&a->dev, "Cleaning fail after KILL!\n");
- outb_p(0x0,SMB_HST_CNTL2);
+ outb_p(0x0, SMB_HST_CNTL2);
}
return status;
}
-static int ali1563_block_start(struct i2c_adapter * a)
+static int ali1563_block_start(struct i2c_adapter *a)
{
u32 data;
int timeout;
@@ -142,8 +142,8 @@ static int ali1563_block_start(struct i2c_adapter * a)
data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) {
- dev_warn(&a->dev,"ali1563: Trying to reset busy device\n");
- outb_p(data | HST_STS_BAD,SMB_HST_STS);
+ dev_warn(&a->dev, "ali1563: Trying to reset busy device\n");
+ outb_p(data | HST_STS_BAD, SMB_HST_STS);
data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD)
return -EBUSY;
@@ -184,13 +184,14 @@ static int ali1563_block_start(struct i2c_adapter * a)
return status;
}
-static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw)
+static int ali1563_block(struct i2c_adapter *a,
+ union i2c_smbus_data *data, u8 rw)
{
int i, len;
int error = 0;
/* Do we need this? */
- outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+ outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1);
if (rw == I2C_SMBUS_WRITE) {
len = data->block[0];
@@ -198,8 +199,8 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8
len = 1;
else if (len > 32)
len = 32;
- outb_p(len,SMB_HST_DAT0);
- outb_p(data->block[1],SMB_BLK_DAT);
+ outb_p(len, SMB_HST_DAT0);
+ outb_p(data->block[1], SMB_BLK_DAT);
} else
len = 32;
@@ -208,10 +209,12 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8
for (i = 0; i < len; i++) {
if (rw == I2C_SMBUS_WRITE) {
outb_p(data->block[i + 1], SMB_BLK_DAT);
- if ((error = ali1563_block_start(a)))
+ error = ali1563_block_start(a);
+ if (error)
break;
} else {
- if ((error = ali1563_block_start(a)))
+ error = ali1563_block_start(a);
+ if (error)
break;
if (i == 0) {
len = inb_p(SMB_HST_DAT0);
@@ -224,25 +227,26 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8
}
}
/* Do we need this? */
- outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+ outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1);
return error;
}
-static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
+static s32 ali1563_access(struct i2c_adapter *a, u16 addr,
unsigned short flags, char rw, u8 cmd,
- int size, union i2c_smbus_data * data)
+ int size, union i2c_smbus_data *data)
{
int error = 0;
int timeout;
u32 reg;
for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) {
- if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY))
+ reg = inb_p(SMB_HST_STS);
+ if (!(reg & HST_STS_BUSY))
break;
}
if (!timeout)
- dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg);
- outb_p(0xff,SMB_HST_STS);
+ dev_warn(&a->dev, "SMBus not idle. HST_STS = %02x\n", reg);
+ outb_p(0xff, SMB_HST_STS);
/* Map the size to what the chip understands */
switch (size) {
@@ -268,13 +272,14 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
}
outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
- outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
+ outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) |
+ (size << 3), SMB_HST_CNTL2);
/* Write the command register */
- switch(size) {
+ switch (size) {
case HST_CNTL2_BYTE:
- if (rw== I2C_SMBUS_WRITE)
+ if (rw == I2C_SMBUS_WRITE)
/* Beware it uses DAT0 register and not CMD! */
outb_p(cmd, SMB_HST_DAT0);
break;
@@ -292,11 +297,12 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
break;
case HST_CNTL2_BLOCK:
outb_p(cmd, SMB_HST_CMD);
- error = ali1563_block(a,data,rw);
+ error = ali1563_block(a, data, rw);
goto Done;
}
- if ((error = ali1563_transaction(a, size)))
+ error = ali1563_transaction(a, size);
+ if (error)
goto Done;
if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
@@ -317,7 +323,7 @@ Done:
return error;
}
-static u32 ali1563_func(struct i2c_adapter * a)
+static u32 ali1563_func(struct i2c_adapter *a)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
@@ -329,13 +335,13 @@ static int ali1563_setup(struct pci_dev *dev)
{
u16 ctrl;
- pci_read_config_word(dev,ALI1563_SMBBA,&ctrl);
+ pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
/* SMB I/O Base in high 12 bits and must be aligned with the
* size of the I/O space. */
ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1);
if (!ali1563_smba) {
- dev_warn(&dev->dev,"ali1563_smba Uninitialized\n");
+ dev_warn(&dev->dev, "ali1563_smba Uninitialized\n");
goto Err;
}
@@ -350,8 +356,8 @@ static int ali1563_setup(struct pci_dev *dev)
ctrl | ALI1563_SMB_IOEN);
pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
if (!(ctrl & ALI1563_SMB_IOEN)) {
- dev_err(&dev->dev, "I/O space still not enabled, "
- "giving up\n");
+ dev_err(&dev->dev,
+ "I/O space still not enabled, giving up\n");
goto Err;
}
}
@@ -375,7 +381,7 @@ Err:
static void ali1563_shutdown(struct pci_dev *dev)
{
- release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
+ release_region(ali1563_smba, ALI1563_SMB_IOSIZE);
}
static const struct i2c_algorithm ali1563_algorithm = {
@@ -394,12 +400,14 @@ static int ali1563_probe(struct pci_dev *dev,
{
int error;
- if ((error = ali1563_setup(dev)))
+ error = ali1563_setup(dev);
+ if (error)
goto exit;
ali1563_adapter.dev.parent = &dev->dev;
snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
"SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
- if ((error = i2c_add_adapter(&ali1563_adapter)))
+ error = i2c_add_adapter(&ali1563_adapter);
+ if (error)
goto exit_shutdown;
return 0;
@@ -416,17 +424,17 @@ static void ali1563_remove(struct pci_dev *dev)
ali1563_shutdown(dev);
}
-static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = {
+static const struct pci_device_id ali1563_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
{},
};
-MODULE_DEVICE_TABLE (pci, ali1563_id_table);
+MODULE_DEVICE_TABLE(pci, ali1563_id_table);
static struct pci_driver ali1563_pci_driver = {
- .name = "ali1563_smbus",
+ .name = "ali1563_smbus",
.id_table = ali1563_id_table,
- .probe = ali1563_probe,
+ .probe = ali1563_probe,
.remove = ali1563_remove,
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 4823206a487..2fa21ce9682 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -476,7 +476,7 @@ static struct i2c_adapter ali15x3_adapter = {
.algo = &smbus_algorithm,
};
-static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
+static const struct pci_device_id ali15x3_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 819d3c1062a..a16f7289135 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -307,7 +307,7 @@ static const char* chipname[] = {
"nVidia nForce", "AMD8111",
};
-static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
+static const struct pci_device_id amd756_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
.driver_data = AMD756 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index f3d4d79855b..95a80a8f81b 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -414,7 +414,7 @@ static const struct i2c_algorithm smbus_algorithm = {
};
-static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
+static const struct pci_device_id amd8111_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 843d01268ae..e95f9ba9679 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -32,7 +32,7 @@
#include <linux/slab.h>
#include <linux/platform_data/dma-atmel.h>
-#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
+#define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
@@ -711,6 +711,7 @@ static int at91_twi_probe(struct platform_device *pdev)
struct resource *mem;
int rc;
u32 phy_addr;
+ u32 bus_clk_rate;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -756,13 +757,18 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->use_dma = true;
}
- at91_calc_twi_clock(dev, TWI_CLK_HZ);
+ rc = of_property_read_u32(dev->dev->of_node, "clock-frequency",
+ &bus_clk_rate);
+ if (rc)
+ bus_clk_rate = DEFAULT_TWI_CLK_HZ;
+
+ at91_calc_twi_clock(dev, bus_clk_rate);
at91_init_twi_bus(dev);
snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.owner = THIS_MODULE;
- dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
dev->adapter.algo = &at91_twi_algorithm;
dev->adapter.dev.parent = dev->dev;
dev->adapter.nr = pdev->id;
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 77df97b932a..214ff9700ef 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -219,40 +219,22 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
- struct resource *mem, *requested, *irq;
+ struct resource *mem, *irq;
u32 bus_clk_rate, divider;
int ret;
struct i2c_adapter *adap;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
- if (!i2c_dev) {
- dev_err(&pdev->dev, "Cannot allocate i2c_dev\n");
+ if (!i2c_dev)
return -ENOMEM;
- }
platform_set_drvdata(pdev, i2c_dev);
i2c_dev->dev = &pdev->dev;
init_completion(&i2c_dev->completion);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No mem resource\n");
- return -ENODEV;
- }
-
- requested = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem),
- dev_name(&pdev->dev));
- if (!requested) {
- dev_err(&pdev->dev, "Could not claim register region\n");
- return -EBUSY;
- }
-
- i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start,
- resource_size(mem));
- if (!i2c_dev->regs) {
- dev_err(&pdev->dev, "Could not map registers\n");
- return -ENOMEM;
- }
+ i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2c_dev->regs))
+ return PTR_ERR(i2c_dev->regs);
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_dev->clk)) {
@@ -295,7 +277,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
adap = &i2c_dev->adapter;
i2c_set_adapdata(adap, i2c_dev);
adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
adap->algo = &bcm2835_i2c_algo;
adap->dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 3b9bd9a3f2b..3e271e7558d 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -21,10 +21,10 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/i2c/bfin_twi.h>
-#include <asm/blackfin.h>
-#include <asm/portmux.h>
#include <asm/irq.h>
+#include <asm/portmux.h>
#include <asm/bfin_twi.h>
/* SMBus mode*/
@@ -65,7 +65,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
/* Transmit next data */
while (iface->writeNum > 0 &&
(read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) {
- SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
}
@@ -248,7 +247,6 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
/* Clear interrupt status */
write_INT_STAT(iface, twi_int_status);
bfin_twi_handle_interrupt(iface, twi_int_status);
- SSYNC();
}
spin_unlock_irqrestore(&iface->lock, flags);
return IRQ_HANDLED;
@@ -294,9 +292,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
* discarded before start a new operation.
*/
write_FIFO_CTL(iface, 0x3);
- SSYNC();
write_FIFO_CTL(iface, 0);
- SSYNC();
if (pmsg->flags & I2C_M_RD)
iface->read_write = I2C_SMBUS_READ;
@@ -306,7 +302,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
if (iface->writeNum > 0) {
write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
- SSYNC();
}
}
@@ -315,7 +310,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
/* Interrupt mask . Enable XMT, RCV interrupt */
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
- SSYNC();
if (pmsg->len <= 255)
write_MASTER_CTL(iface, pmsg->len << 6);
@@ -329,7 +323,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
(iface->msg_num > 1 ? RSTART : 0) |
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
- SSYNC();
while (!iface->result) {
if (!wait_for_completion_timeout(&iface->complete,
@@ -453,7 +446,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
* start a new operation.
*/
write_FIFO_CTL(iface, 0x3);
- SSYNC();
write_FIFO_CTL(iface, 0);
/* clear int stat */
@@ -461,7 +453,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
/* Set Transmit device address */
write_MASTER_ADDR(iface, addr);
- SSYNC();
switch (iface->cur_mode) {
case TWI_I2C_MODE_STANDARDSUB:
@@ -469,7 +460,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV));
- SSYNC();
if (iface->writeNum + 1 <= 255)
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@@ -484,7 +474,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
case TWI_I2C_MODE_COMBINED:
write_XMT_DATA8(iface, iface->command);
write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
- SSYNC();
if (iface->writeNum > 0)
write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@@ -531,7 +520,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
write_INT_MASK(iface, MCOMP | MERR |
((iface->read_write == I2C_SMBUS_READ) ?
RCVSERV : XMTSERV));
- SSYNC();
/* Master enable */
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
@@ -539,7 +527,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
break;
}
- SSYNC();
while (!iface->result) {
if (!wait_for_completion_timeout(&iface->complete,
@@ -633,35 +620,27 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
int rc;
unsigned int clkhilow;
- iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+ iface = devm_kzalloc(&pdev->dev, sizeof(struct bfin_twi_iface),
+ GFP_KERNEL);
if (!iface) {
dev_err(&pdev->dev, "Cannot allocate memory\n");
- rc = -ENOMEM;
- goto out_error_nomem;
+ return -ENOMEM;
}
spin_lock_init(&(iface->lock));
/* Find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
- rc = -ENOENT;
- goto out_error_get_res;
- }
-
- iface->regs_base = ioremap(res->start, resource_size(res));
- if (iface->regs_base == NULL) {
+ iface->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(iface->regs_base)) {
dev_err(&pdev->dev, "Cannot map IO\n");
- rc = -ENXIO;
- goto out_error_ioremap;
+ return PTR_ERR(iface->regs_base);
}
iface->irq = platform_get_irq(pdev, 0);
if (iface->irq < 0) {
dev_err(&pdev->dev, "No IRQ specified\n");
- rc = -ENOENT;
- goto out_error_no_irq;
+ return -ENOENT;
}
p_adap = &iface->adap;
@@ -669,7 +648,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
p_adap->algo = &bfin_twi_algorithm;
p_adap->algo_data = iface;
- p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
p_adap->dev.parent = &pdev->dev;
p_adap->timeout = 5 * HZ;
p_adap->retries = 3;
@@ -679,15 +658,15 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
"i2c-bfin-twi");
if (rc) {
dev_err(&pdev->dev, "Can't setup pin mux!\n");
- goto out_error_pin_mux;
+ return -EBUSY;
}
- rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ rc = devm_request_irq(&pdev->dev, iface->irq, bfin_twi_interrupt_entry,
0, pdev->name, iface);
if (rc) {
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
rc = -ENODEV;
- goto out_error_req_irq;
+ goto out_error;
}
/* Set TWI internal clock as 10MHz */
@@ -704,12 +683,11 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
/* Enable TWI */
write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
- SSYNC();
rc = i2c_add_numbered_adapter(p_adap);
if (rc < 0) {
dev_err(&pdev->dev, "Can't add i2c adapter!\n");
- goto out_error_add_adapter;
+ goto out_error;
}
platform_set_drvdata(pdev, iface);
@@ -719,17 +697,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
return 0;
-out_error_add_adapter:
- free_irq(iface->irq, iface);
-out_error_req_irq:
-out_error_no_irq:
+out_error:
peripheral_free_list(dev_get_platdata(&pdev->dev));
-out_error_pin_mux:
- iounmap(iface->regs_base);
-out_error_ioremap:
-out_error_get_res:
- kfree(iface);
-out_error_nomem:
return rc;
}
@@ -738,10 +707,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
i2c_del_adapter(&(iface->adap));
- free_irq(iface->irq, iface);
peripheral_free_list(dev_get_platdata(&pdev->dev));
- iounmap(iface->regs_base);
- kfree(iface);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
new file mode 100644
index 00000000000..63f3f03ecc9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -0,0 +1,905 @@
+/*
+ * I2C bus driver for the Cadence I2C controller.
+ *
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any
+ * later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/* Register offsets for the I2C device. */
+#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
+#define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */
+#define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
+#define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */
+#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
+#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
+#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
+#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
+#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
+
+/* Control Register Bit mask definitions */
+#define CDNS_I2C_CR_HOLD BIT(4) /* Hold Bus bit */
+#define CDNS_I2C_CR_ACK_EN BIT(3)
+#define CDNS_I2C_CR_NEA BIT(2)
+#define CDNS_I2C_CR_MS BIT(1)
+/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
+#define CDNS_I2C_CR_RW BIT(0)
+/* 1 = Auto init FIFO to zeroes */
+#define CDNS_I2C_CR_CLR_FIFO BIT(6)
+#define CDNS_I2C_CR_DIVA_SHIFT 14
+#define CDNS_I2C_CR_DIVA_MASK (3 << CDNS_I2C_CR_DIVA_SHIFT)
+#define CDNS_I2C_CR_DIVB_SHIFT 8
+#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
+
+/* Status Register Bit mask definitions */
+#define CDNS_I2C_SR_BA BIT(8)
+#define CDNS_I2C_SR_RXDV BIT(5)
+
+/*
+ * I2C Address Register Bit mask definitions
+ * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
+ * bits. A write access to this register always initiates a transfer if the I2C
+ * is in master mode.
+ */
+#define CDNS_I2C_ADDR_MASK 0x000003FF /* I2C Address Mask */
+
+/*
+ * I2C Interrupt Registers Bit mask definitions
+ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
+ * bit definitions.
+ */
+#define CDNS_I2C_IXR_ARB_LOST BIT(9)
+#define CDNS_I2C_IXR_RX_UNF BIT(7)
+#define CDNS_I2C_IXR_TX_OVF BIT(6)
+#define CDNS_I2C_IXR_RX_OVF BIT(5)
+#define CDNS_I2C_IXR_SLV_RDY BIT(4)
+#define CDNS_I2C_IXR_TO BIT(3)
+#define CDNS_I2C_IXR_NACK BIT(2)
+#define CDNS_I2C_IXR_DATA BIT(1)
+#define CDNS_I2C_IXR_COMP BIT(0)
+
+#define CDNS_I2C_IXR_ALL_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_SLV_RDY | \
+ CDNS_I2C_IXR_TO | \
+ CDNS_I2C_IXR_NACK | \
+ CDNS_I2C_IXR_DATA | \
+ CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_IXR_ERR_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_NACK)
+
+#define CDNS_I2C_ENABLED_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_NACK | \
+ CDNS_I2C_IXR_DATA | \
+ CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
+
+#define CDNS_I2C_FIFO_DEPTH 16
+/* FIFO depth at which the DATA interrupt occurs */
+#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
+#define CDNS_I2C_MAX_TRANSFER_SIZE 255
+/* Transfer size in multiples of data interrupt depth */
+#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
+
+#define DRIVER_NAME "cdns-i2c"
+
+#define CDNS_I2C_SPEED_MAX 400000
+#define CDNS_I2C_SPEED_DEFAULT 100000
+
+#define CDNS_I2C_DIVA_MAX 4
+#define CDNS_I2C_DIVB_MAX 64
+
+#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
+#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
+
+/**
+ * struct cdns_i2c - I2C device private data structure
+ * @membase: Base address of the I2C device
+ * @adap: I2C adapter instance
+ * @p_msg: Message pointer
+ * @err_status: Error status in Interrupt Status Register
+ * @xfer_done: Transfer complete status
+ * @p_send_buf: Pointer to transmit buffer
+ * @p_recv_buf: Pointer to receive buffer
+ * @suspended: Flag holding the device's PM status
+ * @send_count: Number of bytes still expected to send
+ * @recv_count: Number of bytes still expected to receive
+ * @irq: IRQ number
+ * @input_clk: Input clock to I2C controller
+ * @i2c_clk: Maximum I2C clock speed
+ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
+ * @clk: Pointer to struct clk
+ * @clk_rate_change_nb: Notifier block for clock rate changes
+ */
+struct cdns_i2c {
+ void __iomem *membase;
+ struct i2c_adapter adap;
+ struct i2c_msg *p_msg;
+ int err_status;
+ struct completion xfer_done;
+ unsigned char *p_send_buf;
+ unsigned char *p_recv_buf;
+ u8 suspended;
+ unsigned int send_count;
+ unsigned int recv_count;
+ int irq;
+ unsigned long input_clk;
+ unsigned int i2c_clk;
+ unsigned int bus_hold_flag;
+ struct clk *clk;
+ struct notifier_block clk_rate_change_nb;
+};
+
+#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
+ clk_rate_change_nb)
+
+/**
+ * cdns_i2c_clear_bus_hold() - Clear bus hold bit
+ * @id: Pointer to driver data struct
+ *
+ * Helper to clear the controller's bus hold bit.
+ */
+static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
+{
+ u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ if (reg & CDNS_I2C_CR_HOLD)
+ cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
+}
+
+/**
+ * cdns_i2c_isr - Interrupt handler for the I2C device
+ * @irq: irq number for the I2C device
+ * @ptr: void pointer to cdns_i2c structure
+ *
+ * This function handles the data interrupt, transfer complete interrupt and
+ * the error interrupts of the I2C device.
+ *
+ * Return: IRQ_HANDLED always
+ */
+static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
+{
+ unsigned int isr_status, avail_bytes;
+ unsigned int bytes_to_recv, bytes_to_send;
+ struct cdns_i2c *id = ptr;
+ /* Signal completion only after everything is updated */
+ int done_flag = 0;
+ irqreturn_t status = IRQ_NONE;
+
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+
+ /* Handling nack and arbitration lost interrupt */
+ if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
+ done_flag = 1;
+ status = IRQ_HANDLED;
+ }
+
+ /* Handling Data interrupt */
+ if ((isr_status & CDNS_I2C_IXR_DATA) &&
+ (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
+ /* Always read data interrupt threshold bytes */
+ bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
+ id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
+ avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+
+ /*
+ * if the tranfer size register value is zero, then
+ * check for the remaining bytes and update the
+ * transfer size register.
+ */
+ if (!avail_bytes) {
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ else
+ cdns_i2c_writereg(id->recv_count,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ }
+
+ /* Process the data received */
+ while (bytes_to_recv--)
+ *(id->p_recv_buf)++ =
+ cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+
+ if (!id->bus_hold_flag &&
+ (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
+ cdns_i2c_clear_bus_hold(id);
+
+ status = IRQ_HANDLED;
+ }
+
+ /* Handling Transfer Complete interrupt */
+ if (isr_status & CDNS_I2C_IXR_COMP) {
+ if (!id->p_recv_buf) {
+ /*
+ * If the device is sending data If there is further
+ * data to be sent. Calculate the available space
+ * in FIFO and fill the FIFO with that many bytes.
+ */
+ if (id->send_count) {
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg(
+ (*(id->p_send_buf)++),
+ CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+ } else {
+ /*
+ * Signal the completion of transaction and
+ * clear the hold bus bit if there are no
+ * further messages to be processed.
+ */
+ done_flag = 1;
+ }
+ if (!id->send_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+ } else {
+ if (!id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+ /*
+ * If the device is receiving data, then signal
+ * the completion of transaction and read the data
+ * present in the FIFO. Signal the completion of
+ * transaction.
+ */
+ while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+ CDNS_I2C_SR_RXDV) {
+ *(id->p_recv_buf)++ =
+ cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+ id->recv_count--;
+ }
+ done_flag = 1;
+ }
+
+ status = IRQ_HANDLED;
+ }
+
+ /* Update the status for errors */
+ id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
+ if (id->err_status)
+ status = IRQ_HANDLED;
+
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ if (done_flag)
+ complete(&id->xfer_done);
+
+ return status;
+}
+
+/**
+ * cdns_i2c_mrecv - Prepare and start a master receive operation
+ * @id: pointer to the i2c device structure
+ */
+static void cdns_i2c_mrecv(struct cdns_i2c *id)
+{
+ unsigned int ctrl_reg;
+ unsigned int isr_status;
+
+ id->p_recv_buf = id->p_msg->buf;
+ id->recv_count = id->p_msg->len;
+
+ /* Put the controller in master receive mode and clear the FIFO */
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
+
+ if (id->p_msg->flags & I2C_M_RECV_LEN)
+ id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+
+ /*
+ * Check for the message size against FIFO depth and set the
+ * 'hold bus' bit if it is greater than FIFO depth.
+ */
+ if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
+ ctrl_reg |= CDNS_I2C_CR_HOLD;
+
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ /* Clear the interrupts in interrupt status register */
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ /*
+ * The no. of bytes to receive is checked against the limit of
+ * max transfer size. Set transfer size register with no of bytes
+ * receive if it is less than transfer size and transfer size if
+ * it is more. Enable the interrupts.
+ */
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ else
+ cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+ /* Clear the bus hold flag if bytes to receive is less than FIFO size */
+ if (!id->bus_hold_flag &&
+ ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
+ (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
+ cdns_i2c_clear_bus_hold(id);
+ /* Set the slave address in address register - triggers operation */
+ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+ CDNS_I2C_ADDR_OFFSET);
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_msend - Prepare and start a master send operation
+ * @id: pointer to the i2c device
+ */
+static void cdns_i2c_msend(struct cdns_i2c *id)
+{
+ unsigned int avail_bytes;
+ unsigned int bytes_to_send;
+ unsigned int ctrl_reg;
+ unsigned int isr_status;
+
+ id->p_recv_buf = NULL;
+ id->p_send_buf = id->p_msg->buf;
+ id->send_count = id->p_msg->len;
+
+ /* Set the controller in Master transmit mode and clear the FIFO. */
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg &= ~CDNS_I2C_CR_RW;
+ ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
+
+ /*
+ * Check for the message size against FIFO depth and set the
+ * 'hold bus' bit if it is greater than FIFO depth.
+ */
+ if (id->send_count > CDNS_I2C_FIFO_DEPTH)
+ ctrl_reg |= CDNS_I2C_CR_HOLD;
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ /* Clear the interrupts in interrupt status register. */
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ /*
+ * Calculate the space available in FIFO. Check the message length
+ * against the space available, and fill the FIFO accordingly.
+ * Enable the interrupts.
+ */
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+
+ /*
+ * Clear the bus hold flag if there is no more data
+ * and if it is the last message.
+ */
+ if (!id->bus_hold_flag && !id->send_count)
+ cdns_i2c_clear_bus_hold(id);
+ /* Set the slave address in address register - triggers operation. */
+ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+ CDNS_I2C_ADDR_OFFSET);
+
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_master_reset - Reset the interface
+ * @adap: pointer to the i2c adapter driver instance
+ *
+ * This function cleanup the fifos, clear the hold bit and status
+ * and disable the interrupts.
+ */
+static void cdns_i2c_master_reset(struct i2c_adapter *adap)
+{
+ struct cdns_i2c *id = adap->algo_data;
+ u32 regval;
+
+ /* Disable the interrupts */
+ cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
+ /* Clear the hold bit and fifos */
+ regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ regval &= ~CDNS_I2C_CR_HOLD;
+ regval |= CDNS_I2C_CR_CLR_FIFO;
+ cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
+ /* Update the transfercount register to zero */
+ cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
+ /* Clear the interupt status register */
+ regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
+ /* Clear the status register */
+ regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
+ cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
+}
+
+static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
+ struct i2c_adapter *adap)
+{
+ int ret;
+ u32 reg;
+
+ id->p_msg = msg;
+ id->err_status = 0;
+ reinit_completion(&id->xfer_done);
+
+ /* Check for the TEN Bit mode on each msg */
+ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ if (msg->flags & I2C_M_TEN) {
+ if (reg & CDNS_I2C_CR_NEA)
+ cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
+ CDNS_I2C_CR_OFFSET);
+ } else {
+ if (!(reg & CDNS_I2C_CR_NEA))
+ cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
+ CDNS_I2C_CR_OFFSET);
+ }
+
+ /* Check for the R/W flag on each msg */
+ if (msg->flags & I2C_M_RD)
+ cdns_i2c_mrecv(id);
+ else
+ cdns_i2c_msend(id);
+
+ /* Wait for the signal of completion */
+ ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
+ if (!ret) {
+ cdns_i2c_master_reset(adap);
+ dev_err(id->adap.dev.parent,
+ "timeout waiting on completion\n");
+ return -ETIMEDOUT;
+ }
+
+ cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,
+ CDNS_I2C_IDR_OFFSET);
+
+ /* If it is bus arbitration error, try again */
+ if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
+ return -EAGAIN;
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_master_xfer - The main i2c transfer function
+ * @adap: pointer to the i2c adapter driver instance
+ * @msgs: pointer to the i2c message structure
+ * @num: the number of messages to transfer
+ *
+ * Initiates the send/recv activity based on the transfer message received.
+ *
+ * Return: number of msgs processed on success, negative error otherwise
+ */
+static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret, count;
+ u32 reg;
+ struct cdns_i2c *id = adap->algo_data;
+
+ /* Check if the bus is free */
+ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
+ return -EAGAIN;
+
+ /*
+ * Set the flag to one when multiple messages are to be
+ * processed with a repeated start.
+ */
+ if (num > 1) {
+ id->bus_hold_flag = 1;
+ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ reg |= CDNS_I2C_CR_HOLD;
+ cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
+ } else {
+ id->bus_hold_flag = 0;
+ }
+
+ /* Process the msg one by one */
+ for (count = 0; count < num; count++, msgs++) {
+ if (count == (num - 1))
+ id->bus_hold_flag = 0;
+
+ ret = cdns_i2c_process_msg(id, msgs, adap);
+ if (ret)
+ return ret;
+
+ /* Report the other error interrupts to application */
+ if (id->err_status) {
+ cdns_i2c_master_reset(adap);
+
+ if (id->err_status & CDNS_I2C_IXR_NACK)
+ return -ENXIO;
+
+ return -EIO;
+ }
+ }
+
+ return num;
+}
+
+/**
+ * cdns_i2c_func - Returns the supported features of the I2C driver
+ * @adap: pointer to the i2c adapter structure
+ *
+ * Return: 32 bit value, each bit corresponding to a feature
+ */
+static u32 cdns_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+ (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm cdns_i2c_algo = {
+ .master_xfer = cdns_i2c_master_xfer,
+ .functionality = cdns_i2c_func,
+};
+
+/**
+ * cdns_i2c_calc_divs - Calculate clock dividers
+ * @f: I2C clock frequency
+ * @input_clk: Input clock frequency
+ * @a: First divider (return value)
+ * @b: Second divider (return value)
+ *
+ * f is used as input and output variable. As input it is used as target I2C
+ * frequency. On function exit f holds the actually resulting I2C frequency.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
+ unsigned int *a, unsigned int *b)
+{
+ unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
+ unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+ unsigned int last_error, current_error;
+
+ /* calculate (divisor_a+1) x (divisor_b+1) */
+ temp = input_clk / (22 * fscl);
+
+ /*
+ * If the calculated value is negative or 0, the fscl input is out of
+ * range. Return error.
+ */
+ if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
+ return -EINVAL;
+
+ last_error = -1;
+ for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
+ div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+ if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
+ continue;
+ div_b--;
+
+ actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+ if (actual_fscl > fscl)
+ continue;
+
+ current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+ (fscl - actual_fscl));
+
+ if (last_error > current_error) {
+ calc_div_a = div_a;
+ calc_div_b = div_b;
+ best_fscl = actual_fscl;
+ last_error = current_error;
+ }
+ }
+
+ *a = calc_div_a;
+ *b = calc_div_b;
+ *f = best_fscl;
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device
+ * @clk_in: I2C clock input frequency in Hz
+ * @id: Pointer to the I2C device structure
+ *
+ * The device must be idle rather than busy transferring data before setting
+ * these device options.
+ * The data rate is set by values in the control register.
+ * The formula for determining the correct register values is
+ * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
+ * See the hardware data sheet for a full explanation of setting the serial
+ * clock rate. The clock can not be faster than the input clock divide by 22.
+ * The two most common clock rates are 100KHz and 400KHz.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
+{
+ unsigned int div_a, div_b;
+ unsigned int ctrl_reg;
+ int ret = 0;
+ unsigned long fscl = id->i2c_clk;
+
+ ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
+ if (ret)
+ return ret;
+
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
+ ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
+ (div_b << CDNS_I2C_CR_DIVB_SHIFT));
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_clk_notifier_cb - Clock rate change callback
+ * @nb: Pointer to notifier block
+ * @event: Notification reason
+ * @data: Pointer to notification data object
+ *
+ * This function is called when the cdns_i2c input clock frequency changes.
+ * The callback checks whether a valid bus frequency can be generated after the
+ * change. If so, the change is acknowledged, otherwise the change is aborted.
+ * New dividers are written to the HW in the pre- or post change notification
+ * depending on the scaling direction.
+ *
+ * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
+ * to acknowedge the change, NOTIFY_DONE if the notification is
+ * considered irrelevant.
+ */
+static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
+ event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct cdns_i2c *id = to_cdns_i2c(nb);
+
+ if (id->suspended)
+ return NOTIFY_OK;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ {
+ unsigned long input_clk = ndata->new_rate;
+ unsigned long fscl = id->i2c_clk;
+ unsigned int div_a, div_b;
+ int ret;
+
+ ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b);
+ if (ret) {
+ dev_warn(id->adap.dev.parent,
+ "clock rate change rejected\n");
+ return NOTIFY_STOP;
+ }
+
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ cdns_i2c_setclk(ndata->new_rate, id);
+
+ return NOTIFY_OK;
+ }
+ case POST_RATE_CHANGE:
+ id->input_clk = ndata->new_rate;
+ /* scale down */
+ if (ndata->new_rate < ndata->old_rate)
+ cdns_i2c_setclk(ndata->new_rate, id);
+ return NOTIFY_OK;
+ case ABORT_RATE_CHANGE:
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ cdns_i2c_setclk(ndata->old_rate, id);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+/**
+ * cdns_i2c_suspend - Suspend method for the driver
+ * @_dev: Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ *
+ * Return: 0 always
+ */
+static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
+{
+ struct platform_device *pdev = container_of(_dev,
+ struct platform_device, dev);
+ struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
+
+ clk_disable(xi2c->clk);
+ xi2c->suspended = 1;
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_resume - Resume from suspend
+ * @_dev: Address of the platform_device structure
+ *
+ * Resume operation after suspend.
+ *
+ * Return: 0 on success and error value on error
+ */
+static int __maybe_unused cdns_i2c_resume(struct device *_dev)
+{
+ struct platform_device *pdev = container_of(_dev,
+ struct platform_device, dev);
+ struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_enable(xi2c->clk);
+ if (ret) {
+ dev_err(_dev, "Cannot enable clock.\n");
+ return ret;
+ }
+
+ xi2c->suspended = 0;
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
+ cdns_i2c_resume);
+
+/**
+ * cdns_i2c_probe - Platform registration call
+ * @pdev: Handle to the platform device structure
+ *
+ * This function does all the memory allocation and registration for the i2c
+ * device. User can modify the address mode to 10 bit address mode using the
+ * ioctl call with option I2C_TENBIT.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *r_mem;
+ struct cdns_i2c *id;
+ int ret;
+
+ id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
+ if (!id)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, id);
+
+ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
+ if (IS_ERR(id->membase))
+ return PTR_ERR(id->membase);
+
+ id->irq = platform_get_irq(pdev, 0);
+
+ id->adap.dev.of_node = pdev->dev.of_node;
+ id->adap.algo = &cdns_i2c_algo;
+ id->adap.timeout = CDNS_I2C_TIMEOUT;
+ id->adap.retries = 3; /* Default retry value. */
+ id->adap.algo_data = id;
+ id->adap.dev.parent = &pdev->dev;
+ init_completion(&id->xfer_done);
+ snprintf(id->adap.name, sizeof(id->adap.name),
+ "Cadence I2C at %08lx", (unsigned long)r_mem->start);
+
+ id->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(id->clk)) {
+ dev_err(&pdev->dev, "input clock not found.\n");
+ return PTR_ERR(id->clk);
+ }
+ ret = clk_prepare_enable(id->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return ret;
+ }
+ id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
+ if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
+ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
+ id->input_clk = clk_get_rate(id->clk);
+
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &id->i2c_clk);
+ if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
+ id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;
+
+ cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
+ CDNS_I2C_CR_OFFSET);
+
+ ret = cdns_i2c_setclk(id->input_clk, id);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
+ ret = -EINVAL;
+ goto err_clk_dis;
+ }
+
+ ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
+ DRIVER_NAME, id);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ goto err_clk_dis;
+ }
+
+ ret = i2c_add_adapter(&id->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+ goto err_clk_dis;
+ }
+
+ dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
+ id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
+
+ return 0;
+
+err_clk_dis:
+ clk_disable_unprepare(id->clk);
+ return ret;
+}
+
+/**
+ * cdns_i2c_remove - Unregister the device after releasing the resources
+ * @pdev: Handle to the platform device structure
+ *
+ * This function frees all the resources allocated to the device.
+ *
+ * Return: 0 always
+ */
+static int cdns_i2c_remove(struct platform_device *pdev)
+{
+ struct cdns_i2c *id = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&id->adap);
+ clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
+ clk_disable_unprepare(id->clk);
+
+ return 0;
+}
+
+static const struct of_device_id cdns_i2c_of_match[] = {
+ { .compatible = "cdns,i2c-r1p10", },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
+
+static struct platform_driver cdns_i2c_drv = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = cdns_i2c_of_match,
+ .pm = &cdns_i2c_dev_pm_ops,
+ },
+ .probe = cdns_i2c_probe,
+ .remove = cdns_i2c_remove,
+};
+
+module_platform_driver(cdns_i2c_drv);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Cadence I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index be7f0a20d63..f3b89a4698b 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -39,7 +39,9 @@
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <asm/cpm.h>
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
new file mode 100644
index 00000000000..8e7a71487bb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Expose an I2C passthrough to the ChromeOS EC.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/**
+ * struct ec_i2c_device - Driver data for I2C tunnel
+ *
+ * @dev: Device node
+ * @adap: I2C adapter
+ * @ec: Pointer to EC device
+ * @remote_bus: The EC bus number we tunnel to on the other side.
+ * @request_buf: Buffer for transmitting data; we expect most transfers to fit.
+ * @response_buf: Buffer for receiving data; we expect most transfers to fit.
+ */
+
+struct ec_i2c_device {
+ struct device *dev;
+ struct i2c_adapter adap;
+ struct cros_ec_device *ec;
+
+ u16 remote_bus;
+
+ u8 request_buf[256];
+ u8 response_buf[256];
+};
+
+/**
+ * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message
+ *
+ * @i2c_msgs: The i2c messages to read
+ * @num: The number of i2c messages.
+ *
+ * Returns the number of bytes the messages will take up.
+ */
+static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num)
+{
+ int i;
+ int size;
+
+ size = sizeof(struct ec_params_i2c_passthru);
+ size += num * sizeof(struct ec_params_i2c_passthru_msg);
+ for (i = 0; i < num; i++)
+ if (!(i2c_msgs[i].flags & I2C_M_RD))
+ size += i2c_msgs[i].len;
+
+ return size;
+}
+
+/**
+ * ec_i2c_construct_message - construct a message to go to the EC
+ *
+ * This function effectively stuffs the standard i2c_msg format of Linux into
+ * a format that the EC understands.
+ *
+ * @buf: The buffer to fill. We assume that the buffer is big enough.
+ * @i2c_msgs: The i2c messages to read.
+ * @num: The number of i2c messages.
+ * @bus_num: The remote bus number we want to talk to.
+ *
+ * Returns 0 or a negative error number.
+ */
+static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[],
+ int num, u16 bus_num)
+{
+ struct ec_params_i2c_passthru *params;
+ u8 *out_data;
+ int i;
+
+ out_data = buf + sizeof(struct ec_params_i2c_passthru) +
+ num * sizeof(struct ec_params_i2c_passthru_msg);
+
+ params = (struct ec_params_i2c_passthru *)buf;
+ params->port = bus_num;
+ params->num_msgs = num;
+ for (i = 0; i < num; i++) {
+ const struct i2c_msg *i2c_msg = &i2c_msgs[i];
+ struct ec_params_i2c_passthru_msg *msg = &params->msg[i];
+
+ msg->len = i2c_msg->len;
+ msg->addr_flags = i2c_msg->addr;
+
+ if (i2c_msg->flags & I2C_M_TEN)
+ msg->addr_flags |= EC_I2C_FLAG_10BIT;
+
+ if (i2c_msg->flags & I2C_M_RD) {
+ msg->addr_flags |= EC_I2C_FLAG_READ;
+ } else {
+ memcpy(out_data, i2c_msg->buf, msg->len);
+ out_data += msg->len;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response
+ *
+ * @i2c_msgs: The i2c messages to to fill up.
+ * @num: The number of i2c messages expected.
+ *
+ * Returns the number of response bytes expeced.
+ */
+static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num)
+{
+ int size;
+ int i;
+
+ size = sizeof(struct ec_response_i2c_passthru);
+ for (i = 0; i < num; i++)
+ if (i2c_msgs[i].flags & I2C_M_RD)
+ size += i2c_msgs[i].len;
+
+ return size;
+}
+
+/**
+ * ec_i2c_parse_response - Parse a response from the EC
+ *
+ * We'll take the EC's response and copy it back into msgs.
+ *
+ * @buf: The buffer to parse.
+ * @i2c_msgs: The i2c messages to to fill up.
+ * @num: The number of i2c messages; will be modified to include the actual
+ * number received.
+ *
+ * Returns 0 or a negative error number.
+ */
+static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[],
+ int *num)
+{
+ const struct ec_response_i2c_passthru *resp;
+ const u8 *in_data;
+ int i;
+
+ in_data = buf + sizeof(struct ec_response_i2c_passthru);
+
+ resp = (const struct ec_response_i2c_passthru *)buf;
+ if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT)
+ return -ETIMEDOUT;
+ else if (resp->i2c_status & EC_I2C_STATUS_ERROR)
+ return -EREMOTEIO;
+
+ /* Other side could send us back fewer messages, but not more */
+ if (resp->num_msgs > *num)
+ return -EPROTO;
+ *num = resp->num_msgs;
+
+ for (i = 0; i < *num; i++) {
+ struct i2c_msg *i2c_msg = &i2c_msgs[i];
+
+ if (i2c_msgs[i].flags & I2C_M_RD) {
+ memcpy(i2c_msg->buf, in_data, i2c_msg->len);
+ in_data += i2c_msg->len;
+ }
+ }
+
+ return 0;
+}
+
+static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
+ int num)
+{
+ struct ec_i2c_device *bus = adap->algo_data;
+ struct device *dev = bus->dev;
+ const u16 bus_num = bus->remote_bus;
+ int request_len;
+ int response_len;
+ u8 *request = NULL;
+ u8 *response = NULL;
+ int result;
+
+ request_len = ec_i2c_count_message(i2c_msgs, num);
+ if (request_len < 0) {
+ dev_warn(dev, "Error constructing message %d\n", request_len);
+ result = request_len;
+ goto exit;
+ }
+ response_len = ec_i2c_count_response(i2c_msgs, num);
+ if (response_len < 0) {
+ /* Unexpected; no errors should come when NULL response */
+ dev_warn(dev, "Error preparing response %d\n", response_len);
+ result = response_len;
+ goto exit;
+ }
+
+ if (request_len <= ARRAY_SIZE(bus->request_buf)) {
+ request = bus->request_buf;
+ } else {
+ request = kzalloc(request_len, GFP_KERNEL);
+ if (request == NULL) {
+ result = -ENOMEM;
+ goto exit;
+ }
+ }
+ if (response_len <= ARRAY_SIZE(bus->response_buf)) {
+ response = bus->response_buf;
+ } else {
+ response = kzalloc(response_len, GFP_KERNEL);
+ if (response == NULL) {
+ result = -ENOMEM;
+ goto exit;
+ }
+ }
+
+ ec_i2c_construct_message(request, i2c_msgs, num, bus_num);
+ result = bus->ec->command_sendrecv(bus->ec, EC_CMD_I2C_PASSTHRU,
+ request, request_len,
+ response, response_len);
+ if (result)
+ goto exit;
+
+ result = ec_i2c_parse_response(response, i2c_msgs, &num);
+ if (result < 0)
+ goto exit;
+
+ /* Indicate success by saying how many messages were sent */
+ result = num;
+exit:
+ if (request != bus->request_buf)
+ kfree(request);
+ if (response != bus->response_buf)
+ kfree(response);
+
+ return result;
+}
+
+static u32 ec_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ec_i2c_algorithm = {
+ .master_xfer = ec_i2c_xfer,
+ .functionality = ec_i2c_functionality,
+};
+
+static int ec_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct ec_i2c_device *bus = NULL;
+ u32 remote_bus;
+ int err;
+
+ if (!ec->command_sendrecv) {
+ dev_err(dev, "Missing sendrecv\n");
+ return -EINVAL;
+ }
+
+ bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+ if (bus == NULL)
+ return -ENOMEM;
+
+ err = of_property_read_u32(np, "google,remote-bus", &remote_bus);
+ if (err) {
+ dev_err(dev, "Couldn't read remote-bus property\n");
+ return err;
+ }
+ bus->remote_bus = remote_bus;
+
+ bus->ec = ec;
+ bus->dev = dev;
+
+ bus->adap.owner = THIS_MODULE;
+ strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name));
+ bus->adap.algo = &ec_i2c_algorithm;
+ bus->adap.algo_data = bus;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = np;
+
+ err = i2c_add_adapter(&bus->adap);
+ if (err) {
+ dev_err(dev, "cannot register i2c adapter\n");
+ return err;
+ }
+ platform_set_drvdata(pdev, bus);
+
+ return err;
+}
+
+static int ec_i2c_remove(struct platform_device *dev)
+{
+ struct ec_i2c_device *bus = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&bus->adap);
+
+ return 0;
+}
+
+static struct platform_driver ec_i2c_tunnel_driver = {
+ .probe = ec_i2c_probe,
+ .remove = ec_i2c_remove,
+ .driver = {
+ .name = "cros-ec-i2c-tunnel",
+ },
+};
+
+module_platform_driver(ec_i2c_tunnel_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EC I2C tunnel driver");
+MODULE_ALIAS("platform:cros-ec-i2c-tunnel");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index af0b5830303..389bc68c55a 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -712,7 +712,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
adap->algo = &i2c_davinci_algo;
adap->dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 14c4b30d4cc..3c20e4bd6dd 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -218,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
*
* If your hardware is free from tHD;STA issue, try this one.
*/
- return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+ return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
else
/*
* Conditional expression:
@@ -234,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
* The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt().
*/
- return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+ return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
+ - 3 + offset;
}
static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@@ -250,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
* account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety.
*/
- return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+ return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
}
static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
@@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
u32 input_clock_khz;
u32 hcnt, lcnt;
u32 reg;
+ u32 sda_falling_time, scl_falling_time;
input_clock_khz = dev->get_clk_rate_khz(dev);
@@ -308,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* set standard and fast speed deviders for high/low periods */
+ sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
+ scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
+
/* Standard-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 40, /* tHD;STA = tHIGH = 4.0 us */
- 3, /* tf = 0.3 us */
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 47, /* tLOW = 4.7 us */
- 3, /* tf = 0.3 us */
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
0); /* No offset */
/* Allow platforms to specify the ideal HCNT and LCNT values */
@@ -330,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* Fast-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 6, /* tHD;STA = tHIGH = 0.6 us */
- 3, /* tf = 0.3 us */
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 13, /* tLOW = 1.3 us */
- 3, /* tf = 0.3 us */
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
0); /* No offset */
if (dev->fs_hcnt && dev->fs_lcnt) {
@@ -417,6 +422,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
*/
dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
+ /* enforce disabled interrupts (due to HW issues) */
+ i2c_dw_disable_int(dev);
+
/* Enable the adapter */
__i2c_dw_enable(dev, true);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index e8a756537ed..d66b6cbc9ed 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -99,6 +99,8 @@ struct dw_i2c_dev {
unsigned int rx_fifo_depth;
int rx_outstanding;
u32 sda_hold_time;
+ u32 sda_falling_time;
+ u32 scl_falling_time;
u16 ss_hcnt;
u16 ss_lcnt;
u16 fs_hcnt;
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index f6ed06c966e..3356f7ab9f7 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -54,6 +54,17 @@ enum dw_pci_ctl_id_t {
medfield_3,
medfield_4,
medfield_5,
+
+ baytrail,
+ haswell,
+};
+
+struct dw_scl_sda_cfg {
+ u32 ss_hcnt;
+ u32 fs_hcnt;
+ u32 ss_lcnt;
+ u32 fs_lcnt;
+ u32 sda_hold;
};
struct dw_pci_controller {
@@ -62,12 +73,38 @@ struct dw_pci_controller {
u32 tx_fifo_depth;
u32 rx_fifo_depth;
u32 clk_khz;
+ u32 functionality;
+ struct dw_scl_sda_cfg *scl_sda_cfg;
};
#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
DW_IC_CON_SLAVE_DISABLE | \
DW_IC_CON_RESTART_EN)
+#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
+ I2C_FUNC_SMBUS_BYTE | \
+ I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA | \
+ I2C_FUNC_SMBUS_I2C_BLOCK)
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+ .ss_hcnt = 0x200,
+ .fs_hcnt = 0x55,
+ .ss_lcnt = 0x200,
+ .fs_lcnt = 0x99,
+ .sda_hold = 0x6,
+};
+
+/* Haswell HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg hsw_config = {
+ .ss_hcnt = 0x01b0,
+ .fs_hcnt = 0x48,
+ .ss_lcnt = 0x01fb,
+ .fs_lcnt = 0xa0,
+ .sda_hold = 0x9,
+};
+
static struct dw_pci_controller dw_pci_controllers[] = {
[moorestown_0] = {
.bus_num = 0,
@@ -132,75 +169,49 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
+ [baytrail] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 100000,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &byt_config,
+ },
+ [haswell] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 100000,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &hsw_config,
+ },
};
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
+#ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
- int err;
-
-
- i2c_dw_disable(i2c);
-
- err = pci_save_state(pdev);
- if (err) {
- dev_err(&pdev->dev, "pci_save_state failed\n");
- return err;
- }
-
- err = pci_set_power_state(pdev, PCI_D3hot);
- if (err) {
- dev_err(&pdev->dev, "pci_set_power_state failed\n");
- return err;
- }
+ i2c_dw_disable(pci_get_drvdata(pdev));
return 0;
}
static int i2c_dw_pci_resume(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
- int err;
- u32 enabled;
-
- enabled = i2c_dw_is_enabled(i2c);
- if (enabled)
- return 0;
-
- err = pci_set_power_state(pdev, PCI_D0);
- if (err) {
- dev_err(&pdev->dev, "pci_set_power_state() failed\n");
- return err;
- }
-
- pci_restore_state(pdev);
- i2c_dw_init(i2c);
- return 0;
+ return i2c_dw_init(pci_get_drvdata(pdev));
}
+#endif
-static int i2c_dw_pci_runtime_idle(struct device *dev)
-{
- int err = pm_schedule_suspend(dev, 500);
- dev_dbg(dev, "runtime_idle called\n");
-
- if (err != 0)
- return 0;
- return -EBUSY;
-}
-
-static const struct dev_pm_ops i2c_dw_pm_ops = {
- .resume = i2c_dw_pci_resume,
- .suspend = i2c_dw_pci_suspend,
- SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
- i2c_dw_pci_runtime_idle)
-};
+static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend,
+ i2c_dw_pci_resume, NULL);
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
@@ -214,6 +225,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
struct i2c_adapter *adap;
int r;
struct dw_pci_controller *controller;
+ struct dw_scl_sda_cfg *cfg;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
@@ -247,13 +259,18 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
- dev->functionality =
- I2C_FUNC_I2C |
- I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK;
+ dev->functionality = controller->functionality |
+ DW_DEFAULT_FUNCTIONALITY;
+
dev->master_cfg = controller->bus_cfg;
+ if (controller->scl_sda_cfg) {
+ cfg = controller->scl_sda_cfg;
+ dev->ss_hcnt = cfg->ss_hcnt;
+ dev->fs_hcnt = cfg->fs_hcnt;
+ dev->ss_lcnt = cfg->ss_lcnt;
+ dev->fs_lcnt = cfg->fs_lcnt;
+ dev->sda_hold_time = cfg->sda_hold;
+ }
pci_set_drvdata(pdev, dev);
@@ -270,8 +287,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev;
adap->nr = controller->bus_num;
- snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
- adap->nr);
+
+ snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
adap->name, dev);
@@ -290,6 +307,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
@@ -309,7 +327,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("i2c_designware-pci");
-static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+static const struct pci_device_id i2_designware_pci_ids[] = {
/* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
@@ -321,6 +339,17 @@ static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
+ /* Baytrail */
+ { PCI_VDEVICE(INTEL, 0x0F41), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F42), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F43), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F44), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F45), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F46), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F47), baytrail },
+ /* Haswell */
+ { PCI_VDEVICE(INTEL, 0x9c61), haswell },
+ { PCI_VDEVICE(INTEL, 0x9c62), haswell },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index d0bdac0498c..402ec3970fe 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev)
"i2c-sda-hold-time-ns", &ht);
dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
1000000);
+
+ of_property_read_u32(pdev->dev.of_node,
+ "i2c-sda-falling-time-ns",
+ &dev->sda_falling_time);
+ of_property_read_u32(pdev->dev.of_node,
+ "i2c-scl-falling-time-ns",
+ &dev->scl_falling_time);
}
dev->functionality =
@@ -195,7 +202,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
sizeof(adap->name));
adap->algo = &i2c_dw_algo;
@@ -240,12 +247,13 @@ static const struct of_device_id dw_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
static int dw_i2c_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
+ i2c_dw_disable(i_dev);
clk_disable_unprepare(i_dev->clk);
return 0;
@@ -261,13 +269,11 @@ static int dw_i2c_resume(struct device *dev)
return 0;
}
-
-static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
-#define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops)
-#else
-#define DW_I2C_DEV_PM_OPS NULL
#endif
+static UNIVERSAL_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend,
+ dw_i2c_resume, NULL);
+
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
@@ -279,7 +285,7 @@ static struct platform_driver dw_i2c_driver = {
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
- .pm = DW_I2C_DEV_PM_OPS,
+ .pm = &dw_i2c_dev_pm_ops,
},
};
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
index 721f7ebf9a3..b19a310bf9b 100644
--- a/drivers/i2c/busses/i2c-diolan-u2c.c
+++ b/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -455,7 +455,6 @@ static int diolan_u2c_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- dev_err(&interface->dev, "no memory for device state\n");
ret = -ENOMEM;
goto error;
}
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
new file mode 100644
index 00000000000..f7eccd682de
--- /dev/null
+++ b/drivers/i2c/busses/i2c-efm32.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "efm32-i2c"
+
+#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
+
+#define REG_CTRL 0x00
+#define REG_CTRL_EN 0x00001
+#define REG_CTRL_SLAVE 0x00002
+#define REG_CTRL_AUTOACK 0x00004
+#define REG_CTRL_AUTOSE 0x00008
+#define REG_CTRL_AUTOSN 0x00010
+#define REG_CTRL_ARBDIS 0x00020
+#define REG_CTRL_GCAMEN 0x00040
+#define REG_CTRL_CLHR__MASK 0x00300
+#define REG_CTRL_BITO__MASK 0x03000
+#define REG_CTRL_BITO_OFF 0x00000
+#define REG_CTRL_BITO_40PCC 0x01000
+#define REG_CTRL_BITO_80PCC 0x02000
+#define REG_CTRL_BITO_160PCC 0x03000
+#define REG_CTRL_GIBITO 0x08000
+#define REG_CTRL_CLTO__MASK 0x70000
+#define REG_CTRL_CLTO_OFF 0x00000
+
+#define REG_CMD 0x04
+#define REG_CMD_START 0x00001
+#define REG_CMD_STOP 0x00002
+#define REG_CMD_ACK 0x00004
+#define REG_CMD_NACK 0x00008
+#define REG_CMD_CONT 0x00010
+#define REG_CMD_ABORT 0x00020
+#define REG_CMD_CLEARTX 0x00040
+#define REG_CMD_CLEARPC 0x00080
+
+#define REG_STATE 0x08
+#define REG_STATE_BUSY 0x00001
+#define REG_STATE_MASTER 0x00002
+#define REG_STATE_TRANSMITTER 0x00004
+#define REG_STATE_NACKED 0x00008
+#define REG_STATE_BUSHOLD 0x00010
+#define REG_STATE_STATE__MASK 0x000e0
+#define REG_STATE_STATE_IDLE 0x00000
+#define REG_STATE_STATE_WAIT 0x00020
+#define REG_STATE_STATE_START 0x00040
+#define REG_STATE_STATE_ADDR 0x00060
+#define REG_STATE_STATE_ADDRACK 0x00080
+#define REG_STATE_STATE_DATA 0x000a0
+#define REG_STATE_STATE_DATAACK 0x000c0
+
+#define REG_STATUS 0x0c
+#define REG_STATUS_PSTART 0x00001
+#define REG_STATUS_PSTOP 0x00002
+#define REG_STATUS_PACK 0x00004
+#define REG_STATUS_PNACK 0x00008
+#define REG_STATUS_PCONT 0x00010
+#define REG_STATUS_PABORT 0x00020
+#define REG_STATUS_TXC 0x00040
+#define REG_STATUS_TXBL 0x00080
+#define REG_STATUS_RXDATAV 0x00100
+
+#define REG_CLKDIV 0x10
+#define REG_CLKDIV_DIV__MASK 0x001ff
+#define REG_CLKDIV_DIV(div) MASK_VAL(REG_CLKDIV_DIV__MASK, (div))
+
+#define REG_SADDR 0x14
+#define REG_SADDRMASK 0x18
+#define REG_RXDATA 0x1c
+#define REG_RXDATAP 0x20
+#define REG_TXDATA 0x24
+#define REG_IF 0x28
+#define REG_IF_START 0x00001
+#define REG_IF_RSTART 0x00002
+#define REG_IF_ADDR 0x00004
+#define REG_IF_TXC 0x00008
+#define REG_IF_TXBL 0x00010
+#define REG_IF_RXDATAV 0x00020
+#define REG_IF_ACK 0x00040
+#define REG_IF_NACK 0x00080
+#define REG_IF_MSTOP 0x00100
+#define REG_IF_ARBLOST 0x00200
+#define REG_IF_BUSERR 0x00400
+#define REG_IF_BUSHOLD 0x00800
+#define REG_IF_TXOF 0x01000
+#define REG_IF_RXUF 0x02000
+#define REG_IF_BITO 0x04000
+#define REG_IF_CLTO 0x08000
+#define REG_IF_SSTOP 0x10000
+
+#define REG_IFS 0x2c
+#define REG_IFC 0x30
+#define REG_IFC__MASK 0x1ffcf
+
+#define REG_IEN 0x34
+
+#define REG_ROUTE 0x38
+#define REG_ROUTE_SDAPEN 0x00001
+#define REG_ROUTE_SCLPEN 0x00002
+#define REG_ROUTE_LOCATION__MASK 0x00700
+#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
+
+struct efm32_i2c_ddata {
+ struct i2c_adapter adapter;
+
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int irq;
+ u8 location;
+ unsigned long frequency;
+
+ /* transfer data */
+ struct completion done;
+ struct i2c_msg *msgs;
+ size_t num_msgs;
+ size_t current_word, current_msg;
+ int retval;
+};
+
+static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset)
+{
+ return readl(ddata->base + offset);
+}
+
+static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata,
+ unsigned offset, u32 value)
+{
+ writel(value, ddata->base + offset);
+}
+
+static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
+ efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 |
+ (cur_msg->flags & I2C_M_RD ? 1 : 0));
+}
+
+static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ if (ddata->current_word >= cur_msg->len) {
+ /* cur_msg completely transferred */
+ ddata->current_word = 0;
+ ddata->current_msg += 1;
+
+ if (ddata->current_msg >= ddata->num_msgs) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_msg(ddata);
+ }
+ } else {
+ efm32_i2c_write32(ddata, REG_TXDATA,
+ cur_msg->buf[ddata->current_word++]);
+ }
+}
+
+static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA);
+ ddata->current_word += 1;
+ if (ddata->current_word >= cur_msg->len) {
+ /* cur_msg completely transferred */
+ ddata->current_word = 0;
+ ddata->current_msg += 1;
+
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK);
+
+ if (ddata->current_msg >= ddata->num_msgs) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_msg(ddata);
+ }
+ } else {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK);
+ }
+}
+
+static irqreturn_t efm32_i2c_irq(int irq, void *dev_id)
+{
+ struct efm32_i2c_ddata *ddata = dev_id;
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+ u32 irqflag = efm32_i2c_read32(ddata, REG_IF);
+ u32 state = efm32_i2c_read32(ddata, REG_STATE);
+
+ efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK);
+
+ switch (state & REG_STATE_STATE__MASK) {
+ case REG_STATE_STATE_IDLE:
+ /* arbitration lost? */
+ ddata->retval = -EAGAIN;
+ complete(&ddata->done);
+ break;
+ case REG_STATE_STATE_WAIT:
+ /*
+ * huh, this shouldn't happen.
+ * Reset hardware state and get out
+ */
+ ddata->retval = -EIO;
+ efm32_i2c_write32(ddata, REG_CMD,
+ REG_CMD_STOP | REG_CMD_ABORT |
+ REG_CMD_CLEARTX | REG_CMD_CLEARPC);
+ complete(&ddata->done);
+ break;
+ case REG_STATE_STATE_START:
+ /* "caller" is expected to send an address */
+ break;
+ case REG_STATE_STATE_ADDR:
+ /* wait for Ack or NAck of slave */
+ break;
+ case REG_STATE_STATE_ADDRACK:
+ if (state & REG_STATE_NACKED) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ ddata->retval = -ENXIO;
+ complete(&ddata->done);
+ } else if (cur_msg->flags & I2C_M_RD) {
+ /* wait for slave to send first data byte */
+ } else {
+ efm32_i2c_send_next_byte(ddata);
+ }
+ break;
+ case REG_STATE_STATE_DATA:
+ if (cur_msg->flags & I2C_M_RD) {
+ efm32_i2c_recv_next_byte(ddata);
+ } else {
+ /* wait for Ack or Nack of slave */
+ }
+ break;
+ case REG_STATE_STATE_DATAACK:
+ if (state & REG_STATE_NACKED) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_byte(ddata);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int efm32_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap);
+ int ret;
+
+ if (ddata->msgs)
+ return -EBUSY;
+
+ ddata->msgs = msgs;
+ ddata->num_msgs = num;
+ ddata->current_word = 0;
+ ddata->current_msg = 0;
+ ddata->retval = -EIO;
+
+ reinit_completion(&ddata->done);
+
+ dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n",
+ efm32_i2c_read32(ddata, REG_STATE),
+ efm32_i2c_read32(ddata, REG_STATUS));
+
+ efm32_i2c_send_next_msg(ddata);
+
+ wait_for_completion(&ddata->done);
+
+ if (ddata->current_msg >= ddata->num_msgs)
+ ret = ddata->num_msgs;
+ else
+ ret = ddata->retval;
+
+ return ret;
+}
+
+static u32 efm32_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm efm32_i2c_algo = {
+ .master_xfer = efm32_i2c_master_xfer,
+ .functionality = efm32_i2c_functionality,
+};
+
+static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata)
+{
+ u32 reg = efm32_i2c_read32(ddata, REG_ROUTE);
+
+ return (reg & REG_ROUTE_LOCATION__MASK) >>
+ __ffs(REG_ROUTE_LOCATION__MASK);
+}
+
+static int efm32_i2c_probe(struct platform_device *pdev)
+{
+ struct efm32_i2c_ddata *ddata;
+ struct resource *res;
+ unsigned long rate;
+ struct device_node *np = pdev->dev.of_node;
+ u32 location, frequency;
+ int ret;
+ u32 clkdiv;
+
+ if (!np)
+ return -EINVAL;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, ddata);
+
+ init_completion(&ddata->done);
+ strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name));
+ ddata->adapter.owner = THIS_MODULE;
+ ddata->adapter.algo = &efm32_i2c_algo;
+ ddata->adapter.dev.parent = &pdev->dev;
+ ddata->adapter.dev.of_node = pdev->dev.of_node;
+ i2c_set_adapdata(&ddata->adapter, ddata);
+
+ ddata->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ddata->clk)) {
+ ret = PTR_ERR(ddata->clk);
+ dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to determine base address\n");
+ return -ENODEV;
+ }
+
+ if (resource_size(res) < 0x42) {
+ dev_err(&pdev->dev, "memory resource too small\n");
+ return -EINVAL;
+ }
+
+ ddata->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ddata->base))
+ return PTR_ERR(ddata->base);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
+ if (!ret)
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ddata->irq = ret;
+
+ ret = clk_prepare_enable(ddata->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "efm32,location", &location);
+ if (!ret) {
+ dev_dbg(&pdev->dev, "using location %u\n", location);
+ } else {
+ /* default to location configured in hardware */
+ location = efm32_i2c_get_configured_location(ddata);
+
+ dev_info(&pdev->dev, "fall back to location %u\n", location);
+ }
+
+ ddata->location = location;
+
+ ret = of_property_read_u32(np, "clock-frequency", &frequency);
+ if (!ret) {
+ dev_dbg(&pdev->dev, "using frequency %u\n", frequency);
+ } else {
+ frequency = 100000;
+ dev_info(&pdev->dev, "defaulting to 100 kHz\n");
+ }
+ ddata->frequency = frequency;
+
+ rate = clk_get_rate(ddata->clk);
+ if (!rate) {
+ dev_err(&pdev->dev, "there is no input clock available\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
+ clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1;
+ if (clkdiv >= 0x200) {
+ dev_err(&pdev->dev,
+ "input clock too fast (%lu) to divide down to bus freq (%lu)",
+ rate, ddata->frequency);
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
+
+ dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n",
+ rate, ddata->frequency, (unsigned long)clkdiv);
+ efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv));
+
+ efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN |
+ REG_ROUTE_SCLPEN |
+ REG_ROUTE_LOCATION(ddata->location));
+
+ efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN |
+ REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO);
+
+ efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK);
+ efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK
+ | REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV);
+
+ /* to make bus idle */
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT);
+
+ ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
+ return ret;
+ }
+
+ ret = i2c_add_adapter(&ddata->adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret);
+ free_irq(ddata->irq, ddata);
+
+err_disable_clk:
+ clk_disable_unprepare(ddata->clk);
+ }
+ return ret;
+}
+
+static int efm32_i2c_remove(struct platform_device *pdev)
+{
+ struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&ddata->adapter);
+ free_irq(ddata->irq, ddata);
+ clk_disable_unprepare(ddata->clk);
+
+ return 0;
+}
+
+static const struct of_device_id efm32_i2c_dt_ids[] = {
+ {
+ .compatible = "energymicro,efm32-i2c",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids);
+
+static struct platform_driver efm32_i2c_driver = {
+ .probe = efm32_i2c_probe,
+ .remove = efm32_i2c_remove,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = efm32_i2c_dt_ids,
+ },
+};
+module_platform_driver(efm32_i2c_driver);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 i2c driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index e08e458bab0..a44ea13d143 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -186,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex);
#define PCI_DEVICE_ID_ML7223_I2C 0x8010
#define PCI_DEVICE_ID_ML7831_I2C 0x8817
-static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = {
+static const struct pci_device_id pch_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
@@ -751,10 +751,8 @@ static int pch_i2c_probe(struct pci_dev *pdev,
pch_pci_dbg(pdev, "Entered.\n");
adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
- if (adap_info == NULL) {
- pch_pci_err(pdev, "Memory allocation FAILED\n");
+ if (adap_info == NULL)
return -ENOMEM;
- }
ret = pci_enable_device(pdev);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 9fd711c03dd..63d22920285 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -76,12 +76,6 @@
#define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4)
#define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16)
-/* As per user manual FIFO max depth is 64bytes */
-#define HSI2C_FIFO_MAX 0x40
-/* default trigger levels for Tx and Rx FIFOs */
-#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30)
-#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10)
-
/* I2C_TRAILING_CTL Register bits */
#define HSI2C_TRAILING_COUNT (0xf)
@@ -183,14 +177,54 @@ struct exynos5_i2c {
* 2. Fast speed upto 1Mbps
*/
int speed_mode;
+
+ /* Version of HS-I2C Hardware */
+ struct exynos_hsi2c_variant *variant;
+};
+
+/**
+ * struct exynos_hsi2c_variant - platform specific HSI2C driver data
+ * @fifo_depth: the fifo depth supported by the HSI2C module
+ *
+ * Specifies platform specific configuration of HSI2C module.
+ * Note: A structure for driver specific platform data is used for future
+ * expansion of its usage.
+ */
+struct exynos_hsi2c_variant {
+ unsigned int fifo_depth;
+};
+
+static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
+ .fifo_depth = 64,
+};
+
+static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
+ .fifo_depth = 16,
};
static const struct of_device_id exynos5_i2c_match[] = {
- { .compatible = "samsung,exynos5-hsi2c" },
- {},
+ {
+ .compatible = "samsung,exynos5-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5250-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5260-hsi2c",
+ .data = &exynos5260_hsi2c_data
+ }, {},
};
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
+static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant
+ (struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_node(exynos5_i2c_match, pdev->dev.of_node);
+ return (struct exynos_hsi2c_variant *)match->data;
+}
+
static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
{
writel(readl(i2c->regs + HSI2C_INT_STATUS),
@@ -415,7 +449,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
- len = HSI2C_FIFO_MAX - fifo_level;
+ len = i2c->variant->fifo_depth - fifo_level;
if (len > (i2c->msg->len - i2c->msg_ptr))
len = i2c->msg->len - i2c->msg_ptr;
@@ -483,6 +517,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
u32 i2c_auto_conf = 0;
u32 fifo_ctl;
unsigned long flags;
+ unsigned short trig_lvl;
i2c_ctl = readl(i2c->regs + HSI2C_CTL);
i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
@@ -493,13 +528,19 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
i2c_auto_conf = HSI2C_READ_WRITE;
- fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL);
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl);
+
int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN |
HSI2C_INT_TRAILING_EN);
} else {
i2c_ctl |= HSI2C_TXCHON;
- fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL);
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl);
+
int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN;
}
@@ -566,7 +607,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
static int exynos5_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
- struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data;
+ struct exynos5_i2c *i2c = adap->algo_data;
int i = 0, ret = 0, stop = 0;
if (i2c->suspended) {
@@ -621,10 +662,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
int ret;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state\n");
+ if (!i2c)
return -ENOMEM;
- }
if (of_property_read_u32(np, "clock-frequency", &op_clock)) {
i2c->speed_mode = HSI2C_FAST_SPD;
@@ -691,7 +730,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
if (ret)
goto err_clk;
- exynos5_i2c_init(i2c);
+ i2c->variant = exynos5_i2c_get_variant(pdev);
+
+ exynos5_i2c_reset(i2c);
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
@@ -715,6 +756,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int exynos5_i2c_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -745,6 +787,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
exynos5_i2c_resume_noirq);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index d9f7e186a4c..71a45b210a2 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -94,6 +94,9 @@ static int of_i2c_gpio_get_pins(struct device_node *np,
*sda_pin = of_get_gpio(np, 0);
*scl_pin = of_get_gpio(np, 1);
+ if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) {
pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
np->full_name, *sda_pin, *scl_pin);
@@ -144,24 +147,22 @@ static int i2c_gpio_probe(struct platform_device *pdev)
scl_pin = pdata->scl_pin;
}
- ret = gpio_request(sda_pin, "sda");
+ ret = devm_gpio_request(&pdev->dev, sda_pin, "sda");
if (ret) {
if (ret == -EINVAL)
ret = -EPROBE_DEFER; /* Try again later */
- goto err_request_sda;
+ return ret;
}
- ret = gpio_request(scl_pin, "scl");
+ ret = devm_gpio_request(&pdev->dev, scl_pin, "scl");
if (ret) {
if (ret == -EINVAL)
ret = -EPROBE_DEFER; /* Try again later */
- goto err_request_scl;
+ return ret;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto err_add_bus;
- }
+ if (!priv)
+ return -ENOMEM;
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
@@ -222,7 +223,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
- goto err_add_bus;
+ return ret;
platform_set_drvdata(pdev, priv);
@@ -232,13 +233,6 @@ static int i2c_gpio_probe(struct platform_device *pdev)
? ", no clock stretching" : "");
return 0;
-
-err_add_bus:
- gpio_free(scl_pin);
-err_request_scl:
- gpio_free(sda_pin);
-err_request_sda:
- return ret;
}
static int i2c_gpio_remove(struct platform_device *pdev)
@@ -252,8 +246,6 @@ static int i2c_gpio_remove(struct platform_device *pdev)
pdata = &priv->pdata;
i2c_del_adapter(adap);
- gpio_free(pdata->scl_pin);
- gpio_free(pdata->sda_pin);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index e248257fe51..14d2b76de25 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -104,7 +104,7 @@ static struct i2c_adapter hydra_adap = {
.algo_data = &hydra_bit_data,
};
-static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
+static const struct pci_device_id hydra_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 349c2d35e79..6777cd6f877 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -60,6 +60,7 @@
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
+ BayTrail (SOC) 0x0f12 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -161,6 +162,7 @@
STATUS_ERROR_FLAGS)
/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
@@ -789,7 +791,7 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = i801_func,
};
-static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
+static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
@@ -822,6 +824,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index db895fb22e6..aa8bc146718 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -183,6 +183,8 @@ struct imx_i2c_struct {
unsigned int disable_delay;
int stopped;
unsigned int ifdr; /* IMX_I2C_IFDR */
+ unsigned int cur_clk;
+ unsigned int bitrate;
const struct imx_i2c_hwdata *hwdata;
};
@@ -305,6 +307,48 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
return 0;
}
+static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
+{
+ struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
+ unsigned int i2c_clk_rate;
+ unsigned int div;
+ int i;
+
+ /* Divider value calculation */
+ i2c_clk_rate = clk_get_rate(i2c_imx->clk);
+ if (i2c_imx->cur_clk == i2c_clk_rate)
+ return;
+ else
+ i2c_imx->cur_clk = i2c_clk_rate;
+
+ div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
+ if (div < i2c_clk_div[0].div)
+ i = 0;
+ else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
+ i = i2c_imx->hwdata->ndivs - 1;
+ else
+ for (i = 0; i2c_clk_div[i].div < div; i++);
+
+ /* Store divider value */
+ i2c_imx->ifdr = i2c_clk_div[i].val;
+
+ /*
+ * There dummy delay is calculated.
+ * It should be about one I2C clock period long.
+ * This delay is used in I2C bus disable function
+ * to fix chip hardware bug.
+ */
+ i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div
+ + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+
+#ifdef CONFIG_I2C_DEBUG_BUS
+ dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n",
+ i2c_clk_rate, div);
+ dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n",
+ i2c_clk_div[i].val, i2c_clk_div[i].div);
+#endif
+}
+
static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
{
unsigned int temp = 0;
@@ -312,6 +356,8 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ i2c_imx_set_clk(i2c_imx);
+
result = clk_prepare_enable(i2c_imx->clk);
if (result)
return result;
@@ -367,45 +413,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
clk_disable_unprepare(i2c_imx->clk);
}
-static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
- unsigned int rate)
-{
- struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
- unsigned int i2c_clk_rate;
- unsigned int div;
- int i;
-
- /* Divider value calculation */
- i2c_clk_rate = clk_get_rate(i2c_imx->clk);
- div = (i2c_clk_rate + rate - 1) / rate;
- if (div < i2c_clk_div[0].div)
- i = 0;
- else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
- i = i2c_imx->hwdata->ndivs - 1;
- else
- for (i = 0; i2c_clk_div[i].div < div; i++);
-
- /* Store divider value */
- i2c_imx->ifdr = i2c_clk_div[i].val;
-
- /*
- * There dummy delay is calculated.
- * It should be about one I2C clock period long.
- * This delay is used in I2C bus disable function
- * to fix chip hardware bug.
- */
- i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div
- + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
-
- /* dev_dbg() can't be used, because adapter is not yet registered */
-#ifdef CONFIG_I2C_DEBUG_BUS
- dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
- __func__, i2c_clk_rate, div);
- dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
- __func__, i2c_clk_div[i].val, i2c_clk_div[i].div);
-#endif
-}
-
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
struct imx_i2c_struct *i2c_imx = dev_id;
@@ -458,10 +465,11 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
return 0;
}
-static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg)
{
int i, result;
unsigned int temp;
+ int block_data = msgs->flags & I2C_M_RECV_LEN;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
@@ -481,7 +489,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
/* setup bus to read data */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
- if (msgs->len - 1)
+
+ /*
+ * Reset the I2CR_TXAK flag initially for SMBus block read since the
+ * length is unknown
+ */
+ if ((msgs->len - 1) || block_data)
temp &= ~I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
@@ -490,19 +503,49 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
/* read data */
for (i = 0; i < msgs->len; i++) {
+ u8 len = 0;
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
- if (i == (msgs->len - 1)) {
- /* It must generate STOP before read I2DR to prevent
- controller from generating another clock cycle */
+ /*
+ * First byte is the length of remaining packet
+ * in the SMBus block data read. Add it to
+ * msgs->len.
+ */
+ if ((!i) && block_data) {
+ len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
+ return -EPROTO;
dev_dbg(&i2c_imx->adapter.dev,
- "<%s> clear MSTA\n", __func__);
- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- temp &= ~(I2CR_MSTA | I2CR_MTX);
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- i2c_imx_bus_busy(i2c_imx, 0);
- i2c_imx->stopped = 1;
+ "<%s> read length: 0x%X\n",
+ __func__, len);
+ msgs->len += len;
+ }
+ if (i == (msgs->len - 1)) {
+ if (is_lastmsg) {
+ /*
+ * It must generate STOP before read I2DR to prevent
+ * controller from generating another clock cycle
+ */
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> clear MSTA\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx->stopped = 1;
+ } else {
+ /*
+ * For i2c master receiver repeat restart operation like:
+ * read -> repeat MSTA -> read/write
+ * The controller must set MTX before read the last byte in
+ * the first read operation, otherwise the first read cost
+ * one extra clock cycle.
+ */
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp |= I2CR_MTX;
+ writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ }
} else if (i == (msgs->len - 2)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> set TXAK\n", __func__);
@@ -510,7 +553,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
temp |= I2CR_TXAK;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
- msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ if ((!i) && block_data)
+ msgs->buf[0] = len;
+ else
+ msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
@@ -523,6 +569,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
{
unsigned int i, temp;
int result;
+ bool is_lastmsg = false;
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
@@ -534,6 +581,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* read/write data */
for (i = 0; i < num; i++) {
+ if (i == num - 1)
+ is_lastmsg = true;
+
if (i) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> repeated start\n", __func__);
@@ -564,7 +614,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
(temp & I2SR_RXAK ? 1 : 0));
#endif
if (msgs[i].flags & I2C_M_RD)
- result = i2c_imx_read(i2c_imx, &msgs[i]);
+ result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);
else
result = i2c_imx_write(i2c_imx, &msgs[i]);
if (result)
@@ -583,7 +633,8 @@ fail0:
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
static struct i2c_algorithm i2c_imx_algo = {
@@ -600,7 +651,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
void __iomem *base;
int irq, ret;
- u32 bitrate;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
@@ -617,10 +667,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct),
GFP_KERNEL);
- if (!i2c_imx) {
- dev_err(&pdev->dev, "can't allocate interface\n");
+ if (!i2c_imx)
return -ENOMEM;
- }
if (of_id)
i2c_imx->hwdata = of_id->data;
@@ -664,12 +712,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
/* Set up clock divider */
- bitrate = IMX_I2C_BIT_RATE;
+ i2c_imx->bitrate = IMX_I2C_BIT_RATE;
ret = of_property_read_u32(pdev->dev.of_node,
- "clock-frequency", &bitrate);
+ "clock-frequency", &i2c_imx->bitrate);
if (ret < 0 && pdata && pdata->bitrate)
- bitrate = pdata->bitrate;
- i2c_imx_set_clk(i2c_imx, bitrate);
+ i2c_imx->bitrate = pdata->bitrate;
/* Set up chip registers to defaults */
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index 8ce4f517fc5..984492553e9 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -182,7 +182,7 @@ struct ismt_priv {
/**
* ismt_ids - PCI device IDs supported by this driver
*/
-static DEFINE_PCI_DEVICE_TABLE(ismt_ids) = {
+static const struct pci_device_id ismt_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index f5391633b53..6a32aa095f8 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -115,7 +115,7 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c)
for (k = 9; k; k--) {
writeccr(i2c, 0);
writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
- udelay(delay_val);
+ readb(i2c->base + MPC_I2C_DR);
writeccr(i2c, CCR_MEN);
udelay(delay_val << 1);
}
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index b8c5187b9ee..9f4b775e2e3 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/mv643xx_i2c.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -97,8 +98,6 @@ enum {
enum {
MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE,
- MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
- MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1,
@@ -149,6 +148,8 @@ struct mv64xxx_i2c_data {
bool offload_enabled;
/* 5us delay in order to avoid repeated start timing violation */
bool errata_delay;
+ struct reset_control *rstc;
+ bool irq_clear_inverted;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -177,11 +178,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
{
u32 dir = 0;
- drv_data->msg = msg;
- drv_data->byte_posn = 0;
- drv_data->bytes_left = msg->len;
- drv_data->aborting = 0;
- drv_data->rc = 0;
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
@@ -204,11 +200,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
unsigned long ctrl_reg;
struct i2c_msg *msg = drv_data->msgs;
- drv_data->msg = msg;
- drv_data->byte_posn = 0;
- drv_data->bytes_left = msg->len;
- drv_data->aborting = 0;
- drv_data->rc = 0;
+ if (!drv_data->offload_enabled)
+ return -EOPNOTSUPP;
+
/* Only regular transactions can be offloaded */
if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
return -EINVAL;
@@ -417,6 +411,23 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
}
}
+static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
+{
+ drv_data->msg = drv_data->msgs;
+ drv_data->byte_posn = 0;
+ drv_data->bytes_left = drv_data->msg->len;
+ drv_data->aborting = 0;
+ drv_data->rc = 0;
+
+ /* Can we offload this msg ? */
+ if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
+ /* No, switch to standard path */
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ }
+}
+
static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
@@ -433,15 +444,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->msgs++;
drv_data->num_msgs--;
- if (!(drv_data->offload_enabled &&
- mv64xxx_i2c_offload_msg(drv_data))) {
- drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
- writel(drv_data->cntl_bits,
- drv_data->reg_base + drv_data->reg_offsets.control);
+ mv64xxx_i2c_send_start(drv_data);
- /* Setup for the next message */
- mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
- }
if (drv_data->errata_delay)
udelay(5);
@@ -458,17 +462,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->reg_base + drv_data->reg_offsets.control);
break;
- case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
- if (!mv64xxx_i2c_offload_msg(drv_data))
- break;
- else
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- /* FALLTHRU */
- case MV64XXX_I2C_ACTION_SEND_START:
- writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
- drv_data->reg_base + drv_data->reg_offsets.control);
- break;
-
case MV64XXX_I2C_ACTION_SEND_ADDR_1:
writel(drv_data->addr1,
drv_data->reg_base + drv_data->reg_offsets.data);
@@ -566,6 +559,11 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
mv64xxx_i2c_fsm(drv_data, status);
mv64xxx_i2c_do_action(drv_data);
+
+ if (drv_data->irq_clear_inverted)
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_IFLG,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+
rc = IRQ_HANDLED;
}
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -625,18 +623,12 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
- if (drv_data->offload_enabled) {
- drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
- } else {
- mv64xxx_i2c_prepare_for_io(drv_data, msg);
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
- }
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+
drv_data->send_stop = is_last;
drv_data->block = 1;
- mv64xxx_i2c_do_action(drv_data);
+ mv64xxx_i2c_send_start(drv_data);
spin_unlock_irqrestore(&drv_data->lock, flags);
mv64xxx_i2c_wait_for_completion(drv_data);
@@ -689,7 +681,8 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
*****************************************************************************
*/
static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
- { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+ { .compatible = "allwinner,sun4i-a10-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+ { .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
@@ -764,6 +757,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
}
drv_data->irq = irq_of_parse_and_map(np, 0);
+ drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
+ if (IS_ERR(drv_data->rstc)) {
+ if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) {
+ rc = -EPROBE_DEFER;
+ goto out;
+ }
+ } else {
+ reset_control_deassert(drv_data->rstc);
+ }
+
/* Its not yet defined how timeouts will be specified in device tree.
* So hard code the value to 1 second.
*/
@@ -788,6 +791,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
drv_data->offload_enabled = false;
drv_data->errata_delay = true;
}
+
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+ drv_data->irq_clear_inverted = true;
+
out:
return rc;
#endif
@@ -850,13 +857,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
}
if (drv_data->irq < 0) {
rc = -ENXIO;
- goto exit_clk;
+ goto exit_reset;
}
drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
- drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
drv_data->adapter.nr = pd->id;
drv_data->adapter.dev.of_node = pd->dev.of_node;
platform_set_drvdata(pd, drv_data);
@@ -870,7 +877,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't register intr handler irq%d: %d\n",
drv_data->irq, rc);
- goto exit_clk;
+ goto exit_reset;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
@@ -881,6 +888,9 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_free_irq:
free_irq(drv_data->irq, drv_data);
+exit_reset:
+ if (!IS_ERR_OR_NULL(drv_data->rstc))
+ reset_control_assert(drv_data->rstc);
exit_clk:
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
@@ -899,6 +909,8 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
+ if (!IS_ERR_OR_NULL(drv_data->rstc))
+ reset_control_assert(drv_data->rstc);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 0cde4e6ab2b..7170fc89282 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -806,7 +806,6 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
struct resource *res;
- resource_size_t res_size;
int err, irq;
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
@@ -819,18 +818,13 @@ static int mxs_i2c_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
-
- if (!res || irq < 0)
- return -ENOENT;
+ i2c->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
- res_size = resource_size(res);
- if (!devm_request_mem_region(dev, res->start, res_size, res->name))
- return -EBUSY;
-
- i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
- if (!i2c->regs)
- return -EBUSY;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
if (err)
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 0038c451095..ee3a76c7ae9 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -306,7 +306,7 @@ static struct i2c_algorithm smbus_algorithm = {
};
-static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+static const struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 4443613514e..0e55d85fd4e 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -111,22 +111,6 @@ enum i2c_freq_mode {
};
/**
- * struct nmk_i2c_controller - client specific controller configuration
- * @clk_freq: clock frequency for the operation mode
- * @tft: Tx FIFO Threshold in bytes
- * @rft: Rx FIFO Threshold in bytes
- * @timeout Slave response timeout(ms)
- * @sm: speed mode
- */
-struct nmk_i2c_controller {
- u32 clk_freq;
- unsigned char tft;
- unsigned char rft;
- int timeout;
- enum i2c_freq_mode sm;
-};
-
-/**
* struct i2c_vendor_data - per-vendor variations
* @has_mtdws: variant has the MTDWS bit
* @fifodepth: variant FIFO depth
@@ -174,12 +158,15 @@ struct i2c_nmk_client {
* @irq: interrupt line for the controller.
* @virtbase: virtual io memory area.
* @clk: hardware i2c block clock.
- * @cfg: machine provided controller configuration.
* @cli: holder of client specific data.
+ * @clk_freq: clock frequency for the operation mode
+ * @tft: Tx FIFO Threshold in bytes
+ * @rft: Rx FIFO Threshold in bytes
+ * @timeout Slave response timeout (ms)
+ * @sm: speed mode
* @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result.
- * @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
struct i2c_vendor_data *vendor;
@@ -188,12 +175,15 @@ struct nmk_i2c_dev {
int irq;
void __iomem *virtbase;
struct clk *clk;
- struct nmk_i2c_controller cfg;
struct i2c_nmk_client cli;
+ u32 clk_freq;
+ unsigned char tft;
+ unsigned char rft;
+ int timeout;
+ enum i2c_freq_mode sm;
int stop;
struct completion xfer_complete;
int result;
- bool busy;
};
/* controller's abort causes */
@@ -386,7 +376,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* slsu = cycles / (1000000000 / f) + 1
*/
ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
- switch (dev->cfg.sm) {
+ switch (dev->sm) {
case I2C_FREQ_MODE_FAST:
case I2C_FREQ_MODE_FAST_PLUS:
slsu = DIV_ROUND_UP(100, ns); /* Fast */
@@ -409,7 +399,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* 2 whereas it is 3 for fast and fastplus mode of
* operation. TODO - high speed support.
*/
- div = (dev->cfg.clk_freq > 100000) ? 3 : 2;
+ div = (dev->clk_freq > 100000) ? 3 : 2;
/*
* generate the mask for baud rate counters. The controller
@@ -419,7 +409,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* so set brcr1 to 0.
*/
brcr1 = 0 << 16;
- brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff;
+ brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff;
/* set the baud rate counter register */
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
@@ -430,7 +420,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* TODO - support for fast mode plus (up to 1Mb/s)
* and high speed (up to 3.4 Mb/s)
*/
- if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
+ if (dev->sm > I2C_FREQ_MODE_FAST) {
dev_err(&dev->adev->dev,
"do not support this mode defaulting to std. mode\n");
brcr2 = i2c_clk/(100000 * 2) & 0xffff;
@@ -438,11 +428,11 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
writel(I2C_FREQ_MODE_STANDARD << 4,
dev->virtbase + I2C_CR);
}
- writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR);
+ writel(dev->sm << 4, dev->virtbase + I2C_CR);
/* set the Tx and Rx FIFO threshold */
- writel(dev->cfg.tft, dev->virtbase + I2C_TFTR);
- writel(dev->cfg.rft, dev->virtbase + I2C_RFTR);
+ writel(dev->tft, dev->virtbase + I2C_TFTR);
+ writel(dev->rft, dev->virtbase + I2C_RFTR);
}
/**
@@ -674,28 +664,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num_msgs)
{
- int status;
+ int status = 0;
int i;
struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
int j;
- dev->busy = true;
-
pm_runtime_get_sync(&dev->adev->dev);
- status = clk_prepare_enable(dev->clk);
- if (status) {
- dev_err(&dev->adev->dev, "can't prepare_enable clock\n");
- goto out_clk;
- }
-
- /* Optionaly enable pins to be muxed in and configured */
- pinctrl_pm_select_default_state(&dev->adev->dev);
-
- status = init_hw(dev);
- if (status)
- goto out;
-
/* Attempt three times to send the message queue */
for (j = 0; j < 3; j++) {
/* setup the i2c controller */
@@ -716,16 +691,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
break;
}
-out:
- clk_disable_unprepare(dev->clk);
-out_clk:
- /* Optionally let pins go into idle state */
- pinctrl_pm_select_idle_state(&dev->adev->dev);
-
pm_runtime_put_sync(&dev->adev->dev);
- dev->busy = false;
-
/* return the no. messages processed */
if (status)
return status;
@@ -909,43 +876,65 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
+#ifdef CONFIG_PM_SLEEP
+static int nmk_i2c_suspend_late(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ pinctrl_pm_select_sleep_state(dev);
+ return 0;
+}
+
+static int nmk_i2c_resume_early(struct device *dev)
+{
+ return pm_runtime_force_resume(dev);
+}
+#endif
#ifdef CONFIG_PM
-static int nmk_i2c_suspend(struct device *dev)
+static int nmk_i2c_runtime_suspend(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
- if (nmk_i2c->busy)
- return -EBUSY;
-
- pinctrl_pm_select_sleep_state(dev);
-
+ clk_disable_unprepare(nmk_i2c->clk);
+ pinctrl_pm_select_idle_state(dev);
return 0;
}
-static int nmk_i2c_resume(struct device *dev)
+static int nmk_i2c_runtime_resume(struct device *dev)
{
- /* First go to the default state */
+ struct amba_device *adev = to_amba_device(dev);
+ struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+ int ret;
+
+ ret = clk_prepare_enable(nmk_i2c->clk);
+ if (ret) {
+ dev_err(dev, "can't prepare_enable clock\n");
+ return ret;
+ }
+
pinctrl_pm_select_default_state(dev);
- /* Then let's idle the pins until the next transfer happens */
- pinctrl_pm_select_idle_state(dev);
- return 0;
+ ret = init_hw(nmk_i2c);
+ if (ret) {
+ clk_disable_unprepare(nmk_i2c->clk);
+ pinctrl_pm_select_idle_state(dev);
+ }
+
+ return ret;
}
-#else
-#define nmk_i2c_suspend NULL
-#define nmk_i2c_resume NULL
#endif
-/*
- * We use noirq so that we suspend late and resume before the wakeup interrupt
- * to ensure that we do the !pm_runtime_suspended() check in resume before
- * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
- */
static const struct dev_pm_ops nmk_i2c_pm = {
- .suspend_noirq = nmk_i2c_suspend,
- .resume_noirq = nmk_i2c_resume,
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early)
+ SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
+ nmk_i2c_runtime_resume,
+ NULL)
};
static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
@@ -958,118 +947,98 @@ static const struct i2c_algorithm nmk_i2c_algo = {
.functionality = nmk_i2c_functionality
};
-static struct nmk_i2c_controller u8500_i2c = {
- .tft = 1, /* Tx FIFO threshold */
- .rft = 8, /* Rx FIFO threshold */
- .clk_freq = 400000, /* fast mode operation */
- .timeout = 200, /* Slave response timeout(ms) */
- .sm = I2C_FREQ_MODE_FAST,
-};
-
static void nmk_i2c_of_probe(struct device_node *np,
- struct nmk_i2c_controller *pdata)
+ struct nmk_i2c_dev *nmk)
{
- of_property_read_u32(np, "clock-frequency", &pdata->clk_freq);
+ /* Default to 100 kHz if no frequency is given in the node */
+ if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq))
+ nmk->clk_freq = 100000;
/* This driver only supports 'standard' and 'fast' modes of operation. */
- if (pdata->clk_freq <= 100000)
- pdata->sm = I2C_FREQ_MODE_STANDARD;
+ if (nmk->clk_freq <= 100000)
+ nmk->sm = I2C_FREQ_MODE_STANDARD;
else
- pdata->sm = I2C_FREQ_MODE_FAST;
+ nmk->sm = I2C_FREQ_MODE_FAST;
+ nmk->tft = 1; /* Tx FIFO threshold */
+ nmk->rft = 8; /* Rx FIFO threshold */
+ nmk->timeout = 200; /* Slave response timeout(ms) */
}
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
- struct nmk_i2c_controller *pdata = dev_get_platdata(&adev->dev);
struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev;
struct i2c_adapter *adap;
struct i2c_vendor_data *vendor = id->data;
u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
- if (!pdata) {
- if (np) {
- pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- ret = -ENOMEM;
- goto err_no_mem;
- }
- /* Provide the default configuration as a base. */
- memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller));
- nmk_i2c_of_probe(np, pdata);
- } else
- /* No i2c configuration found, using the default. */
- pdata = &u8500_i2c;
+ dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&adev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
}
+ dev->vendor = vendor;
+ dev->adev = adev;
+ nmk_i2c_of_probe(np, dev);
- if (pdata->tft > max_fifo_threshold) {
+ if (dev->tft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
- pdata->tft, max_fifo_threshold);
- pdata->tft = max_fifo_threshold;
+ dev->tft, max_fifo_threshold);
+ dev->tft = max_fifo_threshold;
}
- if (pdata->rft > max_fifo_threshold) {
+ if (dev->rft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
- pdata->rft, max_fifo_threshold);
- pdata->rft = max_fifo_threshold;
+ dev->rft, max_fifo_threshold);
+ dev->rft = max_fifo_threshold;
}
- dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
- if (!dev) {
- dev_err(&adev->dev, "cannot allocate memory\n");
- ret = -ENOMEM;
- goto err_no_mem;
- }
- dev->vendor = vendor;
- dev->busy = false;
- dev->adev = adev;
amba_set_drvdata(adev, dev);
- /* Select default pin state */
- pinctrl_pm_select_default_state(&adev->dev);
- /* If possible, let's go to idle until the first transfer */
- pinctrl_pm_select_idle_state(&adev->dev);
-
- dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
+ dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+ resource_size(&adev->res));
if (!dev->virtbase) {
ret = -ENOMEM;
- goto err_no_ioremap;
+ goto err_no_mem;
}
dev->irq = adev->irq[0];
- ret = request_irq(dev->irq, i2c_irq_handler, 0,
+ ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
DRIVER_NAME, dev);
if (ret) {
dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
- goto err_irq;
+ goto err_no_mem;
}
pm_suspend_ignore_children(&adev->dev, true);
- dev->clk = clk_get(&adev->dev, NULL);
+ dev->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(dev->clk)) {
dev_err(&adev->dev, "could not get i2c clock\n");
ret = PTR_ERR(dev->clk);
- goto err_no_clk;
+ goto err_no_mem;
}
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ dev_err(&adev->dev, "can't prepare_enable clock\n");
+ goto err_no_mem;
+ }
+
+ init_hw(dev);
+
adap = &dev->adap;
adap->dev.of_node = np;
adap->dev.parent = &adev->dev;
adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
adap->algo = &nmk_i2c_algo;
- adap->timeout = msecs_to_jiffies(pdata->timeout);
+ adap->timeout = msecs_to_jiffies(dev->timeout);
snprintf(adap->name, sizeof(adap->name),
"Nomadik I2C at %pR", &adev->res);
- /* fetch the controller configuration from machine */
- dev->cfg.clk_freq = pdata->clk_freq;
- dev->cfg.tft = pdata->tft;
- dev->cfg.rft = pdata->rft;
- dev->cfg.sm = pdata->sm;
-
i2c_set_adapdata(adap, dev);
dev_info(&adev->dev,
@@ -1079,21 +1048,15 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
ret = i2c_add_adapter(adap);
if (ret) {
dev_err(&adev->dev, "failed to add adapter\n");
- goto err_add_adap;
+ goto err_no_adap;
}
pm_runtime_put(&adev->dev);
return 0;
- err_add_adap:
- clk_put(dev->clk);
- err_no_clk:
- free_irq(dev->irq, dev);
- err_irq:
- iounmap(dev->virtbase);
- err_no_ioremap:
- kfree(dev);
+ err_no_adap:
+ clk_disable_unprepare(dev->clk);
err_no_mem:
return ret;
@@ -1110,13 +1073,9 @@ static int nmk_i2c_remove(struct amba_device *adev)
clear_all_interrupts(dev);
/* disable the controller */
i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
- free_irq(dev->irq, dev);
- iounmap(dev->virtbase);
+ clk_disable_unprepare(dev->clk);
if (res)
release_mem_region(res->start, resource_size(res));
- clk_put(dev->clk);
- pm_runtime_disable(&adev->dev);
- kfree(dev);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c
deleted file mode 100644
index 36394d737fa..00000000000
--- a/drivers/i2c/busses/i2c-nuc900.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * linux/drivers/i2c/busses/i2c-nuc900.c
- *
- * Copyright (c) 2010 Nuvoton technology corporation.
- *
- * This driver based on S3C2410 I2C driver of Ben Dooks <ben-Y5A6D6n0/KfQXOPxS62xeg@public.gmane.org>.
- * Written by Wan ZongShun <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation;version 2 of the License.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-
-#include <mach/mfp.h>
-#include <linux/platform_data/i2c-nuc900.h>
-
-/* nuc900 i2c registers offset */
-
-#define CSR 0x00
-#define DIVIDER 0x04
-#define CMDR 0x08
-#define SWR 0x0C
-#define RXR 0x10
-#define TXR 0x14
-
-/* nuc900 i2c CSR register bits */
-
-#define IRQEN 0x003
-#define I2CBUSY 0x400
-#define I2CSTART 0x018
-#define IRQFLAG 0x004
-#define ARBIT_LOST 0x200
-#define SLAVE_ACK 0x800
-
-/* nuc900 i2c CMDR register bits */
-
-#define I2C_CMD_START 0x10
-#define I2C_CMD_STOP 0x08
-#define I2C_CMD_READ 0x04
-#define I2C_CMD_WRITE 0x02
-#define I2C_CMD_NACK 0x01
-
-/* i2c controller state */
-
-enum nuc900_i2c_state {
- STATE_IDLE,
- STATE_START,
- STATE_READ,
- STATE_WRITE,
- STATE_STOP
-};
-
-/* i2c controller private data */
-
-struct nuc900_i2c {
- spinlock_t lock;
- wait_queue_head_t wait;
-
- struct i2c_msg *msg;
- unsigned int msg_num;
- unsigned int msg_idx;
- unsigned int msg_ptr;
- unsigned int irq;
-
- enum nuc900_i2c_state state;
-
- void __iomem *regs;
- struct clk *clk;
- struct device *dev;
- struct resource *ioarea;
- struct i2c_adapter adap;
-};
-
-/* nuc900_i2c_master_complete
- *
- * complete the message and wake up the caller, using the given return code,
- * or zero to mean ok.
-*/
-
-static inline void nuc900_i2c_master_complete(struct nuc900_i2c *i2c, int ret)
-{
- dev_dbg(i2c->dev, "master_complete %d\n", ret);
-
- i2c->msg_ptr = 0;
- i2c->msg = NULL;
- i2c->msg_idx++;
- i2c->msg_num = 0;
- if (ret)
- i2c->msg_idx = ret;
-
- wake_up(&i2c->wait);
-}
-
-/* irq enable/disable functions */
-
-static inline void nuc900_i2c_disable_irq(struct nuc900_i2c *i2c)
-{
- unsigned long tmp;
-
- tmp = readl(i2c->regs + CSR);
- writel(tmp & ~IRQEN, i2c->regs + CSR);
-}
-
-static inline void nuc900_i2c_enable_irq(struct nuc900_i2c *i2c)
-{
- unsigned long tmp;
-
- tmp = readl(i2c->regs + CSR);
- writel(tmp | IRQEN, i2c->regs + CSR);
-}
-
-
-/* nuc900_i2c_message_start
- *
- * put the start of a message onto the bus
-*/
-
-static void nuc900_i2c_message_start(struct nuc900_i2c *i2c,
- struct i2c_msg *msg)
-{
- unsigned int addr = (msg->addr & 0x7f) << 1;
-
- if (msg->flags & I2C_M_RD)
- addr |= 0x1;
- writel(addr & 0xff, i2c->regs + TXR);
- writel(I2C_CMD_START | I2C_CMD_WRITE, i2c->regs + CMDR);
-}
-
-static inline void nuc900_i2c_stop(struct nuc900_i2c *i2c, int ret)
-{
-
- dev_dbg(i2c->dev, "STOP\n");
-
- /* stop the transfer */
- i2c->state = STATE_STOP;
- writel(I2C_CMD_STOP, i2c->regs + CMDR);
-
- nuc900_i2c_master_complete(i2c, ret);
- nuc900_i2c_disable_irq(i2c);
-}
-
-/* helper functions to determine the current state in the set of
- * messages we are sending
-*/
-
-/* is_lastmsg()
- *
- * returns TRUE if the current message is the last in the set
-*/
-
-static inline int is_lastmsg(struct nuc900_i2c *i2c)
-{
- return i2c->msg_idx >= (i2c->msg_num - 1);
-}
-
-/* is_msglast
- *
- * returns TRUE if we this is the last byte in the current message
-*/
-
-static inline int is_msglast(struct nuc900_i2c *i2c)
-{
- return i2c->msg_ptr == i2c->msg->len-1;
-}
-
-/* is_msgend
- *
- * returns TRUE if we reached the end of the current message
-*/
-
-static inline int is_msgend(struct nuc900_i2c *i2c)
-{
- return i2c->msg_ptr >= i2c->msg->len;
-}
-
-/* i2c_nuc900_irq_nextbyte
- *
- * process an interrupt and work out what to do
- */
-
-static void i2c_nuc900_irq_nextbyte(struct nuc900_i2c *i2c,
- unsigned long iicstat)
-{
- unsigned char byte;
-
- switch (i2c->state) {
-
- case STATE_IDLE:
- dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
- break;
-
- case STATE_STOP:
- dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
- nuc900_i2c_disable_irq(i2c);
- break;
-
- case STATE_START:
- /* last thing we did was send a start condition on the
- * bus, or started a new i2c message
- */
-
- if (iicstat & SLAVE_ACK &&
- !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
- /* ack was not received... */
-
- dev_dbg(i2c->dev, "ack was not received\n");
- nuc900_i2c_stop(i2c, -ENXIO);
- break;
- }
-
- if (i2c->msg->flags & I2C_M_RD)
- i2c->state = STATE_READ;
- else
- i2c->state = STATE_WRITE;
-
- /* terminate the transfer if there is nothing to do
- * as this is used by the i2c probe to find devices.
- */
-
- if (is_lastmsg(i2c) && i2c->msg->len == 0) {
- nuc900_i2c_stop(i2c, 0);
- break;
- }
-
- if (i2c->state == STATE_READ)
- goto prepare_read;
-
- /* fall through to the write state, as we will need to
- * send a byte as well
- */
-
- case STATE_WRITE:
- /* we are writing data to the device... check for the
- * end of the message, and if so, work out what to do
- */
-
- if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
- if (iicstat & SLAVE_ACK) {
- dev_dbg(i2c->dev, "WRITE: No Ack\n");
-
- nuc900_i2c_stop(i2c, -ECONNREFUSED);
- break;
- }
- }
-
-retry_write:
-
- if (!is_msgend(i2c)) {
- byte = i2c->msg->buf[i2c->msg_ptr++];
- writeb(byte, i2c->regs + TXR);
- writel(I2C_CMD_WRITE, i2c->regs + CMDR);
-
- } else if (!is_lastmsg(i2c)) {
- /* we need to go to the next i2c message */
-
- dev_dbg(i2c->dev, "WRITE: Next Message\n");
-
- i2c->msg_ptr = 0;
- i2c->msg_idx++;
- i2c->msg++;
-
- /* check to see if we need to do another message */
- if (i2c->msg->flags & I2C_M_NOSTART) {
-
- if (i2c->msg->flags & I2C_M_RD) {
- /* cannot do this, the controller
- * forces us to send a new START
- * when we change direction
- */
-
- nuc900_i2c_stop(i2c, -EINVAL);
- }
-
- goto retry_write;
- } else {
- /* send the new start */
- nuc900_i2c_message_start(i2c, i2c->msg);
- i2c->state = STATE_START;
- }
-
- } else {
- /* send stop */
-
- nuc900_i2c_stop(i2c, 0);
- }
- break;
-
- case STATE_READ:
- /* we have a byte of data in the data register, do
- * something with it, and then work out whether we are
- * going to do any more read/write
- */
-
- byte = readb(i2c->regs + RXR);
- i2c->msg->buf[i2c->msg_ptr++] = byte;
-
-prepare_read:
- if (is_msglast(i2c)) {
- /* last byte of buffer */
-
- if (is_lastmsg(i2c))
- writel(I2C_CMD_READ | I2C_CMD_NACK,
- i2c->regs + CMDR);
-
- } else if (is_msgend(i2c)) {
- /* ok, we've read the entire buffer, see if there
- * is anything else we need to do
- */
-
- if (is_lastmsg(i2c)) {
- /* last message, send stop and complete */
- dev_dbg(i2c->dev, "READ: Send Stop\n");
-
- nuc900_i2c_stop(i2c, 0);
- } else {
- /* go to the next transfer */
- dev_dbg(i2c->dev, "READ: Next Transfer\n");
-
- i2c->msg_ptr = 0;
- i2c->msg_idx++;
- i2c->msg++;
-
- writel(I2C_CMD_READ, i2c->regs + CMDR);
- }
-
- } else {
- writel(I2C_CMD_READ, i2c->regs + CMDR);
- }
-
- break;
- }
-}
-
-/* nuc900_i2c_irq
- *
- * top level IRQ servicing routine
-*/
-
-static irqreturn_t nuc900_i2c_irq(int irqno, void *dev_id)
-{
- struct nuc900_i2c *i2c = dev_id;
- unsigned long status;
-
- status = readl(i2c->regs + CSR);
- writel(status | IRQFLAG, i2c->regs + CSR);
-
- if (status & ARBIT_LOST) {
- /* deal with arbitration loss */
- dev_err(i2c->dev, "deal with arbitration loss\n");
- goto out;
- }
-
- if (i2c->state == STATE_IDLE) {
- dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
- goto out;
- }
-
- /* pretty much this leaves us with the fact that we've
- * transmitted or received whatever byte we last sent
- */
-
- i2c_nuc900_irq_nextbyte(i2c, status);
-
- out:
- return IRQ_HANDLED;
-}
-
-
-/* nuc900_i2c_set_master
- *
- * get the i2c bus for a master transaction
-*/
-
-static int nuc900_i2c_set_master(struct nuc900_i2c *i2c)
-{
- int timeout = 400;
-
- while (timeout-- > 0) {
- if (((readl(i2c->regs + SWR) & I2CSTART) == I2CSTART) &&
- ((readl(i2c->regs + CSR) & I2CBUSY) == 0)) {
- return 0;
- }
-
- msleep(1);
- }
-
- return -ETIMEDOUT;
-}
-
-/* nuc900_i2c_doxfer
- *
- * this starts an i2c transfer
-*/
-
-static int nuc900_i2c_doxfer(struct nuc900_i2c *i2c,
- struct i2c_msg *msgs, int num)
-{
- unsigned long iicstat, timeout;
- int spins = 20;
- int ret;
-
- ret = nuc900_i2c_set_master(i2c);
- if (ret != 0) {
- dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
- ret = -EAGAIN;
- goto out;
- }
-
- spin_lock_irq(&i2c->lock);
-
- i2c->msg = msgs;
- i2c->msg_num = num;
- i2c->msg_ptr = 0;
- i2c->msg_idx = 0;
- i2c->state = STATE_START;
-
- nuc900_i2c_message_start(i2c, msgs);
- spin_unlock_irq(&i2c->lock);
-
- timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
-
- ret = i2c->msg_idx;
-
- /* having these next two as dev_err() makes life very
- * noisy when doing an i2cdetect
- */
-
- if (timeout == 0)
- dev_dbg(i2c->dev, "timeout\n");
- else if (ret != num)
- dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
-
- /* ensure the stop has been through the bus */
-
- dev_dbg(i2c->dev, "waiting for bus idle\n");
-
- /* first, try busy waiting briefly */
- do {
- iicstat = readl(i2c->regs + CSR);
- } while ((iicstat & I2CBUSY) && --spins);
-
- /* if that timed out sleep */
- if (!spins) {
- msleep(1);
- iicstat = readl(i2c->regs + CSR);
- }
-
- if (iicstat & I2CBUSY)
- dev_warn(i2c->dev, "timeout waiting for bus idle\n");
-
- out:
- return ret;
-}
-
-/* nuc900_i2c_xfer
- *
- * first port of call from the i2c bus code when an message needs
- * transferring across the i2c bus.
-*/
-
-static int nuc900_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
-{
- struct nuc900_i2c *i2c = (struct nuc900_i2c *)adap->algo_data;
- int retry;
- int ret;
-
- nuc900_i2c_enable_irq(i2c);
-
- for (retry = 0; retry < adap->retries; retry++) {
-
- ret = nuc900_i2c_doxfer(i2c, msgs, num);
-
- if (ret != -EAGAIN)
- return ret;
-
- dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
-
- udelay(100);
- }
-
- return -EREMOTEIO;
-}
-
-/* declare our i2c functionality */
-static u32 nuc900_i2c_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART |
- I2C_FUNC_PROTOCOL_MANGLING;
-}
-
-/* i2c bus registration info */
-
-static const struct i2c_algorithm nuc900_i2c_algorithm = {
- .master_xfer = nuc900_i2c_xfer,
- .functionality = nuc900_i2c_func,
-};
-
-/* nuc900_i2c_probe
- *
- * called by the bus driver when a suitable device is found
-*/
-
-static int nuc900_i2c_probe(struct platform_device *pdev)
-{
- struct nuc900_i2c *i2c;
- struct nuc900_platform_i2c *pdata;
- struct resource *res;
- int ret;
-
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
- i2c = kzalloc(sizeof(struct nuc900_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state\n");
- return -ENOMEM;
- }
-
- strlcpy(i2c->adap.name, "nuc900-i2c0", sizeof(i2c->adap.name));
- i2c->adap.owner = THIS_MODULE;
- i2c->adap.algo = &nuc900_i2c_algorithm;
- i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-
- spin_lock_init(&i2c->lock);
- init_waitqueue_head(&i2c->wait);
-
- /* find the clock and enable it */
-
- i2c->dev = &pdev->dev;
- i2c->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2c->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
- ret = -ENOENT;
- goto err_noclk;
- }
-
- dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
-
- clk_enable(i2c->clk);
-
- /* map the registers */
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "cannot find IO resource\n");
- ret = -ENOENT;
- goto err_clk;
- }
-
- i2c->ioarea = request_mem_region(res->start, resource_size(res),
- pdev->name);
-
- if (i2c->ioarea == NULL) {
- dev_err(&pdev->dev, "cannot request IO\n");
- ret = -ENXIO;
- goto err_clk;
- }
-
- i2c->regs = ioremap(res->start, resource_size(res));
-
- if (i2c->regs == NULL) {
- dev_err(&pdev->dev, "cannot map IO\n");
- ret = -ENXIO;
- goto err_ioarea;
- }
-
- dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
- i2c->regs, i2c->ioarea, res);
-
- /* setup info block for the i2c core */
-
- i2c->adap.algo_data = i2c;
- i2c->adap.dev.parent = &pdev->dev;
-
- mfp_set_groupg(&pdev->dev, NULL);
-
- clk_get_rate(i2c->clk);
-
- ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1;
- writel(ret & 0xffff, i2c->regs + DIVIDER);
-
- /* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
- */
-
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- goto err_iomap;
- }
-
- ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED,
- dev_name(&pdev->dev), i2c);
-
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
- goto err_iomap;
- }
-
- /* Note, previous versions of the driver used i2c_add_adapter()
- * to add the bus at any number. We now pass the bus number via
- * the platform data, so if unset it will now default to always
- * being bus 0.
- */
-
- i2c->adap.nr = pdata->bus_num;
-
- ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
- goto err_irq;
- }
-
- platform_set_drvdata(pdev, i2c);
-
- dev_info(&pdev->dev, "%s: NUC900 I2C adapter\n",
- dev_name(&i2c->adap.dev));
- return 0;
-
- err_irq:
- free_irq(i2c->irq, i2c);
-
- err_iomap:
- iounmap(i2c->regs);
-
- err_ioarea:
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
-
- err_clk:
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
-
- err_noclk:
- kfree(i2c);
- return ret;
-}
-
-/* nuc900_i2c_remove
- *
- * called when device is removed from the bus
-*/
-
-static int nuc900_i2c_remove(struct platform_device *pdev)
-{
- struct nuc900_i2c *i2c = platform_get_drvdata(pdev);
-
- i2c_del_adapter(&i2c->adap);
- free_irq(i2c->irq, i2c);
-
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
-
- iounmap(i2c->regs);
-
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- kfree(i2c);
-
- return 0;
-}
-
-static struct platform_driver nuc900_i2c_driver = {
- .probe = nuc900_i2c_probe,
- .remove = nuc900_i2c_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "nuc900-i2c0",
- },
-};
-
-static int __init i2c_adap_nuc900_init(void)
-{
- return platform_driver_register(&nuc900_i2c_driver);
-}
-
-static void __exit i2c_adap_nuc900_exit(void)
-{
- platform_driver_unregister(&nuc900_i2c_driver);
-}
-subsys_initcall(i2c_adap_nuc900_init);
-module_exit(i2c_adap_nuc900_exit);
-
-MODULE_DESCRIPTION("NUC900 I2C Bus driver");
-MODULE_AUTHOR("Wan ZongShun, <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-i2c0");
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 80e06fa4572..0e10cc6182f 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -246,11 +246,11 @@ static const struct i2c_algorithm ocores_algorithm = {
static struct i2c_adapter ocores_adapter = {
.owner = THIS_MODULE,
.name = "i2c-ocores",
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
.algo = &ocores_algorithm,
};
-static struct of_device_id ocores_i2c_match[] = {
+static const struct of_device_id ocores_i2c_match[] = {
{
.compatible = "opencores,i2c-ocores",
.data = (void *)TYPE_OCORES,
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 90dcc2eaac5..b182793a405 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -636,7 +636,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
int r;
r = pm_runtime_get_sync(dev->dev);
- if (IS_ERR_VALUE(r))
+ if (r < 0)
goto out;
r = omap_i2c_wait_for_bb(dev);
@@ -1114,10 +1114,8 @@ omap_i2c_probe(struct platform_device *pdev)
}
dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
- if (!dev) {
- dev_err(&pdev->dev, "Menory allocation failed\n");
+ if (!dev)
return -ENOMEM;
- }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
@@ -1155,7 +1153,7 @@ omap_i2c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev->dev);
r = pm_runtime_get_sync(dev->dev);
- if (IS_ERR_VALUE(r))
+ if (r < 0)
goto err_free_mem;
/*
@@ -1238,7 +1236,7 @@ omap_i2c_probe(struct platform_device *pdev)
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
adap->algo = &omap_i2c_algo;
adap->dev.parent = &pdev->dev;
@@ -1276,7 +1274,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter);
ret = pm_runtime_get_sync(&pdev->dev);
- if (IS_ERR_VALUE(ret))
+ if (ret < 0)
return ret;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index 615f632c846..7a9dce43e11 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -401,7 +401,7 @@ static void pasemi_smb_remove(struct pci_dev *dev)
kfree(smbus);
}
-static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = {
+static const struct pci_device_id pasemi_smb_ids[] = {
{ PCI_DEVICE(0x1959, 0xa003) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 39dd8ec60df..a6f54ba27e2 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -540,7 +540,7 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = piix4_func,
};
-static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
+static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 9639be86e53..417464e9ea2 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -148,7 +148,7 @@ static void ce4100_i2c_remove(struct pci_dev *dev)
kfree(sds);
}
-static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = {
+static const struct pci_device_id ce4100_i2c_devices[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
{ },
};
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index bbe6dfbc5c0..be671f7a0e0 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1084,7 +1084,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
.functionality = i2c_pxa_functionality,
};
-static struct of_device_id i2c_pxa_dt_ids[] = {
+static const struct of_device_id i2c_pxa_dt_ids[] = {
{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
new file mode 100644
index 00000000000..2a5efb5b487
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* QUP Registers */
+#define QUP_CONFIG 0x000
+#define QUP_STATE 0x004
+#define QUP_IO_MODE 0x008
+#define QUP_SW_RESET 0x00c
+#define QUP_OPERATIONAL 0x018
+#define QUP_ERROR_FLAGS 0x01c
+#define QUP_ERROR_FLAGS_EN 0x020
+#define QUP_HW_VERSION 0x030
+#define QUP_MX_OUTPUT_CNT 0x100
+#define QUP_OUT_FIFO_BASE 0x110
+#define QUP_MX_WRITE_CNT 0x150
+#define QUP_MX_INPUT_CNT 0x200
+#define QUP_MX_READ_CNT 0x208
+#define QUP_IN_FIFO_BASE 0x218
+#define QUP_I2C_CLK_CTL 0x400
+#define QUP_I2C_STATUS 0x404
+
+/* QUP States and reset values */
+#define QUP_RESET_STATE 0
+#define QUP_RUN_STATE 1
+#define QUP_PAUSE_STATE 3
+#define QUP_STATE_MASK 3
+
+#define QUP_STATE_VALID BIT(2)
+#define QUP_I2C_MAST_GEN BIT(4)
+
+#define QUP_OPERATIONAL_RESET 0x000ff0
+#define QUP_I2C_STATUS_RESET 0xfffffc
+
+/* QUP OPERATIONAL FLAGS */
+#define QUP_I2C_NACK_FLAG BIT(3)
+#define QUP_OUT_NOT_EMPTY BIT(4)
+#define QUP_IN_NOT_EMPTY BIT(5)
+#define QUP_OUT_FULL BIT(6)
+#define QUP_OUT_SVC_FLAG BIT(8)
+#define QUP_IN_SVC_FLAG BIT(9)
+#define QUP_MX_OUTPUT_DONE BIT(10)
+#define QUP_MX_INPUT_DONE BIT(11)
+
+/* I2C mini core related values */
+#define QUP_CLOCK_AUTO_GATE BIT(13)
+#define I2C_MINI_CORE (2 << 8)
+#define I2C_N_VAL 15
+/* Most significant word offset in FIFO port */
+#define QUP_MSW_SHIFT (I2C_N_VAL + 1)
+
+/* Packing/Unpacking words in FIFOs, and IO modes */
+#define QUP_OUTPUT_BLK_MODE (1 << 10)
+#define QUP_INPUT_BLK_MODE (1 << 12)
+#define QUP_UNPACK_EN BIT(14)
+#define QUP_PACK_EN BIT(15)
+
+#define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN)
+
+#define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
+#define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07)
+#define QUP_INPUT_BLOCK_SIZE(x) (((x) >> 5) & 0x03)
+#define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07)
+
+/* QUP tags */
+#define QUP_TAG_START (1 << 8)
+#define QUP_TAG_DATA (2 << 8)
+#define QUP_TAG_STOP (3 << 8)
+#define QUP_TAG_REC (4 << 8)
+
+/* Status, Error flags */
+#define I2C_STATUS_WR_BUFFER_FULL BIT(0)
+#define I2C_STATUS_BUS_ACTIVE BIT(8)
+#define I2C_STATUS_ERROR_MASK 0x38000fc
+#define QUP_STATUS_ERROR_FLAGS 0x7c
+
+#define QUP_READ_LIMIT 256
+
+struct qup_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ struct clk *pclk;
+ struct i2c_adapter adap;
+
+ int clk_ctl;
+ int out_fifo_sz;
+ int in_fifo_sz;
+ int out_blk_sz;
+ int in_blk_sz;
+
+ unsigned long one_byte_t;
+
+ struct i2c_msg *msg;
+ /* Current posion in user message buffer */
+ int pos;
+ /* I2C protocol errors */
+ u32 bus_err;
+ /* QUP core errors */
+ u32 qup_err;
+
+ struct completion xfer;
+};
+
+static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
+{
+ struct qup_i2c_dev *qup = dev;
+ u32 bus_err;
+ u32 qup_err;
+ u32 opflags;
+
+ bus_err = readl(qup->base + QUP_I2C_STATUS);
+ qup_err = readl(qup->base + QUP_ERROR_FLAGS);
+ opflags = readl(qup->base + QUP_OPERATIONAL);
+
+ if (!qup->msg) {
+ /* Clear Error interrupt */
+ writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+ return IRQ_HANDLED;
+ }
+
+ bus_err &= I2C_STATUS_ERROR_MASK;
+ qup_err &= QUP_STATUS_ERROR_FLAGS;
+
+ if (qup_err) {
+ /* Clear Error interrupt */
+ writel(qup_err, qup->base + QUP_ERROR_FLAGS);
+ goto done;
+ }
+
+ if (bus_err) {
+ /* Clear Error interrupt */
+ writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+ goto done;
+ }
+
+ if (opflags & QUP_IN_SVC_FLAG)
+ writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+ if (opflags & QUP_OUT_SVC_FLAG)
+ writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+done:
+ qup->qup_err = qup_err;
+ qup->bus_err = bus_err;
+ complete(&qup->xfer);
+ return IRQ_HANDLED;
+}
+
+static int qup_i2c_poll_state_mask(struct qup_i2c_dev *qup,
+ u32 req_state, u32 req_mask)
+{
+ int retries = 1;
+ u32 state;
+
+ /*
+ * State transition takes 3 AHB clocks cycles + 3 I2C master clock
+ * cycles. So retry once after a 1uS delay.
+ */
+ do {
+ state = readl(qup->base + QUP_STATE);
+
+ if (state & QUP_STATE_VALID &&
+ (state & req_mask) == req_state)
+ return 0;
+
+ udelay(1);
+ } while (retries--);
+
+ return -ETIMEDOUT;
+}
+
+static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
+{
+ return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
+}
+
+static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
+{
+ return qup_i2c_poll_state_mask(qup, 0, 0);
+}
+
+static int qup_i2c_poll_state_i2c_master(struct qup_i2c_dev *qup)
+{
+ return qup_i2c_poll_state_mask(qup, QUP_I2C_MAST_GEN, QUP_I2C_MAST_GEN);
+}
+
+static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
+{
+ if (qup_i2c_poll_state_valid(qup) != 0)
+ return -EIO;
+
+ writel(state, qup->base + QUP_STATE);
+
+ if (qup_i2c_poll_state(qup, state) != 0)
+ return -EIO;
+ return 0;
+}
+
+static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
+{
+ unsigned long timeout;
+ u32 opflags;
+ u32 status;
+
+ timeout = jiffies + HZ;
+
+ for (;;) {
+ opflags = readl(qup->base + QUP_OPERATIONAL);
+ status = readl(qup->base + QUP_I2C_STATUS);
+
+ if (!(opflags & QUP_OUT_NOT_EMPTY) &&
+ !(status & I2C_STATUS_BUS_ACTIVE))
+ return 0;
+
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
+ }
+}
+
+static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ /* Number of entries to shift out, including the start */
+ int total = msg->len + 1;
+
+ if (total < qup->out_fifo_sz) {
+ /* FIFO mode */
+ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
+ writel(total, qup->base + QUP_MX_WRITE_CNT);
+ } else {
+ /* BLOCK mode (transfer data on chunks) */
+ writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
+ qup->base + QUP_IO_MODE);
+ writel(total, qup->base + QUP_MX_OUTPUT_CNT);
+ }
+}
+
+static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ u32 addr = msg->addr << 1;
+ u32 qup_tag;
+ u32 opflags;
+ int idx;
+ u32 val;
+
+ if (qup->pos == 0) {
+ val = QUP_TAG_START | addr;
+ idx = 1;
+ } else {
+ val = 0;
+ idx = 0;
+ }
+
+ while (qup->pos < msg->len) {
+ /* Check that there's space in the FIFO for our pair */
+ opflags = readl(qup->base + QUP_OPERATIONAL);
+ if (opflags & QUP_OUT_FULL)
+ break;
+
+ if (qup->pos == msg->len - 1)
+ qup_tag = QUP_TAG_STOP;
+ else
+ qup_tag = QUP_TAG_DATA;
+
+ if (idx & 1)
+ val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
+ else
+ val = qup_tag | msg->buf[qup->pos];
+
+ /* Write out the pair and the last odd value */
+ if (idx & 1 || qup->pos == msg->len - 1)
+ writel(val, qup->base + QUP_OUT_FIFO_BASE);
+
+ qup->pos++;
+ idx++;
+ }
+}
+
+static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ unsigned long left;
+ int ret;
+
+ qup->msg = msg;
+ qup->pos = 0;
+
+ enable_irq(qup->irq);
+
+ qup_i2c_set_write_mode(qup, msg);
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+ do {
+ ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+ if (ret)
+ goto err;
+
+ qup_i2c_issue_write(qup, msg);
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ left = wait_for_completion_timeout(&qup->xfer, HZ);
+ if (!left) {
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ if (qup->bus_err || qup->qup_err) {
+ if (qup->bus_err & QUP_I2C_NACK_FLAG)
+ dev_err(qup->dev, "NACK from %x\n", msg->addr);
+ ret = -EIO;
+ goto err;
+ }
+ } while (qup->pos < msg->len);
+
+ /* Wait for the outstanding data in the fifo to drain */
+ ret = qup_i2c_wait_writeready(qup);
+
+err:
+ disable_irq(qup->irq);
+ qup->msg = NULL;
+
+ return ret;
+}
+
+static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
+{
+ if (len < qup->in_fifo_sz) {
+ /* FIFO mode */
+ writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
+ writel(len, qup->base + QUP_MX_READ_CNT);
+ } else {
+ /* BLOCK mode (transfer data on chunks) */
+ writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
+ qup->base + QUP_IO_MODE);
+ writel(len, qup->base + QUP_MX_INPUT_CNT);
+ }
+}
+
+static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ u32 addr, len, val;
+
+ addr = (msg->addr << 1) | 1;
+
+ /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
+ len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
+
+ val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+ writel(val, qup->base + QUP_OUT_FIFO_BASE);
+}
+
+
+static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ u32 opflags;
+ u32 val = 0;
+ int idx;
+
+ for (idx = 0; qup->pos < msg->len; idx++) {
+ if ((idx & 1) == 0) {
+ /* Check that FIFO have data */
+ opflags = readl(qup->base + QUP_OPERATIONAL);
+ if (!(opflags & QUP_IN_NOT_EMPTY))
+ break;
+
+ /* Reading 2 words at time */
+ val = readl(qup->base + QUP_IN_FIFO_BASE);
+
+ msg->buf[qup->pos++] = val & 0xFF;
+ } else {
+ msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
+ }
+ }
+}
+
+static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ unsigned long left;
+ int ret;
+
+ /*
+ * The QUP block will issue a NACK and STOP on the bus when reaching
+ * the end of the read, the length of the read is specified as one byte
+ * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+ */
+ if (msg->len > QUP_READ_LIMIT) {
+ dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
+ QUP_READ_LIMIT);
+ return -EINVAL;
+ }
+
+ qup->msg = msg;
+ qup->pos = 0;
+
+ enable_irq(qup->irq);
+
+ qup_i2c_set_read_mode(qup, msg->len);
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+ ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+ if (ret)
+ goto err;
+
+ qup_i2c_issue_read(qup, msg);
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ do {
+ left = wait_for_completion_timeout(&qup->xfer, HZ);
+ if (!left) {
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ if (qup->bus_err || qup->qup_err) {
+ if (qup->bus_err & QUP_I2C_NACK_FLAG)
+ dev_err(qup->dev, "NACK from %x\n", msg->addr);
+ ret = -EIO;
+ goto err;
+ }
+
+ qup_i2c_read_fifo(qup, msg);
+ } while (qup->pos < msg->len);
+
+err:
+ disable_irq(qup->irq);
+ qup->msg = NULL;
+
+ return ret;
+}
+
+static int qup_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+ int ret, idx;
+
+ ret = pm_runtime_get_sync(qup->dev);
+ if (ret < 0)
+ goto out;
+
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+ if (ret)
+ goto out;
+
+ /* Configure QUP as I2C mini core */
+ writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+
+ for (idx = 0; idx < num; idx++) {
+ if (msgs[idx].len == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (qup_i2c_poll_state_i2c_master(qup)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (msgs[idx].flags & I2C_M_RD)
+ ret = qup_i2c_read_one(qup, &msgs[idx]);
+ else
+ ret = qup_i2c_write_one(qup, &msgs[idx]);
+
+ if (ret)
+ break;
+
+ ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+ if (ret)
+ break;
+ }
+
+ if (ret == 0)
+ ret = num;
+out:
+
+ pm_runtime_mark_last_busy(qup->dev);
+ pm_runtime_put_autosuspend(qup->dev);
+
+ return ret;
+}
+
+static u32 qup_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm qup_i2c_algo = {
+ .master_xfer = qup_i2c_xfer,
+ .functionality = qup_i2c_func,
+};
+
+static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
+{
+ clk_prepare_enable(qup->clk);
+ clk_prepare_enable(qup->pclk);
+}
+
+static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
+{
+ u32 config;
+
+ qup_i2c_change_state(qup, QUP_RESET_STATE);
+ clk_disable_unprepare(qup->clk);
+ config = readl(qup->base + QUP_CONFIG);
+ config |= QUP_CLOCK_AUTO_GATE;
+ writel(config, qup->base + QUP_CONFIG);
+ clk_disable_unprepare(qup->pclk);
+}
+
+static int qup_i2c_probe(struct platform_device *pdev)
+{
+ static const int blk_sizes[] = {4, 16, 32};
+ struct device_node *node = pdev->dev.of_node;
+ struct qup_i2c_dev *qup;
+ unsigned long one_bit_t;
+ struct resource *res;
+ u32 io_mode, hw_ver, size;
+ int ret, fs_div, hs_div;
+ int src_clk_freq;
+ u32 clk_freq = 100000;
+
+ qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
+ if (!qup)
+ return -ENOMEM;
+
+ qup->dev = &pdev->dev;
+ init_completion(&qup->xfer);
+ platform_set_drvdata(pdev, qup);
+
+ of_property_read_u32(node, "clock-frequency", &clk_freq);
+
+ /* We support frequencies up to FAST Mode (400KHz) */
+ if (!clk_freq || clk_freq > 400000) {
+ dev_err(qup->dev, "clock frequency not supported %d\n",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qup->base = devm_ioremap_resource(qup->dev, res);
+ if (IS_ERR(qup->base))
+ return PTR_ERR(qup->base);
+
+ qup->irq = platform_get_irq(pdev, 0);
+ if (qup->irq < 0) {
+ dev_err(qup->dev, "No IRQ defined\n");
+ return qup->irq;
+ }
+
+ qup->clk = devm_clk_get(qup->dev, "core");
+ if (IS_ERR(qup->clk)) {
+ dev_err(qup->dev, "Could not get core clock\n");
+ return PTR_ERR(qup->clk);
+ }
+
+ qup->pclk = devm_clk_get(qup->dev, "iface");
+ if (IS_ERR(qup->pclk)) {
+ dev_err(qup->dev, "Could not get iface clock\n");
+ return PTR_ERR(qup->pclk);
+ }
+
+ qup_i2c_enable_clocks(qup);
+
+ /*
+ * Bootloaders might leave a pending interrupt on certain QUP's,
+ * so we reset the core before registering for interrupts.
+ */
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = qup_i2c_poll_state_valid(qup);
+ if (ret)
+ goto fail;
+
+ ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt,
+ IRQF_TRIGGER_HIGH, "i2c_qup", qup);
+ if (ret) {
+ dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq);
+ goto fail;
+ }
+ disable_irq(qup->irq);
+
+ hw_ver = readl(qup->base + QUP_HW_VERSION);
+ dev_dbg(qup->dev, "Revision %x\n", hw_ver);
+
+ io_mode = readl(qup->base + QUP_IO_MODE);
+
+ /*
+ * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
+ * associated with each byte written/received
+ */
+ size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
+ if (size >= ARRAY_SIZE(blk_sizes))
+ return -EIO;
+ qup->out_blk_sz = blk_sizes[size] / 2;
+
+ size = QUP_INPUT_BLOCK_SIZE(io_mode);
+ if (size >= ARRAY_SIZE(blk_sizes))
+ return -EIO;
+ qup->in_blk_sz = blk_sizes[size] / 2;
+
+ size = QUP_OUTPUT_FIFO_SIZE(io_mode);
+ qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
+
+ size = QUP_INPUT_FIFO_SIZE(io_mode);
+ qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
+
+ src_clk_freq = clk_get_rate(qup->clk);
+ fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+ hs_div = 3;
+ qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
+
+ /*
+ * Time it takes for a byte to be clocked out on the bus.
+ * Each byte takes 9 clock cycles (8 bits + 1 ack).
+ */
+ one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
+ qup->one_byte_t = one_bit_t * 9;
+
+ dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+ qup->in_blk_sz, qup->in_fifo_sz,
+ qup->out_blk_sz, qup->out_fifo_sz);
+
+ i2c_set_adapdata(&qup->adap, qup);
+ qup->adap.algo = &qup_i2c_algo;
+ qup->adap.dev.parent = qup->dev;
+ qup->adap.dev.of_node = pdev->dev.of_node;
+ strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
+
+ ret = i2c_add_adapter(&qup->adap);
+ if (ret)
+ goto fail;
+
+ pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(qup->dev);
+ pm_runtime_set_active(qup->dev);
+ pm_runtime_enable(qup->dev);
+ return 0;
+
+fail:
+ qup_i2c_disable_clocks(qup);
+ return ret;
+}
+
+static int qup_i2c_remove(struct platform_device *pdev)
+{
+ struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
+
+ disable_irq(qup->irq);
+ qup_i2c_disable_clocks(qup);
+ i2c_del_adapter(&qup->adap);
+ pm_runtime_disable(qup->dev);
+ pm_runtime_set_suspended(qup->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int qup_i2c_pm_suspend_runtime(struct device *device)
+{
+ struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+ dev_dbg(device, "pm_runtime: suspending...\n");
+ qup_i2c_disable_clocks(qup);
+ return 0;
+}
+
+static int qup_i2c_pm_resume_runtime(struct device *device)
+{
+ struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+ dev_dbg(device, "pm_runtime: resuming...\n");
+ qup_i2c_enable_clocks(qup);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int qup_i2c_suspend(struct device *device)
+{
+ qup_i2c_pm_suspend_runtime(device);
+ return 0;
+}
+
+static int qup_i2c_resume(struct device *device)
+{
+ qup_i2c_pm_resume_runtime(device);
+ pm_runtime_mark_last_busy(device);
+ pm_request_autosuspend(device);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ qup_i2c_suspend,
+ qup_i2c_resume)
+ SET_RUNTIME_PM_OPS(
+ qup_i2c_pm_suspend_runtime,
+ qup_i2c_pm_resume_runtime,
+ NULL)
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+ { .compatible = "qcom,i2c-qup-v1.1.1" },
+ { .compatible = "qcom,i2c-qup-v2.1.1" },
+ { .compatible = "qcom,i2c-qup-v2.2.1" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
+static struct platform_driver qup_i2c_driver = {
+ .probe = qup_i2c_probe,
+ .remove = qup_i2c_remove,
+ .driver = {
+ .name = "i2c_qup",
+ .owner = THIS_MODULE,
+ .pm = &qup_i2c_qup_pm_ops,
+ .of_match_table = qup_i2c_dt_match,
+ },
+};
+
+module_platform_driver(qup_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c_qup");
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 0282d4d4280..89940592367 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -1,7 +1,9 @@
/*
- * drivers/i2c/busses/i2c-rcar.c
+ * Driver for the Renesas RCar I2C unit
*
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com>
+ *
+ * Copyright (C) 2012-14 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This file is based on the drivers/i2c/busses/i2c-sh7760.c
@@ -12,16 +14,12 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
+ * the Free Software Foundation; version 2 of the License.
*
* 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/clk.h>
#include <linux/delay.h>
@@ -36,7 +34,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
/* register offsets */
#define ICSCR 0x00 /* slave ctrl */
@@ -60,7 +57,7 @@
#define FSB (1 << 1) /* force stop bit */
#define ESG (1 << 0) /* en startbit gen */
-/* ICMSR */
+/* ICMSR (also for ICMIE) */
#define MNR (1 << 6) /* nack received */
#define MAL (1 << 5) /* arbitration lost */
#define MST (1 << 4) /* sent a stop */
@@ -69,32 +66,18 @@
#define MDR (1 << 1)
#define MAT (1 << 0) /* slave addr xfer done */
-/* ICMIE */
-#define MNRE (1 << 6) /* nack irq en */
-#define MALE (1 << 5) /* arblos irq en */
-#define MSTE (1 << 4) /* stop irq en */
-#define MDEE (1 << 3)
-#define MDTE (1 << 2)
-#define MDRE (1 << 1)
-#define MATE (1 << 0) /* address sent irq en */
+#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
+#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
+#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
-enum {
- RCAR_BUS_PHASE_ADDR,
- RCAR_BUS_PHASE_DATA,
- RCAR_BUS_PHASE_STOP,
-};
+#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
+#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR)
+#define RCAR_IRQ_STOP (MST)
-enum {
- RCAR_IRQ_CLOSE,
- RCAR_IRQ_OPEN_FOR_SEND,
- RCAR_IRQ_OPEN_FOR_RECV,
- RCAR_IRQ_OPEN_FOR_STOP,
-};
+#define RCAR_IRQ_ACK_SEND (~(MAT | MDE))
+#define RCAR_IRQ_ACK_RECV (~(MAT | MDR))
-/*
- * flags
- */
#define ID_LAST_MSG (1 << 0)
#define ID_IOERROR (1 << 1)
#define ID_DONE (1 << 2)
@@ -112,14 +95,12 @@ struct rcar_i2c_priv {
struct i2c_msg *msg;
struct clk *clk;
- spinlock_t lock;
wait_queue_head_t wait;
int pos;
- int irq;
u32 icccr;
u32 flags;
- enum rcar_i2c_type devtype;
+ enum rcar_i2c_type devtype;
};
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@@ -130,9 +111,7 @@ struct rcar_i2c_priv {
#define LOOP_TIMEOUT 1024
-/*
- * basic functions
- */
+
static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
{
writel(val, priv->io + reg);
@@ -161,36 +140,6 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMAR, 0);
}
-static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open)
-{
- u32 val = MNRE | MALE | MSTE | MATE; /* default */
-
- switch (open) {
- case RCAR_IRQ_OPEN_FOR_SEND:
- val |= MDEE; /* default + send */
- break;
- case RCAR_IRQ_OPEN_FOR_RECV:
- val |= MDRE; /* default + read */
- break;
- case RCAR_IRQ_OPEN_FOR_STOP:
- val = MSTE; /* stop irq only */
- break;
- case RCAR_IRQ_CLOSE:
- default:
- val = 0; /* all close */
- break;
- }
- rcar_i2c_write(priv, ICMIER, val);
-}
-
-static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv)
-{
- rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv);
-}
-
-/*
- * bus control functions
- */
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{
int i;
@@ -205,24 +154,6 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
return -EBUSY;
}
-static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase)
-{
- switch (phase) {
- case RCAR_BUS_PHASE_ADDR:
- rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG);
- break;
- case RCAR_BUS_PHASE_DATA:
- rcar_i2c_write(priv, ICMCR, MDBS | MIE);
- break;
- case RCAR_BUS_PHASE_STOP:
- rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB);
- break;
- }
-}
-
-/*
- * clock function
- */
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
u32 bus_speed,
struct device *dev)
@@ -312,60 +243,18 @@ scgd_find:
return 0;
}
-static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv)
+static int rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
{
- rcar_i2c_write(priv, ICCCR, priv->icccr);
-}
+ int read = !!rcar_i2c_is_recv(priv);
-/*
- * status functions
- */
-static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv)
-{
- return rcar_i2c_read(priv, ICMSR);
-}
-
-#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff)
-static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit)
-{
- rcar_i2c_write(priv, ICMSR, ~bit);
-}
-
-/*
- * recv/send functions
- */
-static int rcar_i2c_recv(struct rcar_i2c_priv *priv)
-{
- rcar_i2c_set_addr(priv, 1);
- rcar_i2c_status_clear(priv);
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
- rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV);
-
- return 0;
-}
-
-static int rcar_i2c_send(struct rcar_i2c_priv *priv)
-{
- int ret;
-
- /*
- * It should check bus status when send case
- */
- ret = rcar_i2c_bus_barrier(priv);
- if (ret < 0)
- return ret;
-
- rcar_i2c_set_addr(priv, 0);
- rcar_i2c_status_clear(priv);
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
- rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND);
+ rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
+ rcar_i2c_write(priv, ICMSR, 0);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
return 0;
}
-#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE))
-#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR))
-
/*
* interrupt functions
*/
@@ -386,7 +275,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
* goto data phase.
*/
if (msr & MAT)
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
if (priv->pos < msg->len) {
/*
@@ -414,7 +303,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
* prepare stop condition here.
* ID_DONE will be set on STOP irq.
*/
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
else
/*
* If current msg is _NOT_ last msg,
@@ -425,7 +314,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
return ID_DONE;
}
- rcar_i2c_send_restart(priv);
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
return 0;
}
@@ -462,11 +351,11 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
* otherwise, go to DATA phase.
*/
if (priv->pos + 1 >= msg->len)
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
else
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
- rcar_i2c_recv_restart(priv);
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
return 0;
}
@@ -474,53 +363,31 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
{
struct rcar_i2c_priv *priv = ptr;
- struct device *dev = rcar_i2c_priv_to_dev(priv);
u32 msr;
- /*-------------- spin lock -----------------*/
- spin_lock(&priv->lock);
+ msr = rcar_i2c_read(priv, ICMSR);
- msr = rcar_i2c_status_get(priv);
-
- /*
- * Arbitration lost
- */
+ /* Arbitration lost */
if (msr & MAL) {
- /*
- * CAUTION
- *
- * When arbitration lost, device become _slave_ mode.
- */
- dev_dbg(dev, "Arbitration Lost\n");
rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
goto out;
}
- /*
- * Stop
- */
+ /* Stop */
if (msr & MST) {
- dev_dbg(dev, "Stop\n");
rcar_i2c_flags_set(priv, ID_DONE);
goto out;
}
- /*
- * Nack
- */
+ /* Nack */
if (msr & MNR) {
- dev_dbg(dev, "Nack\n");
-
/* go to stop phase */
- rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
- rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
+ rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
rcar_i2c_flags_set(priv, ID_NACK);
goto out;
}
- /*
- * recv/send
- */
if (rcar_i2c_is_recv(priv))
rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
else
@@ -528,14 +395,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
out:
if (rcar_i2c_flags_has(priv, ID_DONE)) {
- rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE);
- rcar_i2c_status_clear(priv);
+ rcar_i2c_write(priv, ICMIER, 0);
+ rcar_i2c_write(priv, ICMSR, 0);
wake_up(&priv->wait);
}
- spin_unlock(&priv->lock);
- /*-------------- spin unlock -----------------*/
-
return IRQ_HANDLED;
}
@@ -545,24 +409,24 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
struct device *dev = rcar_i2c_priv_to_dev(priv);
- unsigned long flags;
int i, ret, timeout;
pm_runtime_get_sync(dev);
- /*-------------- spin lock -----------------*/
- spin_lock_irqsave(&priv->lock, flags);
-
rcar_i2c_init(priv);
- rcar_i2c_clock_start(priv);
+ /* start clock */
+ rcar_i2c_write(priv, ICCCR, priv->icccr);
- spin_unlock_irqrestore(&priv->lock, flags);
- /*-------------- spin unlock -----------------*/
+ ret = rcar_i2c_bus_barrier(priv);
+ if (ret < 0)
+ goto out;
- ret = -EINVAL;
for (i = 0; i < num; i++) {
- /*-------------- spin lock -----------------*/
- spin_lock_irqsave(&priv->lock, flags);
+ /* This HW can't send STOP after address phase */
+ if (msgs[i].len == 0) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
/* init each data */
priv->msg = &msgs[i];
@@ -571,21 +435,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
if (priv->msg == &msgs[num - 1])
rcar_i2c_flags_set(priv, ID_LAST_MSG);
- /* start send/recv */
- if (rcar_i2c_is_recv(priv))
- ret = rcar_i2c_recv(priv);
- else
- ret = rcar_i2c_send(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- /*-------------- spin unlock -----------------*/
+ ret = rcar_i2c_prepare_msg(priv);
if (ret < 0)
break;
- /*
- * wait result
- */
timeout = wait_event_timeout(priv->wait,
rcar_i2c_flags_has(priv, ID_DONE),
5 * HZ);
@@ -594,9 +448,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
break;
}
- /*
- * error handling
- */
if (rcar_i2c_flags_has(priv, ID_NACK)) {
ret = -ENXIO;
break;
@@ -614,7 +465,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
ret = i + 1; /* The number of transfer */
}
-
+out:
pm_runtime_put(dev);
if (ret < 0 && ret != -ENXIO)
@@ -625,7 +476,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
static u32 rcar_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ /* This HW can't do SMBUS_QUICK and NOSTART */
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}
static const struct i2c_algorithm rcar_i2c_algo = {
@@ -638,6 +490,10 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@@ -650,13 +506,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
u32 bus_speed;
- int ret;
+ int irq, ret;
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "no mem for private data\n");
+ if (!priv)
return -ENOMEM;
- }
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
@@ -684,24 +538,23 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
- priv->irq = platform_get_irq(pdev, 0);
+ irq = platform_get_irq(pdev, 0);
init_waitqueue_head(&priv->wait);
- spin_lock_init(&priv->lock);
adap = &priv->adap;
adap->nr = pdev->id;
adap->algo = &rcar_i2c_algo;
- adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
adap->retries = 3;
adap->dev.parent = dev;
adap->dev.of_node = dev->of_node;
i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name));
- ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0,
+ ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0,
dev_name(dev), priv);
if (ret < 0) {
- dev_err(dev, "cannot get irq %d\n", priv->irq);
+ dev_err(dev, "cannot get irq %d\n", irq);
return ret;
}
@@ -751,6 +604,6 @@ static struct platform_driver rcar_i2c_driver = {
module_platform_driver(rcar_i2c_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index 9e1f8bacfb3..af3b3d032a9 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -404,7 +404,7 @@ static int riic_i2c_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id riic_i2c_dt_ids[] = {
+static const struct of_device_id riic_i2c_dt_ids[] = {
{ .compatible = "renesas,riic-rz" },
{ /* Sentinel */ },
};
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
new file mode 100644
index 00000000000..a9791509966
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -0,0 +1,763 @@
+/*
+ * Driver for I2C adapter in Rockchip RK3xxx SoC
+ *
+ * Max Schwarz <max.schwarz@online.de>
+ * based on the patches by Rockchip Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+
+/* Register Map */
+#define REG_CON 0x00 /* control register */
+#define REG_CLKDIV 0x04 /* clock divisor register */
+#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */
+#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */
+#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */
+#define REG_MRXCNT 0x14 /* number of bytes to be received */
+#define REG_IEN 0x18 /* interrupt enable */
+#define REG_IPD 0x1c /* interrupt pending */
+#define REG_FCNT 0x20 /* finished count */
+
+/* Data buffer offsets */
+#define TXBUFFER_BASE 0x100
+#define RXBUFFER_BASE 0x200
+
+/* REG_CON bits */
+#define REG_CON_EN BIT(0)
+enum {
+ REG_CON_MOD_TX = 0, /* transmit data */
+ REG_CON_MOD_REGISTER_TX, /* select register and restart */
+ REG_CON_MOD_RX, /* receive data */
+ REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes
+ * register addr */
+};
+#define REG_CON_MOD(mod) ((mod) << 1)
+#define REG_CON_MOD_MASK (BIT(1) | BIT(2))
+#define REG_CON_START BIT(3)
+#define REG_CON_STOP BIT(4)
+#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */
+#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */
+
+/* REG_MRXADDR bits */
+#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
+
+/* REG_IEN/REG_IPD bits */
+#define REG_INT_BTF BIT(0) /* a byte was transmitted */
+#define REG_INT_BRF BIT(1) /* a byte was received */
+#define REG_INT_MBTF BIT(2) /* master data transmit finished */
+#define REG_INT_MBRF BIT(3) /* master data receive finished */
+#define REG_INT_START BIT(4) /* START condition generated */
+#define REG_INT_STOP BIT(5) /* STOP condition generated */
+#define REG_INT_NAKRCV BIT(6) /* NACK received */
+#define REG_INT_ALL 0x7f
+
+/* Constants */
+#define WAIT_TIMEOUT 200 /* ms */
+#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
+
+enum rk3x_i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE,
+ STATE_STOP
+};
+
+/**
+ * @grf_offset: offset inside the grf regmap for setting the i2c type
+ */
+struct rk3x_i2c_soc_data {
+ int grf_offset;
+};
+
+struct rk3x_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ struct rk3x_i2c_soc_data *soc_data;
+
+ /* Hardware resources */
+ void __iomem *regs;
+ struct clk *clk;
+
+ /* Settings */
+ unsigned int scl_frequency;
+
+ /* Synchronization & notification */
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ bool busy;
+
+ /* Current message */
+ struct i2c_msg *msg;
+ u8 addr;
+ unsigned int mode;
+ bool is_last_msg;
+
+ /* I2C state machine */
+ enum rk3x_i2c_state state;
+ unsigned int processed; /* sent/received bytes */
+ int error;
+};
+
+static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value,
+ unsigned int offset)
+{
+ writel(value, i2c->regs + offset);
+}
+
+static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
+{
+ return readl(i2c->regs + offset);
+}
+
+/* Reset all interrupt pending bits */
+static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
+{
+ i2c_writel(i2c, REG_INT_ALL, REG_IPD);
+}
+
+/**
+ * Generate a START condition, which triggers a REG_INT_START interrupt.
+ */
+static void rk3x_i2c_start(struct rk3x_i2c *i2c)
+{
+ u32 val;
+
+ rk3x_i2c_clean_ipd(i2c);
+ i2c_writel(i2c, REG_INT_START, REG_IEN);
+
+ /* enable adapter with correct mode, send START condition */
+ val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+
+ /* if we want to react to NACK, set ACTACK bit */
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+ val |= REG_CON_ACTACK;
+
+ i2c_writel(i2c, val, REG_CON);
+}
+
+/**
+ * Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
+ *
+ * @error: Error code to return in rk3x_i2c_xfer
+ */
+static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
+{
+ unsigned int ctrl;
+
+ i2c->processed = 0;
+ i2c->msg = NULL;
+ i2c->error = error;
+
+ if (i2c->is_last_msg) {
+ /* Enable stop interrupt */
+ i2c_writel(i2c, REG_INT_STOP, REG_IEN);
+
+ i2c->state = STATE_STOP;
+
+ ctrl = i2c_readl(i2c, REG_CON);
+ ctrl |= REG_CON_STOP;
+ i2c_writel(i2c, ctrl, REG_CON);
+ } else {
+ /* Signal rk3x_i2c_xfer to start the next message. */
+ i2c->busy = false;
+ i2c->state = STATE_IDLE;
+
+ /*
+ * The HW is actually not capable of REPEATED START. But we can
+ * get the intended effect by resetting its internal state
+ * and issuing an ordinary START.
+ */
+ i2c_writel(i2c, 0, REG_CON);
+
+ /* signal that we are finished with the current msg */
+ wake_up(&i2c->wait);
+ }
+}
+
+/**
+ * Setup a read according to i2c->msg
+ */
+static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
+{
+ unsigned int len = i2c->msg->len - i2c->processed;
+ u32 con;
+
+ con = i2c_readl(i2c, REG_CON);
+
+ /*
+ * The hw can read up to 32 bytes at a time. If we need more than one
+ * chunk, send an ACK after the last byte of the current chunk.
+ */
+ if (unlikely(len > 32)) {
+ len = 32;
+ con &= ~REG_CON_LASTACK;
+ } else {
+ con |= REG_CON_LASTACK;
+ }
+
+ /* make sure we are in plain RX mode if we read a second chunk */
+ if (i2c->processed != 0) {
+ con &= ~REG_CON_MOD_MASK;
+ con |= REG_CON_MOD(REG_CON_MOD_RX);
+ }
+
+ i2c_writel(i2c, con, REG_CON);
+ i2c_writel(i2c, len, REG_MRXCNT);
+}
+
+/**
+ * Fill the transmit buffer with data from i2c->msg
+ */
+static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
+{
+ unsigned int i, j;
+ u32 cnt = 0;
+ u32 val;
+ u8 byte;
+
+ for (i = 0; i < 8; ++i) {
+ val = 0;
+ for (j = 0; j < 4; ++j) {
+ if (i2c->processed == i2c->msg->len)
+ break;
+
+ if (i2c->processed == 0 && cnt == 0)
+ byte = (i2c->addr & 0x7f) << 1;
+ else
+ byte = i2c->msg->buf[i2c->processed++];
+
+ val |= byte << (j * 8);
+ cnt++;
+ }
+
+ i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i);
+
+ if (i2c->processed == i2c->msg->len)
+ break;
+ }
+
+ i2c_writel(i2c, cnt, REG_MTXCNT);
+}
+
+
+/* IRQ handlers for individual states */
+
+static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ if (!(ipd & REG_INT_START)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_START, REG_IPD);
+
+ /* disable start bit */
+ i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON);
+
+ /* enable appropriate interrupts and transition */
+ if (i2c->mode == REG_CON_MOD_TX) {
+ i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN);
+ i2c->state = STATE_WRITE;
+ rk3x_i2c_fill_transmit_buf(i2c);
+ } else {
+ /* in any other case, we are going to be reading. */
+ i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN);
+ i2c->state = STATE_READ;
+ rk3x_i2c_prepare_read(i2c);
+ }
+}
+
+static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ if (!(ipd & REG_INT_MBTF)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_MBTF, REG_IPD);
+
+ /* are we finished? */
+ if (i2c->processed == i2c->msg->len)
+ rk3x_i2c_stop(i2c, i2c->error);
+ else
+ rk3x_i2c_fill_transmit_buf(i2c);
+}
+
+static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ unsigned int i;
+ unsigned int len = i2c->msg->len - i2c->processed;
+ u32 uninitialized_var(val);
+ u8 byte;
+
+ /* we only care for MBRF here. */
+ if (!(ipd & REG_INT_MBRF))
+ return;
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_MBRF, REG_IPD);
+
+ /* read the data from receive buffer */
+ for (i = 0; i < len; ++i) {
+ if (i % 4 == 0)
+ val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4);
+
+ byte = (val >> ((i % 4) * 8)) & 0xff;
+ i2c->msg->buf[i2c->processed++] = byte;
+ }
+
+ /* are we finished? */
+ if (i2c->processed == i2c->msg->len)
+ rk3x_i2c_stop(i2c, i2c->error);
+ else
+ rk3x_i2c_prepare_read(i2c);
+}
+
+static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ unsigned int con;
+
+ if (!(ipd & REG_INT_STOP)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_STOP, REG_IPD);
+
+ /* disable STOP bit */
+ con = i2c_readl(i2c, REG_CON);
+ con &= ~REG_CON_STOP;
+ i2c_writel(i2c, con, REG_CON);
+
+ i2c->busy = false;
+ i2c->state = STATE_IDLE;
+
+ /* signal rk3x_i2c_xfer that we are finished */
+ wake_up(&i2c->wait);
+}
+
+static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
+{
+ struct rk3x_i2c *i2c = dev_id;
+ unsigned int ipd;
+
+ spin_lock(&i2c->lock);
+
+ ipd = i2c_readl(i2c, REG_IPD);
+ if (i2c->state == STATE_IDLE) {
+ dev_warn(i2c->dev, "irq in STATE_IDLE, ipd = 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ goto out;
+ }
+
+ dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd);
+
+ /* Clean interrupt bits we don't care about */
+ ipd &= ~(REG_INT_BRF | REG_INT_BTF);
+
+ if (ipd & REG_INT_NAKRCV) {
+ /*
+ * We got a NACK in the last operation. Depending on whether
+ * IGNORE_NAK is set, we have to stop the operation and report
+ * an error.
+ */
+ i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD);
+
+ ipd &= ~REG_INT_NAKRCV;
+
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+ rk3x_i2c_stop(i2c, -ENXIO);
+ }
+
+ /* is there anything left to handle? */
+ if (unlikely(ipd == 0))
+ goto out;
+
+ switch (i2c->state) {
+ case STATE_START:
+ rk3x_i2c_handle_start(i2c, ipd);
+ break;
+ case STATE_WRITE:
+ rk3x_i2c_handle_write(i2c, ipd);
+ break;
+ case STATE_READ:
+ rk3x_i2c_handle_read(i2c, ipd);
+ break;
+ case STATE_STOP:
+ rk3x_i2c_handle_stop(i2c, ipd);
+ break;
+ case STATE_IDLE:
+ break;
+ }
+
+out:
+ spin_unlock(&i2c->lock);
+ return IRQ_HANDLED;
+}
+
+static void rk3x_i2c_set_scl_rate(struct rk3x_i2c *i2c, unsigned long scl_rate)
+{
+ unsigned long i2c_rate = clk_get_rate(i2c->clk);
+ unsigned int div;
+
+ /* SCL rate = (clk rate) / (8 * DIV) */
+ div = DIV_ROUND_UP(i2c_rate, scl_rate * 8);
+
+ /* The lower and upper half of the CLKDIV reg describe the length of
+ * SCL low & high periods. */
+ div = DIV_ROUND_UP(div, 2);
+
+ i2c_writel(i2c, (div << 16) | (div & 0xffff), REG_CLKDIV);
+}
+
+/**
+ * Setup I2C registers for an I2C operation specified by msgs, num.
+ *
+ * Must be called with i2c->lock held.
+ *
+ * @msgs: I2C msgs to process
+ * @num: Number of msgs
+ *
+ * returns: Number of I2C msgs processed or negative in case of error
+ */
+static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+ u32 addr = (msgs[0].addr & 0x7f) << 1;
+ int ret = 0;
+
+ /*
+ * The I2C adapter can issue a small (len < 4) write packet before
+ * reading. This speeds up SMBus-style register reads.
+ * The MRXADDR/MRXRADDR hold the slave address and the slave register
+ * address in this case.
+ */
+
+ if (num >= 2 && msgs[0].len < 4 &&
+ !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+ u32 reg_addr = 0;
+ int i;
+
+ dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n",
+ addr >> 1);
+
+ /* Fill MRXRADDR with the register address(es) */
+ for (i = 0; i < msgs[0].len; ++i) {
+ reg_addr |= msgs[0].buf[i] << (i * 8);
+ reg_addr |= REG_MRXADDR_VALID(i);
+ }
+
+ /* msgs[0] is handled by hw. */
+ i2c->msg = &msgs[1];
+
+ i2c->mode = REG_CON_MOD_REGISTER_TX;
+
+ i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR);
+ i2c_writel(i2c, reg_addr, REG_MRXRADDR);
+
+ ret = 2;
+ } else {
+ /*
+ * We'll have to do it the boring way and process the msgs
+ * one-by-one.
+ */
+
+ if (msgs[0].flags & I2C_M_RD) {
+ addr |= 1; /* set read bit */
+
+ /*
+ * We have to transmit the slave addr first. Use
+ * MOD_REGISTER_TX for that purpose.
+ */
+ i2c->mode = REG_CON_MOD_REGISTER_TX;
+ i2c_writel(i2c, addr | REG_MRXADDR_VALID(0),
+ REG_MRXADDR);
+ i2c_writel(i2c, 0, REG_MRXRADDR);
+ } else {
+ i2c->mode = REG_CON_MOD_TX;
+ }
+
+ i2c->msg = &msgs[0];
+
+ ret = 1;
+ }
+
+ i2c->addr = msgs[0].addr;
+ i2c->busy = true;
+ i2c->state = STATE_START;
+ i2c->processed = 0;
+ i2c->error = 0;
+
+ rk3x_i2c_clean_ipd(i2c);
+
+ return ret;
+}
+
+static int rk3x_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
+ unsigned long timeout, flags;
+ int ret = 0;
+ int i;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ clk_enable(i2c->clk);
+
+ /* The clock rate might have changed, so setup the divider again */
+ rk3x_i2c_set_scl_rate(i2c, i2c->scl_frequency);
+
+ i2c->is_last_msg = false;
+
+ /*
+ * Process msgs. We can handle more than one message at once (see
+ * rk3x_i2c_setup()).
+ */
+ for (i = 0; i < num; i += ret) {
+ ret = rk3x_i2c_setup(i2c, msgs + i, num - i);
+
+ if (ret < 0) {
+ dev_err(i2c->dev, "rk3x_i2c_setup() failed\n");
+ break;
+ }
+
+ if (i + ret >= num)
+ i2c->is_last_msg = true;
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ rk3x_i2c_start(i2c);
+
+ timeout = wait_event_timeout(i2c->wait, !i2c->busy,
+ msecs_to_jiffies(WAIT_TIMEOUT));
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (timeout == 0) {
+ dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n",
+ i2c_readl(i2c, REG_IPD), i2c->state);
+
+ /* Force a STOP condition without interrupt */
+ i2c_writel(i2c, 0, REG_IEN);
+ i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+
+ i2c->state = STATE_IDLE;
+
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ if (i2c->error) {
+ ret = i2c->error;
+ break;
+ }
+ }
+
+ clk_disable(i2c->clk);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ return ret;
+}
+
+static u32 rk3x_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm rk3x_i2c_algorithm = {
+ .master_xfer = rk3x_i2c_xfer,
+ .functionality = rk3x_i2c_func,
+};
+
+static struct rk3x_i2c_soc_data soc_data[3] = {
+ { .grf_offset = 0x154 }, /* rk3066 */
+ { .grf_offset = 0x0a4 }, /* rk3188 */
+ { .grf_offset = -1 }, /* no I2C switching needed */
+};
+
+static const struct of_device_id rk3x_i2c_match[] = {
+ { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
+ { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
+ { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+ {},
+};
+
+static int rk3x_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ struct rk3x_i2c *i2c;
+ struct resource *mem;
+ int ret = 0;
+ int bus_nr;
+ u32 value;
+ int irq;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ match = of_match_node(rk3x_i2c_match, np);
+ i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->scl_frequency)) {
+ dev_info(&pdev->dev, "using default SCL frequency: %d\n",
+ DEFAULT_SCL_RATE);
+ i2c->scl_frequency = DEFAULT_SCL_RATE;
+ }
+
+ if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) {
+ dev_warn(&pdev->dev, "invalid SCL frequency specified.\n");
+ dev_warn(&pdev->dev, "using default SCL frequency: %d\n",
+ DEFAULT_SCL_RATE);
+ i2c->scl_frequency = DEFAULT_SCL_RATE;
+ }
+
+ strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &rk3x_i2c_algorithm;
+ i2c->adap.retries = 3;
+ i2c->adap.dev.of_node = np;
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ i2c->dev = &pdev->dev;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ return PTR_ERR(i2c->clk);
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ /* Try to set the I2C adapter number from dt */
+ bus_nr = of_alias_get_id(np, "i2c");
+
+ /*
+ * Switch to new interface if the SoC also offers the old one.
+ * The control bit is located in the GRF register space.
+ */
+ if (i2c->soc_data->grf_offset >= 0) {
+ struct regmap *grf;
+
+ grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ dev_err(&pdev->dev,
+ "rk3x-i2c needs 'rockchip,grf' property\n");
+ return PTR_ERR(grf);
+ }
+
+ if (bus_nr < 0) {
+ dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias");
+ return -EINVAL;
+ }
+
+ /* 27+i: write mask, 11+i: value */
+ value = BIT(27 + bus_nr) | BIT(11 + bus_nr);
+
+ ret = regmap_write(grf, i2c->soc_data->grf_offset, value);
+ if (ret != 0) {
+ dev_err(i2c->dev, "Could not write to GRF: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* IRQ setup */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot find rk3x IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq,
+ 0, dev_name(&pdev->dev), i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot request IRQ\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ ret = clk_prepare(i2c->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not prepare clock\n");
+ return ret;
+ }
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register adapter\n");
+ goto err_clk;
+ }
+
+ dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs);
+
+ return 0;
+
+err_clk:
+ clk_unprepare(i2c->clk);
+ return ret;
+}
+
+static int rk3x_i2c_remove(struct platform_device *pdev)
+{
+ struct rk3x_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static struct platform_driver rk3x_i2c_driver = {
+ .probe = rk3x_i2c_probe,
+ .remove = rk3x_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rk3x-i2c",
+ .of_match_table = rk3x_i2c_match,
+ },
+};
+
+module_platform_driver(rk3x_i2c_driver);
+
+MODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver");
+MODULE_AUTHOR("Max Schwarz <max.schwarz@online.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 684d21e71e4..e828a1dba0e 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * Disable the bus so that we won't get any interrupts from now on, or try
+ * to drive any lines. This is the default state when we don't have
+ * anything to send/receive.
+ *
+ * If there is an event on the bus, or we have a pre-existing event at
+ * kernel boot time, we may not notice the event and the I2C controller
+ * will lock the bus with the I2C clock line low indefinitely.
+ */
+static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ /* Stop driving the I2C pins */
+ tmp = readl(i2c->regs + S3C2410_IICSTAT);
+ tmp &= ~S3C2410_IICSTAT_TXRXEN;
+ writel(tmp, i2c->regs + S3C2410_IICSTAT);
+
+ /* We don't expect any interrupts now, and don't want send acks */
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND |
+ S3C2410_IICCON_ACKEN);
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+}
+
/* s3c24xx_i2c_set_master
*
@@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
s3c24xx_i2c_wait_idle(i2c);
+ s3c24xx_i2c_disable_bus(i2c);
+
out:
+ i2c->state = STATE_IDLE;
+
return ret;
}
@@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
- unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
struct s3c2410_platform_i2c *pdata;
unsigned int freq;
@@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
- writel(iicon, i2c->regs + S3C2410_IICCON);
+ writel(0, i2c->regs + S3C2410_IICCON);
+ writel(0, i2c->regs + S3C2410_IICSTAT);
/* we need to work out the divisors for the clock... */
if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
- writel(0, i2c->regs + S3C2410_IICCON);
dev_err(i2c->dev, "cannot meet bus frequency required\n");
return -EINVAL;
}
@@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* todo - check that the i2c lines aren't being dragged anywhere */
dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
- dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+ dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
+ readl(i2c->regs + S3C2410_IICCON));
return 0;
}
@@ -1085,16 +1114,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
}
i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state\n");
+ if (!i2c)
return -ENOMEM;
- }
i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!i2c->pdata) {
- dev_err(&pdev->dev, "no memory for platform data\n");
+ if (!i2c->pdata)
return -ENOMEM;
- }
i2c->quirks = s3c24xx_get_device_quirks(pdev);
if (pdata)
@@ -1106,7 +1131,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm;
i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
i2c->tx_setup = 50;
init_waitqueue_head(&i2c->wait);
@@ -1247,10 +1272,10 @@ static int s3c24xx_i2c_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
- i2c->suspended = 0;
clk_prepare_enable(i2c->clk);
s3c24xx_i2c_init(i2c);
clk_disable_unprepare(i2c->clk);
+ i2c->suspended = 0;
return 0;
}
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 1d79585ba4b..8b5e79cb446 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -32,6 +32,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <linux/i2c/i2c-sh_mobile.h>
/* Transmit operation: */
@@ -139,6 +140,10 @@ struct sh_mobile_i2c_data {
bool send_stop;
};
+struct sh_mobile_dt_config {
+ int clks_per_count;
+};
+
#define IIC_FLAG_HAS_ICIC67 (1 << 0)
#define STANDARD_MODE 100000
@@ -194,7 +199,7 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
}
-static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int offset)
+static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf)
{
/*
* Conditional expression:
@@ -206,10 +211,10 @@ static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int off
* account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety.
*/
- return (((count_khz * (tLOW + tf)) + 5000) / 10000) + offset;
+ return (((count_khz * (tLOW + tf)) + 5000) / 10000);
}
-static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset)
+static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf)
{
/*
* Conditional expression:
@@ -225,52 +230,58 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int of
* to take into account the fall time of SDA signal (tf) at START
* condition, in order to meet both tHIGH and tHD;STA specs.
*/
- return (((count_khz * (tHIGH + tf)) + 5000) / 10000) + offset;
+ return (((count_khz * (tHIGH + tf)) + 5000) / 10000);
}
-static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
+static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
{
unsigned long i2c_clk_khz;
u32 tHIGH, tLOW, tf;
- int offset;
+ uint16_t max_val;
/* Get clock rate after clock is enabled */
clk_prepare_enable(pd->clk);
i2c_clk_khz = clk_get_rate(pd->clk) / 1000;
+ clk_disable_unprepare(pd->clk);
i2c_clk_khz /= pd->clks_per_count;
if (pd->bus_speed == STANDARD_MODE) {
tLOW = 47; /* tLOW = 4.7 us */
tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
tf = 3; /* tf = 0.3 us */
- offset = 0; /* No offset */
} else if (pd->bus_speed == FAST_MODE) {
tLOW = 13; /* tLOW = 1.3 us */
tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
tf = 3; /* tf = 0.3 us */
- offset = 0; /* No offset */
} else {
dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
pd->bus_speed);
- goto out;
+ return -EINVAL;
+ }
+
+ pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
+ pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
+
+ max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
+ if (pd->iccl > max_val || pd->icch > max_val) {
+ dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
+ pd->iccl, pd->icch);
+ return -EINVAL;
}
- pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset);
/* one more bit of ICCL in ICIC */
- if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67))
+ if (pd->iccl & 0x100)
pd->icic |= ICIC_ICCLB8;
else
pd->icic &= ~ICIC_ICCLB8;
- pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset);
/* one more bit of ICCH in ICIC */
- if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67))
+ if (pd->icch & 0x100)
pd->icic |= ICIC_ICCHB8;
else
pd->icic &= ~ICIC_ICCHB8;
-out:
- clk_disable_unprepare(pd->clk);
+ return 0;
}
static void activate_ch(struct sh_mobile_i2c_data *pd)
@@ -316,7 +327,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
switch (op) {
case OP_START: /* issue start and trigger DTE interrupt */
- iic_wr(pd, ICCR, 0x94);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break;
case OP_TX_FIRST: /* disable DTE interrupt and write data */
iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
@@ -327,10 +338,11 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
break;
case OP_TX_STOP: /* write data and issue a stop afterwards */
iic_wr(pd, ICDR, data);
- iic_wr(pd, ICCR, pd->send_stop ? 0x90 : 0x94);
+ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
+ : ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break;
case OP_TX_TO_RX: /* select read mode */
- iic_wr(pd, ICCR, 0x81);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
break;
case OP_RX: /* just read data */
ret = iic_rd(pd, ICDR);
@@ -338,13 +350,13 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
case OP_RX_STOP: /* enable DTE interrupt, issue stop */
iic_wr(pd, ICIC,
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
- iic_wr(pd, ICCR, 0xc0);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
break;
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
iic_wr(pd, ICIC,
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
ret = iic_rd(pd, ICDR);
- iic_wr(pd, ICCR, 0xc0);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
break;
}
@@ -479,7 +491,7 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
{
if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
dev_err(pd->dev, "Unsupported zero length i2c read\n");
- return -EIO;
+ return -EOPNOTSUPP;
}
if (do_init) {
@@ -514,17 +526,12 @@ static int poll_dte(struct sh_mobile_i2c_data *pd)
break;
if (val & ICSR_TACK)
- return -EIO;
+ return -ENXIO;
udelay(10);
}
- if (!i) {
- dev_warn(pd->dev, "Timeout polling for DTE!\n");
- return -ETIMEDOUT;
- }
-
- return 0;
+ return i ? 0 : -ETIMEDOUT;
}
static int poll_busy(struct sh_mobile_i2c_data *pd)
@@ -542,20 +549,18 @@ static int poll_busy(struct sh_mobile_i2c_data *pd)
*/
if (!(val & ICSR_BUSY)) {
/* handle missing acknowledge and arbitration lost */
- if ((val | pd->sr) & (ICSR_TACK | ICSR_AL))
- return -EIO;
+ val |= pd->sr;
+ if (val & ICSR_TACK)
+ return -ENXIO;
+ if (val & ICSR_AL)
+ return -EAGAIN;
break;
}
udelay(10);
}
- if (!i) {
- dev_err(pd->dev, "Polling timed out\n");
- return -ETIMEDOUT;
- }
-
- return 0;
+ return i ? 0 : -ETIMEDOUT;
}
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
@@ -617,42 +622,44 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = {
.master_xfer = sh_mobile_i2c_xfer,
};
-static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
+static const struct sh_mobile_dt_config default_dt_config = {
+ .clks_per_count = 1,
+};
+
+static const struct sh_mobile_dt_config rcar_gen2_dt_config = {
+ .clks_per_count = 2,
+};
+
+static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
+ { .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
+ { .compatible = "renesas,iic-r8a7790", .data = &rcar_gen2_dt_config },
+ { .compatible = "renesas,iic-r8a7791", .data = &rcar_gen2_dt_config },
+ { .compatible = "renesas,iic-r8a7792", .data = &rcar_gen2_dt_config },
+ { .compatible = "renesas,iic-r8a7793", .data = &rcar_gen2_dt_config },
+ { .compatible = "renesas,iic-r8a7794", .data = &rcar_gen2_dt_config },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids);
+
+static int sh_mobile_i2c_hook_irqs(struct platform_device *dev)
{
struct resource *res;
- int ret = -ENXIO;
- int n, k = 0;
+ resource_size_t n;
+ int k = 0, ret;
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
- for (n = res->start; hook && n <= res->end; n++) {
- if (request_irq(n, sh_mobile_i2c_isr, 0,
- dev_name(&dev->dev), dev)) {
- for (n--; n >= res->start; n--)
- free_irq(n, dev);
-
- goto rollback;
+ for (n = res->start; n <= res->end; n++) {
+ ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr,
+ 0, dev_name(&dev->dev), dev);
+ if (ret) {
+ dev_err(&dev->dev, "cannot request IRQ %pa\n", &n);
+ return ret;
}
}
k++;
}
- if (hook)
- return k > 0 ? 0 : -ENOENT;
-
- ret = 0;
-
- rollback:
- k--;
-
- while (k >= 0) {
- res = platform_get_resource(dev, IORESOURCE_IRQ, k);
- for (n = res->start; n <= res->end; n++)
- free_irq(n, dev);
-
- k--;
- }
-
- return ret;
+ return k > 0 ? 0 : -ENOENT;
}
static int sh_mobile_i2c_probe(struct platform_device *dev)
@@ -661,62 +668,64 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
struct sh_mobile_i2c_data *pd;
struct i2c_adapter *adap;
struct resource *res;
- int size;
int ret;
+ u32 bus_speed;
- pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
- if (pd == NULL) {
- dev_err(&dev->dev, "cannot allocate private data\n");
+ pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
+ if (!pd)
return -ENOMEM;
- }
- pd->clk = clk_get(&dev->dev, NULL);
+ pd->clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(pd->clk)) {
dev_err(&dev->dev, "cannot get clock\n");
- ret = PTR_ERR(pd->clk);
- goto err;
+ return PTR_ERR(pd->clk);
}
- ret = sh_mobile_i2c_hook_irqs(dev, 1);
- if (ret) {
- dev_err(&dev->dev, "cannot request IRQ\n");
- goto err_clk;
- }
+ ret = sh_mobile_i2c_hook_irqs(dev);
+ if (ret)
+ return ret;
pd->dev = &dev->dev;
platform_set_drvdata(dev, pd);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&dev->dev, "cannot find IO resource\n");
- ret = -ENOENT;
- goto err_irq;
- }
-
- size = resource_size(res);
- pd->reg = ioremap(res->start, size);
- if (pd->reg == NULL) {
- dev_err(&dev->dev, "cannot map IO\n");
- ret = -ENXIO;
- goto err_irq;
- }
+ pd->reg = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(pd->reg))
+ return PTR_ERR(pd->reg);
/* Use platform data bus speed or STANDARD_MODE */
- pd->bus_speed = STANDARD_MODE;
- if (pdata && pdata->bus_speed)
- pd->bus_speed = pdata->bus_speed;
+ ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
+ pd->bus_speed = ret ? STANDARD_MODE : bus_speed;
+
pd->clks_per_count = 1;
- if (pdata && pdata->clks_per_count)
- pd->clks_per_count = pdata->clks_per_count;
+
+ if (dev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev);
+ if (match) {
+ const struct sh_mobile_dt_config *config;
+
+ config = match->data;
+ pd->clks_per_count = config->clks_per_count;
+ }
+ } else {
+ if (pdata && pdata->bus_speed)
+ pd->bus_speed = pdata->bus_speed;
+ if (pdata && pdata->clks_per_count)
+ pd->clks_per_count = pdata->clks_per_count;
+ }
/* The IIC blocks on SH-Mobile ARM processors
* come with two new bits in ICIC.
*/
- if (size > 0x17)
+ if (resource_size(res) > 0x17)
pd->flags |= IIC_FLAG_HAS_ICIC67;
- sh_mobile_i2c_init(pd);
+ ret = sh_mobile_i2c_init(pd);
+ if (ret)
+ return ret;
/* Enable Runtime PM for this device.
*
@@ -750,24 +759,14 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
ret = i2c_add_numbered_adapter(adap);
if (ret < 0) {
dev_err(&dev->dev, "cannot add numbered adapter\n");
- goto err_all;
+ return ret;
}
dev_info(&dev->dev,
- "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n",
+ "I2C adapter %d with bus speed %lu Hz (L/H=0x%x/0x%x)\n",
adap->nr, pd->bus_speed, pd->iccl, pd->icch);
return 0;
-
- err_all:
- iounmap(pd->reg);
- err_irq:
- sh_mobile_i2c_hook_irqs(dev, 0);
- err_clk:
- clk_put(pd->clk);
- err:
- kfree(pd);
- return ret;
}
static int sh_mobile_i2c_remove(struct platform_device *dev)
@@ -775,11 +774,7 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
i2c_del_adapter(&pd->adap);
- iounmap(pd->reg);
- sh_mobile_i2c_hook_irqs(dev, 0);
- clk_put(pd->clk);
pm_runtime_disable(&dev->dev);
- kfree(pd);
return 0;
}
@@ -800,12 +795,6 @@ static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
.runtime_resume = sh_mobile_i2c_runtime_nop,
};
-static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
- { .compatible = "renesas,rmobile-iic", },
- {},
-};
-MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids);
-
static struct platform_driver sh_mobile_i2c_driver = {
.driver = {
.name = "i2c-sh_mobile",
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
index 294c80f21d6..964e5c6f84a 100644
--- a/drivers/i2c/busses/i2c-simtec.c
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -77,10 +77,8 @@ static int simtec_i2c_probe(struct platform_device *dev)
int ret;
pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
- if (pd == NULL) {
- dev_err(&dev->dev, "cannot allocate private data\n");
+ if (pd == NULL)
return -ENOMEM;
- }
platform_set_drvdata(dev, pd);
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 6784f7f527a..a3216defc1d 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -307,12 +307,11 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
if (!siic) {
- dev_err(&pdev->dev, "Can't allocate driver data\n");
err = -ENOMEM;
goto out;
}
adap = &siic->adapter;
- adap->class = I2C_CLASS_HWMON;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 79fd96a0438..ac9bc33acef 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
.algo = &smbus_algorithm,
};
-static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
+static const struct pci_device_id sis5595_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 19b8505d0cd..c6366733008 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -510,7 +510,7 @@ static struct i2c_adapter sis630_adapter = {
.retries = 3
};
-static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
+static const struct pci_device_id sis630_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index f8aa0c29f02..8dc2fc5f74f 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -244,7 +244,7 @@ static struct i2c_adapter sis96x_adapter = {
.algo = &smbus_algorithm,
};
-static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
+static const struct pci_device_id sis96x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 9cf715d6955..95b94767038 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -574,7 +574,7 @@ static irqreturn_t st_i2c_isr_thread(int irq, void *data)
writel_relaxed(it, i2c_dev->base + SSC_IEN);
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
- c->result = -EIO;
+ c->result = -EAGAIN;
break;
default:
@@ -847,7 +847,7 @@ static int st_i2c_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id st_i2c_match[] = {
+static const struct of_device_id st_i2c_match[] = {
{ .compatible = "st,comms-ssc-i2c", },
{ .compatible = "st,comms-ssc4-i2c", },
{},
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index 5b80ef31084..fefb1c19ec1 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -868,10 +868,8 @@ static int stu300_probe(struct platform_device *pdev)
int ret = 0;
dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL);
- if (!dev) {
- dev_err(&pdev->dev, "could not allocate device struct\n");
+ if (!dev)
return -ENOMEM;
- }
bus_nr = pdev->id;
dev->clk = devm_clk_get(&pdev->dev, NULL);
@@ -911,7 +909,7 @@ static int stu300_probe(struct platform_device *pdev)
adap = &dev->adapter;
adap->owner = THIS_MODULE;
/* DDC class but actually often used for more generic I2C */
- adap->class = I2C_CLASS_DDC;
+ adap->class = I2C_CLASS_DDC | I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
sizeof(adap->name));
adap->nr = bus_nr;
diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c
new file mode 100644
index 00000000000..4d75d475970
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c
@@ -0,0 +1,344 @@
+/*
+ * P2WI (Push-Pull Two Wire Interface) bus driver.
+ *
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * The P2WI controller looks like an SMBus controller which only supports byte
+ * data transfers. But, it differs from standard SMBus protocol on several
+ * aspects:
+ * - it supports only one slave device, and thus drop the address field
+ * - it adds a parity bit every 8bits of data
+ * - only one read access is required to read a byte (instead of a write
+ * followed by a read access in standard SMBus protocol)
+ * - there's no Ack bit after each byte transfer
+ *
+ * This means this bus cannot be used to interface with standard SMBus
+ * devices (the only known device to support this interface is the AXP221
+ * PMIC).
+ *
+ */
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+
+/* P2WI registers */
+#define P2WI_CTRL 0x0
+#define P2WI_CCR 0x4
+#define P2WI_INTE 0x8
+#define P2WI_INTS 0xc
+#define P2WI_DADDR0 0x10
+#define P2WI_DADDR1 0x14
+#define P2WI_DLEN 0x18
+#define P2WI_DATA0 0x1c
+#define P2WI_DATA1 0x20
+#define P2WI_LCR 0x24
+#define P2WI_PMCR 0x28
+
+/* CTRL fields */
+#define P2WI_CTRL_START_TRANS BIT(7)
+#define P2WI_CTRL_ABORT_TRANS BIT(6)
+#define P2WI_CTRL_GLOBAL_INT_ENB BIT(1)
+#define P2WI_CTRL_SOFT_RST BIT(0)
+
+/* CLK CTRL fields */
+#define P2WI_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8)
+#define P2WI_CCR_MAX_CLK_DIV 0xff
+#define P2WI_CCR_CLK_DIV(v) ((v) & P2WI_CCR_MAX_CLK_DIV)
+
+/* STATUS fields */
+#define P2WI_INTS_TRANS_ERR_ID(v) (((v) >> 8) & 0xff)
+#define P2WI_INTS_LOAD_BSY BIT(2)
+#define P2WI_INTS_TRANS_ERR BIT(1)
+#define P2WI_INTS_TRANS_OVER BIT(0)
+
+/* DATA LENGTH fields*/
+#define P2WI_DLEN_READ BIT(4)
+#define P2WI_DLEN_DATA_LENGTH(v) ((v - 1) & 0x7)
+
+/* LINE CTRL fields*/
+#define P2WI_LCR_SCL_STATE BIT(5)
+#define P2WI_LCR_SDA_STATE BIT(4)
+#define P2WI_LCR_SCL_CTL BIT(3)
+#define P2WI_LCR_SCL_CTL_EN BIT(2)
+#define P2WI_LCR_SDA_CTL BIT(1)
+#define P2WI_LCR_SDA_CTL_EN BIT(0)
+
+/* PMU MODE CTRL fields */
+#define P2WI_PMCR_PMU_INIT_SEND BIT(31)
+#define P2WI_PMCR_PMU_INIT_DATA(v) (((v) & 0xff) << 16)
+#define P2WI_PMCR_PMU_MODE_REG(v) (((v) & 0xff) << 8)
+#define P2WI_PMCR_PMU_DEV_ADDR(v) ((v) & 0xff)
+
+#define P2WI_MAX_FREQ 6000000
+
+struct p2wi {
+ struct i2c_adapter adapter;
+ struct completion complete;
+ unsigned int status;
+ void __iomem *regs;
+ struct clk *clk;
+ struct reset_control *rstc;
+ int slave_addr;
+};
+
+static irqreturn_t p2wi_interrupt(int irq, void *dev_id)
+{
+ struct p2wi *p2wi = dev_id;
+ unsigned long status;
+
+ status = readl(p2wi->regs + P2WI_INTS);
+ p2wi->status = status;
+
+ /* Clear interrupts */
+ status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR |
+ P2WI_INTS_TRANS_OVER);
+ writel(status, p2wi->regs + P2WI_INTS);
+
+ complete(&p2wi->complete);
+
+ return IRQ_HANDLED;
+}
+
+static u32 p2wi_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct p2wi *p2wi = i2c_get_adapdata(adap);
+ unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);
+
+ if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) {
+ dev_err(&adap->dev, "invalid P2WI address\n");
+ return -EINVAL;
+ }
+
+ if (!data)
+ return -EINVAL;
+
+ writel(command, p2wi->regs + P2WI_DADDR0);
+
+ if (read_write == I2C_SMBUS_READ)
+ dlen |= P2WI_DLEN_READ;
+ else
+ writel(data->byte, p2wi->regs + P2WI_DATA0);
+
+ writel(dlen, p2wi->regs + P2WI_DLEN);
+
+ if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {
+ dev_err(&adap->dev, "P2WI bus busy\n");
+ return -EBUSY;
+ }
+
+ reinit_completion(&p2wi->complete);
+
+ writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER,
+ p2wi->regs + P2WI_INTE);
+
+ writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB,
+ p2wi->regs + P2WI_CTRL);
+
+ wait_for_completion(&p2wi->complete);
+
+ if (p2wi->status & P2WI_INTS_LOAD_BSY) {
+ dev_err(&adap->dev, "P2WI bus busy\n");
+ return -EBUSY;
+ }
+
+ if (p2wi->status & P2WI_INTS_TRANS_ERR) {
+ dev_err(&adap->dev, "P2WI bus xfer error\n");
+ return -ENXIO;
+ }
+
+ if (read_write == I2C_SMBUS_READ)
+ data->byte = readl(p2wi->regs + P2WI_DATA0);
+
+ return 0;
+}
+
+static const struct i2c_algorithm p2wi_algo = {
+ .smbus_xfer = p2wi_smbus_xfer,
+ .functionality = p2wi_functionality,
+};
+
+static const struct of_device_id p2wi_of_match_table[] = {
+ { .compatible = "allwinner,sun6i-a31-p2wi" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, p2wi_of_match_table);
+
+static int p2wi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *childnp;
+ unsigned long parent_clk_freq;
+ u32 clk_freq = 100000;
+ struct resource *r;
+ struct p2wi *p2wi;
+ u32 slave_addr;
+ int clk_div;
+ int irq;
+ int ret;
+
+ of_property_read_u32(np, "clock-frequency", &clk_freq);
+ if (clk_freq > P2WI_MAX_FREQ) {
+ dev_err(dev,
+ "required clock-frequency (%u Hz) is too high (max = 6MHz)",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ if (of_get_child_count(np) > 1) {
+ dev_err(dev, "P2WI only supports one slave device\n");
+ return -EINVAL;
+ }
+
+ p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);
+ if (!p2wi)
+ return -ENOMEM;
+
+ p2wi->slave_addr = -1;
+
+ /*
+ * Authorize a p2wi node without any children to be able to use an
+ * i2c-dev from userpace.
+ * In this case the slave_addr is set to -1 and won't be checked when
+ * launching a P2WI transfer.
+ */
+ childnp = of_get_next_available_child(np, NULL);
+ 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);
+ return -EINVAL;
+ }
+
+ p2wi->slave_addr = slave_addr;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ p2wi->regs = devm_ioremap_resource(dev, r);
+ if (IS_ERR(p2wi->regs))
+ return PTR_ERR(p2wi->regs);
+
+ strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to retrieve irq: %d\n", irq);
+ return irq;
+ }
+
+ p2wi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(p2wi->clk)) {
+ ret = PTR_ERR(p2wi->clk);
+ dev_err(dev, "failed to retrieve clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(p2wi->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
+ parent_clk_freq = clk_get_rate(p2wi->clk);
+
+ p2wi->rstc = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(p2wi->rstc)) {
+ ret = PTR_ERR(p2wi->rstc);
+ dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ ret = reset_control_deassert(p2wi->rstc);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset line: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ init_completion(&p2wi->complete);
+ p2wi->adapter.dev.parent = dev;
+ p2wi->adapter.algo = &p2wi_algo;
+ p2wi->adapter.owner = THIS_MODULE;
+ p2wi->adapter.dev.of_node = pdev->dev.of_node;
+ platform_set_drvdata(pdev, p2wi);
+ i2c_set_adapdata(&p2wi->adapter, p2wi);
+
+ ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);
+ if (ret) {
+ dev_err(dev, "can't register interrupt handler irq%d: %d\n",
+ irq, ret);
+ goto err_reset_assert;
+ }
+
+ writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL);
+
+ clk_div = parent_clk_freq / clk_freq;
+ if (!clk_div) {
+ dev_warn(dev,
+ "clock-frequency is too high, setting it to %lu Hz\n",
+ parent_clk_freq);
+ clk_div = 1;
+ } else if (clk_div > P2WI_CCR_MAX_CLK_DIV) {
+ dev_warn(dev,
+ "clock-frequency is too low, setting it to %lu Hz\n",
+ parent_clk_freq / P2WI_CCR_MAX_CLK_DIV);
+ clk_div = P2WI_CCR_MAX_CLK_DIV;
+ }
+
+ writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div),
+ p2wi->regs + P2WI_CCR);
+
+ ret = i2c_add_adapter(&p2wi->adapter);
+ if (!ret)
+ return 0;
+
+err_reset_assert:
+ reset_control_assert(p2wi->rstc);
+
+err_clk_disable:
+ clk_disable_unprepare(p2wi->clk);
+
+ return ret;
+}
+
+static int p2wi_remove(struct platform_device *dev)
+{
+ struct p2wi *p2wi = platform_get_drvdata(dev);
+
+ reset_control_assert(p2wi->rstc);
+ clk_disable_unprepare(p2wi->clk);
+ i2c_del_adapter(&p2wi->adapter);
+
+ return 0;
+}
+
+static struct platform_driver p2wi_driver = {
+ .probe = p2wi_probe,
+ .remove = p2wi_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-sunxi-p2wi",
+ .of_match_table = p2wi_of_match_table,
+ },
+};
+module_platform_driver(p2wi_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner P2WI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 9704537aee3..f1bb2fc0679 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -732,10 +732,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
- if (!i2c_dev) {
- dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
+ if (!i2c_dev)
return -ENOMEM;
- }
i2c_dev->base = base;
i2c_dev->div_clk = div_clk;
@@ -794,7 +792,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
i2c_dev->adapter.owner = THIS_MODULE;
- i2c_dev->adapter.class = I2C_CLASS_HWMON;
+ i2c_dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
sizeof(i2c_dev->adapter.name));
i2c_dev->adapter.algo = &tegra_i2c_algo;
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 49d7f14b9d2..f4a1ed75761 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -88,7 +88,7 @@ static struct i2c_adapter vt586b_adapter = {
};
-static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
+static const struct pci_device_id vt586b_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 40d36df678d..6841200b6e5 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -442,7 +442,7 @@ release_region:
return error;
}
-static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
+static const struct pci_device_id vt596_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
.driver_data = SMBBA1 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 2c8a3e4f900..f80a38c2072 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -379,10 +379,8 @@ static int wmt_i2c_probe(struct platform_device *pdev)
u32 clk_rate;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
- if (!i2c_dev) {
- dev_err(&pdev->dev, "device memory allocation failed\n");
+ if (!i2c_dev)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
@@ -454,7 +452,7 @@ static int wmt_i2c_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id wmt_i2c_dt_ids[] = {
+static const struct of_device_id wmt_i2c_dt_ids[] = {
{ .compatible = "wm,wm8505-i2c" },
{ /* Sentinel */ },
};
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 28107502517..7731f179586 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -684,7 +684,7 @@ static const struct i2c_algorithm xiic_algorithm = {
static struct i2c_adapter xiic_adapter = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
.algo = &xiic_algorithm,
};
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 2d1d2c5653f..ff3f5747e43 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -431,10 +431,8 @@ static struct scx200_acb_iface *scx200_create_iface(const char *text,
struct i2c_adapter *adapter;
iface = kzalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface) {
- pr_err("can't allocate memory\n");
+ if (!iface)
return NULL;
- }
adapter = &iface->adapter;
i2c_set_adapdata(adapter, iface);
@@ -556,7 +554,7 @@ static struct platform_driver scx200_pci_driver = {
.remove = scx200_remove,
};
-static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
+static const struct pci_device_id scx200_isa[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
{ 0, }
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 5fb80b8962a..7c7f4b856ba 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -48,10 +48,13 @@
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
#include <linux/acpi.h>
+#include <linux/jump_label.h>
#include <asm/uaccess.h>
#include "i2c-core.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/i2c.h>
/* core_lock protects i2c_adapter_idr, and guarantees
that device detection, deletion of detected devices, and attach_adapter
@@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr);
static struct device_type i2c_client_type;
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
+static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
+
+void i2c_transfer_trace_reg(void)
+{
+ static_key_slow_inc(&i2c_trace_msg);
+}
+
+void i2c_transfer_trace_unreg(void)
+{
+ static_key_slow_dec(&i2c_trace_msg);
+}
+
/* ------------------------------------------------------------------------- */
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
@@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void)
class_compat_unregister(i2c_adapter_compat_class);
#endif
bus_unregister(&i2c_bus_type);
+ tracepoint_synchronize_unregister();
}
/* We must initialize early, because some subsystems register i2c drivers
@@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
unsigned long orig_jiffies;
int ret, try;
+ /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
+ * enabled. This is an efficient way of keeping the for-loop from
+ * being executed when not needed.
+ */
+ if (static_key_false(&i2c_trace_msg)) {
+ int i;
+ for (i = 0; i < num; i++)
+ if (msgs[i].flags & I2C_M_RD)
+ trace_i2c_read(adap, &msgs[i], i);
+ else
+ trace_i2c_write(adap, &msgs[i], i);
+ }
+
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
@@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
break;
}
+ if (static_key_false(&i2c_trace_msg)) {
+ int i;
+ for (i = 0; i < ret; i++)
+ if (msgs[i].flags & I2C_M_RD)
+ trace_i2c_reply(adap, &msgs[i], i);
+ trace_i2c_result(adap, i, ret);
+ }
+
return ret;
}
EXPORT_SYMBOL(__i2c_transfer);
@@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_client *client;
/* Detection succeeded, instantiate the device */
+ if (adapter->class & I2C_CLASS_DEPRECATED)
+ dev_warn(&adapter->dev,
+ "This adapter will soon drop class based instantiation of devices. "
+ "Please make sure client 0x%02x gets instantiated by other means. "
+ "Check 'Documentation/i2c/instantiating-devices' for details.\n",
+ info.addr);
+
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
info.type, info.addr);
client = i2c_new_device(adapter, &info);
@@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
int try;
s32 res;
+ /* If enabled, the following two tracepoints are conditional on
+ * read_write and protocol.
+ */
+ trace_smbus_write(adapter, addr, flags, read_write,
+ command, protocol, data);
+ trace_smbus_read(adapter, addr, flags, read_write,
+ command, protocol);
+
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) {
@@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
i2c_unlock_adapter(adapter);
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
- return res;
+ goto trace;
/*
* Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
* implement native support for the SMBus operation.
*/
}
- return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
- command, protocol, data);
+ res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
+ command, protocol, data);
+
+trace:
+ /* If enabled, the reply tracepoint is conditional on read_write. */
+ trace_smbus_reply(adapter, addr, flags, read_write,
+ command, protocol, data);
+ trace_smbus_result(adapter, addr, flags, read_write,
+ command, protocol, res);
+
+ return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index f7f9865b8b8..f6d313e528d 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -40,6 +40,7 @@ config I2C_MUX_PCA9541
config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches"
+ depends on GPIOLIB
help
If you say yes here you get support for the Philips PCA954x
I2C mux/switch devices.
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 550bd36aa5d..9bd4212782a 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -36,12 +36,11 @@
*/
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#define PCA954X_MAX_NCHANS 8
@@ -186,7 +185,7 @@ static int pca954x_probe(struct i2c_client *client,
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
- struct device_node *np = client->dev.of_node;
+ struct gpio_desc *gpio;
int num, force, class;
struct pca954x *data;
int ret;
@@ -200,21 +199,10 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
- if (IS_ENABLED(CONFIG_OF) && np) {
- enum of_gpio_flags flags;
- int gpio;
-
- /* Get the mux out of reset if a reset GPIO is specified. */
- gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
- if (gpio_is_valid(gpio)) {
- ret = devm_gpio_request_one(&client->dev, gpio,
- flags & OF_GPIO_ACTIVE_LOW ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
- "pca954x reset");
- if (ret < 0)
- return ret;
- }
- }
+ /* Get the mux out of reset if a reset GPIO is specified. */
+ gpio = devm_gpiod_get(&client->dev, "reset");
+ if (!IS_ERR(gpio))
+ gpiod_direction_output(gpio, 0);
/* Write the mux register at addr to verify
* that the mux is in fact present. This also