summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/busses/Kconfig24
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c9
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c15
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c9
-rw-r--r--drivers/i2c/busses/i2c-hix5hd2.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c3
-rw-r--r--drivers/i2c/busses/i2c-k1.c71
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c28
-rw-r--r--drivers/i2c/busses/i2c-nct6694.c196
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c2
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c2
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c8
-rw-r--r--drivers/i2c/busses/i2c-rtl9300.c459
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1
-rw-r--r--drivers/i2c/busses/i2c-sprd.c2
-rw-r--r--drivers/i2c/busses/i2c-st.c2
-rw-r--r--drivers/i2c/busses/i2c-tegra.c26
-rw-r--r--drivers/i2c/busses/i2c-usbio.c320
-rw-r--r--drivers/i2c/busses/i2c-viperboard.c2
-rw-r--r--drivers/i2c/i2c-boardinfo.c4
-rw-r--r--drivers/i2c/i2c-core-base.c9
-rw-r--r--drivers/i2c/i2c-core-slave.c3
-rw-r--r--drivers/i2c/i2c-mux.c9
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca9541.c12
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c50
27 files changed, 990 insertions, 282 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 74b66aec33d4..ee86df4cff4b 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -30,7 +30,7 @@ static int i2c_debug;
#define pca_clock(adap) adap->i2c_clock
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
-#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_wait(adap) adap->wait_for_completion_cb(adap->data)
static void pca_reset(struct i2c_algo_pca_data *adap)
{
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 070d014fdc5d..fd81e49638aa 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -165,6 +165,7 @@ config I2C_I801
Birch Stream (SOC)
Arrow Lake (SOC)
Panther Lake (SOC)
+ Wildcat Lake (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -414,7 +415,7 @@ config I2C_ASPEED
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 || COMPILE_TEST
+ depends on ARCH_MICROCHIP || COMPILE_TEST
help
This supports the use of the I2C interface on Atmel AT91
processors.
@@ -1357,6 +1358,27 @@ config I2C_LJCA
This driver can also be built as a module. If so, the module
will be called i2c-ljca.
+config I2C_NCT6694
+ tristate "Nuvoton NCT6694 I2C adapter support"
+ depends on MFD_NCT6694
+ help
+ If you say yes to this option, support will be included for Nuvoton
+ NCT6694, a USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-nct6694.
+
+config I2C_USBIO
+ tristate "Intel USBIO I2C Adapter support"
+ depends on USB_USBIO
+ default USB_USBIO
+ help
+ Select this option to enable I2C driver for the INTEL
+ USBIO driver stack.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c_usbio.
+
config I2C_CP2615
tristate "Silicon Labs CP2615 USB sound card and I2C adapter"
depends on USB
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 04db855fdfd6..fb985769f5ff 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -135,6 +135,8 @@ obj-$(CONFIG_I2C_GXP) += i2c-gxp.o
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
obj-$(CONFIG_I2C_LJCA) += i2c-ljca.o
+obj-$(CONFIG_I2C_NCT6694) += i2c-nct6694.o
+obj-$(CONFIG_I2C_USBIO) += i2c-usbio.o
obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PCI1XXXX) += i2c-mchp-pci1xxxx.o
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index cbd88ffa5610..c7a72c28786c 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -1068,11 +1068,10 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
if (!(dev->flags & ACCESS_POLLING)) {
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
irq_flags, dev_name(dev->dev), dev);
- if (ret) {
- dev_err(dev->dev, "failure requesting irq %i: %d\n",
- dev->irq, ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev->dev, ret,
+ "failure requesting irq %i: %d\n",
+ dev->irq, ret);
}
ret = i2c_dw_init_recovery_info(dev);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index a35e4c64a1d4..34d881572351 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -238,7 +238,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->rst = devm_reset_control_get_optional_exclusive(device, NULL);
if (IS_ERR(dev->rst))
- return PTR_ERR(dev->rst);
+ return dev_err_probe(device, PTR_ERR(dev->rst), "failed to acquire reset\n");
reset_control_deassert(dev->rst);
@@ -247,21 +247,23 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
goto exit_reset;
ret = i2c_dw_probe_lock_support(dev);
- if (ret)
+ if (ret) {
+ ret = dev_err_probe(device, ret, "failed to probe lock support\n");
goto exit_reset;
+ }
i2c_dw_configure(dev);
/* Optional interface clock */
dev->pclk = devm_clk_get_optional(device, "pclk");
if (IS_ERR(dev->pclk)) {
- ret = PTR_ERR(dev->pclk);
+ ret = dev_err_probe(device, PTR_ERR(dev->pclk), "failed to acquire pclk\n");
goto exit_reset;
}
dev->clk = devm_clk_get_optional(device, NULL);
if (IS_ERR(dev->clk)) {
- ret = PTR_ERR(dev->clk);
+ ret = dev_err_probe(device, PTR_ERR(dev->clk), "failed to acquire clock\n");
goto exit_reset;
}
@@ -314,6 +316,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
exit_probe:
dw_i2c_plat_pm_cleanup(dev);
+ i2c_dw_prepare_clk(dev, false);
exit_reset:
reset_control_assert(dev->rst);
return ret;
@@ -331,9 +334,11 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
i2c_dw_disable(dev);
pm_runtime_dont_use_autosuspend(device);
- pm_runtime_put_sync(device);
+ pm_runtime_put_noidle(device);
dw_i2c_plat_pm_cleanup(dev);
+ i2c_dw_prepare_clk(dev, false);
+
i2c_dw_remove_lock_support(dev);
reset_control_assert(dev->rst);
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index b936a240db0a..6eb16b7d75a6 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -266,11 +266,10 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
IRQF_SHARED, dev_name(dev->dev), dev);
- if (ret) {
- dev_err(dev->dev, "failure requesting IRQ %i: %d\n",
- dev->irq, ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev->dev, ret,
+ "failure requesting IRQ %i: %d\n",
+ dev->irq, ret);
ret = i2c_add_numbered_adapter(adap);
if (ret)
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
index 370f32974763..5358f5ddf924 100644
--- a/drivers/i2c/busses/i2c-hix5hd2.c
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -339,7 +339,7 @@ static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
ret = priv->state;
/*
- * If this is the last message to be transfered (stop == 1)
+ * If this is the last message to be transferred (stop == 1)
* Then check if the bus can be brought back to idle.
*/
if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop)
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index e94ac746a741..cba992fa6557 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -83,6 +83,7 @@
* Arrow Lake-H (SOC) 0x7722 32 hard yes yes yes
* Panther Lake-H (SOC) 0xe322 32 hard yes yes yes
* Panther Lake-P (SOC) 0xe422 32 hard yes yes yes
+ * Wildcat Lake-U (SOC) 0x4d22 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@@ -236,6 +237,7 @@
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
+#define PCI_DEVICE_ID_INTEL_WILDCAT_LAKE_U_SMBUS 0x4d22
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3
@@ -1056,6 +1058,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
+ { PCI_DEVICE_DATA(INTEL, WILDCAT_LAKE_U_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
index b68a21fff0b5..6b918770e612 100644
--- a/drivers/i2c/busses/i2c-k1.c
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -3,6 +3,7 @@
* Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
@@ -14,6 +15,7 @@
#define SPACEMIT_ICR 0x0 /* Control register */
#define SPACEMIT_ISR 0x4 /* Status register */
#define SPACEMIT_IDBR 0xc /* Data buffer register */
+#define SPACEMIT_IRCR 0x18 /* Reset cycle counter */
#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
/* SPACEMIT_ICR register fields */
@@ -25,7 +27,8 @@
#define SPACEMIT_CR_MODE_FAST BIT(8) /* bus mode (master operation) */
/* Bit 9 is reserved */
#define SPACEMIT_CR_UR BIT(10) /* unit reset */
-/* Bits 11-12 are reserved */
+#define SPACEMIT_CR_RSTREQ BIT(11) /* i2c bus reset request */
+/* Bit 12 is reserved */
#define SPACEMIT_CR_SCLE BIT(13) /* master clock enable */
#define SPACEMIT_CR_IUE BIT(14) /* unit enable */
/* Bits 15-17 are reserved */
@@ -76,6 +79,10 @@
SPACEMIT_SR_GCAD | SPACEMIT_SR_IRF | SPACEMIT_SR_ITE | \
SPACEMIT_SR_ALD)
+#define SPACEMIT_RCR_SDA_GLITCH_NOFIX BIT(7) /* bypass the SDA glitch fix */
+/* the cycles of SCL during bus reset */
+#define SPACEMIT_RCR_FIELD_RST_CYC GENMASK(3, 0)
+
/* SPACEMIT_IBMR register fields */
#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
@@ -88,6 +95,8 @@
#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
+#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9
+
enum spacemit_i2c_state {
SPACEMIT_STATE_IDLE,
SPACEMIT_STATE_START,
@@ -160,6 +169,7 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
{
u32 status;
+ u8 clk_cnt;
/* if bus is locked, reset unit. 0: locked */
status = readl(i2c->base + SPACEMIT_IBMR);
@@ -169,9 +179,21 @@ static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
spacemit_i2c_reset(i2c);
usleep_range(10, 20);
- /* check scl status again */
+ for (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) {
+ status = readl(i2c->base + SPACEMIT_IBMR);
+ if (status & SPACEMIT_BMR_SDA)
+ return;
+
+ /* There's nothing left to save here, we are about to exit */
+ writel(FIELD_PREP(SPACEMIT_RCR_FIELD_RST_CYC, 1),
+ i2c->base + SPACEMIT_IRCR);
+ writel(SPACEMIT_CR_RSTREQ, i2c->base + SPACEMIT_ICR);
+ usleep_range(20, 30);
+ }
+
+ /* check sda again here */
status = readl(i2c->base + SPACEMIT_IBMR);
- if (!(status & SPACEMIT_BMR_SCL))
+ if (!(status & SPACEMIT_BMR_SDA))
dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
}
@@ -237,6 +259,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
writel(val, i2c->base + SPACEMIT_ICR);
+
+ /*
+ * The glitch fix in the K1 I2C controller introduces a delay
+ * on restart signals, so we disable the fix here.
+ */
+ val = readl(i2c->base + SPACEMIT_IRCR);
+ val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX;
+ writel(val, i2c->base + SPACEMIT_IRCR);
}
static inline void
@@ -267,19 +297,6 @@ static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
writel(val, i2c->base + SPACEMIT_ICR);
}
-static void spacemit_i2c_stop(struct spacemit_i2c_dev *i2c)
-{
- u32 val;
-
- val = readl(i2c->base + SPACEMIT_ICR);
- val |= SPACEMIT_CR_STOP | SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
-
- if (i2c->read)
- val |= SPACEMIT_CR_ACKNAK;
-
- writel(val, i2c->base + SPACEMIT_ICR);
-}
-
static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
{
unsigned long time_left;
@@ -412,7 +429,6 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
val = readl(i2c->base + SPACEMIT_ICR);
val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
- writel(val, i2c->base + SPACEMIT_ICR);
switch (i2c->state) {
case SPACEMIT_STATE_START:
@@ -429,14 +445,16 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
}
if (i2c->state != SPACEMIT_STATE_IDLE) {
+ val |= SPACEMIT_CR_TB | SPACEMIT_CR_ALDIE;
+
if (spacemit_i2c_is_last_msg(i2c)) {
/* trigger next byte with stop */
- spacemit_i2c_stop(i2c);
- } else {
- /* trigger next byte */
- val |= SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
- writel(val, i2c->base + SPACEMIT_ICR);
+ val |= SPACEMIT_CR_STOP;
+
+ if (i2c->read)
+ val |= SPACEMIT_CR_ACKNAK;
}
+ writel(val, i2c->base + SPACEMIT_ICR);
}
err_out:
@@ -476,12 +494,13 @@ static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, in
spacemit_i2c_enable(i2c);
ret = spacemit_i2c_wait_bus_idle(i2c);
- if (!ret)
+ if (!ret) {
ret = spacemit_i2c_xfer_msg(i2c);
- else if (ret < 0)
- dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
- else
+ if (ret < 0)
+ dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
+ } else {
spacemit_i2c_check_bus_release(i2c);
+ }
spacemit_i2c_disable(i2c);
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index ab456c3717db..aefdbee1f03c 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -868,7 +868,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
return 0;
}
-static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
+static void mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
{
unsigned int clk_src;
unsigned int step_cnt;
@@ -938,9 +938,6 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
break;
}
-
-
- return 0;
}
static void i2c_dump_register(struct mtk_i2c *i2c)
@@ -1243,6 +1240,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
{
int ret;
int left_num = num;
+ bool write_then_read_en = false;
struct mtk_i2c *i2c = i2c_get_adapdata(adap);
ret = clk_bulk_enable(I2C_MT65XX_CLK_MAX, i2c->clocks);
@@ -1256,6 +1254,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
msgs[0].addr == msgs[1].addr) {
i2c->auto_restart = 0;
+ write_then_read_en = true;
}
}
@@ -1280,12 +1279,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
else
i2c->op = I2C_MASTER_WR;
- if (!i2c->auto_restart) {
- if (num > 1) {
- /* combined two messages into one transaction */
- i2c->op = I2C_MASTER_WRRD;
- left_num--;
- }
+ if (write_then_read_en) {
+ /* combined two messages into one transaction */
+ i2c->op = I2C_MASTER_WRRD;
+ left_num--;
}
/* always use DMA mode. */
@@ -1293,7 +1290,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (ret < 0)
goto err_exit;
- msgs++;
+ if (i2c->op == I2C_MASTER_WRRD)
+ msgs += 2;
+ else
+ msgs++;
}
/* the return value is number of executed messages */
ret = num;
@@ -1457,11 +1457,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
strscpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name));
- ret = mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk));
- if (ret) {
- dev_err(&pdev->dev, "Failed to set the speed.\n");
- return -EINVAL;
- }
+ mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk));
if (i2c->dev_comp->max_dma_support > 32) {
ret = dma_set_mask(&pdev->dev,
diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
new file mode 100644
index 000000000000..1413ab6f9462
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nct6694.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton NCT6694 I2C adapter driver based on USB interface.
+ *
+ * Copyright (C) 2025 Nuvoton Technology Corp.
+ */
+
+#include <linux/i2c.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/mfd/nct6694.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/*
+ * USB command module type for NCT6694 I2C controller.
+ * This defines the module type used for communication with the NCT6694
+ * I2C controller over the USB interface.
+ */
+#define NCT6694_I2C_MOD 0x03
+
+/* Command 00h - I2C Deliver */
+#define NCT6694_I2C_DELIVER 0x00
+#define NCT6694_I2C_DELIVER_SEL 0x00
+
+#define NCT6694_I2C_MAX_XFER_SIZE 64
+#define NCT6694_I2C_MAX_DEVS 6
+
+static unsigned char br_reg[NCT6694_I2C_MAX_DEVS] = {[0 ... (NCT6694_I2C_MAX_DEVS - 1)] = 0xFF};
+
+module_param_array(br_reg, byte, NULL, 0644);
+MODULE_PARM_DESC(br_reg,
+ "I2C Baudrate register per adapter: (0=25K, 1=50K, 2=100K, 3=200K, 4=400K, 5=800K, 6=1M), default=2");
+
+enum nct6694_i2c_baudrate {
+ NCT6694_I2C_BR_25K = 0,
+ NCT6694_I2C_BR_50K,
+ NCT6694_I2C_BR_100K,
+ NCT6694_I2C_BR_200K,
+ NCT6694_I2C_BR_400K,
+ NCT6694_I2C_BR_800K,
+ NCT6694_I2C_BR_1M
+};
+
+struct __packed nct6694_i2c_deliver {
+ u8 port;
+ u8 br;
+ u8 addr;
+ u8 w_cnt;
+ u8 r_cnt;
+ u8 rsv[11];
+ u8 write_data[NCT6694_I2C_MAX_XFER_SIZE];
+ u8 read_data[NCT6694_I2C_MAX_XFER_SIZE];
+};
+
+struct nct6694_i2c_data {
+ struct device *dev;
+ struct nct6694 *nct6694;
+ struct i2c_adapter adapter;
+ struct nct6694_i2c_deliver deliver;
+ unsigned char port;
+ unsigned char br;
+};
+
+static int nct6694_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct nct6694_i2c_data *data = adap->algo_data;
+ struct nct6694_i2c_deliver *deliver = &data->deliver;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_I2C_MOD,
+ .cmd = NCT6694_I2C_DELIVER,
+ .sel = NCT6694_I2C_DELIVER_SEL,
+ .len = cpu_to_le16(sizeof(*deliver))
+ };
+ int ret, i;
+
+ for (i = 0; i < num; i++) {
+ struct i2c_msg *msg_temp = &msgs[i];
+
+ memset(deliver, 0, sizeof(*deliver));
+
+ deliver->port = data->port;
+ deliver->br = data->br;
+ deliver->addr = i2c_8bit_addr_from_msg(msg_temp);
+ if (msg_temp->flags & I2C_M_RD) {
+ deliver->r_cnt = msg_temp->len;
+ ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver);
+ if (ret < 0)
+ return ret;
+
+ memcpy(msg_temp->buf, deliver->read_data, msg_temp->len);
+ } else {
+ deliver->w_cnt = msg_temp->len;
+ memcpy(deliver->write_data, msg_temp->buf, msg_temp->len);
+ ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return num;
+}
+
+static u32 nct6694_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_adapter_quirks nct6694_i2c_quirks = {
+ .max_read_len = NCT6694_I2C_MAX_XFER_SIZE,
+ .max_write_len = NCT6694_I2C_MAX_XFER_SIZE,
+};
+
+static const struct i2c_algorithm nct6694_i2c_algo = {
+ .xfer = nct6694_i2c_xfer,
+ .functionality = nct6694_i2c_func,
+};
+
+static int nct6694_i2c_set_baudrate(struct nct6694_i2c_data *data)
+{
+ if (data->port >= NCT6694_I2C_MAX_DEVS) {
+ dev_err(data->dev, "Invalid I2C port index %d\n", data->port);
+ return -EINVAL;
+ }
+
+ if (br_reg[data->port] > NCT6694_I2C_BR_1M) {
+ dev_warn(data->dev, "Invalid baudrate %d for I2C%d, using 100K\n",
+ br_reg[data->port], data->port);
+ br_reg[data->port] = NCT6694_I2C_BR_100K;
+ }
+
+ data->br = br_reg[data->port];
+
+ return 0;
+}
+
+static void nct6694_i2c_ida_free(void *d)
+{
+ struct nct6694_i2c_data *data = d;
+ struct nct6694 *nct6694 = data->nct6694;
+
+ ida_free(&nct6694->i2c_ida, data->port);
+}
+
+static int nct6694_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct nct6694 *nct6694 = dev_get_drvdata(dev->parent);
+ struct nct6694_i2c_data *data;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = dev;
+ data->nct6694 = nct6694;
+
+ ret = ida_alloc(&nct6694->i2c_ida, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+ data->port = ret;
+
+ ret = devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data);
+ if (ret)
+ return ret;
+
+ ret = nct6694_i2c_set_baudrate(data);
+ if (ret)
+ return ret;
+
+ sprintf(data->adapter.name, "NCT6694 I2C Adapter %d", data->port);
+ data->adapter.owner = THIS_MODULE;
+ data->adapter.algo = &nct6694_i2c_algo;
+ data->adapter.quirks = &nct6694_i2c_quirks;
+ data->adapter.dev.parent = dev;
+ data->adapter.algo_data = data;
+
+ platform_set_drvdata(pdev, data);
+
+ return devm_i2c_add_adapter(dev, &data->adapter);
+}
+
+static struct platform_driver nct6694_i2c_driver = {
+ .driver = {
+ .name = "nct6694-i2c",
+ },
+ .probe = nct6694_i2c_probe,
+};
+
+module_platform_driver(nct6694_i2c_driver);
+
+MODULE_DESCRIPTION("USB-I2C adapter driver for NCT6694");
+MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nct6694-i2c");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 85e8cf58e8bf..0cbf2f509527 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -95,7 +95,7 @@ static struct i2c_algo_pca_data pca_isa_data = {
/* .data intentionally left NULL, not needed with ISA */
.write_byte = pca_isa_writebyte,
.read_byte = pca_isa_readbyte,
- .wait_for_completion = pca_isa_waitforcompletion,
+ .wait_for_completion_cb = pca_isa_waitforcompletion,
.reset_chip = pca_isa_resetchip,
};
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index 87da8241b927..c0f35ebbe37d 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -180,7 +180,7 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
}
i2c->algo_data.data = i2c;
- i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
+ i2c->algo_data.wait_for_completion_cb = i2c_pca_pf_waitforcompletion;
if (i2c->gpio)
i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
else
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index ff2289b52c84..95a577764d5c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -870,7 +870,13 @@ static int geni_i2c_probe(struct platform_device *pdev)
goto err_clk;
}
proto = geni_se_read_proto(&gi2c->se);
- if (proto != GENI_SE_I2C) {
+ if (proto == GENI_SE_INVALID_PROTO) {
+ ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
+ if (ret) {
+ dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret);
+ goto err_resources;
+ }
+ } else if (proto != GENI_SE_I2C) {
ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto);
goto err_resources;
}
diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index af991b28e4f8..4723e48cfe18 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -8,6 +8,7 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/unaligned.h>
enum rtl9300_bus_freq {
RTL9300_I2C_STD_FREQ,
@@ -20,103 +21,143 @@ struct rtl9300_i2c_chan {
struct i2c_adapter adap;
struct rtl9300_i2c *i2c;
enum rtl9300_bus_freq bus_freq;
- u8 sda_pin;
+ u8 sda_num;
+};
+
+enum rtl9300_i2c_reg_scope {
+ REG_SCOPE_GLOBAL,
+ REG_SCOPE_MASTER,
+};
+
+struct rtl9300_i2c_reg_field {
+ struct reg_field field;
+ enum rtl9300_i2c_reg_scope scope;
+};
+
+enum rtl9300_i2c_reg_fields {
+ F_DATA_WIDTH = 0,
+ F_DEV_ADDR,
+ F_I2C_FAIL,
+ F_I2C_TRIG,
+ F_MEM_ADDR,
+ F_MEM_ADDR_WIDTH,
+ F_RD_MODE,
+ F_RWOP,
+ F_SCL_FREQ,
+ F_SCL_SEL,
+ F_SDA_OUT_SEL,
+ F_SDA_SEL,
+
+ /* keep last */
+ F_NUM_FIELDS
+};
+
+struct rtl9300_i2c_drv_data {
+ struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS];
+ int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl);
+ u32 data_reg;
+ u8 max_nchan;
};
#define RTL9300_I2C_MUX_NCHAN 8
+#define RTL9310_I2C_MUX_NCHAN 12
struct rtl9300_i2c {
struct regmap *regmap;
struct device *dev;
- struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN];
+ struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
+ struct regmap_field *fields[F_NUM_FIELDS];
u32 reg_base;
- u8 sda_pin;
+ u32 data_reg;
+ u8 scl_num;
+ u8 sda_num;
struct mutex lock;
};
+DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock))
+
+enum rtl9300_i2c_xfer_type {
+ RTL9300_I2C_XFER_BYTE,
+ RTL9300_I2C_XFER_WORD,
+ RTL9300_I2C_XFER_BLOCK,
+};
+
+struct rtl9300_i2c_xfer {
+ enum rtl9300_i2c_xfer_type type;
+ u16 dev_addr;
+ u8 reg_addr;
+ u8 reg_addr_len;
+ u8 *data;
+ u8 data_len;
+ bool write;
+};
+
#define RTL9300_I2C_MST_CTRL1 0x0
-#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8
-#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8)
-#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4
-#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4)
-#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3)
-#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2)
-#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1)
-#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0)
#define RTL9300_I2C_MST_CTRL2 0x4
-#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15)
-#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8
-#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8)
-#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4
-#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4)
-#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2
-#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2)
-#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0
-#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0)
#define RTL9300_I2C_MST_DATA_WORD0 0x8
#define RTL9300_I2C_MST_DATA_WORD1 0xc
#define RTL9300_I2C_MST_DATA_WORD2 0x10
#define RTL9300_I2C_MST_DATA_WORD3 0x14
-
#define RTL9300_I2C_MST_GLB_CTRL 0x384
+#define RTL9310_I2C_MST_IF_CTRL 0x1004
+#define RTL9310_I2C_MST_IF_SEL 0x1008
+#define RTL9310_I2C_MST_CTRL 0x0
+#define RTL9310_I2C_MST_MEMADDR_CTRL 0x4
+#define RTL9310_I2C_MST_DATA_CTRL 0x8
+
static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
- u32 val, mask;
int ret;
- val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS;
- mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK;
-
- ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
+ ret = regmap_field_write(i2c->fields[F_MEM_ADDR_WIDTH], len);
if (ret)
return ret;
- val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS;
- mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK;
-
- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+ return regmap_field_write(i2c->fields[F_MEM_ADDR], reg);
}
-static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
+static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
{
- int ret;
- u32 val, mask;
-
- ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin));
- if (ret)
- return ret;
-
- val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) |
- RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
- mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
+ return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
+}
- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
+{
+ return regmap_field_update_bits(i2c->fields[F_SCL_SEL], BIT(scl), BIT(scl));
}
-static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
- u16 addr, u16 len)
+static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
{
- u32 val, mask;
+ struct rtl9300_i2c_drv_data *drv_data;
+ int ret;
- if (len < 1 || len > 16)
- return -EINVAL;
+ if (i2c->sda_num == chan->sda_num)
+ return 0;
- val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS;
- mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK;
+ ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
+ if (ret)
+ return ret;
- val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS;
- mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK;
+ drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+ ret = drv_data->select_scl(i2c, i2c->scl_num);
+ if (ret)
+ return ret;
- val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS;
- mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK;
+ ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
+ BIT(chan->sda_num));
+ if (ret)
+ return ret;
- mask |= RTL9300_I2C_MST_CTRL2_RD_MODE;
+ ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
+ if (ret)
+ return ret;
- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
+ i2c->sda_num = chan->sda_num;
+ return 0;
}
-static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
+static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
{
u32 vals[4] = {};
int i, ret;
@@ -124,8 +165,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
if (len > 16)
return -EIO;
- ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
- vals, ARRAY_SIZE(vals));
+ ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
if (ret)
return ret;
@@ -137,7 +177,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
return 0;
}
-static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
+static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
{
u32 vals[4] = {};
int i;
@@ -152,56 +192,94 @@ static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
vals[reg] |= buf[i] << shift;
}
- return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
- vals, ARRAY_SIZE(vals));
+ return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
}
static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
{
- return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data);
+ return regmap_write(i2c->regmap, i2c->data_reg, data);
}
-static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
- int size, union i2c_smbus_data *data, int len)
+static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
{
- u32 val, mask;
int ret;
- val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0;
- mask = RTL9300_I2C_MST_CTRL1_RWOP;
+ if (xfer->data_len < 1 || xfer->data_len > 16)
+ return -EINVAL;
+
+ ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
+ if (ret)
+ return ret;
+
+ ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf);
+ if (ret)
+ return ret;
- val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
- mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
+ if (xfer->write) {
+ switch (xfer->type) {
+ case RTL9300_I2C_XFER_BYTE:
+ ret = rtl9300_i2c_writel(i2c, *xfer->data);
+ break;
+ case RTL9300_I2C_XFER_WORD:
+ ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data));
+ break;
+ default:
+ ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len);
+ break;
+ }
+ }
- ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+ return ret;
+}
+
+static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1);
if (ret)
return ret;
- ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1,
- val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000);
+ ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
if (ret)
return ret;
- if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL)
+ ret = regmap_field_read(i2c->fields[F_I2C_FAIL], &val);
+ if (ret)
+ return ret;
+ if (val)
return -EIO;
- if (read_write == I2C_SMBUS_READ) {
- if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) {
- ret = regmap_read(i2c->regmap,
- i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
+ if (!xfer->write) {
+ switch (xfer->type) {
+ case RTL9300_I2C_XFER_BYTE:
+ ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
if (ret)
return ret;
- data->byte = val & 0xff;
- } else if (size == I2C_SMBUS_WORD_DATA) {
- ret = regmap_read(i2c->regmap,
- i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
+
+ *xfer->data = val & 0xff;
+ break;
+ case RTL9300_I2C_XFER_WORD:
+ ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
if (ret)
return ret;
- data->word = val & 0xffff;
- } else {
- ret = rtl9300_i2c_read(i2c, &data->block[0], len);
+
+ put_unaligned(val & 0xffff, (u16*)xfer->data);
+ break;
+ default:
+ ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len);
if (ret)
return ret;
+ break;
}
}
@@ -214,100 +292,68 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
{
struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
struct rtl9300_i2c *i2c = chan->i2c;
- int len = 0, ret;
+ struct rtl9300_i2c_xfer xfer = {0};
+ int ret;
- mutex_lock(&i2c->lock);
- if (chan->sda_pin != i2c->sda_pin) {
- ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
- if (ret)
- goto out_unlock;
- i2c->sda_pin = chan->sda_pin;
- }
+ if (addr > 0x7f)
+ return -EINVAL;
+
+ guard(rtl9300_i2c)(i2c);
+
+ ret = rtl9300_i2c_config_chan(i2c, chan);
+ if (ret)
+ return ret;
+
+ xfer.dev_addr = addr & 0x7f;
+ xfer.write = (read_write == I2C_SMBUS_WRITE);
+ xfer.reg_addr = command;
+ xfer.reg_addr_len = 1;
switch (size) {
case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_WRITE) {
- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
- if (ret)
- goto out_unlock;
- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
- if (ret)
- goto out_unlock;
- } else {
- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
- if (ret)
- goto out_unlock;
- ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
- if (ret)
- goto out_unlock;
- }
+ xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command;
+ xfer.data_len = 1;
+ xfer.reg_addr = 0;
+ xfer.reg_addr_len = 0;
+ xfer.type = RTL9300_I2C_XFER_BYTE;
break;
-
case I2C_SMBUS_BYTE_DATA:
- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
- if (ret)
- goto out_unlock;
- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
- if (ret)
- goto out_unlock;
- if (read_write == I2C_SMBUS_WRITE) {
- ret = rtl9300_i2c_writel(i2c, data->byte);
- if (ret)
- goto out_unlock;
- }
+ xfer.data = &data->byte;
+ xfer.data_len = 1;
+ xfer.type = RTL9300_I2C_XFER_BYTE;
break;
-
case I2C_SMBUS_WORD_DATA:
- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
- if (ret)
- goto out_unlock;
- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2);
- if (ret)
- goto out_unlock;
- if (read_write == I2C_SMBUS_WRITE) {
- ret = rtl9300_i2c_writel(i2c, data->word);
- if (ret)
- goto out_unlock;
- }
+ xfer.data = (u8 *)&data->word;
+ xfer.data_len = 2;
+ xfer.type = RTL9300_I2C_XFER_WORD;
break;
-
case I2C_SMBUS_BLOCK_DATA:
- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
- if (ret)
- goto out_unlock;
- if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
- ret = -EINVAL;
- goto out_unlock;
- }
- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1);
- if (ret)
- goto out_unlock;
- if (read_write == I2C_SMBUS_WRITE) {
- ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1);
- if (ret)
- goto out_unlock;
- }
- len = data->block[0] + 1;
+ xfer.data = &data->block[0];
+ xfer.data_len = data->block[0] + 1;
+ xfer.type = RTL9300_I2C_XFER_BLOCK;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ xfer.data = &data->block[1];
+ xfer.data_len = data->block[0];
+ xfer.type = RTL9300_I2C_XFER_BLOCK;
break;
-
default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
- ret = -EOPNOTSUPP;
- goto out_unlock;
+ return -EOPNOTSUPP;
}
- ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len);
-
-out_unlock:
- mutex_unlock(&i2c->lock);
+ ret = rtl9300_i2c_prepare_xfer(i2c, &xfer);
+ if (ret)
+ return ret;
- return ret;
+ return rtl9300_i2c_do_xfer(i2c, &xfer);
}
static u32 rtl9300_i2c_func(struct i2c_adapter *a)
{
return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
static const struct i2c_algorithm rtl9300_i2c_algo = {
@@ -325,9 +371,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtl9300_i2c *i2c;
- u32 clock_freq, sda_pin;
- int ret, i = 0;
struct fwnode_handle *child;
+ struct rtl9300_i2c_drv_data *drv_data;
+ struct reg_field fields[F_NUM_FIELDS];
+ u32 clock_freq, scl_num, sda_num;
+ int ret, i = 0;
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
@@ -344,16 +392,34 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = device_property_read_u32(dev, "realtek,scl", &scl_num);
+ if (ret || scl_num != 1)
+ scl_num = 0;
+ i2c->scl_num = (u8)scl_num;
+
platform_set_drvdata(pdev, i2c);
- if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN)
+ drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+ if (device_get_child_node_count(dev) > drv_data->max_nchan)
return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+ i2c->data_reg = i2c->reg_base + drv_data->data_reg;
+ for (i = 0; i < F_NUM_FIELDS; i++) {
+ fields[i] = drv_data->field_desc[i].field;
+ if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER)
+ fields[i].reg += i2c->reg_base;
+ }
+ ret = devm_regmap_field_bulk_alloc(dev, i2c->regmap, i2c->fields,
+ fields, F_NUM_FIELDS);
+ if (ret)
+ return ret;
+
+ i = 0;
device_for_each_child_node(dev, child) {
struct rtl9300_i2c_chan *chan = &i2c->chans[i];
struct i2c_adapter *adap = &chan->adap;
- ret = fwnode_property_read_u32(child, "reg", &sda_pin);
+ ret = fwnode_property_read_u32(child, "reg", &sda_num);
if (ret)
return ret;
@@ -365,17 +431,16 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
case I2C_MAX_STANDARD_MODE_FREQ:
chan->bus_freq = RTL9300_I2C_STD_FREQ;
break;
-
case I2C_MAX_FAST_MODE_FREQ:
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
break;
default:
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
- sda_pin, clock_freq);
+ sda_num, clock_freq);
break;
}
- chan->sda_pin = sda_pin;
+ chan->sda_num = sda_num;
chan->i2c = i2c;
adap = &i2c->chans[i].adap;
adap->owner = THIS_MODULE;
@@ -385,23 +450,77 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
adap->dev.parent = dev;
i2c_set_adapdata(adap, chan);
adap->dev.of_node = to_of_node(child);
- snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin);
+ snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num);
i++;
ret = devm_i2c_add_adapter(dev, adap);
if (ret)
return ret;
}
- i2c->sda_pin = 0xff;
+ i2c->sda_num = 0xff;
+
+ /* only use standard read format */
+ ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
+ if (ret)
+ return ret;
return 0;
}
+#define GLB_REG_FIELD(reg, msb, lsb) \
+ { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_GLOBAL }
+#define MST_REG_FIELD(reg, msb, lsb) \
+ { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_MASTER }
+
+static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = {
+ .field_desc = {
+ [F_MEM_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 8, 31),
+ [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 4, 6),
+ [F_SCL_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 3, 3),
+ [F_RWOP] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 2, 2),
+ [F_I2C_FAIL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 1, 1),
+ [F_I2C_TRIG] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+ [F_RD_MODE] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 15, 15),
+ [F_DEV_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 8, 14),
+ [F_DATA_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 4, 7),
+ [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3),
+ [F_SCL_FREQ] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1),
+ [F_SDA_SEL] = GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7),
+ },
+ .select_scl = rtl9300_i2c_select_scl,
+ .data_reg = RTL9300_I2C_MST_DATA_WORD0,
+ .max_nchan = RTL9300_I2C_MUX_NCHAN,
+};
+
+static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+ .field_desc = {
+ [F_SCL_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 12, 13),
+ [F_SDA_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 0, 11),
+ [F_SCL_FREQ] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 30, 31),
+ [F_DEV_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 11, 17),
+ [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 18, 21),
+ [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 9, 10),
+ [F_DATA_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 5, 8),
+ [F_RD_MODE] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 4, 4),
+ [F_RWOP] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 2, 2),
+ [F_I2C_FAIL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1),
+ [F_I2C_TRIG] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+ [F_MEM_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23),
+ },
+ .select_scl = rtl9310_i2c_select_scl,
+ .data_reg = RTL9310_I2C_MST_DATA_CTRL,
+ .max_nchan = RTL9310_I2C_MUX_NCHAN,
+};
+
static const struct of_device_id i2c_rtl9300_dt_ids[] = {
- { .compatible = "realtek,rtl9301-i2c" },
- { .compatible = "realtek,rtl9302b-i2c" },
- { .compatible = "realtek,rtl9302c-i2c" },
- { .compatible = "realtek,rtl9303-i2c" },
+ { .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+ { .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+ { .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+ { .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+ { .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+ { .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+ { .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+ { .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data },
{}
};
MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index f4fa4703acbd..8138f5ef40f0 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -138,7 +138,6 @@ static void i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
#ifdef CONFIG_OF
static const struct of_device_id s3c24xx_i2c_match[] = {
- { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
{ .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 },
{ .compatible = "samsung,s3c2440-hdmiphy-i2c",
.data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c
index 56b2e5c5fb49..26ec34b19ad5 100644
--- a/drivers/i2c/busses/i2c-sprd.c
+++ b/drivers/i2c/busses/i2c-sprd.c
@@ -425,7 +425,7 @@ static irqreturn_t sprd_i2c_isr(int irq, void *dev_id)
* If we did not get one ACK from target when writing data, then we
* should finish this transmission since we got some errors.
*
- * When writing data, if i2c_tran == 0 which means we have writen
+ * When writing data, if i2c_tran == 0 which means we have written
* done all data, then we can finish this transmission.
*
* When reading data, if conut < rx fifo full threshold, which
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index bf28f8e3ee6b..97d70e667227 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -152,7 +152,7 @@ struct st_i2c_timings {
/**
* struct st_i2c_client - client specific data
* @addr: 8-bit target addr, including r/w bit
- * @count: number of bytes to be transfered
+ * @count: number of bytes to be transferred
* @xfered: number of bytes already transferred
* @buf: data buffer
* @result: result of the transfer
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 4eb31b913c1a..e533460bccc3 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -1649,7 +1649,33 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_interface_timing_reg = true,
};
+static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .clk_divisor_hs_mode = 7,
+ .clk_divisor_std_mode = 0x7a,
+ .clk_divisor_fast_mode = 0x40,
+ .clk_divisor_fast_plus_mode = 0x19,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = true,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = true,
+ .has_mst_reset = true,
+ .quirks = &tegra194_i2c_quirks,
+ .supports_bus_clear = true,
+ .has_apb_dma = false,
+ .tlow_std_mode = 0x8,
+ .thigh_std_mode = 0x7,
+ .tlow_fast_fastplus_mode = 0x3,
+ .thigh_fast_fastplus_mode = 0x3,
+ .setup_hold_time_std_mode = 0x08080808,
+ .setup_hold_time_fast_fast_plus_mode = 0x02020202,
+ .setup_hold_time_hs_mode = 0x090909,
+ .has_interface_timing_reg = true,
+};
+
static const struct of_device_id tegra_i2c_of_match[] = {
+ { .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, },
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
diff --git a/drivers/i2c/busses/i2c-usbio.c b/drivers/i2c/busses/i2c-usbio.c
new file mode 100644
index 000000000000..d42f9ab6e9a5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-usbio.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Intel Corporation.
+ * Copyright (c) 2025 Red Hat, Inc.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/usb/usbio.h>
+
+#define I2C_RW_OVERHEAD (sizeof(struct usbio_bulk_packet) + sizeof(struct usbio_i2c_rw))
+
+struct usbio_i2c {
+ struct i2c_adapter adap;
+ struct auxiliary_device *adev;
+ struct usbio_i2c_rw *rwbuf;
+ unsigned long quirks;
+ u32 speed;
+ u16 txbuf_len;
+ u16 rxbuf_len;
+};
+
+static const struct acpi_device_id usbio_i2c_acpi_hids[] = {
+ { "INTC1008" }, /* MTL */
+ { "INTC10B3" }, /* ARL */
+ { "INTC10B6" }, /* LNL */
+ { "INTC10E3" }, /* PTL */
+ { }
+};
+
+static const u32 usbio_i2c_speeds[] = {
+ I2C_MAX_STANDARD_MODE_FREQ,
+ I2C_MAX_FAST_MODE_FREQ,
+ I2C_MAX_FAST_MODE_PLUS_FREQ,
+ I2C_MAX_HIGH_SPEED_MODE_FREQ
+};
+
+static void usbio_i2c_uninit(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+ struct usbio_i2c *i2c = i2c_get_adapdata(adap);
+ struct usbio_i2c_uninit ubuf;
+
+ ubuf.busid = i2c->adev->id;
+ ubuf.config = cpu_to_le16(msg->addr);
+
+ usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_UNINIT, true,
+ &ubuf, sizeof(ubuf), NULL, 0);
+}
+
+static int usbio_i2c_init(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+ struct usbio_i2c *i2c = i2c_get_adapdata(adap);
+ struct usbio_i2c_init ibuf;
+ void *reply_buf;
+ u16 reply_len;
+ int ret;
+
+ ibuf.busid = i2c->adev->id;
+ ibuf.config = cpu_to_le16(msg->addr);
+ ibuf.speed = cpu_to_le32(i2c->speed);
+
+ if (i2c->quirks & USBIO_QUIRK_I2C_NO_INIT_ACK) {
+ reply_buf = NULL;
+ reply_len = 0;
+ } else {
+ reply_buf = &ibuf;
+ reply_len = sizeof(ibuf);
+ }
+
+ ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_INIT, true,
+ &ibuf, sizeof(ibuf), reply_buf, reply_len);
+ if (ret != sizeof(ibuf))
+ return (ret < 0) ? ret : -EIO;
+
+ return 0;
+}
+
+static int usbio_i2c_read(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+ struct usbio_i2c *i2c = i2c_get_adapdata(adap);
+ u16 rxchunk = i2c->rxbuf_len - I2C_RW_OVERHEAD;
+ struct usbio_i2c_rw *rbuf = i2c->rwbuf;
+ int ret;
+
+ rbuf->busid = i2c->adev->id;
+ rbuf->config = cpu_to_le16(msg->addr);
+ rbuf->size = cpu_to_le16(msg->len);
+
+ if (msg->len > rxchunk) {
+ /* Need to split the input buffer */
+ u16 len = 0;
+
+ do {
+ if (msg->len - len < rxchunk)
+ rxchunk = msg->len - len;
+
+ ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C,
+ USBIO_I2CCMD_READ, true,
+ rbuf, len == 0 ? sizeof(*rbuf) : 0,
+ rbuf, sizeof(*rbuf) + rxchunk);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&msg->buf[len], rbuf->data, rxchunk);
+ len += rxchunk;
+ } while (msg->len > len);
+
+ return 0;
+ }
+
+ ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_READ, true,
+ rbuf, sizeof(*rbuf), rbuf, sizeof(*rbuf) + msg->len);
+ if (ret != sizeof(*rbuf) + msg->len)
+ return (ret < 0) ? ret : -EIO;
+
+ memcpy(msg->buf, rbuf->data, msg->len);
+
+ return 0;
+}
+
+static int usbio_i2c_write(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+ struct usbio_i2c *i2c = i2c_get_adapdata(adap);
+ u16 txchunk = i2c->txbuf_len - I2C_RW_OVERHEAD;
+ struct usbio_i2c_rw *wbuf = i2c->rwbuf;
+ int ret;
+
+ if (msg->len > txchunk) {
+ /* Need to split the output buffer */
+ u16 len = 0;
+
+ do {
+ wbuf->busid = i2c->adev->id;
+ wbuf->config = cpu_to_le16(msg->addr);
+
+ if (i2c->quirks & USBIO_QUIRK_I2C_USE_CHUNK_LEN)
+ wbuf->size = cpu_to_le16(txchunk);
+ else
+ wbuf->size = cpu_to_le16(msg->len);
+
+ memcpy(wbuf->data, &msg->buf[len], txchunk);
+ len += txchunk;
+
+ ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C,
+ USBIO_I2CCMD_WRITE, msg->len == len,
+ wbuf, sizeof(*wbuf) + txchunk,
+ wbuf, sizeof(*wbuf));
+ if (ret < 0)
+ return ret;
+
+ if (msg->len - len < txchunk)
+ txchunk = msg->len - len;
+ } while (msg->len > len);
+
+ return 0;
+ }
+
+ wbuf->busid = i2c->adev->id;
+ wbuf->config = cpu_to_le16(msg->addr);
+ wbuf->size = cpu_to_le16(msg->len);
+ memcpy(wbuf->data, msg->buf, msg->len);
+
+ ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_WRITE, true,
+ wbuf, sizeof(*wbuf) + msg->len, wbuf, sizeof(*wbuf));
+ if (ret != sizeof(*wbuf) || le16_to_cpu(wbuf->size) != msg->len)
+ return (ret < 0) ? ret : -EIO;
+
+ return 0;
+}
+
+static int usbio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct usbio_i2c *i2c = i2c_get_adapdata(adap);
+ int ret;
+
+ usbio_acquire(i2c->adev);
+
+ ret = usbio_i2c_init(adap, msgs);
+ if (ret)
+ goto out_release;
+
+ for (int i = 0; i < num; ret = ++i) {
+ if (msgs[i].flags & I2C_M_RD)
+ ret = usbio_i2c_read(adap, &msgs[i]);
+ else
+ ret = usbio_i2c_write(adap, &msgs[i]);
+
+ if (ret)
+ break;
+ }
+
+ usbio_i2c_uninit(adap, msgs);
+
+out_release:
+ usbio_release(i2c->adev);
+
+ return ret;
+}
+
+static u32 usbio_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_adapter_quirks usbio_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START,
+ .max_read_len = SZ_4K,
+ .max_write_len = SZ_4K,
+};
+
+static const struct i2c_adapter_quirks usbio_i2c_quirks_max_rw_len52 = {
+ .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START,
+ .max_read_len = 52,
+ .max_write_len = 52,
+};
+
+static const struct i2c_algorithm usbio_i2c_algo = {
+ .master_xfer = usbio_i2c_xfer,
+ .functionality = usbio_i2c_func,
+};
+
+static int usbio_i2c_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *adev_id)
+{
+ struct usbio_i2c_bus_desc *i2c_desc;
+ struct device *dev = &adev->dev;
+ struct usbio_i2c *i2c;
+ u32 max_speed;
+ int ret;
+
+ i2c_desc = dev_get_platdata(dev);
+ if (!i2c_desc)
+ return -EINVAL;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->adev = adev;
+
+ usbio_acpi_bind(i2c->adev, usbio_i2c_acpi_hids);
+ usbio_get_txrxbuf_len(i2c->adev, &i2c->txbuf_len, &i2c->rxbuf_len);
+
+ i2c->rwbuf = devm_kzalloc(dev, max(i2c->txbuf_len, i2c->rxbuf_len), GFP_KERNEL);
+ if (!i2c->rwbuf)
+ return -ENOMEM;
+
+ i2c->quirks = usbio_get_quirks(i2c->adev);
+
+ max_speed = usbio_i2c_speeds[i2c_desc->caps & USBIO_I2C_BUS_MODE_CAP_MASK];
+ if (max_speed < I2C_MAX_FAST_MODE_FREQ &&
+ (i2c->quirks & USBIO_QUIRK_I2C_ALLOW_400KHZ))
+ max_speed = I2C_MAX_FAST_MODE_FREQ;
+
+ i2c->speed = i2c_acpi_find_bus_speed(dev);
+ if (!i2c->speed)
+ i2c->speed = I2C_MAX_STANDARD_MODE_FREQ;
+ else if (i2c->speed > max_speed) {
+ dev_warn(dev, "Invalid speed %u adjusting to bus max %u\n",
+ i2c->speed, max_speed);
+ i2c->speed = max_speed;
+ }
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.class = I2C_CLASS_HWMON;
+ i2c->adap.dev.parent = dev;
+ i2c->adap.algo = &usbio_i2c_algo;
+
+ if (i2c->quirks & USBIO_QUIRK_I2C_MAX_RW_LEN_52)
+ i2c->adap.quirks = &usbio_i2c_quirks_max_rw_len52;
+ else
+ i2c->adap.quirks = &usbio_i2c_quirks;
+
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name), "%s.%d",
+ USBIO_I2C_CLIENT, i2c->adev->id);
+
+ device_set_node(&i2c->adap.dev, dev_fwnode(&adev->dev));
+
+ auxiliary_set_drvdata(adev, i2c);
+ i2c_set_adapdata(&i2c->adap, i2c);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ return ret;
+
+ if (has_acpi_companion(&i2c->adap.dev))
+ acpi_dev_clear_dependencies(ACPI_COMPANION(&i2c->adap.dev));
+
+ return 0;
+}
+
+static void usbio_i2c_remove(struct auxiliary_device *adev)
+{
+ struct usbio_i2c *i2c = auxiliary_get_drvdata(adev);
+
+ i2c_del_adapter(&i2c->adap);
+}
+
+static const struct auxiliary_device_id usbio_i2c_id_table[] = {
+ { "usbio.usbio-i2c" },
+ { }
+};
+MODULE_DEVICE_TABLE(auxiliary, usbio_i2c_id_table);
+
+static struct auxiliary_driver usbio_i2c_driver = {
+ .name = USBIO_I2C_CLIENT,
+ .probe = usbio_i2c_probe,
+ .remove = usbio_i2c_remove,
+ .id_table = usbio_i2c_id_table
+};
+module_auxiliary_driver(usbio_i2c_driver);
+
+MODULE_DESCRIPTION("Intel USBIO I2C driver");
+MODULE_AUTHOR("Israel Cepeda <israel.a.cepeda.lopez@intel.com>");
+MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("USBIO");
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
index 1bd602852e35..f596efcc291c 100644
--- a/drivers/i2c/busses/i2c-viperboard.c
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -204,7 +204,7 @@ static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
/* copy the received data */
memcpy(msg->buf + start, rmsg, len1);
- /* second read transfer if neccessary */
+ /* second read transfer if necessary */
if (len2 > 0) {
ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2);
if (ret < 0)
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 4df8ad092df3..338800321f8b 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -22,7 +22,7 @@ EXPORT_SYMBOL_GPL(__i2c_board_lock);
LIST_HEAD(__i2c_board_list);
EXPORT_SYMBOL_GPL(__i2c_board_list);
-int __i2c_first_dynamic_bus_num;
+int __i2c_first_dynamic_bus_num __ro_after_init;
EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
@@ -48,7 +48,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
*/
-int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
+int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
{
int status;
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index ecca8c006b02..ae7e9c8b65a6 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -573,7 +573,8 @@ static int i2c_device_probe(struct device *dev)
goto err_clear_wakeup_irq;
do_power_on = !i2c_acpi_waive_d0_probe(dev);
- status = dev_pm_domain_attach(&client->dev, do_power_on ? PD_FLAG_ATTACH_POWER_ON : 0);
+ status = dev_pm_domain_attach(&client->dev, PD_FLAG_DETACH_POWER_OFF |
+ (do_power_on ? PD_FLAG_ATTACH_POWER_ON : 0));
if (status)
goto err_clear_wakeup_irq;
@@ -581,7 +582,7 @@ static int i2c_device_probe(struct device *dev)
GFP_KERNEL);
if (!client->devres_group_id) {
status = -ENOMEM;
- goto err_detach_pm_domain;
+ goto err_clear_wakeup_irq;
}
client->debugfs = debugfs_create_dir(dev_name(&client->dev),
@@ -608,8 +609,6 @@ static int i2c_device_probe(struct device *dev)
err_release_driver_resources:
debugfs_remove_recursive(client->debugfs);
devres_release_group(&client->dev, client->devres_group_id);
-err_detach_pm_domain:
- dev_pm_domain_detach(&client->dev, do_power_on);
err_clear_wakeup_irq:
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
@@ -636,8 +635,6 @@ static void i2c_device_remove(struct device *dev)
devres_release_group(&client->dev, client->devres_group_id);
- dev_pm_domain_detach(&client->dev, true);
-
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
diff --git a/drivers/i2c/i2c-core-slave.c b/drivers/i2c/i2c-core-slave.c
index 7ee6b992b835..02ca55c2246b 100644
--- a/drivers/i2c/i2c-core-slave.c
+++ b/drivers/i2c/i2c-core-slave.c
@@ -112,10 +112,9 @@ bool i2c_detect_slave_mode(struct device *dev)
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (is_of_node(fwnode)) {
- struct fwnode_handle *child __free(fwnode_handle) = NULL;
u32 reg;
- fwnode_for_each_child_node(fwnode, child) {
+ fwnode_for_each_child_node_scoped(fwnode, child) {
fwnode_property_read_u32(child, "reg", &reg);
if (reg & I2C_OWN_SLAVE_ADDRESS)
return true;
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 4d8690981a55..d59644e50f14 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -241,12 +241,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
muxc->parent = parent;
muxc->dev = dev;
- if (flags & I2C_MUX_LOCKED)
- muxc->mux_locked = true;
- if (flags & I2C_MUX_ARBITRATOR)
- muxc->arbitrator = true;
- if (flags & I2C_MUX_GATE)
- muxc->gate = true;
+ muxc->mux_locked = !!(flags & I2C_MUX_LOCKED);
+ muxc->arbitrator = !!(flags & I2C_MUX_ARBITRATOR);
+ muxc->gate = !!(flags & I2C_MUX_GATE);
muxc->select = select;
muxc->deselect = deselect;
muxc->max_adapters = max_adapters;
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 8663c8a7c269..3d8002caf703 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -63,10 +63,6 @@
#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON)
-/* arbitration timeouts, in jiffies */
-#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */
-#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */
-
/* arbitration retry delays, in us */
#define SELECT_DELAY_SHORT 50
#define SELECT_DELAY_LONG 1000
@@ -229,6 +225,9 @@ static int pca9541_arbitrate(struct i2c_client *client)
*/
data->select_timeout = SELECT_DELAY_LONG;
if (time_is_before_eq_jiffies(data->arb_timeout)) {
+ dev_warn(&client->dev,
+ "Arbitration timeout on I2C bus, forcing bus ownership\n");
+
/* Time is up, take the bus and reset it. */
pca9541_reg_write(client,
PCA9541_CONTROL,
@@ -251,10 +250,10 @@ static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
struct pca9541 *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
int ret;
- unsigned long timeout = jiffies + ARB2_TIMEOUT;
+ unsigned long timeout = jiffies + (2 * client->adapter->timeout);
/* give up after this time */
- data->arb_timeout = jiffies + ARB_TIMEOUT;
+ data->arb_timeout = jiffies + client->adapter->timeout;
/* force bus ownership after this time */
do {
@@ -267,6 +266,7 @@ static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
else
msleep(data->select_timeout / 1000);
} while (time_is_after_eq_jiffies(timeout));
+ dev_warn(&client->dev, "Failed to acquire I2C bus, timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index b9f370c9f018..75c8d08fa24e 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -118,7 +118,6 @@ struct pca954x {
raw_spinlock_t lock;
struct regulator *supply;
- struct gpio_desc *reset_gpio;
struct reset_control *reset_cont;
};
@@ -316,6 +315,25 @@ static u8 pca954x_regval(struct pca954x *data, u8 chan)
return 1 << chan;
}
+static void pca954x_reset_assert(struct pca954x *data)
+{
+ if (data->reset_cont)
+ reset_control_assert(data->reset_cont);
+}
+
+static void pca954x_reset_deassert(struct pca954x *data)
+{
+ if (data->reset_cont)
+ reset_control_deassert(data->reset_cont);
+}
+
+static void pca954x_reset_mux(struct pca954x *data)
+{
+ pca954x_reset_assert(data);
+ udelay(1);
+ pca954x_reset_deassert(data);
+}
+
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_mux_priv(muxc);
@@ -329,6 +347,8 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
ret = pca954x_reg_write(muxc->parent, client, regval);
data->last_chan = ret < 0 ? 0 : regval;
}
+ if (ret == -ETIMEDOUT && data->reset_cont)
+ pca954x_reset_mux(data);
return ret;
}
@@ -338,6 +358,7 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
s32 idle_state;
+ int ret = 0;
idle_state = READ_ONCE(data->idle_state);
if (idle_state >= 0)
@@ -347,8 +368,10 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
if (idle_state == MUX_IDLE_DISCONNECT) {
/* Deselect active channel */
data->last_chan = 0;
- return pca954x_reg_write(muxc->parent, client,
- data->last_chan);
+ ret = pca954x_reg_write(muxc->parent, client,
+ data->last_chan);
+ if (ret == -ETIMEDOUT && data->reset_cont)
+ pca954x_reset_mux(data);
}
/* otherwise leave as-is */
@@ -527,29 +550,10 @@ static int pca954x_get_reset(struct device *dev, struct pca954x *data)
if (IS_ERR(data->reset_cont))
return dev_err_probe(dev, PTR_ERR(data->reset_cont),
"Failed to get reset\n");
- else if (data->reset_cont)
- return 0;
-
- /*
- * fallback to legacy reset-gpios
- */
- data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(data->reset_gpio)) {
- return dev_err_probe(dev, PTR_ERR(data->reset_gpio),
- "Failed to get reset gpio");
- }
return 0;
}
-static void pca954x_reset_deassert(struct pca954x *data)
-{
- if (data->reset_cont)
- reset_control_deassert(data->reset_cont);
- else
- gpiod_set_value_cansleep(data->reset_gpio, 0);
-}
-
/*
* I2C init/probing/exit functions
*/
@@ -589,7 +593,7 @@ static int pca954x_probe(struct i2c_client *client)
if (ret)
goto fail_cleanup;
- if (data->reset_cont || data->reset_gpio) {
+ if (data->reset_cont) {
udelay(1);
pca954x_reset_deassert(data);
/* Give the chip some time to recover. */