get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2194235/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2194235,
    "url": "http://patchwork.ozlabs.org/api/patches/2194235/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-i2c/patch/20260207-b4-k3-i2c-pio-v7-2-626942d94d91@linux.spacemit.com/",
    "project": {
        "id": 35,
        "url": "http://patchwork.ozlabs.org/api/projects/35/?format=api",
        "name": "Linux I2C development",
        "link_name": "linux-i2c",
        "list_id": "linux-i2c.vger.kernel.org",
        "list_email": "linux-i2c@vger.kernel.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260207-b4-k3-i2c-pio-v7-2-626942d94d91@linux.spacemit.com>",
    "list_archive_url": null,
    "date": "2026-02-07T15:08:22",
    "name": "[v7,2/2] i2c: spacemit: introduce pio for k1",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "4a0cf17e6bca8bc54dc8ff0d44a0e31596413c61",
    "submitter": {
        "id": 91240,
        "url": "http://patchwork.ozlabs.org/api/people/91240/?format=api",
        "name": "Troy Mitchell",
        "email": "troy.mitchell@linux.spacemit.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-i2c/patch/20260207-b4-k3-i2c-pio-v7-2-626942d94d91@linux.spacemit.com/mbox/",
    "series": [
        {
            "id": 491382,
            "url": "http://patchwork.ozlabs.org/api/series/491382/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-i2c/list/?series=491382",
            "date": "2026-02-07T15:08:20",
            "name": "i2c: spacemit: introduce pio for k1",
            "version": 7,
            "mbox": "http://patchwork.ozlabs.org/series/491382/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2194235/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2194235/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <linux-i2c+bounces-15896-incoming=patchwork.ozlabs.org@vger.kernel.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-i2c@vger.kernel.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=linux.spacemit.com header.i=@linux.spacemit.com\n header.a=rsa-sha256 header.s=mxsw2412 header.b=UFzxJPiA;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.232.135.74; helo=sto.lore.kernel.org;\n envelope-from=linux-i2c+bounces-15896-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=linux.spacemit.com\n header.i=@linux.spacemit.com header.b=\"UFzxJPiA\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=18.169.211.239",
            "smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=linux.spacemit.com",
            "smtp.subspace.kernel.org;\n spf=none smtp.mailfrom=linux.spacemit.com"
        ],
        "Received": [
            "from sto.lore.kernel.org (sto.lore.kernel.org [172.232.135.74])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f7ZCN23Bwz1xvh\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 08 Feb 2026 02:10:40 +1100 (AEDT)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id 5EB7C30055BE\n\tfor <incoming@patchwork.ozlabs.org>; Sat,  7 Feb 2026 15:10:37 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 117A6352FA6;\n\tSat,  7 Feb 2026 15:10:34 +0000 (UTC)",
            "from smtpbg151.qq.com (smtpbg151.qq.com [18.169.211.239])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 602DB352F9E;\n\tSat,  7 Feb 2026 15:10:31 +0000 (UTC)",
            "from = ( [localhost])\n\tby bizesmtp.qq.com (ESMTP) with\n\tid ; Sat, 07 Feb 2026 23:08:30 +0800 (CST)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1770477033; cv=none;\n b=avTXn2Fcy4r5uayWqy/JdYqXsZT+qAlYvgHwl8iAm6M5z805iToYwWJiijMsayfBzv+MhIlo5WpCQOYDpANsNJGz5IkvBoGO521OBbwkCNwsbAQPN4JmSJQfIO2kr7ZZ70kYt/2b1o6L67yLkFIDgjTqf2lFG370ylpqK+hqzwU=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1770477033; c=relaxed/simple;\n\tbh=XfPIQa1n40k4DtDFLExyqh9x4NVudCjNtkjrXUxfOM4=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=gF9ptiXcM4v78qGs5DLZY3E6jLsWnk0v572zkwOLLAv/+3TGszbgB1uBYxPLG+VbS++SjRPZ42PP+poCz9xXuMD2LM8nLAhPwOl/Egef+AFK/kbDxNpI7EXamMSlrm4+k+mXYlW7J7fIiRzGuIo0wF2fwN75sqZhHODGEsB8604=",
        "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=linux.spacemit.com;\n spf=none smtp.mailfrom=linux.spacemit.com;\n dkim=pass (1024-bit key) header.d=linux.spacemit.com\n header.i=@linux.spacemit.com header.b=UFzxJPiA;\n arc=none smtp.client-ip=18.169.211.239",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.spacemit.com;\n\ts=mxsw2412; t=1770476913;\n\tbh=cbEqZrd+eE8o0+V2y9USilf9Tl2MxDFayuDIynRwzC4=;\n\th=From:Date:Subject:MIME-Version:Message-Id:To;\n\tb=UFzxJPiAUjy0aMMkU7iNNKsW6Ismx5z0+WM0+WUG23VswYK2H9MG8E8Bfk2dGtEtM\n\t DeXOsDd7fvS+S5JM8QdGAi2q8DMw85ogXP8Cw3UlHQFPw/QkmLNbIwXYFf1ke2b+YQ\n\t zH2sY/T/bQvUzNmtqMfAF8F+d5g43SN1omu8tUgc=",
        "X-QQ-mid": "zesmtpip4t1770476912tbef9ec7a",
        "X-QQ-Originating-IP": "vw66bwuyFVu3Pk4lOVZ93jjvDuqgSxReQjqwZN7Uwps=",
        "X-QQ-SSF": "0000000000000000000000000000000",
        "X-QQ-GoodBg": "0",
        "X-BIZMAIL-ID": "18296168246919023479",
        "EX-QQ-RecipientCnt": "8",
        "From": "Troy Mitchell <troy.mitchell@linux.spacemit.com>",
        "Date": "Sat, 07 Feb 2026 23:08:22 +0800",
        "Subject": "[PATCH v7 2/2] i2c: spacemit: introduce pio for k1",
        "Precedence": "bulk",
        "X-Mailing-List": "linux-i2c@vger.kernel.org",
        "List-Id": "<linux-i2c.vger.kernel.org>",
        "List-Subscribe": "<mailto:linux-i2c+subscribe@vger.kernel.org>",
        "List-Unsubscribe": "<mailto:linux-i2c+unsubscribe@vger.kernel.org>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20260207-b4-k3-i2c-pio-v7-2-626942d94d91@linux.spacemit.com>",
        "References": "<20260207-b4-k3-i2c-pio-v7-0-626942d94d91@linux.spacemit.com>",
        "In-Reply-To": "<20260207-b4-k3-i2c-pio-v7-0-626942d94d91@linux.spacemit.com>",
        "To": "Andi Shyti <andi.shyti@kernel.org>, Yixun Lan <dlan@gentoo.org>",
        "Cc": "linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org,\n linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,\n Troy Mitchell <troy.mitchell@linux.spacemit.com>,\n Aurelien Jarno <aurelien@aurel32.net>",
        "X-Mailer": "b4 0.14.3",
        "X-Developer-Signature": "v=1; a=ed25519-sha256; t=1770476904; l=17056;\n i=troy.mitchell@linux.spacemit.com; s=20250712; h=from:subject:message-id;\n bh=XfPIQa1n40k4DtDFLExyqh9x4NVudCjNtkjrXUxfOM4=;\n b=XIY4R0qzj1xusVZzihXzER85wSRM7WzaTl1oVUYJFuG7TIXeEs2LcJkkKrNlcoWI+dTRnAxKZ\n oGRgFjUtEi3AkwereTE8OP4fTDYRuwKBa4IYZ5pGBiuz5kZSrBdyzJe",
        "X-Developer-Key": "i=troy.mitchell@linux.spacemit.com; a=ed25519;\n pk=zhRP1xE0bftrurqSWI+SzcSdJGIZ0BTTY9Id0ESzqlI=",
        "X-QQ-SENDSIZE": "520",
        "Feedback-ID": "zesmtpip:linux.spacemit.com:qybglogicsvrgz:qybglogicsvrgz3a-0",
        "X-QQ-XMAILINFO": "N1fXDe1nQuLqzJzJOUTbdH9h9jBP7c8qePKUzi9lLqp7NJW/cdnK4SDM\n\tOv7xtkjxgUqkJbUCzZVNWEAA//WadqOeRj3d7Yvmx1Ibfteccn8eXQWk30GW0zEH/DnAKKF\n\tgq/ars2tRCDRDyafnTWdKbpEmU1mzThCmSRgM4ISdFt3qsbfvC4Ay1Qg5kO1MklkyeXTaBH\n\t4fnUb23QlCFB5SAgCHo3SncwI6jK80TaIWpQRIpSHv8cBx9TQaV0F6mLYn4QaYBdSN5yqhp\n\tcu8AIKtjcFiM+FWZs4ELu/qHSP+h+vUN5IMbcQjT+RiH2l8n40WS9g7HPwE62l2K/XDyqiE\n\thRRH3+n9/P4XFQuyeM3TpT2FT36q0NQTH+BQmLWp1YLSArdH1pdCfXUxUkknKDTKEqT8wSm\n\tDiW30X40xAeQgjhsmB97XPglHIIPXZUo0qnkYHU9w4BU9g84/2zr9PE5KzJtASzM4/gpv7Q\n\thhlDuU+SC+92LBt719y2Az5MEjejRPsaqlR+hYaQhehI93VCSu7otgfWPhEfkKBZ+bCJDp+\n\tyz4MgqiVG8N+JTGMGifUDweUQ+Fb36cgxHxVe8Ua+CAbcHv8ktFO34bpuPLs1ezckfbsQID\n\tigD2VnolVw9FgntHILbxKGAsJCpduRWuWehmTbW27nzqBGoNqZDscOvAM+sNcbfCbg1/Tcu\n\tUEEiSlu3gk0jqLtH//eQlDfaZzjkg3UeMAow4B+e2LqPugXaD4PiY7ehwQeUngSS/hzjAar\n\tz8KFYIm5AUuL6l5rr/tjFN5HRCl5CTPAZ8vplCfRfPd26gBuuLoRUgOmvwCfpijrPaN/UJ0\n\tRw+Pr2E6qPh92W+bwq9HkGx/FXsyokDuNGpvJQDSJCIMqxhcVQSe68ZftKM1l12SuU5nqQb\n\tkYRMG7GMreDpIIgEB04H6x2YbSEr8DlBL99Nv2AQhpH8YA3rT7jeCYMQfCu1HSMRb+D3Y1J\n\tf9V75cUztQmUBrerpSi+nqi+ZoZ/H/EoUMdR1X1+FhordfRmM1xvj9Vwt1uL6McFnrXVWCL\n\t9Li7+DaKm18dIU4b9etg4elYkn8PmagoBIIaTicV+1YxFE23ud4DstSeog39oxHURAz4FB5\n\tRrC4Ti9lZoGjVGGjvy88tkZaDJLKCiT6Y5dadOYSXIIh3ljmgqyhMnbEpvDjlFiidBvgldc\n\tcEVaZ3Flqd110OylhwDgu5S1uMrP0pXmIn+fqghV9c46OSvebs5z3IPHOQ==",
        "X-QQ-XMRINFO": "M/715EihBoGS47X28/vv4NpnfpeBLnr4Qg==",
        "X-QQ-RECHKSPAM": "0"
    },
    "content": "This patch introduces I2C PIO functionality for the Spacemit K1 SoC,\nenabling the use of I2C in atomic context.\n\nWhen i2c xfer_atomic is invoked, use_pio is set accordingly.\n\nSince an atomic context is required, all interrupts are disabled when\noperating in PIO mode. Even with interrupts disabled, the bits in the\nISR (Interrupt Status Register) will still be set, so error handling can\nbe performed by polling the relevant status bits in the ISR.\n\nSigned-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>\nTested-by: Aurelien Jarno <aurelien@aurel32.net>\nReviewed-by: Aurelien Jarno <aurelien@aurel32.net>\n---\nChanges in v7:\n- optimize register access in spacemit_i2c_handle_state() by moving readl() inside the non-idle check\n- refactor loop logic in spacemit_i2c_wait_pio_xfer() for better readability\n- simplify spacemit_i2c_delay() to use fsleep() and remove redundant range arguments\n- fix multi-line comment style and remove unnecessary blank lin\n- Link to v6: https://lore.kernel.org/all/20260108-k1-i2c-atomic-v6-2-41b132b70f68@linux.spacemit.com/\n\nChanges in v6:\n- modify code style\n- modify and add comments\n- Link to v5: https://lore.kernel.org/all/20251226-k1-i2c-atomic-v5-2-023c798c5523@linux.spacemit.com/\n\nChanges in v5:\n- optimize code logic\n- refactor delay handling into spacemit_i2c_delay() helper\n- introduce spacemit_i2c_complete() to centralize transfer completion\n- rework PIO transfer wait logic for clarity and correctness\n- modify and add some comments\n- modify commit message\n- Link to v4: https://lore.kernel.org/all/20251009-k1-i2c-atomic-v4-1-a89367870286@linux.spacemit.com/\n\nChanges in v4:\n- refactor for better readability: simplify condition check and moving if/else (timeout/\n  wait_xfer_complete) logic into a function\n- remove irrelevant changes\n- remove the status clear call in spacemit_i2c_xfer_common()\n- sort functions to avoid forward declarations,\n  move unavoidable ones above function definitions\n- use udelay() in atomic context to avoid sleeping\n- wait for MSD on the last byte in wait_pio_xfer()\n- Link to v3: https://lore.kernel.org/r/20250929-k1-i2c-atomic-v3-1-f7e660c138b6@linux.spacemit.com\n\nChanges in v3:\n- drop 1-5 patches (have been merged)\n- modify commit message\n- use readl_poll_timeout_atomic() in wait_pio_xfer()\n- use msecs_to_jiffies() when get PIO mode timeout value\n- factor out transfer state handling into spacemit_i2c_handle_state().\n- do not disable/enable the controller IRQ around PIO transfers.\n- consolidate spacemit_i2c_init() interrupt setup\n- rename is_pio -> use_pio\n- rename spacemit_i2c_xfer() -> spacemit_i2c_xfer_common()\n- rename spacemit_i2c_int_xfer() -> spacemit_i2c_xfer()\n- rename spacemit_i2c_pio_xfer() -> spacemit_i2c_pio_xfer_atomic()\n- call spacemit_i2c_err_check() in wait_pio_xfer() when write last byte\n- Link to v2: https://lore.kernel.org/r/20250925-k1-i2c-atomic-v2-0-46dc13311cda@linux.spacemit.com\n\nChanges in v2:\n- add is_pio judgement in irq_handler()\n- use a fixed timeout value when PIO\n- use readl_poll_timeout() in  spacemit_i2c_wait_bus_idle() when PIO\n- Link to v1: https://lore.kernel.org/r/20250827-k1-i2c-atomic-v1-0-e59bea02d680@linux.spacemit.com\n---\n drivers/i2c/busses/i2c-k1.c | 300 +++++++++++++++++++++++++++++++++-----------\n 1 file changed, 228 insertions(+), 72 deletions(-)",
    "diff": "diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c\nindex accef6653b56..2e2669a7a9b5 100644\n--- a/drivers/i2c/busses/i2c-k1.c\n+++ b/drivers/i2c/busses/i2c-k1.c\n@@ -97,6 +97,10 @@\n \n #define SPACEMIT_BUS_RESET_CLK_CNT_MAX\t\t9\n \n+#define SPACEMIT_WAIT_TIMEOUT      1000 /* ms */\n+#define SPACEMIT_POLL_TIMEOUT      1000 /* us */\n+#define SPACEMIT_POLL_INTERVAL\t   30\t/* us */\n+\n enum spacemit_i2c_state {\n \tSPACEMIT_STATE_IDLE,\n \tSPACEMIT_STATE_START,\n@@ -125,6 +129,7 @@ struct spacemit_i2c_dev {\n \n \tenum spacemit_i2c_state state;\n \tbool read;\n+\tbool use_pio;\n \tstruct completion complete;\n \tu32 status;\n };\n@@ -171,6 +176,14 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)\n \treturn i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;\n }\n \n+static inline void spacemit_i2c_delay(struct spacemit_i2c_dev *i2c, unsigned int us)\n+{\n+\tif (i2c->use_pio)\n+\t\tudelay(us);\n+\telse\n+\t\tfsleep(us);\n+}\n+\n static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)\n {\n \tu32 status;\n@@ -182,7 +195,8 @@ static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)\n \t\treturn;\n \n \tspacemit_i2c_reset(i2c);\n-\tusleep_range(10, 20);\n+\n+\tspacemit_i2c_delay(i2c, 10);\n \n \tfor (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) {\n \t\tstatus = readl(i2c->base + SPACEMIT_IBMR);\n@@ -211,9 +225,15 @@ static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)\n \tif (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))\n \t\treturn 0;\n \n-\tret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,\n-\t\t\t\t val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),\n-\t\t\t\t 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);\n+\tif (i2c->use_pio)\n+\t\tret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,\n+\t\t\t\t\t\tval, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),\n+\t\t\t\t\t\t1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);\n+\telse\n+\t\tret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,\n+\t\t\t\t\t val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),\n+\t\t\t\t\t 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);\n+\n \tif (ret)\n \t\tspacemit_i2c_reset(i2c);\n \n@@ -225,7 +245,7 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)\n \t/* in case bus is not released after transfer completes */\n \tif (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {\n \t\tspacemit_i2c_conditionally_reset_bus(i2c);\n-\t\tusleep_range(90, 150);\n+\t\tspacemit_i2c_delay(i2c, 90);\n \t}\n }\n \n@@ -237,25 +257,33 @@ spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)\n \n static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)\n {\n-\tu32 val;\n-\n-\t/*\n-\t * Unmask interrupt bits for all xfer mode:\n-\t * bus error, arbitration loss detected.\n-\t * For transaction complete signal, we use master stop\n-\t * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.\n-\t */\n-\tval = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;\n-\n-\t/*\n-\t * Unmask interrupt bits for interrupt xfer mode:\n-\t * When IDBR receives a byte, an interrupt is triggered.\n-\t *\n-\t * For the tx empty interrupt, it will be enabled in the\n-\t * i2c_start function.\n-\t * Otherwise, it will cause an erroneous empty interrupt before i2c_start.\n-\t */\n-\tval |= SPACEMIT_CR_DRFIE;\n+\tu32 val = 0;\n+\n+\tif (!i2c->use_pio) {\n+\t\t/*\n+\t\t * Enable interrupt bits for all xfer mode:\n+\t\t * bus error, arbitration loss detected.\n+\t\t */\n+\t\tval |= SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;\n+\n+\t\t/*\n+\t\t * Unmask interrupt bits for interrupt xfer mode:\n+\t\t * When IDBR receives a byte, an interrupt is triggered.\n+\t\t *\n+\t\t * For the tx empty interrupt, it will be enabled in the\n+\t\t * i2c_start().\n+\t\t * We don't want a TX empty interrupt until we start\n+\t\t * a transfer in i2c_start().\n+\t\t */\n+\t\tval |= SPACEMIT_CR_DRFIE;\n+\n+\t\t/*\n+\t\t * Enable master stop interrupt bit.\n+\t\t * For transaction complete signal, we use master stop\n+\t\t * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.\n+\t\t */\n+\t\tval |= SPACEMIT_CR_MSDIE;\n+\t}\n \n \tif (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)\n \t\tval |= SPACEMIT_CR_MODE_FAST;\n@@ -267,7 +295,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)\n \tval |= SPACEMIT_CR_SCLE;\n \n \t/* enable master stop detected */\n-\tval |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;\n+\tval |= SPACEMIT_CR_MSDE;\n \n \twritel(val, i2c->base + SPACEMIT_ICR);\n \n@@ -300,7 +328,12 @@ static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)\n \t/* send start pulse */\n \tval = readl(i2c->base + SPACEMIT_ICR);\n \tval &= ~SPACEMIT_CR_STOP;\n-\tval |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;\n+\tval |= SPACEMIT_CR_START | SPACEMIT_CR_TB;\n+\n+\t/* Enable the TX empty interrupt */\n+\tif (!i2c->use_pio)\n+\t\tval |= SPACEMIT_CR_DTEIE;\n+\n \twritel(val, i2c->base + SPACEMIT_ICR);\n }\n \n@@ -315,8 +348,23 @@ static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)\n \treturn !i2c->unprocessed;\n }\n \n+static inline void spacemit_i2c_complete(struct spacemit_i2c_dev *i2c)\n+{\n+\t/* SPACEMIT_STATE_IDLE avoids triggering the next byte */\n+\ti2c->state = SPACEMIT_STATE_IDLE;\n+\n+\tif (i2c->use_pio)\n+\t\treturn;\n+\n+\tcomplete(&i2c->complete);\n+}\n+\n static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)\n {\n+\t/* If there's no space in the IDBR, we're done */\n+\tif (!(i2c->status & SPACEMIT_SR_ITE))\n+\t\treturn;\n+\n \t/* if transfer completes, SPACEMIT_ISR will handle it */\n \tif (i2c->status & SPACEMIT_SR_MSD)\n \t\treturn;\n@@ -327,16 +375,19 @@ static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)\n \t\treturn;\n \t}\n \n-\t/* SPACEMIT_STATE_IDLE avoids trigger next byte */\n-\ti2c->state = SPACEMIT_STATE_IDLE;\n-\tcomplete(&i2c->complete);\n+\tspacemit_i2c_complete(i2c);\n }\n \n static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)\n {\n+\t/* If there's nothing in the IDBR, we're done */\n+\tif (!(i2c->status & SPACEMIT_SR_IRF))\n+\t\treturn;\n+\n \tif (i2c->unprocessed) {\n \t\t*i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR);\n \t\ti2c->unprocessed--;\n+\t\treturn;\n \t}\n \n \t/* if transfer completes, SPACEMIT_ISR will handle it */\n@@ -347,9 +398,7 @@ static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)\n \tif (i2c->unprocessed)\n \t\treturn;\n \n-\t/* SPACEMIT_STATE_IDLE avoids trigger next byte */\n-\ti2c->state = SPACEMIT_STATE_IDLE;\n-\tcomplete(&i2c->complete);\n+\tspacemit_i2c_complete(i2c);\n }\n \n static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c)\n@@ -383,8 +432,129 @@ static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c)\n \n \tspacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);\n \n-\ti2c->state = SPACEMIT_STATE_IDLE;\n-\tcomplete(&i2c->complete);\n+\tspacemit_i2c_complete(i2c);\n+}\n+\n+static void spacemit_i2c_handle_state(struct spacemit_i2c_dev *i2c)\n+{\n+\tu32 val;\n+\n+\tif (i2c->status & SPACEMIT_SR_ERR)\n+\t\tgoto err_out;\n+\n+\tswitch (i2c->state) {\n+\tcase SPACEMIT_STATE_START:\n+\t\tspacemit_i2c_handle_start(i2c);\n+\t\tbreak;\n+\tcase SPACEMIT_STATE_READ:\n+\t\tspacemit_i2c_handle_read(i2c);\n+\t\tbreak;\n+\tcase SPACEMIT_STATE_WRITE:\n+\t\tspacemit_i2c_handle_write(i2c);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (i2c->state != SPACEMIT_STATE_IDLE) {\n+\t\tval = readl(i2c->base + SPACEMIT_ICR);\n+\t\tval &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK |\n+\t\t\t SPACEMIT_CR_STOP | SPACEMIT_CR_START);\n+\t\tval |= SPACEMIT_CR_TB;\n+\t\tif (!i2c->use_pio)\n+\t\t\tval |= SPACEMIT_CR_ALDIE;\n+\n+\t\tif (spacemit_i2c_is_last_msg(i2c)) {\n+\t\t\t/* trigger next byte with stop */\n+\t\t\tval |= SPACEMIT_CR_STOP;\n+\n+\t\t\tif (i2c->read)\n+\t\t\t\tval |= SPACEMIT_CR_ACKNAK;\n+\t\t}\n+\t\twritel(val, i2c->base + SPACEMIT_ICR);\n+\t}\n+\n+err_out:\n+\tspacemit_i2c_err_check(i2c);\n+}\n+\n+/*\n+ * In PIO mode, this function is used as a replacement for\n+ * wait_for_completion_timeout(), whose return value indicates\n+ * the remaining time.\n+ *\n+ * We do not have a meaningful remaining-time value here, so\n+ * return a non-zero value on success to indicate \"not timed out\".\n+ * Returning 1 ensures callers treating the return value as\n+ * time_left will not incorrectly report a timeout.\n+ */\n+static int spacemit_i2c_wait_pio_xfer(struct spacemit_i2c_dev *i2c)\n+{\n+\tu32 mask, msec = jiffies_to_msecs(i2c->adapt.timeout);\n+\tktime_t timeout = ktime_add_ms(ktime_get(), msec);\n+\tint ret;\n+\n+\tmask = SPACEMIT_SR_IRF | SPACEMIT_SR_ITE;\n+\n+\tdo {\n+\t\ti2c->status = readl(i2c->base + SPACEMIT_ISR);\n+\n+\t\tspacemit_i2c_clear_int_status(i2c, i2c->status);\n+\n+\t\tif (i2c->status & mask)\n+\t\t\tspacemit_i2c_handle_state(i2c);\n+\t\telse\n+\t\t\tudelay(SPACEMIT_POLL_INTERVAL);\n+\t} while (i2c->unprocessed && ktime_compare(ktime_get(), timeout) < 0);\n+\n+\tif (i2c->unprocessed)\n+\t\treturn 0;\n+\n+\tif (i2c->read)\n+\t\treturn 1;\n+\n+\t/*\n+\t * If this is the last byte to write of the current message,\n+\t * we have to wait here. Otherwise, control will proceed directly\n+\t * to start(), which would overwrite the current data.\n+\t */\n+\tret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,\n+\t\t\t\t\ti2c->status, i2c->status & SPACEMIT_SR_ITE,\n+\t\t\t\t\tSPACEMIT_POLL_INTERVAL, SPACEMIT_POLL_TIMEOUT);\n+\tif (ret)\n+\t\treturn 0;\n+\n+\t/*\n+\t * For writes: in interrupt mode, an ITE (write-empty) interrupt is triggered\n+\t * after the last byte, and the MSD-related handling takes place there.\n+\t * In PIO mode, however, we need to explicitly call err_check() to emulate this\n+\t * step, otherwise the next transfer will fail.\n+\t */\n+\tif (i2c->msg_idx == i2c->msg_num - 1) {\n+\t\tmask = SPACEMIT_SR_MSD | SPACEMIT_SR_ERR;\n+\t\t/*\n+\t\t * In some cases, MSD may not arrive immediately;\n+\t\t * wait here to handle that.\n+\t\t */\n+\t\tret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,\n+\t\t\t\t\t\ti2c->status, i2c->status & mask,\n+\t\t\t\t\t\tSPACEMIT_POLL_INTERVAL, SPACEMIT_POLL_TIMEOUT);\n+\t\tif (ret)\n+\t\t\treturn 0;\n+\n+\t\tspacemit_i2c_err_check(i2c);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static int spacemit_i2c_wait_xfer_complete(struct spacemit_i2c_dev *i2c)\n+{\n+\tif (i2c->use_pio)\n+\t\treturn spacemit_i2c_wait_pio_xfer(i2c);\n+\n+\treturn wait_for_completion_timeout(&i2c->complete,\n+\t\t\t\t\t   i2c->adapt.timeout);\n }\n \n static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)\n@@ -402,8 +572,8 @@ static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)\n \n \t\tspacemit_i2c_start(i2c);\n \n-\t\ttime_left = wait_for_completion_timeout(&i2c->complete,\n-\t\t\t\t\t\t\ti2c->adapt.timeout);\n+\t\ttime_left = spacemit_i2c_wait_xfer_complete(i2c);\n+\n \t\tif (!time_left) {\n \t\t\tdev_err(i2c->dev, \"msg completion timeout\\n\");\n \t\t\tspacemit_i2c_conditionally_reset_bus(i2c);\n@@ -421,7 +591,7 @@ static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)\n static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)\n {\n \tstruct spacemit_i2c_dev *i2c = devid;\n-\tu32 status, val;\n+\tu32 status;\n \n \tstatus = readl(i2c->base + SPACEMIT_ISR);\n \tif (!status)\n@@ -431,41 +601,8 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)\n \n \tspacemit_i2c_clear_int_status(i2c, status);\n \n-\tif (i2c->status & SPACEMIT_SR_ERR)\n-\t\tgoto err_out;\n-\n-\tval = readl(i2c->base + SPACEMIT_ICR);\n-\tval &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);\n+\tspacemit_i2c_handle_state(i2c);\n \n-\tswitch (i2c->state) {\n-\tcase SPACEMIT_STATE_START:\n-\t\tspacemit_i2c_handle_start(i2c);\n-\t\tbreak;\n-\tcase SPACEMIT_STATE_READ:\n-\t\tspacemit_i2c_handle_read(i2c);\n-\t\tbreak;\n-\tcase SPACEMIT_STATE_WRITE:\n-\t\tspacemit_i2c_handle_write(i2c);\n-\t\tbreak;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\tif (i2c->state != SPACEMIT_STATE_IDLE) {\n-\t\tval |= SPACEMIT_CR_TB | SPACEMIT_CR_ALDIE;\n-\n-\t\tif (spacemit_i2c_is_last_msg(i2c)) {\n-\t\t\t/* trigger next byte with stop */\n-\t\t\tval |= SPACEMIT_CR_STOP;\n-\n-\t\t\tif (i2c->read)\n-\t\t\t\tval |= SPACEMIT_CR_ACKNAK;\n-\t\t}\n-\t\twritel(val, i2c->base + SPACEMIT_ICR);\n-\t}\n-\n-err_out:\n-\tspacemit_i2c_err_check(i2c);\n \treturn IRQ_HANDLED;\n }\n \n@@ -474,6 +611,11 @@ static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)\n \tunsigned long timeout;\n \tint idx = 0, cnt = 0;\n \n+\tif (i2c->use_pio) {\n+\t\ti2c->adapt.timeout = msecs_to_jiffies(SPACEMIT_WAIT_TIMEOUT);\n+\t\treturn;\n+\t}\n+\n \tfor (; idx < i2c->msg_num; idx++)\n \t\tcnt += (i2c->msgs + idx)->len + 1;\n \n@@ -486,11 +628,14 @@ static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)\n \ti2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num;\n }\n \n-static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)\n+static inline int\n+spacemit_i2c_xfer_common(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num, bool use_pio)\n {\n \tstruct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt);\n \tint ret;\n \n+\ti2c->use_pio = use_pio;\n+\n \ti2c->msgs = msgs;\n \ti2c->msg_num = num;\n \n@@ -518,6 +663,16 @@ static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, in\n \treturn ret < 0 ? ret : num;\n }\n \n+static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)\n+{\n+\treturn spacemit_i2c_xfer_common(adapt, msgs, num, false);\n+}\n+\n+static int spacemit_i2c_pio_xfer_atomic(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)\n+{\n+\treturn spacemit_i2c_xfer_common(adapt, msgs, num, true);\n+}\n+\n static u32 spacemit_i2c_func(struct i2c_adapter *adap)\n {\n \treturn I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);\n@@ -525,6 +680,7 @@ static u32 spacemit_i2c_func(struct i2c_adapter *adap)\n \n static const struct i2c_algorithm spacemit_i2c_algo = {\n \t.xfer = spacemit_i2c_xfer,\n+\t.xfer_atomic = spacemit_i2c_pio_xfer_atomic,\n \t.functionality = spacemit_i2c_func,\n };\n \n",
    "prefixes": [
        "v7",
        "2/2"
    ]
}