diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-08 11:46:10 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-08 11:46:10 -0800 |
| commit | dab334c98bf3563f57dc694242192f9e1cc95f96 (patch) | |
| tree | 6fa3ca1961d790c226e7054408317b0c84ccaebb /drivers | |
| parent | 206825f50f908771934e1fba2bfc2e1f1138b36a (diff) | |
| parent | c6f49acb52c79f8e84af2eda4fc002a2068a6c9e (diff) | |
| download | linux-dab334c98bf3563f57dc694242192f9e1cc95f96.tar.gz linux-dab334c98bf3563f57dc694242192f9e1cc95f96.tar.bz2 linux-dab334c98bf3563f57dc694242192f9e1cc95f96.zip | |
Merge branch 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
- big refactoring of the PASEMI driver to support the Apple M1
- huge improvements to the XIIC in terms of locking and SMP safety
- refactoring and clean ups for the i801 driver
... and the usual bunch of small driver updates
* 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (43 commits)
i2c: amd-mp2-plat: ACPI: Use ACPI_COMPANION() directly
i2c: i801: Add support for Intel Ice Lake PCH-N
i2c: virtio: update the maintainer to Conghui
i2c: xlr: Fix a resource leak in the error handling path of 'xlr_i2c_probe()'
i2c: qup: move to use request_irq by IRQF_NO_AUTOEN flag
i2c: qup: fix a trivial typo
i2c: tegra: Ensure that device is suspended before driver is removed
i2c: i801: Fix incorrect and needless software PEC disabling
i2c: mediatek: Dump i2c/dma register when a timeout occurs
i2c: mediatek: Reset the handshake signal between i2c and dma
i2c: mlxcpld: Allow flexible polling time setting for I2C transactions
i2c: pasemi: Set enable bit for Apple variant
i2c: pasemi: Add Apple platform driver
i2c: pasemi: Refactor _probe to use devm_*
i2c: pasemi: Allow to configure bus frequency
i2c: pasemi: Move common reset code to own function
i2c: pasemi: Split pci driver to its own file
i2c: pasemi: Split off common probing code
i2c: pasemi: Remove usage of pci_dev
i2c: pasemi: Use dev_name instead of port number
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/i2c/busses/Makefile | 3 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-amd-mp2-pci.c | 4 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-amd-mp2-plat.c | 5 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-bcm-kona.c | 2 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 83 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-ismt.c | 12 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-kempld.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-mlxcpld.c | 14 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-mt65xx.c | 82 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pasemi-core.c (renamed from drivers/i2c/busses/i2c-pasemi.c) | 114 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pasemi-core.h | 21 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pasemi-pci.c | 85 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pasemi-platform.c | 122 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-qup.c | 6 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 6 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 4 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-xiic.c | 161 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-xlr.c | 6 |
20 files changed, 490 insertions, 260 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e17790fe35a7..dce392839017 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -615,7 +615,10 @@ config I2C_EXYNOS5 depends on ARCH_EXYNOS || COMPILE_TEST default y if ARCH_EXYNOS help - High-speed I2C controller on Exynos5 and newer Samsung SoCs. + High-speed I2C controller on Samsung Exynos5 and newer Samsung SoCs: + Exynos5250, Exynos5260, Exynos5410, Exynos542x, Exynos5800, + Exynos5433 and Exynos7. + Choose Y here only if you build for such Samsung SoC. config I2C_GPIO tristate "GPIO-based bitbanging I2C" @@ -856,6 +859,17 @@ config I2C_PASEMI help Supports the PA Semi PWRficient on-chip SMBus interfaces. +config I2C_APPLE + tristate "Apple SMBus platform driver" + depends on ARCH_APPLE || COMPILE_TEST + default ARCH_APPLE + help + Say Y here if you want to use the I2C controller present on Apple + Silicon chips such as the M1. + + This driver can also be built as a module. If so, the module + will be called i2c-apple. + config I2C_PCA_PLATFORM tristate "PCA9564/PCA9665 as platform device" select I2C_ALGOPCA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 1336b04f40e2..d85899fef8c7 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -84,7 +84,10 @@ obj-$(CONFIG_I2C_NPCM7XX) += i2c-npcm7xx.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_OWL) += i2c-owl.o +i2c-pasemi-objs := i2c-pasemi-core.o i2c-pasemi-pci.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o +i2c-apple-objs := i2c-pasemi-core.o i2c-pasemi-platform.o +obj-$(CONFIG_I2C_APPLE) += i2c-apple.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index ce130a821ea5..adf0e8c1ec01 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -307,9 +307,9 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, pci_set_master(pci_dev); - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64)); + rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64)); if (rc) { - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (rc) goto err_dma_mask; } diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index de058671f9b8..84b7e6cbc67b 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -246,12 +246,11 @@ static int i2c_amd_probe(struct platform_device *pdev) { int ret; struct amd_i2c_dev *i2c_dev; - acpi_handle handle = ACPI_HANDLE(&pdev->dev); - struct acpi_device *adev; + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct amd_mp2_dev *mp2_dev; const char *uid; - if (acpi_bus_get_device(handle, &adev)) + if (!adev) return -ENODEV; /* The ACPI namespace doesn't contain information about which MP2 PCI diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index ed5e1275ae46..8e350f20cde0 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -763,7 +763,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) /* Map hardware registers */ dev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->base)) - return -ENOMEM; + return PTR_ERR(dev->base); /* Get and enable external clock */ dev->external_clk = devm_clk_get(dev->device, NULL); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 89ae78ef1a1c..05187457f88a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,6 +64,7 @@ * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes * Cedar Fork (PCH) 0x18df 32 hard yes yes yes * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes + * Ice Lake-N (PCH) 0x38a3 32 hard yes yes yes * Comet Lake (PCH) 0x02a3 32 hard yes yes yes * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes @@ -218,6 +219,7 @@ #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 #define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 +#define PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS 0x38a3 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 #define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 @@ -1042,6 +1044,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, @@ -1192,7 +1195,7 @@ static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, kfree(info); - *((bool *)return_value) = true; + *return_value = NULL; return AE_CTRL_TERMINATE; smo88xx_not_found: @@ -1202,11 +1205,9 @@ smo88xx_not_found: static bool is_dell_system_with_lis3lv02d(void) { - bool found; - const char *vendor; + void *err = ERR_PTR(-ENOENT); - vendor = dmi_get_system_info(DMI_SYS_VENDOR); - if (!vendor || strcmp(vendor, "Dell Inc.")) + if (!dmi_match(DMI_SYS_VENDOR, "Dell Inc.")) return false; /* @@ -1217,11 +1218,9 @@ static bool is_dell_system_with_lis3lv02d(void) * accelerometer but unfortunately ACPI does not provide any other * information (like I2C address). */ - found = false; - acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, - (void **)&found); + acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, &err); - return found; + return !IS_ERR(err); } /* @@ -1395,7 +1394,7 @@ static const struct dmi_system_id mux_dmi_table[] = { }; /* Setup multiplexing if needed */ -static int i801_add_mux(struct i801_priv *priv) +static void i801_add_mux(struct i801_priv *priv) { struct device *dev = &priv->adapter.dev; const struct i801_mux_config *mux_config; @@ -1404,7 +1403,7 @@ static int i801_add_mux(struct i801_priv *priv) int i; if (!priv->mux_drvdata) - return 0; + return; mux_config = priv->mux_drvdata; /* Prepare the platform data */ @@ -1420,13 +1419,11 @@ static int i801_add_mux(struct i801_priv *priv) struct_size(lookup, table, mux_config->n_gpios + 1), GFP_KERNEL); if (!lookup) - return -ENOMEM; + return; lookup->dev_id = "i2c-mux-gpio"; - for (i = 0; i < mux_config->n_gpios; i++) { - lookup->table[i] = (struct gpiod_lookup) - GPIO_LOOKUP(mux_config->gpio_chip, - mux_config->gpios[i], "mux", 0); - } + for (i = 0; i < mux_config->n_gpios; i++) + lookup->table[i] = GPIO_LOOKUP(mux_config->gpio_chip, + mux_config->gpios[i], "mux", 0); gpiod_add_lookup_table(lookup); priv->lookup = lookup; @@ -1444,8 +1441,6 @@ static int i801_add_mux(struct i801_priv *priv) gpiod_remove_lookup_table(lookup); dev_err(dev, "Failed to register i2c-mux-gpio device\n"); } - - return PTR_ERR_OR_ZERO(priv->mux_pdev); } static void i801_del_mux(struct i801_priv *priv) @@ -1475,7 +1470,7 @@ static unsigned int i801_get_adapter_class(struct i801_priv *priv) return class; } #else -static inline int i801_add_mux(struct i801_priv *priv) { return 0; } +static inline void i801_add_mux(struct i801_priv *priv) { } static inline void i801_del_mux(struct i801_priv *priv) { } static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) @@ -1493,7 +1488,6 @@ static struct platform_device * i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, struct resource *tco_res) { - static DEFINE_MUTEX(p2sb_mutex); struct resource *res; unsigned int devfn; u64 base64_addr; @@ -1506,7 +1500,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, * enumerated by the PCI subsystem, so we need to unhide/hide it * to lookup the P2SB BAR. */ - mutex_lock(&p2sb_mutex); + pci_lock_rescan_remove(); devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); @@ -1524,7 +1518,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, /* Hide the P2SB device, if it was hidden before */ if (hidden) pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); - mutex_unlock(&p2sb_mutex); + pci_unlock_rescan_remove(); res = &tco_res[1]; if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) @@ -1624,7 +1618,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * BIOS is accessing the host controller so prevent it from * suspending automatically from now on. */ - pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + pm_runtime_get_sync(&pdev->dev); } if ((function & ACPI_IO_MASK) == ACPI_READ) @@ -1639,31 +1633,22 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, static int i801_acpi_probe(struct i801_priv *priv) { - struct acpi_device *adev; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); acpi_status status; - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (adev) { - status = acpi_install_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, - NULL, priv); - if (ACPI_SUCCESS(status)) - return 0; - } + status = acpi_install_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, + i801_acpi_io_handler, NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); } static void i801_acpi_remove(struct i801_priv *priv) { - struct acpi_device *adev; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (!adev) - return; - - acpi_remove_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); + acpi_remove_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); } #else static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } @@ -1675,7 +1660,6 @@ static void i801_setup_hstcfg(struct i801_priv *priv) unsigned char hstcfg = priv->original_hstcfg; hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ - hstcfg &= ~SMBHSTCNT_PEC_EN; /* Disable software PEC */ hstcfg |= SMBHSTCFG_HST_EN; pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); } @@ -1720,6 +1704,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: case PCI_DEVICE_ID_INTEL_CDF_SMBUS: case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS: case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: @@ -1831,19 +1816,12 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features &= ~FEATURE_IRQ; if (priv->features & FEATURE_IRQ) { - u16 pcictl, pcists; + u16 pcists; /* Complain if an interrupt is already pending */ pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists); if (pcists & PCI_STATUS_INTERRUPT) dev_warn(&dev->dev, "An interrupt is pending!\n"); - - /* Check if interrupts have been disabled */ - pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pcictl); - if (pcictl & PCI_COMMAND_INTX_DISABLE) { - dev_info(&dev->dev, "Interrupts are disabled\n"); - priv->features &= ~FEATURE_IRQ; - } } if (priv->features & FEATURE_IRQ) { @@ -1891,9 +1869,6 @@ static void i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - pm_runtime_forbid(&dev->dev); - pm_runtime_get_noresume(&dev->dev); - i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); @@ -1902,6 +1877,10 @@ static void i801_remove(struct pci_dev *dev) platform_device_unregister(priv->tco_pdev); + /* if acpi_reserved is set then usage_count is incremented already */ + if (!priv->acpi_reserved) + pm_runtime_get_noresume(&dev->dev); + /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index a6187cbec2c9..f4820fd3dc13 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -918,13 +918,11 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)) != 0)) { - dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", - pdev); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "dma_set_mask fail\n"); return -ENODEV; } } diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index 2d60be086b1a..5bbb7f0d7852 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -283,7 +283,8 @@ static const struct i2c_algorithm kempld_i2c_algorithm = { static const struct i2c_adapter kempld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-kempld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | + I2C_CLASS_DEPRECATED, .algo = &kempld_i2c_algorithm, }; diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 015e11c4663f..56aa424fd71d 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -27,7 +27,7 @@ #define MLXCPLD_I2C_MAX_ADDR_LEN 4 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ -#define MLXCPLD_I2C_POLL_TIME 400 /* usec */ +#define MLXCPLD_I2C_POLL_TIME 200 /* usec */ /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 @@ -73,6 +73,7 @@ struct mlxcpld_i2c_priv { struct mlxcpld_i2c_curr_xfer xfer; struct device *dev; bool smbus_block; + int polling_time; }; static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) @@ -267,8 +268,8 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) do { if (!mlxcpld_i2c_check_busy(priv)) break; - usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); - timeout += MLXCPLD_I2C_POLL_TIME; + usleep_range(priv->polling_time / 2, priv->polling_time); + timeout += priv->polling_time; } while (timeout <= MLXCPLD_I2C_XFER_TO); if (timeout > MLXCPLD_I2C_XFER_TO) @@ -288,10 +289,10 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) u8 datalen, val; do { - usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); + usleep_range(priv->polling_time / 2, priv->polling_time); if (!mlxcpld_i2c_check_status(priv, &status)) break; - timeout += MLXCPLD_I2C_POLL_TIME; + timeout += priv->polling_time; } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO); switch (status) { @@ -498,9 +499,11 @@ mlxcpld_i2c_set_frequency(struct mlxcpld_i2c_priv *priv, switch ((regval & data->mask) >> data->bit) { case MLXCPLD_I2C_FREQ_1000KHZ: freq = MLXCPLD_I2C_FREQ_1000KHZ_SET; + priv->polling_time /= 4; break; case MLXCPLD_I2C_FREQ_400KHZ: freq = MLXCPLD_I2C_FREQ_400KHZ_SET; + priv->polling_time /= 4; break; default: return 0; @@ -527,6 +530,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + priv->polling_time = MLXCPLD_I2C_POLL_TIME; /* Set I2C bus frequency if platform data provides this info. */ pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 7d4b3eb7077a..9ea427f53083 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> @@ -49,6 +50,8 @@ #define I2C_RD_TRANAC_VALUE 0x0001 #define I2C_SCL_MIS_COMP_VALUE 0x0000 #define I2C_CHN_CLR_FLAG 0x0000 +#define I2C_RELIABILITY 0x0010 +#define I2C_DMAACK_ENABLE 0x0008 #define I2C_DMA_CON_TX 0x0000 #define I2C_DMA_CON_RX 0x0001 @@ -127,6 +130,7 @@ enum I2C_REGS_OFFSET { OFFSET_HS, OFFSET_SOFTRESET, OFFSET_DCM_EN, + OFFSET_MULTI_DMA, OFFSET_PATH_DIR, OFFSET_DEBUGSTAT, OFFSET_DEBUGCTRL, @@ -194,8 +198,9 @@ static const u16 mt_i2c_regs_v2[] = { [OFFSET_TRANSFER_LEN_AUX] = 0x44, [OFFSET_CLOCK_DIV] = 0x48, [OFFSET_SOFTRESET] = 0x50, + [OFFSET_MULTI_DMA] = 0x8c, [OFFSET_SCL_MIS_COMP_POINT] = 0x90, - [OFFSET_DEBUGSTAT] = 0xe0, + [OFFSET_DEBUGSTAT] = 0xe4, [OFFSET_DEBUGCTRL] = 0xe8, [OFFSET_FIFO_STAT] = 0xf4, [OFFSET_FIFO_THRESH] = 0xf8, @@ -842,6 +847,57 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) return 0; } +static void i2c_dump_register(struct mtk_i2c *i2c) +{ + dev_dbg(i2c->dev, "SLAVE_ADDR: 0x%x, INTR_MASK: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_SLAVE_ADDR), + mtk_i2c_readw(i2c, OFFSET_INTR_MASK)); + dev_dbg(i2c->dev, "INTR_STAT: 0x%x, CONTROL: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_INTR_STAT), + mtk_i2c_readw(i2c, OFFSET_CONTROL)); + dev_dbg(i2c->dev, "TRANSFER_LEN: 0x%x, TRANSAC_LEN: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_TRANSFER_LEN), + mtk_i2c_readw(i2c, OFFSET_TRANSAC_LEN)); + dev_dbg(i2c->dev, "DELAY_LEN: 0x%x, HTIMING: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DELAY_LEN), + mtk_i2c_readw(i2c, OFFSET_TIMING)); + dev_dbg(i2c->dev, "START: 0x%x, EXT_CONF: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_START), + mtk_i2c_readw(i2c, OFFSET_EXT_CONF)); + dev_dbg(i2c->dev, "HS: 0x%x, IO_CONFIG: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_HS), + mtk_i2c_readw(i2c, OFFSET_IO_CONFIG)); + dev_dbg(i2c->dev, "DCM_EN: 0x%x, TRANSFER_LEN_AUX: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DCM_EN), + mtk_i2c_readw(i2c, OFFSET_TRANSFER_LEN_AUX)); + dev_dbg(i2c->dev, "CLOCK_DIV: 0x%x, FIFO_STAT: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_CLOCK_DIV), + mtk_i2c_readw(i2c, OFFSET_FIFO_STAT)); + dev_dbg(i2c->dev, "DEBUGCTRL : 0x%x, DEBUGSTAT: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DEBUGCTRL), + mtk_i2c_readw(i2c, OFFSET_DEBUGSTAT)); + if (i2c->dev_comp->regs == mt_i2c_regs_v2) { + dev_dbg(i2c->dev, "LTIMING: 0x%x, MULTI_DMA: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_LTIMING), + mtk_i2c_readw(i2c, OFFSET_MULTI_DMA)); + } + dev_dbg(i2c->dev, "\nDMA_INT_FLAG: 0x%x, DMA_INT_EN: 0x%x\n", + readl(i2c->pdmabase + OFFSET_INT_FLAG), + readl(i2c->pdmabase + OFFSET_INT_EN)); + dev_dbg(i2c->dev, "DMA_EN: 0x%x, DMA_CON: 0x%x\n", + readl(i2c->pdmabase + OFFSET_EN), + readl(i2c->pdmabase + OFFSET_CON)); + dev_dbg(i2c->dev, "DMA_TX_MEM_ADDR: 0x%x, DMA_RX_MEM_ADDR: 0x%x\n", + readl(i2c->pdmabase + OFFSET_TX_MEM_ADDR), + readl(i2c->pdmabase + OFFSET_RX_MEM_ADDR)); + dev_dbg(i2c->dev, "DMA_TX_LEN: 0x%x, DMA_RX_LEN: 0x%x\n", + readl(i2c->pdmabase + OFFSET_TX_LEN), + readl(i2c->pdmabase + OFFSET_RX_LEN)); + dev_dbg(i2c->dev, "DMA_TX_4G_MODE: 0x%x, DMA_RX_4G_MODE: 0x%x", + readl(i2c->pdmabase + OFFSET_TX_4G_MODE), + readl(i2c->pdmabase + OFFSET_RX_4G_MODE)); +} + static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, int num, int left_num) { @@ -851,6 +907,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, u16 restart_flag = 0; u16 dma_sync = 0; u32 reg_4g_mode; + u32 reg_dma_reset; u8 *dma_rd_buf = NULL; u8 *dma_wr_buf = NULL; dma_addr_t rpaddr = 0; @@ -864,6 +921,28 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, reinit_completion(&i2c->msg_complete); + if (i2c->dev_comp->apdma_sync && + i2c->op != I2C_MASTER_WRRD && num > 1) { + mtk_i2c_writew(i2c, 0x00, OFFSET_DEBUGCTRL); + writel(I2C_DMA_HANDSHAKE_RST | I2C_DMA_WARM_RST, + i2c->pdmabase + OFFSET_RST); + + ret = readw_poll_timeout(i2c->pdmabase + OFFSET_RST, + reg_dma_reset, + !(reg_dma_reset & I2C_DMA_WARM_RST), + 0, 100); + if (ret) { + dev_err(i2c->dev, "DMA warm reset timeout\n"); + return -ETIMEDOUT; + } + + writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST); + mtk_i2c_writew(i2c, I2C_HANDSHAKE_RST, OFFSET_SOFTRESET); + mtk_i2c_writew(i2c, I2C_CHN_CLR_FLAG, OFFSET_SOFTRESET); + mtk_i2c_writew(i2c, I2C_RELIABILITY | I2C_DMAACK_ENABLE, + OFFSET_DEBUGCTRL); + } + control_reg = mtk_i2c_readw(i2c, OFFSET_CONTROL) & ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS); if ((i2c->speed_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) || (left_num >= 1)) @@ -1049,6 +1128,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, if (ret == 0) { dev_dbg(i2c->dev, "addr: %x, transfer timeout\n", msgs->addr); + i2c_dump_register(i2c); mtk_i2c_init_hw(i2c); return -ETIMEDOUT; } diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi-core.c index 20f2772c0e79..4e161a4089d8 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi-core.c @@ -15,20 +15,14 @@ #include <linux/slab.h> #include <linux/io.h> -static struct pci_driver pasemi_smb_driver; - -struct pasemi_smbus { - struct pci_dev *dev; - struct i2c_adapter adapter; - unsigned long base; - int size; -}; +#include "i2c-pasemi-core.h" /* Register offsets */ #define REG_MTXFIFO 0x00 #define REG_MRXFIFO 0x04 #define REG_SMSTA 0x14 #define REG_CTL 0x1c +#define REG_REV 0x28 /* Register defs */ #define MTXFIFO_READ 0x00000400 @@ -44,30 +38,36 @@ struct pasemi_smbus { #define CTL_MRR 0x00000400 #define CTL_MTR 0x00000200 +#define CTL_EN 0x00000800 #define CTL_CLK_M 0x000000ff -#define CLK_100K_DIV 84 -#define CLK_400K_DIV 21 - static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val) { - dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n", - smbus->base + reg, val); - outl(val, smbus->base + reg); + dev_dbg(smbus->dev, "smbus write reg %x val %08x\n", reg, val); + iowrite32(val, smbus->ioaddr + reg); } static inline int reg_read(struct pasemi_smbus *smbus, int reg) { int ret; - ret = inl(smbus->base + reg); - dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n", - smbus->base + reg, ret); + ret = ioread32(smbus->ioaddr + reg); + dev_dbg(smbus->dev, "smbus read reg %x val %08x\n", reg, ret); return ret; } #define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg)) #define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO) +static void pasemi_reset(struct pasemi_smbus *smbus) +{ + u32 val = (CTL_MTR | CTL_MRR | (smbus->clk_div & CTL_CLK_M)); + + if (smbus->hw_rev >= 6) + val |= CTL_EN; + + reg_write(smbus, REG_CTL, val); +} + static void pasemi_smb_clear(struct pasemi_smbus *smbus) { unsigned int status; @@ -93,7 +93,7 @@ static int pasemi_smb_waitready(struct pasemi_smbus *smbus) return -ENXIO; if (timeout < 0) { - dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status); + dev_warn(smbus->dev, "Timeout, status 0x%08x\n", status); reg_write(smbus, REG_SMSTA, status); return -ETIME; } @@ -142,8 +142,7 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, return 0; reset_out: - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + pasemi_reset(smbus); return err; } @@ -309,8 +308,7 @@ static int pasemi_smb_xfer(struct i2c_adapter *adapter, return 0; reset_out: - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + pasemi_reset(smbus); return err; } @@ -328,82 +326,28 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = pasemi_smb_func, }; -static int pasemi_smb_probe(struct pci_dev *dev, - const struct pci_device_id *id) +int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) { - struct pasemi_smbus *smbus; int error; - if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) - return -ENODEV; - - smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL); - if (!smbus) - return -ENOMEM; - - smbus->dev = dev; - smbus->base = pci_resource_start(dev, 0); - smbus->size = pci_resource_len(dev, 0); - - if (!request_region(smbus->base, smbus->size, - pasemi_smb_driver.name)) { - error = -EBUSY; - goto out_kfree; - } - smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), - "PA Semi SMBus adapter at 0x%lx", smbus->base); + "PA Semi SMBus adapter (%s)", dev_name(smbus->dev)); smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; /* set up the sysfs linkage to our parent device */ - smbus->adapter.dev.parent = &dev->dev; + smbus->adapter.dev.parent = smbus->dev; - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + if (smbus->hw_rev != PASEMI_HW_REV_PCI) + smbus->hw_rev = reg_read(smbus, REG_REV); - error = i2c_add_adapter(&smbus->adapter); - if (error) - goto out_release_region; + pasemi_reset(smbus); - pci_set_drvdata(dev, smbus); + error = devm_i2c_add_adapter(smbus->dev, &smbus->adapter); + if (error) + return error; return 0; - - out_release_region: - release_region(smbus->base, smbus->size); - out_kfree: - kfree(smbus); - return error; } - -static void pasemi_smb_remove(struct pci_dev *dev) -{ - struct pasemi_smbus *smbus = pci_get_drvdata(dev); - - i2c_del_adapter(&smbus->adapter); - release_region(smbus->base, smbus->size); - kfree(smbus); -} - -static const struct pci_device_id pasemi_smb_ids[] = { - { PCI_DEVICE(0x1959, 0xa003) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, pasemi_smb_ids); - -static struct pci_driver pasemi_smb_driver = { - .name = "i2c-pasemi", - .id_table = pasemi_smb_ids, - .probe = pasemi_smb_probe, - .remove = pasemi_smb_remove, -}; - -module_pci_driver(pasemi_smb_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); -MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); diff --git a/drivers/i2c/busses/i2c-pasemi-core.h b/drivers/i2c/busses/i2c-pasemi-core.h new file mode 100644 index 000000000000..4655124a37f3 --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi-core.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/de |
