diff options
Diffstat (limited to 'drivers/i2c')
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", ®); 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. */ |