get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2217575,
    "url": "http://patchwork.ozlabs.org/api/patches/2217575/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-aspeed/patch/20260330-upstream_i2c-v28-4-17bdae39c5cb@aspeedtech.com/",
    "project": {
        "id": 57,
        "url": "http://patchwork.ozlabs.org/api/projects/57/?format=api",
        "name": "Linux ASPEED SoC development",
        "link_name": "linux-aspeed",
        "list_id": "linux-aspeed.lists.ozlabs.org",
        "list_email": "linux-aspeed@lists.ozlabs.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260330-upstream_i2c-v28-4-17bdae39c5cb@aspeedtech.com>",
    "list_archive_url": null,
    "date": "2026-03-30T08:21:49",
    "name": "[v28,4/4] i2c: ast2600: Add target mode support",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "662c3126c76076d2a6a185560ae7f328d64bd63f",
    "submitter": {
        "id": 71489,
        "url": "http://patchwork.ozlabs.org/api/people/71489/?format=api",
        "name": "Ryan Chen",
        "email": "ryan_chen@aspeedtech.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-aspeed/patch/20260330-upstream_i2c-v28-4-17bdae39c5cb@aspeedtech.com/mbox/",
    "series": [
        {
            "id": 497972,
            "url": "http://patchwork.ozlabs.org/api/series/497972/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-aspeed/list/?series=497972",
            "date": "2026-03-30T08:21:45",
            "name": "Add ASPEED AST2600 I2C controller driver",
            "version": 28,
            "mbox": "http://patchwork.ozlabs.org/series/497972/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2217575/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2217575/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <linux-aspeed+bounces-3806-incoming=patchwork.ozlabs.org@lists.ozlabs.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-aspeed@lists.ozlabs.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org\n (client-ip=112.213.38.117; helo=lists.ozlabs.org;\n envelope-from=linux-aspeed+bounces-3806-incoming=patchwork.ozlabs.org@lists.ozlabs.org;\n receiver=patchwork.ozlabs.org)",
            "lists.ozlabs.org;\n arc=none smtp.remote-ip=211.20.114.72",
            "lists.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com",
            "lists.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com\n (client-ip=211.20.114.72; helo=twmbx01.aspeed.com;\n envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org)"
        ],
        "Received": [
            "from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fkklg1bp3z1yG8\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 30 Mar 2026 19:23:10 +1100 (AEDT)",
            "from boromir.ozlabs.org (localhost [127.0.0.1])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 4fkkkV6ZtXz2yj3;\n\tMon, 30 Mar 2026 19:22:10 +1100 (AEDT)",
            "from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 4fkkkT2s2sz2yjw;\n\tMon, 30 Mar 2026 19:22:09 +1100 (AEDT)",
            "from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com\n (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 30 Mar\n 2026 16:21:47 +0800",
            "from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com\n (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend\n Transport; Mon, 30 Mar 2026 16:21:47 +0800"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1774858930;\n\tcv=none;\n b=Sw3fd3cMBv6J8t5wBD7UwmrTFbeOVfjilIhcb9Jonx5we4Uf6no1iIuYjtNUKpfa7HGey199Hne6MuZ748+HHEq7xJFHtDOfxQLDObo8GvlLuNVvPZfMnVpDmKc2dahmB6DzcXChuzxD2dmYxAmYl84nXtxQwk2RbG2KcBk4B+H3j3cWdG3PHNJzIcqDT/6i7FKmS2Q1IeFKQp4xyus87LD0g6hHEHOtiRFwaKXLEUT382LhACEthR3gnGF5j1EMyywSzs/oLvYE1Sz2hSoQXqERwPibiiX3W4bW7ivhayLUKnlGctCkFW2yYC/mZs8C8y7+plcsTYgPd/2yUs1Q8Q==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707;\n\tt=1774858930; c=relaxed/relaxed;\n\tbh=BNmKGFX7pUTTS2EhzKuB8YKT7T82bI5W95jsJOVdR9k=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References:\n\t In-Reply-To:To:CC;\n b=ejlOOU+i9FSAYSIGnBtmcB6ECPzHWJqysNxA4/b94hu5m7MCUlo7absAGE7E6qfANmW/p86YqtnKuUReq1JNjyxEgfA5Z5P/RLbkFXPvQOv7dJZjxDmzyxqI9JA64anJQOSI9BuJHdwGphlIXOAiBAJSL3ELC6TcDeI98uQEr5gYOWXxSz3kVqyG3idXEriqkzVNoylhJGR+h3J1J7uTkmx8kbIPu1qsGfwxE9f+hjw+AZYng6rg21PontLqFM/cSB5rvns//trxwoc0HmWjtg4dMY+qV7C2M0cfKggE0OTtkG0EwLntTenM/cU4v2bJ9lZIBXf8NEV4ae+dxmC17Q==",
        "ARC-Authentication-Results": "i=1; lists.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com;\n spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeed.com;\n envelope-from=ryan_chen@aspeedtech.com;\n receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com",
        "From": "Ryan Chen <ryan_chen@aspeedtech.com>",
        "Date": "Mon, 30 Mar 2026 16:21:49 +0800",
        "Subject": "[PATCH v28 4/4] i2c: ast2600: Add target mode support",
        "X-Mailing-List": "linux-aspeed@lists.ozlabs.org",
        "List-Id": "<linux-aspeed.lists.ozlabs.org>",
        "List-Help": "<mailto:linux-aspeed+help@lists.ozlabs.org>",
        "List-Owner": "<mailto:linux-aspeed+owner@lists.ozlabs.org>",
        "List-Post": "<mailto:linux-aspeed@lists.ozlabs.org>",
        "List-Archive": "<https://lore.kernel.org/linux-aspeed/>,\n  <https://lists.ozlabs.org/pipermail/linux-aspeed/>",
        "List-Subscribe": "<mailto:linux-aspeed+subscribe@lists.ozlabs.org>,\n  <mailto:linux-aspeed+subscribe-digest@lists.ozlabs.org>,\n  <mailto:linux-aspeed+subscribe-nomail@lists.ozlabs.org>",
        "List-Unsubscribe": "<mailto:linux-aspeed+unsubscribe@lists.ozlabs.org>",
        "Precedence": "list",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-ID": "<20260330-upstream_i2c-v28-4-17bdae39c5cb@aspeedtech.com>",
        "References": "<20260330-upstream_i2c-v28-0-17bdae39c5cb@aspeedtech.com>",
        "In-Reply-To": "<20260330-upstream_i2c-v28-0-17bdae39c5cb@aspeedtech.com>",
        "To": "<jk@codeconstruct.com.au>, <andriy.shevchenko@linux.intel.com>, Andi Shyti\n\t<andi.shyti@kernel.org>, Rob Herring <robh@kernel.org>, Krzysztof Kozlowski\n\t<krzk+dt@kernel.org>, Conor Dooley <conor+dt@kernel.org>, Joel Stanley\n\t<joel@jms.id.au>, Andrew Jeffery <andrew@codeconstruct.com.au>, \"Benjamin\n Herrenschmidt\" <benh@kernel.crashing.org>, Rayn Chen\n\t<rayn_chen@aspeedtech.com>, Philipp Zabel <p.zabel@pengutronix.de>",
        "CC": "<linux-i2c@vger.kernel.org>, <devicetree@vger.kernel.org>,\n\t<linux-arm-kernel@lists.infradead.org>, <linux-aspeed@lists.ozlabs.org>,\n\t<linux-kernel@vger.kernel.org>, <openbmc@lists.ozlabs.org>, Ryan Chen\n\t<ryan_chen@aspeedtech.com>",
        "X-Mailer": "b4 0.14.3",
        "X-Developer-Signature": "v=1; a=ed25519-sha256; t=1774858906; l=26391;\n i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id;\n bh=qEy71FBUHzKmG83XwMeihp+/Nh+FGHPWZ6g0wGKot5Q=;\n b=3ij5+azsEkfW7DHo1+BEk12rRLX44KXYs85m1yH1apXCQAK2JjitOcG1/2rcz21rFxdWmxVGD\n Gi29+QWhf5HBsz+bJ66eLa5D3NXCDzPaIp9k4aYlooXj7Z8wIz6ZzwV",
        "X-Developer-Key": "i=ryan_chen@aspeedtech.com; a=ed25519;\n pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc=",
        "X-Spam-Status": "No, score=0.0 required=5.0 tests=SPF_HELO_FAIL,SPF_PASS\n\tautolearn=disabled version=4.0.1",
        "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org"
    },
    "content": "Add target mode support to the AST2600 I2C driver.\n\nTarget mode features implemented include:\n- Add target interrupt handling\n- Address match and response logic\n- Separate Tx/Rx DMA address and length configuration\n\nThis complements the existing controller-mode support, enabling\ndual-role capability.\n\nSigned-off-by: Ryan Chen <ryan_chen@aspeedtech.com>\n---\nChanges in v28:\n- fix typo condication -> condition\n- fix compile error, when disable CONFIG_I2C_SLAVE\nChanges in v26:\n- change int to bool target_operate\n- rename target_operate to target_active\n- use i2c_bus->target replace require IO\n- use WRITE_ONCE replace target_operate write.\n---\n drivers/i2c/busses/i2c-ast2600.c | 566 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 566 insertions(+)",
    "diff": "diff --git a/drivers/i2c/busses/i2c-ast2600.c b/drivers/i2c/busses/i2c-ast2600.c\nindex c2368ba309a7..a9b77917a1fe 100644\n--- a/drivers/i2c/busses/i2c-ast2600.c\n+++ b/drivers/i2c/busses/i2c-ast2600.c\n@@ -274,6 +274,13 @@ struct ast2600_i2c_bus {\n \tvoid __iomem\t\t*buf_base;\n \tint (*setup_tx)(u32 cmd, struct ast2600_i2c_bus *i2c_bus);\n \tint (*setup_rx)(u32 cmd, struct ast2600_i2c_bus *i2c_bus);\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t/* target structure */\n+\tbool\t\t\ttarget_active;\n+\tunsigned char\t*target_dma_buf;\n+\tdma_addr_t\t\ttarget_dma_addr;\n+\tstruct i2c_client\t*target;\n+#endif\n };\n \n static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus)\n@@ -357,6 +364,440 @@ static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus)\n \treturn ret;\n }\n \n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+static void ast2600_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts)\n+{\n+\tint target_rx_len = 0;\n+\tu32 cmd = 0;\n+\tu8 value;\n+\tint i;\n+\n+\tsts &= ~(AST2600_I2CS_SLAVE_PENDING);\n+\t/* Handle i2c target timeout condition */\n+\tif (sts & AST2600_I2CS_INACTIVE_TO) {\n+\t\t/* Reset timeout counter */\n+\t\tu32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) &\n+\t\t\t\tAST2600_I2CC_AC_TIMING_MASK;\n+\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\tac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout);\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN;\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\treturn;\n+\t}\n+\n+\tsts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR);\n+\n+\tswitch (sts) {\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA:\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\ttarget_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t      AST2600_I2CS_DMA_LEN_STS));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED,\n+\t\t\t\t\t&i2c_bus->target_dma_buf[i]);\n+\t\t}\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE_NAK |\n+\t\t\tAST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA |\n+\t\t\tAST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_RX_DONE_NAK | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA:\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\t\tif (sts & AST2600_I2CS_SLAVE_MATCH)\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\n+\t\ttarget_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t      AST2600_I2CS_DMA_LEN_STS));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED,\n+\t\t\t\t\t&i2c_bus->target_dma_buf[i]);\n+\t\t}\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tif (sts & AST2600_I2CS_STOP)\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN;\n+\t\tbreak;\n+\n+\t/* it is Mw data Mr coming -> it need send tx */\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA:\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA:\n+\t\t/* it should be repeat start read */\n+\t\tif (sts & AST2600_I2CS_SLAVE_MATCH)\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\n+\t\ttarget_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t      AST2600_I2CS_DMA_LEN_STS));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED,\n+\t\t\t\t\t&i2c_bus->target_dma_buf[i]);\n+\t\t}\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED,\n+\t\t\t\t&i2c_bus->target_dma_buf[0]);\n+\t\twritel(AST2600_I2CS_SET_TX_DMA_LEN(1),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA:\n+\t\t/* First Start read */\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED,\n+\t\t\t\t&i2c_bus->target_dma_buf[0]);\n+\t\twritel(AST2600_I2CS_SET_TX_DMA_LEN(1),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_WAIT_TX_DMA:\n+\t\t/* it should be next start read */\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED,\n+\t\t\t\t&i2c_bus->target_dma_buf[0]);\n+\t\twritel(AST2600_I2CS_SET_TX_DMA_LEN(1),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP:\n+\t\t/* it just tx complete */\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\tbreak;\n+\tcase AST2600_I2CS_STOP:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_dbg(i2c_bus->dev, \"unhandled target isr case %x, sts %x\\n\", sts,\n+\t\t\treadl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF));\n+\t\tbreak;\n+\t}\n+\n+\tif (cmd)\n+\t\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\treadl(i2c_bus->reg_base + AST2600_I2CS_ISR);\n+}\n+\n+static void ast2600_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts)\n+{\n+\tint target_rx_len = 0;\n+\tu32 cmd = 0;\n+\tu8 value;\n+\tint i;\n+\n+\t/* due to controller target is common buffer, need force the master stop not issue */\n+\tif (readl(i2c_bus->reg_base + AST2600_I2CM_CMD_STS) & GENMASK(15, 0)) {\n+\t\twritel(0, i2c_bus->reg_base + AST2600_I2CM_CMD_STS);\n+\t\ti2c_bus->cmd_err = -EBUSY;\n+\t\twritel(0, i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tcomplete(&i2c_bus->cmd_complete);\n+\t}\n+\n+\t/* Handle i2c target timeout condition */\n+\tif (AST2600_I2CS_INACTIVE_TO & sts) {\n+\t\t/* Reset timeout counter */\n+\t\tu32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) &\n+\t\t\t\tAST2600_I2CC_AC_TIMING_MASK;\n+\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\tac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout);\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\twritel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tWRITE_ONCE(i2c_bus->target_active, false);\n+\t\treturn;\n+\t}\n+\n+\tsts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR);\n+\n+\tif (sts & AST2600_I2CS_SLAVE_MATCH)\n+\t\tWRITE_ONCE(i2c_bus->target_active, true);\n+\n+\tswitch (sts) {\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA |\n+\t\t AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_SLAVE_PENDING |\n+\t\t AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_SLAVE_PENDING |\n+\t\t AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tfallthrough;\n+\tcase AST2600_I2CS_SLAVE_PENDING |\n+\t\t AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\tcase AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\tcase AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\tif (sts & AST2600_I2CS_RX_DONE) {\n+\t\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\t       AST2600_I2CC_BUFF_CTRL));\n+\t\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t\t}\n+\t\t}\n+\t\tif (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_RX_BUFF_EN)\n+\t\t\tcmd = 0;\n+\t\telse\n+\t\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;\n+\n+\t\twritel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tbreak;\n+\tcase AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_RX_DONE:\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t       AST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\tcmd |= AST2600_I2CS_RX_BUFF_EN;\n+\t\twritel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA |\n+\t\t\t\tAST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\t\t AST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tcmd |= AST2600_I2CS_RX_BUFF_EN;\n+\t\twritel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\t\t AST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\t/* workaround for avoid next start with len != 0 */\n+\t\twritel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tbreak;\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\t\t AST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\t/* workaround for avoid next start with len != 0 */\n+\t\twritel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE |\n+\t     AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_STOP:\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\t\t AST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);\n+\t\twriteb(value, i2c_bus->buf_base);\n+\t\tbreak;\n+\tcase AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);\n+\t\twriteb(value, i2c_bus->buf_base);\n+\t\twritel(AST2600_I2CC_SET_TX_BUF_LEN(1),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_STOP |\n+\t     AST2600_I2CS_TX_NAK | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\tcase AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_STOP |\n+\t     AST2600_I2CS_TX_NAK | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\tAST2600_I2CC_BUFF_CTRL));\n+\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t}\n+\t\twritel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE:\n+\tcase AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE:\n+\tcase AST2600_I2CS_WAIT_TX_DMA:\n+\t\tif (sts & AST2600_I2CS_SLAVE_MATCH)\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\n+\t\tif (sts & AST2600_I2CS_RX_DONE) {\n+\t\t\ttarget_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +\n+\t\t\t\t\t\t\tAST2600_I2CC_BUFF_CTRL));\n+\t\t\tfor (i = 0; i < target_rx_len; i++) {\n+\t\t\t\tvalue = readb(i2c_bus->buf_base + 0x10 + i);\n+\t\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);\n+\t\t\t}\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);\n+\t\t} else {\n+\t\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &value);\n+\t\t}\n+\t\twriteb(value, i2c_bus->buf_base);\n+\t\twritel(AST2600_I2CC_SET_TX_BUF_LEN(1),\n+\t\t       i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN;\n+\t\tbreak;\n+\t/* workaround : trigger the cmd twice to fix next state keep 1000000 */\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\tcmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;\n+\t\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\tbreak;\n+\tcase AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_STOP:\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_dbg(i2c_bus->dev, \"unhandled target isr case %x, sts %x\\n\", sts,\n+\t\t\treadl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF));\n+\t\tbreak;\n+\t}\n+\n+\tif (cmd)\n+\t\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\treadl(i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\n+\tif ((sts & AST2600_I2CS_STOP) && !(sts & AST2600_I2CS_SLAVE_PENDING))\n+\t\tWRITE_ONCE(i2c_bus->target_active, false);\n+}\n+\n+static void ast2600_i2c_target_byte_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts)\n+{\n+\tu32 i2c_buff = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF);\n+\tu32 cmd = AST2600_I2CS_ACTIVE_ALL;\n+\tu8 byte_data;\n+\tu8 value;\n+\n+\t/* Handle i2c target timeout condition */\n+\tif (sts & AST2600_I2CS_INACTIVE_TO) {\n+\t\t/* Reset timeout counter */\n+\t\tu32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) &\n+\t\t\t\tAST2600_I2CC_AC_TIMING_MASK;\n+\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\tac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout);\n+\t\twritel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);\n+\t\twritel(AST2600_I2CS_ACTIVE_ALL, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\twritel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\t\treadl(i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tWRITE_ONCE(i2c_bus->target_active, false);\n+\t\treturn;\n+\t}\n+\n+\tswitch (sts) {\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);\n+\t\t/* first address match is address */\n+\t\tbyte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff);\n+\t\tbreak;\n+\tcase AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA:\n+\t\tbyte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &byte_data);\n+\t\tbreak;\n+\tcase AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA:\n+\t\tcmd |= AST2600_I2CS_TX_CMD;\n+\t\tbyte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff);\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &byte_data);\n+\t\twritel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF);\n+\t\tbreak;\n+\tcase AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA:\n+\t\tcmd |= AST2600_I2CS_TX_CMD;\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &byte_data);\n+\t\twritel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF);\n+\t\tbreak;\n+\tcase AST2600_I2CS_STOP:\n+\tcase AST2600_I2CS_STOP | AST2600_I2CS_TX_NAK:\n+\t\ti2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_dbg(i2c_bus->dev, \"unhandled pkt isr %x\\n\", sts);\n+\t\tbreak;\n+\t}\n+\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\twritel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\treadl(i2c_bus->reg_base + AST2600_I2CS_ISR);\n+}\n+\n+static int ast2600_i2c_target_irq(struct ast2600_i2c_bus *i2c_bus)\n+{\n+\tu32 ier = readl(i2c_bus->reg_base + AST2600_I2CS_IER);\n+\tu32 isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\n+\tif (!(isr & ier))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Target interrupt coming after controller packet done\n+\t * So need handle controller first.\n+\t */\n+\tif (readl(i2c_bus->reg_base + AST2600_I2CM_ISR) & AST2600_I2CM_PKT_DONE)\n+\t\treturn 0;\n+\n+\tisr &= ~(AST2600_I2CS_ADDR_INDICATE_MASK);\n+\n+\tif (AST2600_I2CS_ADDR1_NAK & isr)\n+\t\tisr &= ~AST2600_I2CS_ADDR1_NAK;\n+\n+\tif (AST2600_I2CS_ADDR2_NAK & isr)\n+\t\tisr &= ~AST2600_I2CS_ADDR2_NAK;\n+\n+\tif (AST2600_I2CS_ADDR3_NAK & isr)\n+\t\tisr &= ~AST2600_I2CS_ADDR3_NAK;\n+\n+\tif (AST2600_I2CS_ADDR_MASK & isr)\n+\t\tisr &= ~AST2600_I2CS_ADDR_MASK;\n+\n+\tif (AST2600_I2CS_PKT_DONE & isr) {\n+\t\tif (i2c_bus->mode == DMA_MODE)\n+\t\t\tast2600_i2c_target_packet_dma_irq(i2c_bus, isr);\n+\t\telse\n+\t\t\tast2600_i2c_target_packet_buff_irq(i2c_bus, isr);\n+\t} else {\n+\t\tast2600_i2c_target_byte_irq(i2c_bus, isr);\n+\t}\n+\n+\treturn 1;\n+}\n+#endif\n+\n static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus)\n {\n \tstruct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index];\n@@ -629,6 +1070,20 @@ static void ast2600_i2c_controller_packet_irq(struct ast2600_i2c_bus *i2c_bus, u\n \t\t}\n \t\tbreak;\n \tcase AST2600_I2CM_RX_DONE:\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t\t/*\n+\t\t * Workaround for controller/target packet mode enable rx done stuck issue\n+\t\t * When controller go for first read (RX_DONE), target mode will also effect\n+\t\t * Then controller will send nack, not operate anymore.\n+\t\t */\n+\t\tif (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_PKT_MODE_EN) {\n+\t\t\tu32 target_cmd = readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\n+\t\t\twritel(0, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\t\twritel(target_cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\t\t}\n+\t\tfallthrough;\n+#endif\n \tcase AST2600_I2CM_RX_DONE | AST2600_I2CM_NORMAL_STOP:\n \t\t/* do next rx */\n \t\tif (i2c_bus->mode == DMA_MODE) {\n@@ -727,6 +1182,12 @@ static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id)\n {\n \tstruct ast2600_i2c_bus *i2c_bus = dev_id;\n \n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\tif (i2c_bus->target) {\n+\t\tif (ast2600_i2c_target_irq(i2c_bus))\n+\t\t\treturn IRQ_HANDLED;\n+\t}\n+#endif\n \treturn IRQ_RETVAL(ast2600_i2c_controller_irq(i2c_bus));\n }\n \n@@ -743,12 +1204,35 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg\n \t\t\treturn ret;\n \t}\n \n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\tif (i2c_bus->mode == BUFF_MODE) {\n+\t\tif (i2c_bus->target_active)\n+\t\t\treturn -EBUSY;\n+\t\t/**\n+\t\t * In BUFF_MODE, controller and target share the same buffer register,\n+\t\t * A target transaction can update buffer state asynchronously via IRQ,\n+\t\t * so block controller transfers while target is active, otherwise we can\n+\t\t * corrupt buffer.\n+\t\t */\n+\t\twritel(0, i2c_bus->reg_base + AST2600_I2CS_IER);\n+\t\tif (readl(i2c_bus->reg_base + AST2600_I2CS_ISR) || i2c_bus->target_active) {\n+\t\t\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);\n+\t\t\treturn -EBUSY;\n+\t\t}\n+\t}\n+#endif\n+\n \ti2c_bus->cmd_err = 0;\n \ti2c_bus->msgs = msgs;\n \ti2c_bus->msgs_index = 0;\n \ti2c_bus->msgs_count = num;\n \treinit_completion(&i2c_bus->cmd_complete);\n \tret = ast2600_i2c_do_start(i2c_bus);\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t/* avoid race condition target is wait and controller wait 1st target operate */\n+\tif (i2c_bus->mode == BUFF_MODE)\n+\t\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);\n+#endif\n \tif (ret)\n \t\tgoto controller_out;\n \ttimeout = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout);\n@@ -767,6 +1251,9 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg\n \t\t * if the bus is still busy.\n \t\t */\n \t\tif (i2c_bus->multi_master &&\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t\t    !i2c_bus->target_active &&\n+#endif\n \t\t    (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) &\n \t\t    AST2600_I2CC_BUS_BUSY_STS))\n \t\t\tast2600_i2c_recover_bus(i2c_bus);\n@@ -814,8 +1301,80 @@ static int ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus)\n \t/* Clear Interrupt */\n \twritel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR);\n \n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t/* for memory buffer initial */\n+\tif (i2c_bus->dma_available) {\n+\t\ti2c_bus->target_dma_buf =\n+\t\t\tdmam_alloc_coherent(i2c_bus->dev, I2C_TARGET_MSG_BUF_SIZE,\n+\t\t\t\t\t    &i2c_bus->target_dma_addr, GFP_KERNEL);\n+\t\tif (!i2c_bus->target_dma_buf)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\twritel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR);\n+\n+\tif (i2c_bus->mode == BYTE_MODE)\n+\t\twritel(GENMASK(15, 0), i2c_bus->reg_base + AST2600_I2CS_IER);\n+\telse\n+\t\twritel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);\n+#endif\n+\n+\treturn 0;\n+}\n+\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+static int ast2600_i2c_reg_target(struct i2c_client *client)\n+{\n+\tstruct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter);\n+\tu32 cmd = TARGET_TRIGGER_CMD;\n+\n+\tif (i2c_bus->target)\n+\t\treturn -EINVAL;\n+\n+\tdev_dbg(i2c_bus->dev, \"target addr %x\\n\", client->addr);\n+\n+\twritel(0, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);\n+\twritel(AST2600_I2CC_SLAVE_EN | readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL),\n+\t       i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);\n+\n+\t/* trigger rx buffer */\n+\tif (i2c_bus->mode == DMA_MODE) {\n+\t\tcmd |= AST2600_I2CS_RX_DMA_EN;\n+\t\twritel(i2c_bus->target_dma_addr, i2c_bus->reg_base + AST2600_I2CS_RX_DMA);\n+\t\twritel(i2c_bus->target_dma_addr, i2c_bus->reg_base + AST2600_I2CS_TX_DMA);\n+\t\twritel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE),\n+\t\t       i2c_bus->reg_base + AST2600_I2CS_DMA_LEN);\n+\t} else if (i2c_bus->mode == BUFF_MODE) {\n+\t\tcmd = TARGET_TRIGGER_CMD;\n+\t} else {\n+\t\tcmd &= ~AST2600_I2CS_PKT_MODE_EN;\n+\t}\n+\n+\twritel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);\n+\ti2c_bus->target = client;\n+\t/* Set target addr. */\n+\twritel(client->addr | AST2600_I2CS_ADDR1_ENABLE,\n+\t       i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);\n+\n+\treturn 0;\n+}\n+\n+static int ast2600_i2c_unreg_target(struct i2c_client *client)\n+{\n+\tstruct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter);\n+\tu32 val;\n+\n+\t/* Turn off target mode. */\n+\tval = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);\n+\twritel(val & ~AST2600_I2CC_SLAVE_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);\n+\tval = readl(i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);\n+\twritel(val & ~AST2600_I2CS_ADDR1_MASK, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);\n+\n+\ti2c_bus->target = NULL;\n+\n \treturn 0;\n }\n+#endif\n \n static u32 ast2600_i2c_functionality(struct i2c_adapter *adap)\n {\n@@ -825,6 +1384,10 @@ static u32 ast2600_i2c_functionality(struct i2c_adapter *adap)\n static const struct i2c_algorithm i2c_ast2600_algorithm = {\n \t.xfer = ast2600_i2c_controller_xfer,\n \t.functionality = ast2600_i2c_functionality,\n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\t.reg_target = ast2600_i2c_reg_target,\n+\t.unreg_target = ast2600_i2c_unreg_target,\n+#endif\n };\n \n static void ast2600_i2c_set_xfer_mode(struct ast2600_i2c_bus *i2c_bus,\n@@ -960,6 +1523,9 @@ static int ast2600_i2c_probe(struct platform_device *pdev)\n \t\tregmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, I2CCG_DIV_CTRL);\n \t}\n \n+#if IS_ENABLED(CONFIG_I2C_SLAVE)\n+\tWRITE_ONCE(i2c_bus->target_active, false);\n+#endif\n \ti2c_bus->dev = dev;\n \ti2c_bus->multi_master = device_property_read_bool(dev, \"multi-master\");\n \ti2c_bus->dma_available = device_property_read_bool(dev, \"aspeed,enable-dma\");\n",
    "prefixes": [
        "v28",
        "4/4"
    ]
}