diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-altera.c | 10 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-amd-mp2-pci.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-aspeed.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-at91-master.c | 20 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bcm-iproc.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 36 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-base.c | 24 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-of.c | 2 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-demux-pinctrl.c | 1 |
11 files changed, 68 insertions, 41 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index dff4e178c732..7f10312d1b88 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -542,7 +542,7 @@ int i2c_pca_add_numbered_bus(struct i2c_adapter *adap) EXPORT_SYMBOL(i2c_pca_add_numbered_bus); MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, " - "Wolfram Sang <w.sang@pengutronix.de>"); + "Wolfram Sang <kernel@pengutronix.de>"); MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c index f5c00f903df3..16ddc26c00e6 100644 --- a/drivers/i2c/busses/i2c-altera.c +++ b/drivers/i2c/busses/i2c-altera.c @@ -70,6 +70,7 @@ * @isr_mask: cached copy of local ISR enables. * @isr_status: cached copy of local ISR status. * @lock: spinlock for IRQ synchronization. + * @isr_mutex: mutex for IRQ thread. */ struct altr_i2c_dev { void __iomem *base; @@ -86,6 +87,7 @@ struct altr_i2c_dev { u32 isr_mask; u32 isr_status; spinlock_t lock; /* IRQ synchronization */ + struct mutex isr_mutex; }; static void @@ -245,10 +247,11 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev) struct altr_i2c_dev *idev = _dev; u32 status = idev->isr_status; + mutex_lock(&idev->isr_mutex); if (!idev->msg) { dev_warn(idev->dev, "unexpected interrupt\n"); altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ); - return IRQ_HANDLED; + goto out; } read = (idev->msg->flags & I2C_M_RD) != 0; @@ -301,6 +304,8 @@ static irqreturn_t altr_i2c_isr(int irq, void *_dev) complete(&idev->msg_complete); dev_dbg(idev->dev, "Message Complete\n"); } +out: + mutex_unlock(&idev->isr_mutex); return IRQ_HANDLED; } @@ -312,6 +317,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg) u32 value; u8 addr = i2c_8bit_addr_from_msg(msg); + mutex_lock(&idev->isr_mutex); idev->msg = msg; idev->msg_len = msg->len; idev->buf = msg->buf; @@ -336,6 +342,7 @@ static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg) altr_i2c_int_enable(idev, imask, true); altr_i2c_fill_tx_fifo(idev); } + mutex_unlock(&idev->isr_mutex); time_left = wait_for_completion_timeout(&idev->msg_complete, ALTR_I2C_XFER_TIMEOUT); @@ -409,6 +416,7 @@ static int altr_i2c_probe(struct platform_device *pdev) idev->dev = &pdev->dev; init_completion(&idev->msg_complete); spin_lock_init(&idev->lock); + mutex_init(&idev->isr_mutex); ret = device_property_read_u32(idev->dev, "fifo-size", &idev->fifo_size); diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index 5e4800d72e00..cd3fd5ee5f65 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -349,12 +349,12 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev, if (!privdata) return -ENOMEM; + privdata->pci_dev = pci_dev; rc = amd_mp2_pci_init(privdata, pci_dev); if (rc) return rc; mutex_init(&privdata->c2p_lock); - privdata->pci_dev = pci_dev; pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000); pm_runtime_use_autosuspend(&pci_dev->dev); diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 07c1993274c5..f51702d86a90 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -603,6 +603,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) /* Ack all interrupts except for Rx done */ writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); + readl(bus->base + ASPEED_I2C_INTR_STS_REG); irq_remaining = irq_received; #if IS_ENABLED(CONFIG_I2C_SLAVE) @@ -645,9 +646,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) irq_received, irq_handled); /* Ack Rx done */ - if (irq_received & ASPEED_I2CD_INTR_RX_DONE) + if (irq_received & ASPEED_I2CD_INTR_RX_DONE) { writel(ASPEED_I2CD_INTR_RX_DONE, bus->base + ASPEED_I2C_INTR_STS_REG); + readl(bus->base + ASPEED_I2C_INTR_STS_REG); + } spin_unlock(&bus->lock); return irq_remaining ? IRQ_NONE : IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 0aba51a7df32..37b96ac9dfae 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -845,6 +845,18 @@ static int at91_init_twi_recovery_info(struct platform_device *pdev, PINCTRL_STATE_DEFAULT); dev->pinctrl_pins_gpio = pinctrl_lookup_state(dev->pinctrl, "gpio"); + if (IS_ERR(dev->pinctrl_pins_default) || + IS_ERR(dev->pinctrl_pins_gpio)) { + dev_info(&pdev->dev, "pinctrl states incomplete for recovery\n"); + return -EINVAL; + } + + /* + * pins will be taken as GPIO, so we might as well inform pinctrl about + * this and move the state to GPIO + */ + pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_gpio); + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -855,9 +867,7 @@ static int at91_init_twi_recovery_info(struct platform_device *pdev, return -EPROBE_DEFER; if (IS_ERR(rinfo->sda_gpiod) || - IS_ERR(rinfo->scl_gpiod) || - IS_ERR(dev->pinctrl_pins_default) || - IS_ERR(dev->pinctrl_pins_gpio)) { + IS_ERR(rinfo->scl_gpiod)) { dev_info(&pdev->dev, "recovery information incomplete\n"); if (!IS_ERR(rinfo->sda_gpiod)) { gpiod_put(rinfo->sda_gpiod); @@ -867,9 +877,13 @@ static int at91_init_twi_recovery_info(struct platform_device *pdev, gpiod_put(rinfo->scl_gpiod); rinfo->scl_gpiod = NULL; } + pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default); return -EINVAL; } + /* change the state of the pins back to their default state */ + pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default); + dev_info(&pdev->dev, "using scl, sda for recovery\n"); rinfo->prepare_recovery = at91_prepare_twi_recovery; diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 44be0926b566..d091a12596ad 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -360,6 +360,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_WRITE_RECEIVED, &value); + if (rx_status == I2C_SLAVE_RX_END) + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_STOP, &value); } } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { /* Master read other than start */ diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 5536673060cc..c429d664f655 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -357,12 +357,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE | - DPM_FLAG_LEAVE_SUSPENDED); + DPM_FLAG_MAY_SKIP_RESUME); } else { dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND | - DPM_FLAG_LEAVE_SUSPENDED); + DPM_FLAG_MAY_SKIP_RESUME); } /* The code below assumes runtime PM to be disabled. */ diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 8280ac7cc1b7..4c4d17ddc96b 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -996,13 +996,14 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev, do { u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS); - if (status) + if (status) { tegra_i2c_isr(i2c_dev->irq, i2c_dev); - if (completion_done(complete)) { - s64 delta = ktime_ms_delta(ktimeout, ktime); + if (completion_done(complete)) { + s64 delta = ktime_ms_delta(ktimeout, ktime); - return msecs_to_jiffies(delta) ?: 1; + return msecs_to_jiffies(delta) ?: 1; + } } ktime = ktime_get(); @@ -1029,18 +1030,14 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev, disable_irq(i2c_dev->irq); /* - * Under some rare circumstances (like running KASAN + - * NFS root) CPU, which handles interrupt, may stuck in - * uninterruptible state for a significant time. In this - * case we will get timeout if I2C transfer is running on - * a sibling CPU, despite of IRQ being raised. - * - * In order to handle this rare condition, the IRQ status - * needs to be checked after timeout. + * There is a chance that completion may happen after IRQ + * synchronization, which is done by disable_irq(). */ - if (ret == 0) - ret = tegra_i2c_poll_completion_timeout(i2c_dev, - complete, 0); + if (ret == 0 && completion_done(complete)) { + dev_warn(i2c_dev->dev, + "completion done after timeout\n"); + ret = 1; + } } return ret; @@ -1219,15 +1216,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, time_left = tegra_i2c_wait_completion_timeout( i2c_dev, &i2c_dev->dma_complete, xfer_time); - /* - * Synchronize DMA first, since dmaengine_terminate_sync() - * performs synchronization after the transfer's termination - * and we want to get a completion if transfer succeeded. - */ - dmaengine_synchronize(i2c_dev->msg_read ? - i2c_dev->rx_dma_chan : - i2c_dev->tx_dma_chan); - dmaengine_terminate_sync(i2c_dev->msg_read ? i2c_dev->rx_dma_chan : i2c_dev->tx_dma_chan); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index a66912782064..1f1442dfcad7 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -7,7 +7,7 @@ * Mux support by Rodolfo Giometti <giometti@enneenne.com> and * Michael Lawnick <michael.lawnick.ext@nsn.com> * - * Copyright (C) 2013-2017 Wolfram Sang <wsa@the-dreams.de> + * Copyright (C) 2013-2017 Wolfram Sang <wsa@kernel.org> */ #define pr_fmt(fmt) "i2c-core: " fmt @@ -338,8 +338,10 @@ static int i2c_device_probe(struct device *dev) } else if (ACPI_COMPANION(dev)) { irq = i2c_acpi_get_irq(client); } - if (irq == -EPROBE_DEFER) - return irq; + if (irq == -EPROBE_DEFER) { + status = irq; + goto put_sync_adapter; + } if (irq < 0) irq = 0; @@ -353,15 +355,19 @@ static int i2c_device_probe(struct device *dev) */ if (!driver->id_table && !i2c_acpi_match_device(dev->driver->acpi_match_table, client) && - !i2c_of_match_device(dev->driver->of_match_table, client)) - return -ENODEV; + !i2c_of_match_device(dev->driver->of_match_table, client)) { + status = -ENODEV; + goto put_sync_adapter; + } if (client->flags & I2C_CLIENT_WAKE) { int wakeirq; wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); - if (wakeirq == -EPROBE_DEFER) - return wakeirq; + if (wakeirq == -EPROBE_DEFER) { + status = wakeirq; + goto put_sync_adapter; + } device_init_wakeup(&client->dev, true); @@ -408,6 +414,10 @@ err_detach_pm_domain: err_clear_wakeup_irq: dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); +put_sync_adapter: + if (client->flags & I2C_CLIENT_HOST_NOTIFY) + pm_runtime_put_sync(&client->adapter->dev); + return status; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 6787c1f71483..3ed74aa4b44b 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -5,7 +5,7 @@ * Copyright (C) 2008 Jochen Friedrich <jochen@scram.de> * based on a previous patch from Jon Smirl <jonsmirl@gmail.com> * - * Copyright (C) 2013, 2018 Wolfram Sang <wsa@the-dreams.de> + * Copyright (C) 2013, 2018 Wolfram Sang <wsa@kernel.org> */ #include <dt-bindings/i2c/i2c.h> diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 0e16490eb3a1..5365199a31f4 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -272,6 +272,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err_rollback_available: device_remove_file(&pdev->dev, &dev_attr_available_masters); err_rollback: + i2c_demux_deactivate_master(priv); for (j = 0; j < i; j++) { of_node_put(priv->chan[j].parent_np); of_changeset_destroy(&priv->chan[j].chgset); |