From ef99066c7dede6ed2b67661308c3f22d526afcdb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Nov 2021 10:16:18 -0600 Subject: i2c: Remove Netlogic XLP variant Netlogic XLP was removed in commit 95b8a5e0111a ("MIPS: Remove NETLOGIC support"). With those gone, the single platform left to support is Cavium ThunderX2. Remove the Netlogic variant and DT support. For simplicity, the existing kconfig name is retained. Signed-off-by: Rob Herring Acked-by George Cherian Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 6 +++--- drivers/i2c/busses/i2c-xlp9xx.c | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index dce392839017..e9dd1640ffde 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1170,11 +1170,11 @@ config I2C_XLR will be called i2c-xlr. config I2C_XLP9XX - tristate "XLP9XX I2C support" - depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST + tristate "Cavium ThunderX2 I2C support" + depends on ARCH_THUNDER2 || COMPILE_TEST help This driver enables support for the on-chip I2C interface of - the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors. + the Cavium ThunderX2 processors. (Originally on Netlogic XLP SoCs.) This driver can also be built as a module. If so, the module will be called i2c-xlp9xx. diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 6d24dc385522..4e3b11c0f732 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -572,12 +572,6 @@ static int xlp9xx_i2c_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id xlp9xx_i2c_of_match[] = { - { .compatible = "netlogic,xlp980-i2c", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); - #ifdef CONFIG_ACPI static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { {"BRCM9007", 0}, @@ -592,7 +586,6 @@ static struct platform_driver xlp9xx_i2c_driver = { .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", - .of_match_table = xlp9xx_i2c_of_match, .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), }, }; -- cgit v1.2.3 From 77e0164630364ebd738f8cc1858f41e655acf38c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Nov 2021 10:16:19 -0600 Subject: i2c: Remove unused Netlogic/Sigma Designs XLR driver Commits 95b8a5e0111a ("MIPS: Remove NETLOGIC support") and edd4488aea9c ("ARM: remove tango platform") removed Netlogic XLR and Sigma Designs Tango platforms which means there are no platforms using the XLR I2C driver and it can be removed. Signed-off-by: Rob Herring Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-xlr.c | 470 ------------------------------------------- 3 files changed, 481 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-xlr.c (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e9dd1640ffde..2f0a440ec446 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1159,16 +1159,6 @@ config I2C_XILINX This driver can also be built as a module. If so, the module will be called xilinx_i2c. -config I2C_XLR - tristate "Netlogic XLR I2C support" - depends on CPU_XLR || COMPILE_TEST - help - This driver enables support for the on-chip I2C interface of - the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs. - - This driver can also be built as a module. If so, the module - will be called i2c-xlr. - config I2C_XLP9XX tristate "Cavium ThunderX2 I2C support" depends on ARCH_THUNDER2 || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index d85899fef8c7..1d00dce77098 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -119,7 +119,6 @@ obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o 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 diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c deleted file mode 100644 index 9ce20652d494..000000000000 --- a/drivers/i2c/busses/i2c-xlr.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2011, Netlogic Microsystems Inc. - * Copyright 2004, Matt Porter - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* XLR I2C REGISTERS */ -#define XLR_I2C_CFG 0x00 -#define XLR_I2C_CLKDIV 0x01 -#define XLR_I2C_DEVADDR 0x02 -#define XLR_I2C_ADDR 0x03 -#define XLR_I2C_DATAOUT 0x04 -#define XLR_I2C_DATAIN 0x05 -#define XLR_I2C_STATUS 0x06 -#define XLR_I2C_STARTXFR 0x07 -#define XLR_I2C_BYTECNT 0x08 -#define XLR_I2C_HDSTATIM 0x09 - -/* Sigma Designs additional registers */ -#define XLR_I2C_INT_EN 0x09 -#define XLR_I2C_INT_STAT 0x0a - -/* XLR I2C REGISTERS FLAGS */ -#define XLR_I2C_BUS_BUSY 0x01 -#define XLR_I2C_SDOEMPTY 0x02 -#define XLR_I2C_RXRDY 0x04 -#define XLR_I2C_ACK_ERR 0x08 -#define XLR_I2C_ARB_STARTERR 0x30 - -/* Register Values */ -#define XLR_I2C_CFG_ADDR 0xF8 -#define XLR_I2C_CFG_NOADDR 0xFA -#define XLR_I2C_STARTXFR_ND 0x02 /* No Data */ -#define XLR_I2C_STARTXFR_RD 0x01 /* Read */ -#define XLR_I2C_STARTXFR_WR 0x00 /* Write */ - -#define XLR_I2C_TIMEOUT 10 /* timeout per byte in msec */ - -/* - * On XLR/XLS, we need to use __raw_ IO to read the I2C registers - * because they are in the big-endian MMIO area on the SoC. - * - * The readl/writel implementation on XLR/XLS byteswaps, because - * those are for its little-endian PCI space (see arch/mips/Kconfig). - */ -static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val) -{ - __raw_writel(val, base + reg); -} - -static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg) -{ - return __raw_readl(base + reg); -} - -#define XLR_I2C_FLAG_IRQ 1 - -struct xlr_i2c_config { - u32 flags; /* optional feature support */ - u32 status_busy; /* value of STATUS[0] when busy */ - u32 cfg_extra; /* extra CFG bits to set */ -}; - -struct xlr_i2c_private { - struct i2c_adapter adap; - u32 __iomem *iobase; - int irq; - int pos; - struct i2c_msg *msg; - const struct xlr_i2c_config *cfg; - wait_queue_head_t wait; - struct clk *clk; -}; - -static int xlr_i2c_busy(struct xlr_i2c_private *priv, u32 status) -{ - return (status & XLR_I2C_BUS_BUSY) == priv->cfg->status_busy; -} - -static int xlr_i2c_idle(struct xlr_i2c_private *priv) -{ - return !xlr_i2c_busy(priv, xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS)); -} - -static int xlr_i2c_wait(struct xlr_i2c_private *priv, unsigned long timeout) -{ - int status; - int t; - - t = wait_event_timeout(priv->wait, xlr_i2c_idle(priv), - msecs_to_jiffies(timeout)); - if (!t) - return -ETIMEDOUT; - - status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - return status & XLR_I2C_ACK_ERR ? -EIO : 0; -} - -static void xlr_i2c_tx_irq(struct xlr_i2c_private *priv, u32 status) -{ - struct i2c_msg *msg = priv->msg; - - if (status & XLR_I2C_SDOEMPTY) - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, - msg->buf[priv->pos++]); -} - -static void xlr_i2c_rx_irq(struct xlr_i2c_private *priv, u32 status) -{ - struct i2c_msg *msg = priv->msg; - - if (status & XLR_I2C_RXRDY) - msg->buf[priv->pos++] = - xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); -} - -static irqreturn_t xlr_i2c_irq(int irq, void *dev_id) -{ - struct xlr_i2c_private *priv = dev_id; - struct i2c_msg *msg = priv->msg; - u32 int_stat, status; - - int_stat = xlr_i2c_rdreg(priv->iobase, XLR_I2C_INT_STAT); - if (!int_stat) - return IRQ_NONE; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, int_stat); - - if (!msg) - return IRQ_HANDLED; - - status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - if (priv->pos < msg->len) { - if (msg->flags & I2C_M_RD) - xlr_i2c_rx_irq(priv, status); - else - xlr_i2c_tx_irq(priv, status); - } - - if (!xlr_i2c_busy(priv, status)) - wake_up(&priv->wait); - - return IRQ_HANDLED; -} - -static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, - u8 *buf, u16 addr) -{ - struct i2c_adapter *adap = &priv->adap; - unsigned long timeout, stoptime, checktime; - u32 i2c_status; - int pos, timedout; - u8 offset; - u32 xfer; - - offset = buf[0]; - xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); - xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, - XLR_I2C_CFG_ADDR | priv->cfg->cfg_extra); - - timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); - stoptime = jiffies + timeout; - timedout = 0; - - if (len == 1) { - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); - xfer = XLR_I2C_STARTXFR_ND; - pos = 1; - } else { - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 2); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[1]); - xfer = XLR_I2C_STARTXFR_WR; - pos = 2; - } - - priv->pos = pos; - -retry: - /* retry can only happen on the first byte */ - xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, xfer); - - if (priv->irq > 0) - return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len); - - while (!timedout) { - checktime = jiffies; - i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - if ((i2c_status & XLR_I2C_SDOEMPTY) && pos < len) { - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos++]); - - /* reset timeout on successful xmit */ - stoptime = jiffies + timeout; - } - timedout = time_after(checktime, stoptime); - - if (i2c_status & XLR_I2C_ARB_STARTERR) { - if (timedout) - break; - goto retry; - } - - if (i2c_status & XLR_I2C_ACK_ERR) - return -EIO; - - if (!xlr_i2c_busy(priv, i2c_status) && pos >= len) - return 0; - } - dev_err(&adap->dev, "I2C transmit timeout\n"); - return -ETIMEDOUT; -} - -static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) -{ - struct i2c_adapter *adap = &priv->adap; - u32 i2c_status; - unsigned long timeout, stoptime, checktime; - int nbytes, timedout; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, - XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra); - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); - - priv->pos = 0; - - timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); - stoptime = jiffies + timeout; - timedout = 0; - nbytes = 0; -retry: - xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD); - - if (priv->irq > 0) - return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len); - - while (!timedout) { - checktime = jiffies; - i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - if (i2c_status & XLR_I2C_RXRDY) { - if (nbytes >= len) - return -EIO; /* should not happen */ - - buf[nbytes++] = - xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); - - /* reset timeout on successful read */ - stoptime = jiffies + timeout; - } - - timedout = time_after(checktime, stoptime); - if (i2c_status & XLR_I2C_ARB_STARTERR) { - if (timedout) - break; - goto retry; - } - - if (i2c_status & XLR_I2C_ACK_ERR) - return -EIO; - - if (!xlr_i2c_busy(priv, i2c_status)) - return 0; - } - - dev_err(&adap->dev, "I2C receive timeout\n"); - return -ETIMEDOUT; -} - -static int xlr_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct i2c_msg *msg; - int i; - int ret = 0; - struct xlr_i2c_private *priv = i2c_get_adapdata(adap); - - ret = clk_enable(priv->clk); - if (ret) - return ret; - - if (priv->irq) - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0xf); - - - for (i = 0; ret == 0 && i < num; i++) { - msg = &msgs[i]; - priv->msg = msg; - if (msg->flags & I2C_M_RD) - ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0], - msg->addr); - else - ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0], - msg->addr); - } - - if (priv->irq) - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0); - - clk_disable(priv->clk); - priv->msg = NULL; - - return (ret != 0) ? ret : num; -} - -static u32 xlr_func(struct i2c_adapter *adap) -{ - /* Emulate SMBUS over I2C */ - return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C; -} - -static const struct i2c_algorithm xlr_i2c_algo = { - .master_xfer = xlr_i2c_xfer, - .functionality = xlr_func, -}; - -static const struct i2c_adapter_quirks xlr_i2c_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - -static const struct xlr_i2c_config xlr_i2c_config_default = { - .status_busy = XLR_I2C_BUS_BUSY, - .cfg_extra = 0, -}; - -static const struct xlr_i2c_config xlr_i2c_config_tangox = { - .flags = XLR_I2C_FLAG_IRQ, - .status_busy = 0, - .cfg_extra = 1 << 8, -}; - -static const struct of_device_id xlr_i2c_dt_ids[] = { - { - .compatible = "sigma,smp8642-i2c", - .data = &xlr_i2c_config_tangox, - }, - { } -}; -MODULE_DEVICE_TABLE(of, xlr_i2c_dt_ids); - -static int xlr_i2c_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct xlr_i2c_private *priv; - struct clk *clk; - unsigned long clk_rate; - unsigned long clk_div; - u32 busfreq; - int irq; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - match = of_match_device(xlr_i2c_dt_ids, &pdev->dev); - if (match) - priv->cfg = match->data; - else - priv->cfg = &xlr_i2c_config_default; - - priv->iobase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->iobase)) - return PTR_ERR(priv->iobase); - - irq = platform_get_irq(pdev, 0); - - if (irq > 0 && (priv->cfg->flags & XLR_I2C_FLAG_IRQ)) { - priv->irq = irq; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0); - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, 0xf); - - ret = devm_request_irq(&pdev->dev, priv->irq, xlr_i2c_irq, - IRQF_SHARED, dev_name(&pdev->dev), - priv); - if (ret) - return ret; - - init_waitqueue_head(&priv->wait); - } - - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &busfreq)) - busfreq = I2C_MAX_STANDARD_MODE_FREQ; - - clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - ret = clk_prepare_enable(clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(clk); - clk_div = DIV_ROUND_UP(clk_rate, 2 * busfreq); - xlr_i2c_wreg(priv->iobase, XLR_I2C_CLKDIV, clk_div); - - clk_disable(clk); - priv->clk = clk; - } - - priv->adap.dev.parent = &pdev->dev; - priv->adap.dev.of_node = pdev->dev.of_node; - priv->adap.owner = THIS_MODULE; - priv->adap.algo_data = priv; - priv->adap.algo = &xlr_i2c_algo; - priv->adap.quirks = &xlr_i2c_quirks; - priv->adap.nr = pdev->id; - priv->adap.class = I2C_CLASS_HWMON; - snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); - - i2c_set_adapdata(&priv->adap, priv); - ret = i2c_add_numbered_adapter(&priv->adap); - if (ret < 0) - goto err_unprepare_clk; - - platform_set_drvdata(pdev, priv); - dev_info(&priv->adap.dev, "Added I2C Bus.\n"); - return 0; - -err_unprepare_clk: - clk_unprepare(clk); - return ret; -} - -static int xlr_i2c_remove(struct platform_device *pdev) -{ - struct xlr_i2c_private *priv; - - priv = platform_get_drvdata(pdev); - i2c_del_adapter(&priv->adap); - clk_unprepare(priv->clk); - - return 0; -} - -static struct platform_driver xlr_i2c_driver = { - .probe = xlr_i2c_probe, - .remove = xlr_i2c_remove, - .driver = { - .name = "xlr-i2cbus", - .of_match_table = xlr_i2c_dt_ids, - }, -}; - -module_platform_driver(xlr_i2c_driver); - -MODULE_AUTHOR("Ganesan Ramalingam "); -MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:xlr-i2cbus"); -- cgit v1.2.3 From f89bf95632b41695402996d96476c44c641d23d7 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 12 Nov 2021 07:39:55 -0600 Subject: i2c: imx: Add timer for handling the stop condition Most IMX I2C interfaces don't generate an interrupt on a stop condition, so it won't generate a timely stop event on a slave mode transfer. Some users, like IPMB, need a timely stop event to work properly. So, add a timer and add the proper handling to generate a stop event in slave mode if the interface goes idle. Signed-off-by: Corey Minyard Tested-by: Andrew Manley Reviewed-by: Andrew Manley Reviewed-by: Oleksij Rempel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 92 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 19 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 3576b63a6c03..27f969b3dc07 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -51,6 +53,8 @@ /* This will be the driver name the kernel reports */ #define DRIVER_NAME "imx-i2c" +#define I2C_IMX_CHECK_DELAY 30000 /* Time to check for bus idle, in NS */ + /* * Enable DMA if transfer byte size is bigger than this threshold. * As the hardware request, it must bigger than 4 bytes.\ @@ -210,6 +214,10 @@ struct imx_i2c_struct { struct imx_i2c_dma *dma; struct i2c_client *slave; enum i2c_slave_event last_slave_event; + + /* For checking slave events. */ + spinlock_t slave_lock; + struct hrtimer slave_timer; }; static const struct imx_i2c_hwdata imx1_i2c_hwdata = { @@ -680,7 +688,7 @@ static void i2c_imx_slave_event(struct imx_i2c_struct *i2c_imx, static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) { - u8 val; + u8 val = 0; while (i2c_imx->last_slave_event != I2C_SLAVE_STOP) { switch (i2c_imx->last_slave_event) { @@ -701,10 +709,11 @@ static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) } } -static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, - unsigned int status, unsigned int ctl) +/* Returns true if the timer should be restarted, false if not. */ +static irqreturn_t i2c_imx_slave_handle(struct imx_i2c_struct *i2c_imx, + unsigned int status, unsigned int ctl) { - u8 value; + u8 value = 0; if (status & I2SR_IAL) { /* Arbitration lost */ i2c_imx_clear_irq(i2c_imx, I2SR_IAL); @@ -712,6 +721,16 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, return IRQ_HANDLED; } + if (!(status & I2SR_IBB)) { + /* No master on the bus, that could mean a stop condition. */ + i2c_imx_slave_finish_op(i2c_imx); + return IRQ_HANDLED; + } + + if (!(status & I2SR_ICF)) + /* Data transfer still in progress, ignore this. */ + goto out; + 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*/ @@ -737,16 +756,9 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); } } 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_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_imx_slave_event(i2c_imx, - I2C_SLAVE_STOP, &value); - } + value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_WRITE_RECEIVED, &value); } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ ctl |= I2CR_MTX; imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); @@ -755,15 +767,43 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, I2C_SLAVE_READ_PROCESSED, &value); imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); - } else { /* Transmit mode received NAK */ + } else { /* Transmit mode received NAK, operation is done */ ctl &= ~I2CR_MTX; imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + i2c_imx_slave_finish_op(i2c_imx); + return IRQ_HANDLED; } +out: + /* + * No need to check the return value here. If it returns 0 or + * 1, then everything is fine. If it returns -1, then the + * timer is running in the handler. This will still work, + * though it may be redone (or already have been done) by the + * timer function. + */ + hrtimer_try_to_cancel(&i2c_imx->slave_timer); + hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY); + hrtimer_restart(&i2c_imx->slave_timer); return IRQ_HANDLED; } +static enum hrtimer_restart i2c_imx_slave_timeout(struct hrtimer *t) +{ + struct imx_i2c_struct *i2c_imx = container_of(t, struct imx_i2c_struct, + slave_timer); + unsigned int ctl, status; + unsigned long flags; + + spin_lock_irqsave(&i2c_imx->slave_lock, flags); + status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + i2c_imx_slave_handle(i2c_imx, status, ctl); + spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); + return HRTIMER_NORESTART; +} + static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx) { int temp; @@ -843,7 +883,9 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) { struct imx_i2c_struct *i2c_imx = dev_id; unsigned int ctl, status; + unsigned long flags; + spin_lock_irqsave(&i2c_imx->slave_lock, flags); status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); @@ -851,14 +893,20 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) i2c_imx_clear_irq(i2c_imx, I2SR_IIF); 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); + irqreturn_t ret; + + ret = i2c_imx_slave_handle(i2c_imx, + status, ctl); + spin_unlock_irqrestore(&i2c_imx->slave_lock, + flags); + return ret; } + i2c_imx_slave_finish_op(i2c_imx); } + spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); return i2c_imx_master_isr(i2c_imx, status); } + spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); return IRQ_NONE; } @@ -1378,6 +1426,10 @@ static int i2c_imx_probe(struct platform_device *pdev) if (!i2c_imx) return -ENOMEM; + spin_lock_init(&i2c_imx->slave_lock); + hrtimer_init(&i2c_imx->slave_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + i2c_imx->slave_timer.function = i2c_imx_slave_timeout; + match = device_get_match_data(&pdev->dev); if (match) i2c_imx->hwdata = match; @@ -1491,6 +1543,8 @@ static int i2c_imx_remove(struct platform_device *pdev) if (ret < 0) return ret; + hrtimer_cancel(&i2c_imx->slave_timer); + /* remove adapter */ dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); i2c_del_adapter(&i2c_imx->adapter); -- cgit v1.2.3 From 379920f5c013c49e0a740634972faf77e26d4ac3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Nov 2021 17:41:59 +0200 Subject: i2c: mux: gpio: Replace custom acpi_get_local_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recently ACPI gained the acpi_get_local_address() API which may be used instead of home grown i2c_mux_gpio_get_acpi_adr(). Signed-off-by: Andy Shevchenko Reviewed-by: Evan Green Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 43 ++-------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index bac415a52b78..31e6eb1591bb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -49,45 +49,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) return 0; } -#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) { @@ -141,9 +102,9 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, 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); + rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i); if (rc) - return rc; + return dev_err_probe(dev, rc, "Cannot get address\n"); } i++; -- cgit v1.2.3 From 533f05f0abc05250dc82416863de711ca5550bd4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Nov 2021 17:42:00 +0200 Subject: i2c: mux: gpio: Don't dereference fwnode from struct device We have a special helper to get fwnode out of struct device. Moreover, dereferencing it directly prevents the fwnode modifications in the future. Signed-off-by: Andy Shevchenko Reviewed-by: Evan Green Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 31e6eb1591bb..b09c10f36ddb 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_probe_fw(struct gpiomux *mux, struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); struct device_node *np = dev->of_node; struct device_node *adapter_np; struct i2c_adapter *adapter = NULL; @@ -60,7 +61,7 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, unsigned *values; int rc, i = 0; - if (is_of_node(dev->fwnode)) { + if (is_of_node(fwnode)) { if (!np) return -ENODEV; @@ -72,7 +73,7 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, adapter = of_find_i2c_adapter_by_node(adapter_np); of_node_put(adapter_np); - } else if (is_acpi_node(dev->fwnode)) { + } else if (is_acpi_node(fwnode)) { /* * In ACPI land the mux should be a direct child of the i2c * bus it muxes. @@ -111,7 +112,7 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, } mux->data.values = values; - if (fwnode_property_read_u32(dev->fwnode, "idle-state", &mux->data.idle)) + if (device_property_read_u32(dev, "idle-state", &mux->data.idle)) mux->data.idle = I2C_MUX_GPIO_NO_IDLE; return 0; -- cgit v1.2.3 From a2fd6f6bc07f525eb5064ac8f0c2286a1138d59c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Nov 2021 17:42:01 +0200 Subject: i2c: mux: gpio: Use array_size() helper Use array_size() helper to aid in 2-factor allocation instances. Signed-off-by: Andy Shevchenko Reviewed-by: Evan Green Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index b09c10f36ddb..73a23e117ebe 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -152,7 +153,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - ngpios * sizeof(*mux->gpios), 0, + array_size(ngpios, sizeof(*mux->gpios)), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; -- cgit v1.2.3 From bd2fdedbf2bac27f4a2ac16b84ab9b9e5f67006c Mon Sep 17 00:00:00 2001 From: Akhil R Date: Thu, 25 Nov 2021 22:23:44 +0530 Subject: i2c: tegra: Add the ACPI support Add support for the ACPI based device registration so that the driver can be also enabled through ACPI table. This does not include the ACPI support for Tegra VI and DVC I2C. Signed-off-by: Akhil R Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 52 ++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b3184c422826..56c9c02821c2 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -6,6 +6,7 @@ * Author: Colin Cross */ +#include #include #include #include @@ -608,6 +609,7 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; + acpi_handle handle = ACPI_HANDLE(i2c_dev->dev); int err; /* @@ -618,7 +620,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) * emit a noisy warning on error, which won't stay unnoticed and * won't hose machine entirely. */ - err = reset_control_reset(i2c_dev->rst); + if (handle) + err = acpi_evaluate_object(handle, "_RST", NULL, NULL); + else + err = reset_control_reset(i2c_dev->rst); + WARN_ON_ONCE(err); if (i2c_dev->is_dvc) @@ -1627,12 +1633,12 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) bool multi_mode; int err; - err = of_property_read_u32(np, "clock-frequency", - &i2c_dev->bus_clk_rate); + err = device_property_read_u32(i2c_dev->dev, "clock-frequency", + &i2c_dev->bus_clk_rate); if (err) i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; - multi_mode = of_property_read_bool(np, "multi-master"); + multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master"); i2c_dev->multimaster_mode = multi_mode; if (of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc")) @@ -1642,10 +1648,26 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) i2c_dev->is_vi = true; } +static int tegra_i2c_init_reset(struct tegra_i2c_dev *i2c_dev) +{ + if (ACPI_HANDLE(i2c_dev->dev)) + return 0; + + i2c_dev->rst = devm_reset_control_get_exclusive(i2c_dev->dev, "i2c"); + if (IS_ERR(i2c_dev->rst)) + return dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->rst), + "failed to get reset control\n"); + + return 0; +} + static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev) { int err; + if (ACPI_HANDLE(i2c_dev->dev)) + return 0; + i2c_dev->clocks[i2c_dev->nclocks++].id = "div-clk"; if (i2c_dev->hw == &tegra20_i2c_hw || i2c_dev->hw == &tegra30_i2c_hw) @@ -1720,7 +1742,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->msg_complete); init_completion(&i2c_dev->dma_complete); - i2c_dev->hw = of_device_get_match_data(&pdev->dev); + i2c_dev->hw = device_get_match_data(&pdev->dev); i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; @@ -1746,15 +1768,12 @@ static int tegra_i2c_probe(struct platform_device *pdev) if (err) return err; - i2c_dev->rst = devm_reset_control_get_exclusive(i2c_dev->dev, "i2c"); - if (IS_ERR(i2c_dev->rst)) { - dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->rst), - "failed to get reset control\n"); - return PTR_ERR(i2c_dev->rst); - } - tegra_i2c_parse_dt(i2c_dev); + err = tegra_i2c_init_reset(i2c_dev); + if (err) + return err; + err = tegra_i2c_init_clocks(i2c_dev); if (err) return err; @@ -1923,12 +1942,21 @@ static const struct dev_pm_ops tegra_i2c_pm = { NULL) }; +static const struct acpi_device_id tegra_i2c_acpi_match[] = { + {.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw}, + {.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw}, + {.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw}, + { } +}; +MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match); + static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, .driver = { .name = "tegra-i2c", .of_match_table = tegra_i2c_of_match, + .acpi_match_table = tegra_i2c_acpi_match, .pm = &tegra_i2c_pm, }, }; -- cgit v1.2.3 From effa453168a7eeb8a562ff4edc1dbf9067360a61 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 7 Nov 2021 22:57:00 +0100 Subject: i2c: i801: Don't silently correct invalid transfer size If an invalid block size is provided, reject it instead of silently changing it to a supported value. Especially critical I see the case of a write transfer with block length 0. In this case we have no guarantee that the byte we would write is valid. When silently reducing a read to 32 bytes then we don't return an error and the caller may falsely assume that we returned the full requested data. If this change should break any (broken) caller, then I think we should fix the caller. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 41446f9cc52d..c87ea470eba9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -775,6 +775,11 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data * int result = 0; unsigned char hostc; + if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { if (read_write == I2C_SMBUS_WRITE) { /* set I2C_EN bit in configuration register */ @@ -788,16 +793,6 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data * } } - if (read_write == I2C_SMBUS_WRITE - || command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (data->block[0] < 1) - data->block[0] = 1; - if (data->block[0] > I2C_SMBUS_BLOCK_MAX) - data->block[0] = I2C_SMBUS_BLOCK_MAX; - } else { - data->block[0] = 32; /* max for SMBus block reads */ - } - /* Experience has shown that the block buffer can only be used for SMBus (not I2C) block transactions, even though the datasheet doesn't mention this limitation. */ -- cgit v1.2.3 From 1e1d6582f483a4dba4ea03445e6f2f05d9de5bcf Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 18 Nov 2021 23:58:17 +0100 Subject: i2c: i801: Remove i801_set_block_buffer_mode If FEATURE_BLOCK_BUFFER is set then bit SMBAUXCTL_E32B is supported and there's no benefit in reading it back. Origin of this check seems to be 14 yrs ago when people were not completely sure which chip versions support the block buffer mode. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c87ea470eba9..8af502394f46 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -523,9 +523,11 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, return -EOPNOTSUPP; } + /* Set block buffer mode */ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); + inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ - /* Use 32-byte buffer to process this transaction */ if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; outb_p(len, SMBHSTDAT0(priv)); @@ -760,14 +762,6 @@ exit: return i801_check_post(priv, status); } -static int i801_set_block_buffer_mode(struct i801_priv *priv) -{ - outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); - if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) - return -EIO; - return 0; -} - /* Block transaction function */ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data, char read_write, int command) @@ -796,9 +790,8 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data * /* Experience has shown that the block buffer can only be used for SMBus (not I2C) block transactions, even though the datasheet doesn't mention this limitation. */ - if ((priv->features & FEATURE_BLOCK_BUFFER) - && command != I2C_SMBUS_I2C_BLOCK_DATA - && i801_set_block_buffer_mode(priv) == 0) + if ((priv->features & FEATURE_BLOCK_BUFFER) && + command != I2C_SMBUS_I2C_BLOCK_DATA) result = i801_block_transaction_by_block(priv, data, read_write, command); -- cgit v1.2.3 From 41acd4b03ca9ba9c9a3ab993817112d9b9f7cf44 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 19 Nov 2021 21:45:54 +0100 Subject: i2c: i801: Improve handling of chip-specific feature definitions Reduce source code and code size by defining the chip features statically. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 191 +++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 125 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 8af502394f46..720f7e9d0de9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -997,66 +997,72 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; +#define FEATURES_ICH5 (FEATURE_BLOCK_PROC | FEATURE_I2C_BLOCK_READ | \ + FEATURE_IRQ | FEATURE_SMBUS_PEC | \ + FEATURE_BLOCK_BUFFER | FEATURE_HOST_NOTIFY) +#define FEATURES_ICH4 (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER | \ + FEATURE_HOST_NOTIFY) + static const struct pci_device_id i801_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, - { 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) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS) }, + { PCI_DEVICE_DATA(INTEL, 82801AA_3, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801AB_3, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801BA_2, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801CA_3, FEATURE_HOST_NOTIFY) }, + { PCI_DEVICE_DATA(INTEL, 82801DB_3, FEATURES_ICH4) }, + { PCI_DEVICE_DATA(INTEL, 82801EB_3, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ESB_4, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH6_16, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH7_17, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ESB2_17, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH8_5, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH9_6, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, EP80579_1, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH10_4, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH10_5, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, 5_3400_SERIES_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, COUGARPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF0, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF1, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF2, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, DH89XXCC_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PANTHERPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LYNXPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LYNXPOINT_LP_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, AVOTON_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS0, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS1, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS2, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, COLETOCREEK_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, GEMINILAKE_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_LP_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, BAYTRAIL_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, BRASWELL_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, CDF_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, DNV_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, EBG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, BROXTON_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LEWISBURG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, LEWISBURG_SSKU_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, KABYLAKE_PCH_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, CANNONLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, CANNONLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ICELAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ICELAKE_N_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_V_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, ELKHART_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, TIGERLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, TIGERLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, JASPER_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { 0, } }; @@ -1685,72 +1691,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) mutex_init(&priv->acpi_lock); priv->pci_dev = dev; - switch (dev->device) { - case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: - case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: - case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: - case PCI_DEVICE_ID_INTEL_DNV_SMBUS: - case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - priv->features |= FEATURE_TCO_SPT; - priv->features |= FEATURE_HOST_NOTIFY; - break; - - case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: - case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_CDF_SMBUS: - case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: - case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: - case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: - 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: - case PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - priv->features |= FEATURE_TCO_CNL; - priv->features |= FEATURE_HOST_NOTIFY; - break; - - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: - priv->features |= FEATURE_IDF; - fallthrough; - default: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801DB_3: - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801CA_3: - priv->features |= FEATURE_HOST_NOTIFY; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801BA_2: - case PCI_DEVICE_ID_INTEL_82801AB_3: - case PCI_DEVICE_ID_INTEL_82801AA_3: - break; - } + priv->features = id->driver_data; /* Disable features on user request */ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { -- cgit v1.2.3 From b57e90189f208e8e873f532b797f8b649973f7a2 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Mon, 4 Oct 2021 14:15:39 +0100 Subject: i2c: rk3x: enable clock before getting rate clk_get_rate() is documented as requiring the clock to be enabled. Ensure that the bus clock is enabled before calling clk_get_rate() in rk3x_i2c_probe() to satisfy this requirement. Signed-off-by: John Keeping Reviewed-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 819ab4ee517e..332755fab2a1 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1338,8 +1338,15 @@ static int rk3x_i2c_probe(struct platform_device *pdev) goto err_pclk; } + ret = clk_enable(i2c->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret); + goto err_clk_notifier; + } + clk_rate = clk_get_rate(i2c->clk); rk3x_i2c_adapt_div(i2c, clk_rate); + clk_disable(i2c->clk); ret = i2c_add_adapter(&i2c->adap); if (ret < 0) -- cgit v1.2.3 From 1ead7e992abee922b7e6ff1238dc47c06605c5bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Nov 2021 14:34:59 +0200 Subject: i2c: designware: Fix the kernel doc description for struct dw_i2c_dev $ scripts/kernel-doc -none drivers/i2c/busses/i2c-designware-core.h warning: Function parameter or member 'rst' not described in 'dw_i2c_dev' warning: Function parameter or member 'get_clk_rate_khz' not described in 'dw_i2c_dev' warning: Function parameter or member 'flags' not described in 'dw_i2c_dev' warning: Function parameter or member 'functionality' not described in 'dw_i2c_dev' warning: Function parameter or member 'master_cfg' not described in 'dw_i2c_dev' warning: Function parameter or member 'set_sda_hold_time' not described in 'dw_i2c_dev' warning: Function parameter or member 'rinfo' not described in 'dw_i2c_dev' Signed-off-by: Andy Shevchenko Acked-by: Jarkko Nikula Acked-by: Randy Dunlap Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 60a2e750cee9..4b26cba40139 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -191,23 +191,26 @@ struct reset_control; * @cmd_complete: tx completion indicator * @clk: input reference clock * @pclk: clock required to access the registers + * @rst: optional reset for the controller * @slave: represent an I2C slave device + * @get_clk_rate_khz: callback to retrieve IP specific bus speed * @cmd_err: run time hadware error code * @msgs: points to an array of messages currently being transferred * @msgs_num: the number of elements in msgs - * @msg_write_idx: the element index of the current tx message in the msgs - * array + * @msg_write_idx: the element index of the current tx message in the msgs array * @tx_buf_len: the length of the current tx buffer * @tx_buf: the current tx buffer - * @msg_read_idx: the element index of the current rx message in the msgs - * array + * @msg_read_idx: the element index of the current rx message in the msgs array * @rx_buf_len: the length of the current rx buffer * @rx_buf: the current rx buffer * @msg_err: error status of the current transfer * @status: i2c master status, one of STATUS_* * @abort_source: copy of the TX_ABRT_SOURCE register * @irq: interrupt number for the i2c master + * @flags: platform specific flags like type of IO accessors or model * @adapter: i2c subsystem adapter node + * @functionality: I2C_FUNC_* ORed bits to reflect what controller does support + * @master_cfg: configuration for the master device * @slave_cfg: configuration for the slave device * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo @@ -228,7 +231,9 @@ struct reset_control; * @disable: function to disable the controller * @disable_int: function to disable all interrupts * @init: function to initialize the I2C hardware + * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE + * @rinfo: I²C GPIO recovery information * @suspended: set to true if the controller is suspended * * HCNT and LCNT parameters can be used if the platform knows more accurate -- cgit v1.2.3 From ebe82cf92cd4825c3029434cabfcd2f1780e64be Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 11 May 2017 14:20:33 +0200 Subject: i2c: mpc: Correct I2C reset procedure Current I2C reset procedure is broken in two ways: 1) It only generate 1 START instead of 9 STARTs and STOP. 2) It leaves the bus Busy so every I2C xfer after the first fixup calls the reset routine again, for every xfer there after. This fixes both errors. Signed-off-by: Joakim Tjernlund Acked-by: Scott Wood Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mpc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index a6ea1eb1394e..f7f26f1f8da5 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -119,23 +119,30 @@ static inline void writeccr(struct mpc_i2c *i2c, u32 x) /* Sometimes 9th clock pulse isn't generated, and slave doesn't release * the bus, because it wants to send ACK. * Following sequence of enabling/disabling and sending start/stop generates - * the 9 pulses, so it's all OK. + * the 9 pulses, each with a START then ending with STOP, so it's all OK. */ static void mpc_i2c_fixup(struct mpc_i2c *i2c) { int k; - u32 delay_val = 1000000 / i2c->real_clk + 1; - - if (delay_val < 2) - delay_val = 2; + unsigned long flags; for (k = 9; k; k--) { writeccr(i2c, 0); - writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); + writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */ + writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */ + readb(i2c->base + MPC_I2C_DR); /* init xfer */ + udelay(15); /* let it hit the bus */ + local_irq_save(flags); /* should not be delayed further */ + writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */ readb(i2c->base + MPC_I2C_DR); - writeccr(i2c, CCR_MEN); - udelay(delay_val << 1); + if (k != 1) + udelay(5); + local_irq_restore(flags); } + writeccr(i2c, CCR_MEN); /* Initiate STOP */ + readb(i2c->base + MPC_I2C_DR); + udelay(15); /* Let STOP propagate */ + writeccr(i2c, 0); } static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask) -- cgit v1.2.3 From 7c5b3c158b38dcf0c3c62657d9aa39decaf59cdc Mon Sep 17 00:00:00 2001 From: Rajat Jain Date: Mon, 25 Oct 2021 14:35:29 -0700 Subject: i2c: designware: Enable async suspend / resume of designware devices Mark the designware devices for asynchronous suspend. With this, the resume for designware devices does not get stuck behind other unrelated devices (e.g. intel_backlight that takes hundreds of ms to resume, waiting for its parent devices). Signed-off-by: Rajat Jain Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 21113665ddea..2bd81abc86f6 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -293,6 +293,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) DPM_FLAG_MAY_SKIP_RESUME); } + device_enable_async_suspend(&pdev->dev); + /* The code below assumes runtime PM to be disabled. */ WARN_ON(pm_runtime_enabled(&pdev->dev)); -- cgit v1.2.3 From d320ec7acc83a66cb1367f6cdee53177f07a9f5d Mon Sep 17 00:00:00 2001 From: Rajat Jain Date: Mon, 25 Oct 2021 14:35:30 -0700 Subject: i2c: enable async suspend/resume for i2c adapters Enable async suspend/resume of i2c adapters. It enormously helps with reducing the resume time of systems (as much as 20%-40%) where I2C devices can take significant time (100s of ms) to resume. Signed-off-by: Rajat Jain Tested-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index f193f9058584..457504a0e567 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1577,6 +1577,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (res) goto out_reg; + device_enable_async_suspend(&adap->dev); pm_runtime_no_callbacks(&adap->dev); pm_suspend_ignore_children(&adap->dev, true); pm_runtime_enable(&adap->dev); -- cgit v1.2.3 From 172d931910e1db800f4e71e8ed92281b6f8c6ee2 Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Mon, 25 Oct 2021 14:35:31 -0700 Subject: i2c: enable async suspend/resume on i2c client devices This enables the async suspend for i2c client devices. This reduces the suspend/resume time considerably on platforms where i2c devices can take a lot of time (hundreds of ms) to resume. Signed-off-by: Derek Basehore Signed-off-by: Rajat Jain Tested-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 457504a0e567..1072a47ce775 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1048,6 +1048,7 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf client->dev.of_node = of_node_get(info->of_node); client->dev.fwnode = info->fwnode; + device_enable_async_suspend(&client->dev); i2c_dev_set_name(adap, client, info); if (info->swnode) { -- cgit v1.2.3 From e8578547ce59ddba3651ac0e68dbcb6daa8ce790 Mon Sep 17 00:00:00 2001 From: Lakshmi Sowjanya D Date: Tue, 9 Nov 2021 16:05:51 +0530 Subject: i2c: designware-pci: Add support for Fast Mode Plus and High Speed Mode Add support to configure HCNT, LCNT values for Fast Mode Plus and High Speed Mode. Signed-off-by: Lakshmi Sowjanya D Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 0f409a4c2da0..174938fc7a7e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -41,8 +41,12 @@ enum dw_pci_ctl_id_t { struct dw_scl_sda_cfg { u32 ss_hcnt; u32 fs_hcnt; + u32 fp_hcnt; + u32 hs_hcnt; u32 ss_lcnt; u32 fs_lcnt; + u32 fp_lcnt; + u32 hs_lcnt; u32 sda_hold; }; @@ -306,8 +310,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, cfg = controller->scl_sda_cfg; dev->ss_hcnt = cfg->ss_hcnt; dev->fs_hcnt = cfg->fs_hcnt; + dev->fp_hcnt = cfg->fp_hcnt; + dev->hs_hcnt = cfg->hs_hcnt; dev->ss_lcnt = cfg->ss_lcnt; dev->fs_lcnt = cfg->fs_lcnt; + dev->fp_lcnt = cfg->fp_lcnt; + dev->hs_lcnt = cfg->hs_lcnt; dev->sda_hold_time = cfg->sda_hold; } -- cgit v1.2.3 From 36af188f795bd1b0d794dd735623979dc6b698d3 Mon Sep 17 00:00:00 2001 From: Lakshmi Sowjanya D Date: Tue, 9 Nov 2021 16:05:52 +0530 Subject: i2c: designware-pci: Set ideal timing parameters for Elkhart Lake PSE Set optimal HCNT, LCNT and hold time values for all the speeds supported in Intel Programmable Service Engine I2C controller in Intel Elkhart Lake. Signed-off-by: Lakshmi Sowjanya D Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 174938fc7a7e..3418148f8bb5 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -84,6 +84,19 @@ static struct dw_scl_sda_cfg hsw_config = { .sda_hold = 0x9, }; +/* Elkhart Lake HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg ehl_config = { + .ss_hcnt = 0x190, + .fs_hcnt = 0x4E, + .fp_hcnt = 0x1A, + .hs_hcnt = 0x1F, + .ss_lcnt = 0x1d6, + .fs_lcnt = 0x96, + .fp_lcnt = 0x32, + .hs_lcnt = 0x36, + .sda_hold = 0x1E, +}; + /* NAVI-AMD HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg navi_amd_config = { .ss_hcnt = 0x1ae, @@ -200,6 +213,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, [elkhartlake] = { .bus_num = -1, + .scl_sda_cfg = &ehl_config, .get_clk_rate_khz = ehl_get_clk_rate_khz, }, [navi_amd] = { -- cgit v1.2.3 From 2352b05fdf1a225d103044cceb9a7456624ea0ae Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 29 Nov 2021 20:53:14 +0100 Subject: i2c: i801: Improve handling platform data for tco device The platform data structures are used in the respective i801_add_tco functions only. Therefore we can make the definitions local to these functions. Reviewed-by: Jean Delvare Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 720f7e9d0de9..930c6edbe4c6 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1487,15 +1487,14 @@ static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) } #endif -static const struct itco_wdt_platform_data spt_tco_platform_data = { - .name = "Intel PCH", - .version = 4, -}; - static struct platform_device * i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, struct resource *tco_res) { + static const struct itco_wdt_platform_data pldata = { + .name = "Intel PCH", + .version = 4, + }; struct resource *res; unsigned int devfn; u64 base64_addr; @@ -1538,22 +1537,20 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, res->flags = IORESOURCE_MEM; return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, - tco_res, 2, &spt_tco_platform_data, - sizeof(spt_tco_platform_data)); + tco_res, 2, &pldata, sizeof(pldata)); } -static const struct itco_wdt_platform_data cnl_tco_platform_data = { - .name = "Intel PCH", - .version = 6, -}; - static struct platform_device * i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, struct resource *tco_res) { - return platform_device_register_resndata(&pci_dev->dev, - "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, - sizeof(cnl_tco_platform_data)); + static const struct itco_wdt_platform_data pldata = { + .name = "Intel PCH", + .version = 6, + }; + + return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, + tco_res, 1, &pldata, sizeof(pldata)); } static void i801_add_tco(struct i801_priv *priv) -- cgit v1.2.3 From 606974c7aceb24d25870b0d58bad1adbba2f3158 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Nov 2021 22:32:01 +0100 Subject: Revert "i2c: designware-pci: Set ideal timing parameters for Elkhart Lake PSE" This reverts commit 36af188f795bd1b0d794dd735623979dc6b698d3. Drivers should read these values from ACPI tables. Reported-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 3418148f8bb5..174938fc7a7e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -84,19 +84,6 @@ static struct dw_scl_sda_cfg hsw_config = { .sda_hold = 0x9, }; -/* Elkhart Lake HCNT/LCNT/SDA hold time */ -static struct dw_scl_sda_cfg ehl_config = { - .ss_hcnt = 0x190, - .fs_hcnt = 0x4E, - .fp_hcnt = 0x1A, - .hs_hcnt = 0x1F, - .ss_lcnt = 0x1d6, - .fs_lcnt = 0x96, - .fp_lcnt = 0x32, - .hs_lcnt = 0x36, - .sda_hold = 0x1E, -}; - /* NAVI-AMD HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg navi_amd_config = { .ss_hcnt = 0x1ae, @@ -213,7 +200,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, [elkhartlake] = { .bus_num = -1, - .scl_sda_cfg = &ehl_config, .get_clk_rate_khz = ehl_get_clk_rate_khz, }, [navi_amd] = { -- cgit v1.2.3 From 1071d1ad31503cd45fabcdb5bfa778508f68f3a0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Nov 2021 22:32:47 +0100 Subject: Revert "i2c: designware-pci: Add support for Fast Mode Plus and High Speed Mode" This reverts commit e8578547ce59ddba3651ac0e68dbcb6daa8ce790. Drivers should read these values from ACPI tables. Reported-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 174938fc7a7e..0f409a4c2da0 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -41,12 +41,8 @@ enum dw_pci_ctl_id_t { struct dw_scl_sda_cfg { u32 ss_hcnt; u32 fs_hcnt; - u32 fp_hcnt; - u32 hs_hcnt; u32 ss_lcnt; u32 fs_lcnt; - u32 fp_lcnt; - u32 hs_lcnt; u32 sda_hold; }; @@ -310,12 +306,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, cfg = controller->scl_sda_cfg; dev->ss_hcnt = cfg->ss_hcnt; dev->fs_hcnt = cfg->fs_hcnt; - dev->fp_hcnt = cfg->fp_hcnt; - dev->hs_hcnt = cfg->hs_hcnt; dev->ss_lcnt = cfg->ss_lcnt; dev->fs_lcnt = cfg->fs_lcnt; - dev->fp_lcnt = cfg->fp_lcnt; - dev->hs_lcnt = cfg->hs_lcnt; dev->sda_hold_time = cfg->sda_hold; } -- cgit v1.2.3 From 05907656b94f6c1b96cbcc3063a683f4c580b63a Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 1 Dec 2021 12:47:50 +0100 Subject: i2c: stm32: get rid of stm32f7_i2c_release_bus return value Function stm32f7_i2c_release_bus is always returning 0, hence it should be a void function. Update the function and remove the return value error checking code in caller functions. Signed-off-by: Alain Volmat Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index b9b19a2a2ffa..9b713c50abb8 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -828,7 +828,7 @@ static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); } -static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) +static void stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); @@ -838,8 +838,6 @@ static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) STM32F7_I2C_CR1_PE); stm32f7_i2c_hw_config(i2c_dev); - - return 0; } static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) @@ -856,11 +854,7 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) dev_info(i2c_dev->dev, "bus busy\n"); - ret = stm32f7_i2c_release_bus(&i2c_dev->adap); - if (ret) { - dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); - return ret; - } + stm32f7_i2c_release_bus(&i2c_dev->adap); return -EBUSY; } -- cgit v1.2.3 From 15f0ae7a91a9ca8fb34ecc6e0c7d8bd3a3ce180c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 1 Dec 2021 12:47:51 +0100 Subject: i2c: stm32f7: remove noisy and imprecise log messages The log messages talk about 'bus recovery' while it is not a bus recovery with 9 pulses but merely a controller reset. Controller resets are not worth log messages. The 'bus busy' message should be emitted by upper layers, a busy bus may be expected in some cases. Signed-off-by: Wolfram Sang Reviewed-by: Alain Volmat --- drivers/i2c/busses/i2c-stm32f7.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 9b713c50abb8..62623da18126 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -832,8 +832,6 @@ static void stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); - dev_info(i2c_dev->dev, "Trying to recover bus\n"); - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_PE); @@ -852,8 +850,6 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) if (!ret) return 0; - dev_info(i2c_dev->dev, "bus busy\n"); - stm32f7_i2c_release_bus(&i2c_dev->adap); return -EBUSY; -- cgit v1.2.3 From 3f68910259524ce84eaee05075141cdaa45e9195 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Sat, 4 Dec 2021 23:58:16 +0200 Subject: i2c: exynos5: Add support for ExynosAutoV9 SoC ExynosAutoV9 functioning logic mostly follows I2C_TYPE_EXYNOS7, but timing calculation and configuration procedure is changed: e.g. only timing_s3 has to be set now. Another change of HSI2C controller in ExynosAutoV9 SoC is that it's now a part of USIv2 IP-core. No changes is needed for I2C driver though, as all USI related configuration is done in USI driver. Signed-off-by: Jaewon Kim Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 62 ++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 97d4f3ac0abd..c7e3cae99d13 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -169,6 +169,7 @@ enum i2c_type_exynos { I2C_TYPE_EXYNOS5, I2C_TYPE_EXYNOS7, + I2C_TYPE_EXYNOSAUTOV9, }; struct exynos5_i2c { @@ -230,6 +231,11 @@ static const struct exynos_hsi2c_variant exynos7_hsi2c_data = { .hw = I2C_TYPE_EXYNOS7, }; +static const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = { + .fifo_depth = 64, + .hw = I2C_TYPE_EXYNOSAUTOV9, +}; + static const struct of_device_id exynos5_i2c_match[] = { { .compatible = "samsung,exynos5-hsi2c", @@ -243,6 +249,9 @@ static const struct of_device_id exynos5_i2c_match[] = { }, { .compatible = "samsung,exynos7-hsi2c", .data = &exynos7_hsi2c_data + }, { + .compatible = "samsung,exynosautov9-hsi2c", + .data = &exynosautov9_hsi2c_data }, {}, }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); @@ -281,6 +290,31 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) i2c->op_clock; int div, clk_cycle, temp; + /* + * In case of HSI2C controllers in ExynosAutoV9: + * + * FSCL = IPCLK / ((CLK_DIV + 1) * 16) + * T_SCL_LOW = IPCLK * (CLK_DIV + 1) * (N + M) + * [N : number of 0's in the TSCL_H_HS] + * [M : number of 0's in the TSCL_L_HS] + * T_SCL_HIGH = IPCLK * (CLK_DIV + 1) * (N + M) + * [N : number of 1's in the TSCL_H_HS] + * [M : number of 1's in the TSCL_L_HS] + * + * Result of (N + M) is always 8. + * In general case, we don't need to control timing_s1 and timing_s2. + */ + if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) { + div = ((clkin / (16 * i2c->op_clock)) - 1); + i2c_timing_s3 = div << 16; + if (hs_timings) + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); + else + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); + + return 0; + } + /* * In case of HSI2C controller in Exynos5 series * FPCLK / FI2C = @@ -422,7 +456,10 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) writel(int_status, i2c->regs + HSI2C_INT_STATUS); /* handle interrupt related to the transfer status */ - if (i2c->variant->hw == I2C_TYPE_EXYNOS7) { + switch (i2c->variant->hw) { + case I2C_TYPE_EXYNOSAUTOV9: + fallthrough; + case I2C_TYPE_EXYNOS7: if (int_status & HSI2C_INT_TRANS_DONE) { i2c->trans_done = 1; i2c->state = 0; @@ -443,7 +480,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->state = -ETIMEDOUT; goto stop; } - } else if (int_status & HSI2C_INT_I2C) { + + break; + case I2C_TYPE_EXYNOS5: + if (!(int_status & HSI2C_INT_I2C)) + break; + trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (trans_status & HSI2C_NO_DEV_ACK) { dev_dbg(i2c->dev, "No ACK from device\n"); @@ -465,6 +507,8 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->trans_done = 1; i2c->state = 0; } + + break; } if ((i2c->msg->flags & I2C_M_RD) && (int_status & @@ -569,13 +613,13 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) { unsigned long timeout; - if (i2c->variant->hw != I2C_TYPE_EXYNOS7) + if (i2c->variant->hw == I2C_TYPE_EXYNOS5) return; /* - * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction - * indicates that bus is stuck (SDA is low). In such case bus recovery - * can be performed. + * HSI2C_MASTER_ST_LOSE state (in Exynos7 and ExynosAutoV9 variants) + * before transaction indicates that bus is stuck (SDA is low). + * In such case bus recovery can be performed. */ timeout = jiffies + msecs_to_jiffies(100); for (;;) { @@ -611,10 +655,10 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) unsigned long flags; unsigned short trig_lvl; - if (i2c->variant->hw == I2C_TYPE_EXYNOS7) - int_en |= HSI2C_INT_I2C_TRANS; - else + if (i2c->variant->hw == I2C_TYPE_EXYNOS5) int_en |= HSI2C_INT_I2C; + else + int_en |= HSI2C_INT_I2C_TRANS; i2c_ctl = readl(i2c->regs + HSI2C_CTL); i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); -- cgit v1.2.3 From 697ad2490c96981ec12b0a6d3c7c26fbad80e1e8 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 9 Dec 2021 16:03:13 +0200 Subject: i2c: exynos5: Add bus clock support In new Exynos SoCs (like Exynos850) where HSI2C is implemented as a part of USIv2 block, there are two clocks provided to HSI2C controller: - PCLK: bus clock (APB), provides access to register interface - IPCLK: operating IP-core clock; SCL is derived from this one Both clocks have to be asserted for HSI2C to be functional in that case. Add code to obtain and enable/disable PCLK in addition to already handled operating clock. Make it optional though, as older Exynos SoC variants only have one HSI2C clock. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanho Park Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 46 +++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index c7e3cae99d13..693903e80892 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -182,7 +182,8 @@ struct exynos5_i2c { unsigned int irq; void __iomem *regs; - struct clk *clk; + struct clk *clk; /* operating clock */ + struct clk *pclk; /* bus clock */ struct device *dev; int state; @@ -757,10 +758,14 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct exynos5_i2c *i2c = adap->algo_data; int i, ret; - ret = clk_enable(i2c->clk); + ret = clk_enable(i2c->pclk); if (ret) return ret; + ret = clk_enable(i2c->clk); + if (ret) + goto err_pclk; + for (i = 0; i < num; ++i) { ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); if (ret) @@ -768,6 +773,8 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, } clk_disable(i2c->clk); +err_pclk: + clk_disable(i2c->pclk); return ret ?: num; } @@ -807,10 +814,18 @@ static int exynos5_i2c_probe(struct platform_device *pdev) return -ENOENT; } - ret = clk_prepare_enable(i2c->clk); + i2c->pclk = devm_clk_get(&pdev->dev, "hsi2c_pclk"); + if (IS_ERR(i2c->pclk)) + i2c->pclk = NULL; /* pclk is optional */ + + ret = clk_prepare_enable(i2c->pclk); if (ret) return ret; + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto err_pclk; + i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) { ret = PTR_ERR(i2c->regs); @@ -853,11 +868,15 @@ static int exynos5_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); clk_disable(i2c->clk); + clk_disable(i2c->pclk); return 0; err_clk: clk_disable_unprepare(i2c->clk); + + err_pclk: + clk_disable_unprepare(i2c->pclk); return ret; } @@ -868,6 +887,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); clk_unprepare(i2c->clk); + clk_unprepare(i2c->pclk); return 0; } @@ -879,6 +899,7 @@ static int exynos5_i2c_suspend_noirq(struct device *dev) i2c_mark_adapter_suspended(&i2c->adap); clk_unprepare(i2c->clk); + clk_unprepare(i2c->pclk); return 0; } @@ -888,21 +909,30 @@ static int exynos5_i2c_resume_noirq(struct device *dev) struct exynos5_i2c *i2c = dev_get_drvdata(dev); int ret = 0; - ret = clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->pclk); if (ret) return ret; + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto err_pclk; + ret = exynos5_hsi2c_clock_setup(i2c); - if (ret) { - clk_disable_unprepare(i2c->clk); - return ret; - } + if (ret) + goto err_clk; exynos5_i2c_init(i2c); clk_disable(i2c->clk); + clk_disable(i2c->pclk); i2c_mark_adapter_resumed(&i2c->adap); return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); +err_pclk: + clk_disable_unprepare(i2c->pclk); + return ret; } #endif -- cgit v1.2.3 From c4bcef90cc490685df116aede776e54ca567cef0 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 4 Dec 2021 23:58:18 +0200 Subject: i2c: exynos5: Mention Exynos850 and ExynosAutoV9 in Kconfig I2C controller chosen by I2C_EXYNOS5 config option is also suitable for Exynos850 and ExynosAutoV9 SoCs. State that specifically in I2C_EXYNOS5 symbol help section. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanho Park Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2f0a440ec446..c3ac78a112ec 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -617,7 +617,7 @@ config I2C_EXYNOS5 help High-speed I2C controller on Samsung Exynos5 and newer Samsung SoCs: Exynos5250, Exynos5260, Exynos5410, Exynos542x, Exynos5800, - Exynos5433 and Exynos7. + Exynos5433, Exynos7, Exynos850 and ExynosAutoV9. Choose Y here only if you build for such Samsung SoC. config I2C_GPIO -- cgit v1.2.3 From 8c7a89678f3befa42a05da67724bf501e3187023 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 2 Dec 2021 10:53:05 +0100 Subject: i2c: i801: Don't read back cleared status in i801_check_pre() I see no need to read back the registers to verify that the bits have actually been cleared. I can't imagine any scenario where the bits would remain set after a write to them. Whilst at it, change involved syslog messages to use pci_dbg() et al. to simplify them. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 930c6edbe4c6..b452f36c9c73 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -328,22 +328,14 @@ static int i801_check_pre(struct i801_priv *priv) status = inb_p(SMBHSTSTS(priv)); if (status & SMBHSTSTS_HOST_BUSY) { - dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); + pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n"); return -EBUSY; } status &= STATUS_FLAGS; if (status) { - dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", - status); + pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status); outb_p(status, SMBHSTSTS(priv)); - status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; - if (status) { - dev_err(&priv->pci_dev->dev, - "Failed clearing status flags (%02x)\n", - status); - return -EBUSY; - } } /* @@ -356,16 +348,8 @@ static int i801_check_pre(struct i801_priv *priv) if (priv->features & FEATURE_SMBUS_PEC) { status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; if (status) { - dev_dbg(&priv->pci_dev->dev, - "Clearing aux status flags (%02x)\n", status); + pci_dbg(priv->pci_dev, "Clearing aux status flags (%02x)\n", status); outb_p(status, SMBAUXSTS(priv)); - status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; - if (status) { - dev_err(&priv->pci_dev->dev, - "Failed clearing aux status flags (%02x)\n", - status); - return -EBUSY; - } } } -- cgit v1.2.3 From 4f7275fc7e570dfc46f733ff8ae131cb128a4758 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 4 Dec 2021 21:04:40 +0100 Subject: i2c: i801: Don't clear status flags twice in interrupt mode In interrupt mode we clear the status flags twice, in the interrupt handler and in i801_check_post(). Remove clearing the status flags from i801_check_post() and handle polling mode by using the SMBus unlocking write to also clear the status flags if still set. To be precise: One could still argue that the status flags are cleared twice in interrupt mode, but it comes for free. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index b452f36c9c73..7428cc6af5cc 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -356,11 +356,6 @@ static int i801_check_pre(struct i801_priv *priv) return 0; } -/* - * Convert the status register to an error code, and clear it. - * Note that status only contains the bits we want to clear, not the - * actual register value. - */ static int i801_check_post(struct i801_priv *priv, int status) { int result = 0; @@ -385,7 +380,6 @@ static int i801_check_post(struct i801_priv *priv, int status) !(status & SMBHSTSTS_FAILED)) dev_err(&priv->pci_dev->dev, "Failed terminating the transaction\n"); - outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); return -ETIMEDOUT; } @@ -424,9 +418,6 @@ static int i801_check_post(struct i801_priv *priv, int status) dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); } - /* Clear status flags except BYTE_DONE, to be cleared by caller */ - outb_p(status, SMBHSTSTS(priv)); - return result; } @@ -923,8 +914,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, } out: - /* Unlock the SMBus device for use by BIOS/ACPI */ - outb_p(SMBHSTSTS_INUSE_STS, SMBHSTSTS(priv)); + /* + * Unlock the SMBus device for use by BIOS/ACPI, + * and clear status flags if not done already. + */ + outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv)); pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); -- cgit v1.2.3 From 50665d58db052b04f640fd54de1632aeecd4fc77 Mon Sep 17 00:00:00 2001 From: Akhil R Date: Fri, 10 Dec 2021 17:45:57 +0530 Subject: i2c: tegra: use i2c_timings for bus clock freq Use i2c_timings struct and corresponding methods to get bus clock frequency Signed-off-by: Akhil R Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 56c9c02821c2..03cea102ab76 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -246,7 +246,7 @@ struct tegra_i2c_hw_feature { * @msg_buf: pointer to current message data * @msg_buf_remaining: size of unsent data in the message buffer * @msg_read: indicates that the transfer is a read access - * @bus_clk_rate: current I2C bus clock rate + * @timings: i2c timings information like bus frequency * @multimaster_mode: indicates that I2C controller is in multi-master mode * @tx_dma_chan: DMA transmit channel * @rx_dma_chan: DMA receive channel @@ -273,7 +273,7 @@ struct tegra_i2c_dev { unsigned int nclocks; struct clk *div_clk; - u32 bus_clk_rate; + struct i2c_timings timings; struct completion msg_complete; size_t msg_buf_remaining; @@ -610,6 +610,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; acpi_handle handle = ACPI_HANDLE(i2c_dev->dev); + struct i2c_timings *t = &i2c_dev->timings; int err; /* @@ -642,14 +643,14 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (i2c_dev->is_vi) tegra_i2c_vi_init(i2c_dev); - switch (i2c_dev->bus_clk_rate) { + switch (t->bus_freq_hz) { case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ: default: tlow = i2c_dev->hw->tlow_fast_fastplus_mode; thigh = i2c_dev->hw->thigh_fast_fastplus_mode; tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode; - if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) + if (t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode; else non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode; @@ -685,7 +686,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1); err = clk_set_rate(i2c_dev->div_clk, - i2c_dev->bus_clk_rate * clk_multiplier); + t->bus_freq_hz * clk_multiplier); if (err) { dev_err(i2c_dev->dev, "failed to set div-clk rate: %d\n", err); return err; @@ -724,7 +725,7 @@ static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev) * before disabling the controller so that the STOP condition has * been delivered properly. */ - udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate)); + udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->timings.bus_freq_hz)); cnfg = i2c_readl(i2c_dev, I2C_CNFG); if (cnfg & I2C_CNFG_PACKET_MODE_EN) @@ -1254,7 +1255,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits */ xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC, - i2c_dev->bus_clk_rate); + i2c_dev->timings.bus_freq_hz); int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; tegra_i2c_unmask_irq(i2c_dev, int_mask); @@ -1631,12 +1632,8 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) { struct device_node *np = i2c_dev->dev->of_node; bool multi_mode; - int err; - err = device_property_read_u32(i2c_dev->dev, "clock-frequency", - &i2c_dev->bus_clk_rate); - if (err) - i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; + i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true); multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master"); i2c_dev->multimaster_mode = multi_mode; -- cgit v1.2.3 From f4e0ba52a89fc2f1b009b3f6af8e617ad1a3c315 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Wed, 15 Dec 2021 17:12:00 +0200 Subject: i2c: designware: Do not complete i2c read without RX_FULL interrupt Intel Keem Bay platform supports multi-master operations over same i2c bus using Synopsys i2c DesignWare IP. When multi-masters initiate i2c operation simultaneously in a loop, SCL line is stucked low forever after few i2c operations. Following interrupt sequences are observed in: working case: TX_EMPTY, RX_FULL and STOP_DET non working case: TX_EMPTY, STOP_DET, RX_FULL. DW_apb_i2c stretches the SCL line when the TX FIFO is empty or when RX FIFO is full. The DW_apb_i2c master will continue to hold the SCL line LOW until RX FIFO is read. Linux kernel i2c DesignWare driver does not handle above non working sequence. TX_EMPTY, RX_FULL and STOP_DET routine execution are required in sequence although RX_FULL interrupt is raised after STOP_DET by hardware. Clear STOP_DET for the following conditions: (STOP_DET ,RX_FULL, rx_outstanding) Write Operation: (1, 0, 0) Read Operation: RX_FULL followed by STOP_DET: (0, 1, 1) -> (1, 0, 0) STOP_DET followed by RX_FULL: (1, 0, 1) -> (1, 1, 0) RX_FULL and STOP_DET together: (1, 1, 1) Signed-off-by: Tamal Saha Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-master.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 9b08bb5df38d..9177463c2cbb 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -701,7 +701,8 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy); if (stat & DW_IC_INTR_ACTIVITY) regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy); - if (stat & DW_IC_INTR_STOP_DET) + if ((stat & DW_IC_INTR_STOP_DET) && + ((dev->rx_outstanding == 0) || (stat & DW_IC_INTR_RX_FULL))) regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy); if (stat & DW_IC_INTR_START_DET) regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy); @@ -723,6 +724,7 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status = STATUS_IDLE; + dev->rx_outstanding = 0; /* * Anytime TX_ABRT is set, the contents of the tx/rx @@ -745,7 +747,8 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) */ tx_aborted: - if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) + if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) && + (dev->rx_outstanding == 0)) complete(&dev->cmd_complete); else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { /* Workaround to trigger pending interrupt */ -- cgit v1.2.3 From d52097010078c1844348dc0e467305e5f90fd317 Mon Sep 17 00:00:00 2001 From: Lakshmi Sowjanya D Date: Wed, 15 Dec 2021 17:12:01 +0200 Subject: i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters The data type of hcnt and lcnt in the struct dw_i2c_dev is of type u16. It's better to have same data type in struct dw_scl_sda_cfg as well. Reported-by: Wolfram Sang Signed-off-by: Lakshmi Sowjanya D Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 0f409a4c2da0..5b45941bcbdd 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -39,10 +39,10 @@ enum dw_pci_ctl_id_t { }; struct dw_scl_sda_cfg { - u32 ss_hcnt; - u32 fs_hcnt; - u32 ss_lcnt; - u32 fs_lcnt; + u16 ss_hcnt; + u16 fs_hcnt; + u16 ss_lcnt; + u16 fs_lcnt; u32 sda_hold; }; -- cgit v1.2.3 From c2d7fa2207d0df23bde6ef3fb4d56135f3d2977b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Dec 2021 17:12:02 +0200 Subject: i2c: designware-pci: Add a note about struct dw_scl_sda_cfg usage Add a note about struct dw_scl_sda_cfg usage to discourage people of using this structure on new platforms. Instead they should try hard to put the needed information into firmware descriptions. Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 5b45941bcbdd..f49c41ba5647 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -38,6 +38,13 @@ enum dw_pci_ctl_id_t { navi_amd, }; +/* + * This is a legacy structure to describe the hardware counters + * to configure signal timings on the bus. For Device Tree platforms + * one should use the respective properties and for ACPI there is + * a set of ACPI methods that provide these counters. No new + * platform should use this structure. + */ struct dw_scl_sda_cfg { u16 ss_hcnt; u16 fs_hcnt; -- cgit v1.2.3 From c3c9bab1e398073df117fc0b5bb1b81beada9fd6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Dec 2021 17:12:03 +0200 Subject: i2c: designware-pci: Group MODULE_*() macros For better maintenance group MODULE_*() macros together. Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index f49c41ba5647..9276e4bf0b75 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -359,9 +359,6 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) pci_free_irq_vectors(pdev); } -/* work with hotplug and coldplug */ -MODULE_ALIAS("i2c_designware-pci"); - static const struct pci_device_id i2_designware_pci_ids[] = { /* Medfield */ { PCI_VDEVICE(INTEL, 0x0817), medfield }, @@ -418,9 +415,10 @@ static struct pci_driver dw_i2c_driver = { .pm = &i2c_dw_pm_ops, }, }; - module_pci_driver(dw_i2c_driver); +/* Work with hotplug and coldplug */ +MODULE_ALIAS("i2c_designware-pci"); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 0897f1735910a547d5e3aa2a5cf177ff96efb0ea Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Dec 2021 17:12:04 +0200 Subject: i2c: designware-pci: use __maybe_unused for PM functions Use __maybe_unused for PM functions instead of ifdeffery. Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 9276e4bf0b75..134919af0e36 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -213,8 +213,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, }; -#ifdef CONFIG_PM -static int i2c_dw_pci_suspend(struct device *dev) +static int __maybe_unused i2c_dw_pci_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); @@ -224,7 +223,7 @@ static int i2c_dw_pci_suspend(struct device *dev) return 0; } -static int i2c_dw_pci_resume(struct device *dev) +static int __maybe_unused i2c_dw_pci_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); int ret; @@ -234,7 +233,6 @@ static int i2c_dw_pci_resume(struct device *dev) return ret; } -#endif static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend, i2c_dw_pci_resume, NULL); -- cgit v1.2.3 From 2759181d9a131a2334211637eb56db3de2e7d84c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Dec 2021 17:12:05 +0200 Subject: i2c: designware-pci: Convert to use dev_err_probe() It's fine to call dev_err_probe() in ->probe() when error code is known. Convert the driver to use dev_err_probe(). Signed-off-by: Andy Shevchenko Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 134919af0e36..ef4250f8852b 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -246,28 +246,24 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct dw_pci_controller *controller; struct dw_scl_sda_cfg *cfg; - if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { - dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, - id->driver_data); - return -EINVAL; - } + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) + return dev_err_probe(&pdev->dev, -EINVAL, + "Invalid driver data %ld\n", + id->driver_data); controller = &dw_pci_controllers[id->driver_data]; r = pcim_enable_device(pdev); - if (r) { - dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n", - r); - return r; - } + if (r) + return dev_err_probe(&pdev->dev, r, + "Failed to enable I2C PCI device\n"); pci_set_master(pdev); r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); - if (r) { - dev_err(&pdev->dev, "I/O memory remapping failed\n"); - return r; - } + if (r) + return dev_err_probe(&pdev->dev, r, + "I/O memory remapping failed\n"); dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); if (!dev) -- cgit v1.2.3 From ac18935d2e5130744b9675f6fb72acb783f86d77 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sun, 12 Dec 2021 20:10:57 +0200 Subject: i2c: exynos5: Fix getting the optional clock "hsi2c_pclk" clock is optional and may not be present for some SoCs supported by this driver. Nevertheless, in case the clock is provided but some error happens during its getting, that error should be handled properly. Use devm_clk_get_optional() API for that. Also report possible errors using dev_err_probe() to handle properly -EPROBE_DEFER error (if clock provider is not ready by the time I2C probe function is executed). Fixes: 697ad2490c96 ("i2c: exynos5: Add bus clock support") Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanho Park [wsa: fixed SHA1 of Fixes tag] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 693903e80892..b812d1090c0f 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -814,9 +814,11 @@ static int exynos5_i2c_probe(struct platform_device *pdev) return -ENOENT; } - i2c->pclk = devm_clk_get(&pdev->dev, "hsi2c_pclk"); - if (IS_ERR(i2c->pclk)) - i2c->pclk = NULL; /* pclk is optional */ + i2c->pclk = devm_clk_get_optional(&pdev->dev, "hsi2c_pclk"); + if (IS_ERR(i2c->pclk)) { + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), + "cannot get pclk"); + } ret = clk_prepare_enable(i2c->pclk); if (ret) -- cgit v1.2.3 From a5f7cf953f2b47e5025a7acd1698eea997b2fd94 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Dec 2021 09:45:42 +0100 Subject: i2c: rcar: update to new DMAENGINE API when terminating dmaengine_terminate_all() is deprecated. When converting the existing calls, it turned out that the termination in the interrupt handlers was superfluous and only a side effect of simply calling rcar_i2c_cleanup_dma(). As either no DMA transfers have been submitted yet or the last one has successfully completed, there is nothing to terminate and we can leave it out. So, merge the DMA unmap and cleanup function to save some code. Then, add a flag if the new cleanup function needs to terminate DMA. This is only the case for the erorr handling in the main thread, so we can finally switch from dmaengine_terminate_all() to dmaengine_terminate_sync() here. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index fc13511f4562..f71c730f9838 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -367,11 +367,15 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv) rcar_i2c_prepare_msg(priv); } -static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv) +static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate) { struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE ? priv->dma_rx : priv->dma_tx; + /* only allowed from thread context! */ + if (terminate) + dmaengine_terminate_sync(chan); + dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg), sg_dma_len(&priv->sg), priv->dma_direction); @@ -386,25 +390,13 @@ static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICDMAER, 0); } -static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv) -{ - if (priv->dma_direction == DMA_NONE) - return; - else if (priv->dma_direction == DMA_FROM_DEVICE) - dmaengine_terminate_all(priv->dma_rx); - else if (priv->dma_direction == DMA_TO_DEVICE) - dmaengine_terminate_all(priv->dma_tx); - - rcar_i2c_dma_unmap(priv); -} - static void rcar_i2c_dma_callback(void *data) { struct rcar_i2c_priv *priv = data; priv->pos += sg_dma_len(&priv->sg); - rcar_i2c_dma_unmap(priv); + rcar_i2c_cleanup_dma(priv, false); } static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) @@ -456,7 +448,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_dbg(dev, "dma prep slave sg failed, using PIO\n"); - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, false); return false; } @@ -466,7 +458,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) cookie = dmaengine_submit(txdesc); if (dma_submit_error(cookie)) { dev_dbg(dev, "submitting dma failed, using PIO\n"); - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, false); return false; } @@ -846,7 +838,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, /* cleanup DMA if it couldn't complete properly due to an error */ if (priv->dma_direction != DMA_NONE) - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, true); if (!time_left) { rcar_i2c_init(priv); -- cgit v1.2.3 From 44df8a79283d94f4aed2e3a14ed67e49a3c210ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Dec 2021 09:45:43 +0100 Subject: i2c: sh_mobile: update to new DMAENGINE API when terminating dmaengine_terminate_all() is deprecated. When converting the existing calls, it turned out that the termination in the DMA setup and callback were superfluous and only a side effect of simply calling rcar_i2c_cleanup_dma(). As either no DMA transfers have been submitted yet or the last one has successfully completed, there is nothing to terminate and we can leave it out. So, merge the DMA unmap and cleanup function to save some code. Then, add a flag if the new cleanup function needs to terminate DMA. This is only the case for the erorr handling in the main thread, so we can finally switch from dmaengine_terminate_all() to dmaengine_terminate_sync() here. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index db8fa4186814..7b8caf172851 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -442,34 +442,26 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void sh_mobile_i2c_dma_unmap(struct sh_mobile_i2c_data *pd) +static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd, bool terminate) { struct dma_chan *chan = pd->dma_direction == DMA_FROM_DEVICE ? pd->dma_rx : pd->dma_tx; + /* only allowed from thread context! */ + if (terminate) + dmaengine_terminate_sync(chan); + dma_unmap_single(chan->device->dev, sg_dma_address(&pd->sg), pd->msg->len, pd->dma_direction); pd->dma_direction = DMA_NONE; } -static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd) -{ - if (pd->dma_direction == DMA_NONE) - return; - else if (pd->dma_direction == DMA_FROM_DEVICE) - dmaengine_terminate_sync(pd->dma_rx); - else if (pd->dma_direction == DMA_TO_DEVICE) - dmaengine_terminate_sync(pd->dma_tx); - - sh_mobile_i2c_dma_unmap(pd); -} - static void sh_mobile_i2c_dma_callback(void *data) { struct sh_mobile_i2c_data *pd = data; - sh_mobile_i2c_dma_unmap(pd); + sh_mobile_i2c_cleanup_dma(pd, false); pd->pos = pd->msg->len; pd->stop_after_dma = true; @@ -549,7 +541,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -559,7 +551,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) cookie = dmaengine_submit(txdesc); if (dma_submit_error(cookie)) { dev_dbg(pd->dev, "submitting dma failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -698,7 +690,7 @@ static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd, if (!time_left) { dev_err(pd->dev, "Transfer request timed out\n"); if (pd->dma_direction != DMA_NONE) - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, true); err = -ETIMEDOUT; break; -- cgit v1.2.3 From 653becec6d568a28666f726ed4c84b10f3c09f5e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 7 Dec 2021 15:17:22 +0100 Subject: i2c: aspeed: Remove unused includes No symbols from the linux/irqchip/chained_irq.h and linux/irqdomain.h headers are used in the driver, so they can be removed. Signed-off-by: Thierry Reding Reviewed-by: Joel Stanley Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-aspeed.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 67e8b97c0c95..771e53d3d197 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include #include #include -- cgit v1.2.3 From c3b2f911ac11892b672df7829becf28d3a830073 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 21 Dec 2021 17:53:20 +0000 Subject: i2c: bcm2835: Use platform_get_irq() to get the interrupt platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static allocation of IRQ resources in DT core code, this causes an issue when using hierarchical interrupt domains using "interrupts" property in the node as this bypasses the hierarchical setup and messes up the irq chaining. In preparation for removal of static setup of IRQ resource from DT core code use platform_get_irq(). Signed-off-by: Lad Prabhakar Reviewed-by: Florian Fainelli Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 37443edbf754..dfc534065595 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -402,7 +402,7 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quirks = { static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; - struct resource *mem, *irq; + struct resource *mem; int ret; struct i2c_adapter *adap; struct clk *mclk; @@ -452,12 +452,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) return ret; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "No IRQ resource\n"); - return -ENODEV; - } - i2c_dev->irq = irq->start; + i2c_dev->irq = platform_get_irq(pdev, 0); + if (i2c_dev->irq < 0) + return i2c_dev->irq; ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, dev_name(&pdev->dev), i2c_dev); -- cgit v1.2.3 From aab799e44ce3953ac56c42721742c9cd9208b2f4 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 21 Dec 2021 17:53:21 +0000 Subject: i2c: sh_mobile: Use platform_get_irq_optional() to get the interrupt platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static allocation of IRQ resources in DT core code, this causes an issue when using hierarchical interrupt domains using "interrupts" property in the node as this bypasses the hierarchical setup and messes up the irq chaining. In preparation for removal of static setup of IRQ resource from DT core code use platform_get_irq_optional() for DT users only. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 7b8caf172851..9754849dbb23 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -830,20 +830,38 @@ static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd) static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile_i2c_data *pd) { - struct resource *res; - resource_size_t n; + struct device_node *np = dev_of_node(&dev->dev); int k = 0, ret; - while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { - for (n = res->start; n <= res->end; n++) { - ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, - 0, dev_name(&dev->dev), pd); + if (np) { + int irq; + + while ((irq = platform_get_irq_optional(dev, k)) != -ENXIO) { + if (irq < 0) + return irq; + ret = devm_request_irq(&dev->dev, irq, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); if (ret) { - dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + dev_err(&dev->dev, "cannot request IRQ %d\n", irq); return ret; } + k++; + }; + } else { + struct resource *res; + resource_size_t n; + + while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { + for (n = res->start; n <= res->end; n++) { + ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); + if (ret) { + dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + return ret; + } + } + k++; } - k++; } return k > 0 ? 0 : -ENOENT; -- cgit v1.2.3 From 8ab1ff9b1ec819bf431cf6c370ba3d9f8c8a108b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 21 Dec 2021 17:53:22 +0000 Subject: i2c: riic: Use platform_get_irq() to get the interrupt platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static allocation of IRQ resources in DT core code, this causes an issue when using hierarchical interrupt domains using "interrupts" property in the node as this bypasses the hierarchical setup and messes up the irq chaining. In preparation for removal of static setup of IRQ resource from DT core code use platform_get_irq(). Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-riic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 78b84445ee6a..8dfd27dc6149 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -433,12 +433,12 @@ static int riic_i2c_probe(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num); - if (!res) - return -ENODEV; + ret = platform_get_irq(pdev, riic_irqs[i].res_num); + if (ret < 0) + return ret; - ret = devm_request_irq(&pdev->dev, res->start, riic_irqs[i].isr, - 0, riic_irqs[i].name, riic); + ret = devm_request_irq(&pdev->dev, ret, riic_irqs[i].isr, + 0, riic_irqs[i].name, riic); if (ret) { dev_err(&pdev->dev, "failed to request irq %s\n", riic_irqs[i].name); return ret; -- cgit v1.2.3 From bf3c39f5da43499c52d4127b7f2f495b69dfeebf Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sat, 8 Jan 2022 13:41:09 +0800 Subject: i2c: sh_mobile: remove unneeded semicolon Eliminate the following coccicheck warning: ./drivers/i2c/busses/i2c-sh_mobile.c:849:3-4: Unneeded semicolon Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 9754849dbb23..72f024a0c363 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -846,7 +846,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile return ret; } k++; - }; + } } else { struct resource *res; resource_size_t n; -- cgit v1.2.3