From 785e21cfaa68fd77b07b8c902991d4f255361946 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Dec 2020 20:13:00 +0100 Subject: i2c: core: Do not print duplicate error when failing to register an i2c-client from ACPI i2c_new_client_device() already prints an error when it fails. Some ACPI tables contain 2 ACPI devices describing the same i2c-client, leading to errors like this: [ 1.620847] i2c i2c-4: Failed to register i2c client MAGN0001:00 at 0x1d (-16) [ 1.620870] i2c i2c-4: failed to add I2C device MAGN0001:00 from ACPI There is nothing we can do about the first -EBUSY error being logged, but the second error does not really add any new information, so lets drop it. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-acpi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 37c510d9347a..8ceaa88dd78f 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -225,12 +225,8 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter, adev->power.flags.ignore_parent = true; acpi_device_set_enumerated(adev); - if (IS_ERR(i2c_new_client_device(adapter, info))) { + if (IS_ERR(i2c_new_client_device(adapter, info))) adev->power.flags.ignore_parent = false; - dev_err(&adapter->dev, - "failed to add I2C device %s from ACPI\n", - dev_name(&adev->dev)); - } } static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, -- cgit From f069291bd5fcb85c6eb53f9b1ab23bcfcaad93f2 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 10 Dec 2020 18:51:11 +0200 Subject: i2c: mlxcpld: Update module license Update license to SPDX-License. Signed-off-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 71d7bae2cbca..dbd185368c38 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -1,34 +1,8 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /* - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. - * Copyright (c) 2016 Michael Shych + * Mellanox i2c driver * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Copyright (C) 2016-2020 Mellanox Technologies */ #include -- cgit From cb9744178f330dcd5ea73788eba00b65deb068bb Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 10 Dec 2020 18:51:12 +0200 Subject: i2c: mlxcpld: Decrease polling time for performance improvement Decrease polling time 'MLXCPLD_I2C_POLL_TIME' from 2000 usec to 400 usec. It greatly improves performance of I2C transactions. Reliability of setting polling time to 400 usec has been thoroughly validated across all the supported systems. Signed-off-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index dbd185368c38..9e45214d1eb6 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -25,7 +25,7 @@ #define MLXCPLD_I2C_MAX_ADDR_LEN 4 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ -#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ +#define MLXCPLD_I2C_POLL_TIME 400 /* usec */ /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 -- cgit From d321ad1286d2ac1f14fccadee822519a6ac9dd64 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 28 Dec 2020 22:06:16 +0200 Subject: gpiolib: Follow usual pattern for gpiod_remove_lookup_table() call The usual pattern for the remove calls, like gpiod_remove_lookup_table(), is to be NULL-aware, i.o.w. become a no-op whenever parameter is NULL. Update gpiod_remove_lookup_table() call to follow this pattern. Signed-off-by: Andy Shevchenko Acked-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/gpio/gpiolib.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b02cc2abd3b6..611d6ea82d75 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3460,6 +3460,10 @@ EXPORT_SYMBOL_GPL(gpiod_add_lookup_table); */ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) { + /* Nothing to remove */ + if (!table) + return; + mutex_lock(&gpio_lookup_lock); list_del(&table->list); -- cgit From 926e6b2cd1ca9de8d89d4e9e31804a3cc0b8ecea Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 28 Dec 2020 22:06:17 +0200 Subject: i2c: i801: Drop duplicate NULL check in i801_del_mux() Since gpiod_remove_lookup_table() is NULL-aware, no need to have this check in the caller. Drop duplicate NULL check. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae90713443fa..7c2569a18f8c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1487,8 +1487,7 @@ static void i801_del_mux(struct i801_priv *priv) { if (priv->mux_pdev) platform_device_unregister(priv->mux_pdev); - if (priv->lookup) - gpiod_remove_lookup_table(priv->lookup); + gpiod_remove_lookup_table(priv->lookup); } static unsigned int i801_get_adapter_class(struct i801_priv *priv) -- cgit From 5581b4167c0f309d5556673d93e96fb90b31c64d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 28 Dec 2020 22:06:18 +0200 Subject: i2c: i801: Refactor mux code since platform_device_unregister() is NULL aware platform_device_unregister() is NULL-aware and thus doesn't required a duplication check in i801_del_mux(). Besides that it's also error pointer aware, and we may drop unneeded assignment in i801_add_mux() followed by conversion to PTR_ERR_OR_ZERO() for the returned value. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 7c2569a18f8c..1400a8716388 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1433,7 +1433,7 @@ static int i801_add_mux(struct i801_priv *priv) const struct i801_mux_config *mux_config; struct i2c_mux_gpio_platform_data gpio_data; struct gpiod_lookup_table *lookup; - int err, i; + int i; if (!priv->mux_drvdata) return 0; @@ -1473,20 +1473,16 @@ static int i801_add_mux(struct i801_priv *priv) PLATFORM_DEVID_NONE, &gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); if (IS_ERR(priv->mux_pdev)) { - err = PTR_ERR(priv->mux_pdev); gpiod_remove_lookup_table(lookup); - priv->mux_pdev = NULL; dev_err(dev, "Failed to register i2c-mux-gpio device\n"); - return err; } - return 0; + return PTR_ERR_OR_ZERO(priv->mux_pdev); } static void i801_del_mux(struct i801_priv *priv) { - if (priv->mux_pdev) - platform_device_unregister(priv->mux_pdev); + platform_device_unregister(priv->mux_pdev); gpiod_remove_lookup_table(priv->lookup); } -- cgit From 357ee8841d0b7bd822f25fc768afbc0c2ab7e47b Mon Sep 17 00:00:00 2001 From: Roja Rani Yarubandi Date: Mon, 21 Dec 2020 18:08:00 +0530 Subject: i2c: qcom-geni: Store DMA mapping data in geni_i2c_dev struct Store DMA mapping data in geni_i2c_dev struct to enhance DMA mapping data scope. For example during shutdown callback to unmap DMA mapping, this stored DMA mapping data can be used to call geni_se_tx_dma_unprep and geni_se_rx_dma_unprep functions. Add two helper functions geni_i2c_rx_msg_cleanup and geni_i2c_tx_msg_cleanup to unwrap the things after rx/tx FIFO/DMA transfers, so that the same can be used in geni_i2c_stop_xfer() function during shutdown callback. Signed-off-by: Roja Rani Yarubandi Reviewed-by: Akash Asthana Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 59 +++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 046d241183c5..214b4c913a13 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -86,6 +86,9 @@ struct geni_i2c_dev { u32 clk_freq_out; const struct geni_i2c_clk_fld *clk_fld; int suspended; + void *dma_buf; + size_t xfer_len; + dma_addr_t dma_addr; }; struct geni_i2c_err_log { @@ -348,14 +351,39 @@ static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c) dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n"); } +static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c, + struct i2c_msg *cur) +{ + gi2c->cur_rd = 0; + if (gi2c->dma_buf) { + if (gi2c->err) + geni_i2c_rx_fsm_rst(gi2c); + geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); + i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); + } +} + +static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c, + struct i2c_msg *cur) +{ + gi2c->cur_wr = 0; + if (gi2c->dma_buf) { + if (gi2c->err) + geni_i2c_tx_fsm_rst(gi2c); + geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); + i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); + } +} + static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, u32 m_param) { - dma_addr_t rx_dma; + dma_addr_t rx_dma = 0; unsigned long time_left; void *dma_buf; struct geni_se *se = &gi2c->se; size_t len = msg->len; + struct i2c_msg *cur; dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) @@ -370,19 +398,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, geni_se_select_mode(se, GENI_SE_FIFO); i2c_put_dma_safe_msg_buf(dma_buf, msg, false); dma_buf = NULL; + } else { + gi2c->xfer_len = len; + gi2c->dma_addr = rx_dma; + gi2c->dma_buf = dma_buf; } + cur = gi2c->cur; time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); if (!time_left) geni_i2c_abort_xfer(gi2c); - gi2c->cur_rd = 0; - if (dma_buf) { - if (gi2c->err) - geni_i2c_rx_fsm_rst(gi2c); - geni_se_rx_dma_unprep(se, rx_dma, len); - i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err); - } + geni_i2c_rx_msg_cleanup(gi2c, cur); return gi2c->err; } @@ -390,11 +417,12 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, u32 m_param) { - dma_addr_t tx_dma; + dma_addr_t tx_dma = 0; unsigned long time_left; void *dma_buf; struct geni_se *se = &gi2c->se; size_t len = msg->len; + struct i2c_msg *cur; dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) @@ -409,22 +437,21 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, geni_se_select_mode(se, GENI_SE_FIFO); i2c_put_dma_safe_msg_buf(dma_buf, msg, false); dma_buf = NULL; + } else { + gi2c->xfer_len = len; + gi2c->dma_addr = tx_dma; + gi2c->dma_buf = dma_buf; } if (!dma_buf) /* Get FIFO IRQ */ writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG); + cur = gi2c->cur; time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); if (!time_left) geni_i2c_abort_xfer(gi2c); - gi2c->cur_wr = 0; - if (dma_buf) { - if (gi2c->err) - geni_i2c_tx_fsm_rst(gi2c); - geni_se_tx_dma_unprep(se, tx_dma, len); - i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err); - } + geni_i2c_tx_msg_cleanup(gi2c, cur); return gi2c->err; } -- cgit From c7b514ec979e23a08c411f3d8ed39c7922751422 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Dec 2020 18:21:51 +0100 Subject: i2c: rcar: faster irq code to minimize HW race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid the HW race condition on R-Car Gen2 and earlier, we need to write to ICMCR as soon as possible in the interrupt handler. We can improve this by writing a static value instead of masking out bits. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 217def2d7cb4..824586d7ee56 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -91,7 +91,6 @@ #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_DATA (MDBS | MIE) -#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) #define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE) @@ -621,7 +620,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) /* * This driver has a lock-free design because there are IP cores (at least * R-Car Gen2) which have an inherent race condition in their hardware design. - * There, we need to clear RCAR_BUS_MASK_DATA bits as soon as possible after + * There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after * the interrupt was generated, otherwise an unwanted repeated message gets * generated. It turned out that taking a spinlock at the beginning of the ISR * was already causing repeated messages. Thus, this driver was converted to @@ -630,13 +629,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) static irqreturn_t rcar_i2c_irq(int irq, void *ptr) { struct rcar_i2c_priv *priv = ptr; - u32 msr, val; + u32 msr; /* Clear START or STOP immediately, except for REPSTART after read */ - if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) { - val = rcar_i2c_read(priv, ICMCR); - rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); - } + if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); msr = rcar_i2c_read(priv, ICMSR); -- cgit From 25c2e0fb5fefb8d7847214cf114d94c7aad8e9ce Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Dec 2020 18:21:52 +0100 Subject: i2c: rcar: optimize cacheline to minimize HW race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'flags' and 'io' are needed first, so they should be at the beginning of the private struct. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 824586d7ee56..ad6630e3cc77 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -119,6 +119,7 @@ enum rcar_i2c_type { }; struct rcar_i2c_priv { + u32 flags; void __iomem *io; struct i2c_adapter adap; struct i2c_msg *msg; @@ -129,7 +130,6 @@ struct rcar_i2c_priv { int pos; u32 icccr; - u32 flags; u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; -- cgit From 24c6d4bc563881539d2cd4433e502436ad87d512 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Dec 2020 18:21:53 +0100 Subject: i2c: rcar: make sure irq is not threaded on Gen2 and earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure this irq runs as fast as possible. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index ad6630e3cc77..3c9c3a6f7ac8 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -928,6 +928,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) struct rcar_i2c_priv *priv; struct i2c_adapter *adap; struct device *dev = &pdev->dev; + unsigned long irqflags = 0; int ret; /* Otherwise logic will break because some bytes must always use PIO */ @@ -976,6 +977,9 @@ static int rcar_i2c_probe(struct platform_device *pdev) rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ + if (priv->devtype < I2C_RCAR_GEN3) + irqflags |= IRQF_NO_THREAD; + if (priv->devtype == I2C_RCAR_GEN3) { priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (!IS_ERR(priv->rstc)) { @@ -995,7 +999,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) priv->flags |= ID_P_HOST_NOTIFY; priv->irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv); + ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, irqflags, dev_name(dev), priv); if (ret < 0) { dev_err(dev, "cannot get irq %d\n", priv->irq); goto out_pm_disable; -- cgit From 9c975c432bc0aa53a90438fc80b369cb35134a48 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Dec 2020 18:21:54 +0100 Subject: i2c: rcar: protect against supurious interrupts on V3U MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V3U creates spurious interrupts which we need to handle. This costs time until BUS_PHASE_DATA can be activated which is problematic for Gen2 SoCs and earlier. Because of this we introduce two interrupt handlers here which will call a generic main irq function once the timing critical stuff is done. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 57 ++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 3c9c3a6f7ac8..12f6d452c0f7 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -625,20 +625,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) * generated. It turned out that taking a spinlock at the beginning of the ISR * was already causing repeated messages. Thus, this driver was converted to * the now lockless behaviour. Please keep this in mind when hacking the driver. + * R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are + * likely affected. Therefore, we have different interrupt handler entries. */ -static irqreturn_t rcar_i2c_irq(int irq, void *ptr) +static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr) { - struct rcar_i2c_priv *priv = ptr; - u32 msr; - - /* Clear START or STOP immediately, except for REPSTART after read */ - if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) - rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); - - msr = rcar_i2c_read(priv, ICMSR); - - /* Only handle interrupts that are currently enabled */ - msr &= rcar_i2c_read(priv, ICMIER); if (!msr) { if (rcar_i2c_slave_irq(priv)) return IRQ_HANDLED; @@ -682,6 +673,41 @@ out: return IRQ_HANDLED; } +static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr) +{ + struct rcar_i2c_priv *priv = ptr; + u32 msr; + + /* Clear START or STOP immediately, except for REPSTART after read */ + if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); + + /* Only handle interrupts that are currently enabled */ + msr = rcar_i2c_read(priv, ICMSR); + msr &= rcar_i2c_read(priv, ICMIER); + + return rcar_i2c_irq(irq, priv, msr); +} + +static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr) +{ + struct rcar_i2c_priv *priv = ptr; + u32 msr; + + /* Only handle interrupts that are currently enabled */ + msr = rcar_i2c_read(priv, ICMSR); + msr &= rcar_i2c_read(priv, ICMIER); + + /* + * Clear START or STOP immediately, except for REPSTART after read or + * if a spurious interrupt was detected. + */ + if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr)) + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); + + return rcar_i2c_irq(irq, priv, msr); +} + static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, dma_addr_t port_addr) @@ -929,6 +955,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct device *dev = &pdev->dev; unsigned long irqflags = 0; + irqreturn_t (*irqhandler)(int irq, void *ptr) = rcar_i2c_gen3_irq; int ret; /* Otherwise logic will break because some bytes must always use PIO */ @@ -977,8 +1004,10 @@ static int rcar_i2c_probe(struct platform_device *pdev) rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ - if (priv->devtype < I2C_RCAR_GEN3) + if (priv->devtype < I2C_RCAR_GEN3) { irqflags |= IRQF_NO_THREAD; + irqhandler = rcar_i2c_gen2_irq; + } if (priv->devtype == I2C_RCAR_GEN3) { priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); @@ -999,7 +1028,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) priv->flags |= ID_P_HOST_NOTIFY; priv->irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, irqflags, dev_name(dev), priv); + ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv); if (ret < 0) { dev_err(dev, "cannot get irq %d\n", priv->irq); goto out_pm_disable; -- cgit From 1ca1b4516088c4e275e47efd3cb243023388753c Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:28 +0530 Subject: i2c: iproc: handle Master aborted error Handle Master aborted error by flushing tx and rx fifo and reinitializing the hw. Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index d8295b1c379d..834a98caeada 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -93,6 +93,7 @@ #define S_CMD_STATUS_MASK 0x07 #define S_CMD_STATUS_SUCCESS 0x0 #define S_CMD_STATUS_TIMEOUT 0x5 +#define S_CMD_STATUS_MASTER_ABORT 0x7 #define IE_OFFSET 0x38 #define IE_M_RX_FIFO_FULL_SHIFT 31 @@ -311,9 +312,10 @@ static void bcm_iproc_i2c_check_slave_status( return; val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; - if (val == S_CMD_STATUS_TIMEOUT) { - dev_err(iproc_i2c->device, "slave random stretch time timeout\n"); - + if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) { + dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ? + "slave random stretch time timeout\n" : + "Master aborted read transaction\n"); /* re-initialize i2c for recovery */ bcm_iproc_i2c_enable_disable(iproc_i2c, false); bcm_iproc_i2c_slave_init(iproc_i2c, true); -- cgit From 545f4011e156554d704d6278245d54543f6680d1 Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:29 +0530 Subject: i2c: iproc: handle only slave interrupts which are enabled Handle only slave interrupts which are enabled. The IS_OFFSET register contains the interrupt status bits which will be set regardless of the enabling of the corresponding interrupt condition. One must therefore look at both IS_OFFSET and IE_OFFSET to determine whether an interrupt condition is set and enabled. Fixes: c245d94ed106 ("i2c: iproc: Add multi byte read-write support for slave mode") Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 834a98caeada..b54f5130d246 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -507,12 +507,17 @@ static void bcm_iproc_i2c_process_m_event(struct bcm_iproc_i2c_dev *iproc_i2c, static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) { struct bcm_iproc_i2c_dev *iproc_i2c = data; - u32 status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET); + u32 slave_status; + u32 status; bool ret; - u32 sl_status = status & ISR_MASK_SLAVE; - if (sl_status) { - ret = bcm_iproc_i2c_slave_isr(iproc_i2c, sl_status); + status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET); + /* process only slave interrupt which are enabled */ + slave_status = status & iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET) & + ISR_MASK_SLAVE; + + if (slave_status) { + ret = bcm_iproc_i2c_slave_isr(iproc_i2c, slave_status); if (ret) return IRQ_HANDLED; else -- cgit From 603e77af7b0704bdb057de0368f1f2b04fc9552c Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:30 +0530 Subject: i2c: iproc: update slave isr mask (ISR_MASK_SLAVE) Update slave isr mask (ISR_MASK_SLAVE) to include remaining two slave interrupts. Fixes: c245d94ed106 ("i2c: iproc: Add multi byte read-write support for slave mode") Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index b54f5130d246..cd687696bf0b 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -216,7 +216,8 @@ struct bcm_iproc_i2c_dev { #define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\ | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\ - | BIT(IS_S_TX_UNDERRUN_SHIFT)) + | BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\ + | BIT(IS_S_RX_THLD_SHIFT)) static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave); static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave); -- cgit From 514bfc64efa52848fa862010060af666f5e4a74c Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:31 +0530 Subject: i2c: iproc: fix typo in slave_isr function Fix typo in bcm_iproc_i2c_slave_isr(). Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index cd687696bf0b..7a235f9f5884 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -382,7 +382,7 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, if (status & BIT(IS_S_START_BUSY_SHIFT)) { i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); /* - * Enable interrupt for TX FIFO becomes empty and + * Disable interrupt for TX FIFO becomes empty and * less than PKT_LENGTH bytes were output on the SMBUS */ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); -- cgit From e21d79778768e4e187b2892d662c6aaa01e1d399 Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:32 +0530 Subject: i2c: iproc: handle master read request Handle single or multi byte master read request with or without repeated start. Fixes: c245d94ed106 ("i2c: iproc: Add multi byte read-write support for slave mode") Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 215 +++++++++++++++++++++++++++++-------- 1 file changed, 170 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 7a235f9f5884..22e04055b447 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -160,6 +160,11 @@ #define IE_S_ALL_INTERRUPT_SHIFT 21 #define IE_S_ALL_INTERRUPT_MASK 0x3f +/* + * It takes ~18us to reading 10bytes of data, hence to keep tasklet + * running for less time, max slave read per tasklet is set to 10 bytes. + */ +#define MAX_SLAVE_RX_PER_INT 10 enum i2c_slave_read_status { I2C_SLAVE_RX_FIFO_EMPTY = 0, @@ -206,8 +211,18 @@ struct bcm_iproc_i2c_dev { /* bytes that have been read */ unsigned int rx_bytes; unsigned int thld_bytes; + + bool slave_rx_only; + bool rx_start_rcvd; + bool slave_read_complete; + u32 tx_underrun; + u32 slave_int_mask; + struct tasklet_struct slave_rx_tasklet; }; +/* tasklet to process slave rx data */ +static void slave_rx_tasklet_fn(unsigned long); + /* * Can be expanded in the future if more interrupt status bits are utilized */ @@ -261,6 +276,7 @@ static void bcm_iproc_i2c_slave_init( { u32 val; + iproc_i2c->tx_underrun = 0; if (need_reset) { /* put controller in reset */ val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET); @@ -297,8 +313,11 @@ static void bcm_iproc_i2c_slave_init( /* Enable interrupt register to indicate a valid byte in receive fifo */ val = BIT(IE_S_RX_EVENT_SHIFT); + /* Enable interrupt register to indicate a Master read transaction */ + val |= BIT(IE_S_RD_EVENT_SHIFT); /* Enable interrupt register for the Slave BUSY command */ val |= BIT(IE_S_START_BUSY_SHIFT); + iproc_i2c->slave_int_mask = val; iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); } @@ -324,76 +343,176 @@ static void bcm_iproc_i2c_check_slave_status( } } -static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, - u32 status) +static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c) { + u8 rx_data, rx_status; + u32 rx_bytes = 0; u32 val; - u8 value, rx_status; - /* Slave RX byte receive */ - if (status & BIT(IS_S_RX_EVENT_SHIFT)) { + while (rx_bytes < MAX_SLAVE_RX_PER_INT) { val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK; - if (rx_status == I2C_SLAVE_RX_START) { - /* Start of SMBUS for Master write */ - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_REQUESTED, &value); + rx_data = ((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); - val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); - value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); + if (rx_status == I2C_SLAVE_RX_START) { + /* Start of SMBUS Master write */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_RECEIVED, &value); - } else if (status & BIT(IS_S_RD_EVENT_SHIFT)) { - /* Start of SMBUS for Master Read */ + I2C_SLAVE_WRITE_REQUESTED, &rx_data); + iproc_i2c->rx_start_rcvd = true; + iproc_i2c->slave_read_complete = false; + } else if (rx_status == I2C_SLAVE_RX_DATA && + iproc_i2c->rx_start_rcvd) { + /* Middle of SMBUS Master write */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_REQUESTED, &value); - iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + I2C_SLAVE_WRITE_RECEIVED, &rx_data); + } else if (rx_status == I2C_SLAVE_RX_END && + iproc_i2c->rx_start_rcvd) { + /* End of SMBUS Master write */ + if (iproc_i2c->slave_rx_only) + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_WRITE_RECEIVED, + &rx_data); + + i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, + &rx_data); + } else if (rx_status == I2C_SLAVE_RX_FIFO_EMPTY) { + iproc_i2c->rx_start_rcvd = false; + iproc_i2c->slave_read_complete = true; + break; + } - val = BIT(S_CMD_START_BUSY_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + rx_bytes++; + } +} - /* - * Enable interrupt for TX FIFO becomes empty and - * less than PKT_LENGTH bytes were output on the SMBUS - */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val |= BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); - } else { - /* Master write other than start */ - value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); +static void slave_rx_tasklet_fn(unsigned long data) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = (struct bcm_iproc_i2c_dev *)data; + u32 int_clr; + + bcm_iproc_i2c_slave_read(iproc_i2c); + + /* clear pending IS_S_RX_EVENT_SHIFT interrupt */ + int_clr = BIT(IS_S_RX_EVENT_SHIFT); + + if (!iproc_i2c->slave_rx_only && iproc_i2c->slave_read_complete) { + /* + * In case of single byte master-read request, + * IS_S_TX_UNDERRUN_SHIFT event is generated before + * IS_S_START_BUSY_SHIFT event. Hence start slave data send + * from first IS_S_TX_UNDERRUN_SHIFT event. + * + * This means don't send any data from slave when + * IS_S_RD_EVENT_SHIFT event is generated else it will increment + * eeprom or other backend slave driver read pointer twice. + */ + iproc_i2c->tx_underrun = 0; + iproc_i2c->slave_int_mask |= BIT(IE_S_TX_UNDERRUN_SHIFT); + + /* clear IS_S_RD_EVENT_SHIFT interrupt */ + int_clr |= BIT(IS_S_RD_EVENT_SHIFT); + } + + /* clear slave interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, int_clr); + /* enable slave interrupts */ + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, iproc_i2c->slave_int_mask); +} + +static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, + u32 status) +{ + u32 val; + u8 value; + + /* + * Slave events in case of master-write, master-write-read and, + * master-read + * + * Master-write : only IS_S_RX_EVENT_SHIFT event + * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events + * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events or only IS_S_RD_EVENT_SHIFT + */ + if (status & BIT(IS_S_RX_EVENT_SHIFT) || + status & BIT(IS_S_RD_EVENT_SHIFT)) { + /* disable slave interrupts */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~iproc_i2c->slave_int_mask; + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + + if (status & BIT(IS_S_RD_EVENT_SHIFT)) + /* Master-write-read request */ + iproc_i2c->slave_rx_only = false; + else + /* Master-write request only */ + iproc_i2c->slave_rx_only = true; + + /* schedule tasklet to read data later */ + tasklet_schedule(&iproc_i2c->slave_rx_tasklet); + + /* clear only IS_S_RX_EVENT_SHIFT interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_RX_EVENT_SHIFT)); + } + + if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { + iproc_i2c->tx_underrun++; + if (iproc_i2c->tx_underrun == 1) + /* Start of SMBUS for Master Read */ 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 */ - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_PROCESSED, &value); + I2C_SLAVE_READ_REQUESTED, + &value); + else + /* Master read other than start */ + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_READ_PROCESSED, + &value); iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + /* start transfer */ val = BIT(S_CMD_START_BUSY_SHIFT); iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + + /* clear interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_TX_UNDERRUN_SHIFT)); } - /* Stop */ + /* Stop received from master in case of master read transaction */ if (status & BIT(IS_S_START_BUSY_SHIFT)) { - i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); /* * Disable interrupt for TX FIFO becomes empty and * less than PKT_LENGTH bytes were output on the SMBUS */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, + iproc_i2c->slave_int_mask); + + /* End of SMBUS for Master Read */ + val = BIT(S_TX_WR_STATUS_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val); + + val = BIT(S_CMD_START_BUSY_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); + + /* flush TX FIFOs */ + val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET); + val |= (BIT(S_FIFO_TX_FLUSH_SHIFT)); + iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val); + + i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); + + /* clear interrupt */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, + BIT(IS_S_START_BUSY_SHIFT)); } - /* clear interrupt status */ - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status); + /* check slave transmit status only if slave is transmitting */ + if (!iproc_i2c->slave_rx_only) + bcm_iproc_i2c_check_slave_status(iproc_i2c); - bcm_iproc_i2c_check_slave_status(iproc_i2c); return true; } @@ -1074,6 +1193,10 @@ static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave) return -EAFNOSUPPORT; iproc_i2c->slave = slave; + + tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn, + (unsigned long)iproc_i2c); + bcm_iproc_i2c_slave_init(iproc_i2c, false); return 0; } @@ -1094,6 +1217,8 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave) IE_S_ALL_INTERRUPT_SHIFT); iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp); + tasklet_kill(&iproc_i2c->slave_rx_tasklet); + /* Erase the slave address programmed */ tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET); tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT); -- cgit From 4d658451c9d620ab8fb79483bf83d65b14375723 Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Mon, 2 Nov 2020 09:24:33 +0530 Subject: i2c: iproc: handle rx fifo full interrupt Add code to handle IS_S_RX_FIFO_FULL_SHIFT interrupt to support master write request with >= 64 bytes. Iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes full. This can happen if master issues write request of more than 64 bytes. Signed-off-by: Rayagonda Kokatanur Acked-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 22e04055b447..cceaf69279a9 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -313,6 +313,8 @@ static void bcm_iproc_i2c_slave_init( /* Enable interrupt register to indicate a valid byte in receive fifo */ val = BIT(IE_S_RX_EVENT_SHIFT); + /* Enable interrupt register to indicate Slave Rx FIFO Full */ + val |= BIT(IE_S_RX_FIFO_FULL_SHIFT); /* Enable interrupt register to indicate a Master read transaction */ val |= BIT(IE_S_RD_EVENT_SHIFT); /* Enable interrupt register for the Slave BUSY command */ @@ -434,9 +436,15 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, * events * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT * events or only IS_S_RD_EVENT_SHIFT + * + * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt + * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes + * full. This can happen if Master issues write requests of more than + * 64 bytes. */ if (status & BIT(IS_S_RX_EVENT_SHIFT) || - status & BIT(IS_S_RD_EVENT_SHIFT)) { + status & BIT(IS_S_RD_EVENT_SHIFT) || + status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { /* disable slave interrupts */ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); val &= ~iproc_i2c->slave_int_mask; @@ -452,9 +460,14 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, /* schedule tasklet to read data later */ tasklet_schedule(&iproc_i2c->slave_rx_tasklet); - /* clear only IS_S_RX_EVENT_SHIFT interrupt */ - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, - BIT(IS_S_RX_EVENT_SHIFT)); + /* + * clear only IS_S_RX_EVENT_SHIFT and + * IS_S_RX_FIFO_FULL_SHIFT interrupt. + */ + val = BIT(IS_S_RX_EVENT_SHIFT); + if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) + val |= BIT(IS_S_RX_FIFO_FULL_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val); } if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { -- cgit From 61adf63a1108f6d35a36adfd0dbd59bd3246a6c5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 14 Dec 2020 17:00:44 +0100 Subject: i2c: gpio: fix MODULE_LICENCE Let MODULE_LICENCE match the SPDX header which is correctly based on the previous textual description. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index a4a6825c8758..7a048abbf92b 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -520,5 +520,5 @@ module_exit(i2c_gpio_exit); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:i2c-gpio"); -- cgit From 2478b9c1dcc9aa84cfd71ed7b5ca2a2c0ede75b7 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Fri, 25 Dec 2020 16:40:06 +0800 Subject: i2c: fix platform_get_irq.cocci warnings Remove dev_err() messages after platform_get_irq*() failures. drivers/i2c/busses/i2c-hix5hd2.c:417:2-9: line 417 is redundant because platform_get_irq() already prints an error Signed-off-by: Tian Tao Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-hix5hd2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index ab15b1ec2ab3..c45f226c2b85 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -413,10 +413,8 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) return PTR_ERR(priv->regs); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n"); + if (irq <= 0) return irq; - } priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { -- cgit From 9d64834b2a68b1c969f8c8d845471c0e91191549 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Tue, 22 Dec 2020 21:31:31 +0800 Subject: i2c: use DIV_ROUND_UP macro to do calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't open-code DIV_ROUND_UP() kernel macro. Signed-off-by: Zheng Yongjun Reviewed-by: Fabio Estevam Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index b444fbf1a262..149e2898cd2f 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -537,7 +537,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, i2c_imx->cur_clk = i2c_clk_rate; - div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; + div = DIV_ROUND_UP(i2c_clk_rate, i2c_imx->bitrate); if (div < i2c_clk_div[0].div) i = 0; else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) @@ -555,8 +555,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, * This delay is used in I2C bus disable function * to fix chip hardware bug. */ - i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div - + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); + i2c_imx->disable_delay = DIV_ROUND_UP(500000U * i2c_clk_div[i].div, + i2c_clk_rate / 2); #ifdef CONFIG_I2C_DEBUG_BUS dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n", -- cgit From 45c6c873c0ec3fab35aca3ef81b36cd3b1599d98 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Mon, 28 Dec 2020 21:51:20 +0800 Subject: i2c: busses: Use DEFINE_SPINLOCK() for spinlock spinlock can be initialized automatically with DEFINE_SPINLOCK() rather than explicitly calling spin_lock_init(). Signed-off-by: Zheng Yongjun Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-elektor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 140426db28df..671f9ac8387e 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -49,7 +49,7 @@ static int mmapped; static wait_queue_head_t pcf_wait; static int pcf_pending; -static spinlock_t lock; +static DEFINE_SPINLOCK(lock); static struct i2c_adapter pcf_isa_ops; @@ -132,7 +132,6 @@ static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) { static int pcf_isa_init(void) { - spin_lock_init(&lock); if (!mmapped) { if (!request_region(base, 2, pcf_isa_ops.name)) { printk(KERN_ERR "%s: requested I/O region (%#x:2) is " -- cgit From 66b0c2846ba8de569026a067bb5a34ea5768408c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 6 Jan 2021 01:33:47 +0200 Subject: i2c: mlxcpld: Add support for I2C bus frequency setting Add support for I2C bus frequency setting according to the specific system capability. This capability is obtained from CPLD frequency setting register, which could be provided through the platform data. If such register is provided, it specifies minimal I2C bus frequency to be used for the devices attached to the I2C bus. Supported freqeuncies are 100KHz, 400KHz, 1MHz, while 100KHz is the default. Signed-off-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 63 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 9e45214d1eb6..4e0b7c2882ce 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include /* General defines */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000 @@ -46,6 +48,16 @@ #define MLXCPLD_LPCI2C_ACK_IND 1 #define MLXCPLD_LPCI2C_NACK_IND 2 +#define MLXCPLD_I2C_FREQ_1000KHZ_SET 0x04 +#define MLXCPLD_I2C_FREQ_400KHZ_SET 0x0f +#define MLXCPLD_I2C_FREQ_100KHZ_SET 0x42 + +enum mlxcpld_i2c_frequency { + MLXCPLD_I2C_FREQ_1000KHZ = 1, + MLXCPLD_I2C_FREQ_400KHZ = 2, + MLXCPLD_I2C_FREQ_100KHZ = 3, +}; + struct mlxcpld_i2c_curr_xfer { u8 cmd; u8 addr_width; @@ -463,8 +475,45 @@ static struct i2c_adapter mlxcpld_i2c_adapter = { .nr = MLXCPLD_I2C_BUS_NUM, }; +static int +mlxcpld_i2c_set_frequency(struct mlxcpld_i2c_priv *priv, + struct mlxreg_core_hotplug_platform_data *pdata) +{ + struct mlxreg_core_item *item = pdata->items; + struct mlxreg_core_data *data; + u32 regval; + u8 freq; + int err; + + if (!item) + return 0; + + /* Read frequency setting. */ + data = item->data; + err = regmap_read(pdata->regmap, data->reg, ®val); + if (err) + return err; + + /* Set frequency only if it is not 100KHz, which is default. */ + switch ((data->reg & data->mask) >> data->bit) { + case MLXCPLD_I2C_FREQ_1000KHZ: + freq = MLXCPLD_I2C_FREQ_1000KHZ_SET; + break; + case MLXCPLD_I2C_FREQ_400KHZ: + freq = MLXCPLD_I2C_FREQ_400KHZ_SET; + break; + default: + return 0; + } + + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_HALF_CYC_REG, &freq, 1); + + return 0; +} + static int mlxcpld_i2c_probe(struct platform_device *pdev) { + struct mlxreg_core_hotplug_platform_data *pdata; struct mlxcpld_i2c_priv *priv; int err; u8 val; @@ -479,6 +528,14 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + /* Set I2C bus frequency if platform data provides this info. */ + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + err = mlxcpld_i2c_set_frequency(priv, pdata); + if (err) + goto mlxcpld_i2_probe_failed; + } + /* Register with i2c layer */ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); /* Read capability register */ @@ -497,8 +554,12 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) err = i2c_add_numbered_adapter(&priv->adap); if (err) - mutex_destroy(&priv->lock); + goto mlxcpld_i2_probe_failed; + return 0; + +mlxcpld_i2_probe_failed: + mutex_destroy(&priv->lock); return err; } -- cgit From f0535df039e225983506351c943d11ee954e88c9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 11 Jan 2021 21:40:38 +0100 Subject: i2c: smbus: switch from loops to memcpy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When copying memory from one buffer to another, instead of open-coding loops with byte-by-byte copies let's use memcpy() which might be a bit faster and makes intent more clear. Signed-off-by: Dmitry Torokhov Reviewed-by: Luca Ceresoli Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index f5c9787992e9..bf6bfe7c5cfe 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -398,8 +398,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, } i2c_smbus_try_get_dmabuf(&msg[0], command); - for (i = 1; i < msg[0].len; i++) - msg[0].buf[i] = data->block[i - 1]; + memcpy(msg[0].buf + 1, data->block, msg[0].len - 1); } break; case I2C_SMBUS_BLOCK_PROC_CALL: @@ -414,8 +413,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, msg[0].len = data->block[0] + 2; i2c_smbus_try_get_dmabuf(&msg[0], command); - for (i = 1; i < msg[0].len; i++) - msg[0].buf[i] = data->block[i - 1]; + memcpy(msg[0].buf + 1, data->block, msg[0].len - 1); msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by @@ -437,8 +435,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, msg[0].len = data->block[0] + 1; i2c_smbus_try_get_dmabuf(&msg[0], command); - for (i = 1; i <= data->block[0]; i++) - msg[0].buf[i] = data->block[i]; + memcpy(msg[0].buf + 1, data->block + 1, data->block[0]); } break; default: @@ -490,8 +487,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; case I2C_SMBUS_I2C_BLOCK_DATA: - for (i = 0; i < data->block[0]; i++) - data->block[i + 1] = msg[1].buf[i]; + memcpy(data->block + 1, msg[1].buf, data->block[0]); break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: @@ -502,8 +498,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, status = -EPROTO; goto cleanup; } - for (i = 0; i < msg[1].buf[0] + 1; i++) - data->block[i] = msg[1].buf[i]; + memcpy(data->block, msg[1].buf, msg[1].buf[0] + 1); break; } -- cgit From e4555a32ba427e628b75fa03593d55b1f38527b1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 15 Jan 2021 16:51:28 +0100 Subject: i2c: Drop unused efm32 bus driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for this machine was just removed, so drop the now unused i2c bus driver, too. Signed-off-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 7 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-efm32.c | 469 ----------------------------------------- 3 files changed, 477 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-efm32.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d4d60ad0eda0..fd919f9339d6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -586,13 +586,6 @@ config I2C_DIGICOLOR This driver can also be built as a module. If so, the module will be called i2c-digicolor. -config I2C_EFM32 - tristate "EFM32 I2C controller" - depends on ARCH_EFM32 || COMPILE_TEST - help - This driver supports the i2c block found in Energy Micro's EFM32 - SoCs. - config I2C_EG20T tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" depends on PCI && (X86_32 || MIPS || COMPILE_TEST) diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 683c49faca05..894ff95885b8 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -58,7 +58,6 @@ i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-bayt obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-y := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o -obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c deleted file mode 100644 index f6e13ceeb2b3..000000000000 --- a/drivers/i2c/busses/i2c-efm32.c +++ /dev/null @@ -1,469 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix - */ -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "efm32-i2c" - -#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask) - -#define REG_CTRL 0x00 -#define REG_CTRL_EN 0x00001 -#define REG_CTRL_SLAVE 0x00002 -#define REG_CTRL_AUTOACK 0x00004 -#define REG_CTRL_AUTOSE 0x00008 -#define REG_CTRL_AUTOSN 0x00010 -#define REG_CTRL_ARBDIS 0x00020 -#define REG_CTRL_GCAMEN 0x00040 -#define REG_CTRL_CLHR__MASK 0x00300 -#define REG_CTRL_BITO__MASK 0x03000 -#define REG_CTRL_BITO_OFF 0x00000 -#define REG_CTRL_BITO_40PCC 0x01000 -#define REG_CTRL_BITO_80PCC 0x02000 -#define REG_CTRL_BITO_160PCC 0x03000 -#define REG_CTRL_GIBITO 0x08000 -#define REG_CTRL_CLTO__MASK 0x70000 -#define REG_CTRL_CLTO_OFF 0x00000 - -#define REG_CMD 0x04 -#define REG_CMD_START 0x00001 -#define REG_CMD_STOP 0x00002 -#define REG_CMD_ACK 0x00004 -#define REG_CMD_NACK 0x00008 -#define REG_CMD_CONT 0x00010 -#define REG_CMD_ABORT 0x00020 -#define REG_CMD_CLEARTX 0x00040 -#define REG_CMD_CLEARPC 0x00080 - -#define REG_STATE 0x08 -#define REG_STATE_BUSY 0x00001 -#define REG_STATE_MASTER 0x00002 -#define REG_STATE_TRANSMITTER 0x00004 -#define REG_STATE_NACKED 0x00008 -#define REG_STATE_BUSHOLD 0x00010 -#define REG_STATE_STATE__MASK 0x000e0 -#define REG_STATE_STATE_IDLE 0x00000 -#define REG_STATE_STATE_WAIT 0x00020 -#define REG_STATE_STATE_START 0x00040 -#define REG_STATE_STATE_ADDR 0x00060 -#define REG_STATE_STATE_ADDRACK 0x00080 -#define REG_STATE_STATE_DATA 0x000a0 -#define REG_STATE_STATE_DATAACK 0x000c0 - -#define REG_STATUS 0x0c -#define REG_STATUS_PSTART 0x00001 -#define REG_STATUS_PSTOP 0x00002 -#define REG_STATUS_PACK 0x00004 -#define REG_STATUS_PNACK 0x00008 -#define REG_STATUS_PCONT 0x00010 -#define REG_STATUS_PABORT 0x00020 -#define REG_STATUS_TXC 0x00040 -#define REG_STATUS_TXBL 0x00080 -#define REG_STATUS_RXDATAV 0x00100 - -#define REG_CLKDIV 0x10 -#define REG_CLKDIV_DIV__MASK 0x001ff -#define REG_CLKDIV_DIV(div) MASK_VAL(REG_CLKDIV_DIV__MASK, (div)) - -#define REG_SADDR 0x14 -#define REG_SADDRMASK 0x18 -#define REG_RXDATA 0x1c -#define REG_RXDATAP 0x20 -#define REG_TXDATA 0x24 -#define REG_IF 0x28 -#define REG_IF_START 0x00001 -#define REG_IF_RSTART 0x00002 -#define REG_IF_ADDR 0x00004 -#define REG_IF_TXC 0x00008 -#define REG_IF_TXBL 0x00010 -#define REG_IF_RXDATAV 0x00020 -#define REG_IF_ACK 0x00040 -#define REG_IF_NACK 0x00080 -#define REG_IF_MSTOP 0x00100 -#define REG_IF_ARBLOST 0x00200 -#define REG_IF_BUSERR 0x00400 -#define REG_IF_BUSHOLD 0x00800 -#define REG_IF_TXOF 0x01000 -#define REG_IF_RXUF 0x02000 -#define REG_IF_BITO 0x04000 -#define REG_IF_CLTO 0x08000 -#define REG_IF_SSTOP 0x10000 - -#define REG_IFS 0x2c -#define REG_IFC 0x30 -#define REG_IFC__MASK 0x1ffcf - -#define REG_IEN 0x34 - -#define REG_ROUTE 0x38 -#define REG_ROUTE_SDAPEN 0x00001 -#define REG_ROUTE_SCLPEN 0x00002 -#define REG_ROUTE_LOCATION__MASK 0x00700 -#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n)) - -struct efm32_i2c_ddata { - struct i2c_adapter adapter; - - struct clk *clk; - void __iomem *base; - unsigned int irq; - u8 location; - unsigned long frequency; - - /* transfer data */ - struct completion done; - struct i2c_msg *msgs; - size_t num_msgs; - size_t current_word, current_msg; - int retval; -}; - -static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset) -{ - return readl(ddata->base + offset); -} - -static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata, - unsigned offset, u32 value) -{ - writel(value, ddata->base + offset); -} - -static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata) -{ - struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; - - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START); - efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg)); -} - -static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata) -{ - struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; - - if (ddata->current_word >= cur_msg->len) { - /* cur_msg completely transferred */ - ddata->current_word = 0; - ddata->current_msg += 1; - - if (ddata->current_msg >= ddata->num_msgs) { - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP); - complete(&ddata->done); - } else { - efm32_i2c_send_next_msg(ddata); - } - } else { - efm32_i2c_write32(ddata, REG_TXDATA, - cur_msg->buf[ddata->current_word++]); - } -} - -static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata) -{ - struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; - - cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA); - ddata->current_word += 1; - if (ddata->current_word >= cur_msg->len) { - /* cur_msg completely transferred */ - ddata->current_word = 0; - ddata->current_msg += 1; - - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK); - - if (ddata->current_msg >= ddata->num_msgs) { - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP); - complete(&ddata->done); - } else { - efm32_i2c_send_next_msg(ddata); - } - } else { - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK); - } -} - -static irqreturn_t efm32_i2c_irq(int irq, void *dev_id) -{ - struct efm32_i2c_ddata *ddata = dev_id; - struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; - u32 irqflag = efm32_i2c_read32(ddata, REG_IF); - u32 state = efm32_i2c_read32(ddata, REG_STATE); - - efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK); - - switch (state & REG_STATE_STATE__MASK) { - case REG_STATE_STATE_IDLE: - /* arbitration lost? */ - ddata->retval = -EAGAIN; - complete(&ddata->done); - break; - case REG_STATE_STATE_WAIT: - /* - * huh, this shouldn't happen. - * Reset hardware state and get out - */ - ddata->retval = -EIO; - efm32_i2c_write32(ddata, REG_CMD, - REG_CMD_STOP | REG_CMD_ABORT | - REG_CMD_CLEARTX | REG_CMD_CLEARPC); - complete(&ddata->done); - break; - case REG_STATE_STATE_START: - /* "caller" is expected to send an address */ - break; - case REG_STATE_STATE_ADDR: - /* wait for Ack or NAck of slave */ - break; - case REG_STATE_STATE_ADDRACK: - if (state & REG_STATE_NACKED) { - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP); - ddata->retval = -ENXIO; - complete(&ddata->done); - } else if (cur_msg->flags & I2C_M_RD) { - /* wait for slave to send first data byte */ - } else { - efm32_i2c_send_next_byte(ddata); - } - break; - case REG_STATE_STATE_DATA: - if (cur_msg->flags & I2C_M_RD) { - efm32_i2c_recv_next_byte(ddata); - } else { - /* wait for Ack or Nack of slave */ - } - break; - case REG_STATE_STATE_DATAACK: - if (state & REG_STATE_NACKED) { - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP); - complete(&ddata->done); - } else { - efm32_i2c_send_next_byte(ddata); - } - } - - return IRQ_HANDLED; -} - -static int efm32_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap); - int ret; - - if (ddata->msgs) - return -EBUSY; - - ddata->msgs = msgs; - ddata->num_msgs = num; - ddata->current_word = 0; - ddata->current_msg = 0; - ddata->retval = -EIO; - - reinit_completion(&ddata->done); - - dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n", - efm32_i2c_read32(ddata, REG_STATE), - efm32_i2c_read32(ddata, REG_STATUS)); - - efm32_i2c_send_next_msg(ddata); - - wait_for_completion(&ddata->done); - - if (ddata->current_msg >= ddata->num_msgs) - ret = ddata->num_msgs; - else - ret = ddata->retval; - - return ret; -} - -static u32 efm32_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm efm32_i2c_algo = { - .master_xfer = efm32_i2c_master_xfer, - .functionality = efm32_i2c_functionality, -}; - -static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata) -{ - u32 reg = efm32_i2c_read32(ddata, REG_ROUTE); - - return (reg & REG_ROUTE_LOCATION__MASK) >> - __ffs(REG_ROUTE_LOCATION__MASK); -} - -static int efm32_i2c_probe(struct platform_device *pdev) -{ - struct efm32_i2c_ddata *ddata; - struct resource *res; - unsigned long rate; - struct device_node *np = pdev->dev.of_node; - u32 location, frequency; - int ret; - u32 clkdiv; - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - platform_set_drvdata(pdev, ddata); - - init_completion(&ddata->done); - strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name)); - ddata->adapter.owner = THIS_MODULE; - ddata->adapter.algo = &efm32_i2c_algo; - ddata->adapter.dev.parent = &pdev->dev; - ddata->adapter.dev.of_node = pdev->dev.of_node; - i2c_set_adapdata(&ddata->adapter, ddata); - - ddata->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ddata->clk)) { - ret = PTR_ERR(ddata->clk); - dev_err(&pdev->dev, "failed to get clock: %d\n", ret); - return ret; - } - - ddata->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(ddata->base)) - return PTR_ERR(ddata->base); - - if (resource_size(res) < 0x42) { - dev_err(&pdev->dev, "memory resource too small\n"); - return -EINVAL; - } - - ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - if (!ret) - ret = -EINVAL; - return ret; - } - - ddata->irq = ret; - - ret = clk_prepare_enable(ddata->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret); - return ret; - } - - - ret = of_property_read_u32(np, "energymicro,location", &location); - - if (ret) - /* fall back to wrongly namespaced property */ - ret = of_property_read_u32(np, "efm32,location", &location); - - if (!ret) { - dev_dbg(&pdev->dev, "using location %u\n", location); - } else { - /* default to location configured in hardware */ - location = efm32_i2c_get_configured_location(ddata); - - dev_info(&pdev->dev, "fall back to location %u\n", location); - } - - ddata->location = location; - - ret = of_property_read_u32(np, "clock-frequency", &frequency); - if (!ret) { - dev_dbg(&pdev->dev, "using frequency %u\n", frequency); - } else { - frequency = I2C_MAX_STANDARD_MODE_FREQ; - dev_info(&pdev->dev, "defaulting to 100 kHz\n"); - } - ddata->frequency = frequency; - - rate = clk_get_rate(ddata->clk); - if (!rate) { - dev_err(&pdev->dev, "there is no input clock available\n"); - ret = -EINVAL; - goto err_disable_clk; - } - clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1; - if (clkdiv >= 0x200) { - dev_err(&pdev->dev, - "input clock too fast (%lu) to divide down to bus freq (%lu)", - rate, ddata->frequency); - ret = -EINVAL; - goto err_disable_clk; - } - - dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n", - rate, ddata->frequency, (unsigned long)clkdiv); - efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv)); - - efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN | - REG_ROUTE_SCLPEN | - REG_ROUTE_LOCATION(ddata->location)); - - efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN | - REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO); - - efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK); - efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK - | REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV); - - /* to make bus idle */ - efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT); - - ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq (%d)\n", ret); - goto err_disable_clk; - } - - ret = i2c_add_adapter(&ddata->adapter); - if (ret) { - free_irq(ddata->irq, ddata); - -err_disable_clk: - clk_disable_unprepare(ddata->clk); - } - return ret; -} - -static int efm32_i2c_remove(struct platform_device *pdev) -{ - struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev); - - i2c_del_adapter(&ddata->adapter); - free_irq(ddata->irq, ddata); - clk_disable_unprepare(ddata->clk); - - return 0; -} - -static const struct of_device_id efm32_i2c_dt_ids[] = { - { - .compatible = "energymicro,efm32-i2c", - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids); - -static struct platform_driver efm32_i2c_driver = { - .probe = efm32_i2c_probe, - .remove = efm32_i2c_remove, - - .driver = { - .name = DRIVER_NAME, - .of_match_table = efm32_i2c_dt_ids, - }, -}; -module_platform_driver(efm32_i2c_driver); - -MODULE_AUTHOR("Uwe Kleine-Koenig "); -MODULE_DESCRIPTION("EFM32 i2c driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit From 19eb29b05cc6dd6842ddc475a45da6723428e927 Mon Sep 17 00:00:00 2001 From: Evan Green Date: Wed, 18 Nov 2020 15:40:24 -0800 Subject: i2c: i2c-mux-gpio: Factor out pdev->dev in _probe_dt() Factor out &pdev->dev into a local variable in preparation for the ACPI enablement of this function, which will utilize the variable more. Signed-off-by: Evan Green Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 4effe563e9e8..caaa782b50d8 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -53,6 +53,7 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; struct device_node *adapter_np, *child; struct i2c_adapter *adapter; @@ -77,11 +78,11 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, mux->data.n_values = of_get_child_count(np); - values = devm_kcalloc(&pdev->dev, + values = devm_kcalloc(dev, mux->data.n_values, sizeof(*mux->data.values), GFP_KERNEL); if (!values) { - dev_err(&pdev->dev, "Cannot allocate values array"); + dev_err(dev, "Cannot allocate values array"); return -ENOMEM; } -- cgit From 98b2b712bc8592c4ad212449162e36e47761a46c Mon Sep 17 00:00:00 2001 From: Evan Green Date: Wed, 18 Nov 2020 15:40:25 -0800 Subject: i2c: i2c-mux-gpio: Enable this driver in ACPI land Enable i2c-mux-gpio devices to be defined via ACPI. The idle-state property translates directly to a fwnode_property_*() call. The child reg property translates naturally into _ADR in ACPI. The i2c-parent binding is a relic from the days when the bindings dictated that all direct children of an I2C controller had to be I2C devices. These days that's no longer required. The i2c-mux can sit as a direct child of its parent controller, which is where it makes the most sense from a hardware description perspective. For the ACPI implementation we'll assume that's always how the i2c-mux-gpio is instantiated. Signed-off-by: Evan Green Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 107 +++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index caaa782b50d8..bac415a52b78 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -49,35 +49,85 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) return 0; } -#ifdef CONFIG_OF -static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, - struct platform_device *pdev) +#ifdef CONFIG_ACPI + +static int i2c_mux_gpio_get_acpi_adr(struct device *dev, + struct fwnode_handle *fwdev, + unsigned int *adr) + +{ + unsigned long long adr64; + acpi_status status; + + status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev), + METHOD_NAME__ADR, + NULL, &adr64); + + if (!ACPI_SUCCESS(status)) { + dev_err(dev, "Cannot get address\n"); + return -EINVAL; + } + + *adr = adr64; + if (*adr != adr64) { + dev_err(dev, "Address out of range\n"); + return -ERANGE; + } + + return 0; +} + +#else + +static int i2c_mux_gpio_get_acpi_adr(struct device *dev, + struct fwnode_handle *fwdev, + unsigned int *adr) +{ + return -EINVAL; +} + +#endif + +static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, + struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; - struct device_node *adapter_np, *child; - struct i2c_adapter *adapter; + struct device_node *np = dev->of_node; + struct device_node *adapter_np; + struct i2c_adapter *adapter = NULL; + struct fwnode_handle *child; unsigned *values; - int i = 0; + int rc, i = 0; + + if (is_of_node(dev->fwnode)) { + if (!np) + return -ENODEV; - if (!np) - return -ENODEV; + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); + + } else if (is_acpi_node(dev->fwnode)) { + /* + * In ACPI land the mux should be a direct child of the i2c + * bus it muxes. + */ + acpi_handle dev_handle = ACPI_HANDLE(dev->parent); - adapter_np = of_parse_phandle(np, "i2c-parent", 0); - if (!adapter_np) { - dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); - return -ENODEV; + adapter = i2c_acpi_find_adapter_by_handle(dev_handle); } - adapter = of_find_i2c_adapter_by_node(adapter_np); - of_node_put(adapter_np); + if (!adapter) return -EPROBE_DEFER; mux->data.parent = i2c_adapter_id(adapter); put_device(&adapter->dev); - mux->data.n_values = of_get_child_count(np); - + mux->data.n_values = device_get_child_node_count(dev); values = devm_kcalloc(dev, mux->data.n_values, sizeof(*mux->data.values), GFP_KERNEL); @@ -86,24 +136,25 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, return -ENOMEM; } - for_each_child_of_node(np, child) { - of_property_read_u32(child, "reg", values + i); + device_for_each_child_node(dev, child) { + if (is_of_node(child)) { + fwnode_property_read_u32(child, "reg", values + i); + + } else if (is_acpi_node(child)) { + rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i); + if (rc) + return rc; + } + i++; } mux->data.values = values; - if (of_property_read_u32(np, "idle-state", &mux->data.idle)) + if (fwnode_property_read_u32(dev->fwnode, "idle-state", &mux->data.idle)) mux->data.idle = I2C_MUX_GPIO_NO_IDLE; return 0; } -#else -static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, - struct platform_device *pdev) -{ - return 0; -} -#endif static int i2c_mux_gpio_probe(struct platform_device *pdev) { @@ -119,7 +170,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) return -ENOMEM; if (!dev_get_platdata(&pdev->dev)) { - ret = i2c_mux_gpio_probe_dt(mux, pdev); + ret = i2c_mux_gpio_probe_fw(mux, pdev); if (ret < 0) return ret; } else { -- cgit From bed3139613ea1665f7bbd0a53b247e7b2d43e2b1 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Wed, 13 Jan 2021 18:44:56 -0800 Subject: i2c: stub: remove definition of DEBUG Defining DEBUG should only be done in development. So remove DEBUG. Signed-off-by: Tom Rix Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-stub.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c index 537a598e22db..d642cad219d9 100644 --- a/drivers/i2c/i2c-stub.c +++ b/drivers/i2c/i2c-stub.c @@ -7,7 +7,6 @@ */ -#define DEBUG 1 #define pr_fmt(fmt) "i2c-stub: " fmt #include -- cgit From 2cea84ddae1cc3af3969bfeae015aa303bf6e08d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 20 Jan 2021 14:28:32 +0100 Subject: i2c: remove sirf bus driver The CSR SiRF prima2/atlas platforms are getting removed, so this driver is no longer needed. Signed-off-by: Arnd Bergmann Acked-by: Barry Song Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-sirf.c | 475 ------------------------------------------ 3 files changed, 486 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-sirf.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fd919f9339d6..ce2efb56df54 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -993,16 +993,6 @@ config I2C_SIMTEC This driver can also be built as a module. If so, the module will be called i2c-simtec. -config I2C_SIRF - tristate "CSR SiRFprimaII I2C interface" - depends on ARCH_SIRF || COMPILE_TEST - help - If you say yes to this option, support will be included for the - CSR SiRFprimaII I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-sirf. - config I2C_SPRD tristate "Spreadtrum I2C interface" depends on I2C=y && (ARCH_SPRD || COMPILE_TEST) diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 894ff95885b8..1c30bba977ef 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -98,7 +98,6 @@ obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o -obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c deleted file mode 100644 index 30db8fafe078..000000000000 --- a/drivers/i2c/busses/i2c-sirf.c +++ /dev/null @@ -1,475 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * I2C bus driver for CSR SiRFprimaII - * - * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SIRFSOC_I2C_CLK_CTRL 0x00 -#define SIRFSOC_I2C_STATUS 0x0C -#define SIRFSOC_I2C_CTRL 0x10 -#define SIRFSOC_I2C_IO_CTRL 0x14 -#define SIRFSOC_I2C_SDA_DELAY 0x18 -#define SIRFSOC_I2C_CMD_START 0x1C -#define SIRFSOC_I2C_CMD_BUF 0x30 -#define SIRFSOC_I2C_DATA_BUF 0x80 - -#define SIRFSOC_I2C_CMD_BUF_MAX 16 -#define SIRFSOC_I2C_DATA_BUF_MAX 16 - -#define SIRFSOC_I2C_CMD(x) (SIRFSOC_I2C_CMD_BUF + (x)*0x04) -#define SIRFSOC_I2C_DATA_MASK(x) (0xFF<<(((x)&3)*8)) -#define SIRFSOC_I2C_DATA_SHIFT(x) (((x)&3)*8) - -#define SIRFSOC_I2C_DIV_MASK (0xFFFF) - -/* I2C status flags */ -#define SIRFSOC_I2C_STAT_BUSY BIT(0) -#define SIRFSOC_I2C_STAT_TIP BIT(1) -#define SIRFSOC_I2C_STAT_NACK BIT(2) -#define SIRFSOC_I2C_STAT_TR_INT BIT(4) -#define SIRFSOC_I2C_STAT_STOP BIT(6) -#define SIRFSOC_I2C_STAT_CMD_DONE BIT(8) -#define SIRFSOC_I2C_STAT_ERR BIT(9) -#define SIRFSOC_I2C_CMD_INDEX (0x1F<<16) - -/* I2C control flags */ -#define SIRFSOC_I2C_RESET BIT(0) -#define SIRFSOC_I2C_CORE_EN BIT(1) -#define SIRFSOC_I2C_MASTER_MODE BIT(2) -#define SIRFSOC_I2C_CMD_DONE_EN BIT(11) -#define SIRFSOC_I2C_ERR_INT_EN BIT(12) - -#define SIRFSOC_I2C_SDA_DELAY_MASK (0xFF) -#define SIRFSOC_I2C_SCLF_FILTER (3<<8) - -#define SIRFSOC_I2C_START_CMD BIT(0) - -#define SIRFSOC_I2C_CMD_RP(x) ((x)&0x7) -#define SIRFSOC_I2C_NACK BIT(3) -#define SIRFSOC_I2C_WRITE BIT(4) -#define SIRFSOC_I2C_READ BIT(5) -#define SIRFSOC_I2C_STOP BIT(6) -#define SIRFSOC_I2C_START BIT(7) - -#define SIRFSOC_I2C_ERR_NOACK 1 -#define SIRFSOC_I2C_ERR_TIMEOUT 2 - -struct sirfsoc_i2c { - void __iomem *base; - struct clk *clk; - u32 cmd_ptr; /* Current position in CMD buffer */ - u8 *buf; /* Buffer passed by user */ - u32 msg_len; /* Message length */ - u32 finished_len; /* number of bytes read/written */ - u32 read_cmd_len; /* number of read cmd sent */ - int msg_read; /* 1 indicates a read message */ - int err_status; /* 1 indicates an error on bus */ - - u32 sda_delay; /* For suspend/resume */ - u32 clk_div; - int last; /* Last message in transfer, STOP cmd can be sent */ - - struct completion done; /* indicates completion of message transfer */ - struct i2c_adapter adapter; -}; - -static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic) -{ - u32 data = 0; - int i; - - for (i = 0; i < siic->read_cmd_len; i++) { - if (!(i & 0x3)) - data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i); - siic->buf[siic->finished_len++] = - (u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >> - SIRFSOC_I2C_DATA_SHIFT(i)); - } -} - -static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic) -{ - u32 regval; - int i = 0; - - if (siic->msg_read) { - while (((siic->finished_len + i) < siic->msg_len) - && (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) { - regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0); - if (((siic->finished_len + i) == - (siic->msg_len - 1)) && siic->last) - regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK; - writel(regval, - siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); - i++; - } - - siic->read_cmd_len = i; - } else { - while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1) - && (siic->finished_len < siic->msg_len)) { - regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0); - if ((siic->finished_len == (siic->msg_len - 1)) - && siic->last) - regval |= SIRFSOC_I2C_STOP; - writel(regval, - siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); - writel(siic->buf[siic->finished_len++], - siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); - } - } - siic->cmd_ptr = 0; - - /* Trigger the transfer */ - writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START); -} - -static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id) -{ - struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id; - u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS); - - if (i2c_stat & SIRFSOC_I2C_STAT_ERR) { - /* Error conditions */ - siic->err_status = SIRFSOC_I2C_ERR_NOACK; - writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS); - - if (i2c_stat & SIRFSOC_I2C_STAT_NACK) - dev_dbg(&siic->adapter.dev, "ACK not received\n"); - else - dev_err(&siic->adapter.dev, "I2C error\n"); - - /* - * Due to hardware ANOMALY, we need to reset I2C earlier after - * we get NOACK while accessing non-existing clients, otherwise - * we will get errors even we access existing clients later - */ - writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, - siic->base + SIRFSOC_I2C_CTRL); - while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) - cpu_relax(); - - complete(&siic->done); - } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) { - /* CMD buffer execution complete */ - if (siic->msg_read) - i2c_sirfsoc_read_data(siic); - if (siic->finished_len == siic->msg_len) - complete(&siic->done); - else /* Fill a new CMD buffer for left data */ - i2c_sirfsoc_queue_cmd(siic); - - writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS); - } - - return IRQ_HANDLED; -} - -static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic, - struct i2c_msg *msg) -{ - unsigned char addr; - u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE; - - /* no data and last message -> add STOP */ - if (siic->last && (msg->len == 0)) - regval |= SIRFSOC_I2C_STOP; - - writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); - - addr = i2c_8bit_addr_from_msg(msg); - - /* Reverse direction bit */ - if (msg->flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; - - writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); -} - -static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg) -{ - u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL); - /* timeout waiting for the xfer to finish or fail */ - int timeout = msecs_to_jiffies((msg->len + 1) * 50); - - i2c_sirfsoc_set_address(siic, msg); - - writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN, - siic->base + SIRFSOC_I2C_CTRL); - i2c_sirfsoc_queue_cmd(siic); - - if (wait_for_completion_timeout(&siic->done, timeout) == 0) { - siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT; - dev_err(&siic->adapter.dev, "Transfer timeout\n"); - } - - writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN), - siic->base + SIRFSOC_I2C_CTRL); - writel(0, siic->base + SIRFSOC_I2C_CMD_START); - - /* i2c control doesn't response, reset it */ - if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) { - writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, - siic->base + SIRFSOC_I2C_CTRL); - while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) - cpu_relax(); - } - return siic->err_status ? -EAGAIN : 0; -} - -static u32 i2c_sirfsoc_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) -{ - struct sirfsoc_i2c *siic = adap->algo_data; - int i, ret; - - clk_enable(siic->clk); - - for (i = 0; i < num; i++) { - siic->buf = msgs[i].buf; - siic->msg_len = msgs[i].len; - siic->msg_read = !!(msgs[i].flags & I2C_M_RD); - siic->err_status = 0; - siic->cmd_ptr = 0; - siic->finished_len = 0; - siic->last = (i == (num - 1)); - - ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]); - if (ret) { - clk_disable(siic->clk); - return ret; - } - } - - clk_disable(siic->clk); - return num; -} - -/* I2C algorithms associated with this master controller driver */ -static const struct i2c_algorithm i2c_sirfsoc_algo = { - .master_xfer = i2c_sirfsoc_xfer, - .functionality = i2c_sirfsoc_func, -}; - -static int i2c_sirfsoc_probe(struct platform_device *pdev) -{ - struct sirfsoc_i2c *siic; - struct i2c_adapter *adap; - struct clk *clk; - int bitrate; - int ctrl_speed; - int irq; - - int err; - u32 regval; - - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - dev_err(&pdev->dev, "Clock get failed\n"); - goto err_get_clk; - } - - err = clk_prepare(clk); - if (err) { - dev_err(&pdev->dev, "Clock prepare failed\n"); - goto err_clk_prep; - } - - err = clk_enable(clk); - if (err) { - dev_err(&pdev->dev, "Clock enable failed\n"); - goto err_clk_en; - } - - ctrl_speed = clk_get_rate(clk); - - siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL); - if (!siic) { - err = -ENOMEM; - goto out; - } - adap = &siic->adapter; - adap->class = I2C_CLASS_DEPRECATED; - - siic->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(siic->base)) { - err = PTR_ERR(siic->base); - goto out; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto out; - } - err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0, - dev_name(&pdev->dev), siic); - if (err) - goto out; - - adap->algo = &i2c_sirfsoc_algo; - adap->algo_data = siic; - adap->retries = 3; - - adap->dev.of_node = pdev->dev.of_node; - adap->dev.parent = &pdev->dev; - adap->nr = pdev->id; - - strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name)); - - platform_set_drvdata(pdev, adap); - init_completion(&siic->done); - - /* Controller initialisation */ - - writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); - while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) - cpu_relax(); - writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, - siic->base + SIRFSOC_I2C_CTRL); - - siic->clk = clk; - - err = of_property_read_u32(pdev->dev.of_node, - "clock-frequency", &bitrate); - if (err < 0) - bitrate = I2C_MAX_STANDARD_MODE_FREQ; - - /* - * Due to some hardware design issues, we need to tune the formula. - * Since i2c is open drain interface that allows the slave to - * stall the transaction by holding the SCL line at '0', the RTL - * implementation is waiting for SCL feedback from the pin after - * setting it to High-Z ('1'). This wait adds to the high-time - * interval counter few cycles of the input synchronization - * (depending on the SCL_FILTER_REG field), and also the time it - * takes for the board pull-up resistor to rise the SCL line. - * For slow SCL settings these additions are negligible, - * but they start to affect the speed when clock is set to faster - * frequencies. - * Through the actual tests, use the different user_div value(which - * in the divider formula 'Fio / (Fi2c * user_div)') to adapt - * the different ranges of i2c bus clock frequency, to make the SCL - * more accurate. - */ - if (bitrate <= 30000) - regval = ctrl_speed / (bitrate * 5); - else if (bitrate > 30000 && bitrate <= 280000) - regval = (2 * ctrl_speed) / (bitrate * 11); - else - regval = ctrl_speed / (bitrate * 6); - - writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL); - if (regval > 0xFF) - writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY); - else - writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY); - - err = i2c_add_numbered_adapter(adap); - if (err < 0) - goto out; - - clk_disable(clk); - - dev_info(&pdev->dev, " I2C adapter ready to operate\n"); - - return 0; - -out: - clk_disable(clk); -err_clk_en: - clk_unprepare(clk); -err_clk_prep: - clk_put(clk); -err_get_clk: - return err; -} - -static int i2c_sirfsoc_remove(struct platform_device *pdev) -{ - struct i2c_adapter *adapter = platform_get_drvdata(pdev); - struct sirfsoc_i2c *siic = adapter->algo_data; - - writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); - i2c_del_adapter(adapter); - clk_unprepare(siic->clk); - clk_put(siic->clk); - return 0; -} - -#ifdef CONFIG_PM -static int i2c_sirfsoc_suspend(struct device *dev) -{ - struct i2c_adapter *adapter = dev_get_drvdata(dev); - struct sirfsoc_i2c *siic = adapter->algo_data; - - clk_enable(siic->clk); - siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY); - siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL); - clk_disable(siic->clk); - return 0; -} - -static int i2c_sirfsoc_resume(struct device *dev) -{ - struct i2c_adapter *adapter = dev_get_drvdata(dev); - struct sirfsoc_i2c *siic = adapter->algo_data; - - clk_enable(siic->clk); - writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); - while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) - cpu_relax(); - writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, - siic->base + SIRFSOC_I2C_CTRL); - writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL); - writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY); - clk_disable(siic->clk); - return 0; -} - -static const struct dev_pm_ops i2c_sirfsoc_pm_ops = { - .suspend = i2c_sirfsoc_suspend, - .resume = i2c_sirfsoc_resume, -}; -#endif - -static const struct of_device_id sirfsoc_i2c_of_match[] = { - { .compatible = "sirf,prima2-i2c", }, - {}, -}; -MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match); - -static struct platform_driver i2c_sirfsoc_driver = { - .driver = { - .name = "sirfsoc_i2c", -#ifdef CONFIG_PM - .pm = &i2c_sirfsoc_pm_ops, -#endif - .of_match_table = sirfsoc_i2c_of_match, - }, - .probe = i2c_sirfsoc_probe, - .remove = i2c_sirfsoc_remove, -}; -module_platform_driver(i2c_sirfsoc_driver); - -MODULE_DESCRIPTION("SiRF SoC I2C master controller driver"); -MODULE_AUTHOR("Zhiwu Song "); -MODULE_AUTHOR("Xiangzhen Ye "); -MODULE_LICENSE("GPL v2"); -- cgit From 1059b2bcc683ab29c25d542af4902bfdb3f91b40 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 20 Jan 2021 14:28:33 +0100 Subject: i2c: remove u300 bus driver The ST-Ericsson U300 platform is getting removed, so this driver is no longer needed. Signed-off-by: Arnd Bergmann Reviewed-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 13 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-stu300.c | 1008 --------------------------------------- 3 files changed, 1022 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-stu300.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ce2efb56df54..4fe74259d44c 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1032,19 +1032,6 @@ config I2C_STM32F7 This driver can also be built as module. If so, the module will be called i2c-stm32f7. -config I2C_STU300 - tristate "ST Microelectronics DDC I2C interface" - depends on MACH_U300 || COMPILE_TEST - default y if MACH_U300 - help - If you say yes to this option, support will be included for the - I2C interface from ST Microelectronics simply called "DDC I2C" - supporting both I2C and DDC, used in e.g. the U300 series - mobile platforms. - - This driver can also be built as a module. If so, the module - will be called i2c-stu300. - config I2C_SUN6I_P2WI tristate "Allwinner sun6i internal P2WI controller" depends on RESET_CONTROLLER diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 1c30bba977ef..572d5fcc6016 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -103,7 +103,6 @@ obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o -obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c deleted file mode 100644 index 64d739baf480..000000000000 --- a/drivers/i2c/busses/i2c-stu300.c +++ /dev/null @@ -1,1008 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007-2012 ST-Ericsson AB - * ST DDC I2C master mode driver, used in e.g. U300 series platforms. - * Author: Linus Walleij - * Author: Jonas Aaberg - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* the name of this kernel module */ -#define NAME "stu300" - -/* CR (Control Register) 8bit (R/W) */ -#define I2C_CR (0x00000000) -#define I2C_CR_RESET_VALUE (0x00) -#define I2C_CR_RESET_UMASK (0x00) -#define I2C_CR_DDC1_ENABLE (0x80) -#define I2C_CR_TRANS_ENABLE (0x40) -#define I2C_CR_PERIPHERAL_ENABLE (0x20) -#define I2C_CR_DDC2B_ENABLE (0x10) -#define I2C_CR_START_ENABLE (0x08) -#define I2C_CR_ACK_ENABLE (0x04) -#define I2C_CR_STOP_ENABLE (0x02) -#define I2C_CR_INTERRUPT_ENABLE (0x01) -/* SR1 (Status Register 1) 8bit (R/-) */ -#define I2C_SR1 (0x00000004) -#define I2C_SR1_RESET_VALUE (0x00) -#define I2C_SR1_RESET_UMASK (0x00) -#define I2C_SR1_EVF_IND (0x80) -#define I2C_SR1_ADD10_IND (0x40) -#define I2C_SR1_TRA_IND (0x20) -#define I2C_SR1_BUSY_IND (0x10) -#define I2C_SR1_BTF_IND (0x08) -#define I2C_SR1_ADSL_IND (0x04) -#define I2C_SR1_MSL_IND (0x02) -#define I2C_SR1_SB_IND (0x01) -/* SR2 (Status Register 2) 8bit (R/-) */ -#define I2C_SR2 (0x00000008) -#define I2C_SR2_RESET_VALUE (0x00) -#define I2C_SR2_RESET_UMASK (0x40) -#define I2C_SR2_MASK (0xBF) -#define I2C_SR2_SCLFAL_IND (0x80) -#define I2C_SR2_ENDAD_IND (0x20) -#define I2C_SR2_AF_IND (0x10) -#define I2C_SR2_STOPF_IND (0x08) -#define I2C_SR2_ARLO_IND (0x04) -#define I2C_SR2_BERR_IND (0x02) -#define I2C_SR2_DDC2BF_IND (0x01) -/* CCR (Clock Control Register) 8bit (R/W) */ -#define I2C_CCR (0x0000000C) -#define I2C_CCR_RESET_VALUE (0x00) -#define I2C_CCR_RESET_UMASK (0x00) -#define I2C_CCR_MASK (0xFF) -#define I2C_CCR_FMSM (0x80) -#define I2C_CCR_CC_MASK (0x7F) -/* OAR1 (Own Address Register 1) 8bit (R/W) */ -#define I2C_OAR1 (0x00000010) -#define I2C_OAR1_RESET_VALUE (0x00) -#define I2C_OAR1_RESET_UMASK (0x00) -#define I2C_OAR1_ADD_MASK (0xFF) -/* OAR2 (Own Address Register 2) 8bit (R/W) */ -#define I2C_OAR2 (0x00000014) -#define I2C_OAR2_RESET_VALUE (0x40) -#define I2C_OAR2_RESET_UMASK (0x19) -#define I2C_OAR2_MASK (0xE6) -#define I2C_OAR2_FR_25_10MHZ (0x00) -#define I2C_OAR2_FR_10_1667MHZ (0x20) -#define I2C_OAR2_FR_1667_2667MHZ (0x40) -#define I2C_OAR2_FR_2667_40MHZ (0x60) -#define I2C_OAR2_FR_40_5333MHZ (0x80) -#define I2C_OAR2_FR_5333_66MHZ (0xA0) -#define I2C_OAR2_FR_66_80MHZ (0xC0) -#define I2C_OAR2_FR_80_100MHZ (0xE0) -#define I2C_OAR2_FR_MASK (0xE0) -#define I2C_OAR2_ADD_MASK (0x06) -/* DR (Data Register) 8bit (R/W) */ -#define I2C_DR (0x00000018) -#define I2C_DR_RESET_VALUE (0x00) -#define I2C_DR_RESET_UMASK (0xFF) -#define I2C_DR_D_MASK (0xFF) -/* ECCR (Extended Clock Control Register) 8bit (R/W) */ -#define I2C_ECCR (0x0000001C) -#define I2C_ECCR_RESET_VALUE (0x00) -#define I2C_ECCR_RESET_UMASK (0xE0) -#define I2C_ECCR_MASK (0x1F) -#define I2C_ECCR_CC_MASK (0x1F) - -/* - * These events are more or less responses to commands - * sent into the hardware, presumably reflecting the state - * of an internal state machine. - */ -enum stu300_event { - STU300_EVENT_NONE = 0, - STU300_EVENT_1, - STU300_EVENT_2, - STU300_EVENT_3, - STU300_EVENT_4, - STU300_EVENT_5, - STU300_EVENT_6, - STU300_EVENT_7, - STU300_EVENT_8, - STU300_EVENT_9 -}; - -enum stu300_error { - STU300_ERROR_NONE = 0, - STU300_ERROR_ACKNOWLEDGE_FAILURE, - STU300_ERROR_BUS_ERROR, - STU300_ERROR_ARBITRATION_LOST, - STU300_ERROR_UNKNOWN -}; - -/* timeout waiting for the controller to respond */ -#define STU300_TIMEOUT (msecs_to_jiffies(1000)) - -/* - * The number of address send athemps tried before giving up. - * If the first one fails it seems like 5 to 8 attempts are required. - */ -#define NUM_ADDR_RESEND_ATTEMPTS 12 - -/* I2C clock speed, in Hz 0-400kHz*/ -static unsigned int scl_frequency = I2C_MAX_STANDARD_MODE_FREQ; -module_param(scl_frequency, uint, 0644); - -/** - * struct stu300_dev - the stu300 driver state holder - * @pdev: parent platform device - * @adapter: corresponding I2C adapter - * @clk: hardware block clock - * @irq: assigned interrupt line - * @cmd_issue_lock: this locks the following cmd_ variables - * @cmd_complete: acknowledge completion for an I2C command - * @cmd_event: expected event coming in as a response to a command - * @cmd_err: error code as response to a command - * @speed: current bus speed in Hz - * @msg_index: index of current message - * @msg_len: length of current message - */ - -struct stu300_dev { - struct platform_device *pdev; - struct i2c_adapter adapter; - void __iomem *virtbase; - struct clk *clk; - int irq; - spinlock_t cmd_issue_lock; - struct completion cmd_complete; - enum stu300_event cmd_event; - enum stu300_error cmd_err; - unsigned int speed; - int msg_index; - int msg_len; -}; - -/* Local forward function declarations */ -static int stu300_init_hw(struct stu300_dev *dev); - -/* - * The block needs writes in both MSW and LSW in order - * for all data lines to reach their destination. - */ -static inline void stu300_wr8(u32 value, void __iomem *address) -{ - writel((value << 16) | value, address); -} - -/* - * This merely masks off the duplicates which appear - * in bytes 1-3. You _MUST_ use 32-bit bus access on this - * device, else it will not work. - */ -static inline u32 stu300_r8(void __iomem *address) -{ - return readl(address) & 0x000000FFU; -} - -static void stu300_irq_enable(struct stu300_dev *dev) -{ - u32 val; - val = stu300_r8(dev->virtbase + I2C_CR); - val |= I2C_CR_INTERRUPT_ENABLE; - /* Twice paranoia (possible HW glitch) */ - stu300_wr8(val, dev->virtbase + I2C_CR); - stu300_wr8(val, dev->virtbase + I2C_CR); -} - -static void stu300_irq_disable(struct stu300_dev *dev) -{ - u32 val; - val = stu300_r8(dev->virtbase + I2C_CR); - val &= ~I2C_CR_INTERRUPT_ENABLE; - /* Twice paranoia (possible HW glitch) */ - stu300_wr8(val, dev->virtbase + I2C_CR); - stu300_wr8(val, dev->virtbase + I2C_CR); -} - - -/* - * Tells whether a certain event or events occurred in - * response to a command. The events represent states in - * the internal state machine of the hardware. The events - * are not very well described in the hardware - * documentation and can only be treated as abstract state - * machine states. - * - * @ret 0 = event has not occurred or unknown error, any - * other value means the correct event occurred or an error. - */ - -static int stu300_event_occurred(struct stu300_dev *dev, - enum stu300_event mr_event) { - u32 status1; - u32 status2; - - /* What event happened? */ - status1 = stu300_r8(dev->virtbase + I2C_SR1); - - if (!(status1 & I2C_SR1_EVF_IND)) - /* No event at all */ - return 0; - - status2 = stu300_r8(dev->virtbase + I2C_SR2); - - /* Block any multiple interrupts */ - stu300_irq_disable(dev); - - /* Check for errors first */ - if (status2 & I2C_SR2_AF_IND) { - dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE; - return 1; - } else if (status2 & I2C_SR2_BERR_IND) { - dev->cmd_err = STU300_ERROR_BUS_ERROR; - return 1; - } else if (status2 & I2C_SR2_ARLO_IND) { - dev->cmd_err = STU300_ERROR_ARBITRATION_LOST; - return 1; - } - - switch (mr_event) { - case STU300_EVENT_1: - if (status1 & I2C_SR1_ADSL_IND) - return 1; - break; - case STU300_EVENT_2: - case STU300_EVENT_3: - case STU300_EVENT_7: - case STU300_EVENT_8: - if (status1 & I2C_SR1_BTF_IND) { - return 1; - } - break; - case STU300_EVENT_4: - if (status2 & I2C_SR2_STOPF_IND) - return 1; - break; - case STU300_EVENT_5: - if (status1 & I2C_SR1_SB_IND) - /* Clear start bit */ - return 1; - break; - case STU300_EVENT_6: - if (status2 & I2C_SR2_ENDAD_IND) { - /* First check for any errors */ - return 1; - } - break; - case STU300_EVENT_9: - if (status1 & I2C_SR1_ADD10_IND) - return 1; - break; - default: - break; - } - /* If we get here, we're on thin ice. - * Here we are in a status where we have - * gotten a response that does not match - * what we requested. - */ - dev->cmd_err = STU300_ERROR_UNKNOWN; - dev_err(&dev->pdev->dev, - "Unhandled interrupt! %d sr1: 0x%x sr2: 0x%x\n", - mr_event, status1, status2); - return 0; -} - -static irqreturn_t stu300_irh(int irq, void *data) -{ - struct stu300_dev *dev = data; - int res; - - /* Just make sure that the block is clocked */ - clk_enable(dev->clk); - - /* See if this was what we were waiting for */ - spin_lock(&dev->cmd_issue_lock); - - res = stu300_event_occurred(dev, dev->cmd_event); - if (res || dev->cmd_err != STU300_ERROR_NONE) - complete(&dev->cmd_complete); - - spin_unlock(&dev->cmd_issue_lock); - - clk_disable(dev->clk); - - return IRQ_HANDLED; -} - -/* - * Sends a command and then waits for the bits masked by *flagmask* - * to go high or low by IRQ awaiting. - */ -static int stu300_start_and_await_event(struct stu300_dev *dev, - u8 cr_value, - enum stu300_event mr_event) -{ - int ret; - - /* Lock command issue, fill in an event we wait for */ - spin_lock_irq(&dev->cmd_issue_lock); - init_completion(&dev->cmd_complete); - dev->cmd_err = STU300_ERROR_NONE; - dev->cmd_event = mr_event; - spin_unlock_irq(&dev->cmd_issue_lock); - - /* Turn on interrupt, send command and wait. */ - cr_value |= I2C_CR_INTERRUPT_ENABLE; - stu300_wr8(cr_value, dev->virtbase + I2C_CR); - ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, - STU300_TIMEOUT); - if (ret < 0) { - dev_err(&dev->pdev->dev, - "wait_for_completion_interruptible_timeout() " - "returned %d waiting for event %04x\n", ret, mr_event); - return ret; - } - - if (ret == 0) { - dev_err(&dev->pdev->dev, "controller timed out " - "waiting for event %d, reinit hardware\n", mr_event); - (void) stu300_init_hw(dev); - return -ETIMEDOUT; - } - - if (dev->cmd_err != STU300_ERROR_NONE) { - dev_err(&dev->pdev->dev, "controller (start) " - "error %d waiting for event %d, reinit hardware\n", - dev->cmd_err, mr_event); - (void) stu300_init_hw(dev); - return -EIO; - } - - return 0; -} - -/* - * This waits for a flag to be set, if it is not set on entry, an interrupt is - * configured to wait for the flag using a completion. - */ -static int stu300_await_event(struct stu300_dev *dev, - enum stu300_event mr_event) -{ - int ret; - - /* Is it already here? */ - spin_lock_irq(&dev->cmd_issue_lock); - dev->cmd_err = STU300_ERROR_NONE; - dev->cmd_event = mr_event; - - init_completion(&dev->cmd_complete); - - /* Turn on the I2C interrupt for current operation */ - stu300_irq_enable(dev); - - /* Unlock the command block and wait for the event to occur */ - spin_unlock_irq(&dev->cmd_issue_lock); - - ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, - STU300_TIMEOUT); - if (ret < 0) { - dev_err(&dev->pdev->dev, - "wait_for_completion_interruptible_timeout()" - "returned %d waiting for event %04x\n", ret, mr_event); - return ret; - } - - if (ret == 0) { - if (mr_event != STU300_EVENT_6) { - dev_err(&dev->pdev->dev, "controller " - "timed out waiting for event %d, reinit " - "hardware\n", mr_event); - (void) stu300_init_hw(dev); - } - return -ETIMEDOUT; - } - - if (dev->cmd_err != STU300_ERROR_NONE) { - if (mr_event != STU300_EVENT_6) { - dev_err(&dev->pdev->dev, "controller " - "error (await_event) %d waiting for event %d, " - "reinit hardware\n", dev->cmd_err, mr_event); - (void) stu300_init_hw(dev); - } - return -EIO; - } - - return 0; -} - -/* - * Waits for the busy bit to go low by repeated polling. - */ -#define BUSY_RELEASE_ATTEMPTS 10 -static int stu300_wait_while_busy(struct stu300_dev *dev) -{ - unsigned long timeout; - int i; - - for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) { - timeout = jiffies + STU300_TIMEOUT; - - while (!time_after(jiffies, timeout)) { - /* Is not busy? */ - if ((stu300_r8(dev->virtbase + I2C_SR1) & - I2C_SR1_BUSY_IND) == 0) - return 0; - msleep(1); - } - - dev_err(&dev->pdev->dev, "transaction timed out " - "waiting for device to be free (not busy). " - "Attempt: %d\n", i+1); - - dev_err(&dev->pdev->dev, "base address = " - "0x%p, reinit hardware\n", dev->virtbase); - - (void) stu300_init_hw(dev); - } - - dev_err(&dev->pdev->dev, "giving up after %d attempts " - "to reset the bus.\n", BUSY_RELEASE_ATTEMPTS); - - return -ETIMEDOUT; -} - -struct stu300_clkset { - unsigned long rate; - u32 setting; -}; - -static const struct stu300_clkset stu300_clktable[] = { - { 0, 0xFFU }, - { 2500000, I2C_OAR2_FR_25_10MHZ }, - { 10000000, I2C_OAR2_FR_10_1667MHZ }, - { 16670000, I2C_OAR2_FR_1667_2667MHZ }, - { 26670000, I2C_OAR2_FR_2667_40MHZ }, - { 40000000, I2C_OAR2_FR_40_5333MHZ }, - { 53330000, I2C_OAR2_FR_5333_66MHZ }, - { 66000000, I2C_OAR2_FR_66_80MHZ }, - { 80000000, I2C_OAR2_FR_80_100MHZ }, - { 100000000, 0xFFU }, -}; - - -static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) -{ - - u32 val; - int i = 0; - - /* Locate the appropriate clock setting */ - while (i < ARRAY_SIZE(stu300_clktable) - 1 && - stu300_clktable[i].rate < clkrate) - i++; - - if (stu300_clktable[i].setting == 0xFFU) { - dev_err(&dev->pdev->dev, "too %s clock rate requested " - "(%lu Hz).\n", i ? "high" : "low", clkrate); - return -EINVAL; - } - - stu300_wr8(stu300_clktable[i].setting, - dev->virtbase + I2C_OAR2); - - dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz " - "virtbase %p\n", clkrate, dev->speed, dev->virtbase); - - if (dev->speed > I2C_MAX_STANDARD_MODE_FREQ) - /* Fast Mode I2C */ - val = ((clkrate/dev->speed) - 9)/3 + 1; - else - /* Standard Mode I2C */ - val = ((clkrate/dev->speed) - 7)/2 + 1; - - /* According to spec the divider must be > 2 */ - if (val < 0x002) { - dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n", - clkrate); - return -EINVAL; - } - - /* We have 12 bits clock divider only! */ - if (val & 0xFFFFF000U) { - dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n", - clkrate); - return -EINVAL; - } - - if (dev->speed > I2C_MAX_STANDARD_MODE_FREQ) { - /* CC6..CC0 */ - stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM, - dev->virtbase + I2C_CCR); - dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, " - "Fast Mode I2C\n", val); - } else { - /* CC6..CC0 */ - stu300_wr8((val & I2C_CCR_CC_MASK), - dev->virtbase + I2C_CCR); - dev_dbg(&dev->pdev->dev, "set clock divider to " - "0x%08x, Standard Mode I2C\n", val); - } - - /* CC11..CC7 */ - stu300_wr8(((val >> 7) & 0x1F), - dev->virtbase + I2C_ECCR); - - return 0; -} - - -static int stu300_init_hw(struct stu300_dev *dev) -{ - u32 dummy; - unsigned long clkrate; - int ret; - - /* Disable controller */ - stu300_wr8(0x00, dev->virtbase + I2C_CR); - /* - * Set own address to some default value (0x00). - * We do not support slave mode anyway. - */ - stu300_wr8(0x00, dev->virtbase + I2C_OAR1); - /* - * The I2C controller only operates properly in 26 MHz but we - * program this driver as if we didn't know. This will also set the two - * high bits of the own address to zero as well. - * There is no known hardware issue with running in 13 MHz - * However, speeds over 200 kHz are not used. - */ - clkrate = clk_get_rate(dev->clk); - ret = stu300_set_clk(dev, clkrate); - - if (ret) - return ret; - /* - * Enable block, do it TWICE (hardware glitch) - * Setting bit 7 can enable DDC mode. (Not used currently.) - */ - stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, - dev->virtbase + I2C_CR); - stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, - dev->virtbase + I2C_CR); - /* Make a dummy read of the status register SR1 & SR2 */ - dummy = stu300_r8(dev->virtbase + I2C_SR2); - dummy = stu300_r8(dev->virtbase + I2C_SR1); - - return 0; -} - - - -/* Send slave address. */ -static int stu300_send_address(struct stu300_dev *dev, - struct i2c_msg *msg, int resend) -{ - u32 val; - int ret; - - if (msg->flags & I2C_M_TEN) { - /* This is probably how 10 bit addresses look */ - val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) & - I2C_DR_D_MASK; - if (msg->flags & I2C_M_RD) - /* This is the direction bit */ - val |= 0x01; - } else { - val = i2c_8bit_addr_from_msg(msg); - } - - if (resend) { - if (msg->flags & I2C_M_RD) - dev_dbg(&dev->pdev->dev, "read resend\n"); - else - dev_dbg(&dev->pdev->dev, "write resend\n"); - } - - stu300_wr8(val, dev->virtbase + I2C_DR); - - /* For 10bit addressing, await 10bit request (EVENT 9) */ - if (msg->flags & I2C_M_TEN) { - ret = stu300_await_event(dev, STU300_EVENT_9); - /* - * The slave device wants a 10bit address, send the rest - * of the bits (the LSBits) - */ - val = msg->addr & I2C_DR_D_MASK; - /* This clears "event 9" */ - stu300_wr8(val, dev->virtbase + I2C_DR); - if (ret != 0) - return ret; - } - /* FIXME: Why no else here? two events for 10bit? - * Await event 6 (normal) or event 9 (10bit) - */ - - if (resend) - dev_dbg(&dev->pdev->dev, "await event 6\n"); - ret = stu300_await_event(dev, STU300_EVENT_6); - - /* - * Clear any pending EVENT 6 no matter what happened during - * await_event. - */ - val = stu300_r8(dev->virtbase + I2C_CR); - val |= I2C_CR_PERIPHERAL_ENABLE; - stu300_wr8(val, dev->virtbase + I2C_CR); - - return ret; -} - -static int stu300_xfer_msg(struct i2c_adapter *adap, - struct i2c_msg *msg, int stop) -{ - u32 cr; - u32 val; - u32 i; - int ret; - int attempts = 0; - struct stu300_dev *dev = i2c_get_adapdata(adap); - - clk_enable(dev->clk); - - /* Remove this if (0) to trace each and every message. */ - if (0) { - dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, " - "flags: 0x%04x, stop: %d\n", - msg->addr, msg->len, msg->flags, stop); - } - - /* - * For some reason, sending the address sometimes fails when running - * on the 13 MHz clock. No interrupt arrives. This is a work around, - * which tries to restart and send the address up to 10 times before - * really giving up. Usually 5 to 8 attempts are enough. - */ - do { - if (attempts) - dev_dbg(&dev->pdev->dev, "wait while busy\n"); - /* Check that the bus is free, or wait until some timeout */ - ret = stu300_wait_while_busy(dev); - if (ret != 0) - goto exit_disable; - - if (attempts) - dev_dbg(&dev->pdev->dev, "re-int hw\n"); - /* - * According to ST, there is no problem if the clock is - * changed between 13 and 26 MHz during a transfer. - */ - ret = stu300_init_hw(dev); - if (ret) - goto exit_disable; - - /* Send a start condition */ - cr = I2C_CR_PERIPHERAL_ENABLE; - /* Setting the START bit puts the block in master mode */ - if (!(msg->flags & I2C_M_NOSTART)) - cr |= I2C_CR_START_ENABLE; - if ((msg->flags & I2C_M_RD) && (msg->len > 1)) - /* On read more than 1 byte, we need ack. */ - cr |= I2C_CR_ACK_ENABLE; - /* Check that it gets through */ - if (!(msg->flags & I2C_M_NOSTART)) { - if (attempts) - dev_dbg(&dev->pdev->dev, "send start event\n"); - ret = stu300_start_and_await_event(dev, cr, - STU300_EVENT_5); - } - - if (attempts) - dev_dbg(&dev->pdev->dev, "send address\n"); - - if (ret == 0) - /* Send address */ - ret = stu300_send_address(dev, msg, attempts != 0); - - if (ret != 0) { - attempts++; - dev_dbg(&dev->pdev->dev, "failed sending address, " - "retrying. Attempt: %d msg_index: %d/%d\n", - attempts, dev->msg_index, dev->msg_len); - } - - } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS); - - if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) { - dev_dbg(&dev->pdev->dev, "managed to get address " - "through after %d attempts\n", attempts); - } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) { - dev_dbg(&dev->pdev->dev, "I give up, tried %d times " - "to resend address.\n", - NUM_ADDR_RESEND_ATTEMPTS); - goto exit_disable; - } - - - if (msg->flags & I2C_M_RD) { - /* READ: we read the actual bytes one at a time */ - for (i = 0; i < msg->len; i++) { - if (i == msg->len-1) { - /* - * Disable ACK and set STOP condition before - * reading last byte - */ - val = I2C_CR_PERIPHERAL_ENABLE; - - if (stop) - val |= I2C_CR_STOP_ENABLE; - - stu300_wr8(val, - dev->virtbase + I2C_CR); - } - /* Wait for this byte... */ - ret = stu300_await_event(dev, STU300_EVENT_7); - if (ret != 0) - goto exit_disable; - /* This clears event 7 */ - msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR); - } - } else { - /* WRITE: we send the actual bytes one at a time */ - for (i = 0; i < msg->len; i++) { - /* Write the byte */ - stu300_wr8(msg->buf[i], - dev->virtbase + I2C_DR); - /* Check status */ - ret = stu300_await_event(dev, STU300_EVENT_8); - /* Next write to DR will clear event 8 */ - if (ret != 0) { - dev_err(&dev->pdev->dev, "error awaiting " - "event 8 (%d)\n", ret); - goto exit_disable; - } - } - /* Check NAK */ - if (!(msg->flags & I2C_M_IGNORE_NAK)) { - if (stu300_r8(dev->virtbase + I2C_SR2) & - I2C_SR2_AF_IND) { - dev_err(&dev->pdev->dev, "I2C payload " - "send returned NAK!\n"); - ret = -EIO; - goto exit_disable; - } - } - if (stop) { - /* Send stop condition */ - val = I2C_CR_PERIPHERAL_ENABLE; - val |= I2C_CR_STOP_ENABLE; - stu300_wr8(val, dev->virtbase + I2C_CR); - } - } - - /* Check that the bus is free, or wait until some timeout occurs */ - ret = stu300_wait_while_busy(dev); - if (ret != 0) { - dev_err(&dev->pdev->dev, "timeout waiting for transfer " - "to commence.\n"); - goto exit_disable; - } - - /* Dummy read status registers */ - val = stu300_r8(dev->virtbase + I2C_SR2); - val = stu300_r8(dev->virtbase + I2C_SR1); - ret = 0; - - exit_disable: - /* Disable controller */ - stu300_wr8(0x00, dev->virtbase + I2C_CR); - clk_disable(dev->clk); - return ret; -} - -static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) -{ - int ret = -1; - int i; - - struct stu300_dev *dev = i2c_get_adapdata(adap); - dev->msg_len = num; - - for (i = 0; i < num; i++) { - /* - * Another driver appears to send stop for each message, - * here we only do that for the last message. Possibly some - * peripherals require this behaviour, then their drivers - * have to send single messages in order to get "stop" for - * each message. - */ - dev->msg_index = i; - - ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1))); - - if (ret != 0) { - num = ret; - break; - } - } - - return num; -} - -static int stu300_xfer_todo(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - /* TODO: implement polling for this case if need be. */ - WARN(1, "%s: atomic transfers not implemented\n", dev_name(&adap->dev)); - return -EOPNOTSUPP; -} - -static u32 stu300_func(struct i2c_adapter *adap) -{ - /* This is the simplest thing you can think of... */ - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; -} - -static const struct i2c_algorithm stu300_algo = { - .master_xfer = stu300_xfer, - .master_xfer_atomic = stu300_xfer_todo, - .functionality = stu300_func, -}; - -static const struct i2c_adapter_quirks stu300_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - -static int stu300_probe(struct platform_device *pdev) -{ - struct stu300_dev *dev; - struct i2c_adapter *adap; - int bus_nr; - int ret = 0; - - dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - bus_nr = pdev->id; - dev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - dev_err(&pdev->dev, "could not retrieve i2c bus clock\n"); - return PTR_ERR(dev->clk); - } - - dev->pdev = pdev; - dev->virtbase = devm_platform_ioremap_resource(pdev, 0); - dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual " - "base %p\n", bus_nr, dev->virtbase); - if (IS_ERR(dev->virtbase)) - return PTR_ERR(dev->virtbase); - - dev->irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev); - if (ret < 0) - return ret; - - dev->speed = scl_frequency; - - clk_prepare_enable(dev->clk); - ret = stu300_init_hw(dev); - clk_disable(dev->clk); - if (ret != 0) { - dev_err(&dev->pdev->dev, "error initializing hardware.\n"); - return -EIO; - } - - /* IRQ event handling initialization */ - spin_lock_init(&dev->cmd_issue_lock); - dev->cmd_event = STU300_EVENT_NONE; - dev->cmd_err = STU300_ERROR_NONE; - - adap = &dev->adapter; - adap->owner = THIS_MODULE; - /* DDC class but actually often used for more generic I2C */ - adap->class = I2C_CLASS_DEPRECATED; - strlcpy(adap->name, "ST Microelectronics DDC I2C adapter", - sizeof(adap->name)); - adap->nr = bus_nr; - adap->algo = &stu300_algo; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; - adap->quirks = &stu300_quirks; - - i2c_set_adapdata(adap, dev); - - /* i2c device drivers may be active on return from add_adapter() */ - ret = i2c_add_numbered_adapter(adap); - if (ret) - return ret; - - platform_set_drvdata(pdev, dev); - dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n", - dev->virtbase, dev->irq); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int stu300_suspend(struct device *device) -{ - struct stu300_dev *dev = dev_get_drvdata(device); - - /* Turn off everything */ - stu300_wr8(0x00, dev->virtbase + I2C_CR); - return 0; -} - -static int stu300_resume(struct device *device) -{ - int ret = 0; - struct stu300_dev *dev = dev_get_drvdata(device); - - clk_enable(dev->clk); - ret = stu300_init_hw(dev); - clk_disable(dev->clk); - - if (ret != 0) - dev_err(device, "error re-initializing hardware.\n"); - return ret; -} - -static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume); -#define STU300_I2C_PM (&stu300_pm) -#else -#define STU300_I2C_PM NULL -#endif - -static int stu300_remove(struct platform_device *pdev) -{ - struct stu300_dev *dev = platform_get_drvdata(pdev); - - i2c_del_adapter(&dev->adapter); - /* Turn off everything */ - stu300_wr8(0x00, dev->virtbase + I2C_CR); - return 0; -} - -static const struct of_device_id stu300_dt_match[] = { - { .compatible = "st,ddci2c" }, - {}, -}; -MODULE_DEVICE_TABLE(of, stu300_dt_match); - -static struct platform_driver stu300_i2c_driver = { - .driver = { - .name = NAME, - .pm = STU300_I2C_PM, - .of_match_table = stu300_dt_match, - }, - .probe = stu300_probe, - .remove = stu300_remove, - -}; - -static int __init stu300_init(void) -{ - return platform_driver_register(&stu300_i2c_driver); -} - -static void __exit stu300_exit(void) -{ - platform_driver_unregister(&stu300_i2c_driver); -} - -/* - * The systems using this bus often have very basic devices such - * as regulators on the I2C bus, so this needs to be loaded early. - * Therefore it is registered in the subsys_initcall(). - */ -subsys_initcall(stu300_init); -module_exit(stu300_exit); - -MODULE_AUTHOR("Linus Walleij "); -MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" NAME); -- cgit From 58d23305db951feb0e4b597c91bd642d521aea01 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jan 2021 13:43:10 +0100 Subject: i2c: algo: bit: use new macro to specifiy capabilities Let's use the new macro for emulating SMBus with RECV_LEN support. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/algos/i2c-algo-bit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 913db013fe90..fc90293afcbf 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -622,9 +622,7 @@ static int bit_xfer_atomic(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], static u32 bit_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_SMBUS_READ_BLOCK_DATA | - I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL_ALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } -- cgit From 416365e02a33ce50660862a126dd407b09736c7c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jan 2021 13:43:11 +0100 Subject: i2c: qup: advertise SMBus transfers using RECV_LEN This driver implements I2C_M_RECV_LEN, so it can advertise the SMBus transfers needing it. This also enables client devices to check for the RECV_LEN capability. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 5a47915869ae..61dc20fd1191 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1603,7 +1603,7 @@ out: static u32 qup_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL_ALL & ~I2C_FUNC_SMBUS_QUICK); } static const struct i2c_algorithm qup_i2c_algo = { -- cgit From 81f199329df703dc3066cd16250da69886600e4f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jan 2021 13:43:12 +0100 Subject: i2c: s3c2410: advertise SMBus transfers using RECV_LEN This driver implements I2C_M_RECV_LEN, so it can advertise the SMBus transfers needing it. This also enables client devices to check for the RECV_LEN capability. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3eafe0eb3e4c..62a903fbe912 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -781,7 +781,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, /* declare our i2c functionality */ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL_ALL | I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING; } -- cgit From 73cc584cfced260133cfc635f9921d66da676749 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 20 Jan 2021 14:28:34 +0100 Subject: i2c: remove zte zx bus driver The zte zx platform is getting removed, so this driver is no longer needed. Signed-off-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 9 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-zx2967.c | 602 ---------------------------------------- 3 files changed, 612 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-zx2967.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4fe74259d44c..2a89d0b061ee 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1370,15 +1370,6 @@ config I2C_OPAL This driver can also be built as a module. If so, the module will be called as i2c-opal. -config I2C_ZX2967 - tristate "ZTE ZX2967 I2C support" - depends on ARCH_ZX - default y - help - Selecting this option will add ZX2967 I2C driver. - This driver can also be built as a module. If so, the module will be - called i2c-zx2967. - config I2C_FSI tristate "FSI I2C driver" depends on FSI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 572d5fcc6016..615f35e3e31f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -119,7 +119,6 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o -obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c deleted file mode 100644 index 8db9519695a6..000000000000 --- a/drivers/i2c/busses/i2c-zx2967.c +++ /dev/null @@ -1,602 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 Sanechips Technology Co., Ltd. - * Copyright 2017 Linaro Ltd. - * - * Author: Baoyou Xie - */ - -#include -#include -#include -#include -#include -#include - -#define REG_CMD 0x04 -#define REG_DEVADDR_H 0x0C -#define REG_DEVADDR_L 0x10 -#define REG_CLK_DIV_FS 0x14 -#define REG_CLK_DIV_HS 0x18 -#define REG_WRCONF 0x1C -#define REG_RDCONF 0x20 -#define REG_DATA 0x24 -#define REG_STAT 0x28 - -#define I2C_STOP 0 -#define I2C_MASTER BIT(0) -#define I2C_ADDR_MODE_TEN BIT(1) -#define I2C_IRQ_MSK_ENABLE BIT(3) -#define I2C_RW_READ BIT(4) -#define I2C_CMB_RW_EN BIT(5) -#define I2C_START BIT(6) - -#define I2C_ADDR_LOW_MASK GENMASK(6, 0) -#define I2C_ADDR_LOW_SHIFT 0 -#define I2C_ADDR_HI_MASK GENMASK(2, 0) -#define I2C_ADDR_HI_SHIFT 7 - -#define I2C_WFIFO_RESET BIT(7) -#define I2C_RFIFO_RESET BIT(7) - -#define I2C_IRQ_ACK_CLEAR BIT(7) -#define I2C_INT_MASK GENMASK(6, 0) - -#define I2C_TRANS_DONE BIT(0) -#define I2C_SR_EDEVICE BIT(1) -#define I2C_SR_EDATA BIT(2) - -#define I2C_FIFO_MAX 16 - -#define I2C_TIMEOUT msecs_to_jiffies(1000) - -#define DEV(i2c) ((i2c)->adap.dev.parent) - -struct zx2967_i2c { - struct i2c_adapter adap; - struct clk *clk; - struct completion complete; - u32 clk_freq; - void __iomem *reg_base; - size_t residue; - int irq; - int msg_rd; - u8 *cur_trans; - u8 access_cnt; - int error; -}; - -static void zx2967_i2c_writel(struct zx2967_i2c *i2c, - u32 val, unsigned long reg) -{ - writel_relaxed(val, i2c->reg_base + reg); -} - -static u32 zx2967_i2c_readl(struct zx2967_i2c *i2c, unsigned long reg) -{ - return readl_relaxed(i2c->reg_base + reg); -} - -static void zx2967_i2c_writesb(struct zx2967_i2c *i2c, - void *data, unsigned long reg, int len) -{ - writesb(i2c->reg_base + reg, data, len); -} - -static void zx2967_i2c_readsb(struct zx2967_i2c *i2c, - void *data, unsigned long reg, int len) -{ - readsb(i2c->reg_base + reg, data, len); -} - -static void zx2967_i2c_start_ctrl(struct zx2967_i2c *i2c) -{ - u32 status; - u32 ctl; - - status = zx2967_i2c_readl(i2c, REG_STAT); - status |= I2C_IRQ_ACK_CLEAR; - zx2967_i2c_writel(i2c, status, REG_STAT); - - ctl = zx2967_i2c_readl(i2c, REG_CMD); - if (i2c->msg_rd) - ctl |= I2C_RW_READ; - else - ctl &= ~I2C_RW_READ; - ctl &= ~I2C_CMB_RW_EN; - ctl |= I2C_START; - zx2967_i2c_writel(i2c, ctl, REG_CMD); -} - -static void zx2967_i2c_flush_fifos(struct zx2967_i2c *i2c) -{ - u32 offset; - u32 val; - - if (i2c->msg_rd) { - offset = REG_RDCONF; - val = I2C_RFIFO_RESET; - } else { - offset = REG_WRCONF; - val = I2C_WFIFO_RESET; - } - - val |= zx2967_i2c_readl(i2c, offset); - zx2967_i2c_writel(i2c, val, offset); -} - -static int zx2967_i2c_empty_rx_fifo(struct zx2967_i2c *i2c, u32 size) -{ - u8 val[I2C_FIFO_MAX] = {0}; - int i; - - if (size > I2C_FIFO_MAX) { - dev_err(DEV(i2c), "fifo size %d over the max value %d\n", - size, I2C_FIFO_MAX); - return -EINVAL; - } - - zx2967_i2c_readsb(i2c, val, REG_DATA, size); - for (i = 0; i < size; i++) { - *i2c->cur_trans++ = val[i]; - i2c->residue--; - } - - barrier(); - - return 0; -} - -static int zx2967_i2c_fill_tx_fifo(struct zx2967_i2c *i2c) -{ - size_t residue = i2c->residue; - u8 *buf = i2c->cur_trans; - - if (residue == 0) { - dev_err(DEV(i2c), "residue is %d\n", (int)residue); - return -EINVAL; - } - - if (residue <= I2C_FIFO_MAX) { - zx2967_i2c_writesb(i2c, buf, REG_DATA, residue); - - /* Again update before writing to FIFO to make sure isr sees. */ - i2c->residue = 0; - i2c->cur_trans = NULL; - } else { - zx2967_i2c_writesb(i2c, buf, REG_DATA, I2C_FIFO_MAX); - i2c->residue -= I2C_FIFO_MAX; - i2c->cur_trans += I2C_FIFO_MAX; - } - - barrier(); - - return 0; -} - -static int zx2967_i2c_reset_hardware(struct zx2967_i2c *i2c) -{ - u32 val; - u32 clk_div; - - val = I2C_MASTER | I2C_IRQ_MSK_ENABLE; - zx2967_i2c_writel(i2c, val, REG_CMD); - - clk_div = clk_get_rate(i2c->clk) / i2c->clk_freq - 1; - zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_FS); - zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_HS); - - zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_WRCONF); - zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_RDCONF); - zx2967_i2c_writel(i2c, 1, REG_RDCONF); - - zx2967_i2c_flush_fifos(i2c); - - return 0; -} - -static void zx2967_i2c_isr_clr(struct zx2967_i2c *i2c) -{ - u32 status; - - status = zx2967_i2c_readl(i2c, REG_STAT); - status |= I2C_IRQ_ACK_CLEAR; - zx2967_i2c_writel(i2c, status, REG_STAT); -} - -static irqreturn_t zx2967_i2c_isr(int irq, void *dev_id) -{ - u32 status; - struct zx2967_i2c *i2c = (struct zx2967_i2c *)dev_id; - - status = zx2967_i2c_readl(i2c, REG_STAT) & I2C_INT_MASK; - zx2967_i2c_isr_clr(i2c); - - if (status & I2C_SR_EDEVICE) - i2c->error = -ENXIO; - else if (status & I2C_SR_EDATA) - i2c->error = -EIO; - else if (status & I2C_TRANS_DONE) - i2c->error = 0; - else - goto done; - - complete(&i2c->complete); -done: - return IRQ_HANDLED; -} - -static void zx2967_set_addr(struct zx2967_i2c *i2c, u16 addr) -{ - u16 val; - - val = (addr >> I2C_ADDR_LOW_SHIFT) & I2C_ADDR_LOW_MASK; - zx2967_i2c_writel(i2c, val, REG_DEVADDR_L); - - val = (addr >> I2C_ADDR_HI_SHIFT) & I2C_ADDR_HI_MASK; - zx2967_i2c_writel(i2c, val, REG_DEVADDR_H); - if (val) - val = zx2967_i2c_readl(i2c, REG_CMD) | I2C_ADDR_MODE_TEN; - else - val = zx2967_i2c_readl(i2c, REG_CMD) & ~I2C_ADDR_MODE_TEN; - zx2967_i2c_writel(i2c, val, REG_CMD); -} - -static int zx2967_i2c_xfer_bytes(struct zx2967_i2c *i2c, u32 bytes) -{ - unsigned long time_left; - int rd = i2c->msg_rd; - int ret; - - reinit_completion(&i2c->complete); - - if (rd) { - zx2967_i2c_writel(i2c, bytes - 1, REG_RDCONF); - } else { - ret = zx2967_i2c_fill_tx_fifo(i2c); - if (ret) - return ret; - } - - zx2967_i2c_start_ctrl(i2c); - - time_left = wait_for_completion_timeout(&i2c->complete, - I2C_TIMEOUT); - if (time_left == 0) - return -ETIMEDOUT; - - if (i2c->error) - return i2c->error; - - return rd ? zx2967_i2c_empty_rx_fifo(i2c, bytes) : 0; -} - -static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c, - struct i2c_msg *msg) -{ - int ret; - int i; - - zx2967_i2c_flush_fifos(i2c); - - i2c->cur_trans = msg->buf; - i2c->residue = msg->len; - i2c->access_cnt = msg->len / I2C_FIFO_MAX; - i2c->msg_rd = msg->flags & I2C_M_RD; - - for (i = 0; i < i2c->access_cnt; i++) { - ret = zx2967_i2c_xfer_bytes(i2c, I2C_FIFO_MAX); - if (ret) - return ret; - } - - if (i2c->residue > 0) { - ret = zx2967_i2c_xfer_bytes(i2c, i2c->residue); - if (ret) - return ret; - } - - i2c->residue = 0; - i2c->access_cnt = 0; - - return 0; -} - -static int zx2967_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct zx2967_i2c *i2c = i2c_get_adapdata(adap); - int ret; - int i; - - zx2967_set_addr(i2c, msgs->addr); - - for (i = 0; i < num; i++) { - ret = zx2967_i2c_xfer_msg(i2c, &msgs[i]); - if (ret) - return ret; - } - - return num; -} - -static void -zx2967_smbus_xfer_prepare(struct zx2967_i2c *i2c, u16 addr, - char read_write, u8 command, int size, - union i2c_smbus_data *data) -{ - u32 val; - - val = zx2967_i2c_readl(i2c, REG_RDCONF); - val |= I2C_RFIFO_RESET; - zx2967_i2c_writel(i2c, val, REG_RDCONF); - zx2967_set_addr(i2c, addr); - val = zx2967_i2c_readl(i2c, REG_CMD); - val &= ~I2C_RW_READ; - zx2967_i2c_writel(i2c, val, REG_CMD); - - switch (size) { - case I2C_SMBUS_BYTE: - zx2967_i2c_writel(i2c, command, REG_DATA); - break; - case I2C_SMBUS_BYTE_DATA: - zx2967_i2c_writel(i2c, command, REG_DATA); - if (read_write == I2C_SMBUS_WRITE) - zx2967_i2c_writel(i2c, data->byte, REG_DATA); - break; - case I2C_SMBUS_WORD_DATA: - zx2967_i2c_writel(i2c, command, REG_DATA); - if (read_write == I2C_SMBUS_WRITE) { - zx2967_i2c_writel(i2c, (data->word >> 8), REG_DATA); - zx2967_i2c_writel(i2c, (data->word & 0xff), - REG_DATA); - } - break; - } -} - -static int zx2967_smbus_xfer_read(struct zx2967_i2c *i2c, int size, - union i2c_smbus_data *data) -{ - unsigned long time_left; - u8 buf[2]; - u32 val; - - reinit_completion(&i2c->complete); - - val = zx2967_i2c_readl(i2c, REG_CMD); - val |= I2C_CMB_RW_EN; - zx2967_i2c_writel(i2c, val, REG_CMD); - - val = zx2967_i2c_readl(i2c, REG_CMD); - val |= I2C_START; - zx2967_i2c_writel(i2c, val, REG_CMD); - - time_left = wait_for_completion_timeout(&i2c->complete, - I2C_TIMEOUT); - if (time_left == 0) - return -ETIMEDOUT; - - if (i2c->error) - return i2c->error; - - switch (size) { - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - val = zx2967_i2c_readl(i2c, REG_DATA); - data->byte = val; - break; - case I2C_SMBUS_WORD_DATA: - case I2C_SMBUS_PROC_CALL: - buf[0] = zx2967_i2c_readl(i2c, REG_DATA); - buf[1] = zx2967_i2c_readl(i2c, REG_DATA); - data->word = (buf[0] << 8) | buf[1]; - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int zx2967_smbus_xfer_write(struct zx2967_i2c *i2c) -{ - unsigned long time_left; - u32 val; - - reinit_completion(&i2c->complete); - val = zx2967_i2c_readl(i2c, REG_CMD); - val |= I2C_START; - zx2967_i2c_writel(i2c, val, REG_CMD); - - time_left = wait_for_completion_timeout(&i2c->complete, - I2C_TIMEOUT); - if (time_left == 0) - return -ETIMEDOUT; - - if (i2c->error) - return i2c->error; - - return 0; -} - -static int zx2967_smbus_xfer(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data) -{ - struct zx2967_i2c *i2c = i2c_get_adapdata(adap); - - if (size == I2C_SMBUS_QUICK) - read_write = I2C_SMBUS_WRITE; - - switch (size) { - case I2C_SMBUS_QUICK: - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - case I2C_SMBUS_WORD_DATA: - zx2967_smbus_xfer_prepare(i2c, addr, read_write, - command, size, data); - break; - default: - return -EOPNOTSUPP; - } - - if (read_write == I2C_SMBUS_READ) - return zx2967_smbus_xfer_read(i2c, size, data); - - return zx2967_smbus_xfer_write(i2c); -} - -static u32 zx2967_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | - I2C_FUNC_SMBUS_QUICK | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | - I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_SMBUS_I2C_BLOCK; -} - -static int __maybe_unused zx2967_i2c_suspend(struct device *dev) -{ - struct zx2967_i2c *i2c = dev_get_drvdata(dev); - - i2c_mark_adapter_suspended(&i2c->adap); - clk_disable_unprepare(i2c->clk); - - return 0; -} - -static int __maybe_unused zx2967_i2c_resume(struct device *dev) -{ - struct zx2967_i2c *i2c = dev_get_drvdata(dev); - - clk_prepare_enable(i2c->clk); - i2c_mark_adapter_resumed(&i2c->adap); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(zx2967_i2c_dev_pm_ops, - zx2967_i2c_suspend, zx2967_i2c_resume); - -static const struct i2c_algorithm zx2967_i2c_algo = { - .master_xfer = zx2967_i2c_xfer, - .smbus_xfer = zx2967_smbus_xfer, - .functionality = zx2967_i2c_func, -}; - -static const struct i2c_adapter_quirks zx2967_i2c_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - -static const struct of_device_id zx2967_i2c_of_match[] = { - { .compatible = "zte,zx296718-i2c", }, - { }, -}; -MODULE_DEVICE_TABLE(of, zx2967_i2c_of_match); - -static int zx2967_i2c_probe(struct platform_device *pdev) -{ - struct zx2967_i2c *i2c; - void __iomem *reg_base; - struct clk *clk; - int ret; - - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) - return -ENOMEM; - - reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(reg_base)) - return PTR_ERR(reg_base); - - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "missing controller clock"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable i2c_clk\n"); - return ret; - } - - ret = device_property_read_u32(&pdev->dev, "clock-frequency", - &i2c->clk_freq); - if (ret) { - dev_err(&pdev->dev, "missing clock-frequency"); - return ret; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - - i2c->irq = ret; - i2c->reg_base = reg_base; - i2c->clk = clk; - - init_completion(&i2c->complete); - platform_set_drvdata(pdev, i2c); - - ret = zx2967_i2c_reset_hardware(i2c); - if (ret) { - dev_err(&pdev->dev, "failed to initialize i2c controller\n"); - goto err_clk_unprepare; - } - - ret = devm_request_irq(&pdev->dev, i2c->irq, - zx2967_i2c_isr, 0, dev_name(&pdev->dev), i2c); - if (ret) { - dev_err(&pdev->dev, "failed to request irq %i\n", i2c->irq); - goto err_clk_unprepare; - } - - i2c_set_adapdata(&i2c->adap, i2c); - strlcpy(i2c->adap.name, "zx2967 i2c adapter", - sizeof(i2c->adap.name)); - i2c->adap.algo = &zx2967_i2c_algo; - i2c->adap.quirks = &zx2967_i2c_quirks; - i2c->adap.nr = pdev->id; - i2c->adap.dev.parent = &pdev->dev; - i2c->adap.dev.of_node = pdev->dev.of_node; - - ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret) - goto err_clk_unprepare; - - return 0; - -err_clk_unprepare: - clk_disable_unprepare(i2c->clk); - return ret; -} - -static int zx2967_i2c_remove(struct platform_device *pdev) -{ - struct zx2967_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); - clk_disable_unprepare(i2c->clk); - - return 0; -} - -static struct platform_driver zx2967_i2c_driver = { - .probe = zx2967_i2c_probe, - .remove = zx2967_i2c_remove, - .driver = { - .name = "zx2967_i2c", - .of_match_table = zx2967_i2c_of_match, - .pm = &zx2967_i2c_dev_pm_ops, - }, -}; -module_platform_driver(zx2967_i2c_driver); - -MODULE_AUTHOR("Baoyou Xie "); -MODULE_DESCRIPTION("ZTE ZX2967 I2C Bus Controller driver"); -MODULE_LICENSE("GPL v2"); -- cgit From 3928bbb0206bac100b7f4942356790aef758ed39 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 12 Jan 2021 16:17:09 +0300 Subject: i2c: tegra: Use threaded interrupt Switch to use threaded interrupt context in order to avoid checking of "are we in interrupt?" for the code that may sleep in the IRQ handler. I2C doesn't require a very low interrupt-handling latency, hence this change doesn't introduce any noticeable effects. Signed-off-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 8b113ae32dc7..c883044715f3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -550,7 +550,7 @@ static int tegra_i2c_poll_register(struct tegra_i2c_dev *i2c_dev, void __iomem *addr = i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg); u32 val; - if (!i2c_dev->atomic_mode && !in_irq()) + if (!i2c_dev->atomic_mode) return readl_relaxed_poll_timeout(addr, val, !(val & mask), delay_us, timeout_us); @@ -1739,9 +1739,10 @@ static int tegra_i2c_probe(struct platform_device *pdev) /* interrupt will be enabled during of transfer time */ irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN); - err = devm_request_irq(i2c_dev->dev, i2c_dev->irq, tegra_i2c_isr, - IRQF_NO_SUSPEND, dev_name(i2c_dev->dev), - i2c_dev); + err = devm_request_threaded_irq(i2c_dev->dev, i2c_dev->irq, + NULL, tegra_i2c_isr, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + dev_name(i2c_dev->dev), i2c_dev); if (err) return err; -- cgit From 265fec2aab03c84fc9ba7c00d43b3f22eba3ace2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 12 Jan 2021 16:12:29 +0100 Subject: i2c: smbus: don't abuse loop variable Don't use 'i' to carry data, make a specific variable for it. After the move to memcpy recently, we can even remove 'i'. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index bf6bfe7c5cfe..6cda46913d89 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -324,7 +324,6 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ ? 2 : 1; - int i; u8 partial_pec = 0; int status; struct i2c_msg msg[2] = { @@ -340,6 +339,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, .buf = msgbuf1, }, }; + bool wants_pec = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA); msgbuf0[0] = command; switch (size) { @@ -443,9 +444,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, return -EOPNOTSUPP; } - i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK - && size != I2C_SMBUS_I2C_BLOCK_DATA); - if (i) { + if (wants_pec) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { if (num == 1) /* Write only */ @@ -468,7 +467,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, status = 0; /* Check PEC if last message is a read */ - if (i && (msg[num-1].flags & I2C_M_RD)) { + if (wants_pec && (msg[num-1].flags & I2C_M_RD)) { status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); if (status < 0) goto cleanup; -- cgit From 0390bdd4bf0cbe234d639b1891739bf5645137ee Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 12 Jan 2021 16:12:30 +0100 Subject: i2c: smbus: improve naming in i2c_smbus_xfer_emulated() This may be just taste, but I think 'nmsgs' is way more readable than a generic 'num' variable. Also, fix spaces around operators while here. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 6cda46913d89..d2d32c0fd8c3 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -323,7 +323,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, */ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; - int num = read_write == I2C_SMBUS_READ ? 2 : 1; + int nmsgs = read_write == I2C_SMBUS_READ ? 2 : 1; u8 partial_pec = 0; int status; struct i2c_msg msg[2] = { @@ -349,13 +349,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, /* Special case: The read/write field is used as data */ msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? I2C_M_RD : 0); - num = 1; + nmsgs = 1; break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { /* Special case: only a read! */ msg[0].flags = I2C_M_RD | flags; - num = 1; + nmsgs = 1; } break; case I2C_SMBUS_BYTE_DATA: @@ -376,7 +376,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, } break; case I2C_SMBUS_PROC_CALL: - num = 2; /* Special case */ + nmsgs = 2; /* Special case */ read_write = I2C_SMBUS_READ; msg[0].len = 3; msg[1].len = 2; @@ -403,7 +403,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, } break; case I2C_SMBUS_BLOCK_PROC_CALL: - num = 2; /* Another special case */ + nmsgs = 2; /* Another special case */ read_write = I2C_SMBUS_READ; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { dev_err(&adapter->dev, @@ -447,28 +447,28 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, if (wants_pec) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { - if (num == 1) /* Write only */ + if (nmsgs == 1) /* Write only */ i2c_smbus_add_pec(&msg[0]); else /* Write followed by read */ partial_pec = i2c_smbus_msg_pec(0, &msg[0]); } /* Ask for PEC if last message is a read */ - if (msg[num-1].flags & I2C_M_RD) - msg[num-1].len++; + if (msg[nmsgs - 1].flags & I2C_M_RD) + msg[nmsgs - 1].len++; } - status = __i2c_transfer(adapter, msg, num); + status = __i2c_transfer(adapter, msg, nmsgs); if (status < 0) goto cleanup; - if (status != num) { + if (status != nmsgs) { status = -EIO; goto cleanup; } status = 0; /* Check PEC if last message is a read */ - if (wants_pec && (msg[num-1].flags & I2C_M_RD)) { - status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); + if (wants_pec && (msg[nmsgs - 1].flags & I2C_M_RD)) { + status = i2c_smbus_check_pec(partial_pec, &msg[nmsgs - 1]); if (status < 0) goto cleanup; } -- cgit From 337bc68c294dd42538409f2a37b3daad2c851f98 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 22 Jan 2021 21:24:56 +0200 Subject: i2c: mux: mlxcpld: Update module license Update license to SPDX-License. Signed-off-by: Vadim Pasternak Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 5ed55ca4fe93..53bce81cf5c9 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -1,35 +1,8 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /* - * drivers/i2c/muxes/i2c-mux-mlxcpld.c - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. - * Copyright (c) 2016 Michael Shych + * Mellanox i2c mux driver * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * Copyright (C) 2016-2020 Mellanox Technologies */ #include -- cgit From 98d29c410475f30b627502d845794352e9be4046 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 22 Jan 2021 21:24:58 +0200 Subject: i2c: mux: mlxcpld: Move header file out of x86 realm Move out header file from include/linux/platform_data/x86/ to include/linux/platform_data/, since it does not depend on x86 architecture. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 53bce81cf5c9..3d894cfb19df 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include -- cgit From 267e82b9592d0d97f732d65a63db12b0e0d73bd4 Mon Sep 17 00:00:00 2001 From: Richard Neumann Date: Mon, 1 Feb 2021 18:51:37 +0100 Subject: i2c: amd-mp2: convert to PCI logging functions Use pci_{info,warn,err,dbg} functions of the kernel's PCI API. Remove unnecessary ndev_pdev(), ndev_name() and ndev_dev() macros. While at it, remove useless __func__ from logging. Signed-off-by: Richard Neumann Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-amd-mp2-pci.c | 55 +++++++++++++++-------------------- drivers/i2c/busses/i2c-amd-mp2-plat.c | 3 +- drivers/i2c/busses/i2c-amd-mp2.h | 3 -- 3 files changed, 24 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index cd3fd5ee5f65..ce130a821ea5 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -30,7 +30,7 @@ static void amd_mp2_c2p_mutex_unlock(struct amd_i2c_common *i2c_common) struct amd_mp2_dev *privdata = i2c_common->mp2_dev; if (unlikely(privdata->c2p_lock_busid != i2c_common->bus_id)) { - dev_warn(ndev_dev(privdata), + pci_warn(privdata->pci_dev, "bus %d attempting to unlock C2P locked by bus %d\n", i2c_common->bus_id, privdata->c2p_lock_busid); return; @@ -59,8 +59,7 @@ int amd_mp2_bus_enable_set(struct amd_i2c_common *i2c_common, bool enable) struct amd_mp2_dev *privdata = i2c_common->mp2_dev; union i2c_cmd_base i2c_cmd_base; - dev_dbg(ndev_dev(privdata), "%s id: %d\n", __func__, - i2c_common->bus_id); + pci_dbg(privdata->pci_dev, "id: %d\n", i2c_common->bus_id); i2c_cmd_base.ul = 0; i2c_cmd_base.s.i2c_cmd = enable ? i2c_enable : i2c_disable; @@ -111,20 +110,19 @@ EXPORT_SYMBOL_GPL(amd_mp2_rw); static void amd_mp2_pci_check_rw_event(struct amd_i2c_common *i2c_common) { struct amd_mp2_dev *privdata = i2c_common->mp2_dev; + struct pci_dev *pdev = privdata->pci_dev; int len = i2c_common->eventval.r.length; u32 slave_addr = i2c_common->eventval.r.slave_addr; bool err = false; if (unlikely(len != i2c_common->msg->len)) { - dev_err(ndev_dev(privdata), - "length %d in event doesn't match buffer length %d!\n", + pci_err(pdev, "length %d in event doesn't match buffer length %d!\n", len, i2c_common->msg->len); err = true; } if (unlikely(slave_addr != i2c_common->msg->addr)) { - dev_err(ndev_dev(privdata), - "unexpected slave address %x (expected: %x)!\n", + pci_err(pdev, "unexpected slave address %x (expected: %x)!\n", slave_addr, i2c_common->msg->addr); err = true; } @@ -136,13 +134,14 @@ static void amd_mp2_pci_check_rw_event(struct amd_i2c_common *i2c_common) static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common) { struct amd_mp2_dev *privdata = i2c_common->mp2_dev; + struct pci_dev *pdev = privdata->pci_dev; enum status_type sts = i2c_common->eventval.r.status; enum response_type res = i2c_common->eventval.r.response; int len = i2c_common->eventval.r.length; if (res != command_success) { if (res != command_failed) - dev_err(ndev_dev(privdata), "invalid response to i2c command!\n"); + pci_err(pdev, "invalid response to i2c command!\n"); return; } @@ -155,32 +154,26 @@ static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common) privdata->mmio + AMD_C2P_MSG2, len); } else if (sts != i2c_readfail_event) { - dev_err(ndev_dev(privdata), - "invalid i2c status after read (%d)!\n", sts); + pci_err(pdev, "invalid i2c status after read (%d)!\n", sts); } break; case i2c_write: if (sts == i2c_writecomplete_event) amd_mp2_pci_check_rw_event(i2c_common); else if (sts != i2c_writefail_event) - dev_err(ndev_dev(privdata), - "invalid i2c status after write (%d)!\n", sts); + pci_err(pdev, "invalid i2c status after write (%d)!\n", sts); break; case i2c_enable: if (sts == i2c_busenable_complete) i2c_common->cmd_success = true; else if (sts != i2c_busenable_failed) - dev_err(ndev_dev(privdata), - "invalid i2c status after bus enable (%d)!\n", - sts); + pci_err(pdev, "invalid i2c status after bus enable (%d)!\n", sts); break; case i2c_disable: if (sts == i2c_busdisable_complete) i2c_common->cmd_success = true; else if (sts != i2c_busdisable_failed) - dev_err(ndev_dev(privdata), - "invalid i2c status after bus disable (%d)!\n", - sts); + pci_err(pdev, "invalid i2c status after bus disable (%d)!\n", sts); break; default: break; @@ -190,10 +183,10 @@ static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common) void amd_mp2_process_event(struct amd_i2c_common *i2c_common) { struct amd_mp2_dev *privdata = i2c_common->mp2_dev; + struct pci_dev *pdev = privdata->pci_dev; if (unlikely(i2c_common->reqcmd == i2c_none)) { - dev_warn(ndev_dev(privdata), - "received msg but no cmd was sent (bus = %d)!\n", + pci_warn(pdev, "received msg but no cmd was sent (bus = %d)!\n", i2c_common->bus_id); return; } @@ -208,6 +201,7 @@ EXPORT_SYMBOL_GPL(amd_mp2_process_event); static irqreturn_t amd_mp2_irq_isr(int irq, void *dev) { struct amd_mp2_dev *privdata = dev; + struct pci_dev *pdev = privdata->pci_dev; struct amd_i2c_common *i2c_common; u32 val; unsigned int bus_id; @@ -236,8 +230,7 @@ static irqreturn_t amd_mp2_irq_isr(int irq, void *dev) val = readl(privdata->mmio + AMD_P2C_MSG_INTEN); if (val != 0) { writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); - dev_warn(ndev_dev(privdata), - "received irq without message\n"); + pci_warn(pdev, "received irq without message\n"); ret = IRQ_HANDLED; } } @@ -255,13 +248,13 @@ EXPORT_SYMBOL_GPL(amd_mp2_rw_timeout); int amd_mp2_register_cb(struct amd_i2c_common *i2c_common) { struct amd_mp2_dev *privdata = i2c_common->mp2_dev; + struct pci_dev *pdev = privdata->pci_dev; if (i2c_common->bus_id > 1) return -EINVAL; if (privdata->busses[i2c_common->bus_id]) { - dev_err(ndev_dev(privdata), - "Bus %d already taken!\n", i2c_common->bus_id); + pci_err(pdev, "Bus %d already taken!\n", i2c_common->bus_id); return -EINVAL; } @@ -301,13 +294,13 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, rc = pcim_enable_device(pci_dev); if (rc) { - dev_err(ndev_dev(privdata), "Failed to enable MP2 PCI device\n"); + pci_err(pci_dev, "Failed to enable MP2 PCI device\n"); goto err_pci_enable; } rc = pcim_iomap_regions(pci_dev, 1 << 2, pci_name(pci_dev)); if (rc) { - dev_err(ndev_dev(privdata), "I/O memory remapping failed\n"); + pci_err(pci_dev, "I/O memory remapping failed\n"); goto err_pci_enable; } privdata->mmio = pcim_iomap_table(pci_dev)[2]; @@ -327,7 +320,7 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, rc = devm_request_irq(&pci_dev->dev, pci_dev->irq, amd_mp2_irq_isr, IRQF_SHARED, dev_name(&pci_dev->dev), privdata); if (rc) - dev_err(&pci_dev->dev, "Failure requesting irq %i: %d\n", + pci_err(pci_dev, "Failure requesting irq %i: %d\n", pci_dev->irq, rc); return rc; @@ -363,7 +356,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev, privdata->probed = true; - dev_info(&pci_dev->dev, "MP2 device registered.\n"); + pci_info(pci_dev, "MP2 device registered.\n"); return 0; } @@ -397,8 +390,7 @@ static int amd_mp2_pci_suspend(struct device *dev) ret = pci_save_state(pci_dev); if (ret) { - dev_err(ndev_dev(privdata), - "pci_save_state failed = %d\n", ret); + pci_err(pci_dev, "pci_save_state failed = %d\n", ret); return ret; } @@ -417,8 +409,7 @@ static int amd_mp2_pci_resume(struct device *dev) pci_restore_state(pci_dev); ret = pci_enable_device(pci_dev); if (ret < 0) { - dev_err(ndev_dev(privdata), - "pci_enable_device failed = %d\n", ret); + pci_err(pci_dev, "pci_enable_device failed = %d\n", ret); return ret; } diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 506433bc0ff2..de058671f9b8 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -88,8 +88,7 @@ static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common) union i2c_event *event = &i2c_common->eventval; if (event->r.status == i2c_readcomplete_event) - dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n", - __func__, event->r.length, + dev_dbg(&i2c_dev->pdev->dev, "readdata:%*ph\n", event->r.length, i2c_common->msg->buf); complete(&i2c_dev->cmd_complete); diff --git a/drivers/i2c/busses/i2c-amd-mp2.h b/drivers/i2c/busses/i2c-amd-mp2.h index 058362edebaa..6b91e285745d 100644 --- a/drivers/i2c/busses/i2c-amd-mp2.h +++ b/drivers/i2c/busses/i2c-amd-mp2.h @@ -185,9 +185,6 @@ struct amd_mp2_dev { unsigned int probed; }; -#define ndev_pdev(ndev) ((ndev)->pci_dev) -#define ndev_name(ndev) pci_name(ndev_pdev(ndev)) -#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev) #define work_amd_i2c_common(__work) \ container_of(__work, struct amd_i2c_common, work.work) -- cgit From 622fa41b496d5d15247727cbfc5d000f36755bbc Mon Sep 17 00:00:00 2001 From: Richard Neumann Date: Mon, 1 Feb 2021 18:51:38 +0100 Subject: i2c: amd-mp2: Remove unused macro Remove unused work_amd_i2c_common() macro. Signed-off-by: Richard Neumann Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-amd-mp2.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-amd-mp2.h b/drivers/i2c/busses/i2c-amd-mp2.h index 6b91e285745d..ddecd0c88656 100644 --- a/drivers/i2c/busses/i2c-amd-mp2.h +++ b/drivers/i2c/busses/i2c-amd-mp2.h @@ -185,9 +185,6 @@ struct amd_mp2_dev { unsigned int probed; }; -#define work_amd_i2c_common(__work) \ - container_of(__work, struct amd_i2c_common, work.work) - /* PCIe communication driver */ int amd_mp2_rw(struct amd_i2c_common *i2c_common, enum i2c_cmd reqcmd); -- cgit From e5c02cf541541605f704fbbb9a764e23f88ad0cb Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 3 Jan 2021 04:51:46 -0600 Subject: i2c: mv64xxx: Add runtime PM support To save power, gate the clock when the bus is inactive, during system sleep, and during shutdown. On some platforms, specifically Allwinner A13/A20, gating the clock implicitly resets the module as well. Since the module already needs to be reset after some suspend/resume cycles, it is simple enough to reset it during every runtime suspend/resume. Because the bus may be used by wakeup source IRQ threads, it needs to be functional as soon as IRQs are enabled. Thus, its system PM hooks need to run in the noirq phase. Signed-off-by: Samuel Holland Tested-by: Ondrej Jirman Acked-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 120 +++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 5cfe70aedced..b03c344323d1 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -717,6 +718,10 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); int rc, ret = num; + rc = pm_runtime_resume_and_get(&adap->dev); + if (rc) + return rc; + BUG_ON(drv_data->msgs != NULL); drv_data->msgs = msgs; drv_data->num_msgs = num; @@ -732,6 +737,9 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) drv_data->num_msgs = 0; drv_data->msgs = NULL; + pm_runtime_mark_last_busy(&adap->dev); + pm_runtime_put_autosuspend(&adap->dev); + return ret; } @@ -828,7 +836,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, 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. @@ -893,6 +900,32 @@ static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data, return 0; } +static int +mv64xxx_i2c_runtime_suspend(struct device *dev) +{ + struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); + + reset_control_assert(drv_data->rstc); + clk_disable_unprepare(drv_data->reg_clk); + clk_disable_unprepare(drv_data->clk); + + return 0; +} + +static int +mv64xxx_i2c_runtime_resume(struct device *dev) +{ + struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); + + clk_prepare_enable(drv_data->clk); + clk_prepare_enable(drv_data->reg_clk); + reset_control_reset(drv_data->rstc); + + mv64xxx_i2c_hw_init(drv_data); + + return 0; +} + static int mv64xxx_i2c_probe(struct platform_device *pd) { @@ -920,18 +953,22 @@ mv64xxx_i2c_probe(struct platform_device *pd) /* Not all platforms have clocks */ drv_data->clk = devm_clk_get(&pd->dev, NULL); - if (PTR_ERR(drv_data->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR(drv_data->clk)) - clk_prepare_enable(drv_data->clk); + if (IS_ERR(drv_data->clk)) { + if (PTR_ERR(drv_data->clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + drv_data->clk = NULL; + } drv_data->reg_clk = devm_clk_get(&pd->dev, "reg"); - if (PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR(drv_data->reg_clk)) - clk_prepare_enable(drv_data->reg_clk); + if (IS_ERR(drv_data->reg_clk)) { + if (PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + drv_data->reg_clk = NULL; + } drv_data->irq = platform_get_irq(pd, 0); + if (drv_data->irq < 0) + return drv_data->irq; if (pdata) { drv_data->freq_m = pdata->freq_m; @@ -942,16 +979,12 @@ mv64xxx_i2c_probe(struct platform_device *pd) } else if (pd->dev.of_node) { rc = mv64xxx_of_config(drv_data, &pd->dev); if (rc) - goto exit_clk; - } - if (drv_data->irq < 0) { - rc = drv_data->irq; - goto exit_reset; + return rc; } rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev); if (rc == -EPROBE_DEFER) - goto exit_reset; + return rc; drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.algo = &mv64xxx_i2c_algo; @@ -962,7 +995,14 @@ mv64xxx_i2c_probe(struct platform_device *pd) platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); - mv64xxx_i2c_hw_init(drv_data); + pm_runtime_set_autosuspend_delay(&pd->dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(&pd->dev); + pm_runtime_enable(&pd->dev); + if (!pm_runtime_enabled(&pd->dev)) { + rc = mv64xxx_i2c_runtime_resume(&pd->dev); + if (rc) + goto exit_disable_pm; + } rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, MV64XXX_I2C_CTLR_NAME, drv_data); @@ -970,7 +1010,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) dev_err(&drv_data->adapter.dev, "mv64xxx: Can't register intr handler irq%d: %d\n", drv_data->irq, rc); - goto exit_reset; + goto exit_disable_pm; } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { dev_err(&drv_data->adapter.dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); @@ -981,54 +1021,50 @@ mv64xxx_i2c_probe(struct platform_device *pd) exit_free_irq: free_irq(drv_data->irq, drv_data); -exit_reset: - reset_control_assert(drv_data->rstc); -exit_clk: - clk_disable_unprepare(drv_data->reg_clk); - clk_disable_unprepare(drv_data->clk); +exit_disable_pm: + pm_runtime_disable(&pd->dev); + if (!pm_runtime_status_suspended(&pd->dev)) + mv64xxx_i2c_runtime_suspend(&pd->dev); return rc; } static int -mv64xxx_i2c_remove(struct platform_device *dev) +mv64xxx_i2c_remove(struct platform_device *pd) { - struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev); + struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(pd); i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); - reset_control_assert(drv_data->rstc); - clk_disable_unprepare(drv_data->reg_clk); - clk_disable_unprepare(drv_data->clk); + pm_runtime_disable(&pd->dev); + if (!pm_runtime_status_suspended(&pd->dev)) + mv64xxx_i2c_runtime_suspend(&pd->dev); return 0; } -#ifdef CONFIG_PM -static int mv64xxx_i2c_resume(struct device *dev) +static void +mv64xxx_i2c_shutdown(struct platform_device *pd) { - struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); - - mv64xxx_i2c_hw_init(drv_data); - - return 0; + pm_runtime_disable(&pd->dev); + if (!pm_runtime_status_suspended(&pd->dev)) + mv64xxx_i2c_runtime_suspend(&pd->dev); } -static const struct dev_pm_ops mv64xxx_i2c_pm = { - .resume = mv64xxx_i2c_resume, +static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { + SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend, + mv64xxx_i2c_runtime_resume, NULL) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; -#define mv64xxx_i2c_pm_ops (&mv64xxx_i2c_pm) -#else -#define mv64xxx_i2c_pm_ops NULL -#endif - static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, .remove = mv64xxx_i2c_remove, + .shutdown = mv64xxx_i2c_shutdown, .driver = { .name = MV64XXX_I2C_CTLR_NAME, - .pm = mv64xxx_i2c_pm_ops, + .pm = &mv64xxx_i2c_pm_ops, .of_match_table = mv64xxx_i2c_of_match_table, }, }; -- cgit From e0371298ddc51761be257698554ea507ac8bf831 Mon Sep 17 00:00:00 2001 From: Roja Rani Yarubandi Date: Fri, 8 Jan 2021 20:35:45 +0530 Subject: i2c: i2c-qcom-geni: Add shutdown callback for i2c If the hardware is still accessing memory after SMMU translation is disabled (as part of smmu shutdown callback), then the IOVAs (I/O virtual address) which it was using will go on the bus as the physical addresses which will result in unknown crashes like NoC/interconnect errors. So, implement shutdown callback to i2c driver to stop on-going transfer and unmap DMA mappings during system "reboot" or "shutdown". Fixes: 37692de5d523 ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller") Signed-off-by: Roja Rani Yarubandi Reviewed-by: Akash Asthana Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 214b4c913a13..c3f584795911 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -375,6 +375,32 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c, } } +static void geni_i2c_stop_xfer(struct geni_i2c_dev *gi2c) +{ + int ret; + u32 geni_status; + struct i2c_msg *cur; + + /* Resume device, as runtime suspend can happen anytime during transfer */ + ret = pm_runtime_get_sync(gi2c->se.dev); + if (ret < 0) { + dev_err(gi2c->se.dev, "Failed to resume device: %d\n", ret); + return; + } + + geni_status = readl_relaxed(gi2c->se.base + SE_GENI_STATUS); + if (geni_status & M_GENI_CMD_ACTIVE) { + cur = gi2c->cur; + geni_i2c_abort_xfer(gi2c); + if (cur->flags & I2C_M_RD) + geni_i2c_rx_msg_cleanup(gi2c, cur); + else + geni_i2c_tx_msg_cleanup(gi2c, cur); + } + + pm_runtime_put_sync_suspend(gi2c->se.dev); +} + static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, u32 m_param) { @@ -650,6 +676,13 @@ static int geni_i2c_remove(struct platform_device *pdev) return 0; } +static void geni_i2c_shutdown(struct platform_device *pdev) +{ + struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); + + geni_i2c_stop_xfer(gi2c); +} + static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) { int ret; @@ -714,6 +747,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); static struct platform_driver geni_i2c_driver = { .probe = geni_i2c_probe, .remove = geni_i2c_remove, + .shutdown = geni_i2c_shutdown, .driver = { .name = "geni_i2c", .pm = &geni_i2c_pm_ops, -- cgit From 05ae60bc24f765d0db6b7c6e5acabf22718b823d Mon Sep 17 00:00:00 2001 From: Kevin Paul Herbert Date: Tue, 22 Dec 2020 11:48:50 -0800 Subject: i2c: imx: Synthesize end of transaction events without idle interrupts Only the Layerscape SoCs have interrupts on bus idle, which facilitate sending events which complete slave bus transactions. Add support for synthesizing missing events. If we see a master request, or a newly addressed slave request, if the last event sent to the backend was I2C_SLAVE_READ_REQUESTED, send the backend a I2C_SLAVE_READ_PROCESSED followed by I2C_SLAVE_STOP. For all other events, send an I2C_SLAVE_STOP. Signed-off-by: Kevin Paul Herbert Tested-by: Oleksij Rempel Reviewed-by: Oleksij Rempel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 59 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index ca47e4041ca5..b80fdc1f0092 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -209,6 +209,7 @@ struct imx_i2c_struct { struct imx_i2c_dma *dma; struct i2c_client *slave; + enum i2c_slave_event last_slave_event; }; static const struct imx_i2c_hwdata imx1_i2c_hwdata = { @@ -675,6 +676,36 @@ static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx) } } +static void i2c_imx_slave_event(struct imx_i2c_struct *i2c_imx, + enum i2c_slave_event event, u8 *val) +{ + i2c_slave_event(i2c_imx->slave, event, val); + i2c_imx->last_slave_event = event; +} + +static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) +{ + u8 val; + + while (i2c_imx->last_slave_event != I2C_SLAVE_STOP) { + switch (i2c_imx->last_slave_event) { + case I2C_SLAVE_READ_REQUESTED: + i2c_imx_slave_event(i2c_imx, I2C_SLAVE_READ_PROCESSED, + &val); + break; + + case I2C_SLAVE_WRITE_REQUESTED: + case I2C_SLAVE_READ_PROCESSED: + case I2C_SLAVE_WRITE_RECEIVED: + i2c_imx_slave_event(i2c_imx, I2C_SLAVE_STOP, &val); + break; + + case I2C_SLAVE_STOP: + break; + } + } +} + static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, unsigned int status, unsigned int ctl) { @@ -687,9 +718,11 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, } if (status & I2SR_IAAS) { /* Addressed as a slave */ + i2c_imx_slave_finish_op(i2c_imx); if (status & I2SR_SRW) { /* Master wants to read from us*/ dev_dbg(&i2c_imx->adapter.dev, "read requested"); - i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_READ_REQUESTED, &value); /* Slave transmit */ ctl |= I2CR_MTX; @@ -699,7 +732,8 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); } else { /* Master wants to write to us */ dev_dbg(&i2c_imx->adapter.dev, "write requested"); - i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_WRITE_REQUESTED, &value); /* Slave receive */ ctl &= ~I2CR_MTX; @@ -710,17 +744,20 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, } else if (!(ctl & I2CR_MTX)) { /* Receive mode */ if (status & I2SR_IBB) { /* No STOP signal detected */ value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); - i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_WRITE_RECEIVED, &value); } else { /* STOP signal is detected */ dev_dbg(&i2c_imx->adapter.dev, "STOP signal detected"); - i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_STOP, &value); } } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ ctl |= I2CR_MTX; imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); - i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_READ_PROCESSED, &value); imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); } else { /* Transmit mode received NAK */ @@ -761,6 +798,7 @@ static int i2c_imx_reg_slave(struct i2c_client *client) return -EBUSY; i2c_imx->slave = client; + i2c_imx->last_slave_event = I2C_SLAVE_STOP; /* Resume */ ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); @@ -813,10 +851,17 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + if (status & I2SR_IIF) { i2c_imx_clear_irq(i2c_imx, I2SR_IIF); - if (i2c_imx->slave && !(ctl & I2CR_MSTA)) - return i2c_imx_slave_isr(i2c_imx, status, ctl); + if (i2c_imx->slave) { + if (!(ctl & I2CR_MSTA)) { + return i2c_imx_slave_isr(i2c_imx, status, ctl); + } else if (i2c_imx->last_slave_event != + I2C_SLAVE_STOP) { + i2c_imx_slave_finish_op(i2c_imx); + } + } return i2c_imx_master_isr(i2c_imx, status); } -- cgit From 84af1b168c5015fca0761cf9cce4add31e354dce Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:01 +0200 Subject: i2c: mux: mlxcpld: Convert driver to platform driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert driver from 'i2c' to 'platform'. The motivation is to avoid I2C addressing conflict between ‘i2c-mux-cpld’ driver, providing mux selection and deselection through CPLD ‘mux control’ register, and CPLD host driver. The CPLD is I2C device and is multi-functional device performing logic for different components, like LED, ‘hwmon’, interrupt control, watchdog etcetera. For such configuration CPLD should be host I2C device, connected to the relevant I2C bus with the relevant I2C address and all others component drivers are supposed to be its children. The hierarchy in such case will be like in the below example: ls /sys/bus/i2c/devices/44-0032 i2c-mux-mlxcpld.44 leds-mlxreg.44 mlxreg-io.44 ls /sys/bus/i2c/devices/44-0032/i2c-mux-mlxcpld.44 channel-0, …, channel-X Currently this driver is not activated by any kernel driver, so this conversion doesn’t affect any user. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 62 +++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 3d894cfb19df..b53f1479272d 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -20,10 +20,12 @@ /* mlxcpld_mux - mux control structure: * @last_chan - last register value * @client - I2C device client + * @pdata: platform data */ struct mlxcpld_mux { u8 last_chan; struct i2c_client *client; + struct mlxcpld_mux_plat_data pdata; }; /* MUX logic description. @@ -54,37 +56,30 @@ struct mlxcpld_mux { * */ -static const struct i2c_device_id mlxcpld_mux_id[] = { - { "mlxcpld_mux_module", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id); - /* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer() * for this as they will try to lock adapter a second time. */ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, - struct i2c_client *client, u8 val) + struct mlxcpld_mux *mux, u8 val) { - struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); + struct i2c_client *client = mux->client; union i2c_smbus_data data = { .byte = val }; return __i2c_smbus_xfer(adap, client->addr, client->flags, - I2C_SMBUS_WRITE, pdata->sel_reg_addr, + I2C_SMBUS_WRITE, mux->pdata.sel_reg_addr, I2C_SMBUS_BYTE_DATA, &data); } static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) { - struct mlxcpld_mux *data = i2c_mux_priv(muxc); - struct i2c_client *client = data->client; + struct mlxcpld_mux *mux = i2c_mux_priv(muxc); u8 regval = chan + 1; int err = 0; /* Only select the channel if its different from the last channel */ - if (data->last_chan != regval) { - err = mlxcpld_mux_reg_write(muxc->parent, client, regval); - data->last_chan = err < 0 ? 0 : regval; + if (mux->last_chan != regval) { + err = mlxcpld_mux_reg_write(muxc->parent, mux, regval); + mux->last_chan = err < 0 ? 0 : regval; } return err; @@ -92,21 +87,19 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) { - struct mlxcpld_mux *data = i2c_mux_priv(muxc); - struct i2c_client *client = data->client; + struct mlxcpld_mux *mux = i2c_mux_priv(muxc); /* Deselect active channel */ - data->last_chan = 0; + mux->last_chan = 0; - return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan); + return mlxcpld_mux_reg_write(muxc->parent, mux, mux->last_chan); } /* Probe/reomove functions */ -static int mlxcpld_mux_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mlxcpld_mux_probe(struct platform_device *pdev) { - struct i2c_adapter *adap = client->adapter; - struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); + struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&pdev->dev); + struct i2c_client *client = to_i2c_client(pdev->dev.parent); struct i2c_mux_core *muxc; int num, force; struct mlxcpld_mux *data; @@ -115,18 +108,20 @@ static int mlxcpld_mux_probe(struct i2c_client *client, if (!pdata) return -EINVAL; - if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return -ENODEV; - muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS, + muxc = i2c_mux_alloc(client->adapter, &pdev->dev, CPLD_MUX_MAX_NCHANS, sizeof(*data), 0, mlxcpld_mux_select_chan, mlxcpld_mux_deselect); if (!muxc) return -ENOMEM; + platform_set_drvdata(pdev, muxc); data = i2c_mux_priv(muxc); - i2c_set_clientdata(client, muxc); data->client = client; + memcpy(&data->pdata, pdata, sizeof(*pdata)); data->last_chan = 0; /* force the first selection */ /* Create an adapter for each channel. */ @@ -149,24 +144,23 @@ virt_reg_failed: return err; } -static int mlxcpld_mux_remove(struct i2c_client *client) +static int mlxcpld_mux_remove(struct platform_device *pdev) { - struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); return 0; } -static struct i2c_driver mlxcpld_mux_driver = { - .driver = { - .name = "mlxcpld-mux", +static struct platform_driver mlxcpld_mux_driver = { + .driver = { + .name = "i2c-mux-mlxcpld", }, - .probe = mlxcpld_mux_probe, - .remove = mlxcpld_mux_remove, - .id_table = mlxcpld_mux_id, + .probe = mlxcpld_mux_probe, + .remove = mlxcpld_mux_remove, }; -module_i2c_driver(mlxcpld_mux_driver); +module_platform_driver(mlxcpld_mux_driver); MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); -- cgit From 81566938083af15aec75201293cf6047bb04f4d3 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:02 +0200 Subject: i2c: mux: mlxcpld: Prepare mux selection infrastructure for two-byte support Allow to program register value zero to the mux register, which is required for word address mux register space support. Change key selector type from 'unsigned short' to 'integer' in order to allow to set it to -1 on deselection. Rename key selector field from 'last_chan' to 'last_val', since this fields keeps actually selector value and not channel number. Signed-off-by: Vadim Pasternak Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index b53f1479272d..113ad84cdd94 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -18,12 +18,12 @@ #define CPLD_MUX_MAX_NCHANS 8 /* mlxcpld_mux - mux control structure: - * @last_chan - last register value + * @last_val - last selected register value or -1 if mux deselected * @client - I2C device client * @pdata: platform data */ struct mlxcpld_mux { - u8 last_chan; + int last_val; struct i2c_client *client; struct mlxcpld_mux_plat_data pdata; }; @@ -60,7 +60,7 @@ struct mlxcpld_mux { * for this as they will try to lock adapter a second time. */ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, - struct mlxcpld_mux *mux, u8 val) + struct mlxcpld_mux *mux, u32 val) { struct i2c_client *client = mux->client; union i2c_smbus_data data = { .byte = val }; @@ -73,13 +73,13 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) { struct mlxcpld_mux *mux = i2c_mux_priv(muxc); - u8 regval = chan + 1; + u32 regval = chan + 1; int err = 0; /* Only select the channel if its different from the last channel */ - if (mux->last_chan != regval) { + if (mux->last_val != regval) { err = mlxcpld_mux_reg_write(muxc->parent, mux, regval); - mux->last_chan = err < 0 ? 0 : regval; + mux->last_val = err < 0 ? -1 : regval; } return err; @@ -90,9 +90,9 @@ static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) struct mlxcpld_mux *mux = i2c_mux_priv(muxc); /* Deselect active channel */ - mux->last_chan = 0; + mux->last_val = -1; - return mlxcpld_mux_reg_write(muxc->parent, mux, mux->last_chan); + return mlxcpld_mux_reg_write(muxc->parent, mux, 0); } /* Probe/reomove functions */ @@ -122,7 +122,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) data = i2c_mux_priv(muxc); data->client = client; memcpy(&data->pdata, pdata, sizeof(*pdata)); - data->last_chan = 0; /* force the first selection */ + data->last_val = -1; /* force the first selection */ /* Create an adapter for each channel. */ for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) { -- cgit From cae5216387d18c888f9f38a0cf5be341a0af75a6 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:03 +0200 Subject: i2c: mux: mlxcpld: Get rid of adapter numbers enforcement Do not set the argument 'force_nr' of i2c_mux_add_adapter() routine, instead provide argument 'chan_id'. Rename mux ids array from 'adap_ids' to 'chan_ids'. The motivation is to prepare infrastructure to be able to: - Create only the child adapters which are actually needed - for which channel ids are specified. - To assign 'nrs' to these child adapters dynamically, with no 'nr' enforcement. Signed-off-by: Vadim Pasternak Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 113ad84cdd94..e99a7ad09886 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -101,9 +101,8 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&pdev->dev); struct i2c_client *client = to_i2c_client(pdev->dev.parent); struct i2c_mux_core *muxc; - int num, force; struct mlxcpld_mux *data; - int err; + int num, err; if (!pdata) return -EINVAL; @@ -130,9 +129,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) /* discard unconfigured channels */ break; - force = pdata->adap_ids[num]; - - err = i2c_mux_add_adapter(muxc, force, num, 0); + err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0); if (err) goto virt_reg_failed; } -- cgit From c52a1c5f5db55c6a71110c2db9ae26b9f5269d20 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:04 +0200 Subject: i2c: mux: mlxcpld: Extend driver to support word address space devices Extend driver to allow I2C routing control through CPLD devices with word address space. Till now only CPLD devices with byte address space have been supported. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 47 ++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index e99a7ad09886..10767ad4adb4 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -63,19 +63,39 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, struct mlxcpld_mux *mux, u32 val) { struct i2c_client *client = mux->client; - union i2c_smbus_data data = { .byte = val }; - - return __i2c_smbus_xfer(adap, client->addr, client->flags, - I2C_SMBUS_WRITE, mux->pdata.sel_reg_addr, - I2C_SMBUS_BYTE_DATA, &data); + union i2c_smbus_data data; + struct i2c_msg msg; + u8 buf[3]; + + switch (mux->pdata.reg_size) { + case 1: + data.byte = val; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, mux->pdata.sel_reg_addr, + I2C_SMBUS_BYTE_DATA, &data); + case 2: + buf[0] = mux->pdata.sel_reg_addr >> 8; + buf[1] = mux->pdata.sel_reg_addr; + buf[2] = val; + msg.addr = client->addr; + msg.buf = buf; + msg.len = mux->pdata.reg_size + 1; + msg.flags = 0; + return __i2c_transfer(adap, &msg, 1); + default: + return -EINVAL; + } } static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) { struct mlxcpld_mux *mux = i2c_mux_priv(muxc); - u32 regval = chan + 1; + u32 regval = chan; int err = 0; + if (mux->pdata.reg_size == 1) + regval += 1; + /* Only select the channel if its different from the last channel */ if (mux->last_val != regval) { err = mlxcpld_mux_reg_write(muxc->parent, mux, regval); @@ -103,12 +123,23 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) struct i2c_mux_core *muxc; struct mlxcpld_mux *data; int num, err; + u32 func; if (!pdata) return -EINVAL; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + switch (pdata->reg_size) { + case 1: + func = I2C_FUNC_SMBUS_WRITE_BYTE_DATA; + break; + case 2: + func = I2C_FUNC_I2C; + break; + default: + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, func)) return -ENODEV; muxc = i2c_mux_alloc(client->adapter, &pdev->dev, CPLD_MUX_MAX_NCHANS, -- cgit From 699c0506543ee9ba3f5a67ab0837b292b098aeb4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:05 +0200 Subject: i2c: mux: mlxcpld: Extend supported mux number Allow to extend mux number supported by driver. Currently it is limited by eight, which is not enough for new coming Mellanox modular system with line cards, which require up to 64 mux support. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 10767ad4adb4..5e0672f9979b 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -15,8 +15,6 @@ #include #include -#define CPLD_MUX_MAX_NCHANS 8 - /* mlxcpld_mux - mux control structure: * @last_val - last selected register value or -1 if mux deselected * @client - I2C device client @@ -142,7 +140,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) if (!i2c_check_functionality(client->adapter, func)) return -ENODEV; - muxc = i2c_mux_alloc(client->adapter, &pdev->dev, CPLD_MUX_MAX_NCHANS, + muxc = i2c_mux_alloc(client->adapter, &pdev->dev, pdata->num_adaps, sizeof(*data), 0, mlxcpld_mux_select_chan, mlxcpld_mux_deselect); if (!muxc) @@ -155,11 +153,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) data->last_val = -1; /* force the first selection */ /* Create an adapter for each channel. */ - for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) { - if (num >= pdata->num_adaps) - /* discard unconfigured channels */ - break; - + for (num = 0; num < pdata->num_adaps; num++) { err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0); if (err) goto virt_reg_failed; -- cgit From a39bd92e92b96d05d676fb5c9493cf1c911d2a0a Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:06 +0200 Subject: i2c: mux: mlxcpld: Add callback to notify mux creation completion Add notification to inform caller that mux objects array has been created. It allows to user, invoked platform device registration for "i2c-mux-mlxcpld" driver, to be notified that mux infrastructure is available, and thus some devices could be connected to this infrastructure. Signed-off-by: Vadim Pasternak Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 5e0672f9979b..1a879f6a31ef 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -159,6 +159,10 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) goto virt_reg_failed; } + /* Notify caller when all channels' adapters are created. */ + if (pdata->completion_notify) + pdata->completion_notify(pdata->handle, muxc->parent, muxc->adapter); + return 0; virt_reg_failed: -- cgit From aab0b4fe1b757fb40466e506d296b81b03cc1594 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 8 Feb 2021 00:19:22 -0600 Subject: i2c: mv64xxx: Fix check for missing clock after adding RPM In commit e5c02cf54154 ("i2c: mv64xxx: Add runtime PM support"), error pointers to optional clocks were replaced by NULL to simplify the resume callback implementation. However, that commit missed that the IS_ERR check in mv64xxx_of_config should be replaced with a NULL check. As a result, the check always passes, even for an invalid device tree. Fixes: e5c02cf54154 ("i2c: mv64xxx: Add runtime PM support") Reported-by: Dan Carpenter Signed-off-by: Samuel Holland Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index b03c344323d1..c590d36b5fd1 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -813,7 +813,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, * need to know tclk in order to calculate bus clock * factors. */ - if (IS_ERR(drv_data->clk)) { + if (!drv_data->clk) { rc = -ENODEV; goto out; } -- cgit From d1f50bcfd646b620bef0e0ccb9b7523ad14fef63 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 14 Jan 2021 16:38:11 +0200 Subject: i2c: i801: Add support for Intel Alder Lake PCH-P Add PCI ID of SMBus controller on Intel Alder Lake PCH-P. Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 207332faefd8..4acee6f9e5a3 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -72,6 +72,7 @@ * Jasper Lake (SOC) 0x4da3 32 hard yes yes yes * Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes + * Alder Lake-P (PCH) 0x51a3 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -228,6 +229,7 @@ #define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 #define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 #define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 @@ -1084,6 +1086,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS) }, { 0, } }; @@ -1767,6 +1770,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: case PCI_DEVICE_ID_INTEL_EBG_SMBUS: case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: + case PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS: priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; -- cgit From bb3fe9ff5306d058af952f689f22448af286def8 Mon Sep 17 00:00:00 2001 From: Weihang Li Date: Mon, 8 Feb 2021 18:48:37 +0800 Subject: i2c: busses: Replace spin_lock_irqsave with spin_lock in hard IRQ There is no need to do irqsave and irqrestore in context of hard IRQ. Signed-off-by: Weihang Li Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-digicolor.c | 5 ++--- drivers/i2c/busses/i2c-jz4780.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index f67639dc74b7..60c838c7c454 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -160,12 +160,11 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id) { struct dc_i2c *i2c = dev_id; int cmd_status = dc_i2c_cmd_status(i2c); - unsigned long flags; u8 addr_cmd; writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); - spin_lock_irqsave(&i2c->lock, flags); + spin_lock(&i2c->lock); if (cmd_status == II_CMD_STATUS_ACK_BAD || cmd_status == II_CMD_STATUS_ABORT) { @@ -207,7 +206,7 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id) } out: - spin_unlock_irqrestore(&i2c->lock, flags); + spin_unlock(&i2c->lock); return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index cb4a25ebb890..8509c5f11356 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -437,9 +437,8 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) unsigned short intst; unsigned short intmsk; struct jz4780_i2c *i2c = dev_id; - unsigned long flags; - spin_lock_irqsave(&i2c->lock, flags); + spin_lock(&i2c->lock); intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST); @@ -551,7 +550,7 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) } done: - spin_unlock_irqrestore(&i2c->lock, flags); + spin_unlock(&i2c->lock); return IRQ_HANDLED; } -- cgit From b39ab96aa894e3f4a9a1cdfc070bd8ebefaeb9d8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 9 Feb 2021 12:19:27 +0100 Subject: i2c: testunit: add support for block process calls Devices offering SMBus block process calls are rare, so add it to the testunit. This is also a good test case for testing proper I2C_M_RECV_LEN flag handling of I2C bus masters emulating SMBus. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-slave-testunit.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index c288102de324..56dae08dfd48 100644 --- a/drivers/i2c/i2c-slave-testunit.c +++ b/drivers/i2c/i2c-slave-testunit.c @@ -19,6 +19,7 @@ enum testunit_cmds { TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */ TU_CMD_HOST_NOTIFY, + TU_CMD_SMBUS_BLOCK_PROC_CALL, TU_NUM_CMDS }; @@ -88,6 +89,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) { struct testunit_data *tu = i2c_get_clientdata(client); + bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 && + tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL; int ret = 0; switch (event) { @@ -118,12 +121,17 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, fallthrough; case I2C_SLAVE_WRITE_REQUESTED: + memset(tu->regs, 0, TU_NUM_REGS); tu->reg_idx = 0; break; - case I2C_SLAVE_READ_REQUESTED: case I2C_SLAVE_READ_PROCESSED: - *val = TU_CUR_VERSION; + if (is_proc_call && tu->regs[TU_REG_DATAH]) + tu->regs[TU_REG_DATAH]--; + fallthrough; + + case I2C_SLAVE_READ_REQUESTED: + *val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION; break; } -- cgit From 0b16cfd9e660f59e396ab5f3af7d49e3677e3f9c Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Tue, 12 Jan 2021 00:53:11 -0800 Subject: i2c: remove redundant error print in stm32f7_i2c_probe Coccinelle reports a redundant error print in stm32f7_i2c_probe. As 'platform_get_irq' already prints the error message, error print here is redundant and can be removed. Signed-off-by: Menglong Dong Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 9aa8e65b511e..adba496e1e31 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2026,12 +2026,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) } irq_error = platform_get_irq(pdev, 1); - if (irq_error <= 0) { - if (irq_error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", - irq_error); + if (irq_error <= 0) return irq_error ? : -ENOENT; - } i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, "wakeup-source"); -- cgit