From patchwork Mon Apr 8 02:54:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787065 Received: from mx2.zhaoxin.com (mx2.zhaoxin.com [203.110.167.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D4B4E522F for ; Mon, 8 Apr 2024 02:55:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.110.167.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544931; cv=none; b=L7T2FPTOIrlu9Nu/TBnRPk9zxGotMXqELx5T+1T75YFt/+rL9qfLp+bm8D9/4lb8ZwXGc12j+ObczAJ1Zrbf/j1TgL4JPvcglxU8UgohQHC0/YtbxcLrFRG3qZb08SjhtHgMcWqI5IsKLupzY78qAEhCoBOqBIiCE1SBTJVyeYE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544931; c=relaxed/simple; bh=6+fNF8rV5VOB50UC2byZehxiLfN3QtBdY4SWB9gNVnQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ElYU/kJ0E+XAXN8+kOtnRMKoea30WFY0P8YqZsejAnsJgmYdWvkw7Yq00LkwVu5EqH8lYdKyS2TFFZ7nfCuHW6zMuA0QUpYWw09EPEY2SmB5jhVg+uguxA/8NNt58dJJFhOErUCv3PokNqRdoZPMBzqrZFQhQbQTDj1BRklZHqc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=203.110.167.99 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544890-1eb14e2b8127a00002-PT6Irj Received: from ZXSHMBX1.zhaoxin.com (ZXSHMBX1.zhaoxin.com [10.28.252.163]) by mx2.zhaoxin.com with ESMTP id DMTEOq0hgFpb8xbS (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:50 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.163 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX1.zhaoxin.com (10.28.252.163) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:50 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:49 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.163 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Date: Mon, 8 Apr 2024 10:54:43 +0800 X-ASG-Orig-Subj: [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Message-ID: <60d6194d9e6623744955047a3881f9010b4da85a.1712479417.git.hanshu-oc@zhaoxin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX1.zhaoxin.com[10.28.252.163] X-Barracuda-Start-Time: 1712544890 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.36:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 3842 X-Barracuda-BRTS-Status: 0 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- Some common initialization actions are put in the function wmt_i2c_init(), which is convenient to share with zhaoxin. Reviewed-by: Andi Shyti Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- drivers/i2c/busses/i2c-wmt.c | 65 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 198afee5233c..76ede433f65c 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -109,7 +109,7 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) unsigned long wait_result; wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); + msecs_to_jiffies(500)); if (!wait_result) return -ETIMEDOUT; @@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data) return IRQ_HANDLED; } +static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +{ + int err; + struct wmt_i2c_dev *i2c_dev; + struct device_node *np = pdev->dev.of_node; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) + return -EINVAL; + + err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, + 0, pdev->name, i2c_dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq %i\n", i2c_dev->irq); + + i2c_dev->dev = &pdev->dev; + init_completion(&i2c_dev->complete); + platform_set_drvdata(pdev, i2c_dev); + + *pi2c_dev = i2c_dev; + return 0; +} + static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) { int err; @@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev) int err; u32 clk_rate; - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) - return -ENOMEM; - - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); - - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) { - dev_err(&pdev->dev, "irq missing or invalid\n"); - return -EINVAL; - } + err = wmt_i2c_init(pdev, &i2c_dev); + if (err) + return err; i2c_dev->clk = of_clk_get(np, 0); if (IS_ERR(i2c_dev->clk)) { @@ -348,18 +370,9 @@ static int wmt_i2c_probe(struct platform_device *pdev) } err = of_property_read_u32(np, "clock-frequency", &clk_rate); - if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ)) + if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) i2c_dev->tcr = TCR_FAST_MODE; - i2c_dev->dev = &pdev->dev; - - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0, - "i2c", i2c_dev); - if (err) { - dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq); - return err; - } - adap = &i2c_dev->adapter; i2c_set_adapdata(adap, i2c_dev); strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); @@ -368,8 +381,6 @@ static int wmt_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - init_completion(&i2c_dev->complete); - err = wmt_i2c_reset_hardware(i2c_dev); if (err) { dev_err(&pdev->dev, "error initializing hardware\n"); @@ -380,8 +391,6 @@ static int wmt_i2c_probe(struct platform_device *pdev) if (err) goto err_disable_clk; - platform_set_drvdata(pdev, i2c_dev); - return 0; err_disable_clk: From patchwork Mon Apr 8 02:54:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787302 Received: from mx1.zhaoxin.com (MX1.ZHAOXIN.COM [210.0.225.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 331DF8473 for ; Mon, 8 Apr 2024 02:55:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.0.225.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544904; cv=none; b=Qim5uK1OL/iNe01Qf6dc0ZXzCZUDQ2s/xvDP2IUlnXTK82n8YuU34XbrX9pp3uTy3Qi8EELDWZpM8hfl2QAqAawXVkH7OTLqNwGkH3qTf6d6nC5OUsJjIuPZb7YVpuLy5AaS1et72da5/wEXo3mSjrztJccVK8elxwqaq1+w0N4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544904; c=relaxed/simple; bh=RlBXznX3EmfGPKMKmzeLHMH9ev7BRtit7eW0yqQLLyQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=R1u8vsV8HhO7A6Uh8rq6cSUrUsQJuC7HIdKRmAOyheFPoBVVItQeUya+xnuUFsYrEwv4htnBzELRKAhNxpo1oHghPVUXVfNdu3efhS4hnSPDkKdAlNO0T38tsniRTIpUP7xyDoN9pFhSa/ASZK86V7pIxoY24F+hyIK686xTe88= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=210.0.225.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544891-086e23661934350001-PT6Irj Received: from ZXSHMBX3.zhaoxin.com (ZXSHMBX3.zhaoxin.com [10.28.252.165]) by mx1.zhaoxin.com with ESMTP id pTmbFUcSjEuQQ6DP (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:51 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX3.zhaoxin.com (10.28.252.165) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:51 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:50 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 2/6] i2c: wmt: split out common files Date: Mon, 8 Apr 2024 10:54:44 +0800 X-ASG-Orig-Subj: [PATCH v10 2/6] i2c: wmt: split out common files Message-ID: <86530488f4163951f1ffdfdaedb343c85bb4528e.1712479417.git.hanshu-oc@zhaoxin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX3.zhaoxin.com[10.28.252.165] X-Barracuda-Start-Time: 1712544891 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.35:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 25125 X-Barracuda-BRTS-Status: 1 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- Since the I2C IP of both wmt and zhaoxin originates from VIA, it is better to separate the common code first. The common driver is named as i2c-viai2c-common.c. Old i2c-wmt.c renamed to i2c-viai2c-wmt.c. The MAINTAINERS file will be updated accordingly in upcoming commits. Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- MAINTAINERS | 2 +- drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++ drivers/i2c/busses/i2c-viai2c-common.h | 71 ++++ drivers/i2c/busses/i2c-viai2c-wmt.c | 148 +++++++++ drivers/i2c/busses/i2c-wmt.c | 430 ------------------------- 6 files changed, 442 insertions(+), 431 deletions(-) create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c delete mode 100644 drivers/i2c/busses/i2c-wmt.c diff --git a/MAINTAINERS b/MAINTAINERS index 7c121493f43d..97fcb8d38210 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3018,7 +3018,7 @@ S: Orphan F: Documentation/devicetree/bindings/i2c/i2c-wmt.txt F: arch/arm/mach-vt8500/ F: drivers/clocksource/timer-vt8500.c -F: drivers/i2c/busses/i2c-wmt.c +F: drivers/i2c/busses/i2c-viai2c-wmt.c F: drivers/mmc/host/wmt-sdmmc.c F: drivers/pwm/pwm-vt8500.c F: drivers/rtc/rtc-vt8500.c diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index aa0ee8ecd6f2..63c7bbad8134 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o +i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o obj-$(CONFIG_I2C_WMT) += i2c-wmt.o i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c new file mode 100644 index 000000000000..b36a5d902990 --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "i2c-viai2c-common.h" + +int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) +{ + unsigned long timeout; + + timeout = jiffies + WMT_I2C_TIMEOUT; + while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); + return -EBUSY; + } + msleep(20); + } + + return 0; +} + +int wmt_check_status(struct wmt_i2c_dev *i2c_dev) +{ + int ret = 0; + unsigned long wait_result; + + wait_result = wait_for_completion_timeout(&i2c_dev->complete, + msecs_to_jiffies(500)); + if (!wait_result) + return -ETIMEDOUT; + + if (i2c_dev->cmd_status & ISR_NACK_ADDR) + ret = -EIO; + + if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) + ret = -ETIMEDOUT; + + return ret; +} + +static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last) +{ + u16 val, tcr_val = i2c_dev->tcr; + int ret; + int xfer_len = 0; + + if (pmsg->len == 0) { + /* + * We still need to run through the while (..) once, so + * start at -1 and break out early from the loop + */ + xfer_len = -1; + writew(0, i2c_dev->base + REG_CDR); + } else { + writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); + } + + if (!(pmsg->flags & I2C_M_NOSTART)) { + val = readw(i2c_dev->base + REG_CR); + val &= ~CR_TX_END; + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + reinit_completion(&i2c_dev->complete); + + tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + xfer_len++; + + val = readw(i2c_dev->base + REG_CSR); + if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { + dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); + return -EIO; + } + + if (pmsg->len == 0) { + val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; + writew(val, i2c_dev->base + REG_CR); + break; + } + + if (xfer_len == pmsg->len) { + if (last != 1) + writew(CR_ENABLE, i2c_dev->base + REG_CR); + } else { + writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + + REG_CDR); + writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); + } + } + + return 0; +} + +static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) +{ + u16 val, tcr_val = i2c_dev->tcr; + int ret; + u32 xfer_len = 0; + + val = readw(i2c_dev->base + REG_CR); + val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); + + if (!(pmsg->flags & I2C_M_NOSTART)) + val |= CR_CPU_RDY; + + if (pmsg->len == 1) + val |= CR_TX_NEXT_NO_ACK; + + writew(val, i2c_dev->base + REG_CR); + + reinit_completion(&i2c_dev->complete); + + tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; + xfer_len++; + + val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; + if (xfer_len == pmsg->len - 1) + val |= CR_TX_NEXT_NO_ACK; + writew(val, i2c_dev->base + REG_CR); + } + + return 0; +} + +int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + + for (i = 0; ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + if (!(pmsg->flags & I2C_M_NOSTART)) { + ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + if (ret < 0) + return ret; + } + + if (pmsg->flags & I2C_M_RD) + ret = wmt_i2c_read(i2c_dev, pmsg); + else + ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); + } + + return (ret < 0) ? ret : i; +} + +static irqreturn_t wmt_i2c_isr(int irq, void *data) +{ + struct wmt_i2c_dev *i2c_dev = data; + + /* save the status and write-clear it */ + i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); + writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); + + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +{ + int err; + struct wmt_i2c_dev *i2c_dev; + struct device_node *np = pdev->dev.of_node; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) + return -EINVAL; + + err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, + 0, pdev->name, i2c_dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq %i\n", i2c_dev->irq); + + i2c_dev->dev = &pdev->dev; + init_completion(&i2c_dev->complete); + platform_set_drvdata(pdev, i2c_dev); + + *pi2c_dev = i2c_dev; + return 0; +} diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h new file mode 100644 index 000000000000..fcff8e4456eb --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __I2C_VIAI2C_COMMON_H_ +#define __I2C_VIAI2C_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CR 0x00 +#define REG_TCR 0x02 +#define REG_CSR 0x04 +#define REG_ISR 0x06 +#define REG_IMR 0x08 +#define REG_CDR 0x0A +#define REG_TR 0x0C +#define REG_MCR 0x0E + +/* REG_CR Bit fields */ +#define CR_TX_NEXT_ACK 0x0000 +#define CR_ENABLE 0x0001 +#define CR_TX_NEXT_NO_ACK 0x0002 +#define CR_TX_END 0x0004 +#define CR_CPU_RDY 0x0008 +#define SLAV_MODE_SEL 0x8000 + +/* REG_TCR Bit fields */ +#define TCR_STANDARD_MODE 0x0000 +#define TCR_MASTER_WRITE 0x0000 +#define TCR_HS_MODE 0x2000 +#define TCR_MASTER_READ 0x4000 +#define TCR_FAST_MODE 0x8000 +#define TCR_SLAVE_ADDR_MASK 0x007F + +/* REG_ISR Bit fields */ +#define ISR_NACK_ADDR 0x0001 +#define ISR_BYTE_END 0x0002 +#define ISR_SCL_TIMEOUT 0x0004 +#define ISR_WRITE_ALL 0x0007 + +/* REG_IMR Bit fields */ +#define IMR_ENABLE_ALL 0x0007 + +/* REG_CSR Bit fields */ +#define CSR_RCV_NOT_ACK 0x0001 +#define CSR_RCV_ACK_MASK 0x0001 +#define CSR_READY_MASK 0x0002 + +#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) + +struct wmt_i2c_dev { + struct i2c_adapter adapter; + struct completion complete; + struct device *dev; + void __iomem *base; + struct clk *clk; + u16 tcr; + int irq; + u16 cmd_status; +}; + +int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev); +int wmt_check_status(struct wmt_i2c_dev *i2c_dev); +int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); +int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev); + +#endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c new file mode 100644 index 000000000000..3125374cc2c0 --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Wondermedia I2C Master Mode Driver + * + * Copyright (C) 2012 Tony Prisk + * + * Derived from GPLv2+ licensed source: + * - Copyright (C) 2008 WonderMedia Technologies, Inc. + */ + +#include +#include +#include +#include "i2c-viai2c-common.h" + +#define REG_SLAVE_CR 0x10 +#define REG_SLAVE_SR 0x12 +#define REG_SLAVE_ISR 0x14 +#define REG_SLAVE_IMR 0x16 +#define REG_SLAVE_DR 0x18 +#define REG_SLAVE_TR 0x1A + +/* REG_TR */ +#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) +#define TR_STD 0x0064 +#define TR_HS 0x0019 + +/* REG_MCR */ +#define MCR_APB_96M 7 +#define MCR_APB_166M 12 + +static u32 wmt_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm wmt_i2c_algo = { + .master_xfer = wmt_i2c_xfer, + .functionality = wmt_i2c_func, +}; + +static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) +{ + int err; + + err = clk_prepare_enable(i2c_dev->clk); + if (err) { + dev_err(i2c_dev->dev, "failed to enable clock\n"); + return err; + } + + err = clk_set_rate(i2c_dev->clk, 20000000); + if (err) { + dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); + clk_disable_unprepare(i2c_dev->clk); + return err; + } + + writew(0, i2c_dev->base + REG_CR); + writew(MCR_APB_166M, i2c_dev->base + REG_MCR); + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); + writew(CR_ENABLE, i2c_dev->base + REG_CR); + readw(i2c_dev->base + REG_CSR); /* read clear */ + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + + if (i2c_dev->tcr == TCR_FAST_MODE) + writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + else + writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); + + return 0; +} + +static int wmt_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct wmt_i2c_dev *i2c_dev; + struct i2c_adapter *adap; + int err; + u32 clk_rate; + + err = wmt_i2c_init(pdev, &i2c_dev); + if (err) + return err; + + i2c_dev->clk = of_clk_get(np, 0); + if (IS_ERR(i2c_dev->clk)) { + dev_err(&pdev->dev, "unable to request clock\n"); + return PTR_ERR(i2c_dev->clk); + } + + err = of_property_read_u32(np, "clock-frequency", &clk_rate); + if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) + i2c_dev->tcr = TCR_FAST_MODE; + + adap = &i2c_dev->adapter; + i2c_set_adapdata(adap, i2c_dev); + strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->algo = &wmt_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + err = wmt_i2c_reset_hardware(i2c_dev); + if (err) { + dev_err(&pdev->dev, "error initializing hardware\n"); + return err; + } + + err = i2c_add_adapter(adap); + if (err) + /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ + clk_disable_unprepare(i2c_dev->clk); + + return err; +} + +static void wmt_i2c_remove(struct platform_device *pdev) +{ + struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + /* Disable interrupts, clock and delete adapter */ + writew(0, i2c_dev->base + REG_IMR); + clk_disable_unprepare(i2c_dev->clk); + i2c_del_adapter(&i2c_dev->adapter); +} + +static const struct of_device_id wmt_i2c_dt_ids[] = { + { .compatible = "wm,wm8505-i2c" }, + { /* Sentinel */ }, +}; + +static struct platform_driver wmt_i2c_driver = { + .probe = wmt_i2c_probe, + .remove_new = wmt_i2c_remove, + .driver = { + .name = "wmt-i2c", + .of_match_table = wmt_i2c_dt_ids, + }, +}; + +module_platform_driver(wmt_i2c_driver); + +MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); +MODULE_AUTHOR("Tony Prisk "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c deleted file mode 100644 index 76ede433f65c..000000000000 --- a/drivers/i2c/busses/i2c-wmt.c +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Wondermedia I2C Master Mode Driver - * - * Copyright (C) 2012 Tony Prisk - * - * Derived from GPLv2+ licensed source: - * - Copyright (C) 2008 WonderMedia Technologies, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REG_CR 0x00 -#define REG_TCR 0x02 -#define REG_CSR 0x04 -#define REG_ISR 0x06 -#define REG_IMR 0x08 -#define REG_CDR 0x0A -#define REG_TR 0x0C -#define REG_MCR 0x0E -#define REG_SLAVE_CR 0x10 -#define REG_SLAVE_SR 0x12 -#define REG_SLAVE_ISR 0x14 -#define REG_SLAVE_IMR 0x16 -#define REG_SLAVE_DR 0x18 -#define REG_SLAVE_TR 0x1A - -/* REG_CR Bit fields */ -#define CR_TX_NEXT_ACK 0x0000 -#define CR_ENABLE 0x0001 -#define CR_TX_NEXT_NO_ACK 0x0002 -#define CR_TX_END 0x0004 -#define CR_CPU_RDY 0x0008 -#define SLAV_MODE_SEL 0x8000 - -/* REG_TCR Bit fields */ -#define TCR_STANDARD_MODE 0x0000 -#define TCR_MASTER_WRITE 0x0000 -#define TCR_HS_MODE 0x2000 -#define TCR_MASTER_READ 0x4000 -#define TCR_FAST_MODE 0x8000 -#define TCR_SLAVE_ADDR_MASK 0x007F - -/* REG_ISR Bit fields */ -#define ISR_NACK_ADDR 0x0001 -#define ISR_BYTE_END 0x0002 -#define ISR_SCL_TIMEOUT 0x0004 -#define ISR_WRITE_ALL 0x0007 - -/* REG_IMR Bit fields */ -#define IMR_ENABLE_ALL 0x0007 - -/* REG_CSR Bit fields */ -#define CSR_RCV_NOT_ACK 0x0001 -#define CSR_RCV_ACK_MASK 0x0001 -#define CSR_READY_MASK 0x0002 - -/* REG_TR */ -#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) -#define TR_STD 0x0064 -#define TR_HS 0x0019 - -/* REG_MCR */ -#define MCR_APB_96M 7 -#define MCR_APB_166M 12 - -#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) - -struct wmt_i2c_dev { - struct i2c_adapter adapter; - struct completion complete; - struct device *dev; - void __iomem *base; - struct clk *clk; - u16 tcr; - int irq; - u16 cmd_status; -}; - -static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) -{ - unsigned long timeout; - - timeout = jiffies + WMT_I2C_TIMEOUT; - while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { - if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); - return -EBUSY; - } - msleep(20); - } - - return 0; -} - -static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) -{ - int ret = 0; - unsigned long wait_result; - - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - if (!wait_result) - return -ETIMEDOUT; - - if (i2c_dev->cmd_status & ISR_NACK_ADDR) - ret = -EIO; - - if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) - ret = -ETIMEDOUT; - - return ret; -} - -static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, - int last) -{ - u16 val, tcr_val = i2c_dev->tcr; - int ret; - int xfer_len = 0; - - if (pmsg->len == 0) { - /* - * We still need to run through the while (..) once, so - * start at -1 and break out early from the loop - */ - xfer_len = -1; - writew(0, i2c_dev->base + REG_CDR); - } else { - writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); - } - - if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - reinit_completion(&i2c_dev->complete); - - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - xfer_len++; - - val = readw(i2c_dev->base + REG_CSR); - if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { - dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); - return -EIO; - } - - if (pmsg->len == 0) { - val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; - writew(val, i2c_dev->base + REG_CR); - break; - } - - if (xfer_len == pmsg->len) { - if (last != 1) - writew(CR_ENABLE, i2c_dev->base + REG_CR); - } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + - REG_CDR); - writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); - } - } - - return 0; -} - -static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) -{ - u16 val, tcr_val = i2c_dev->tcr; - int ret; - u32 xfer_len = 0; - - val = readw(i2c_dev->base + REG_CR); - val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); - - if (!(pmsg->flags & I2C_M_NOSTART)) - val |= CR_CPU_RDY; - - if (pmsg->len == 1) - val |= CR_TX_NEXT_NO_ACK; - - writew(val, i2c_dev->base + REG_CR); - - reinit_completion(&i2c_dev->complete); - - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; - xfer_len++; - - val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; - if (xfer_len == pmsg->len - 1) - val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - } - - return 0; -} - -static int wmt_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], - int num) -{ - struct i2c_msg *pmsg; - int i; - int ret = 0; - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - - for (i = 0; ret >= 0 && i < num; i++) { - pmsg = &msgs[i]; - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - - if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(i2c_dev, pmsg); - else - ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); - } - - return (ret < 0) ? ret : i; -} - -static u32 wmt_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; -} - -static const struct i2c_algorithm wmt_i2c_algo = { - .master_xfer = wmt_i2c_xfer, - .functionality = wmt_i2c_func, -}; - -static irqreturn_t wmt_i2c_isr(int irq, void *data) -{ - struct wmt_i2c_dev *i2c_dev = data; - - /* save the status and write-clear it */ - i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); - writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); - - complete(&i2c_dev->complete); - - return IRQ_HANDLED; -} - -static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) -{ - int err; - struct wmt_i2c_dev *i2c_dev; - struct device_node *np = pdev->dev.of_node; - - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) - return -ENOMEM; - - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); - - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) - return -EINVAL; - - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, - 0, pdev->name, i2c_dev); - if (err) - return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c_dev->irq); - - i2c_dev->dev = &pdev->dev; - init_completion(&i2c_dev->complete); - platform_set_drvdata(pdev, i2c_dev); - - *pi2c_dev = i2c_dev; - return 0; -} - -static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) -{ - int err; - - err = clk_prepare_enable(i2c_dev->clk); - if (err) { - dev_err(i2c_dev->dev, "failed to enable clock\n"); - return err; - } - - err = clk_set_rate(i2c_dev->clk, 20000000); - if (err) { - dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); - clk_disable_unprepare(i2c_dev->clk); - return err; - } - - writew(0, i2c_dev->base + REG_CR); - writew(MCR_APB_166M, i2c_dev->base + REG_MCR); - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); - writew(CR_ENABLE, i2c_dev->base + REG_CR); - readw(i2c_dev->base + REG_CSR); /* read clear */ - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - - if (i2c_dev->tcr == TCR_FAST_MODE) - writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); - else - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); - - return 0; -} - -static int wmt_i2c_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct wmt_i2c_dev *i2c_dev; - struct i2c_adapter *adap; - int err; - u32 clk_rate; - - err = wmt_i2c_init(pdev, &i2c_dev); - if (err) - return err; - - i2c_dev->clk = of_clk_get(np, 0); - if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "unable to request clock\n"); - return PTR_ERR(i2c_dev->clk); - } - - err = of_property_read_u32(np, "clock-frequency", &clk_rate); - if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) - i2c_dev->tcr = TCR_FAST_MODE; - - adap = &i2c_dev->adapter; - i2c_set_adapdata(adap, i2c_dev); - strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); - adap->owner = THIS_MODULE; - adap->algo = &wmt_i2c_algo; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; - - err = wmt_i2c_reset_hardware(i2c_dev); - if (err) { - dev_err(&pdev->dev, "error initializing hardware\n"); - return err; - } - - err = i2c_add_adapter(adap); - if (err) - goto err_disable_clk; - - return 0; - -err_disable_clk: - clk_disable_unprepare(i2c_dev->clk); - return err; -} - -static void wmt_i2c_remove(struct platform_device *pdev) -{ - struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - - /* Disable interrupts, clock and delete adapter */ - writew(0, i2c_dev->base + REG_IMR); - clk_disable_unprepare(i2c_dev->clk); - i2c_del_adapter(&i2c_dev->adapter); -} - -static const struct of_device_id wmt_i2c_dt_ids[] = { - { .compatible = "wm,wm8505-i2c" }, - { /* Sentinel */ }, -}; - -static struct platform_driver wmt_i2c_driver = { - .probe = wmt_i2c_probe, - .remove_new = wmt_i2c_remove, - .driver = { - .name = "wmt-i2c", - .of_match_table = wmt_i2c_dt_ids, - }, -}; - -module_platform_driver(wmt_i2c_driver); - -MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); -MODULE_AUTHOR("Tony Prisk "); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); From patchwork Mon Apr 8 02:54:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787301 Received: from mx1.zhaoxin.com (MX1.ZHAOXIN.COM [210.0.225.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 331958460 for ; Mon, 8 Apr 2024 02:55:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.0.225.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544905; cv=none; b=h7S0Voa/A2Z6p15P8USyTSmjXQ0+VYuhal/SenTzVIat3eXQh+yF2a6wPxX4lwq65fjY73QytqCPJUhwJ4KqU1waP/W1gKzyUDALmheqIKA9BeNhry70XTYXrUzoxim147wtsRQnxWfyZvHmfAhzZz+UbnoGZ7aGLGL0jw3+Pao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544905; c=relaxed/simple; bh=KTXwlMsBSuYD7qPVnH1K4nAyyH5HLNqa8fVromsTE58=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=okbqR3WKZUguB57fKFTshO5n0dZPXV/SOnNRomhwaKns/2MtxIKH4sb8FB5x0KQRw0seJNClMNzPg6hWD8RmLnNPaVS2osgaSQDF7g3EGCVV/HvdkRccvYD2JoYW0F4wpBeYoDCmK/VPmVLYqwnggxhTfOotWJTceLnnawoC6XY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=210.0.225.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544891-086e23661934350002-PT6Irj Received: from ZXSHMBX3.zhaoxin.com (ZXSHMBX3.zhaoxin.com [10.28.252.165]) by mx1.zhaoxin.com with ESMTP id r5GXZtHIRQLh1Lvs (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:52 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX3.zhaoxin.com (10.28.252.165) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:51 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:50 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 3/6] i2c: wmt: rename something Date: Mon, 8 Apr 2024 10:54:45 +0800 X-ASG-Orig-Subj: [PATCH v10 3/6] i2c: wmt: rename something Message-ID: <51f2d3e750e64a1ccdc7bba4a85fb92a3dd99b90.1712479417.git.hanshu-oc@zhaoxin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX3.zhaoxin.com[10.28.252.165] X-Barracuda-Start-Time: 1712544891 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.35:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 17611 X-Barracuda-BRTS-Status: 1 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename common registers, functions, and variable names to follow the VIAI2C_ and viai2c_ naming conventions for consistency and clarity. 2. rename i2c_dev to i2c, to shorten the length of a line. 3. rename wait_result to time_left, make it better to reflect the meaning of the value returned by wait_for_completion_timeout(). 4. remove TCR_MASTER_WRITE, its value is 0. Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- drivers/i2c/busses/i2c-viai2c-common.c | 157 ++++++++++++------------- drivers/i2c/busses/i2c-viai2c-common.h | 70 ++++++----- drivers/i2c/busses/i2c-viai2c-wmt.c | 62 +++++----- 3 files changed, 143 insertions(+), 146 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index b36a5d902990..59901c53ad48 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -2,14 +2,14 @@ #include #include "i2c-viai2c-common.h" -int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) +int viai2c_wait_bus_not_busy(struct viai2c *i2c) { unsigned long timeout; - timeout = jiffies + WMT_I2C_TIMEOUT; - while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { + timeout = jiffies + VIAI2C_TIMEOUT; + while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) { if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); + dev_warn(i2c->dev, "timeout waiting for bus ready\n"); return -EBUSY; } msleep(20); @@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) return 0; } -int wmt_check_status(struct wmt_i2c_dev *i2c_dev) +int viai2c_check_status(struct viai2c *i2c) { int ret = 0; - unsigned long wait_result; + unsigned long time_left; - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - if (!wait_result) + time_left = wait_for_completion_timeout(&i2c->complete, + msecs_to_jiffies(500)); + if (!time_left) return -ETIMEDOUT; - if (i2c_dev->cmd_status & ISR_NACK_ADDR) + if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR) ret = -EIO; - if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) + if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT) ret = -ETIMEDOUT; return ret; } -static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last) +static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) { - u16 val, tcr_val = i2c_dev->tcr; + u16 val, tcr_val = i2c->tcr; int ret; int xfer_len = 0; @@ -49,173 +49,172 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int * start at -1 and break out early from the loop */ xfer_len = -1; - writew(0, i2c_dev->base + REG_CDR); + writew(0, i2c->base + VIAI2C_REG_CDR); } else { - writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); + writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); } if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~VIAI2C_CR_TX_END; + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } - reinit_completion(&i2c_dev->complete); + reinit_completion(&i2c->complete); - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); + tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK; - writew(tcr_val, i2c_dev->base + REG_TCR); + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); + ret = viai2c_check_status(i2c); if (ret) return ret; xfer_len++; - val = readw(i2c_dev->base + REG_CSR); - if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { - dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); + val = readw(i2c->base + VIAI2C_REG_CSR); + if (val & VIAI2C_CSR_RCV_NOT_ACK) { + dev_dbg(i2c->dev, "write RCV NACK error\n"); return -EIO; } if (pmsg->len == 0) { - val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; - writew(val, i2c_dev->base + REG_CR); + val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; + writew(val, i2c->base + VIAI2C_REG_CR); break; } if (xfer_len == pmsg->len) { if (last != 1) - writew(CR_ENABLE, i2c_dev->base + REG_CR); + writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + - REG_CDR); - writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); + writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR); + writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); } } return 0; } -static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) +static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) { - u16 val, tcr_val = i2c_dev->tcr; + u16 val, tcr_val = i2c->tcr; int ret; u32 xfer_len = 0; - val = readw(i2c_dev->base + REG_CR); - val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); if (!(pmsg->flags & I2C_M_NOSTART)) - val |= CR_CPU_RDY; + val |= VIAI2C_CR_CPU_RDY; if (pmsg->len == 1) - val |= CR_TX_NEXT_NO_ACK; + val |= VIAI2C_CR_RX_END; - writew(val, i2c_dev->base + REG_CR); + writew(val, i2c->base + VIAI2C_REG_CR); - reinit_completion(&i2c_dev->complete); + reinit_completion(&i2c->complete); - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); + tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK); - writew(tcr_val, i2c_dev->base + REG_TCR); + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); + ret = viai2c_check_status(i2c); if (ret) return ret; - pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; + pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8; xfer_len++; - val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; + val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; if (xfer_len == pmsg->len - 1) - val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); + val |= VIAI2C_CR_RX_END; + writew(val, i2c->base + VIAI2C_REG_CR); } return 0; } -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct i2c_msg *pmsg; int i; int ret = 0; - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + struct viai2c *i2c = i2c_get_adapdata(adap); for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + ret = viai2c_wait_bus_not_busy(i2c); if (ret < 0) return ret; } if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(i2c_dev, pmsg); + ret = viai2c_read(i2c, pmsg); else - ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); + ret = viai2c_write(i2c, pmsg, (i + 1) == num); } return (ret < 0) ? ret : i; } -static irqreturn_t wmt_i2c_isr(int irq, void *data) +static irqreturn_t viai2c_isr(int irq, void *data) { - struct wmt_i2c_dev *i2c_dev = data; + struct viai2c *i2c = data; /* save the status and write-clear it */ - i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); - writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); + i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR); + writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR); - complete(&i2c_dev->complete); + complete(&i2c->complete); return IRQ_HANDLED; } -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) { int err; - struct wmt_i2c_dev *i2c_dev; + struct viai2c *i2c; struct device_node *np = pdev->dev.of_node; - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) return -ENOMEM; - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) + i2c->irq = irq_of_parse_and_map(np, 0); + if (!i2c->irq) return -EINVAL; - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, - 0, pdev->name, i2c_dev); + err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr, + 0, pdev->name, i2c); if (err) return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c_dev->irq); + "failed to request irq %i\n", i2c->irq); - i2c_dev->dev = &pdev->dev; - init_completion(&i2c_dev->complete); - platform_set_drvdata(pdev, i2c_dev); + i2c->dev = &pdev->dev; + init_completion(&i2c->complete); + platform_set_drvdata(pdev, i2c); - *pi2c_dev = i2c_dev; + *pi2c = i2c; return 0; } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index fcff8e4456eb..28799e7e97f0 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -11,48 +11,46 @@ #include #include -#define REG_CR 0x00 -#define REG_TCR 0x02 -#define REG_CSR 0x04 -#define REG_ISR 0x06 -#define REG_IMR 0x08 -#define REG_CDR 0x0A -#define REG_TR 0x0C -#define REG_MCR 0x0E - /* REG_CR Bit fields */ -#define CR_TX_NEXT_ACK 0x0000 -#define CR_ENABLE 0x0001 -#define CR_TX_NEXT_NO_ACK 0x0002 -#define CR_TX_END 0x0004 -#define CR_CPU_RDY 0x0008 -#define SLAV_MODE_SEL 0x8000 +#define VIAI2C_REG_CR 0x00 +#define VIAI2C_CR_ENABLE BIT(0) +#define VIAI2C_CR_RX_END BIT(1) +#define VIAI2C_CR_TX_END BIT(2) +#define VIAI2C_CR_CPU_RDY BIT(3) +#define VIAI2C_CR_END_MASK GENMASK(2, 1) /* REG_TCR Bit fields */ -#define TCR_STANDARD_MODE 0x0000 -#define TCR_MASTER_WRITE 0x0000 -#define TCR_HS_MODE 0x2000 -#define TCR_MASTER_READ 0x4000 -#define TCR_FAST_MODE 0x8000 -#define TCR_SLAVE_ADDR_MASK 0x007F +#define VIAI2C_REG_TCR 0x02 +#define VIAI2C_TCR_HS_MODE BIT(13) +#define VIAI2C_TCR_READ BIT(14) +#define VIAI2C_TCR_FAST BIT(15) +#define VIAI2C_TCR_ADDR_MASK GENMASK(6, 0) + +/* REG_CSR Bit fields */ +#define VIAI2C_REG_CSR 0x04 +#define VIAI2C_CSR_RCV_NOT_ACK BIT(0) +#define VIAI2C_CSR_RCV_ACK_MASK BIT(0) +#define VIAI2C_CSR_READY_MASK BIT(1) /* REG_ISR Bit fields */ -#define ISR_NACK_ADDR 0x0001 -#define ISR_BYTE_END 0x0002 -#define ISR_SCL_TIMEOUT 0x0004 -#define ISR_WRITE_ALL 0x0007 +#define VIAI2C_REG_ISR 0x06 +#define VIAI2C_ISR_NACK_ADDR BIT(0) +#define VIAI2C_ISR_BYTE_END BIT(1) +#define VIAI2C_ISR_SCL_TIMEOUT BIT(2) +#define VIAI2C_ISR_MASK_ALL GENMASK(2, 0) /* REG_IMR Bit fields */ -#define IMR_ENABLE_ALL 0x0007 +#define VIAI2C_REG_IMR 0x08 +#define VIAI2C_IMR_BYTE BIT(1) +#define VIAI2C_IMR_ENABLE_ALL GENMASK(2, 0) -/* REG_CSR Bit fields */ -#define CSR_RCV_NOT_ACK 0x0001 -#define CSR_RCV_ACK_MASK 0x0001 -#define CSR_READY_MASK 0x0002 +#define VIAI2C_REG_CDR 0x0A +#define VIAI2C_REG_TR 0x0C +#define VIAI2C_REG_MCR 0x0E -#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) +#define VIAI2C_TIMEOUT (msecs_to_jiffies(1000)) -struct wmt_i2c_dev { +struct viai2c { struct i2c_adapter adapter; struct completion complete; struct device *dev; @@ -63,9 +61,9 @@ struct wmt_i2c_dev { u16 cmd_status; }; -int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev); -int wmt_check_status(struct wmt_i2c_dev *i2c_dev); -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev); +int viai2c_wait_bus_not_busy(struct viai2c *i2c); +int viai2c_check_status(struct viai2c *i2c); +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 3125374cc2c0..1e9db735e1fa 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm wmt_i2c_algo = { - .master_xfer = wmt_i2c_xfer, + .master_xfer = viai2c_xfer, .functionality = wmt_i2c_func, }; -static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) +static int wmt_i2c_reset_hardware(struct viai2c *i2c) { int err; - err = clk_prepare_enable(i2c_dev->clk); + err = clk_prepare_enable(i2c->clk); if (err) { - dev_err(i2c_dev->dev, "failed to enable clock\n"); + dev_err(i2c->dev, "failed to enable clock\n"); return err; } - err = clk_set_rate(i2c_dev->clk, 20000000); + err = clk_set_rate(i2c->clk, 20000000); if (err) { - dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); - clk_disable_unprepare(i2c_dev->clk); + dev_err(i2c->dev, "failed to set clock = 20Mhz\n"); + clk_disable_unprepare(i2c->clk); return err; } - writew(0, i2c_dev->base + REG_CR); - writew(MCR_APB_166M, i2c_dev->base + REG_MCR); - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); - writew(CR_ENABLE, i2c_dev->base + REG_CR); - readw(i2c_dev->base + REG_CSR); /* read clear */ - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + writew(0, i2c->base + VIAI2C_REG_CR); + writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR); + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); + writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR); + writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); + readw(i2c->base + VIAI2C_REG_CSR); /* read clear */ + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); - if (i2c_dev->tcr == TCR_FAST_MODE) - writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + if (i2c->tcr == VIAI2C_TCR_FAST) + writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR); else - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); + writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR); return 0; } @@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) static int wmt_i2c_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct wmt_i2c_dev *i2c_dev; + struct viai2c *i2c; struct i2c_adapter *adap; int err; u32 clk_rate; - err = wmt_i2c_init(pdev, &i2c_dev); + err = viai2c_init(pdev, &i2c); if (err) return err; - i2c_dev->clk = of_clk_get(np, 0); - if (IS_ERR(i2c_dev->clk)) { + i2c->clk = of_clk_get(np, 0); + if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "unable to request clock\n"); - return PTR_ERR(i2c_dev->clk); + return PTR_ERR(i2c->clk); } err = of_property_read_u32(np, "clock-frequency", &clk_rate); if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) - i2c_dev->tcr = TCR_FAST_MODE; + i2c->tcr = VIAI2C_TCR_FAST; - adap = &i2c_dev->adapter; - i2c_set_adapdata(adap, i2c_dev); + adap = &i2c->adapter; + i2c_set_adapdata(adap, i2c); strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); adap->owner = THIS_MODULE; adap->algo = &wmt_i2c_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - err = wmt_i2c_reset_hardware(i2c_dev); + err = wmt_i2c_reset_hardware(i2c); if (err) { dev_err(&pdev->dev, "error initializing hardware\n"); return err; @@ -111,19 +111,19 @@ static int wmt_i2c_probe(struct platform_device *pdev) err = i2c_add_adapter(adap); if (err) /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ - clk_disable_unprepare(i2c_dev->clk); + clk_disable_unprepare(i2c->clk); return err; } static void wmt_i2c_remove(struct platform_device *pdev) { - struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + struct viai2c *i2c = platform_get_drvdata(pdev); /* Disable interrupts, clock and delete adapter */ - writew(0, i2c_dev->base + REG_IMR); - clk_disable_unprepare(i2c_dev->clk); - i2c_del_adapter(&i2c_dev->adapter); + writew(0, i2c->base + VIAI2C_REG_IMR); + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adapter); } static const struct of_device_id wmt_i2c_dt_ids[] = { From patchwork Mon Apr 8 02:54:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787066 Received: from mx1.zhaoxin.com (MX1.ZHAOXIN.COM [210.0.225.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 791BF8475 for ; Mon, 8 Apr 2024 02:55:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.0.225.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544905; cv=none; b=qwcaIhZYx3OPVAcTRXxPKlwB3j+8Rrx15jjwB0yNiqFLK7e6wk2lBBnixlC9YLOQhf0liSMBNvptDPDvRarHVUmfldcitL8DoaZ9pAReTBKMBo6II450Njx+dZZjwsf/Fe4qq/cZeeHQa7Iqr5IUkb88clY8tOl3RSGwarI2ZF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544905; c=relaxed/simple; bh=M0A3T1qoqeDPx/w1hoUzXltwdzXzSGacJMLU90MA7Yc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HFqLbT42+rAyn8jqxTCofljo+0Zi9dOl2vfhrzusmTPaMbOm9qHErUXn9E0Fr0nISFmYLZ0chQtbTqSNZtOKvrRJwoBmAB4lVSEWczoYV0I59NqmefC/6BbZo5sgE38rIguwaqQXLlEJepJkt59oadKj4hE/mnMJwiJasj0f3Dw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=210.0.225.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544891-086e23661934350003-PT6Irj Received: from ZXSHMBX3.zhaoxin.com (ZXSHMBX3.zhaoxin.com [10.28.252.165]) by mx1.zhaoxin.com with ESMTP id WuAjz247YrgJ1ST5 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:52 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX3.zhaoxin.com (10.28.252.165) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:52 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:51 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.165 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked Date: Mon, 8 Apr 2024 10:54:46 +0800 X-ASG-Orig-Subj: [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked Message-ID: <4c1cf04bd240008df4ee98fe503aca157ff4fcb1.1712479417.git.hanshu-oc@zhaoxin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX3.zhaoxin.com[10.28.252.165] X-Barracuda-Start-Time: 1712544892 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.35:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 6896 X-Barracuda-BRTS-Status: 0 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- During each byte access, the host performs clock stretching. To reduce the host performs clock stretching, move most of the per-msg processing to the interrupt context. Suggested-by: Wolfram Sang Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- drivers/i2c/busses/i2c-viai2c-common.c | 145 +++++++++++++------------ drivers/i2c/busses/i2c-viai2c-common.h | 6 +- 2 files changed, 80 insertions(+), 71 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 59901c53ad48..1b39cf4f0d6c 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -18,37 +18,18 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c) return 0; } -int viai2c_check_status(struct viai2c *i2c) -{ - int ret = 0; - unsigned long time_left; - - time_left = wait_for_completion_timeout(&i2c->complete, - msecs_to_jiffies(500)); - if (!time_left) - return -ETIMEDOUT; - - if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR) - ret = -EIO; - - if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT) - ret = -ETIMEDOUT; - - return ret; -} - static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) { u16 val, tcr_val = i2c->tcr; - int ret; - int xfer_len = 0; + + i2c->last = last; if (pmsg->len == 0) { /* * We still need to run through the while (..) once, so * start at -1 and break out early from the loop */ - xfer_len = -1; + i2c->xfered_len = -1; writew(0, i2c->base + VIAI2C_REG_CDR); } else { writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); @@ -73,42 +54,15 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(val, i2c->base + VIAI2C_REG_CR); } - while (xfer_len < pmsg->len) { - ret = viai2c_check_status(i2c); - if (ret) - return ret; - - xfer_len++; - - val = readw(i2c->base + VIAI2C_REG_CSR); - if (val & VIAI2C_CSR_RCV_NOT_ACK) { - dev_dbg(i2c->dev, "write RCV NACK error\n"); - return -EIO; - } - - if (pmsg->len == 0) { - val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; - writew(val, i2c->base + VIAI2C_REG_CR); - break; - } - - if (xfer_len == pmsg->len) { - if (last != 1) - writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); - } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR); - writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); - } - } + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; - return 0; + return i2c->ret; } static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) { u16 val, tcr_val = i2c->tcr; - int ret; - u32 xfer_len = 0; val = readw(i2c->base + VIAI2C_REG_CR); val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); @@ -133,21 +87,10 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(val, i2c->base + VIAI2C_REG_CR); } - while (xfer_len < pmsg->len) { - ret = viai2c_check_status(i2c); - if (ret) - return ret; - - pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8; - xfer_len++; - - val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; - if (xfer_len == pmsg->len - 1) - val |= VIAI2C_CR_RX_END; - writew(val, i2c->base + VIAI2C_REG_CR); - } + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; - return 0; + return i2c->ret; } int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -165,6 +108,9 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return ret; } + i2c->msg = pmsg; + i2c->xfered_len = 0; + if (pmsg->flags & I2C_M_RD) ret = viai2c_read(i2c, pmsg); else @@ -174,15 +120,76 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return (ret < 0) ? ret : i; } +/* + * Main process of the byte mode xfer + * + * Return value indicates whether the transfer is complete + * 1: all the data has been successfully transferred + * 0: there is still data that needs to be transferred + * -EIO: error occurred + */ +static int viai2c_irq_xfer(struct viai2c *i2c) +{ + u16 val; + struct i2c_msg *msg = i2c->msg; + u8 read = msg->flags & I2C_M_RD; + void __iomem *base = i2c->base; + + if (read) { + msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8; + + val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; + if (i2c->xfered_len == msg->len - 2) + val |= VIAI2C_CR_RX_END; + writew(val, base + VIAI2C_REG_CR); + } else { + val = readw(base + VIAI2C_REG_CSR); + if (val & VIAI2C_CSR_RCV_NOT_ACK) + return -EIO; + + /* I2C_SMBUS_QUICK */ + if (msg->len == 0) { + val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; + writew(val, base + VIAI2C_REG_CR); + return 1; + } + + if ((i2c->xfered_len + 1) == msg->len) { + if (!i2c->last) + writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + } else { + writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); + writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + } + } + + i2c->xfered_len++; + + return i2c->xfered_len == msg->len; +} + static irqreturn_t viai2c_isr(int irq, void *data) { struct viai2c *i2c = data; + u8 status; /* save the status and write-clear it */ - i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR); - writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR); + status = readw(i2c->base + VIAI2C_REG_ISR); + writew(status, i2c->base + VIAI2C_REG_ISR); + + i2c->ret = 0; + if (status & VIAI2C_ISR_NACK_ADDR) + i2c->ret = -EIO; + + if (status & VIAI2C_ISR_SCL_TIMEOUT) + i2c->ret = -ETIMEDOUT; + + if (!i2c->ret) + i2c->ret = viai2c_irq_xfer(i2c); - complete(&i2c->complete); + /* All the data has been successfully transferred or error occurred */ + if (i2c->ret) + complete(&i2c->complete); return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index 28799e7e97f0..c92e054ac7e7 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -58,11 +58,13 @@ struct viai2c { struct clk *clk; u16 tcr; int irq; - u16 cmd_status; + u16 xfered_len; + struct i2c_msg *msg; + int ret; + bool last; }; int viai2c_wait_bus_not_busy(struct viai2c *i2c); -int viai2c_check_status(struct viai2c *i2c); int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c); From patchwork Mon Apr 8 02:54:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787067 Received: from mx1.zhaoxin.com (MX1.ZHAOXIN.COM [210.0.225.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA697847B for ; Mon, 8 Apr 2024 02:55:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.0.225.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544904; cv=none; b=kEE6oAZn1Bn7S4/piXZYMv6A+5T/6qQhhvvZu959up4QbgHC6VDALmT3V+03gOa/7e7AcGJz1jdTHojSyF2fKPLveeZTjICzHSlGsYL5EvIxByhyggpZU1aWvvA1mtYx8z1h7JYeVOjaXuJqVcbtbdu4a1MAYK360lH2lp3DzrU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544904; c=relaxed/simple; bh=QBkP/YG4kdVt34iPTAjmFk33v/xqeHhCMaHoSi8i9TA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ULGX4wVZ50FTIUiDFfMWjxX4eD1+FahgqXUwPgyth64EVhOUyuu31tsQ+ND3aVCrOvR92Z+Mzb/0UKyaxHCsPlPSa6L4CmCsXse86yNWrMqEuQnfVoOLD0PDn1ECyIHmGbSjwFm69VvKt3Hu4Y+S7Tp748ah/7kLdllxSns3Xb4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=210.0.225.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544893-086e23661834350001-PT6Irj Received: from ZXSHMBX2.zhaoxin.com (ZXSHMBX2.zhaoxin.com [10.28.252.164]) by mx1.zhaoxin.com with ESMTP id iCTaZIIRnim1x9ah (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:53 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.164 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX2.zhaoxin.com (10.28.252.164) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:53 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:52 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.164 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Date: Mon, 8 Apr 2024 10:54:47 +0800 X-ASG-Orig-Subj: [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Message-ID: <7c8f75dc368be5eca1b368998d78b743487b8b89.1712479417.git.hanshu-oc@zhaoxin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX2.zhaoxin.com[10.28.252.164] X-Barracuda-Start-Time: 1712544893 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.35:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 5565 X-Barracuda-BRTS-Status: 0 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- Enumeration variables are added to differentiate between different platforms. Acked-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- drivers/i2c/busses/i2c-viai2c-common.c | 32 ++++++++++++++++---------- drivers/i2c/busses/i2c-viai2c-common.h | 7 +++++- drivers/i2c/busses/i2c-viai2c-wmt.c | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 1b39cf4f0d6c..22a2e31e9c14 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -35,7 +35,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); } - if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { val = readw(i2c->base + VIAI2C_REG_CR); val &= ~VIAI2C_CR_TX_END; val |= VIAI2C_CR_CPU_RDY; @@ -48,7 +48,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (pmsg->flags & I2C_M_NOSTART) { + if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -67,7 +67,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) val = readw(i2c->base + VIAI2C_REG_CR); val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); - if (!(pmsg->flags & I2C_M_NOSTART)) + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) val |= VIAI2C_CR_CPU_RDY; if (pmsg->len == 1) @@ -81,7 +81,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (pmsg->flags & I2C_M_NOSTART) { + if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -102,7 +102,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; - if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { ret = viai2c_wait_bus_not_busy(i2c); if (ret < 0) return ret; @@ -155,7 +155,7 @@ static int viai2c_irq_xfer(struct viai2c *i2c) } if ((i2c->xfered_len + 1) == msg->len) { - if (!i2c->last) + if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last) writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); } else { writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); @@ -181,7 +181,7 @@ static irqreturn_t viai2c_isr(int irq, void *data) if (status & VIAI2C_ISR_NACK_ADDR) i2c->ret = -EIO; - if (status & VIAI2C_ISR_SCL_TIMEOUT) + if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT)) i2c->ret = -ETIMEDOUT; if (!i2c->ret) @@ -194,9 +194,10 @@ static irqreturn_t viai2c_isr(int irq, void *data) return IRQ_HANDLED; } -int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) { int err; + int irq_flags; struct viai2c *i2c; struct device_node *np = pdev->dev.of_node; @@ -208,12 +209,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); - i2c->irq = irq_of_parse_and_map(np, 0); - if (!i2c->irq) - return -EINVAL; + if (plat == VIAI2C_PLAT_WMT) { + irq_flags = 0; + i2c->irq = irq_of_parse_and_map(np, 0); + if (!i2c->irq) + return -EINVAL; + } else { + return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n"); + } + + i2c->platform = plat; err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr, - 0, pdev->name, i2c); + irq_flags, pdev->name, i2c); if (err) return dev_err_probe(&pdev->dev, err, "failed to request irq %i\n", i2c->irq); diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index c92e054ac7e7..cfe5ab2bd779 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -50,6 +50,10 @@ #define VIAI2C_TIMEOUT (msecs_to_jiffies(1000)) +enum { + VIAI2C_PLAT_WMT, +}; + struct viai2c { struct i2c_adapter adapter; struct completion complete; @@ -62,10 +66,11 @@ struct viai2c { struct i2c_msg *msg; int ret; bool last; + unsigned int platform; }; int viai2c_wait_bus_not_busy(struct viai2c *i2c); int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); -int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c); +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 1e9db735e1fa..e1988f946026 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev) int err; u32 clk_rate; - err = viai2c_init(pdev, &i2c); + err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); if (err) return err; From patchwork Mon Apr 8 02:54:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans Hu X-Patchwork-Id: 787300 Received: from mx1.zhaoxin.com (MX1.ZHAOXIN.COM [210.0.225.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2377F8494 for ; Mon, 8 Apr 2024 02:55:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.0.225.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544906; cv=none; b=YhydW5hgCwV3fLBeUN6wKxcCxjLHLGZiEXcfefYz2kesdJQcaMjY4v8KAT3ZS3Q8WTODTo4EWjSjvL64fGrz2v3IpNHm2eU0cf8644D/Nl7FGRh6ww5Qo4NQhyEFtU5t+52TcGRPWIryj9a772OtvK0uVfMnpPu62kkRO40wQzg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712544906; c=relaxed/simple; bh=2/6e5h1maycnkzbtvKi6EnYvv4W+DeAopb/rb8P7DeA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pyCkgatSSSqHrG+sAan3OKpstoRrUrxNo17np8c33h1vTHwscnZxdwzRNrOW+he1OEhZ/sTDhKeqqZVbFd/nGtnGhoBSqZPbV2J5AOoDGFvpJE6pW91ipI2YtV0s48TWcWsbbuui7Fph9Hc/X4B4wlREiAF+Z8pg9sa9wfWsaUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com; spf=pass smtp.mailfrom=zhaoxin.com; arc=none smtp.client-ip=210.0.225.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zhaoxin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zhaoxin.com X-ASG-Debug-ID: 1712544893-086e23661834350002-PT6Irj Received: from ZXSHMBX2.zhaoxin.com (ZXSHMBX2.zhaoxin.com [10.28.252.164]) by mx1.zhaoxin.com with ESMTP id ln0raOdiRyMKkrFx (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO); Mon, 08 Apr 2024 10:54:53 +0800 (CST) X-Barracuda-Envelope-From: HansHu-oc@zhaoxin.com X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.164 Received: from ZXBJMBX03.zhaoxin.com (10.29.252.7) by ZXSHMBX2.zhaoxin.com (10.28.252.164) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:53 +0800 Received: from ml-HP-ProDesk-680-G4-MT.zhaoxin.com (10.28.66.68) by ZXBJMBX03.zhaoxin.com (10.29.252.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Mon, 8 Apr 2024 10:54:52 +0800 X-Barracuda-RBL-Trusted-Forwarder: 10.28.252.164 From: Hans Hu X-Barracuda-RBL-Trusted-Forwarder: 10.29.252.7 To: , CC: , , , "Wolfram Sang" Subject: [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver Date: Mon, 8 Apr 2024 10:54:48 +0800 X-ASG-Orig-Subj: [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver Message-ID: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: zxbjmbx1.zhaoxin.com (10.29.252.163) To ZXBJMBX03.zhaoxin.com (10.29.252.7) X-Barracuda-Connect: ZXSHMBX2.zhaoxin.com[10.28.252.164] X-Barracuda-Start-Time: 1712544893 X-Barracuda-Encrypted: ECDHE-RSA-AES128-GCM-SHA256 X-Barracuda-URL: https://10.28.252.35:4443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at zhaoxin.com X-Barracuda-Scan-Msg-Size: 16095 X-Barracuda-BRTS-Status: 1 X-Barracuda-Bayes: INNOCENT GLOBAL 0.0000 1.0000 -2.0210 X-Barracuda-Spam-Score: -2.02 X-Barracuda-Spam-Status: No, SCORE=-2.02 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=9.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.123213 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- Add Zhaoxin I2C controller driver. It provides the access to the i2c busses, which connects to the touchpad, eeprom, I2S, etc. Zhaoxin I2C controller has two separate busses, so may accommodate up to two I2C adapters. Those adapters are listed in the ACPI namespace with the IIC1D17 HID, and probed by a platform driver. The driver works with IRQ mode, and supports basic I2C features. Flags I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit the unsupported access. Acked-by: Wolfram Sang Signed-off-by: Andi Shyti Signed-off-by: Hans Hu --- MAINTAINERS | 8 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 2 + drivers/i2c/busses/i2c-viai2c-common.c | 31 ++- drivers/i2c/busses/i2c-viai2c-common.h | 9 + drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 ++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 5 deletions(-) create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c diff --git a/MAINTAINERS b/MAINTAINERS index 97fcb8d38210..134c83409a3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10265,6 +10265,14 @@ L: linux-i2c@vger.kernel.org F: Documentation/i2c/busses/i2c-ismt.rst F: drivers/i2c/busses/i2c-ismt.c +I2C/SMBUS ZHAOXIN DRIVER +M: Hans Hu +L: linux-i2c@vger.kernel.org +S: Maintained +W: https://www.zhaoxin.com +F: drivers/i2c/busses/i2c-viai2c-common.c +F: drivers/i2c/busses/i2c-viai2c-zhaoxin.c + I2C/SMBUS STUB DRIVER M: Jean Delvare L: linux-i2c@vger.kernel.org diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 97989c914260..cc781f8ec714 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -336,6 +336,16 @@ config I2C_VIAPRO if ACPI +config I2C_ZHAOXIN + tristate "Zhaoxin I2C Interface" + depends on PCI || COMPILE_TEST + help + If you say yes to this option, support will be included for the + ZHAOXIN I2C interface + + This driver can also be built as a module. If so, the module + will be called i2c-zhaoxin. + comment "ACPI drivers" config I2C_SCMI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 63c7bbad8134..3d65934f5eb4 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o +i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o +obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o # Mac SMBus host controller drivers obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 22a2e31e9c14..1844d13f1f79 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) return i2c->ret; } -static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) +static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first) { u16 val, tcr_val = i2c->tcr; @@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) { + if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) || + (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int ret = 0; struct viai2c *i2c = i2c_get_adapdata(adap); + i2c->mode = VIAI2C_BYTE_MODE; for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { @@ -112,7 +114,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c->xfered_len = 0; if (pmsg->flags & I2C_M_RD) - ret = viai2c_read(i2c, pmsg); + ret = viai2c_read(i2c, pmsg, i == 0); else ret = viai2c_write(i2c, pmsg, (i + 1) == num); } @@ -157,6 +159,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c) if ((i2c->xfered_len + 1) == msg->len) { if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last) writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last) + writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR); } else { writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); @@ -168,6 +172,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c) return i2c->xfered_len == msg->len; } +int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) +{ + return 0; +} + static irqreturn_t viai2c_isr(int irq, void *data) { struct viai2c *i2c = data; @@ -175,6 +184,9 @@ static irqreturn_t viai2c_isr(int irq, void *data) /* save the status and write-clear it */ status = readw(i2c->base + VIAI2C_REG_ISR); + if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN) + return IRQ_NONE; + writew(status, i2c->base + VIAI2C_REG_ISR); i2c->ret = 0; @@ -184,8 +196,12 @@ static irqreturn_t viai2c_isr(int irq, void *data) if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT)) i2c->ret = -ETIMEDOUT; - if (!i2c->ret) - i2c->ret = viai2c_irq_xfer(i2c); + if (!i2c->ret) { + if (i2c->mode == VIAI2C_BYTE_MODE) + i2c->ret = viai2c_irq_xfer(i2c); + else + i2c->ret = viai2c_fifo_irq_xfer(i2c, true); + } /* All the data has been successfully transferred or error occurred */ if (i2c->ret) @@ -214,6 +230,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) i2c->irq = irq_of_parse_and_map(np, 0); if (!i2c->irq) return -EINVAL; + } else if (plat == VIAI2C_PLAT_ZHAOXIN) { + irq_flags = IRQF_SHARED; + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) + return i2c->irq; } else { return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n"); } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index cfe5ab2bd779..81e827c54434 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -52,6 +52,12 @@ enum { VIAI2C_PLAT_WMT, + VIAI2C_PLAT_ZHAOXIN +}; + +enum { + VIAI2C_BYTE_MODE, + VIAI2C_FIFO_MODE }; struct viai2c { @@ -66,11 +72,14 @@ struct viai2c { struct i2c_msg *msg; int ret; bool last; + unsigned int mode; unsigned int platform; + void *pltfm_priv; }; int viai2c_wait_bus_not_busy(struct viai2c *i2c); int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat); +int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c new file mode 100644 index 000000000000..7e3ac2a3e1fd --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation. + * All rights reserved. + */ + +#include +#include "i2c-viai2c-common.h" + +/* + * registers + */ +/* Zhaoxin specific register bit fields */ +/* REG_CR Bit fields */ +#define ZXI2C_CR_MST_RST BIT(7) +#define ZXI2C_CR_FIFO_MODE BIT(14) +/* REG_ISR/IMR Bit fields */ +#define ZXI2C_IRQ_FIFONACK BIT(4) +#define ZXI2C_IRQ_FIFOEND BIT(3) +#define ZXI2C_IRQ_MASK (VIAI2C_ISR_MASK_ALL \ + | ZXI2C_IRQ_FIFOEND \ + | ZXI2C_IRQ_FIFONACK) +/* Zhaoxin specific registers */ +#define ZXI2C_REG_CLK 0x10 +#define ZXI2C_CLK_50M BIT(0) +#define ZXI2C_REG_REV 0x11 +#define ZXI2C_REG_HCR 0x12 +#define ZXI2C_HCR_RST_FIFO GENMASK(1, 0) +#define ZXI2C_REG_HTDR 0x13 +#define ZXI2C_REG_HRDR 0x14 +#define ZXI2C_REG_HTLR 0x15 +#define ZXI2C_REG_HRLR 0x16 +#define ZXI2C_REG_HWCNTR 0x18 +#define ZXI2C_REG_HRCNTR 0x19 + +/* parameters Constants */ +#define ZXI2C_GOLD_FSTP_100K 0xF3 +#define ZXI2C_GOLD_FSTP_400K 0x38 +#define ZXI2C_GOLD_FSTP_1M 0x13 +#define ZXI2C_GOLD_FSTP_3400K 0x37 +#define ZXI2C_HS_MASTER_CODE (0x08 << 8) + +#define ZXI2C_FIFO_SIZE 32 + +struct viai2c_zhaoxin { + u8 hrv; + u16 tr; + u16 mcr; + u16 xfer_len; +}; + +/* 'irq == true' means in interrupt context */ +int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) +{ + u16 i; + u8 tmp; + struct i2c_msg *msg = i2c->msg; + void __iomem *base = i2c->base; + bool read = !!(msg->flags & I2C_M_RD); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + if (irq) { + /* get the received data */ + if (read) + for (i = 0; i < priv->xfer_len; i++) + msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR); + + i2c->xfered_len += priv->xfer_len; + if (i2c->xfered_len == msg->len) + return 1; + } + + /* reset fifo buffer */ + tmp = ioread8(base + ZXI2C_REG_HCR); + iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR); + + /* set xfer len */ + priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE); + if (read) { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR); + } else { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR); + /* set write data */ + for (i = 0; i < priv->xfer_len; i++) + iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR); + } + + /* prepare to stop transmission */ + if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) { + tmp = ioread8(base + VIAI2C_REG_CR); + tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END; + iowrite8(tmp, base + VIAI2C_REG_CR); + } + + if (irq) { + /* continue transmission */ + tmp = ioread8(base + VIAI2C_REG_CR); + iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR); + } else { + u16 tcr_val = i2c->tcr; + + /* start transmission */ + tcr_val |= read ? VIAI2C_TCR_READ : 0; + writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR); + } + + return 0; +} + +static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + u8 tmp; + int ret; + struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + void __iomem *base = i2c->base; + + ret = viai2c_wait_bus_not_busy(i2c); + if (ret) + return ret; + + tmp = ioread8(base + VIAI2C_REG_CR); + tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END); + + if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) { + /* enable fifo mode */ + iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable fifo irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR); + + i2c->msg = msgs; + i2c->mode = VIAI2C_FIFO_MODE; + priv->xfer_len = 0; + i2c->xfered_len = 0; + + viai2c_fifo_irq_xfer(i2c, 0); + + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; + + ret = i2c->ret; + } else { + /* enable byte mode */ + iowrite16(tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable byte irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR); + + ret = viai2c_xfer(adap, msgs, num); + if (ret == -ETIMEDOUT) + iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR); + } + /* dis interrupt */ + iowrite8(0, base + VIAI2C_REG_IMR); + + return ret; +} + +static u32 zxi2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm zxi2c_algorithm = { + .master_xfer = zxi2c_master_xfer, + .functionality = zxi2c_func, +}; + +static const struct i2c_adapter_quirks zxi2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ, +}; + +static const u32 zxi2c_speed_params_table[][3] = { + /* speed, ZXI2C_TCR, ZXI2C_FSTP */ + { I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K }, + { I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K }, + { I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M }, + { I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST, + ZXI2C_GOLD_FSTP_3400K }, +}; + +static void zxi2c_set_bus_speed(struct viai2c *i2c) +{ + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR); + iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK); + iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR); +} + +static void zxi2c_get_bus_speed(struct viai2c *i2c) +{ + u8 i, count; + u8 fstp; + const u32 *params; + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev); + + count = ARRAY_SIZE(zxi2c_speed_params_table); + for (i = 0; i < count; i++) + if (acpi_speed == zxi2c_speed_params_table[i][0]) + break; + /* if not found, use 400k as default */ + i = i < count ? i : 1; + + params = zxi2c_speed_params_table[i]; + fstp = ioread8(i2c->base + VIAI2C_REG_TR); + if (abs(fstp - params[2]) > 0x10) { + /* + * if BIOS setting value far from golden value, + * use golden value and warn user + */ + dev_warn(i2c->dev, "FW FSTP[%x] might cause wrong timings, dropped\n", fstp); + priv->tr = params[2] | 0xff00; + } else { + priv->tr = fstp | 0xff00; + } + + i2c->tcr = params[1]; + priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR); + /* for Hs-mode, use 0x80 as master code */ + if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ) + priv->mcr |= ZXI2C_HS_MASTER_CODE; + + dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0])); +} + +static int zxi2c_probe(struct platform_device *pdev) +{ + int error; + struct viai2c *i2c; + struct i2c_adapter *adap; + struct viai2c_zhaoxin *priv; + + error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN); + if (error) + return error; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + i2c->pltfm_priv = priv; + + zxi2c_get_bus_speed(i2c); + zxi2c_set_bus_speed(i2c); + + priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV); + + adap = &i2c->adapter; + adap->owner = THIS_MODULE; + adap->algo = &zxi2c_algorithm; + adap->quirks = &zxi2c_quirks; + adap->dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); + snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s", + dev_name(pdev->dev.parent), dev_name(i2c->dev)); + i2c_set_adapdata(adap, i2c); + + return devm_i2c_add_adapter(&pdev->dev, adap); +} + +static int __maybe_unused zxi2c_resume(struct device *dev) +{ + struct viai2c *i2c = dev_get_drvdata(dev); + + iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR); + zxi2c_set_bus_speed(i2c); + + return 0; +} + +static const struct dev_pm_ops zxi2c_pm = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume) +}; + +static const struct acpi_device_id zxi2c_acpi_match[] = { + {"IIC1D17", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match); + +static struct platform_driver zxi2c_driver = { + .probe = zxi2c_probe, + .driver = { + .name = "i2c_zhaoxin", + .acpi_match_table = zxi2c_acpi_match, + .pm = &zxi2c_pm, + }, +}; + +module_platform_driver(zxi2c_driver); + +MODULE_AUTHOR("HansHu@zhaoxin.com"); +MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver"); +MODULE_LICENSE("GPL");