diff options
author | Wolfram Sang <wsa+renesas@sang-engineering.com> | 2024-11-18 08:35:47 +0100 |
---|---|---|
committer | Wolfram Sang <wsa+renesas@sang-engineering.com> | 2024-11-18 08:35:47 +0100 |
commit | 1b3073291ddbe23fede7e0dd1b6f5635e370f8ba (patch) | |
tree | a3245db38b3389d4a63731b2c679c2d38eb24026 /drivers/i2c | |
parent | 48730a9d04ffccda541602d722d1ff81920a85d8 (diff) | |
parent | 1922bc245541bd08e3282d8199c8ac703e366111 (diff) |
Merge tag 'i2c-host-6.13-p1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-mergewindow
i2c-host updates for v6.13, part 1
Major Improvements and Refactoring:
- All controllers using the 'remove_new' callback have been
reverted to use the 'remove' callback.
- Intel SCH controller underwent significant refactoring,
this brings love and a modern look to the driver.
- PIIX4 driver refactored to enable usage by other drivers
(e.g., AMD ASF).
- iMX/MXC improved message handling to reduce protocol overhead:
Refactored DMA/non-DMA read/write and bus polling mechanisms
to achieve this.
- ACPI documentation for PIIX4.
New Features:
- i2c-cadence added support for atomic transfers.
- Qualcomm CII added support for a 32MHz serial engine clock.
Deprecated Features:
- Dropped outdated support for AMD756 S4882 and NFORCE2 S4985. If
somebody misses this, Jean will rewrite support using the proper
i2c mux framework.
New Hardware Support:
- Added support for:
- Intel Panther Lake (new ID)
- AMD ASF (new driver)
- S32G2/S32G3 SoCs (new ID)
- Realtek RTL I2C Controller (new driver)
- HJMC01 DesignWare ACPI HID (new ID)
- PIC64GX to Microchip Core (new ID)
- Qualcomm SDM670 to Qualcomm CCI (new ID)
Diffstat (limited to 'drivers/i2c')
107 files changed, 1950 insertions, 1136 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6b3ba7e5723a..bd9a6bcaaca4 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -62,19 +62,6 @@ config I2C_AMD756 This driver can also be built as a module. If so, the module will be called i2c-amd756. -config I2C_AMD756_S4882 - tristate "SMBus multiplexing on the Tyan S4882" - depends on I2C_AMD756 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 8 different channels, where the various memory module EEPROMs - and temperature sensors live. Saying yes here will give you access - to these in addition to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-amd756-s4882. - config I2C_AMD8111 tristate "AMD 8111" depends on PCI && HAS_IOPORT @@ -95,6 +82,23 @@ config I2C_AMD_MP2 This driver can also be built as modules. If so, the modules will be called i2c-amd-mp2-pci and i2c-amd-mp2-plat. +config I2C_AMD_ASF + tristate "AMD ASF I2C Controller Support" + depends on I2C_PIIX4 + select I2C_SLAVE + help + This option enables support for the AMD ASF (Alert Standard Format) + I2C controller. The AMD ASF controller is an SMBus controller with + built-in ASF functionality, allowing it to issue generic SMBus + packets and communicate with the DASH controller using MCTP over + ASF. + + If you have an AMD system with ASF support and want to enable this + functionality, say Y or M here. If unsure, say N. + + To compile this driver as a module, choose M here: the module will + be called i2c_amd_asf_plat. + config I2C_HIX5HD2 tristate "Hix5hd2 high-speed I2C driver" depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST @@ -160,6 +164,7 @@ config I2C_I801 Meteor Lake (SOC and PCH) Birch Stream (SOC) Arrow Lake (SOC) + Panther Lake (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -250,19 +255,6 @@ config I2C_NFORCE2 This driver can also be built as a module. If so, the module will be called i2c-nforce2. -config I2C_NFORCE2_S4985 - tristate "SMBus multiplexing on the Tyan S4985" - depends on I2C_NFORCE2 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 4 different channels, where the various memory module EEPROMs - live. Saying yes here will give you access to these in addition - to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-nforce2-s4985. - config I2C_NVIDIA_GPU tristate "NVIDIA GPU I2C controller" depends on PCI @@ -439,7 +431,7 @@ config I2C_AT91 are facing this situation, use the i2c-gpio driver. config I2C_AT91_SLAVE_EXPERIMENTAL - tristate "Microchip AT91 I2C experimental slave mode" + bool "Microchip AT91 I2C experimental slave mode" depends on I2C_AT91 select I2C_SLAVE help @@ -448,7 +440,7 @@ config I2C_AT91_SLAVE_EXPERIMENTAL been tested in a heavy way, help wanted. There are known bugs: - It can hang, on a SAMA5D4, after several transfers. - - There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as + - There are some mismatches with a SAMA5D4 as slave and a SAMA5D2 as master. config I2C_AU1550 @@ -741,13 +733,14 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || COMPILE_TEST + depends on ARCH_MXC || ARCH_LAYERSCAPE || ARCH_S32 || COLDFIRE \ + || COMPILE_TEST select I2C_SLAVE help Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC, Layerscape or ColdFire processors. + the Freescale i.MX/MXC/S32G, Layerscape or ColdFire processors. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called i2c-imx. config I2C_IMX_LPI2C @@ -1060,6 +1053,16 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. +config I2C_RTL9300 + tristate "Realtek RTL9300 I2C controller" + depends on MACH_REALTEK_RTL || COMPILE_TEST + help + Say Y here to include support for the I2C controller in Realtek + RTL9300 SoCs. + + This driver can also be built as a module. If so, the module will + be called i2c-rtl9300. + config I2C_RZV2M tristate "Renesas RZ/V2M adapter" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ecc07c50f2a0..49154c7bceee 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -14,14 +14,12 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o -obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_ISCH) += i2c-isch.o obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o -obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o @@ -38,12 +36,11 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o +obj-$(CONFIG_I2C_AMD_ASF) += i2c-amd-asf-plat.o obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o -i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o -ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) - i2c-at91-objs += i2c-at91-slave.o -endif +i2c-at91-y := i2c-at91-core.o i2c-at91-master.o +i2c-at91-$(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL) += i2c-at91-slave.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o @@ -103,6 +100,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o +obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o @@ -111,8 +109,8 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o -i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o +i2c-stm32f7-drv-y := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o @@ -121,10 +119,10 @@ obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o -i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o -i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o +i2c-octeon-y := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o +i2c-thunderx-y := i2c-octeon-core.o i2c-thunderx-pcidrv.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c index f4dde08a3b92..2da73173ce24 100644 --- a/drivers/i2c/busses/i2c-altera.c +++ b/drivers/i2c/busses/i2c-altera.c @@ -482,7 +482,7 @@ MODULE_DEVICE_TABLE(of, altr_i2c_of_match); static struct platform_driver altr_i2c_driver = { .probe = altr_i2c_probe, - .remove_new = altr_i2c_remove, + .remove = altr_i2c_remove, .driver = { .name = "altera-i2c", .of_match_table = altr_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c new file mode 100644 index 000000000000..ba47df5370c7 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Alert Standard Format Platform Driver + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sanket Goswami <Sanket.Goswami@amd.com> + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/devm-helpers.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/sprintf.h> + +#include "i2c-piix4.h" + +/* ASF register bits */ +#define ASF_SLV_LISTN 0 +#define ASF_SLV_INTR 1 +#define ASF_SLV_RST 4 +#define ASF_PEC_SP 5 +#define ASF_DATA_EN 7 +#define ASF_MSTR_EN 16 +#define ASF_CLK_EN 17 + +/* ASF address offsets */ +#define ASFINDEX (0x07 + piix4_smba) +#define ASFLISADDR (0x09 + piix4_smba) +#define ASFSTA (0x0A + piix4_smba) +#define ASFSLVSTA (0x0D + piix4_smba) +#define ASFDATARWPTR (0x11 + piix4_smba) +#define ASFSETDATARDPTR (0x12 + piix4_smba) +#define ASFDATABNKSEL (0x13 + piix4_smba) +#define ASFSLVEN (0x15 + piix4_smba) + +#define ASF_BLOCK_MAX_BYTES 72 +#define ASF_ERROR_STATUS GENMASK(3, 1) + +struct amd_asf_dev { + struct i2c_adapter adap; + void __iomem *eoi_base; + struct i2c_client *target; + struct delayed_work work_buf; + struct sb800_mmio_cfg mmio_cfg; + struct resource *port_addr; +}; + +static void amd_asf_process_target(struct work_struct *work) +{ + struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work); + unsigned short piix4_smba = dev->port_addr->start; + u8 data[ASF_BLOCK_MAX_BYTES]; + u8 bank, reg, cmd; + u8 len = 0, idx, val; + + /* Read target status register */ + reg = inb_p(ASFSLVSTA); + + /* Check if no error bits are set in target status register */ + if (reg & ASF_ERROR_STATUS) { + /* Set bank as full */ + cmd = 0; + reg |= GENMASK(3, 2); + outb_p(reg, ASFDATABNKSEL); + } else { + /* Read data bank */ + reg = inb_p(ASFDATABNKSEL); + bank = (reg & BIT(3)) ? 1 : 0; + + /* Set read data bank */ + if (bank) { + reg |= BIT(4); + reg &= ~BIT(3); + } else { + reg &= ~BIT(4); + reg &= ~BIT(2); + } + + /* Read command register */ + outb_p(reg, ASFDATABNKSEL); + cmd = inb_p(ASFINDEX); + len = inb_p(ASFDATARWPTR); + for (idx = 0; idx < len; idx++) + data[idx] = inb_p(ASFINDEX); + + /* Clear data bank status */ + if (bank) { + reg |= BIT(3); + outb_p(reg, ASFDATABNKSEL); + } else { + reg |= BIT(2); + outb_p(reg, ASFDATABNKSEL); + } + } + + outb_p(0, ASFSETDATARDPTR); + if (cmd & BIT(0)) + return; + + /* + * Although i2c_slave_event() returns an appropriate error code, we + * don't check it here because we're operating in the workqueue context. + */ + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val); + for (idx = 0; idx < len; idx++) { + val = data[idx]; + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val); + } + i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val); +} + +static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit, + unsigned long offset, bool set) +{ + unsigned long reg; + + reg = inb_p(offset); + __assign_bit(bit, ®, set); + outb_p(reg, offset); +} + +static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set) +{ + unsigned long reg; + + reg = ioread32(dev->mmio_cfg.addr); + __assign_bit(bit, ®, set); + iowrite32(reg, dev->mmio_cfg.addr); +} + +static void amd_asf_setup_target(struct amd_asf_dev *dev) +{ + unsigned short piix4_smba = dev->port_addr->start; + + /* Reset both host and target before setting up */ + outb_p(0, SMBHSTSTS); + outb_p(0, ASFSLVSTA); + outb_p(0, ASFSTA); + + /* Update target address */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true); + /* Enable target and set the clock */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false); + amd_asf_update_mmio_target(dev, ASF_CLK_EN, true); + /* Enable target interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); +} + +static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 i, len; + + outb_p((addr << 1), SMBHSTADD); + outb_p(command, SMBHSTCMD); + len = data[0]; + if (len == 0 || len > ASF_BLOCK_MAX_BYTES) + return -EINVAL; + + outb_p(len, SMBHSTDAT0); + /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); + for (i = 1; i <= len; i++) + outb_p(data[i], SMBBLKDAT); + + outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); + + return piix4_transaction(adap, piix4_smba); +} + +static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 asf_data[ASF_BLOCK_MAX_BYTES]; + struct i2c_msg *dev_msgs = msgs; + u8 prev_port; + int ret; + + if (msgs->flags & I2C_M_RD) { + dev_err(&adap->dev, "ASF: Read not supported\n"); + return -EOPNOTSUPP; + } + + /* Exclude the receive header and PEC */ + if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) { + dev_warn(&adap->dev, "ASF: max message length exceeded\n"); + return -EOPNOTSUPP; + } + + asf_data[0] = dev_msgs->len; + memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len); + + ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg); + if (ret) + return ret; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false); + /* Clear ASF target status */ + outb_p(0, ASFSLVSTA); + + /* Enable ASF SMBus controller function */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true); + prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg); + ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data); + piix4_sb800_port_sel(prev_port, &dev->mmio_cfg); + amd_asf_setup_target(dev); + piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg); + return ret; +} + +static int amd_asf_reg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + int ret; + u8 reg; + + if (dev->target) + return -EBUSY; + + ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg); + if (ret) + return ret; + + reg = (target->addr << 1) | I2C_M_RD; + outb_p(reg, ASFLISADDR); + + amd_asf_setup_target(dev); + dev->target = target; + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false); + piix4_sb800_region_release(&target->dev, &dev->mmio_cfg); + + return 0; +} + +static int amd_asf_unreg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + dev->target = NULL; + + return 0; +} + +static u32 amd_asf_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE; +} + +static const struct i2c_algorithm amd_asf_smbus_algorithm = { + .master_xfer = amd_asf_xfer, + .reg_slave = amd_asf_reg_target, + .unreg_slave = amd_asf_unreg_target, + .functionality = amd_asf_func, +}; + +static irqreturn_t amd_asf_irq_handler(int irq, void *ptr) +{ + struct amd_asf_dev *dev = ptr; + unsigned short piix4_smba = dev->port_addr->start; + u8 target_int = inb_p(ASFSTA); + + if (target_int & BIT(6)) { + /* Target Interrupt */ + outb_p(target_int | BIT(6), ASFSTA); + schedule_delayed_work(&dev->work_buf, HZ); + } else { + /* Controller Interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true); + } + + return IRQ_HANDLED; +} + +static int amd_asf_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct amd_asf_dev *asf_dev; + struct resource *eoi_addr; + int ret, irq; + + asf_dev = devm_kzalloc(dev, sizeof(*asf_dev), GFP_KERNEL); + if (!asf_dev) + return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n"); + + asf_dev->mmio_cfg.use_mmio = true; + asf_dev->port_addr = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!asf_dev->port_addr) + return dev_err_probe(dev, -EINVAL, "missing IO resources\n"); + + /* + * The resource obtained via ACPI might not belong to the ASF device address space. Instead, + * it could be within other IP blocks of the ASIC, which are crucial for generating + * subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and + * use platform_get_resource() and devm_ioremap() separately to prevent any address space + * conflicts. + */ + eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!eoi_addr) + return dev_err_probe(dev, -EINVAL, "missing MEM resources\n"); + + asf_dev->eoi_base = devm_ioremap(dev, eoi_addr->start, resource_size(eoi_addr)); + if (!asf_dev->eoi_base) + return dev_err_probe(dev, -EBUSY, "failed mapping IO region\n"); + + ret = devm_delayed_work_autocancel(dev, &asf_dev->work_buf, amd_asf_process_target); + if (ret) + return dev_err_probe(dev, ret, "failed to create work queue\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "missing IRQ resources\n"); + + ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev); + if (ret) + return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq); + + asf_dev->adap.owner = THIS_MODULE; + asf_dev->adap.algo = &amd_asf_smbus_algorithm; + asf_dev->adap.dev.parent = dev; + + i2c_set_adapdata(&asf_dev->adap, asf_dev); + snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name), "AMD ASF adapter"); + + return devm_i2c_add_adapter(dev, &asf_dev->adap); +} + +static const struct acpi_device_id amd_asf_acpi_ids[] = { + { "AMDI001A" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids); + +static struct platform_driver amd_asf_driver = { + .driver = { + .name = "i2c-amd-asf", + .acpi_match_table = amd_asf_acpi_ids, + }, + .probe = amd_asf_probe, +}; +module_platform_driver(amd_asf_driver); + +MODULE_IMPORT_NS(PIIX4_SMBUS); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Alert Standard Format Driver"); diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 6f0ef587e76d..d9dd0e475d1a 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match); static struct platform_driver i2c_amd_plat_driver = { .probe = i2c_amd_probe, - .remove_new = i2c_amd_remove, + .remove = i2c_amd_remove, .driver = { .name = "i2c_amd_mp2", .acpi_match_table = ACPI_PTR(i2c_amd_acpi_match), diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c deleted file mode 100644 index 063274388a75..000000000000 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard - * - * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de> - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4, and 0x4c (LM63) - * located on multiplexed channels 0 and 5-7. We define one - * virtual adapter per CPU, which corresponds to two multiplexed - * channels: - * CPU0: virtual adapter 1, channels 1 and 0 - * CPU1: virtual adapter 2, channels 2 and 5 - * CPU2: virtual adapter 3, channels 3 and 6 - * CPU3: virtual adapter 4, channels 4 and 7 - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -extern struct i2c_adapter amd756_smbus; - -static struct i2c_adapter *s4882_adapter; -static struct i2c_algorithm *s4882_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(amd756_lock); - -static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&amd756_lock); - - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - - mutex_unlock(&amd756_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&amd756_lock); - - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&amd756_lock); - return error; -} - -static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU0: channels 1 and 0 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x03); -} - -static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU1: channels 2 and 5 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x24); -} - -static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU2: channels 3 and 6 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x48); -} - -static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU3: channels 4 and 7 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x90); -} - -static int __init amd756_s4882_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!amd756_smbus.dev.parent) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(&amd756_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); - /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR1; - } - if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4882_algo[0] = *(amd756_smbus.algo); - s4882_algo[0].smbus_xfer = amd756_access_virt0; - s4882_adapter[0] = amd756_smbus; - s4882_adapter[0].algo = s4882_algo; - s4882_adapter[0].dev.parent = amd756_smbus.dev.parent; - for (i = 1; i < 5; i++) { - s4882_algo[i] = *(amd756_smbus.algo); - s4882_adapter[i] = amd756_smbus; - snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name), - "SMBus 8111 adapter (CPU%d)", i-1); - s4882_adapter[i].algo = s4882_algo+i; - s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; - } - s4882_algo[1].smbus_xfer = amd756_access_virt1; - s4882_algo[2].smbus_xfer = amd756_access_virt2; - s4882_algo[3].smbus_xfer = amd756_access_virt3; - s4882_algo[4].smbus_xfer = amd756_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4882_adapter+i); - if (error) { - printk(KERN_ERR "i2c-amd756-s4882: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4882_adapter+i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4882_algo); - s4882_algo = NULL; -ERROR2: - kfree(s4882_adapter); - s4882_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(&amd756_smbus); -ERROR0: - return error; -} - -static void __exit amd756_s4882_exit(void) -{ - if (s4882_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4882_adapter+i); - kfree(s4882_adapter); - s4882_adapter = NULL; - } - kfree(s4882_algo); - s4882_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(&amd756_smbus)) - printk(KERN_ERR "i2c-amd756-s4882: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); -MODULE_DESCRIPTION("S4882 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(amd756_s4882_init); -module_exit(amd756_s4882_exit); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 208310db906d..fa0d5a2c3732 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -283,7 +283,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = amd756_func, }; -struct i2c_adapter amd756_smbus = { +static struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, @@ -398,5 +398,3 @@ module_pci_driver(amd756_driver); MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>"); MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(amd756_smbus); diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index cc5a26637fd5..1550d3d552ae 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -1102,7 +1102,7 @@ static void aspeed_i2c_remove_bus(struct platform_device *pdev) static struct platform_driver aspeed_i2c_bus_driver = { .probe = aspeed_i2c_probe_bus, - .remove_new = aspeed_i2c_remove_bus, + .remove = aspeed_i2c_remove_bus, .driver = { .name = "aspeed-i2c-bus", .of_match_table = aspeed_i2c_bus_of_table, diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index dc52b3530725..edc047e3e535 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -330,7 +330,7 @@ static const struct dev_pm_ops __maybe_unused at91_twi_pm = { static struct platform_driver at91_twi_driver = { .probe = at91_twi_probe, - .remove_new = at91_twi_remove, + .remove = at91_twi_remove, .id_table = at91_twi_devtypes, .driver = { .name = "at91_i2c", diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 902e420e761e..b78b38ddac46 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -368,7 +368,7 @@ static struct platform_driver au1xpsc_smbus_driver = { .pm = pm_sleep_ptr(&i2c_au1550_pmops), }, .probe = i2c_au1550_probe, - .remove_new = i2c_au1550_remove, + .remove = i2c_au1550_remove, }; module_platform_driver(au1xpsc_smbus_driver); diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index a66f7f67b3b8..48916cf45ff7 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, axxia_i2c_of_match); static struct platform_driver axxia_i2c_driver = { .probe = axxia_i2c_probe, - .remove_new = axxia_i2c_remove, + .remove = axxia_i2c_remove, .driver = { .name = "axxia-i2c", .of_match_table = axxia_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 133d02899c6b..15b632a146e1 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1264,7 +1264,7 @@ static struct platform_driver bcm_iproc_i2c_driver = { .pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops), }, .probe = bcm_iproc_i2c_probe, - .remove_new = bcm_iproc_i2c_remove, + .remove = bcm_iproc_i2c_remove, }; module_platform_driver(bcm_iproc_i2c_driver); diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index eb5c46a8f824..340fe1305dd9 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -877,7 +877,7 @@ static struct platform_driver bcm_kona_i2c_driver = { .of_match_table = bcm_kona_i2c_of_match, }, .probe = bcm_kona_i2c_probe, - .remove_new = bcm_kona_i2c_remove, + .remove = bcm_kona_i2c_remove, }; module_platform_driver(bcm_kona_i2c_driver); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index ae42e37052a8..8554e790f8e3 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match); static struct platform_driver bcm2835_i2c_driver = { .probe = bcm2835_i2c_probe, - .remove_new = bcm2835_i2c_remove, + .remove = bcm2835_i2c_remove, .driver = { .name = "i2c-bcm2835", .of_match_table = bcm2835_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 83b85011e377..00f1a046e985 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -744,7 +744,7 @@ static struct platform_driver brcmstb_i2c_driver = { .pm = pm_sleep_ptr(&brcmstb_i2c_pm), }, .probe = brcmstb_i2c_probe, - .remove_new = brcmstb_i2c_remove, + .remove = brcmstb_i2c_remove, }; module_platform_driver(brcmstb_i2c_driver); diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 87b9ba95b2e1..b64026fbca66 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -129,6 +129,7 @@ #define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) #define CDNS_I2C_POLL_US 100000 +#define CDNS_I2C_POLL_US_ATOMIC 10 #define CDNS_I2C_TIMEOUT_US 500000 #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) @@ -189,6 +190,8 @@ enum cdns_i2c_slave_state { * @slave_state: I2C Slave state(idle/read/write). * @fifo_depth: The depth of the transfer FIFO * @transfer_size: The maximum number of bytes in one transfer + * @atomic: Mode of transfer + * @err_status_atomic: Error status in atomic mode */ struct cdns_i2c { struct device *dev; @@ -219,6 +222,8 @@ struct cdns_i2c { #endif u32 fifo_depth; unsigned int transfer_size; + bool atomic; + int err_status_atomic; }; struct cdns_platform_data { @@ -229,6 +234,66 @@ struct cdns_platform_data { clk_rate_change_nb) /** + * cdns_i2c_init - Controller initialisation + * @id: Device private data structure + * + * Initialise the i2c controller. + * + */ +static void cdns_i2c_init(struct cdns_i2c *id) +{ + cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); + /* + * Cadence I2C controller has a bug wherein it generates + * invalid read transaction after HW timeout in master receiver mode. + * HW timeout is not used by this driver and the interrupt is disabled. + * But the feature itself cannot be disabled. Hence maximum value + * is written to this register to reduce the chances of error. + */ + cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); +} + +/** + * cdns_i2c_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the platform_device structure + * + * Put the driver into low power mode. + * + * Return: 0 always + */ +static int cdns_i2c_runtime_suspend(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + + clk_disable(xi2c->clk); + + return 0; +} + +/** + * cdns_i2c_runtime_resume - Runtime resume + * @dev: Address of the platform_device structure + * + * Runtime resume callback. + * + * Return: 0 on success and error value on error + */ +static int cdns_i2c_runtime_resume(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(xi2c->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + cdns_i2c_init(xi2c); + + return 0; +} + +/** * cdns_i2c_clear_bus_hold - Clear bus hold bit * @id: Pointer to driver data struct * @@ -561,6 +626,89 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) return cdns_i2c_master_isr(ptr); } +static bool cdns_i2c_error_check(struct cdns_i2c *id) +{ + unsigned int isr_status; + + id->err_status = 0; + + isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); + cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET); + + id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK; + + return !!id->err_status; +} + +static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id) +{ + while (id->recv_count > 0) { + bool updatetx; + + /* + * Check if transfer size register needs to be updated again for a + * large data receive operation. + */ + updatetx = id->recv_count > id->curr_recv_count; + + while (id->curr_recv_count > 0) { + if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) { + *id->p_recv_buf = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); + id->p_recv_buf++; + id->recv_count--; + id->curr_recv_count--; + + /* + * Clear the hold bit that was set for FIFO control, + * if the remaining RX data is less than or equal to + * the FIFO depth, unless a repeated start is selected. + */ + if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); + } + if (cdns_i2c_error_check(id)) + return; + if (cdns_is_holdquirk(id, updatetx)) + break; + } + + /* + * The controller sends NACK to the slave/target when transfer size + * register reaches zero without considering the HOLD bit. + * This workaround is implemented for large data transfers to + * maintain transfer size non-zero while performing a large + * receive operation. + */ + if (cdns_is_holdquirk(id, updatetx)) { + /* wait while fifo is full */ + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != + (id->curr_recv_count - id->fifo_depth)) + ; + + /* + * Check number of bytes to be received against maximum + * transfer size and update register accordingly. + */ + if ((id->recv_count - id->fifo_depth) > + id->transfer_size) { + cdns_i2c_writereg(id->transfer_size, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->transfer_size + + id->fifo_depth; + } else { + cdns_i2c_writereg(id->recv_count - + id->fifo_depth, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; + } + } + } + + /* Clear hold (if not repeated start) */ + if (!id->recv_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); +} + /** * cdns_i2c_mrecv - Prepare and start a master receive operation * @id: pointer to the i2c device structure @@ -655,7 +803,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET); } - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else + cdns_i2c_mrecv_atomic(id); +} + +static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id) +{ + while (id->send_count) { + unsigned int avail_bytes; + unsigned int bytes_to_send; + + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET); + id->send_count--; + } + if (cdns_i2c_error_check(id)) + return; + } + + if (!id->send_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); } /** @@ -718,7 +893,10 @@ static void cdns_i2c_msend(struct cdns_i2c *id) cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET); - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else if (id->send_count > 0) + cdns_i2c_msend_rem_atomic(id); } /** @@ -758,7 +936,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, id->p_msg = msg; id->err_status = 0; - reinit_completion(&id->xfer_done); + if (!id->atomic) + reinit_completion(&id->xfer_done); /* Check for the TEN Bit mode on each msg */ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); @@ -780,14 +959,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, /* Minimal time to execute this message */ msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); - /* Plus some wiggle room */ - msg_timeout += msecs_to_jiffies(500); + + /* + * Plus some wiggle room. + * For non-atomic contexts, 500 ms is added to the timeout. + * For atomic contexts, 2000 ms is added because transfers happen in polled + * mode, requiring more time to account for the polling overhead. + */ + if (!id->atomic) + msg_timeout += msecs_to_jiffies(500); + else + msg_timeout += msecs_to_jiffies(2000); if (msg_timeout < adap->timeout) msg_timeout = adap->timeout; - /* Wait for the signal of completion */ - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + if (!id->atomic) { + /* Wait for the signal of completion */ + time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + } else { + /* 0 is success, -ETIMEDOUT is error */ + time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET, + reg, (reg & CDNS_I2C_IXR_COMP), + CDNS_I2C_POLL_US_ATOMIC, msg_timeout); + } + if (time_left == 0) { cdns_i2c_master_reset(adap); return -ETIMEDOUT; @@ -806,58 +1002,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, return 0; } -/** - * cdns_i2c_master_xfer - The main i2c transfer function - * @adap: pointer to the i2c adapter driver instance - * @msgs: pointer to the i2c message structure - * @num: the number of messages to transfer - * - * Initiates the send/recv activity based on the transfer message received. - * - * Return: number of msgs processed on success, negative error otherwise - */ -static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) { int ret, count; u32 reg; struct cdns_i2c *id = adap->algo_data; bool hold_quirk; -#if IS_ENABLED(CONFIG_I2C_SLAVE) - bool change_role = false; -#endif - - ret = pm_runtime_resume_and_get(id->dev); - if (ret < 0) - return ret; - -#if IS_ENABLED(CONFIG_I2C_SLAVE) - /* Check i2c operating mode and switch if possible */ - if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { - if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { - ret = -EAGAIN; - goto out; - } - - /* Set mode to master */ - cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); - - /* Mark flag to change role once xfer is completed */ - change_role = true; - } -#endif /* Check if the bus is free */ - - ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, - reg, - !(reg & CDNS_I2C_SR_BA), - CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + if (!id->atomic) + ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + else + ret = readl_poll_timeout_atomic(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US_ATOMIC, CDNS_I2C_TIMEOUT_US); if (ret) { ret = -EAGAIN; if (id->adap.bus_recovery_info) i2c_recover_bus(adap); - goto out; + return ret; } hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); @@ -877,8 +1046,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (msgs[count].flags & I2C_M_RD) { dev_warn(adap->dev.parent, "Can't do repeated start after a receive message\n"); - ret = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } } id->bus_hold_flag = 1; @@ -896,26 +1064,65 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ret = cdns_i2c_process_msg(id, msgs, adap); if (ret) - goto out; + return ret; /* Report the other error interrupts to application */ - if (id->err_status) { + if (id->err_status || id->err_status_atomic) { cdns_i2c_master_reset(adap); - if (id->err_status & CDNS_I2C_IXR_NACK) { - ret = -ENXIO; - goto out; - } - ret = -EIO; - goto out; + if (id->err_status & CDNS_I2C_IXR_NACK) + return -ENXIO; + + return -EIO; } } + return 0; +} + +/** + * cdns_i2c_master_xfer - The main i2c transfer function + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Initiates the send/recv activity based on the transfer message received. + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; +#if IS_ENABLED(CONFIG_I2C_SLAVE) + bool change_role = false; +#endif - ret = num; + ret = pm_runtime_resume_and_get(id->dev); + if (ret < 0) + return ret; -out: +#if IS_ENABLED(CONFIG_I2C_SLAVE) + /* Check i2c operating mode and switch if possible */ + if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { + if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { + ret = -EAGAIN; + goto out; + } + + /* Set mode to master */ + cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); + + /* Mark flag to change role once xfer is completed */ + change_role = true; + } +#endif + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; #if IS_ENABLED(CONFIG_I2C_SLAVE) +out: /* Switch i2c mode to slave */ if (change_role) cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); @@ -927,6 +1134,41 @@ out: } /** + * cdns_i2c_master_xfer_atomic - The i2c transfer function in atomic mode + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; + + ret = cdns_i2c_runtime_resume(id->dev); + if (ret) + return ret; + + if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) { + dev_warn(id->adap.dev.parent, + "Atomic xfer not supported for version 1.0\n"); + return 0; + } + + id->atomic = true; + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; + + id->atomic = false; + cdns_i2c_runtime_suspend(id->dev); + + return ret; +} + +/** * cdns_i2c_func - Returns the supported features of the I2C driver * @adap: pointer to the i2c adapter structure * @@ -990,6 +1232,7 @@ static int cdns_unreg_slave(struct i2c_client *slave) static const struct i2c_algorithm cdns_i2c_algo = { .master_xfer = cdns_i2c_master_xfer, + .master_xfer_atomic = cdns_i2c_master_xfer_atomic, .functionality = cdns_i2c_func, #if IS_ENABLED(CONFIG_I2C_SLAVE) .reg_slave = cdns_reg_slave, @@ -1158,23 +1401,6 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long } } -/** - * cdns_i2c_runtime_suspend - Runtime suspend method for the driver - * @dev: Address of the platform_device structure - * - * Put the driver into low power mode. - * - * Return: 0 always - */ -static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) -{ - struct cdns_i2c *xi2c = dev_get_drvdata(dev); - - clk_disable(xi2c->clk); - - return 0; -} - static int __maybe_unused cdns_i2c_suspend(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); @@ -1187,49 +1413,6 @@ static int __maybe_unused cdns_i2c_suspend(struct device *dev) return 0; } -/** - * cdns_i2c_init - Controller initialisation - * @id: Device private data structure - * - * Initialise the i2c controller. - * - */ -static void cdns_i2c_init(struct cdns_i2c *id) -{ - cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); - /* - * Cadence I2C controller has a bug wherein it generates - * invalid read transaction after HW timeout in master receiver mode. - * HW timeout is not used by this driver and the interrupt is disabled. - * But the feature itself cannot be disabled. Hence maximum value - * is written to this register to reduce the chances of error. - */ - cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); -} - -/** - * cdns_i2c_runtime_resume - Runtime resume - * @dev: Address of the platform_device structure - * - * Runtime resume callback. - * - * Return: 0 on success and error value on error - */ -static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) -{ - struct cdns_i2c *xi2c = dev_get_drvdata(dev); - int ret; - - ret = clk_enable(xi2c->clk); - if (ret) { - dev_err(dev, "Cannot enable clock.\n"); - return ret; - } - cdns_i2c_init(xi2c); - - return 0; -} - static int __maybe_unused cdns_i2c_resume(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); @@ -1469,7 +1652,7 @@ static struct platform_driver cdns_i2c_drv = { .pm = &cdns_i2c_dev_pm_ops, }, .probe = cdns_i2c_probe, - .remove_new = cdns_i2c_remove, + .remove = cdns_i2c_remove, }; module_platform_driver(cdns_i2c_drv); diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c index fdc1758a3275..8065c7e4462e 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids); static struct platform_driver cbus_i2c_driver = { .probe = cbus_i2c_probe, - .remove_new = cbus_i2c_remove, + .remove = cbus_i2c_remove, .driver = { .name = "i2c-cbus-gpio", .of_match_table = of_match_ptr(i2c_cbus_dt_ids), diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 52e3000626c5..26a36a65521e 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -546,7 +546,7 @@ MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table); static struct platform_driver cht_wc_i2c_adap_driver = { .probe = cht_wc_i2c_adap_i2c_probe, - .remove_new = cht_wc_i2c_adap_i2c_remove, + .remove = cht_wc_i2c_adap_i2c_remove, .driver = { .name = "cht_wcove_ext_chgr", }, diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 4794ec066eb0..260e1643c2cc 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -701,7 +701,7 @@ MODULE_DEVICE_TABLE(of, cpm_i2c_match); static struct platform_driver cpm_i2c_driver = { .probe = cpm_i2c_probe, - .remove_new = cpm_i2c_remove, + .remove = cpm_i2c_remove, .driver = { .name = "fsl-i2c-cpm", .of_match_table = cpm_i2c_match, diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index ab2688bd4d33..43bf90d90eeb 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -304,7 +304,7 @@ MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id); static struct platform_driver ec_i2c_tunnel_driver = { .probe = ec_i2c_probe, - .remove_new = ec_i2c_remove, + .remove = ec_i2c_remove, .driver = { .name = "cros-ec-i2c-tunnel", .acpi_match_table = ACPI_PTR(cros_ec_i2c_tunnel_acpi_id), diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c4fb5e9ab506..71dc0a6688b7 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -935,7 +935,7 @@ MODULE_DEVICE_TABLE(platform, davinci_i2c_driver_ids); static struct platform_driver davinci_i2c_driver = { .probe = davinci_i2c_probe, - .remove_new = davinci_i2c_remove, + .remove = davinci_i2c_remove, .id_table = davinci_i2c_driver_ids, .driver = { .name = "i2c_davinci", diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index 63454b06e5da..8fbd2a10c31a 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -155,7 +155,7 @@ static void psp_release_i2c_bus_deferred(struct work_struct *work) /* * If there is any pending transaction, cannot release the bus here. - * psp_release_i2c_bus will take care of this later. + * psp_release_i2c_bus() will take care of this later. */ if (psp_i2c_access_count) goto cleanup; @@ -210,12 +210,12 @@ static void psp_release_i2c_bus(void) { mutex_lock(&psp_i2c_access_mutex); - /* Return early if mailbox was malfunctional */ + /* Return early if mailbox was malfunctioned */ if (psp_i2c_mbox_fail) goto cleanup; /* - * If we are last owner of PSP semaphore, need to release aribtration + * If we are last owner of PSP semaphore, need to release arbitration * via mailbox. */ psp_i2c_access_count--; @@ -235,9 +235,9 @@ cleanup: /* * Locking methods are based on the default implementation from - * drivers/i2c/i2c-core-base.c, but with psp acquire and release operations + * drivers/i2c/i2c-core-base.c, but with PSP acquire and release operations * added. With this in place we can ensure that i2c clients on the bus shared - * with psp are able to lock HW access to the bus for arbitrary number of + * with PSP are able to lock HW access to the bus for arbitrary number of * operations - that is e.g. write-wait-read. */ static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index f31d352d98b5..443f946acf36 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -33,7 +33,7 @@ #include "i2c-designware-core.h" -static char *abort_sources[] = { +static const char *const abort_sources[] = { [ABRT_7B_ADDR_NOACK] = "slave address not acknowledged (7bit mode)", [ABRT_10ADDR1_NOACK] = @@ -127,6 +127,8 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val) * Autodetects needed register access mode and creates the regmap with * corresponding read/write callbacks. This must be called before doing any * other register access. + * + * Return: 0 on success, or negative errno otherwise. */ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) { @@ -174,7 +176,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) /* * Note we'll check the return value of the regmap IO accessors only * at the probe stage. The rest of the code won't do this because - * basically we have MMIO-based regmap so non of the read/write methods + * basically we have MMIO-based regmap, so none of the read/write methods * can fail. */ dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg); @@ -336,7 +338,7 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device) acpi_speed = i2c_acpi_find_bus_speed(device); /* - * Some DSTDs use a non standard speed, round down to the lowest + * Some DSDTs use a non standard speed, round down to the lowest * standard speed. */ for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) { @@ -407,47 +409,26 @@ static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg) } u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, - u32 tSYMBOL, u32 tf, int cond, int offset) + u32 tSYMBOL, u32 tf, int offset) { if (!ic_clk) return i2c_dw_read_scl_reg(dev, reg); /* - * DesignWare I2C core doesn't seem to have solid strategy to meet - * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec - * will result in violation of the tHD;STA spec. + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) + * + * This is just experimental rule; the tHD;STA period turned + * out to be proportinal to (_HCNT + 3). With this setting, + * we could meet both tHIGH and tHD;STA timing specs. + * + * If unsure, you'd better to take this alternative. + * + * The reason why we need to take into account "tf" here, + * is the same as described in i2c_dw_scl_lcnt(). */ - if (cond) - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH - * - * This is based on the DW manuals, and represents an ideal - * configuration. The resulting I2C bus speed will be - * faster than any of the others. - * - * If your hardware is free from tHD;STA issue, try this one. - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) - - 8 + offset; - else - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) - * - * This is just experimental rule; the tHD;STA period turned - * out to be proportinal to (_HCNT + 3). With this setting, - * we could meet both tHIGH and tHD;STA timing specs. - * - * If unsure, you'd better to take this alternative. - * - * The reason why we need to take into account "tf" here, - * is the same as described in i2c_dw_scl_lcnt(). - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - - 3 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; } u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, @@ -467,8 +448,7 @@ u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - - 1 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset; } int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) @@ -524,7 +504,7 @@ err_release_lock: void __i2c_dw_disable(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; - unsigned int raw_intr_stats; + unsigned int raw_intr_stats, ic_stats; unsigned int enable; int timeout = 100; bool abort_needed; @@ -532,9 +512,11 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) int ret; regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_intr_stats); + regmap_read(dev->map, DW_IC_STATUS, &ic_stats); regmap_read(dev->map, DW_IC_ENABLE, &enable); - abort_needed = raw_intr_stats & DW_IC_INTR_MST_ON_HOLD; + abort_needed = (raw_intr_stats & DW_IC_INTR_MST_ON_HOLD) || + (ic_stats & DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY); if (abort_needed) { if (!(enable & DW_IC_ENABLE_ENABLE)) { regmap_write(dev->map, DW_IC_ENABLE, DW_IC_ENABLE_ENABLE); @@ -569,7 +551,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) /* * Wait 10 times the signaling period of the highest I2C - * transfer supported by the driver (for 400KHz this is + * transfer supported by the driver (for 400kHz this is * 25us) as described in the DesignWare I2C databook. */ usleep_range(25, 250); @@ -676,10 +658,10 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) if (abort_source & DW_IC_TX_ARB_LOST) return -EAGAIN; - else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + if (abort_source & DW_IC_TX_ABRT_GCALL_READ) return -EINVAL; /* wrong msgs[] data */ - else - return -EIO; + + return -EIO; } int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 8e8854ec9882..520f9699e3bd 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -116,6 +116,7 @@ #define DW_IC_STATUS_RFNE BIT(3) #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) +#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7) #define DW_IC_SDA_HOLD_RX_SHIFT 16 #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) @@ -142,10 +143,10 @@ #define DW_IC_SLAVE 1 /* - * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register. * - * Only expected abort codes are listed here - * refer to the datasheet for the full list + * Only expected abort codes are listed here, + * refer to the datasheet for the full list. */ #define ABRT_7B_ADDR_NOACK 0 #define ABRT_10ADDR1_NOACK 1 @@ -200,7 +201,7 @@ struct reset_control; * @rst: optional reset for the controller * @slave: represent an I2C slave device * @get_clk_rate_khz: callback to retrieve IP specific bus speed - * @cmd_err: run time hadware error code + * @cmd_err: run time hardware error code * @msgs: points to an array of messages currently being transferred * @msgs_num: the number of elements in msgs * @msg_write_idx: the element index of the current tx message in the msgs array @@ -236,7 +237,7 @@ struct reset_control; * @release_lock: function to release a hardware lock on the bus * @semaphore_idx: Index of table with semaphore type attached to the bus. It's * -1 if there is no semaphore. - * @shared_with_punit: true if this bus is shared with the SoCs PUNIT + * @shared_with_punit: true if this bus is shared with the SoC's PUNIT * @init: function to initialize the I2C hardware * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE @@ -328,7 +329,7 @@ struct i2c_dw_semaphore_callbacks { int i2c_dw_init_regmap(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, - u32 tSYMBOL, u32 tf, int cond, int offset); + u32 tSYMBOL, u32 tf, int offset); u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, u32 tLOW, u32 tf, int offset); int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index e8ac9a7bf0b3..528b969253a7 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -71,7 +71,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 4000, /* tHD;STA = tHIGH = 4.0 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->ss_lcnt = i2c_dw_scl_lcnt(dev, @@ -105,7 +104,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 260, /* tHIGH = 260 ns */ sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->fs_lcnt = i2c_dw_scl_lcnt(dev, @@ -129,7 +127,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 600, /* tHD;STA = tHIGH = 0.6 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->fs_lcnt = i2c_dw_scl_lcnt(dev, @@ -161,7 +158,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 160, /* tHIGH = 160 ns */ sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->hs_lcnt = i2c_dw_scl_lcnt(dev, @@ -184,12 +180,14 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_master() - Initialize the designware I2C master hardware + * i2c_dw_init_master() - Initialize the DesignWare I2C master hardware * @dev: device private data * * This functions configures and enables the I2C master. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_master(struct dw_i2c_dev *dev) { @@ -357,7 +355,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate the i2c read/write transaction of buffer length, * and poll for bus busy status. For the last message transfer, - * update the command with stopbit enable. + * update the command with stop bit enable. */ for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) { if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1) @@ -402,7 +400,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate (and continue) low level master read/write transaction. - * This function is only called from i2c_dw_isr, and pumping i2c_msg + * This function is only called from i2c_dw_isr(), and pumping i2c_msg * messages into the tx buffer. Even if the size of i2c_msg data is * longer than the size of the tx buffer, it handles everything. */ @@ -440,7 +438,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) buf = msgs[dev->msg_write_idx].buf; buf_len = msgs[dev->msg_write_idx].len; - /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and + /* + * If both IC_EMPTYFIFO_HOLD_MASTER_EN and * IC_RESTART_EN are set, we must manually * set restart bit between messages. */ @@ -971,7 +970,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; adap->bus_recovery_info = rinfo; - dev_info(dev->dev, "running with gpio recovery mode! scl%s", + dev_info(dev->dev, "running with GPIO recovery mode! scl%s", rinfo->sda_gpiod ? ",sda" : ""); return 0; diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 7b2c5d71a7fc..38265c3dc454 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -51,7 +51,7 @@ struct dw_scl_sda_cfg { u16 fs_hcnt; u16 ss_lcnt; u16 fs_lcnt; - u32 sda_hold; + u32 sda_hold_time; }; struct dw_pci_controller { @@ -76,7 +76,7 @@ static struct dw_scl_sda_cfg byt_config = { .fs_hcnt = 0x55, .ss_lcnt = 0x200, .fs_lcnt = 0x99, - .sda_hold = 0x6, + .sda_hold_time = 0x6, }; /* Haswell HCNT/LCNT/SDA hold time */ @@ -85,14 +85,14 @@ static struct dw_scl_sda_cfg hsw_config = { .fs_hcnt = 0x48, .ss_lcnt = 0x01fb, .fs_lcnt = 0xa0, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; /* NAVI-AMD HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg navi_amd_config = { .ss_hcnt = 0x1ae, .ss_lcnt = 0x23a, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev) @@ -207,6 +207,7 @@ static const struct software_node dgpu_node = { static int i2c_dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *device = &pdev->dev; struct dw_i2c_dev *dev; struct i2c_adapter *adap; int r; @@ -214,25 +215,22 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) - return dev_err_probe(&pdev->dev, -EINVAL, - "Invalid driver data %ld\n", + return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n", id->driver_data); controller = &dw_pci_controllers[id->driver_data]; r = pcim_enable_device(pdev); if (r) - return dev_err_probe(&pdev->dev, r, - "Failed to enable I2C PCI device\n"); + return dev_err_probe(device, r, "Failed to enable I2C PCI device\n"); pci_set_master(pdev); r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); if (r) - return dev_err_probe(&pdev->dev, r, - "I/O memory remapping failed\n"); + return dev_err_probe(device, r, "I/O memory remapping failed\n"); - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -242,7 +240,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->get_clk_rate_khz = controller->get_clk_rate_khz; dev->base = pcim_iomap_table(pdev)[0]; - dev->dev = &pdev->dev; + dev->dev = device; dev->irq = pci_irq_vector(pdev, 0); dev->flags |= controller->flags; @@ -266,7 +264,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->fs_hcnt = cfg->fs_hcnt; dev->ss_lcnt = cfg->ss_lcnt; dev->fs_lcnt = cfg->fs_lcnt; - dev->sda_hold_time = cfg->sda_hold; + dev->sda_hold_time = cfg->sda_hold_time; } adap = &dev->adapter; @@ -281,14 +279,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node); if (IS_ERR(dev->slave)) - return dev_err_probe(dev->dev, PTR_ERR(dev->slave), + return dev_err_probe(device, PTR_ERR(dev->slave), "register UCSI failed\n"); } - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); - pm_runtime_allow(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_put_autosuspend(device); + pm_runtime_allow(device); return 0; } @@ -296,11 +294,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, static void i2c_dw_pci_remove(struct pci_dev *pdev) { struct dw_i2c_dev *dev = pci_get_drvdata(pdev); + struct device *device = &pdev->dev; i2c_dw_disable(dev); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_forbid(device); + pm_runtime_get_noresume(device); i2c_del_adapter(&dev->adapter); } diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 2d0c7348e491..1643cad6489c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -72,7 +72,7 @@ static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val) return ret; return regmap_write(dev->sysmap, BT1_I2C_CTL, - BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); + BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); } static const struct regmap_config bt1_i2c_cfg = { @@ -205,6 +205,7 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) static int dw_i2c_plat_probe(struct platform_device *pdev) { + struct device *device = &pdev->dev; struct i2c_adapter *adap; struct dw_i2c_dev *dev; int irq, ret; @@ -213,15 +214,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (irq < 0) return irq; - dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); - if (device_property_present(&pdev->dev, "wx,i2c-snps-model")) + dev->flags = (uintptr_t)device_get_match_data(device); + if (device_property_present(device, "wx,i2c-snps-model")) dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING; - dev->dev = &pdev->dev; + dev->dev = device; dev->irq = irq; platform_set_drvdata(pdev, dev); @@ -229,7 +230,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (ret) return ret; - dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + dev->rst = devm_reset_control_get_optional_exclusive(device, NULL); if (IS_ERR(dev->rst)) return PTR_ERR(dev->rst); @@ -246,13 +247,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure(dev); /* Optional interface clock */ - dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); + dev->pclk = devm_clk_get_optional(device, "pclk"); if (IS_ERR(dev->pclk)) { ret = PTR_ERR(dev->pclk); goto exit_reset; } - dev->clk = devm_clk_get_optional(&pdev->dev, NULL); + dev->clk = devm_clk_get_optional(device, NULL); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); goto exit_reset; @@ -277,31 +278,27 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) adap = &dev->adapter; adap->owner = THIS_MODULE; adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ? - I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; + I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; adap->nr = -1; - if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE); - } else { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE | - DPM_FLAG_SMART_SUSPEND); - } + if (dev->flags & ACCESS_NO_IRQ_SUSPEND) + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE); + else + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND); - device_enable_async_suspend(&pdev->dev); + device_enable_async_suspend(device); /* The code below assumes runtime PM to be disabled. */ - WARN_ON(pm_runtime_enabled(&pdev->dev)); + WARN_ON(pm_runtime_enabled(device)); - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_set_active(device); if (dev->shared_with_punit) - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_get_noresume(device); - pm_runtime_enable(&pdev->dev); + pm_runtime_enable(device); ret = i2c_dw_probe(dev); if (ret) @@ -319,15 +316,16 @@ exit_reset: static void dw_i2c_plat_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct device *device = &pdev->dev; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(device); i2c_del_adapter(&dev->adapter); i2c_dw_disable(dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_dont_use_autosuspend(device); + pm_runtime_put_sync(device); dw_i2c_plat_pm_cleanup(dev); i2c_dw_remove_lock_support(dev); @@ -354,6 +352,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "HISI02A1", 0 }, { "HISI02A2", 0 }, { "HISI02A3", 0 }, + { "HJMC3001", 0 }, { "HYGO0010", ACCESS_INTR_MASK }, { "INT33C2", 0 }, { "INT33C3", 0 }, @@ -372,7 +371,7 @@ MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids); static struct platform_driver dw_i2c_driver = { .probe = dw_i2c_plat_probe, - .remove_new = dw_i2c_plat_remove, + .remove = dw_i2c_plat_remove, .driver = { .name = "i2c_designware", .of_match_table = dw_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index 7035296aa24c..fad568e3523b 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -32,12 +32,14 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_slave() - Initialize the designware i2c slave hardware + * i2c_dw_init_slave() - Initialize the DesignWare i2c slave hardware * @dev: device private data * * This function configures and enables the I2C in slave mode. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { @@ -264,7 +266,7 @@ 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_err(dev->dev, "failure requesting IRQ %i: %d\n", dev->irq, ret); return ret; } diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 3dc5a46698fc..38d7f31aee79 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, dc_i2c_match); static struct platform_driver dc_i2c_driver = { .probe = dc_i2c_probe, - .remove_new = dc_i2c_remove, + .remove = dc_i2c_remove, .driver = { .name = "digicolor-i2c", .of_match_table = dc_i2c_match, diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index 11ed055143d3..bde2ef098862 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -245,7 +245,7 @@ static void dln2_i2c_remove(struct platform_device *pdev) static struct platform_driver dln2_i2c_driver = { .driver.name = "dln2-i2c", .probe = dln2_i2c_probe, - .remove_new = dln2_i2c_remove, + .remove = dln2_i2c_remove, }; module_platform_driver(dln2_i2c_driver); diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index d08be3f3cede..2512cef8e2a2 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -425,7 +425,7 @@ static const struct of_device_id em_i2c_ids[] = { static struct platform_driver em_i2c_driver = { .probe = em_i2c_probe, - .remove_new = em_i2c_remove, + .remove = em_i2c_remove, .driver = { .name = "em-i2c", .of_match_table = em_i2c_ids, diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index d8baca9b610c..e330015087ab 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -1009,7 +1009,7 @@ static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { static struct platform_driver exynos5_i2c_driver = { .probe = exynos5_i2c_probe, - .remove_new = exynos5_i2c_remove, + .remove = exynos5_i2c_remove, .driver = { .name = "exynos5-hsi2c", .pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index e0bd218e2f14..f4355b17bfbf 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -481,7 +481,7 @@ static struct platform_driver i2c_gpio_driver = { .acpi_match_table = i2c_gpio_acpi_match, }, .probe = i2c_gpio_probe, - .remove_new = i2c_gpio_remove, + .remove = i2c_gpio_remove, }; static int __init i2c_gpio_init(void) diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index efafc0528c44..0fc39caa6c87 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -595,7 +595,7 @@ MODULE_DEVICE_TABLE(of, gxp_i2c_of_match); static struct platform_driver gxp_i2c_driver = { .probe = gxp_i2c_probe, - .remove_new = gxp_i2c_remove, + .remove = gxp_i2c_remove, .driver = { .name = "gxp-i2c", .of_match_table = gxp_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index ec1ebacb9aa8..78c5845e0877 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -454,7 +454,7 @@ static struct platform_driver highlander_i2c_driver = { }, .probe = highlander_i2c_probe, - .remove_new = highlander_i2c_remove, + .remove = highlander_i2c_remove, }; module_platform_driver(highlander_i2c_driver); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 64cade6ba923..370f32974763 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -508,7 +508,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match); static struct platform_driver hix5hd2_i2c_driver = { .probe = hix5hd2_i2c_probe, - .remove_new = hix5hd2_i2c_remove, + .remove = hix5hd2_i2c_remove, .driver = { .name = "hix5hd2-i2c", .pm = pm_ptr(&hix5hd2_i2c_pm_ops), diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 299fe9d3afab..75dab01d43a7 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -81,6 +81,8 @@ * Meteor Lake PCH-S (PCH) 0x7f23 32 hard yes yes yes * Birch Stream (SOC) 0x5796 32 hard yes yes yes * 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 * * Features supported by this driver: * Software PEC no @@ -261,6 +263,8 @@ #define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 #define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS 0xae22 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_H_SMBUS 0xe322 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_P_SMBUS 0xe422 struct i801_mux_config { char *gpio_chip; @@ -1055,6 +1059,8 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { 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) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 82dedb1bb5be..c76c4116ddc7 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -790,7 +790,7 @@ static struct platform_driver ibm_iic_driver = { .of_match_table = ibm_iic_match, }, .probe = iic_probe, - .remove_new = iic_remove, + .remove = iic_remove, }; module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index e0e87185f6bb..02f75cf310aa 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1497,7 +1497,7 @@ static struct platform_driver img_scb_i2c_driver = { .pm = pm_ptr(&img_i2c_pm), }, .probe = img_i2c_probe, - .remove_new = img_i2c_remove, + .remove = img_i2c_remove, }; module_platform_driver(img_scb_i2c_driver); diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 976d43f73f38..8adf2963d764 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -703,7 +703,7 @@ static const struct dev_pm_ops lpi2c_pm_ops = { static struct platform_driver lpi2c_imx_driver = { .probe = lpi2c_imx_probe, - .remove_new = lpi2c_imx_remove, + .remove = lpi2c_imx_remove, .driver = { .name = DRIVER_NAME, .of_match_table = lpi2c_imx_of_match, diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 98539313cbc9..f751d231ded8 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -17,7 +17,7 @@ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> * * Copyright 2013 Freescale Semiconductor, Inc. - * Copyright 2020 NXP + * Copyright 2020, 2024 NXP * */ @@ -84,6 +84,7 @@ #define IMX_I2C_REGSHIFT 2 #define VF610_I2C_REGSHIFT 0 +#define S32G_I2C_REGSHIFT 0 /* Bits of IMX I2C registers */ #define I2SR_RXAK 0x01 @@ -165,9 +166,34 @@ static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = { { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, }; +/* S32G2/S32G3 clock divider, register value pairs */ +static struct imx_i2c_clk_pair s32g2_i2c_clk_div[] = { + { 34, 0x00 }, { 36, 0x01 }, { 38, 0x02 }, { 40, 0x03 }, + { 42, 0x04 }, { 44, 0x05 }, { 46, 0x06 }, { 48, 0x09 }, + { 52, 0x0A }, { 54, 0x07 }, { 56, 0x0B }, { 60, 0x0C }, + { 64, 0x0D }, { 68, 0x40 }, { 72, 0x0E }, { 76, 0x42 }, + { 80, 0x12 }, { 84, 0x0F }, { 88, 0x13 }, { 96, 0x14 }, + { 104, 0x15 }, { 108, 0x47 }, { 112, 0x19 }, { 120, 0x16 }, + { 128, 0x1A }, { 136, 0x80 }, { 144, 0x17 }, { 152, 0x82 }, + { 160, 0x1C }, { 168, 0x84 }, { 176, 0x1D }, { 192, 0x21 }, + { 208, 0x1E }, { 216, 0x87 }, { 224, 0x22 }, { 240, 0x56 }, + { 256, 0x1F }, { 288, 0x24 }, { 320, 0x25 }, { 336, 0x8F }, + { 352, 0x93 }, { 356, 0x5D }, { 358, 0x98 }, { 384, 0x26 }, + { 416, 0x56 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, + { 576, 0x2C }, { 640, 0x2D }, { 704, 0x9D }, { 768, 0x2E }, + { 832, 0x9D }, { 896, 0x32 }, { 960, 0x2F }, { 1024, 0x33 }, + { 1152, 0x34 }, { 1280, 0x35 }, { 1536, 0x36 }, { 1792, 0x3A }, + { 1920, 0x37 }, { 2048, 0x3B }, { 2304, 0x74 }, { 2560, 0x3D }, + { 3072, 0x3E }, { 3584, 0x7A }, { 3840, 0x3F }, { 4096, 0x7B }, + { 4608, 0x7C }, { 5120, 0x7D }, { 6144, 0x7E }, { 7168, 0xBA }, + { 7680, 0x7F }, { 8192, 0xBB }, { 9216, 0xBC }, { 10240, 0xBD }, + { 12288, 0xBE }, { 15360, 0xBF }, +}; + enum imx_i2c_type { IMX1_I2C, IMX21_I2C, + S32G_I2C, VF610_I2C, }; @@ -197,6 +223,17 @@ struct imx_i2c_dma { enum dma_data_direction dma_data_dir; }; +enum imx_i2c_state { + IMX_I2C_STATE_DONE, + IMX_I2C_STATE_FAILED, + IMX_I2C_STATE_WRITE, + IMX_I2C_STATE_DMA, + IMX_I2C_STATE_READ, + IMX_I2C_STATE_READ_CONTINUE, + IMX_I2C_STATE_READ_BLOCK_DATA, + IMX_I2C_STATE_READ_BLOCK_DATA_LEN, +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -216,6 +253,14 @@ struct imx_i2c_struct { struct i2c_client *slave; enum i2c_slave_event last_slave_event; + struct i2c_msg *msg; + unsigned int msg_buf_idx; + int isr_result; + bool is_lastmsg; + enum imx_i2c_state state; + + bool multi_master; + /* For checking slave events. */ spinlock_t slave_lock; struct hrtimer slave_timer; @@ -258,7 +303,15 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = { .ndivs = ARRAY_SIZE(vf610_i2c_clk_div), .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, +}; +static const struct imx_i2c_hwdata s32g2_i2c_hwdata = { + .devtype = S32G_I2C, + .regshift = S32G_I2C_REGSHIFT, + .clk_div = s32g2_i2c_clk_div, + .ndivs = ARRAY_SIZE(s32g2_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, }; static const struct platform_device_id imx_i2c_devtype[] = { @@ -288,6 +341,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, + { .compatible = "nxp,s32g2-i2c", .data = &s32g2_i2c_hwdata, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); @@ -481,6 +535,9 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a unsigned long orig_jiffies = jiffies; unsigned int temp; + if (!i2c_imx->multi_master) + return 0; + while (1) { temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); @@ -540,8 +597,8 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic) return -ETIMEDOUT; } - /* check for arbitration lost */ - if (i2c_imx->i2csr & I2SR_IAL) { + /* In multi-master mode check for arbitration lost */ + if (i2c_imx->multi_master && (i2c_imx->i2csr & I2SR_IAL)) { dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__); i2c_imx_clear_irq(i2c_imx, I2SR_IAL); @@ -903,11 +960,156 @@ static int i2c_imx_unreg_slave(struct i2c_client *client) return ret; } +static inline int i2c_imx_isr_acked(struct imx_i2c_struct *i2c_imx) +{ + i2c_imx->isr_result = 0; + + if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) { + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -ENXIO; + wake_up(&i2c_imx->queue); + } + + return i2c_imx->isr_result; +} + +static inline int i2c_imx_isr_write(struct imx_i2c_struct *i2c_imx) +{ + int result; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + if (i2c_imx->msg->len == i2c_imx->msg_buf_idx) + return 0; + + imx_i2c_write_reg(i2c_imx->msg->buf[i2c_imx->msg_buf_idx++], i2c_imx, IMX_I2C_I2DR); + + return 1; +} + +static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx) +{ + int result; + unsigned int temp; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + if (i2c_imx->msg->len - 1) + temp &= ~I2CR_TXAK; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + +static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) +{ + unsigned int temp; + + if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) { + if (i2c_imx->is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + if (!(temp & I2CR_MSTA)) + i2c_imx->stopped = 1; + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_MTX; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + } else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_TXAK; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); +} + +static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx) +{ + u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) { + i2c_imx->isr_result = -EPROTO; + i2c_imx->state = IMX_I2C_STATE_FAILED; + wake_up(&i2c_imx->queue); + } + i2c_imx->msg->len += len; +} + static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status) { - /* save status register */ - i2c_imx->i2csr = status; - wake_up(&i2c_imx->queue); + /* + * This state machine handles I2C reception and transmission in non-DMA + * mode. We must process all the data in the ISR to reduce the delay + * between two consecutive messages. If the data is not processed in + * the ISR, SMBus devices may timeout, leading to a bus error. + */ + switch (i2c_imx->state) { + case IMX_I2C_STATE_DMA: + i2c_imx->i2csr = status; + wake_up(&i2c_imx->queue); + break; + + case IMX_I2C_STATE_READ: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_READ_CONTINUE: + i2c_imx_isr_read_continue(i2c_imx); + if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) { + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + } + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA_LEN; + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA_LEN: + i2c_imx_isr_read_block_data_len(i2c_imx); + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_WRITE: + if (i2c_imx_isr_write(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + break; + + default: + i2c_imx->i2csr = status; + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -EINVAL; + wake_up(&i2c_imx->queue); + } return IRQ_HANDLED; } @@ -954,6 +1156,8 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + dma->chan_using = dma->chan_tx; dma->dma_transfer_dir = DMA_MEM_TO_DEV; dma->dma_data_dir = DMA_TO_DEVICE; @@ -1006,6 +1210,42 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, return i2c_imx_acked(i2c_imx); } +static int i2c_imx_prepare_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool use_dma) +{ + int result; + unsigned int temp = 0; + + /* write slave address */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + result = i2c_imx_trx_complete(i2c_imx, !use_dma); + if (result) + return result; + result = i2c_imx_acked(i2c_imx); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + + /* + * Reset the I2CR_TXAK flag initially for SMBus block read since the + * length is unknown + */ + if (msgs->len - 1) + temp &= ~I2CR_TXAK; + if (use_dma) + temp |= I2CR_DMAEN; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { @@ -1016,6 +1256,13 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + + result = i2c_imx_prepare_read(i2c_imx, msgs, true); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -1092,8 +1339,8 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, return 0; } -static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool atomic) +static int i2c_imx_atomic_write(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs) { int i, result; @@ -1102,7 +1349,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, /* write slave address */ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1116,7 +1363,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, "<%s> write byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1126,55 +1373,54 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool is_lastmsg, bool atomic) +static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +{ + dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->state = IMX_I2C_STATE_WRITE; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> write failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> write timedout\n", __func__); + return -ETIMEDOUT; + } + return 0; +} + +static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool is_lastmsg) { int i, result; unsigned int temp; int block_data = msgs->flags & I2C_M_RECV_LEN; - int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE && - msgs->len >= DMA_THRESHOLD && !block_data; - - dev_dbg(&i2c_imx->adapter.dev, - "<%s> write slave address: addr=0x%x\n", - __func__, i2c_8bit_addr_from_msg(msgs)); - /* write slave address */ - imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); - if (result) - return result; - result = i2c_imx_acked(i2c_imx); + result = i2c_imx_prepare_read(i2c_imx, msgs, false); if (result) return result; - dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); - - /* setup bus to read data */ - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp &= ~I2CR_MTX; - - /* - * Reset the I2CR_TXAK flag initially for SMBus block read since the - * length is unknown - */ - if ((msgs->len - 1) || block_data) - temp &= ~I2CR_TXAK; - if (use_dma) - temp |= I2CR_DMAEN; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ - dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (use_dma) - return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); - /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; /* @@ -1205,7 +1451,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); if (!i2c_imx->stopped) - i2c_imx_bus_busy(i2c_imx, 0, atomic); + i2c_imx_bus_busy(i2c_imx, 0, true); } else { /* * For i2c master receiver repeat restart operation like: @@ -1236,6 +1482,48 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, + bool is_lastmsg) +{ + int block_data = msgs->flags & I2C_M_RECV_LEN; + + dev_dbg(&i2c_imx->adapter.dev, + "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->is_lastmsg = is_lastmsg; + + if (block_data) + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA; + else + i2c_imx->state = IMX_I2C_STATE_READ; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> read failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__); + return -ETIMEDOUT; + } + if (!i2c_imx->stopped) + return i2c_imx_bus_busy(i2c_imx, 0, false); + + return 0; +} + static int i2c_imx_xfer_common(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, bool atomic) { @@ -1243,6 +1531,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, int result; bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); + int use_dma = 0; /* Start I2C transfer */ result = i2c_imx_start(i2c_imx, atomic); @@ -1295,15 +1584,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), (temp & I2SR_RXAK ? 1 : 0)); #endif + + use_dma = i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && + msgs[i].flags & I2C_M_DMA_SAFE; if (msgs[i].flags & I2C_M_RD) { - result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic); + int block_data = msgs->flags & I2C_M_RECV_LEN; + + if (atomic) + result = i2c_imx_atomic_read(i2c_imx, &msgs[i], is_lastmsg); + else if (use_dma && !block_data) + result = i2c_imx_dma_read(i2c_imx, &msgs[i], is_lastmsg); + else + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); } else { - if (!atomic && - i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && - msgs[i].flags & I2C_M_DMA_SAFE) + if (atomic) + result = i2c_imx_atomic_write(i2c_imx, &msgs[i]); + else if (use_dma) result = i2c_imx_dma_write(i2c_imx, &msgs[i]); else - result = i2c_imx_write(i2c_imx, &msgs[i], atomic); + result = i2c_imx_write(i2c_imx, &msgs[i]); } if (result) goto fail0; @@ -1468,6 +1767,12 @@ static int i2c_imx_probe(struct platform_device *pdev) goto rpm_disable; } + /* + * We use the single-master property for backward compatibility. + * By default multi master mode is enabled. + */ + i2c_imx->multi_master = !of_property_read_bool(pdev->dev.of_node, "single-master"); + /* Set up clock divider */ i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; ret = of_property_read_u32(pdev->dev.of_node, @@ -1576,7 +1881,7 @@ static const struct dev_pm_ops i2c_imx_pm_ops = { static struct platform_driver i2c_imx_driver = { .probe = i2c_imx_probe, - .remove_new = i2c_imx_remove, + .remove = i2c_imx_remove, .driver = { .name = DRIVER_NAME, .pm = pm_ptr(&i2c_imx_pm_ops), diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 859c14e340e7..ce5ca5b90b39 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -524,7 +524,7 @@ MODULE_DEVICE_TABLE(of, i2c_iop3xx_match); static struct platform_driver iop3xx_i2c_driver = { .probe = iop3xx_i2c_probe, - .remove_new = iop3xx_i2c_remove, + .remove = iop3xx_i2c_remove, .driver = { .name = "IOP3xx-I2C", .of_match_table = i2c_iop3xx_match, diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index f59158489ad9..2b3b65ef2900 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -1,41 +1,39 @@ // SPDX-License-Identifier: GPL-2.0-only /* - i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus - - Based on i2c-piix4.c - Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and - Philip Edelbrock <phil@netroedge.com> - - Intel SCH support - Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com> - -*/ + * Linux kernel driver for Intel SCH chipset SMBus + * - Based on i2c-piix4.c + * Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and + * Philip Edelbrock <phil@netroedge.com> + * - Intel SCH support + * Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com> + */ -/* - Supports: - Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) - Note: we assume there can only be one device, with one SMBus interface. -*/ +/* Supports: Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) */ +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> +#include <linux/i2c.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/delay.h> +#include <linux/sprintf.h> #include <linux/stddef.h> -#include <linux/ioport.h> -#include <linux/i2c.h> -#include <linux/io.h> +#include <linux/string_choices.h> +#include <linux/types.h> /* SCH SMBus address offsets */ -#define SMBHSTCNT (0 + sch_smba) -#define SMBHSTSTS (1 + sch_smba) -#define SMBHSTCLK (2 + sch_smba) -#define SMBHSTADD (4 + sch_smba) /* TSA */ -#define SMBHSTCMD (5 + sch_smba) -#define SMBHSTDAT0 (6 + sch_smba) -#define SMBHSTDAT1 (7 + sch_smba) -#define SMBBLKDAT (0x20 + sch_smba) - -/* Other settings */ -#define MAX_RETRIES 5000 +#define SMBHSTCNT 0x00 +#define SMBHSTSTS 0x01 +#define SMBHSTCLK 0x02 +#define SMBHSTADD 0x04 /* TSA */ +#define SMBHSTCMD 0x05 +#define SMBHSTDAT0 0x06 +#define SMBHSTDAT1 0x07 +#define SMBBLKDAT 0x20 /* I2C constants */ #define SCH_QUICK 0x00 @@ -44,109 +42,134 @@ #define SCH_WORD_DATA 0x03 #define SCH_BLOCK_DATA 0x05 -static unsigned short sch_smba; -static struct i2c_adapter sch_adapter; +struct sch_i2c { + struct i2c_adapter adapter; + void __iomem *smba; +}; + static int backbone_speed = 33000; /* backbone speed in kHz */ -module_param(backbone_speed, int, S_IRUSR | S_IWUSR); +module_param(backbone_speed, int, 0600); MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)"); -/* - * Start the i2c transaction -- the i2c_access will prepare the transaction - * and this function will execute it. - * return 0 for success and others for failure. +static inline u8 sch_io_rd8(struct sch_i2c *priv, unsigned int offset) +{ + return ioread8(priv->smba + offset); +} + +static inline void sch_io_wr8(struct sch_i2c *priv, unsigned int offset, u8 value) +{ + iowrite8(value, priv->smba + offset); +} + +static inline u16 sch_io_rd16(struct sch_i2c *priv, unsigned int offset) +{ + return ioread16(priv->smba + offset); +} + +static inline void sch_io_wr16(struct sch_i2c *priv, unsigned int offset, u16 value) +{ + iowrite16(value, priv->smba + offset); +} + +/** + * sch_transaction - Start the i2c transaction + * @adap: the i2c adapter pointer + * + * The sch_access() will prepare the transaction and + * this function will execute it. + * + * Return: 0 for success and others for failure. */ -static int sch_transaction(void) +static int sch_transaction(struct i2c_adapter *adap) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int temp; - int result = 0; - int retries = 0; + int rc; - dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); + dev_dbg(&adap->dev, + "Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { /* Can not be busy since we checked it in sch_access */ - if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Completion (%02x). " - "Clear...\n", temp); - } - if (temp & 0x06) { - dev_dbg(&sch_adapter.dev, "SMBus error (%02x). " - "Resetting...\n", temp); - } - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x0f; + if (temp & 0x01) + dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp); + if (temp & 0x06) + dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp); + sch_io_wr8(priv, SMBHSTSTS, temp); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { - dev_err(&sch_adapter.dev, - "SMBus is not ready: (%02x)\n", temp); + dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp); return -EAGAIN; } } - /* start the transaction by setting bit 4 */ - outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); - - do { - usleep_range(100, 200); - temp = inb(SMBHSTSTS) & 0x0f; - } while ((temp & 0x08) && (retries++ < MAX_RETRIES)); + /* Start the transaction by setting bit 4 */ + temp = sch_io_rd8(priv, SMBHSTCNT); + temp |= 0x10; + sch_io_wr8(priv, SMBHSTCNT, temp); + rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS); /* If the SMBus is still busy, we give up */ - if (retries > MAX_RETRIES) { - dev_err(&sch_adapter.dev, "SMBus Timeout!\n"); - result = -ETIMEDOUT; + if (rc) { + dev_err(&adap->dev, "SMBus Timeout!\n"); } else if (temp & 0x04) { - result = -EIO; - dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be " - "locked until next hard reset. (sorry!)\n"); + rc = -EIO; + dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n"); /* Clock stops and target is stuck in mid-transmission */ } else if (temp & 0x02) { - result = -EIO; - dev_err(&sch_adapter.dev, "Error: no response!\n"); + rc = -EIO; + dev_err(&adap->dev, "Error: no response!\n"); } else if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Post complete!\n"); - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x07; + dev_dbg(&adap->dev, "Post complete!\n"); + sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07; if (temp & 0x06) { /* Completion clear failed */ - dev_dbg(&sch_adapter.dev, "Failed reset at end of " - "transaction (%02x), Bus error!\n", temp); + dev_dbg(&adap->dev, + "Failed reset at end of transaction (%02x), Bus error!\n", temp); } } else { - result = -ENXIO; - dev_dbg(&sch_adapter.dev, "No such address.\n"); + rc = -ENXIO; + dev_dbg(&adap->dev, "No such address.\n"); } - dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); - return result; + dev_dbg(&adap->dev, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); + return rc; } -/* - * This is the main access entry for i2c-sch access - * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write - * (0 for read and 1 for write), size is i2c transaction type and data is the - * union of transaction for data to be transferred or data read from bus. - * return 0 for success and others for failure. +/** + * sch_access - the main access entry for i2c-sch access + * @adap: the i2c adapter pointer + * @addr: the i2c device bus address + * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC) + * @read_write: 0 for read and 1 for write + * @command: Byte interpreted by slave, for protocols which use such bytes + * @size: the i2c transaction type + * @data: the union of transaction for data to be transferred or data read from bus + * + * Return: 0 for success and others for failure. */ static s32 sch_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int i, len, temp, rc; /* Make sure the SMBus host is not busy */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp & 0x08) { - dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp); + dev_dbg(&adap->dev, "SMBus busy (%02x)\n", temp); return -EAGAIN; } - temp = inw(SMBHSTCLK); + temp = sch_io_rd16(priv, SMBHSTCLK); if (!temp) { /* * We can't determine if we have 33 or 25 MHz clock for @@ -154,50 +177,48 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, * 100 kHz. If we actually run at 25 MHz the bus will be * run ~75 kHz instead which should do no harm. */ - dev_notice(&sch_adapter.dev, - "Clock divider uninitialized. Setting defaults\n"); - outw(backbone_speed / (4 * 100), SMBHSTCLK); + dev_notice(&adap->dev, "Clock divider uninitialized. Setting defaults\n"); + sch_io_wr16(priv, SMBHSTCLK, backbone_speed / (4 * 100)); } - dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size, - (read_write)?"READ":"WRITE"); + dev_dbg(&adap->dev, "access size: %d %s\n", size, str_read_write(read_write)); switch (size) { case I2C_SMBUS_QUICK: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); size = SCH_QUICK; break; case I2C_SMBUS_BYTE: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); if (read_write == I2C_SMBUS_WRITE) - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTCMD, command); size = SCH_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) - outb(data->byte, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, data->byte); size = SCH_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { - outb(data->word & 0xff, SMBHSTDAT0); - outb((data->word & 0xff00) >> 8, SMBHSTDAT1); + sch_io_wr8(priv, SMBHSTDAT0, data->word >> 0); + sch_io_wr8(priv, SMBHSTDAT1, data->word >> 8); } size = SCH_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) return -EINVAL; - outb(len, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, len); for (i = 1; i <= len; i++) - outb(data->block[i], SMBBLKDAT+i-1); + sch_io_wr8(priv, SMBBLKDAT + i - 1, data->block[i]); } size = SCH_BLOCK_DATA; break; @@ -205,10 +226,13 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -EOPNOTSUPP; } - dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); - outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT); + dev_dbg(&adap->dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); + + temp = sch_io_rd8(priv, SMBHSTCNT); + temp = (temp & 0xb0) | (size & 0x7); + sch_io_wr8(priv, SMBHSTCNT, temp); - rc = sch_transaction(); + rc = sch_transaction(adap); if (rc) /* Error in transaction */ return rc; @@ -218,17 +242,18 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, switch (size) { case SCH_BYTE: case SCH_BYTE_DATA: - data->byte = inb(SMBHSTDAT0); + data->byte = sch_io_rd8(priv, SMBHSTDAT0); break; case SCH_WORD_DATA: - data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8); + data->word = (sch_io_rd8(priv, SMBHSTDAT0) << 0) + + (sch_io_rd8(priv, SMBHSTDAT1) << 8); break; case SCH_BLOCK_DATA: - data->block[0] = inb(SMBHSTDAT0); + data->block[0] = sch_io_rd8(priv, SMBHSTDAT0); if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) return -EPROTO; for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb(SMBBLKDAT+i-1); + data->block[i] = sch_io_rd8(priv, SMBBLKDAT + i - 1); break; } return 0; @@ -246,51 +271,34 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = sch_func, }; -static struct i2c_adapter sch_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON, - .algo = &smbus_algorithm, -}; - -static int smbus_sch_probe(struct platform_device *dev) +static int smbus_sch_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct sch_i2c *priv; struct resource *res; - int retval; - res = platform_get_resource(dev, IORESOURCE_IO, 0); - if (!res) - return -EBUSY; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - if (!devm_request_region(&dev->dev, res->start, resource_size(res), - dev->name)) { - dev_err(&dev->dev, "SMBus region 0x%x already in use!\n", - sch_smba); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) return -EBUSY; - } - - sch_smba = res->start; - dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba); + priv->smba = devm_ioport_map(dev, res->start, resource_size(res)); + if (!priv->smba) + return dev_err_probe(dev, -EBUSY, "SMBus region %pR already in use!\n", res); - /* set up the sysfs linkage to our parent device */ - sch_adapter.dev.parent = &dev->dev; + /* Set up the sysfs linkage to our parent device */ + priv->adapter.dev.parent = dev; + priv->adapter.owner = THIS_MODULE, + priv->adapter.class = I2C_CLASS_HWMON, + priv->adapter.algo = &smbus_algorithm, - snprintf(sch_adapter.name, sizeof(sch_adapter.name), - "SMBus SCH adapter at %04x", sch_smba); + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus SCH adapter at %04x", (unsigned short)res->start); - retval = i2c_add_adapter(&sch_adapter); - if (retval) - sch_smba = 0; - - return retval; -} - -static void smbus_sch_remove(struct platform_device *pdev) -{ - if (sch_smba) { - i2c_del_adapter(&sch_adapter); - sch_smba = 0; - } + return devm_i2c_add_adapter(dev, &priv->adapter); } static struct platform_driver smbus_sch_driver = { @@ -298,7 +306,6 @@ static struct platform_driver smbus_sch_driver = { .name = "isch_smbus", }, .probe = smbus_sch_probe, - .remove_new = smbus_sch_remove, }; module_platform_driver(smbus_sch_driver); diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 92cc5b091137..664a5471d933 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -847,7 +847,7 @@ static void jz4780_i2c_remove(struct platform_device *pdev) static struct platform_driver jz4780_i2c_driver = { .probe = jz4780_i2c_probe, - .remove_new = jz4780_i2c_remove, + .remove = jz4780_i2c_remove, .driver = { .name = "jz4780-i2c", .of_match_table = jz4780_i2c_of_matches, diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index eb66942e0b7d..212196af68ba 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -385,7 +385,7 @@ static struct platform_driver kempld_i2c_driver = { .pm = pm_sleep_ptr(&kempld_i2c_pm_ops), }, .probe = kempld_i2c_probe, - .remove_new = kempld_i2c_remove, + .remove = kempld_i2c_remove, }; module_platform_driver(kempld_i2c_driver); diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 9fb33cbf7419..6943a0de860a 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, lpc2k_i2c_match); static struct platform_driver i2c_lpc2k_driver = { .probe = i2c_lpc2k_probe, - .remove_new = i2c_lpc2k_remove, + .remove = i2c_lpc2k_remove, .driver = { .name = "lpc2k-i2c", .pm = pm_sleep_ptr(&i2c_lpc2k_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index c7b203cc4434..e1d69537353b 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -565,7 +565,7 @@ MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { .probe = meson_i2c_probe, - .remove_new = meson_i2c_remove, + .remove = meson_i2c_remove, .driver = { .name = "meson-i2c", .of_match_table = meson_i2c_match, diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index 0b0a1c4d17ca..d1543e7d8380 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match); static struct platform_driver mchp_corei2c_driver = { .probe = mchp_corei2c_probe, - .remove_new = mchp_corei2c_remove, + .remove = mchp_corei2c_remove, .driver = { .name = "microchip-corei2c", .of_match_table = mchp_corei2c_of_match, diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index b3a73921ab69..21f67f3b65b6 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -2456,7 +2456,7 @@ static void mlxbf_i2c_remove(struct platform_device *pdev) static struct platform_driver mlxbf_i2c_driver = { .probe = mlxbf_i2c_probe, - .remove_new = mlxbf_i2c_remove, + .remove = mlxbf_i2c_remove, .driver = { .name = "i2c-mlxbf", .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 8223f6d29eb3..07d3cadbf510 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -591,7 +591,7 @@ static void mlxcpld_i2c_remove(struct platform_device *pdev) static struct platform_driver mlxcpld_i2c_driver = { .probe = mlxcpld_i2c_probe, - .remove_new = mlxcpld_i2c_remove, + .remove = mlxcpld_i2c_remove, .driver = { .name = MLXCPLD_I2C_DEVICE_NAME, }, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 236d6b8ba867..28c5c5c1fb7a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -938,7 +938,7 @@ MODULE_DEVICE_TABLE(of, mpc_i2c_of_match); /* Structure for a device driver */ static struct platform_driver mpc_i2c_driver = { .probe = fsl_i2c_probe, - .remove_new = fsl_i2c_remove, + .remove = fsl_i2c_remove, .driver = { .name = "mpc-i2c", .of_match_table = mpc_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index e0ba653dec2d..5bd342047d59 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -1550,7 +1550,7 @@ static const struct dev_pm_ops mtk_i2c_pm = { static struct platform_driver mtk_i2c_driver = { .probe = mtk_i2c_probe, - .remove_new = mtk_i2c_remove, + .remove = mtk_i2c_remove, .driver = { .name = I2C_DRV_NAME, .pm = pm_sleep_ptr(&mtk_i2c_pm), diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 23d417ff5e71..2103f21f9ddd 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -331,7 +331,7 @@ static void mtk_i2c_remove(struct platform_device *pdev) static struct platform_driver mtk_i2c_driver = { .probe = mtk_i2c_probe, - .remove_new = mtk_i2c_remove, + .remove = mtk_i2c_remove, .driver = { .name = "i2c-mt7621", .of_match_table = i2c_mtk_dt_ids, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 29f94efedf60..874309580c33 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -1104,7 +1104,7 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, - .remove_new = mv64xxx_i2c_remove, + .remove = mv64xxx_i2c_remove, .driver = { .name = MV64XXX_I2C_CTLR_NAME, .pm = &mv64xxx_i2c_pm_ops, diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 36def0a9c95c..ad62d56b2186 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -881,7 +881,7 @@ static struct platform_driver mxs_i2c_driver = { .of_match_table = mxs_i2c_dt_ids, }, .probe = mxs_i2c_probe, - .remove_new = mxs_i2c_remove, + .remove = mxs_i2c_remove, }; static int __init mxs_i2c_init(void) diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c deleted file mode 100644 index 69a71bc9830d..000000000000 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard - * - * Copyright (C) 2008 Jean Delvare <jdelvare@suse.de> - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4. We define one virtual - * adapter per CPU, which corresponds to one multiplexed channel: - * CPU0: virtual adapter 1, channel 1 - * CPU1: virtual adapter 2, channel 2 - * CPU2: virtual adapter 3, channel 3 - * CPU3: virtual adapter 4, channel 4 - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -extern struct i2c_adapter *nforce2_smbus; - -static struct i2c_adapter *s4985_adapter; -static struct i2c_algorithm *s4985_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(nforce2_lock); - -static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&nforce2_lock); - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - mutex_unlock(&nforce2_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&nforce2_lock); - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&nforce2_lock); - return error; -} - -static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU0: channel 1 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x02); -} - -static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU1: channel 2 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x04); -} - -static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU2: channel 3 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x08); -} - -static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU3: channel 4 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x10); -} - -static int __init nforce2_s4985_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!nforce2_smbus) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(nforce2_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n"); - /* Define the 5 virtual adapters and algorithms structures */ - s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL); - if (!s4985_adapter) { - error = -ENOMEM; - goto ERROR1; - } - s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL); - if (!s4985_algo) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4985_algo[0] = *(nforce2_smbus->algo); - s4985_algo[0].smbus_xfer = nforce2_access_virt0; - s4985_adapter[0] = *nforce2_smbus; - s4985_adapter[0].algo = s4985_algo; - s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent; - for (i = 1; i < 5; i++) { - s4985_algo[i] = *(nforce2_smbus->algo); - s4985_adapter[i] = *nforce2_smbus; - snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name), - "SMBus nForce2 adapter (CPU%d)", i - 1); - s4985_adapter[i].algo = s4985_algo + i; - s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent; - } - s4985_algo[1].smbus_xfer = nforce2_access_virt1; - s4985_algo[2].smbus_xfer = nforce2_access_virt2; - s4985_algo[3].smbus_xfer = nforce2_access_virt3; - s4985_algo[4].smbus_xfer = nforce2_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4985_adapter + i); - if (error) { - printk(KERN_ERR "i2c-nforce2-s4985: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4985_adapter + i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4985_algo); - s4985_algo = NULL; -ERROR2: - kfree(s4985_adapter); - s4985_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(nforce2_smbus); -ERROR0: - return error; -} - -static void __exit nforce2_s4985_exit(void) -{ - if (s4985_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4985_adapter+i); - kfree(s4985_adapter); - s4985_adapter = NULL; - } - kfree(s4985_algo); - s4985_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(nforce2_smbus)) - printk(KERN_ERR "i2c-nforce2-s4985: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); -MODULE_DESCRIPTION("S4985 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(nforce2_s4985_init); -module_exit(nforce2_s4985_exit); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index fab662e6bc08..d58a308582e4 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -117,20 +117,6 @@ static const struct dmi_system_id nforce2_dmi_blacklist2[] = { static struct pci_driver nforce2_driver; -/* For multiplexing support, we need a global reference to the 1st - SMBus channel */ -#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985) -struct i2c_adapter *nforce2_smbus; -EXPORT_SYMBOL_GPL(nforce2_smbus); - -static void nforce2_set_reference(struct i2c_adapter *adap) -{ - nforce2_smbus = adap; -} -#else -static inline void nforce2_set_reference(struct i2c_adapter *adap) { } -#endif - static void nforce2_abort(struct i2c_adapter *adap) { struct nforce2_smbus *smbus = adap->algo_data; @@ -411,7 +397,6 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - nforce2_set_reference(&smbuses[0].adapter); return 0; } @@ -420,7 +405,6 @@ static void nforce2_remove(struct pci_dev *dev) { struct nforce2_smbus *smbuses = pci_get_drvdata(dev); - nforce2_set_reference(NULL); if (smbuses[0].base) { i2c_del_adapter(&smbuses[0].adapter); release_region(smbuses[0].base, smbuses[0].size); diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index bbcb4d6668ce..482a0074d448 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -334,6 +334,7 @@ struct npcm_i2c { u64 nack_cnt; u64 timeout_cnt; u64 tx_complete_cnt; + bool ber_state; /* Indicate the bus error state */ }; static inline void npcm_i2c_select_bank(struct npcm_i2c *bus, @@ -1521,6 +1522,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) if (npcm_i2c_is_master(bus)) { npcm_i2c_master_abort(bus); } else { + bus->ber_state = true; npcm_i2c_clear_master_status(bus); /* Clear BB (BUS BUSY) bit */ @@ -1628,13 +1630,10 @@ static void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst) npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0)); /* SDA interrupt, after start\restart */ } else { - if (NPCM_I2CST_XMIT & i2cst) { - bus->operation = I2C_WRITE_OPER; + if (bus->operation == I2C_WRITE_OPER) npcm_i2c_irq_master_handler_write(bus); - } else { - bus->operation = I2C_READ_OPER; + else if (bus->operation == I2C_READ_OPER) npcm_i2c_irq_master_handler_read(bus); - } } } @@ -1702,6 +1701,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", bus->num, bus->dest_addr); npcm_i2c_reset(bus); + bus->ber_state = false; return 0; } @@ -1766,6 +1766,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) if (bus->rec_succ_cnt < ULLONG_MAX) bus->rec_succ_cnt++; } + bus->ber_state = false; return status; } @@ -2161,7 +2162,16 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } while (time_is_after_jiffies(time_left) && bus_busy); - if (bus_busy) { + /* + * Check the BER (bus error) state, when ber_state is true, it means that the module + * detects the bus error which is caused by some factor like that the electricity + * noise occurs on the bus. Under this condition, the module is reset and the bus + * gets recovered. + * + * While ber_state is false, the module reset and bus recovery also get done as the + * bus is busy. + */ + if (bus_busy || bus->ber_state) { iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); npcm_i2c_reset(bus); i2c_recover_bus(adap); @@ -2363,7 +2373,7 @@ MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table); static struct platform_driver npcm_i2c_bus_driver = { .probe = npcm_i2c_probe_bus, - .remove_new = npcm_i2c_remove_bus, + .remove = npcm_i2c_remove_bus, .driver = { .name = "nuvoton-i2c", .of_match_table = npcm_i2c_bus_of_table, diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 482b37c8a129..0f67e57cdeff 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -769,7 +769,7 @@ static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm, static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, - .remove_new = ocores_i2c_remove, + .remove = ocores_i2c_remove, .driver = { .name = "ocores-i2c", .of_match_table = ocores_i2c_match, diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c index dc6dff95c68c..edfca7b20f29 100644 --- a/drivers/i2c/busses/i2c-octeon-platdrv.c +++ b/drivers/i2c/busses/i2c-octeon-platdrv.c @@ -269,7 +269,7 @@ MODULE_DEVICE_TABLE(of, octeon_i2c_match); static struct platform_driver octeon_i2c_driver = { .probe = octeon_i2c_probe, - .remove_new = octeon_i2c_remove, + .remove = octeon_i2c_remove, .driver = { .name = DRV_NAME, .of_match_table = octeon_i2c_match, diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1d9ad25c89ae..92faf03d64cf 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1605,7 +1605,7 @@ static const struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove_new = omap_i2c_remove, + .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", .pm = pm_ptr(&omap_i2c_pm_ops), diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index d9dd71cf37fd..c9b62892397a 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -249,7 +249,7 @@ MODULE_DEVICE_TABLE(of, i2c_opal_of_match); static struct platform_driver i2c_opal_driver = { .probe = i2c_opal_probe, - .remove_new = i2c_opal_remove, + .remove = i2c_opal_remove, .driver = { .name = "i2c-opal", .of_match_table = i2c_opal_of_match, diff --git a/drivers/i2c/busses/i2c-pasemi-platform.c b/drivers/i2c/busses/i2c-pasemi-platform.c index 5fbfb9b41744..a486a37d3863 100644 --- a/drivers/i2c/busses/i2c-pasemi-platform.c +++ b/drivers/i2c/busses/i2c-pasemi-platform.c @@ -104,7 +104,7 @@ static struct platform_driver pasemi_platform_i2c_driver = { .of_match_table = pasemi_platform_i2c_of_match, }, .probe = pasemi_platform_i2c_probe, - .remove_new = pasemi_platform_i2c_remove, + .remove = pasemi_platform_i2c_remove, }; module_platform_driver(pasemi_platform_i2c_driver); diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index b8d5480c54f6..87da8241b927 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -238,7 +238,7 @@ MODULE_DEVICE_TABLE(of, i2c_pca_of_match_table); static struct platform_driver i2c_pca_pf_driver = { .probe = i2c_pca_pf_probe, - .remove_new = i2c_pca_pf_remove, + .remove = i2c_pca_pf_remove, .driver = { .name = "i2c-pca-platform", .of_match_table = of_match_ptr(i2c_pca_of_match_table), diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index febbd9950d8f..9402fa3811c5 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -35,20 +35,7 @@ #include <linux/acpi.h> #include <linux/io.h> - -/* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) +#include "i2c-piix4.h" /* count for request_region */ #define SMBIOSIZE 9 @@ -70,7 +57,6 @@ #define PIIX4_BYTE 0x04 #define PIIX4_BYTE_DATA 0x08 #define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 /* Multi-port constants */ #define PIIX4_MAX_ADAPTERS 4 @@ -101,6 +87,7 @@ #define SB800_PIIX4_FCH_PM_ADDR 0xFED80300 #define SB800_PIIX4_FCH_PM_SIZE 8 +#define SB800_ASF_ACPI_PATH "\\_SB.ASFC" /* insmod parameters */ @@ -160,11 +147,6 @@ static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = { }; static const char *piix4_aux_port_name_sb800 = " port 1"; -struct sb800_mmio_cfg { - void __iomem *addr; - bool use_mmio; -}; - struct i2c_piix4_adapdata { unsigned short smba; @@ -175,8 +157,7 @@ struct i2c_piix4_adapdata { struct sb800_mmio_cfg mmio_cfg; }; -static int piix4_sb800_region_request(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { void __iomem *addr; @@ -214,9 +195,9 @@ static int piix4_sb800_region_request(struct device *dev, return 0; } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_request, PIIX4_SMBUS); -static void piix4_sb800_region_release(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { iounmap(mmio_cfg->addr); @@ -227,6 +208,7 @@ static void piix4_sb800_region_release(struct device *dev, release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_release, PIIX4_SMBUS); static bool piix4_sb800_use_mmio(struct pci_dev *PIIX4_dev) { @@ -536,10 +518,8 @@ static int piix4_setup_aux(struct pci_dev *PIIX4_dev, return piix4_smba; } -static int piix4_transaction(struct i2c_adapter *piix4_adapter) +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba) { - struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); - unsigned short piix4_smba = adapdata->smba; int temp; int result = 0; int timeout = 0; @@ -611,6 +591,7 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) inb_p(SMBHSTDAT1)); return result; } +EXPORT_SYMBOL_NS_GPL(piix4_transaction, PIIX4_SMBUS); /* Return negative errno on error. */ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, @@ -675,7 +656,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - status = piix4_transaction(adap); + status = piix4_transaction(adap, piix4_smba); if (status) return status; @@ -764,7 +745,7 @@ static void piix4_imc_wakeup(void) release_region(KERNCZ_IMC_IDX, 2); } -static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) { u8 smba_en_lo, val; @@ -786,6 +767,7 @@ static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) return (smba_en_lo & piix4_port_mask_sb800); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_port_sel, PIIX4_SMBUS); /* * Handles access to multiple SMBus ports on the SB800. @@ -1043,6 +1025,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; bool is_sb800 = false; + bool is_asf = false; + acpi_status status; + acpi_handle handle; if ((dev->vendor == PCI_VENDOR_ID_ATI && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && @@ -1105,10 +1090,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) } } + status = acpi_get_handle(NULL, (acpi_string)SB800_ASF_ACPI_PATH, &handle); + if (ACPI_SUCCESS(status)) + is_asf = true; + if (dev->vendor == PCI_VENDOR_ID_AMD && (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS || dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) { - retval = piix4_setup_sb800(dev, id, 1); + /* Do not setup AUX port if ASF is enabled */ + if (!is_asf) + retval = piix4_setup_sb800(dev, id, 1); } if (retval > 0) { diff --git a/drivers/i2c/busses/i2c-piix4.h b/drivers/i2c/busses/i2c-piix4.h new file mode 100644 index 000000000000..36bc6ce82a27 --- /dev/null +++ b/drivers/i2c/busses/i2c-piix4.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * PIIX4/SB800 SMBus Interfaces + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sanket Goswami <Sanket.Goswami@amd.com> + */ + +#ifndef I2C_PIIX4_H +#define I2C_PIIX4_H + +#include <linux/types.h> + +/* PIIX4 SMBus address offsets */ +#define SMBHSTSTS (0x00 + piix4_smba) +#define SMBHSLVSTS (0x01 + piix4_smba) +#define SMBHSTCNT (0x02 + piix4_smba) +#define SMBHSTCMD (0x03 + piix4_smba) +#define SMBHSTADD (0x04 + piix4_smba) +#define SMBHSTDAT0 (0x05 + piix4_smba) +#define SMBHSTDAT1 (0x06 + piix4_smba) +#define SMBBLKDAT (0x07 + piix4_smba) +#define SMBSLVCNT (0x08 + piix4_smba) +#define SMBSHDWCMD (0x09 + piix4_smba) +#define SMBSLVEVT (0x0A + piix4_smba) +#define SMBSLVDAT (0x0C + piix4_smba) + +/* PIIX4 constants */ +#define PIIX4_BLOCK_DATA 0x14 + +struct sb800_mmio_cfg { + void __iomem *addr; + bool use_mmio; +}; + +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg); +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba); +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); + +#endif /* I2C_PIIX4_H */ diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 1dafadda73af..d4d139b97513 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -733,7 +733,7 @@ static struct platform_driver i2c_pnx_driver = { .pm = pm_sleep_ptr(&i2c_pnx_pm), }, .probe = i2c_pnx_probe, - .remove_new = i2c_pnx_remove, + .remove = i2c_pnx_remove, }; static int __init i2c_adap_pnx_init(void) diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index b6b03539f626..9a867c817db0 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -437,7 +437,7 @@ static int i2c_powermac_probe(struct platform_device *dev) static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, - .remove_new = i2c_powermac_remove, + .remove = i2c_powermac_remove, .driver = { .name = "i2c-powermac", .bus = &platform_bus_type, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 4d76e71cdd4b..cb6988482673 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1574,7 +1574,7 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, - .remove_new = i2c_pxa_remove, + .remove = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", .pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 414882c57d7f..05b73326afd4 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -120,7 +120,6 @@ struct cci_data { unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; - unsigned long cci_clk_rate; struct hw_params params[3]; }; @@ -523,7 +522,6 @@ static const struct dev_pm_ops qcom_cci_pm = { static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - unsigned long cci_clk_rate = 0; struct device_node *child; struct resource *r; struct cci *cci; @@ -594,22 +592,6 @@ static int cci_probe(struct platform_device *pdev) return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); cci->nclocks = ret; - /* Retrieve CCI clock rate */ - for (i = 0; i < cci->nclocks; i++) { - if (!strcmp(cci->clocks[i].id, "cci")) { - cci_clk_rate = clk_get_rate(cci->clocks[i].clk); - break; - } - } - - if (cci_clk_rate != cci->data->cci_clk_rate) { - /* cci clock set by the bootloader or via assigned clock rate - * in DT. - */ - dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", - cci_clk_rate, cci->data->cci_clk_rate); - } - ret = cci_enable_clocks(cci); if (ret < 0) return ret; @@ -699,7 +681,6 @@ static const struct cci_data cci_v1_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -733,7 +714,6 @@ static const struct cci_data cci_v1_5_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -767,7 +747,6 @@ static const struct cci_data cci_v2_data = { .max_write_len = 11, .max_read_len = 12, }, - .cci_clk_rate = 37500000, .params[I2C_MODE_STANDARD] = { .thigh = 201, .tlow = 174, @@ -826,7 +805,7 @@ MODULE_DEVICE_TABLE(of, cci_dt_match); static struct platform_driver qcom_cci_driver = { .probe = cci_probe, - .remove_new = cci_remove, + .remove = cci_remove, .driver = { .name = "i2c-qcom-cci", .of_match_table = cci_dt_match, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 212336f724a6..7a22e1f46e60 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -16,6 +16,7 @@ #include <linux/pm_runtime.h> #include <linux/soc/qcom/geni-se.h> #include <linux/spinlock.h> +#include <linux/units.h> #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -146,22 +147,36 @@ struct geni_i2c_clk_fld { * clk_freq_out = t / t_cycle * source_clock = 19.2 MHz */ -static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { +static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = { {KHZ(100), 7, 10, 11, 26}, {KHZ(400), 2, 5, 12, 24}, {KHZ(1000), 1, 3, 9, 18}, + {}, +}; + +/* source_clock = 32 MHz */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { + {KHZ(100), 8, 14, 18, 40}, + {KHZ(400), 4, 3, 11, 20}, + {KHZ(1000), 2, 3, 6, 15}, + {}, }; static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) { - int i; - const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + const struct geni_i2c_clk_fld *itr; - for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + if (clk_get_rate(gi2c->se.clk) == 32 * HZ_PER_MHZ) + itr = geni_i2c_clk_map_32mhz; + else + itr = geni_i2c_clk_map_19p2mhz; + + while (itr->clk_freq_out != 0) { if (itr->clk_freq_out == gi2c->clk_freq_out) { gi2c->clk_fld = itr; return 0; } + itr++; } return -EINVAL; } @@ -818,6 +833,8 @@ static int geni_i2c_probe(struct platform_device *pdev) init_completion(&gi2c->done); spin_lock_init(&gi2c->lock); platform_set_drvdata(pdev, gi2c); + + /* Keep interrupts disabled initially to allow for low-power modes */ ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); if (ret) { @@ -1049,7 +1066,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); static struct platform_driver geni_i2c_driver = { .probe = geni_i2c_probe, - .remove_new = geni_i2c_remove, + .remove = geni_i2c_remove, .shutdown = geni_i2c_shutdown, .driver = { .name = "geni_i2c", diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index d480162a4d39..86ec391616b0 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1974,7 +1974,7 @@ MODULE_DEVICE_TABLE(of, qup_i2c_dt_match); static struct platform_driver qup_i2c_driver = { .probe = qup_i2c_probe, - .remove_new = qup_i2c_remove, + .remove = qup_i2c_remove, .driver = { .name = "i2c_qup", .pm = pm_ptr(&qup_i2c_qup_pm_ops), diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 9267df38c2d0..a7b77d14ee86 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1271,7 +1271,7 @@ static struct platform_driver rcar_i2c_driver = { .pm = pm_sleep_ptr(&rcar_i2c_pm_ops), }, .probe = rcar_i2c_probe, - .remove_new = rcar_i2c_remove, + .remove = rcar_i2c_remove, }; module_platform_driver(rcar_i2c_driver); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index c7f3a4c02470..c218f73c3650 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -632,7 +632,7 @@ static const struct of_device_id riic_i2c_dt_ids[] = { static struct platform_driver riic_i2c_driver = { .probe = riic_i2c_probe, - .remove_new = riic_i2c_remove, + .remove = riic_i2c_remove, .driver = { .name = "i2c-riic", .of_match_table = riic_i2c_dt_ids, diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 4ef9bad77b85..d4e9196445c0 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1398,7 +1398,7 @@ static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume); static struct platform_driver rk3x_i2c_driver = { .probe = rk3x_i2c_probe, - .remove_new = rk3x_i2c_remove, + .remove = rk3x_i2c_remove, .driver = { .name = "rk3x-i2c", .of_match_table = rk3x_i2c_match, diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c new file mode 100644 index 000000000000..e064e8a4a1f0 --- /dev/null +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/bits.h> +#include <linux/i2c.h> +#include <linux/i2c-mux.h> +#include <linux/mod_devicetable.h> +#include <linux/mfd/syscon.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +enum rtl9300_bus_freq { + RTL9300_I2C_STD_FREQ, + RTL9300_I2C_FAST_FREQ, +}; + +struct rtl9300_i2c; + +struct rtl9300_i2c_chan { + struct i2c_adapter adap; + struct rtl9300_i2c *i2c; + enum rtl9300_bus_freq bus_freq; + u8 sda_pin; +}; + +#define RTL9300_I2C_MUX_NCHAN 8 + +struct rtl9300_i2c { + struct regmap *regmap; + struct device *dev; + struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN]; + u32 reg_base; + u8 sda_pin; + struct mutex lock; +}; + +#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 + +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); + 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); +} + +static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin) +{ + 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_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); +} + +static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan, + u16 addr, u16 len) +{ + u32 val, mask; + + val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; + mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; + + val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS; + mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK; + + val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS; + mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK; + + mask |= RTL9300_I2C_MST_CTRL2_RD_MODE; + + return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); +} + +static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) +{ + u32 vals[4] = {}; + int i, ret; + + if (len > 16) + return -EIO; + + ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, + vals, ARRAY_SIZE(vals)); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + buf[i] = vals[i/4] & 0xff; + vals[i/4] >>= 8; + } + + return 0; +} + +static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len) +{ + u32 vals[4] = {}; + int i; + + if (len > 16) + return -EIO; + + for (i = 0; i < len; i++) { + if (i % 4 == 0) + vals[i/4] = 0; + vals[i/4] <<= 8; + vals[i/4] |= buf[i]; + } + + return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, + 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); +} + +static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, + int size, union i2c_smbus_data *data, int len) +{ + u32 val, mask; + int ret; + + val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0; + mask = RTL9300_I2C_MST_CTRL1_RWOP; + + val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; + mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; + + ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); + 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, 2000); + if (ret) + return ret; + + if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL) + 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 (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); + if (ret) + return ret; + data->word = val & 0xffff; + } else { + ret = rtl9300_i2c_read(i2c, &data->block[0], len); + if (ret) + return ret; + } + } + + return 0; +} + +static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) +{ + struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap); + struct rtl9300_i2c *i2c = chan->i2c; + int len = 0, 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; + } + + switch (size) { + case I2C_SMBUS_QUICK: + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); + if (ret) + goto out_unlock; + break; + + 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; + } + 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; + } + 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; + } + break; + + case I2C_SMBUS_BLOCK_DATA: + ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); + if (ret) + goto out_unlock; + if (read_write == I2C_SMBUS_WRITE) { + ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); + if (ret) + goto out_unlock; + } + len = data->block[0]; + break; + + default: + dev_err(&adap->dev, "Unsupported transaction %d\n", size); + ret = -EOPNOTSUPP; + goto out_unlock; + } + + ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len); + +out_unlock: + mutex_unlock(&i2c->lock); + + return ret; +} + +static u32 rtl9300_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm rtl9300_i2c_algo = { + .smbus_xfer = rtl9300_i2c_smbus_xfer, + .functionality = rtl9300_i2c_func, +}; + +static struct i2c_adapter_quirks rtl9300_i2c_quirks = { + .flags = I2C_AQ_NO_CLK_STRETCH, + .max_read_len = 16, + .max_write_len = 16, +}; + +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; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(i2c->regmap)) + return PTR_ERR(i2c->regmap); + i2c->dev = dev; + + mutex_init(&i2c->lock); + + ret = device_property_read_u32(dev, "reg", &i2c->reg_base); + if (ret) + return ret; + + platform_set_drvdata(pdev, i2c); + + if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) + return dev_err_probe(dev, -EINVAL, "Too many channels\n"); + + 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); + if (ret) + return ret; + + ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq); + if (ret) + clock_freq = I2C_MAX_STANDARD_MODE_FREQ; + + switch (clock_freq) { + 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); + break; + } + + chan->sda_pin = sda_pin; + chan->i2c = i2c; + adap = &i2c->chans[i].adap; + adap->owner = THIS_MODULE; + adap->algo = &rtl9300_i2c_algo; + adap->quirks = &rtl9300_i2c_quirks; + adap->retries = 3; + 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); + i++; + + ret = devm_i2c_add_adapter(dev, adap); + if (ret) + return ret; + } + i2c->sda_pin = 0xff; + + return 0; +} + +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" }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); + +static struct platform_driver rtl9300_i2c_driver = { + .probe = rtl9300_i2c_probe, + .driver = { + .name = "i2c-rtl9300", + .of_match_table = i2c_rtl9300_dt_ids, + }, +}; + +module_platform_driver(rtl9300_i2c_driver); + +MODULE_DESCRIPTION("RTL9300 I2C controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 8380a68538ab..02b76e24a476 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -536,7 +536,7 @@ static struct platform_driver rzv2m_i2c_driver = { .pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops), }, .probe = rzv2m_i2c_probe, - .remove_new = rzv2m_i2c_remove, + .remove = rzv2m_i2c_remove, }; module_platform_driver(rzv2m_i2c_driver); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 7698d9d59744..0f3cf500df68 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1176,7 +1176,7 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, - .remove_new = s3c24xx_i2c_remove, + .remove = s3c24xx_i2c_remove, .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c-i2c", diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index d7af8e0d7599..10a5146b3aa5 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -411,7 +411,7 @@ static void smbus_cmi_remove(struct platform_device *device) static struct platform_driver smbus_cmi_driver = { .probe = smbus_cmi_probe, - .remove_new = smbus_cmi_remove, + .remove = smbus_cmi_remove, .driver = { .name = "smbus_cmi", .acpi_match_table = acpi_smbus_cmi_ids, diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 8a043f5fca1e..620f12596763 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -552,7 +552,7 @@ static struct platform_driver sh7760_i2c_drv = { .name = SH7760_I2C_DEVNAME, }, .probe = sh7760_i2c_probe, - .remove_new = sh7760_i2c_remove, + .remove = sh7760_i2c_remove, }; module_platform_driver(sh7760_i2c_drv); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index f86c29737df1..efe29621b8d7 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -983,7 +983,7 @@ static struct platform_driver sh_mobile_i2c_driver = { .pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops), }, .probe = sh_mobile_i2c_probe, - .remove_new = sh_mobile_i2c_remove, + .remove = sh_mobile_i2c_remove, }; static int __init sh_mobile_i2c_adap_init(void) diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 18516bc64e04..d90606048611 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -144,7 +144,7 @@ static struct platform_driver simtec_i2c_driver = { .name = "simtec-i2c", }, .probe = simtec_i2c_probe, - .remove_new = simtec_i2c_remove, + .remove = simtec_i2c_remove, }; module_platform_driver(simtec_i2c_driver); diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 9c45e75b9187..56b2e5c5fb49 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -643,7 +643,7 @@ MODULE_DEVICE_TABLE(of, sprd_i2c_of_match); static struct platform_driver sprd_i2c_driver = { .probe = sprd_i2c_probe, - .remove_new = sprd_i2c_remove, + .remove = sprd_i2c_remove, .driver = { .name = "sprd-i2c", .of_match_table = sprd_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 05b19ede65a0..750fff3d2389 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -893,7 +893,7 @@ static struct platform_driver st_i2c_driver = { .pm = pm_sleep_ptr(&st_i2c_pm), }, .probe = st_i2c_probe, - .remove_new = st_i2c_remove, + .remove = st_i2c_remove, }; module_platform_driver(st_i2c_driver); diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 230fff0c0bf9..b3d56d0aa9d0 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -869,7 +869,7 @@ static struct platform_driver stm32f4_i2c_driver = { .of_match_table = stm32f4_i2c_match, }, .probe = stm32f4_i2c_probe, - .remove_new = stm32f4_i2c_remove, + .remove = stm32f4_i2c_remove, }; module_platform_driver(stm32f4_i2c_driver); diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 0174ead99de6..973a3a8c6d4a 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2532,7 +2532,7 @@ static struct platform_driver stm32f7_i2c_driver = { .pm = &stm32f7_i2c_pm_ops, }, .probe = stm32f7_i2c_probe, - .remove_new = stm32f7_i2c_remove, + .remove = stm32f7_i2c_remove, }; module_platform_driver(stm32f7_i2c_driver); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index 074eade6c4a4..fb5280b8cf7f 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -319,7 +319,7 @@ static void p2wi_remove(struct platform_device *dev) static struct platform_driver p2wi_driver = { .probe = p2wi_probe, - .remove_new = p2wi_remove, + .remove = p2wi_remove, .driver = { .name = "i2c-sunxi-p2wi", .of_match_table = p2wi_of_match_table, diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index bbb9062669e4..31f8d08e32a4 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -629,7 +629,7 @@ MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids); static struct platform_driver synquacer_i2c_driver = { .probe = synquacer_i2c_probe, - .remove_new = synquacer_i2c_remove, + .remove = synquacer_i2c_remove, .driver = { .name = "synquacer_i2c", .of_match_table = of_match_ptr(synquacer_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index dabadbcc6d6a..bb0de6db6391 100644 --- a/drivers/i2c/busses/i2c-tegra-bpmp.c +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -335,7 +335,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = { .of_match_table = tegra_bpmp_i2c_of_match, }, .probe = tegra_bpmp_i2c_probe, - .remove_new = tegra_bpmp_i2c_remove, + .remove = tegra_bpmp_i2c_remove, }; module_platform_driver(tegra_bpmp_i2c_driver); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 1df5b4204142..87976e99e6d0 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -1964,7 +1964,7 @@ MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match); static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, - .remove_new = tegra_i2c_remove, + .remove = tegra_i2c_remove, .driver = { .name = "tegra-i2c", .of_match_table = tegra_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index 10a99cd08972..d877f5a1f579 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -615,7 +615,7 @@ MODULE_DEVICE_TABLE(of, uniphier_fi2c_match); static struct platform_driver uniphier_fi2c_drv = { .probe = uniphier_fi2c_probe, - .remove_new = uniphier_fi2c_remove, + .remove = uniphier_fi2c_remove, .driver = { .name = "uniphier-fi2c", .of_match_table = uniphier_fi2c_match, diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index ef5753307469..b95d50d4d7db 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(of, uniphier_i2c_match); static struct platform_driver uniphier_i2c_drv = { .probe = uniphier_i2c_probe, - .remove_new = uniphier_i2c_remove, + .remove = uniphier_i2c_remove, .driver = { .name = "uniphier-i2c", .of_match_table = uniphier_i2c_match, diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 76abfa77e200..a1ab6ef6f071 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -109,7 +109,7 @@ MODULE_DEVICE_TABLE(of, i2c_versatile_match); static struct platform_driver i2c_versatile_driver = { .probe = i2c_versatile_probe, - .remove_new = i2c_versatile_remove, + .remove = i2c_versatile_remove, .driver = { .name = "versatile-i2c", .of_match_table = i2c_versatile_match, diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 3415683dab91..4eb740faf268 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -169,7 +169,7 @@ static const struct of_device_id wmt_i2c_dt_ids[] = { static struct platform_driver wmt_i2c_driver = { .probe = wmt_i2c_probe, - .remove_new = wmt_i2c_remove, + .remove = wmt_i2c_remove, .driver = { .name = "wmt-i2c", .of_match_table = wmt_i2c_dt_ids, diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 2ed4130c0339..503e2f4d6f84 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -415,7 +415,7 @@ static void vprbrd_i2c_remove(struct platform_device *pdev) static struct platform_driver vprbrd_i2c_driver = { .driver.name = "viperboard-i2c", .probe = vprbrd_i2c_probe, - .remove_new = vprbrd_i2c_remove, + .remove = vprbrd_i2c_remove, }; static int __init vprbrd_i2c_init(void) diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 658396c9eeab..663fe5604dd6 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -581,7 +581,7 @@ MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); static struct platform_driver xgene_slimpro_i2c_driver = { .probe = xgene_slimpro_i2c_probe, - .remove_new = xgene_slimpro_i2c_remove, + .remove = xgene_slimpro_i2c_remove, .driver = { .name = "xgene-slimpro-i2c", .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 1d68177241a6..c4d3eb02da09 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -1395,7 +1395,7 @@ static const struct dev_pm_ops xiic_dev_pm_ops = { static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, - .remove_new = xiic_i2c_remove, + .remove = xiic_i2c_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(xiic_of_match), diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 08a59a920929..4d5e49b6321b 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -579,7 +579,7 @@ MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); static struct platform_driver xlp9xx_i2c_driver = { .probe = xlp9xx_i2c_probe, - .remove_new = xlp9xx_i2c_remove, + .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 3648382b885a..4d6abd7e92ce 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -536,7 +536,7 @@ static struct platform_driver scx200_pci_driver = { .name = "cs5535-smb", }, .probe = scx200_probe, - .remove_new = scx200_remove, + .remove = scx200_remove, }; static const struct pci_device_id scx200_isa[] = { diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 7aa6e795d833..d6ef91b888c6 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -190,7 +190,7 @@ MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match); static struct platform_driver i2c_arbitrator_driver = { .probe = i2c_arbitrator_probe, - .remove_new = i2c_arbitrator_remove, + .remove = i2c_arbitrator_remove, .driver = { .name = "i2c-arb-gpio-challenge", .of_match_table = i2c_arbitrator_of_match, diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 7e2686b606c0..dce18f763a09 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -314,7 +314,7 @@ static struct platform_driver i2c_demux_pinctrl_driver = { .of_match_table = i2c_demux_pinctrl_of_match, }, .probe = i2c_demux_pinctrl_probe, - .remove_new = i2c_demux_pinctrl_remove, + .remove = i2c_demux_pinctrl_remove, }; module_platform_driver(i2c_demux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 944577bb09c1..9b46b84e84fb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -247,7 +247,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, - .remove_new = i2c_mux_gpio_remove, + .remove = i2c_mux_gpio_remove, .driver = { .name = "i2c-mux-gpio", .of_match_table = i2c_mux_gpio_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index 10d63307b14d..ab8e11661052 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -152,7 +152,7 @@ static void i2c_mux_remove(struct platform_device *pdev) static struct platform_driver i2c_mux_driver = { .probe = i2c_mux_probe, - .remove_new = i2c_mux_remove, + .remove = i2c_mux_remove, .driver = { .name = "i2c-mux-gpmux", .of_match_table = i2c_mux_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 3f06aa3331a7..1c2debcf379c 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -182,7 +182,7 @@ static struct platform_driver mlxcpld_mux_driver = { .name = "i2c-mux-mlxcpld", }, .probe = mlxcpld_mux_probe, - .remove_new = mlxcpld_mux_remove, + .remove = mlxcpld_mux_remove, }; module_platform_driver(mlxcpld_mux_driver); diff --git a/drivers/i2c/muxes/i2c-mux-mule.c b/drivers/i2c/muxes/i2c-mux-mule.c index 8e942470b35f..284ff4afeeac 100644 --- a/drivers/i2c/muxes/i2c-mux-mule.c +++ b/drivers/i2c/muxes/i2c-mux-mule.c @@ -66,8 +66,8 @@ static int mule_i2c_mux_probe(struct platform_device *pdev) priv = i2c_mux_priv(muxc); priv->regmap = dev_get_regmap(mux_dev->parent, NULL); - if (IS_ERR(priv->regmap)) - return dev_err_probe(mux_dev, PTR_ERR(priv->regmap), + if (!priv->regmap) + return dev_err_probe(mux_dev, -ENODEV, "No parent i2c register map\n"); platform_set_drvdata(pdev, muxc); diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 02aaf0781e9c..fc686a350ae8 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -186,7 +186,7 @@ static struct platform_driver i2c_mux_pinctrl_driver = { .of_match_table = i2c_mux_pinctrl_of_match, }, .probe = i2c_mux_pinctrl_probe, - .remove_new = i2c_mux_pinctrl_remove, + .remove = i2c_mux_pinctrl_remove, }; module_platform_driver(i2c_mux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index ef765fcd33f5..dfa472d514cc 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -247,7 +247,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_reg_of_match); static struct platform_driver i2c_mux_reg_driver = { .probe = i2c_mux_reg_probe, - .remove_new = i2c_mux_reg_remove, + .remove = i2c_mux_reg_remove, .driver = { .name = "i2c-mux-reg", .of_match_table = of_match_ptr(i2c_mux_reg_of_match), |