From 743cc37561188e222eff5200d4507eabcccf9d41 Mon Sep 17 00:00:00 2001 From: Julia Cartwright Date: Thu, 9 Mar 2017 10:21:59 -0600 Subject: i2c: mux: pca954x: make use of raw_spinlock variants The pca954x i2c mux driver currently implements an irq_chip for handling interrupts; due to how irq_chip handling is done, it's necessary for the irq_chip methods to be invoked from hardirq context, even on a a real-time kernel. Because the spinlock_t type becomes a "sleeping" spinlock w/ RT kernels, it is not suitable to be used with irq_chips. A quick audit of the operations under the lock reveal that they do only minimal, bounded work, and are therefore safe to do under a raw spinlock. Signed-off-by: Julia Cartwright Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index dfc1c0e37c40..15dfc1648716 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -85,7 +85,7 @@ struct pca954x { struct irq_domain *irq; unsigned int irq_mask; - spinlock_t lock; + raw_spinlock_t lock; }; /* Provide specs for the PCA954x types we know about */ @@ -264,13 +264,13 @@ static void pca954x_irq_mask(struct irq_data *idata) unsigned int pos = idata->hwirq; unsigned long flags; - spin_lock_irqsave(&data->lock, flags); + raw_spin_lock_irqsave(&data->lock, flags); data->irq_mask &= ~BIT(pos); if (!data->irq_mask) disable_irq(data->client->irq); - spin_unlock_irqrestore(&data->lock, flags); + raw_spin_unlock_irqrestore(&data->lock, flags); } static void pca954x_irq_unmask(struct irq_data *idata) @@ -279,13 +279,13 @@ static void pca954x_irq_unmask(struct irq_data *idata) unsigned int pos = idata->hwirq; unsigned long flags; - spin_lock_irqsave(&data->lock, flags); + raw_spin_lock_irqsave(&data->lock, flags); if (!data->irq_mask) enable_irq(data->client->irq); data->irq_mask |= BIT(pos); - spin_unlock_irqrestore(&data->lock, flags); + raw_spin_unlock_irqrestore(&data->lock, flags); } static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) @@ -311,7 +311,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) if (!data->chip->has_irq || client->irq <= 0) return 0; - spin_lock_init(&data->lock); + raw_spin_lock_init(&data->lock); data->irq = irq_domain_add_linear(client->dev.of_node, data->chip->nchans, -- cgit v1.2.3 From 78c43af2c1d79653e2e6fb9a05c8f3def7c87940 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 20 Mar 2017 14:37:30 +0100 Subject: i2c-designware: increase timeout of semaphore transfer Our testing shows the semaphore failing to be transferred on CherryTrail in about 0.5% of all cases. The existing timeout needs to be lengthened to accommodate the worst cases. V2: Rebased on https://cgit.freedesktop.org/drm-intel/commit/?h=topic/designware-baytrail Signed-off-by: Oliver Neukum Reviewed-by: Hans de Goede Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-baytrail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index 1749a0f5a9fa..c0e7c8806342 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -22,7 +22,7 @@ #include "i2c-designware-core.h" -#define SEMAPHORE_TIMEOUT 100 +#define SEMAPHORE_TIMEOUT 500 #define PUNIT_SEMAPHORE 0x7 #define PUNIT_SEMAPHORE_CHT 0x10e #define PUNIT_SEMAPHORE_BIT BIT(0) -- cgit v1.2.3 From 41c80b8a63bccf9de96698b4eb0916e223fb6e72 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 13 Mar 2017 23:25:09 +0100 Subject: i2c: designware: Never suspend i2c-busses used for accessing the system PMIC Currently we are already setting a pm_runtime_disabled flag and disabling runtime-pm for i2c-busses used for accessing the system PMIC on x86. But this is not enough, there are ACPI opregions which may want to access the PMIC during late-suspend and early-resume, so we need to completely disable pm to be safe. This commit renames the flag from pm_runtime_disabled to pm_disabled and adds the following new behavior if the flag is set: 1) Call dev_pm_syscore_device(dev, true) which disables normal suspend / resume and remove the pm_runtime_disabled check from dw_i2c_plat_resume since that will now never get called. This fixes suspend_late handlers which use ACPI PMIC opregions causing errors like these: PM: Suspending system (freeze) PM: suspend of devices complete after 1127.751 msecs i2c_designware 808622C1:06: timeout waiting for bus ready ACPI Exception: AE_ERROR, Returned by Handler for [UserDefinedRegion] acpi 80860F14:02: Failed to change power state to D3hot PM: late suspend of devices failed 2) Set IRQF_NO_SUSPEND irq flag. This fixes resume_early handlers which handlers which use ACPI PMIC opregions causing errors like these: PM: resume from suspend-to-idle i2c_designware 808622C1:06: controller timed out ACPI Exception: AE_ERROR, Returned by Handler for [UserDefinedRegion] Signed-off-by: Hans de Goede Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-baytrail.c | 2 +- drivers/i2c/busses/i2c-designware-core.c | 11 +++++++++-- drivers/i2c/busses/i2c-designware-core.h | 4 ++-- drivers/i2c/busses/i2c-designware-platdrv.c | 10 ++++------ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index c0e7c8806342..1ac042972020 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -170,7 +170,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) dev_info(dev->dev, "I2C bus managed by PUNIT\n"); dev->acquire_lock = baytrail_i2c_acquire; dev->release_lock = baytrail_i2c_release; - dev->pm_runtime_disabled = true; + dev->pm_disabled = true; pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 15a534818d4f..c453717b753b 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -960,6 +960,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; + unsigned long irq_flags; int r; init_completion(&dev->cmd_complete); @@ -975,9 +976,15 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) adap->dev.parent = dev->dev; i2c_set_adapdata(adap, dev); + if (dev->pm_disabled) { + dev_pm_syscore_device(dev->dev, true); + irq_flags = IRQF_NO_SUSPEND; + } else { + irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND; + } + i2c_dw_disable_int(dev); - r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, - IRQF_SHARED | IRQF_COND_SUSPEND, + r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, dev_name(dev->dev), dev); if (r) { dev_err(dev->dev, "failure requesting irq %i: %d\n", diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 846ea57f85af..a7cf429daf60 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -79,7 +79,7 @@ * @pm_qos: pm_qos_request used while holding a hardware lock on the bus * @acquire_lock: function to acquire a hardware lock on the bus * @release_lock: function to release a hardware lock on the bus - * @pm_runtime_disabled: true if pm runtime is disabled + * @pm_disabled: true if power-management should be disabled for this i2c-bus * * HCNT and LCNT parameters can be used if the platform knows more accurate * values than the one computed based only on the input clock frequency. @@ -128,7 +128,7 @@ struct dw_i2c_dev { struct pm_qos_request pm_qos; int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); - bool pm_runtime_disabled; + bool pm_disabled; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d8665098dce9..0b6f6dc671a8 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -286,7 +286,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - if (dev->pm_runtime_disabled) { + if (dev->pm_disabled) { pm_runtime_forbid(&pdev->dev); } else { pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); @@ -302,7 +302,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) return r; exit_probe: - if (!dev->pm_runtime_disabled) + if (!dev->pm_disabled) pm_runtime_disable(&pdev->dev); exit_reset: if (!IS_ERR_OR_NULL(dev->rst)) @@ -322,7 +322,7 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); - if (!dev->pm_runtime_disabled) + if (!dev->pm_disabled) pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -374,9 +374,7 @@ static int dw_i2c_plat_resume(struct device *dev) struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); i2c_dw_plat_prepare_clk(i_dev, true); - - if (!i_dev->pm_runtime_disabled) - i2c_dw_init(i_dev); + i2c_dw_init(i_dev); return 0; } -- cgit v1.2.3 From a3d411fb38c0472ce96aea58062db87cc9357780 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 13 Mar 2017 23:25:10 +0100 Subject: i2c: designware: Disable pm for PMIC i2c-bus even if there is no _SEM method Cherrytrail devices use the dw i2c-bus with uid 7 to access their PMIC. Even if the i2c-bus to the PMIC is not shared with the SoC's P-Unit and i2c-designware-baytrail.c thus does not set the pm_disabled flag, we still need to disable pm so that ACPI PMIC opregions can access the PMIC during late-suspend and early-resume. This fixes errors like these blocking suspend: i2c_designware 808622C1:06: timeout waiting for bus ready ACPI Exception: AE_ERROR, Returned by Handler for [UserDefinedRegion] acpi 80860F14:02: Failed to change power state to D3hot PM: late suspend of devices failed Signed-off-by: Hans de Goede Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0b6f6dc671a8..a597ba32de7e 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -95,7 +95,10 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], static int dw_i2c_acpi_configure(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + acpi_handle handle = ACPI_HANDLE(&pdev->dev); const struct acpi_device_id *id; + struct acpi_device *adev; + const char *uid; dev->adapter.nr = -1; dev->tx_fifo_depth = 32; @@ -115,6 +118,18 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) if (id && id->driver_data) dev->flags |= (u32)id->driver_data; + if (acpi_bus_get_device(handle, &adev)) + return -ENODEV; + + /* + * Cherrytrail I2C7 gets used for the PMIC which gets accessed + * through ACPI opregions during late suspend / early resume + * disable pm for it. + */ + uid = adev->pnp.unique_id; + if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7")) + dev->pm_disabled = true; + return 0; } -- cgit v1.2.3 From 2e157681eb2f44f8a521ed91c76bfd62e29bb744 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Thu, 16 Mar 2017 21:17:20 +0800 Subject: dt-bindings: i2c: rk3x: add support for rk3328 The rk3328 i2c is the same as rk3399 Signed-off-by: Liang Chen Reviewed-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt index bbc5a1ed5fa1..e18445d0980c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt @@ -11,6 +11,7 @@ Required properties : - "rockchip,rk3188-i2c": for rk3188 - "rockchip,rk3228-i2c": for rk3228 - "rockchip,rk3288-i2c": for rk3288 + - "rockchip,rk3328-i2c", "rockchip,rk3399-i2c": for rk3328 - "rockchip,rk3399-i2c": for rk3399 - interrupts : interrupt number - clocks: See ../clock/clock-bindings.txt -- cgit v1.2.3 From 1ae5214a22f51b42d5f63161e70cf8af4803ff55 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 23 Mar 2017 11:56:56 +0000 Subject: i2c: tegra-bpmp: Enable Tegra BPMP I2C adapter Enable the Tegra BPMP I2C adapter by default if the Tegra BPMP itself is enabled. This adapter is used as the I2C interface for the PMIC on the Tegra186 Jetson-TX2 platform. Signed-off-by: Jon Hunter Acked-by: Thierry Reding Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8adc0f1d7ad0..39c0ead2a6df 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -933,6 +933,7 @@ config I2C_TEGRA config I2C_TEGRA_BPMP tristate "NVIDIA Tegra BPMP I2C controller" depends on TEGRA_BPMP + default y help If you say yes to this option, support will be included for the I2C controller embedded in NVIDIA Tegra SoCs accessed via the BPMP. -- cgit v1.2.3 From 074363a5a08c1be345c7d4bd6b0cf0d87a76c729 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 15 Mar 2017 12:31:34 +0100 Subject: i2c: mv64xxx: simplify optional reset handling As of commit bb475230b8e5 ("reset: make optional functions really optional"), the reset framework API calls use NULL pointers to describe optional, non-present reset controls. This allows to return errors from devm_reset_control_get_optional and to call reset_control_(de)assert unconditionally. Signed-off-by: Philipp Zabel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a50bd6891e27..cf737ec8563b 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -823,13 +823,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, drv_data->rstc = devm_reset_control_get_optional(dev, NULL); if (IS_ERR(drv_data->rstc)) { - if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) { - rc = -EPROBE_DEFER; - goto out; - } - } else { - reset_control_deassert(drv_data->rstc); + rc = PTR_ERR(drv_data->rstc); + goto out; } + reset_control_deassert(drv_data->rstc); /* Its not yet defined how timeouts will be specified in device tree. * So hard code the value to 1 second. @@ -951,8 +948,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) exit_free_irq: free_irq(drv_data->irq, drv_data); exit_reset: - if (!IS_ERR_OR_NULL(drv_data->rstc)) - reset_control_assert(drv_data->rstc); + reset_control_assert(drv_data->rstc); exit_clk: /* Not all platforms have a clk */ if (!IS_ERR(drv_data->clk)) @@ -968,8 +964,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); - if (!IS_ERR_OR_NULL(drv_data->rstc)) - reset_control_assert(drv_data->rstc); + reset_control_assert(drv_data->rstc); /* Not all platforms have a clk */ if (!IS_ERR(drv_data->clk)) clk_disable_unprepare(drv_data->clk); -- cgit v1.2.3 From 4165bd4b91b9328fda07da8b2d1f49707f54abe1 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sun, 12 Mar 2017 10:54:55 +0000 Subject: i2c: xlp9xx: update for ARCH_THUNDER2 ARCH_VULCAN arm64 platform (for Broadcom Vulcan ARM64 processors) has been discontinued. Cavium's ThunderX2 CN99XX (ARCH_THUNDER2) will be the next revision of the platform. Update compile dependencies and ACPI ID to reflect this change. There is not need to retain ARCH_VULCAN since the Vulcan processor was never in production and the config option will be removed soon. Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-xlp9xx.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 39c0ead2a6df..144cbadc7c72 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1022,7 +1022,7 @@ config I2C_XLR config I2C_XLP9XX tristate "XLP9XX I2C support" - depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST + depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST help This driver enables support for the on-chip I2C interface of the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors. diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 66b464d52c9c..ae80228104e9 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -432,6 +432,7 @@ MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { {"BRCM9007", 0}, + {"CAV9007", 0}, {} }; MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); -- cgit v1.2.3 From 346e400cfcebeb2a3dc3ede80cbd8b6fb95165ce Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 2 Mar 2017 11:34:07 +0100 Subject: i2c: thunderx: ACPI support for clock settings Add support for reading the system clock and the TWSI clock frequency from ACPI DSDT. TWSI clock was already covered by using device_property_read(). Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-thunderx-pcidrv.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index 1d4c2beacf2e..b4bc884cef93 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -85,17 +85,23 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) { int ret; - i2c->clk = clk_get(dev, NULL); - if (IS_ERR(i2c->clk)) { - i2c->clk = NULL; - goto skip; + if (acpi_disabled) { + /* DT */ + i2c->clk = clk_get(dev, NULL); + if (IS_ERR(i2c->clk)) { + i2c->clk = NULL; + goto skip; + } + + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto skip; + i2c->sys_freq = clk_get_rate(i2c->clk); + } else { + /* ACPI */ + device_property_read_u32(dev, "sclk", &i2c->sys_freq); } - ret = clk_prepare_enable(i2c->clk); - if (ret) - goto skip; - i2c->sys_freq = clk_get_rate(i2c->clk); - skip: if (!i2c->sys_freq) i2c->sys_freq = SYS_FREQ_DEFAULT; -- cgit v1.2.3 From 8edf52a1e92d24fa42425b100d8621874cf172e1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 13:58:30 +0100 Subject: i2c: meson: use min instead of min_t where min_t isn't needed Use min instead of min_t where min_t isn't needed. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 73b97c71a484..40e5da9a0af0 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -156,10 +156,10 @@ static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, rdata0, rdata1, len); - for (i = 0; i < min_t(int, 4, len); i++) + for (i = 0; i < min(4, len); i++) *buf++ = (rdata0 >> i * 8) & 0xff; - for (i = 4; i < min_t(int, 8, len); i++) + for (i = 4; i < min(8, len); i++) *buf++ = (rdata1 >> (i - 4) * 8) & 0xff; } @@ -168,10 +168,10 @@ static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) u32 wdata0 = 0, wdata1 = 0; int i; - for (i = 0; i < min_t(int, 4, len); i++) + for (i = 0; i < min(4, len); i++) wdata0 |= *buf++ << (i * 8); - for (i = 4; i < min_t(int, 8, len); i++) + for (i = 4; i < min(8, len); i++) wdata1 |= *buf++ << ((i - 4) * 8); writel(wdata0, i2c->regs + REG_TOK_WDATA0); @@ -186,7 +186,7 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) bool write = !(i2c->msg->flags & I2C_M_RD); int i; - i2c->count = min_t(int, i2c->msg->len - i2c->pos, 8); + i2c->count = min(i2c->msg->len - i2c->pos, 8); for (i = 0; i < i2c->count - 1; i++) meson_i2c_add_token(i2c, TOKEN_DATA); -- cgit v1.2.3 From a55cc70af61bb97f76cd4f8ab0fce979c6d0cd42 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:01:32 +0100 Subject: i2c: meson: remove member irq from struct meson_i2c Member irq can be replaced with a local variable in probe because it's nowhere else accessed. Signed-off-by: Heiner Kallweit Reviewed-by: Jerome Brunet Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 40e5da9a0af0..04614a6010d6 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -82,7 +82,6 @@ struct meson_i2c { struct device *dev; void __iomem *regs; struct clk *clk; - int irq; struct i2c_msg *msg; int state; @@ -391,7 +390,7 @@ static int meson_i2c_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct meson_i2c *i2c; struct resource *mem; - int ret = 0; + int irq, ret = 0; i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); if (!i2c) @@ -418,14 +417,13 @@ static int meson_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); - i2c->irq = platform_get_irq(pdev, 0); - if (i2c->irq < 0) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "can't find IRQ\n"); - return i2c->irq; + return irq; } - ret = devm_request_irq(&pdev->dev, i2c->irq, meson_i2c_irq, - 0, dev_name(&pdev->dev), i2c); + ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); if (ret < 0) { dev_err(&pdev->dev, "can't request IRQ\n"); return ret; -- cgit v1.2.3 From 09af1c2fa490169c40cbd153c5b83b5a70a0ec4b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:04:42 +0100 Subject: i2c: meson: set clock divider in probe instead of setting it for each transfer The bus frequency is fixed to what is set DT, therefore we can set the clock divider in probe already and we don't have to set it for each transfer. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 04614a6010d6..a692594fb82c 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -73,7 +73,6 @@ enum { * @error: Flag set when an error is received * @lock: To avoid race conditions between irq handler and xfer code * @done: Completion used to wait for transfer termination - * @frequency: Operating frequency of I2C bus clock * @tokens: Sequence of tokens to be written to the device * @num_tokens: Number of tokens */ @@ -92,7 +91,6 @@ struct meson_i2c { spinlock_t lock; struct completion done; - unsigned int frequency; u32 tokens[2]; int num_tokens; }; @@ -131,17 +129,17 @@ static void meson_i2c_write_tokens(struct meson_i2c *i2c) writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); } -static void meson_i2c_set_clk_div(struct meson_i2c *i2c) +static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) { unsigned long clk_rate = clk_get_rate(i2c->clk); unsigned int div; - div = DIV_ROUND_UP(clk_rate, i2c->frequency * 4); + div = DIV_ROUND_UP(clk_rate, freq * 4); meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, div << REG_CTRL_CLKDIV_SHIFT); dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, - clk_rate, i2c->frequency, div); + clk_rate, freq, div); } static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) @@ -361,7 +359,6 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int i, ret = 0, count = 0; clk_enable(i2c->clk); - meson_i2c_set_clk_div(i2c); for (i = 0; i < num; i++) { ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); @@ -390,15 +387,15 @@ static int meson_i2c_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct meson_i2c *i2c; struct resource *mem; + u32 freq; int irq, ret = 0; i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &i2c->frequency)) - i2c->frequency = DEFAULT_FREQ; + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", &freq)) + freq = DEFAULT_FREQ; i2c->dev = &pdev->dev; platform_set_drvdata(pdev, i2c); @@ -455,6 +452,8 @@ static int meson_i2c_probe(struct platform_device *pdev) return ret; } + meson_i2c_set_clk_div(i2c, freq); + return 0; } -- cgit v1.2.3 From 39b2ca68537aaf013ad192eb1c9e6b88e267d257 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:06:35 +0100 Subject: i2c: meson: use i2c core for DT clock-frequency parsing We don't have to parse the DT manually to retrieve the bus frequency and we don't have to maintain an own default for the bus frequency. Let the i2c core do this for us. Signed-off-by: Heiner Kallweit Reviewed-by: Jerome Brunet Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-meson.txt | 2 ++ drivers/i2c/busses/i2c-meson.c | 8 +++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt index 386357d1aab0..611b934c7e10 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-meson.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt @@ -8,6 +8,8 @@ Required properties: - #address-cells: should be <1> - #size-cells: should be <0> +For details regarding the following core I2C bindings see also i2c.txt. + Optional properties: - clock-frequency: the desired I2C bus clock frequency in Hz; in absence of this property the default value is used (100 kHz). diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index a692594fb82c..852db0f0bec2 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -38,7 +38,6 @@ #define REG_CTRL_CLKDIV_MASK ((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT) #define I2C_TIMEOUT_MS 500 -#define DEFAULT_FREQ 100000 enum { TOKEN_END = 0, @@ -387,15 +386,14 @@ static int meson_i2c_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct meson_i2c *i2c; struct resource *mem; - u32 freq; + struct i2c_timings timings; int irq, ret = 0; i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", &freq)) - freq = DEFAULT_FREQ; + i2c_parse_fw_timings(&pdev->dev, &timings, true); i2c->dev = &pdev->dev; platform_set_drvdata(pdev, i2c); @@ -452,7 +450,7 @@ static int meson_i2c_probe(struct platform_device *pdev) return ret; } - meson_i2c_set_clk_div(i2c, freq); + meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); return 0; } -- cgit v1.2.3 From 47bb8f71caba9f3c424d35a2ac18428aaa85348a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:07:57 +0100 Subject: i2c: meson: use full 12 bits for clock divider The clock divider has 12 bits, splitted into a 10 bit field and a 2 bit field. The extra 2 bits aren't used currently. Change this to use the full 12 bits and warn if the requested frequency is too low. Signed-off-by: Heiner Kallweit Acked-by: Jerome Brunet Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 852db0f0bec2..abaa7cae0936 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -35,7 +35,9 @@ #define REG_CTRL_STATUS BIT(2) #define REG_CTRL_ERROR BIT(3) #define REG_CTRL_CLKDIV_SHIFT 12 -#define REG_CTRL_CLKDIV_MASK ((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT) +#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12) +#define REG_CTRL_CLKDIVEXT_SHIFT 28 +#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28) #define I2C_TIMEOUT_MS 500 @@ -134,8 +136,18 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) unsigned int div; div = DIV_ROUND_UP(clk_rate, freq * 4); + + /* clock divider has 12 bits */ + if (div >= (1 << 12)) { + dev_err(i2c->dev, "requested bus frequency too low\n"); + div = (1 << 12) - 1; + } + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, - div << REG_CTRL_CLKDIV_SHIFT); + (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT); + + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK, + (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT); dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, clk_rate, freq, div); -- cgit v1.2.3 From e4d6bc380c9a3dd955a2c8c6c8856e913b1b42cb Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:09:03 +0100 Subject: i2c: meson: remove variable count from meson_i2c_xfer Variable count has always the same value as i, so we don't need it. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index abaa7cae0936..0a9847c37a63 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -367,7 +367,7 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct meson_i2c *i2c = adap->algo_data; - int i, ret = 0, count = 0; + int i, ret = 0; clk_enable(i2c->clk); @@ -375,12 +375,11 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); if (ret) break; - count++; } clk_disable(i2c->clk); - return ret ? ret : count; + return ret ?: i; } static u32 meson_i2c_func(struct i2c_adapter *adap) -- cgit v1.2.3 From 38ed55ca9ec2808ed7ee5183bec1f4e7187d3ea2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:10:08 +0100 Subject: i2c: meson: improve interrupt handler and detect spurious interrupts If state is STATE_IDLE no interrupt should occur. Return IRQ_NONE if such a spurious interrupt is detected. Not having to take care of STATE_IDLE later in the interrupt handler allows to further simplify the interrupt handler in subsequent patches of this series. In addition move resetting REG_CTRL_START bit to the start of the interrupt handler to ensure that the start bit is always reset. Currently the start bit is not reset for STATE_STOP because i2c->state is set to STATE_IDLE. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 0a9847c37a63..76aefd9264c2 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -231,12 +231,18 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) spin_lock(&i2c->lock); meson_i2c_reset_tokens(i2c); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); ctrl = readl(i2c->regs + REG_CTRL); dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n", i2c->state, i2c->pos, i2c->count, ctrl); - if (ctrl & REG_CTRL_ERROR && i2c->state != STATE_IDLE) { + if (i2c->state == STATE_IDLE) { + spin_unlock(&i2c->lock); + return IRQ_NONE; + } + + if (ctrl & REG_CTRL_ERROR) { /* * The bit is set when the IGNORE_NAK bit is cleared * and the device didn't respond. In this case, the @@ -279,15 +285,12 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) i2c->state = STATE_IDLE; complete(&i2c->done); break; - case STATE_IDLE: - break; } out: if (i2c->state != STATE_IDLE) { /* Restart the processing */ meson_i2c_write_tokens(i2c); - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); } -- cgit v1.2.3 From 3f205d7b47611f82316776c9ef7317525242307b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:11:08 +0100 Subject: i2c: meson: don't create separate token chain just for the stop command We can directly add the stop token to the token chain including the last transfer chunk. This is more efficient than creating a separate token chain just for the stop command. And it allows us to get rid of state STATE_STOP completely. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 76aefd9264c2..3b3be0c8d1f1 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -55,7 +55,6 @@ enum { STATE_IDLE, STATE_READ, STATE_WRITE, - STATE_STOP, }; /** @@ -208,19 +207,9 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) if (write) meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); -} - -static void meson_i2c_stop(struct meson_i2c *i2c) -{ - dev_dbg(i2c->dev, "%s: last %d\n", __func__, i2c->last); - if (i2c->last) { - i2c->state = STATE_STOP; + if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len) meson_i2c_add_token(i2c, TOKEN_STOP); - } else { - i2c->state = STATE_IDLE; - complete(&i2c->done); - } } static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) @@ -265,7 +254,8 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) } if (i2c->pos >= i2c->msg->len) { - meson_i2c_stop(i2c); + i2c->state = STATE_IDLE; + complete(&i2c->done); break; } @@ -275,16 +265,13 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) i2c->pos += i2c->count; if (i2c->pos >= i2c->msg->len) { - meson_i2c_stop(i2c); + i2c->state = STATE_IDLE; + complete(&i2c->done); break; } meson_i2c_prepare_xfer(i2c); break; - case STATE_STOP: - i2c->state = STATE_IDLE; - complete(&i2c->done); - break; } out: -- cgit v1.2.3 From 3911764cfbe7f5d229498d818aa2eff6e5611da8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:12:04 +0100 Subject: i2c: meson: remove meson_i2c_write_tokens meson_i2c_write_tokens is always called directly after meson_i2c_prepare_xfer (and only then). So we can simplify the code by removing meson_i2c_write_tokens and moving the two statements of meson_i2c_write_tokens to the end of meson_i2c_prepare_xfer. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 3b3be0c8d1f1..be9f83bd92fc 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -123,12 +123,6 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token) i2c->num_tokens++; } -static void meson_i2c_write_tokens(struct meson_i2c *i2c) -{ - writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); - writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); -} - static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) { unsigned long clk_rate = clk_get_rate(i2c->clk); @@ -210,6 +204,9 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len) meson_i2c_add_token(i2c, TOKEN_STOP); + + writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); + writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); } static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) @@ -275,12 +272,10 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) } out: - if (i2c->state != STATE_IDLE) { + if (i2c->state != STATE_IDLE) /* Restart the processing */ - meson_i2c_write_tokens(i2c); meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); - } spin_unlock(&i2c->lock); @@ -321,7 +316,6 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; meson_i2c_prepare_xfer(i2c); - meson_i2c_write_tokens(i2c); reinit_completion(&i2c->done); /* Start the transfer */ -- cgit v1.2.3 From cda816d163e08abb698f10ec32aa2d173ad93e7f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 25 Mar 2017 14:14:08 +0100 Subject: i2c: meson: improve and simplify interrupt handler The preceding changes in this patch series now allow to simplify the interrupt handler significantly. Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index be9f83bd92fc..88d15b92ec35 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -242,41 +242,21 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) goto out; } - switch (i2c->state) { - case STATE_READ: - if (i2c->count > 0) { - meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, - i2c->count); - i2c->pos += i2c->count; - } - - if (i2c->pos >= i2c->msg->len) { - i2c->state = STATE_IDLE; - complete(&i2c->done); - break; - } - - meson_i2c_prepare_xfer(i2c); - break; - case STATE_WRITE: - i2c->pos += i2c->count; + if (i2c->state == STATE_READ && i2c->count) + meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); - if (i2c->pos >= i2c->msg->len) { - i2c->state = STATE_IDLE; - complete(&i2c->done); - break; - } + i2c->pos += i2c->count; - meson_i2c_prepare_xfer(i2c); - break; + if (i2c->pos >= i2c->msg->len) { + i2c->state = STATE_IDLE; + complete(&i2c->done); + goto out; } + /* Restart the processing */ + meson_i2c_prepare_xfer(i2c); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); out: - if (i2c->state != STATE_IDLE) - /* Restart the processing */ - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, - REG_CTRL_START); - spin_unlock(&i2c->lock); return IRQ_HANDLED; -- cgit v1.2.3 From 8d4d159f25a79bdaf1f8ae5536471ba9b26b26c2 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 09:28:43 +0200 Subject: i2c: mux: provide more info on failure in i2c_mux_add_adapter No callers then need to report any further info, thus reducing both the amount of code and the log noise. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/i2c-mux.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 2178266bca79..26f7237558ba 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -395,13 +395,16 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, if (force_nr) { priv->adap.nr = force_nr; ret = i2c_add_numbered_adapter(&priv->adap); + dev_err(&parent->dev, + "failed to add mux-adapter %u as bus %u (error=%d)\n", + chan_id, force_nr, ret); } else { ret = i2c_add_adapter(&priv->adap); + dev_err(&parent->dev, + "failed to add mux-adapter %u (error=%d)\n", + chan_id, ret); } if (ret < 0) { - dev_err(&parent->dev, - "failed to add mux-adapter (error=%d)\n", - ret); kfree(priv); return ret; } -- cgit v1.2.3 From 1144d13eaaaec21a55614ca7ade2c8fc1d9f1685 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:06 +0200 Subject: i2c: arb: gpio-challenge: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 86fc2d4c081b..812b8cff265f 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -202,10 +202,8 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) /* Actually add the mux adapter */ ret = i2c_mux_add_adapter(muxc, 0, 0, 0); - if (ret) { - dev_err(dev, "Failed to add adapter\n"); + if (ret) i2c_put_adapter(muxc->parent); - } return ret; } -- cgit v1.2.3 From 1b00900fa0bdd4a634f6864efe3d07c216523688 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:11 +0200 Subject: i2c: mux: gpio: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-gpio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 655684d621a4..1a9973ede443 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -245,10 +245,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + if (ret) goto add_adapter_failed; - } } dev_info(&pdev->dev, "%d port mux on %s adapter\n", -- cgit v1.2.3 From 664d9bbadaf61c80a6e5c7c6c83f80a0731bc184 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:19 +0200 Subject: i2c: mux: pca9541: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca9541.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 77840f7845a1..9e318c9516c7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -369,10 +369,8 @@ static int pca9541_probe(struct i2c_client *client, i2c_set_clientdata(client, muxc); ret = i2c_mux_add_adapter(muxc, force, 0, 0); - if (ret) { - dev_err(&client->dev, "failed to register master selector\n"); + if (ret) return ret; - } dev_info(&client->dev, "registered master selector for I2C %s\n", client->name); -- cgit v1.2.3 From 0756ac323573406662c56d3f26a20b4382451c96 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:22 +0200 Subject: i2c: mux: pca954x: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 15dfc1648716..b2a85a2d00f7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -434,13 +434,8 @@ static int pca954x_probe(struct i2c_client *client, idle_disconnect_dt) << num; ret = i2c_mux_add_adapter(muxc, force, num, class); - - if (ret) { - dev_err(&client->dev, - "failed to register multiplexed adapter" - " %d as bus %d\n", num, force); + if (ret) goto fail_del_adapters; - } } dev_info(&client->dev, -- cgit v1.2.3 From c99a23e55fbe97acb235e7ebbd8800870c3e689f Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:25 +0200 Subject: i2c: mux: pinctrl: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pinctrl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 35bb775e1b74..7c0c264b07bc 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -245,10 +245,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) (mux->pdata->base_bus_num + i) : 0; ret = i2c_mux_add_adapter(muxc, bus, i, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + if (ret) goto err_del_adapter; - } } return 0; -- cgit v1.2.3 From f089236114cb09594d7e27a15ed72c2ebb669448 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 10:14:29 +0200 Subject: i2c: mux: reg: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-reg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index c6a90b4a9c62..406d5059072c 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -222,10 +222,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) class = mux->data.classes ? mux->data.classes[i] : 0; ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + if (ret) goto add_adapter_failed; - } } dev_dbg(&pdev->dev, "%d port mux on %s adapter\n", -- cgit v1.2.3 From 84ffac897161745b173eb879513bfa311549b7e4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Apr 2017 14:16:15 +0200 Subject: dt-bindings: i2c: mux: ltc4306: Add dt-bindings for I2C multiplexer/switch This patch adds support for the Analog Devices / Linear Technology LTC4306 and LTC4305 4/2 Channel I2C Bus Multiplexer/Switches. The LTC4306 optionally provides two general purpose input/output pins (GPIOs) that can be configured as logic inputs, opendrain outputs or push-pull outputs via the generic GPIOLIB framework. Signed-off-by: Michael Hennerich Acked-by: Rob Herring Signed-off-by: Peter Rosin --- .../devicetree/bindings/i2c/i2c-mux-ltc4306.txt | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt new file mode 100644 index 000000000000..1e98c6b3a721 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt @@ -0,0 +1,61 @@ +* Linear Technology / Analog Devices I2C bus switch + +Required Properties: + + - compatible: Must contain one of the following. + "lltc,ltc4305", "lltc,ltc4306" + - reg: The I2C address of the device. + + The following required properties are defined externally: + + - Standard I2C mux properties. See i2c-mux.txt in this directory. + - I2C child bus nodes. See i2c-mux.txt in this directory. + +Optional Properties: + + - enable-gpios: Reference to the GPIO connected to the enable input. + - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all + children in idle state. This is necessary for example, if there are several + multiplexers on the bus and the devices behind them use same I2C addresses. + - gpio-controller: Marks the device node as a GPIO Controller. + - #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - ltc,downstream-accelerators-enable: Enables the rise time accelerators + on the downstream port. + - ltc,upstream-accelerators-enable: Enables the rise time accelerators + on the upstream port. + +Example: + + ltc4306: i2c-mux@4a { + compatible = "lltc,ltc4306"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a>; + + gpio-controller; + #gpio-cells = <2>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + }; -- cgit v1.2.3 From dbed8a803bd3fb64339a6180adaff2cec46242ce Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Apr 2017 14:16:16 +0200 Subject: i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch This patch adds support for the Analog Devices / Linear Technology LTC4306 and LTC4305 4/2 Channel I2C Bus Multiplexer/Switches. The LTC4306 optionally provides two general purpose input/output pins (GPIOs) that can be configured as logic inputs, opendrain outputs or push-pull outputs via the generic GPIOLIB framework. Signed-off-by: Michael Hennerich Reviewed-by: Linus Walleij Signed-off-by: Peter Rosin --- MAINTAINERS | 8 + drivers/i2c/muxes/Kconfig | 11 ++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/i2c-mux-ltc4306.c | 322 ++++++++++++++++++++++++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 drivers/i2c/muxes/i2c-mux-ltc4306.c diff --git a/MAINTAINERS b/MAINTAINERS index c776906f67a9..9a27a197b1f6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7698,6 +7698,14 @@ S: Maintained F: Documentation/hwmon/ltc4261 F: drivers/hwmon/ltc4261.c +LTC4306 I2C MULTIPLEXER DRIVER +M: Michael Hennerich +W: http://ez.analog.com/community/linux-device-drivers +L: linux-i2c@vger.kernel.org +S: Supported +F: drivers/i2c/muxes/i2c-mux-ltc4306.c +F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt + LTP (Linux Test Project) M: Mike Frysinger M: Cyril Hrubis diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 10b3d17ae3ea..1e160fc37ecc 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -30,6 +30,17 @@ config I2C_MUX_GPIO This driver can also be built as a module. If so, the module will be called i2c-mux-gpio. +config I2C_MUX_LTC4306 + tristate "LTC LTC4306/5 I2C multiplexer" + select GPIOLIB + select REGMAP_I2C + help + If you say yes here you get support for the Analog Devices + LTC4306 or LTC4305 I2C mux/switch devices. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-ltc4306. + config I2C_MUX_PCA9541 tristate "NXP PCA9541 I2C Master Selector" help diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 9948fa45037f..ff7618cd5312 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o +obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c new file mode 100644 index 000000000000..311b1cced0c0 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -0,0 +1,322 @@ +/* + * Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch + * + * Copyright (C) 2017 Analog Devices Inc. + * + * Licensed under the GPL-2. + * + * Based on: i2c-mux-pca954x.c + * + * Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LTC4305_MAX_NCHANS 2 +#define LTC4306_MAX_NCHANS 4 + +#define LTC_REG_STATUS 0x0 +#define LTC_REG_CONFIG 0x1 +#define LTC_REG_MODE 0x2 +#define LTC_REG_SWITCH 0x3 + +#define LTC_DOWNSTREAM_ACCL_EN BIT(6) +#define LTC_UPSTREAM_ACCL_EN BIT(7) + +#define LTC_GPIO_ALL_INPUT 0xC0 +#define LTC_SWITCH_MASK 0xF0 + +enum ltc_type { + ltc_4305, + ltc_4306, +}; + +struct chip_desc { + u8 nchans; + u8 num_gpios; +}; + +struct ltc4306 { + struct regmap *regmap; + struct gpio_chip gpiochip; + const struct chip_desc *chip; +}; + +static const struct chip_desc chips[] = { + [ltc_4305] = { + .nchans = LTC4305_MAX_NCHANS, + }, + [ltc_4306] = { + .nchans = LTC4306_MAX_NCHANS, + .num_gpios = 2, + }, +}; + +static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg) +{ + return (reg == LTC_REG_CONFIG) ? true : false; +} + +static const struct regmap_config ltc4306_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LTC_REG_SWITCH, + .volatile_reg = ltc4306_is_volatile_reg, + .cache_type = REGCACHE_FLAT, +}; + +static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val); + if (ret < 0) + return ret; + + return !!(val & BIT(1 - offset)); +} + +static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + + regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset), + value ? BIT(5 - offset) : 0); +} + +static int ltc4306_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, LTC_REG_MODE, &val); + if (ret < 0) + return ret; + + return !!(val & BIT(7 - offset)); +} + +static int ltc4306_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + + return regmap_update_bits(data->regmap, LTC_REG_MODE, + BIT(7 - offset), BIT(7 - offset)); +} + +static int ltc4306_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + + ltc4306_gpio_set(chip, offset, value); + return regmap_update_bits(data->regmap, LTC_REG_MODE, + BIT(7 - offset), 0); +} + +static int ltc4306_gpio_set_config(struct gpio_chip *chip, + unsigned int offset, unsigned long config) +{ + struct ltc4306 *data = gpiochip_get_data(chip); + unsigned int val; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + val = 0; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + val = BIT(4 - offset); + break; + default: + return -ENOTSUPP; + } + + return regmap_update_bits(data->regmap, LTC_REG_MODE, + BIT(4 - offset), val); +} + +static int ltc4306_gpio_init(struct ltc4306 *data) +{ + struct device *dev = regmap_get_device(data->regmap); + + if (!data->chip->num_gpios) + return 0; + + data->gpiochip.label = dev_name(dev); + data->gpiochip.base = -1; + data->gpiochip.ngpio = data->chip->num_gpios; + data->gpiochip.parent = dev; + data->gpiochip.can_sleep = true; + data->gpiochip.get_direction = ltc4306_gpio_get_direction; + data->gpiochip.direction_input = ltc4306_gpio_direction_input; + data->gpiochip.direction_output = ltc4306_gpio_direction_output; + data->gpiochip.get = ltc4306_gpio_get; + data->gpiochip.set = ltc4306_gpio_set; + data->gpiochip.set_config = ltc4306_gpio_set_config; + data->gpiochip.owner = THIS_MODULE; + + /* gpiolib assumes all GPIOs default input */ + regmap_write(data->regmap, LTC_REG_MODE, LTC_GPIO_ALL_INPUT); + + return devm_gpiochip_add_data(dev, &data->gpiochip, data); +} + +static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct ltc4306 *data = i2c_mux_priv(muxc); + + return regmap_update_bits(data->regmap, LTC_REG_SWITCH, + LTC_SWITCH_MASK, BIT(7 - chan)); +} + +static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct ltc4306 *data = i2c_mux_priv(muxc); + + return regmap_update_bits(data->regmap, LTC_REG_SWITCH, + LTC_SWITCH_MASK, 0); +} + +static const struct i2c_device_id ltc4306_id[] = { + { "ltc4305", ltc_4305 }, + { "ltc4306", ltc_4306 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc4306_id); + +static const struct of_device_id ltc4306_of_match[] = { + { .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] }, + { .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc4306_of_match); + +static int ltc4306_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + const struct chip_desc *chip; + struct i2c_mux_core *muxc; + struct ltc4306 *data; + struct gpio_desc *gpio; + bool idle_disc; + unsigned int val = 0; + int num, ret; + + chip = of_device_get_match_data(&client->dev); + + if (!chip) + chip = &chips[id->driver_data]; + + idle_disc = device_property_read_bool(&client->dev, + "i2c-mux-idle-disconnect"); + + muxc = i2c_mux_alloc(adap, &client->dev, + chip->nchans, sizeof(*data), + I2C_MUX_LOCKED, ltc4306_select_mux, + idle_disc ? ltc4306_deselect_mux : NULL); + if (!muxc) + return -ENOMEM; + data = i2c_mux_priv(muxc); + data->chip = chip; + + i2c_set_clientdata(client, muxc); + + data->regmap = devm_regmap_init_i2c(client, <c4306_regmap_config); + if (IS_ERR(data->regmap)) { + ret = PTR_ERR(data->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + /* Reset and enable the mux if an enable GPIO is specified. */ + gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + if (gpio) { + udelay(1); + gpiod_set_value(gpio, 1); + } + + /* + * Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. + */ + if (regmap_write(data->regmap, LTC_REG_SWITCH, 0) < 0) { + dev_warn(&client->dev, "probe failed\n"); + return -ENODEV; + } + + if (device_property_read_bool(&client->dev, + "ltc,downstream-accelerators-enable")) + val |= LTC_DOWNSTREAM_ACCL_EN; + + if (device_property_read_bool(&client->dev, + "ltc,upstream-accelerators-enable")) + val |= LTC_UPSTREAM_ACCL_EN; + + if (regmap_write(data->regmap, LTC_REG_CONFIG, val) < 0) + return -ENODEV; + + ret = ltc4306_gpio_init(data); + if (ret < 0) + return ret; + + /* Now create an adapter for each channel */ + for (num = 0; num < chip->nchans; num++) { + ret = i2c_mux_add_adapter(muxc, 0, num, 0); + if (ret) { + i2c_mux_del_adapters(muxc); + return ret; + } + } + + dev_info(&client->dev, + "registered %d multiplexed busses for I2C switch %s\n", + num, client->name); + + return 0; +} + +static int ltc4306_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); + + return 0; +} + +static struct i2c_driver ltc4306_driver = { + .driver = { + .name = "ltc4306", + .of_match_table = of_match_ptr(ltc4306_of_match), + }, + .probe = ltc4306_probe, + .remove = ltc4306_remove, + .id_table = ltc4306_id, +}; + +module_i2c_driver(ltc4306_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e058e7a4bc89104540a8a303682248614b5df6f1 Mon Sep 17 00:00:00 2001 From: Edgar Cherkasov Date: Tue, 4 Apr 2017 19:18:27 +0300 Subject: i2c: i2c-scmi: add a MS HID Description of the problem: - i2c-scmi driver contains only two identifiers "SMBUS01" and "SMBUSIBM"; - the fist HID (SMBUS01) is clearly defined in "SMBus Control Method Interface Specification, version 1.0": "Each device must specify 'SMBUS01' as its _HID and use a unique _UID value"; - unfortunately, BIOS vendors (like AMI) seem to ignore this requirement and implement "SMB0001" HID instead of "SMBUS01"; - I speculate that they do this because only "SMB0001" is hard coded in Windows SMBus driver produced by Microsoft. This leads to following situation: - SMBus works out of box in Windows but not in Linux; - board vendors are forced to add correct "SMBUS01" HID to BIOS to make SMBus work in Linux. Moreover the same board vendors complain that tools (3-rd party ASL compiler) do not like the "SMBUS01" identifier and produce errors. So they need to constantly patch the compiler for each new version of BIOS. As it is very unlikely that BIOS vendors implement a correct HID in future, I would propose to consider whether it is possible to work around the problem by adding MS HID to the Linux i2c-scmi driver. v2: move the definition of the new HID to the driver itself. Signed-off-by: Edgar Cherkasov Signed-off-by: Michael Brunner Acked-by: Viktor Krasnov Reviewed-by: Jean Delvare Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-scmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index dfc98df7b1b6..7aa7b9cb6203 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -18,6 +18,9 @@ #define ACPI_SMBUS_HC_CLASS "smbus" #define ACPI_SMBUS_HC_DEVICE_NAME "cmi" +/* SMBUS HID definition as supported by Microsoft Windows */ +#define ACPI_SMBUS_MS_HID "SMB0001" + ACPI_MODULE_NAME("smbus_cmi"); struct smbus_methods_t { @@ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = { static const struct acpi_device_id acpi_smbus_cmi_ids[] = { {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, + {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); -- cgit v1.2.3 From 879bce228526c500bff3ed8ffec7bf89d98a9e11 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sun, 9 Apr 2017 09:41:31 +0800 Subject: i2c: img-scb: use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-img-scb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index db8e8b40569d..84fb35f6837f 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1362,9 +1362,8 @@ static int img_i2c_probe(struct platform_device *pdev) } /* Set up the exception check timer */ - init_timer(&i2c->check_timer); - i2c->check_timer.function = img_i2c_check_timer; - i2c->check_timer.data = (unsigned long)i2c; + setup_timer(&i2c->check_timer, img_i2c_check_timer, + (unsigned long)i2c); i2c->bitrate = timings[0].max_bitrate; if (!of_property_read_u32(node, "clock-frequency", &val)) -- cgit v1.2.3 From 417f784379c2b582d96bde2b438dc1ecb0abd7c3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Apr 2017 00:03:32 +0200 Subject: i2c: core: Allow getting ACPI info by index Modify struct i2c_acpi_lookup and i2c_acpi_fill_info() to allow using them to get the info from a certain index in the ACPI-resource list rather then taking the first I2cSerialBus resource. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d2402bbf6729..f7faa991a44c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -112,6 +112,8 @@ struct i2c_acpi_lookup { acpi_handle adapter_handle; acpi_handle device_handle; acpi_handle search_handle; + int n; + int index; u32 speed; u32 min_speed; }; @@ -130,6 +132,9 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) return 1; + if (lookup->index != -1 && lookup->n++ != lookup->index) + return 1; + status = acpi_get_handle(lookup->device_handle, sb->resource_source.string_ptr, &lookup->adapter_handle); @@ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev, memset(&lookup, 0, sizeof(lookup)); lookup.info = info; + lookup.index = -1; ret = i2c_acpi_do_lookup(adev, &lookup); if (ret) @@ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) lookup.search_handle = ACPI_HANDLE(dev); lookup.min_speed = UINT_MAX; lookup.info = &dummy; + lookup.index = -1; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, I2C_ACPI_MAX_SCAN_DEPTH, -- cgit v1.2.3 From 605f8fc2244236f8d6bf15bcc0586644af3a32e7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Apr 2017 00:03:33 +0200 Subject: i2c: core: Add new i2c_acpi_new_device helper function By default the i2c subsys creates an i2c-client for the first I2cSerialBus resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus resources and we may want to instantiate i2c-clients for the others. This commit adds a new i2c_acpi_new_device function which can be used to create an i2c-client for any I2cSerialBus resource of an acpi_device. Note that the other resources may even be on a different i2c bus, so just retrieving the client address is not enough. Here is an example DSDT excerpt from such a device: Device (WIDR) { Name (_HID, "INT33FE" /* XPOWER Battery Device */) Name (_CID, "INT33FE" /* XPOWER Battery Device */) Name (_DDN, "WC PMIC Battery Device") Name (RBUF, ResourceTemplate () { I2cSerialBusV2 (0x005E, ControllerInitiated, 0x000186A0, AddressingMode7Bit, "\\_SB.PCI0.I2C7", 0x00, ResourceConsumer, , Exclusive, ) I2cSerialBusV2 (0x0036, ControllerInitiated, 0x000186A0, AddressingMode7Bit, "\\_SB.PCI0.I2C1", 0x00, ResourceConsumer, , Exclusive, ) I2cSerialBusV2 (0x0022, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.PCI0.I2C1", 0x00, ResourceConsumer, , Exclusive, ) I2cSerialBusV2 (0x0054, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.PCI0.I2C1", 0x00, ResourceConsumer, , Exclusive, ) GpioInt (Level, ActiveLow, Exclusive, PullNone, 0x0000, "\\_SB.PCI0.I2C7.PMI5", 0x00, ResourceConsumer, , ) { // Pin list 0x0012 } GpioInt (Edge, ActiveLow, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPO1", 0x00, ResourceConsumer, , ) { // Pin list 0x0005 } GpioInt (Level, ActiveLow, Exclusive, PullNone, 0x0000, "\\_SB.PCI0.I2C7.PMI5", 0x00, ResourceConsumer, , ) { // Pin list 0x0013 } }) Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Return (RBUF) /* \_SB_.PCI0.I2C7.WIDR.RBUF */ } } Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c.h | 7 +++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f7faa991a44c..00c4cef716f7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -421,6 +421,55 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, static struct notifier_block i2c_acpi_notifier = { .notifier_call = i2c_acpi_notify, }; + +/** + * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource + * @dev: Device owning the ACPI resources to get the client from + * @index: Index of ACPI resource to get + * @info: describes the I2C device; note this is modified (addr gets set) + * Context: can sleep + * + * By default the i2c subsys creates an i2c-client for the first I2cSerialBus + * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus + * resources, in that case this function can be used to create an i2c-client + * for other I2cSerialBus resources in the Current Resource Settings table. + * + * Also see i2c_new_device, which this function calls to create the i2c-client. + * + * Returns a pointer to the new i2c-client, or NULL if the adapter is not found. + */ +struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, + struct i2c_board_info *info) +{ + struct i2c_acpi_lookup lookup; + struct i2c_adapter *adapter; + struct acpi_device *adev; + LIST_HEAD(resource_list); + int ret; + + adev = ACPI_COMPANION(dev); + if (!adev) + return NULL; + + memset(&lookup, 0, sizeof(lookup)); + lookup.info = info; + lookup.device_handle = acpi_device_handle(adev); + lookup.index = index; + + ret = acpi_dev_get_resources(adev, &resource_list, + i2c_acpi_fill_info, &lookup); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !info->addr) + return NULL; + + adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); + if (!adapter) + return NULL; + + return i2c_new_device(adapter, info); +} +EXPORT_SYMBOL_GPL(i2c_acpi_new_device); #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } extern struct notifier_block i2c_acpi_notifier; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6b183521c616..53fa50fc63fb 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -824,11 +824,18 @@ static inline const struct of_device_id #if IS_ENABLED(CONFIG_ACPI) u32 i2c_acpi_find_bus_speed(struct device *dev); +struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, + struct i2c_board_info *info); #else static inline u32 i2c_acpi_find_bus_speed(struct device *dev) { return 0; } +static inline struct i2c_client *i2c_acpi_new_device(struct device *dev, + int index, struct i2c_board_info *info) +{ + return NULL; +} #endif /* CONFIG_ACPI */ #endif /* _LINUX_I2C_H */ -- cgit v1.2.3 From d1d84bb95364ed604015c2b788caaf3dbca0262f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Apr 2017 00:03:34 +0200 Subject: i2c: core: Allow drivers to disable i2c-core irq mapping By default the i2c-core will try to get an irq with index 0 on ACPI / of instantiated devices. This is troublesome on some ACPI systems where the irq info at index 0 in the CRS table may contain nonsense and/or point to an irqchip for which there is no Linux driver. If this happens then before this commit the driver's probe method would never get called because i2c_device_probe will try to get an irq by calling acpi_dev_gpio_irq_get which will always return -EPROBE in this case, as it waits for a matching irqchip driver to load. Thus causing the driver to not get a chance to bind. This commit adds a new disable_i2c_core_irq_mapping flag to struct i2c_driver which a driver can set to tell the core to skip irq mapping. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 6 +++--- include/linux/i2c.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 00c4cef716f7..7a065c4260f3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -985,7 +985,9 @@ static int i2c_device_probe(struct device *dev) if (!client) return 0; - if (!client->irq) { + driver = to_i2c_driver(dev->driver); + + if (!client->irq && !driver->disable_i2c_core_irq_mapping) { int irq = -ENOENT; if (client->flags & I2C_CLIENT_HOST_NOTIFY) { @@ -1007,8 +1009,6 @@ static int i2c_device_probe(struct device *dev) client->irq = irq; } - driver = to_i2c_driver(dev->driver); - /* * An I2C ID table is not mandatory, if and only if, a suitable Device * Tree match table entry is supplied for the probing device. diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 53fa50fc63fb..3a57e3dc9bec 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -149,6 +149,7 @@ enum i2c_alert_protocol { * @detect: Callback for device detection * @address_list: The I2C addresses to probe (for detect) * @clients: List of detected clients we created (for i2c-core use only) + * @disable_i2c_core_irq_mapping: Tell the i2c-core to not do irq-mapping * * The driver.owner field should be set to the module owner of this driver. * The driver.name field should be set to the name of this driver. @@ -212,6 +213,8 @@ struct i2c_driver { int (*detect)(struct i2c_client *, struct i2c_board_info *); const unsigned short *address_list; struct list_head clients; + + bool disable_i2c_core_irq_mapping; }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) -- cgit v1.2.3 From f6cfec891622f7bc3fb04170b7d7cb8bfebc82a7 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 3 Apr 2017 09:35:31 +0200 Subject: [media] cx231xx: stop double error reporting i2c_mux_add_adapter already logs a message on failure. Reviewed-by: Wolfram Sang Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Peter Rosin --- drivers/media/usb/cx231xx/cx231xx-i2c.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 35e9acfe63d3..dff514e147da 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -576,17 +576,10 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev) int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no) { - int rc; - - rc = i2c_mux_add_adapter(dev->muxc, - 0, - mux_no /* chan_id */, - 0 /* class */); - if (rc) - dev_warn(dev->dev, - "i2c mux %d register FAILED\n", mux_no); - - return rc; + return i2c_mux_add_adapter(dev->muxc, + 0, + mux_no /* chan_id */, + 0 /* class */); } void cx231xx_i2c_mux_unregister(struct cx231xx *dev) -- cgit v1.2.3 From bd698d24b1b5790d0a22d44a0705dabd47235ad4 Mon Sep 17 00:00:00 2001 From: "chin.yew.tan@intel.com" Date: Tue, 28 Mar 2017 16:48:02 +0800 Subject: i2c: designware: Get selected speed mode sda-hold-time via ACPI Sda-hold-time is an important parameter for tuning i2c to meet the electrical specification especially for high speed. I2C with incorrect sda-hold-time may cause lost arbitration error. Instead of loading all speed mode settings, only selected speed mode settings are loaded. Signed-off-by: Tan Chin Yew Reviewed-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 31 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index a597ba32de7e..5a4eb6b6bd92 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -85,8 +85,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], *hcnt = (u16)objs[0].integer.value; *lcnt = (u16)objs[1].integer.value; - if (sda_hold) - *sda_hold = (u32)objs[2].integer.value; + *sda_hold = (u32)objs[2].integer.value; } kfree(buf.pointer); @@ -105,14 +104,28 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) dev->rx_fifo_depth = 32; /* - * Try to get SDA hold time and *CNT values from an ACPI method if - * it exists for both supported speed modes. + * Try to get SDA hold time and *CNT values from an ACPI method for + * selected speed modes. */ - dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL); - dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, - &dev->sda_hold_time); - dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL); - dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL); + switch (dev->clk_freq) { + case 100000: + dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, + &dev->sda_hold_time); + break; + case 1000000: + dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, + &dev->sda_hold_time); + break; + case 3400000: + dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, + &dev->sda_hold_time); + break; + case 400000: + default: + dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, + &dev->sda_hold_time); + break; + } id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (id && id->driver_data) -- cgit v1.2.3 From c7f82ea8605627b3088f166d9f4a5ca7857e8383 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 20 Mar 2017 11:51:23 +0000 Subject: i2c: designware-baytrail: fix potential null pointer dereference on dev The assignment to addr requires a call to get_sem_addr that dereferences dev, however, this dereference occurs before a null pointer check on dev. Move this assignment after the null check on dev to avoid a potential null pointer dereference. Detected by CoverityScan, CID#1419700 ("Dereference before null check") Fixes: fd476fa22a1f432 ("i2c: designware-baytrail: Add support for cherrytrail") Signed-off-by: Colin Ian King Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-baytrail.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index 1ac042972020..dbda8c9c8a1c 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -70,7 +70,7 @@ static void reset_semaphore(struct dw_i2c_dev *dev) static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) { - u32 addr = get_sem_addr(dev); + u32 addr; u32 sem = PUNIT_SEMAPHORE_ACQUIRE; int ret; unsigned long start, end; @@ -94,6 +94,8 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) */ pm_qos_update_request(&dev->pm_qos, 0); + addr = get_sem_addr(dev); + /* host driver writes to side band semaphore register */ ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem); if (ret) { -- cgit v1.2.3 From b917d4fd5050e46979835486a70c99b5cb688689 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 23 Feb 2017 17:47:26 +0100 Subject: i2c: exynos5: simplify timings calculation Instead of using cryptic loop direct calculation of timings can be used. Signed-off-by: Andrzej Hajda Tested-by: Javier Martinez Canillas Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 736a82472101..5f24c3ef7d1d 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -292,9 +292,9 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) unsigned int t_sr_release; unsigned int t_ftl_cycle; unsigned int clkin = clk_get_rate(i2c->clk); - unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle; unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ? i2c->hs_clock : i2c->fs_clock; + int div, clk_cycle, temp; /* * In case of HSI2C controller in Exynos5 series @@ -305,33 +305,21 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) * FPCLK / FI2C = * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE * - * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) - * utemp1 = (TSCLK_L + TSCLK_H + 2) + * clk_cycle := TSCLK_L + TSCLK_H + * temp := (CLK_DIV + 1) * (clk_cycle + 2) + * + * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510 + * */ t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; - utemp0 = (clkin / op_clk) - 8; - - if (i2c->variant->hw == HSI2C_EXYNOS7) - utemp0 -= t_ftl_cycle; - else - utemp0 -= 2 * t_ftl_cycle; - - /* CLK_DIV max is 256 */ - for (div = 0; div < 256; div++) { - utemp1 = utemp0 / (div + 1); - - /* - * SCL_L and SCL_H each has max value of 255 - * Hence, For the clk_cycle to the have right value - * utemp1 has to be less then 512 and more than 4. - */ - if ((utemp1 < 512) && (utemp1 > 4)) { - clk_cycle = utemp1 - 2; - break; - } else if (div == 255) { - dev_warn(i2c->dev, "Failed to calculate divisor"); - return -EINVAL; - } + temp = clkin / op_clk - 8 - t_ftl_cycle; + if (i2c->variant->hw != HSI2C_EXYNOS7) + temp -= t_ftl_cycle; + div = temp / 512; + clk_cycle = temp / (div + 1) - 2; + if (temp < 4 || div >= 256 || clk_cycle < 2) { + dev_warn(i2c->dev, "Failed to calculate divisor"); + return -EINVAL; } t_scl_l = clk_cycle / 2; -- cgit v1.2.3 From b9d5b31a0dee47e3a1351589d361443e66f4f125 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 24 Feb 2017 12:16:01 +0100 Subject: i2c: exynos5: simplify clock frequency handling There is no need to keep separate settings for high and fast speed clock. Signed-off-by: Andrzej Hajda Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 45 +++++++++++----------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 5f24c3ef7d1d..3d21bc280927 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -168,8 +168,6 @@ */ #define HSI2C_HS_TX_CLOCK 1000000 #define HSI2C_FS_TX_CLOCK 100000 -#define HSI2C_HIGH_SPD 1 -#define HSI2C_FAST_SPD 0 #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -200,15 +198,7 @@ struct exynos5_i2c { int trans_done; /* Controller operating frequency */ - unsigned int fs_clock; - unsigned int hs_clock; - - /* - * HSI2C Controller can operate in - * 1. High speed upto 3.4Mbps - * 2. Fast speed upto 1Mbps - */ - int speed_mode; + unsigned int op_clock; /* Version of HS-I2C Hardware */ struct exynos_hsi2c_variant *variant; @@ -279,7 +269,7 @@ static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) * Returns 0 on success, -EINVAL if the cycle length cannot * be calculated. */ -static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) +static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) { u32 i2c_timing_s1; u32 i2c_timing_s2; @@ -292,8 +282,9 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) unsigned int t_sr_release; unsigned int t_ftl_cycle; unsigned int clkin = clk_get_rate(i2c->clk); - unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ? - i2c->hs_clock : i2c->fs_clock; + unsigned int op_clk = hs_timings ? i2c->op_clock : + (i2c->op_clock >= HSI2C_HS_TX_CLOCK) ? HSI2C_FS_TX_CLOCK : + i2c->op_clock; int div, clk_cycle, temp; /* @@ -344,7 +335,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) div, t_sr_release); dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd); - if (mode == HSI2C_HIGH_SPD) { + if (hs_timings) { writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1); writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2); writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); @@ -364,14 +355,14 @@ static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c) * Configure the Fast speed timing values * Even the High Speed mode initially starts with Fast mode */ - if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) { + if (exynos5_i2c_set_timing(i2c, false)) { dev_err(i2c->dev, "HSI2C FS Clock set up failed\n"); return -EINVAL; } /* configure the High speed timing values */ - if (i2c->speed_mode == HSI2C_HIGH_SPD) { - if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) { + if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) { + if (exynos5_i2c_set_timing(i2c, true)) { dev_err(i2c->dev, "HSI2C HS Clock set up failed\n"); return -EINVAL; } @@ -397,7 +388,7 @@ static void exynos5_i2c_init(struct exynos5_i2c *i2c) i2c->regs + HSI2C_CTL); writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL); - if (i2c->speed_mode == HSI2C_HIGH_SPD) { + if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) { writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)), i2c->regs + HSI2C_ADDR); i2c_conf |= HSI2C_HS_MODE; @@ -735,26 +726,14 @@ static int exynos5_i2c_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct exynos5_i2c *i2c; struct resource *mem; - unsigned int op_clock; int ret; i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - if (of_property_read_u32(np, "clock-frequency", &op_clock)) { - i2c->speed_mode = HSI2C_FAST_SPD; - i2c->fs_clock = HSI2C_FS_TX_CLOCK; - } else { - if (op_clock >= HSI2C_HS_TX_CLOCK) { - i2c->speed_mode = HSI2C_HIGH_SPD; - i2c->fs_clock = HSI2C_FS_TX_CLOCK; - i2c->hs_clock = op_clock; - } else { - i2c->speed_mode = HSI2C_FAST_SPD; - i2c->fs_clock = op_clock; - } - } + if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock)) + i2c->op_clock = HSI2C_FS_TX_CLOCK; strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; -- cgit v1.2.3 From 70c8c4e9bf3b586516b0cd224bb3aed008efc300 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 24 Feb 2017 12:16:02 +0100 Subject: i2c: exynos5: de-duplicate error logs on clock setup In case of clock setup error it is enough to log it once. Moreover patch simplifies clock setup routines. Signed-off-by: Andrzej Hajda Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 3d21bc280927..a1e1e7cba448 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -309,7 +309,8 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) div = temp / 512; clk_cycle = temp / (div + 1) - 2; if (temp < 4 || div >= 256 || clk_cycle < 2) { - dev_warn(i2c->dev, "Failed to calculate divisor"); + dev_err(i2c->dev, "%s clock set-up failed\n", + hs_timings ? "HS" : "FS"); return -EINVAL; } @@ -351,24 +352,13 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c) { - /* - * Configure the Fast speed timing values - * Even the High Speed mode initially starts with Fast mode - */ - if (exynos5_i2c_set_timing(i2c, false)) { - dev_err(i2c->dev, "HSI2C FS Clock set up failed\n"); - return -EINVAL; - } + /* always set Fast Speed timings */ + int ret = exynos5_i2c_set_timing(i2c, false); - /* configure the High speed timing values */ - if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) { - if (exynos5_i2c_set_timing(i2c, true)) { - dev_err(i2c->dev, "HSI2C HS Clock set up failed\n"); - return -EINVAL; - } - } + if (ret < 0 || i2c->op_clock < HSI2C_HS_TX_CLOCK) + return ret; - return 0; + return exynos5_i2c_set_timing(i2c, true); } /* -- cgit v1.2.3 From b371f866d9e1eebd6048c644b4a0e78eb951c3b3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 24 Feb 2017 14:36:00 +0100 Subject: i2c: exynos5: use core helper to get driver data Driver core provides of_device_get_match_data which can be used to get driver data instead of custom helper. Signed-off-by: Andrzej Hajda Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index a1e1e7cba448..23ed4d67ecad 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -201,7 +202,7 @@ struct exynos5_i2c { unsigned int op_clock; /* Version of HS-I2C Hardware */ - struct exynos_hsi2c_variant *variant; + const struct exynos_hsi2c_variant *variant; }; /** @@ -247,15 +248,6 @@ static const struct of_device_id exynos5_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); -static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant - (struct platform_device *pdev) -{ - const struct of_device_id *match; - - match = of_match_node(exynos5_i2c_match, pdev->dev.of_node); - return (struct exynos_hsi2c_variant *)match->data; -} - static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) { writel(readl(i2c->regs + HSI2C_INT_STATUS), @@ -774,8 +766,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) goto err_clk; } - /* Need to check the variant before setting up. */ - i2c->variant = exynos5_i2c_get_variant(pdev); + i2c->variant = of_device_get_match_data(&pdev->dev); ret = exynos5_hsi2c_clock_setup(i2c); if (ret) -- cgit v1.2.3 From 8c91fd5ee64241d96c9cad97669389bacd10f4ea Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 21 Apr 2017 07:56:53 +0100 Subject: i2c: tegra: fix spelling mistake: "contoller" -> "controller" trivial fix to spelling mistake in MODULE_DESCRIPTION text Signed-off-by: Colin Ian King Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra-bpmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index 9eed69d5e17e..f6cd35d0a2ac 100644 --- a/drivers/i2c/busses/i2c-tegra-bpmp.c +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -340,7 +340,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = { }; module_platform_driver(tegra_bpmp_i2c_driver); -MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver"); +MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus controller driver"); MODULE_AUTHOR("Shardar Shariff Md "); MODULE_AUTHOR("Juha-Matti Tilli"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From ae481cc139658e89eb3ea671dd00b67bd87f01a3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 18 Apr 2017 20:38:35 +0200 Subject: i2c: rcar: fix resume by always initializing registers before transfer Resume failed because of uninitialized registers. Instead of adding a resume callback, we simply initialize registers before every transfer. This lightweight change is more robust and will keep us safe if we ever need support for power domains or dynamic frequency changes. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 26f2ff22e97e..66b84bf51bbf 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, pm_runtime_get_sync(dev); + rcar_i2c_init(priv); + ret = rcar_i2c_bus_barrier(priv); if (ret < 0) goto out; @@ -860,8 +862,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) goto out_pm_put; - rcar_i2c_init(priv); - /* Don't suspend when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master")) priv->flags |= ID_P_PM_BLOCKED; -- cgit v1.2.3 From 63a761eef55759c0bc725739fe575193c09fa4ef Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 20 Apr 2017 12:04:33 +0200 Subject: i2c: rcar: clarify PM handling with more comments PM handling is correct but might be a bit subtle. Add some comments for clarification. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 66b84bf51bbf..214bf2835d1f 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -753,6 +753,7 @@ static int rcar_reg_slave(struct i2c_client *slave) if (slave->flags & I2C_CLIENT_TEN) return -EAFNOSUPPORT; + /* Keep device active for slave address detection logic */ pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv)); priv->slave = slave; @@ -856,13 +857,14 @@ static int rcar_i2c_probe(struct platform_device *pdev) priv->dma_direction = DMA_NONE; priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER); + /* Activate device for clock calculation */ pm_runtime_enable(dev); pm_runtime_get_sync(dev); ret = rcar_i2c_clock_calculate(priv, &i2c_t); if (ret < 0) goto out_pm_put; - /* Don't suspend when multi-master to keep arbitration working */ + /* Stay always active when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master")) priv->flags |= ID_P_PM_BLOCKED; else -- cgit v1.2.3 From 889ef45cd4b64cc4fd6dbebecddb8ea4df8cc1e7 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 21 Apr 2017 16:43:55 +0200 Subject: i2c: thunderx: Enable HWMON class probing Set I2C_CLASS_HWMON to enable automatic probing of BMC devices by the ipmi-ssif driver. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-thunderx-pcidrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index b4bc884cef93..ea35a895b568 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -211,6 +211,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, i2c->adap = thunderx_i2c_ops; i2c->adap.retries = 5; + i2c->adap.class = I2C_CLASS_HWMON; i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; i2c->adap.dev.parent = dev; i2c->adap.dev.of_node = pdev->dev.of_node; -- cgit v1.2.3