get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2195219,
    "url": "http://patchwork.ozlabs.org/api/patches/2195219/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260210151459.2348758-12-raymondmaoca@gmail.com/",
    "project": {
        "id": 18,
        "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api",
        "name": "U-Boot",
        "link_name": "uboot",
        "list_id": "u-boot.lists.denx.de",
        "list_email": "u-boot@lists.denx.de",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260210151459.2348758-12-raymondmaoca@gmail.com>",
    "list_archive_url": null,
    "date": "2026-02-10T15:14:54",
    "name": "[v2,11/16] i2c: k1: add I2C driver support",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "c0b9916be73292ec6cc2c7e926a4fe18ed26240a",
    "submitter": {
        "id": 91989,
        "url": "http://patchwork.ozlabs.org/api/people/91989/?format=api",
        "name": "Raymond Mao",
        "email": "raymondmaoca@gmail.com"
    },
    "delegate": {
        "id": 20174,
        "url": "http://patchwork.ozlabs.org/api/users/20174/?format=api",
        "username": "Andes",
        "first_name": "Andes",
        "last_name": "",
        "email": "uboot@andestech.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260210151459.2348758-12-raymondmaoca@gmail.com/mbox/",
    "series": [
        {
            "id": 491690,
            "url": "http://patchwork.ozlabs.org/api/series/491690/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=491690",
            "date": "2026-02-10T15:14:43",
            "name": "Add board support for Spacemit K1 SoC in SPL",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/491690/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2195219/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2195219/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<u-boot-bounces@lists.denx.de>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=B4Ium1zk;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)",
            "phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=gmail.com",
            "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de",
            "phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.b=\"B4Ium1zk\";\n\tdkim-atps=neutral",
            "phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=gmail.com",
            "phobos.denx.de;\n spf=pass smtp.mailfrom=raymondmaoca@gmail.com"
        ],
        "Received": [
            "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\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 4f9QCf4QJ2z1xwG\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 11 Feb 2026 02:17:18 +1100 (AEDT)",
            "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id B916E83E57;\n\tTue, 10 Feb 2026 16:15:48 +0100 (CET)",
            "by phobos.denx.de (Postfix, from userid 109)\n id 4BD5D83E3A; Tue, 10 Feb 2026 16:15:47 +0100 (CET)",
            "from mail-qt1-x830.google.com (mail-qt1-x830.google.com\n [IPv6:2607:f8b0:4864:20::830])\n (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 53D1F83DEB\n for <u-boot@lists.denx.de>; Tue, 10 Feb 2026 16:15:43 +0100 (CET)",
            "by mail-qt1-x830.google.com with SMTP id\n d75a77b69052e-50146483bf9so60744281cf.3\n for <u-boot@lists.denx.de>; Tue, 10 Feb 2026 07:15:43 -0800 (PST)",
            "from ubuntu.localdomain (174-138-202-16.cpe.distributel.net.\n [174.138.202.16]) by smtp.gmail.com with ESMTPSA id\n 6a1803df08f44-8953c057751sm101019286d6.43.2026.02.10.07.15.39\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 10 Feb 2026 07:15:40 -0800 (PST)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-1.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FORGED_GMAIL_RCVD,FREEMAIL_FROM,\n RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=no\n autolearn_force=no version=3.4.2",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20230601; t=1770736542; x=1771341342; darn=lists.denx.de;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=kWLwhFs0a+1ZQQ+Z8uvfizdHlIGpPwNHh+8OxMjGJCU=;\n b=B4Ium1zkBbZXfhguN019P/cqg2+5FaYmygxOEa/vSmYCA6+tUwkaVMDfZsc8rUvxH3\n EP/bntSYTK07LC62nxGlxJ57RKtXA9KDoX8LRKMXxCAiLDMJzyB2mg4ZajtuiKgRFh65\n FGnOWCdn7AXFpZcAruJw/e/cqPyOZ1hwXzSK4JKBgeaLPl9TEylPT+TiQnFV+g1PcUUy\n jq1lMX0SxbFbhmjpV941wa1vkm9cuLW3SEPqME+aYisMNrOFMlfb1RBasK8v0+oenvfs\n ONKWsfeWnrNqltGpN4AGd/wVSRWK4k8clD24rtURg9W+WJ9SzRQhllS6jio1asaERglb\n i78A==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770736542; x=1771341342;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=kWLwhFs0a+1ZQQ+Z8uvfizdHlIGpPwNHh+8OxMjGJCU=;\n b=r4XSBFMj/i2rx3ila2fY/c7X3d6IPUFktzF8d4GkvFA4hBx2Zzj9gVm15lulx9xPKt\n FZA6Z9TfNAZQ+sVHgKFzu+uT0LBgiijpOQj8h51tpXJJ/a22llugdTfy0ft6o73MdvLB\n Gm+uFvfgixu1RRYAGdMg/IgPKKSs4JVGNKC20ibdLpl0Dt+m0bYASZJFXtBMLleYtU6x\n MZiQqq7ZsxjogVCK9gy0ZQQyx7BKXJEvO4QzG8EyyCLSyMpnMAZj7nSeEbVc7FR+MO2e\n GCWf6geMW8W4ruAzrrrO88WrSak2n+tcBCikKCqyVb/vX3d6T/jly3JIR+hkbdE8S/t6\n wjBA==",
        "X-Gm-Message-State": "AOJu0YyTlXnW+d7uDSG9vV/OYdSFLwdxjQ43nwM3Zt8Qmfz9yV6S9/E7\n I0CN1WcVXKQdY7rcSyGmJ+ZL5Y6IohNIgk8+7cL0jMPBWdjtA03cuoojUcbLig==",
        "X-Gm-Gg": "AZuq6aKHhbBCb8LiQhlLpvL8Kowj2HLHogEyBG7A46UimNA+X2vqGnq8piuU3XRvqCd\n Av5LwpDXIt3Fl1j38vNtP+2IgaQFRBmFcqqe6C3FIPr3/GymB3AxrTOx/o3GHL7JsJ3SeAd0wEr\n /ZeTM0FPXGrprCq3azIS3aPYJHvJ4fBoJTFsjypZrmO8R0uw3e0+7o3I5VP+xh8j56v9xe28sbM\n S9DR8UwV/m/9ikwWVOYbv2ddcAUPAeUsRu86iK1GfcWLBLxPnGoTVywXPI2aoqIpL2czejgJ6TY\n UwIYeeH9xLxUr3WiQ9nUkNHOrEbAyAGA0J1F5umTEto0MMwtLP7hQTKfx7fzWghx38ZA3KZzrgy\n 4tniqsU+XUZsR+ho/woFwQjmVD1Zo5IzdKa0hSFZPBeMtbmYuMkeGniuLAVIjWIyBbnxSW1NI3P\n irCC3qYsxMPJYYjx64sEY4Omi089Sh8di54NZDq8Z8rkQit5BJxhCX++zuamIcj865+ZSHNhVaL\n ePjWqZFYbNEGVF7xl1HvA==",
        "X-Received": "by 2002:ac8:7f50:0:b0:4f3:5f7b:cc1d with SMTP id\n d75a77b69052e-506398de232mr207272021cf.34.1770736541392;\n Tue, 10 Feb 2026 07:15:41 -0800 (PST)",
        "From": "Raymond Mao <raymondmaoca@gmail.com>",
        "To": "u-boot@lists.denx.de",
        "Cc": "uboot@riscstar.com, u-boot-spacemit@groups.io, raymond.mao@riscstar.com,\n rick@andestech.com, ycliang@andestech.com, trini@konsulko.com,\n lukma@denx.de, hs@nabladev.com, jh80.chung@samsung.com, peng.fan@nxp.com,\n xypron.glpk@gmx.de, randolph@andestech.com, dlan@gentoo.org,\n junhui.liu@pigmoral.tech, neil.armstrong@linaro.org,\n quentin.schulz@cherry.de, samuel@sholland.org, raymondmaoca@gmail.com,\n Guodong Xu <guodong.xu@riscstar.com>",
        "Subject": "[PATCH v2 11/16] i2c: k1: add I2C driver support",
        "Date": "Tue, 10 Feb 2026 10:14:54 -0500",
        "Message-Id": "<20260210151459.2348758-12-raymondmaoca@gmail.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20260210151459.2348758-1-raymondmaoca@gmail.com>",
        "References": "<20260210151459.2348758-1-raymondmaoca@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "u-boot@lists.denx.de",
        "X-Mailman-Version": "2.1.39",
        "Precedence": "list",
        "List-Id": "U-Boot discussion <u-boot.lists.denx.de>",
        "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>",
        "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>",
        "List-Post": "<mailto:u-boot@lists.denx.de>",
        "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>",
        "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>",
        "Errors-To": "u-boot-bounces@lists.denx.de",
        "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>",
        "X-Virus-Scanned": "clamav-milter 0.103.8 at phobos.denx.de",
        "X-Virus-Status": "Clean"
    },
    "content": "From: Raymond Mao <raymond.mao@riscstar.com>\n\nAdd I2C driver support on Spacemit K1 SoC using driver model.\n\nSigned-off-by: Raymond Mao <raymond.mao@riscstar.com>\nSigned-off-by: Guodong Xu <guodong.xu@riscstar.com>\n---\n drivers/i2c/Kconfig  |   7 +\n drivers/i2c/Makefile |   1 +\n drivers/i2c/k1_i2c.c | 516 +++++++++++++++++++++++++++++++++++++++++++\n drivers/i2c/k1_i2c.h |  69 ++++++\n 4 files changed, 593 insertions(+)\n create mode 100644 drivers/i2c/k1_i2c.c\n create mode 100644 drivers/i2c/k1_i2c.h",
    "diff": "diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig\nindex 55465dc1d46..eb7219f15a6 100644\n--- a/drivers/i2c/Kconfig\n+++ b/drivers/i2c/Kconfig\n@@ -817,6 +817,13 @@ config SYS_I2C_IHS\n         help\n           Support for gdsys IHS I2C driver on FPGA bus.\n \n+config SYS_I2C_SPACEMIT_K1\n+\tbool \"Spacemit K1 I2C driver\"\n+\tdepends on DM_I2C\n+\thelp\n+\t  Support for Spacemit I2C controller. It's based on\n+\t  Driver Model.\n+\n source \"drivers/i2c/muxes/Kconfig\"\n \n endif\ndiff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile\nindex 5fe30d0df4f..d57daaba70b 100644\n--- a/drivers/i2c/Makefile\n+++ b/drivers/i2c/Makefile\n@@ -48,6 +48,7 @@ obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o\n obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o\n obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o\n obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o\n+obj-$(CONFIG_SYS_I2C_SPACEMIT_K1) += k1_i2c.o\n obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o\n obj-$(CONFIG_SYS_I2C_SUN6I_P2WI) += sun6i_p2wi.o\n obj-$(CONFIG_SYS_I2C_SUN8I_RSB) += sun8i_rsb.o\ndiff --git a/drivers/i2c/k1_i2c.c b/drivers/i2c/k1_i2c.c\nnew file mode 100644\nindex 00000000000..0be2debc828\n--- /dev/null\n+++ b/drivers/i2c/k1_i2c.c\n@@ -0,0 +1,516 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Copyright (C) 2023-2026 Spacemit, Inc\n+ * Copyright (C) 2025-2026 RISCstar Ltd.\n+ */\n+\n+#include <asm/io.h>\n+#include <clk.h>\n+#include <dm.h>\n+#include <dm/device_compat.h>\n+#include <i2c.h>\n+#include <linux/delay.h>\n+#include <linux/iopoll.h>\n+#include <reset.h>\n+#include \"k1_i2c.h\"\n+\n+#define ICR_OFFSET\t\t0x00\n+#define ISR_OFFSET\t\t0x04\n+#define ISAR_OFFSET\t\t0x08\n+#define IDBR_OFFSET\t\t0x0c\n+#define ILCR_OFFSET\t\t0x10\n+#define IWCR_OFFSET\t\t0x14\n+#define IRCR_OFFSET\t\t0x18\n+#define IBMR_OFFSET\t\t0x1c\n+#define WFIFO_OFFSET\t\t0x20\n+#define WFIFO_WPTR_OFFSET\t0x24\n+#define WFIFO_RPTR_OFFSET\t0x28\n+#define RFIFO_OFFSET\t\t0x2c\n+#define RFIFO_WPTR_OFFSET\t0x30\n+#define RFIFO_RPTR_OFFSET\t0x34\n+\n+/* All transfers are described by this data structure */\n+struct k1_i2c_msg {\n+\tu8 condition;\n+\tu8 acknack;\n+\tu8 direction;\n+\tu8 data;\n+};\n+\n+struct k1_i2c {\n+\tu32 icr;\n+\tu32 isr;\n+\tu32 isar;\n+\tu32 idbr;\n+\tu32 ilcr;\n+\tu32 iwcr;\n+\tu32 irst_cyc;\n+\tu32 ibmr;\n+};\n+\n+struct k1_i2c_priv {\n+\tint id;\n+\tvoid __iomem *base;\n+\tstruct reset_ctl_bulk resets;\n+\tstruct clk clk;\n+\tu32 clk_rate;\n+};\n+\n+/*\n+ * i2c_reset: - reset the host controller\n+ *\n+ */\n+static void i2c_reset(void __iomem *base)\n+{\n+\tu32 icr_mode;\n+\tu32 val;\n+\n+\t/* Save bus mode (standard or fast speed) for later use */\n+\ticr_mode = readl(base + ICR_OFFSET) & ICR_MODE_MASK;\n+\t/* disable unit */\n+\tval = readl(base + ICR_OFFSET);\n+\twritel(val & ~ICR_IUE, base + ICR_OFFSET);\n+\tudelay(10);\n+\t/* reset the unit */\n+\tval = readl(base + ICR_OFFSET);\n+\tval |= ICR_UR;\n+\twritel(val, base + ICR_OFFSET);\n+\tudelay(100);\n+\t/* disable unit */\n+\tval = readl(base + ICR_OFFSET);\n+\twritel(val & ~ICR_IUE, base + ICR_OFFSET);\n+\n+\t/* set slave address */\n+\twritel(0x00, base + ISR_OFFSET);\n+\t/* set control reg values */\n+\twritel(I2C_ICR_INIT | icr_mode, base + ICR_OFFSET);\n+\twritel(I2C_ISR_INIT, base + ISR_OFFSET); /* set clear interrupt bits */\n+\tval = readl(base + ICR_OFFSET);\n+\tval |= ICR_IUE;\n+\twritel(val, base + ICR_OFFSET); /* enable unit */\n+\tudelay(100);\n+}\n+\n+static inline bool is_isr_set_or_clr(unsigned long isr, unsigned long set_mask,\n+\t\t\t\t     unsigned long clr_mask)\n+{\n+\treturn ((isr & set_mask) == set_mask) && ((isr & clr_mask) == 0);\n+}\n+\n+/*\n+ * i2c_isr_set_cleared: - wait until certain bits of the I2C status register\n+ *\t                  are set and cleared\n+ *\n+ * @return: 0 on success or -ETIMEDOUT.\n+ */\n+static int i2c_isr_set_cleared(void __iomem *base, unsigned long set_mask,\n+\t\t\t       unsigned long clr_mask)\n+{\n+\tint cnt = 1000, delay = 10, isr, ret;\n+\n+\tret = read_poll_timeout(readl, isr,\n+\t\t\t\tis_isr_set_or_clr(isr, set_mask, clr_mask),\n+\t\t\t\tdelay, delay * cnt, base + ISR_OFFSET);\n+\treturn ret;\n+}\n+\n+/*\n+ * i2c_transfer: - Transfer one byte over the i2c bus\n+ *\n+ * This function can transfer a byte over the i2c bus in both directions.\n+ * It is used by the public API functions.\n+ *\n+ * @return:  0: transfer successful or error code\n+ */\n+static int i2c_transfer(void __iomem *base, struct k1_i2c_msg *msg)\n+{\n+\tint ret;\n+\tu32 val;\n+\n+\tif (!msg)\n+\t\tgoto transfer_error_msg_empty;\n+\n+\tswitch (msg->direction) {\n+\tcase I2C_WRITE:\n+\t\t/* check if bus is not busy */\n+\t\tif (i2c_isr_set_cleared(base, 0, ISR_IBB))\n+\t\t\tgoto transfer_error_bus_busy;\n+\n+\t\t/* start transmission */\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_START;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_STOP;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\twritel(msg->data, base + IDBR_OFFSET);\n+\t\tif (msg->condition == I2C_COND_START) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_START;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->condition == I2C_COND_STOP) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_STOP;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->acknack == I2C_ACKNAK_SENDNAK) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_ACKNAK;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->acknack == I2C_ACKNAK_SENDACK) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval &= ~ICR_ACKNAK;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_ALDIE;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval |= ICR_TB;\n+\t\twritel(val, base + ICR_OFFSET);\n+\n+\t\t/* transmit register empty? */\n+\t\tif (i2c_isr_set_cleared(base, ISR_ITE, 0))\n+\t\t\tgoto transfer_error_transmit_timeout;\n+\n+\t\t/* clear 'transmit empty' state */\n+\t\tval = readl(base + ISR_OFFSET);\n+\t\tval |= ISR_ITE;\n+\t\twritel(val, base + ISR_OFFSET);\n+\n+\t\t/* wait for ACK from slave */\n+\t\tif (msg->acknack == I2C_ACKNAK_WAITACK)\n+\t\t\tif (i2c_isr_set_cleared(base, 0, ISR_ACKNAK))\n+\t\t\t\tgoto transfer_error_ack_missing;\n+\t\tbreak;\n+\n+\tcase I2C_READ:\n+\t\t/* check if bus is not busy */\n+\t\tif (i2c_isr_set_cleared(base, 0, ISR_IBB))\n+\t\t\tgoto transfer_error_bus_busy;\n+\n+\t\t/* start receive */\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_START;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_STOP;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\tif (msg->condition == I2C_COND_START) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_START;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->condition == I2C_COND_STOP) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_STOP;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->acknack == I2C_ACKNAK_SENDNAK) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval |= ICR_ACKNAK;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tif (msg->acknack == I2C_ACKNAK_SENDACK) {\n+\t\t\tval = readl(base + ICR_OFFSET);\n+\t\t\tval &= ~ICR_ACKNAK;\n+\t\t\twritel(val, base + ICR_OFFSET);\n+\t\t}\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval &= ~ICR_ALDIE;\n+\t\twritel(val, base + ICR_OFFSET);\n+\t\tval = readl(base + ICR_OFFSET);\n+\t\tval |= ICR_TB;\n+\t\twritel(val, base + ICR_OFFSET);\n+\n+\t\t/* receive register full? */\n+\t\tif (i2c_isr_set_cleared(base, ISR_IRF, 0))\n+\t\t\tgoto transfer_error_receive_timeout;\n+\n+\t\tmsg->data = readl(base + IDBR_OFFSET);\n+\n+\t\t/* clear 'receive empty' state */\n+\t\tval = readl(base + ISR_OFFSET);\n+\t\tval |= ISR_IRF;\n+\t\twritel(val, base + ISR_OFFSET);\n+\t\tbreak;\n+\tdefault:\n+\t\tgoto transfer_error_illegal_param;\n+\t}\n+\n+\treturn 0;\n+\n+transfer_error_msg_empty:\n+\tdebug(\"%s: error: 'msg' is empty\\n\", __func__);\n+\tret = -EINVAL;\n+\tgoto i2c_transfer_finish;\n+\n+transfer_error_transmit_timeout:\n+\tdebug(\"%s: error: transmit timeout\\n\", __func__);\n+\tret = -ETIMEDOUT;\n+\tgoto i2c_transfer_finish;\n+\n+transfer_error_ack_missing:\n+\tdebug(\"%s: error: ACK missing\\n\", __func__);\n+\tret = -EREMOTEIO;\n+\tgoto i2c_transfer_finish;\n+\n+transfer_error_receive_timeout:\n+\tdebug(\"%s: error: receive timeout\\n\", __func__);\n+\tret = -ETIMEDOUT;\n+\tgoto i2c_transfer_finish;\n+\n+transfer_error_illegal_param:\n+\tdebug(\"%s: error: illegal parameters\\n\", __func__);\n+\tret = -EINVAL;\n+\tgoto i2c_transfer_finish;\n+\n+transfer_error_bus_busy:\n+\tdebug(\"%s: error: bus is busy\\n\", __func__);\n+\tret = -EIO;\n+\tgoto i2c_transfer_finish;\n+\n+i2c_transfer_finish:\n+\tdebug(\"%s: ISR: 0x%04x\\n\", __func__, readl(base + ISR_OFFSET));\n+\ti2c_reset(base);\n+\treturn ret;\n+}\n+\n+static int __i2c_read(void __iomem *base, uchar chip, u8 *addr, int alen,\n+\t\t      uchar *buffer, int len)\n+{\n+\tstruct k1_i2c_msg msg;\n+\tint ret;\n+\n+\tdebug(\"%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\\n\",\n+\t      __func__, chip, *addr, alen, len);\n+\n+\tif (len == 0) {\n+\t\tpr_err(\"reading zero byte is invalid\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ti2c_reset(base);\n+\n+\t/* dummy chip address write */\n+\tdebug(\"%s: dummy chip address write\\n\", __func__);\n+\tmsg.condition = I2C_COND_START;\n+\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\tmsg.direction = I2C_WRITE;\n+\tmsg.data = (chip << 1);\n+\tmsg.data &= 0xFE;\n+\tret = i2c_transfer(base, &msg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/*\n+\t * send memory address bytes;\n+\t * alen defines how much bytes we have to send.\n+\t */\n+\twhile (--alen >= 0) {\n+\t\tdebug(\"%s: send address byte %02x (alen=%d)\\n\",\n+\t\t      __func__, *addr, alen);\n+\t\tmsg.condition = I2C_COND_NORMAL;\n+\t\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\t\tmsg.direction = I2C_WRITE;\n+\t\tmsg.data      = addr[alen];\n+\t\tret = i2c_transfer(base, &msg);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\t/* start read sequence */\n+\tdebug(\"%s: start read sequence\\n\", __func__);\n+\tmsg.condition = I2C_COND_START;\n+\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\tmsg.direction = I2C_WRITE;\n+\tmsg.data      = (chip << 1);\n+\tmsg.data     |= 0x01;\n+\tret = i2c_transfer(base, &msg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* read bytes; send NACK at last byte */\n+\twhile (len--) {\n+\t\tif (len == 0) {\n+\t\t\tmsg.condition = I2C_COND_STOP;\n+\t\t\tmsg.acknack   = I2C_ACKNAK_SENDNAK;\n+\t\t} else {\n+\t\t\tmsg.condition = I2C_COND_NORMAL;\n+\t\t\tmsg.acknack   = I2C_ACKNAK_SENDACK;\n+\t\t}\n+\n+\t\tmsg.direction = I2C_READ;\n+\t\tmsg.data      = 0x00;\n+\t\tret = i2c_transfer(base, &msg);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\t*buffer = msg.data;\n+\t\tdebug(\"%s: reading byte (%p)=0x%02x\\n\",\n+\t\t      __func__, buffer, *buffer);\n+\t\tbuffer++;\n+\t}\n+\n+\ti2c_reset(base);\n+\n+\treturn 0;\n+}\n+\n+static int __i2c_write(struct k1_i2c *base, uchar chip, u8 *addr, int alen,\n+\t\t       uchar *buffer, int len)\n+{\n+\tstruct k1_i2c_msg msg;\n+\tint ret;\n+\n+\tdebug(\"%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\\n\",\n+\t      __func__, chip, *addr, alen, len);\n+\n+\ti2c_reset(base);\n+\n+\t/* chip address write */\n+\tdebug(\"%s: chip address write\\n\", __func__);\n+\tmsg.condition = I2C_COND_START;\n+\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\tmsg.direction = I2C_WRITE;\n+\tmsg.data = (chip << 1);\n+\tmsg.data &= 0xFE;\n+\tret = i2c_transfer(base, &msg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/*\n+\t * send memory address bytes;\n+\t * alen defines how much bytes we have to send.\n+\t */\n+\twhile (--alen >= 0) {\n+\t\tdebug(\"%s: send address byte %02x (alen=%d)\\n\",\n+\t\t      __func__, *addr, alen);\n+\t\tmsg.condition = I2C_COND_NORMAL;\n+\t\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\t\tmsg.direction = I2C_WRITE;\n+\t\tmsg.data      = addr[alen];\n+\t\tret = i2c_transfer(base, &msg);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\t/* write bytes; send NACK at last byte */\n+\twhile (len--) {\n+\t\tdebug(\"%s: writing byte (%p)=0x%02x\\n\",\n+\t\t      __func__, buffer, *buffer);\n+\n+\t\tif (len == 0)\n+\t\t\tmsg.condition = I2C_COND_STOP;\n+\t\telse\n+\t\t\tmsg.condition = I2C_COND_NORMAL;\n+\n+\t\tmsg.acknack   = I2C_ACKNAK_WAITACK;\n+\t\tmsg.direction = I2C_WRITE;\n+\t\tmsg.data      = *(buffer++);\n+\n+\t\tret = i2c_transfer(base, &msg);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\ti2c_reset(base);\n+\n+\treturn 0;\n+}\n+\n+static int k1_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)\n+{\n+\tstruct k1_i2c_priv *i2c = dev_get_priv(bus);\n+\tstruct i2c_msg *dmsg, *omsg, dummy;\n+\n+\tmemset(&dummy, 0, sizeof(struct i2c_msg));\n+\n+\t/*\n+\t * We expect either two messages (one with an offset and one with the\n+\t * actual data) or one message (just data or offset/data combined)\n+\t */\n+\tif (nmsgs > 2 || nmsgs == 0) {\n+\t\tdebug(\"%s: Only one or two messages are supported.\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tomsg = nmsgs == 1 ? &dummy : msg;\n+\tdmsg = nmsgs == 1 ? msg : msg + 1;\n+\n+\tif (dmsg->flags & I2C_M_RD)\n+\t\treturn __i2c_read(i2c->base, dmsg->addr, omsg->buf,\n+\t\t\t\t  omsg->len, dmsg->buf, dmsg->len);\n+\telse\n+\t\treturn __i2c_write(i2c->base, dmsg->addr, omsg->buf,\n+\t\t\t\t   omsg->len, dmsg->buf, dmsg->len);\n+}\n+\n+static int k1_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)\n+{\n+\tstruct k1_i2c_priv *priv = dev_get_priv(bus);\n+\tvoid __iomem *base = priv->base;\n+\tu32 val;\n+\n+\tif (speed > I2C_SPEED_STANDARD_RATE)\n+\t\tval = ICR_FM;\n+\telse\n+\t\tval = ICR_SM;\n+\tclrsetbits_le32(base + ICR_OFFSET, ICR_MODE_MASK, val);\n+\n+\treturn 0;\n+}\n+\n+static int k1_i2c_probe(struct udevice *bus)\n+{\n+\tstruct k1_i2c_priv *priv = dev_get_priv(bus);\n+\tstruct reset_ctl reset;\n+\tint ret;\n+\n+\tpriv->id = dev_seq(bus);\n+\tret = reset_get_by_index(bus, 0, &reset);\n+\tif (ret) {\n+\t\tdev_err(bus, \"%s: can not get reset\\n\", __func__);\n+\t\treturn ret;\n+\t}\n+\treset_assert(&reset);\n+\tudelay(10);\n+\treset_deassert(&reset);\n+\tudelay(10);\n+\n+\tret = clk_get_by_index(bus, 0, &priv->clk);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = clk_enable(&priv->clk);\n+\tif (ret && ret != -ENOSYS && ret != -EOPNOTSUPP) {\n+\t\tdebug(\"%s: failed to enable clock\\n\", __func__);\n+\t\treturn ret;\n+\t}\n+\tpriv->clk_rate = clk_get_rate(&priv->clk);\n+\n+\tpriv->base = (void *)devfdt_get_addr_ptr(bus);\n+\tk1_i2c_set_bus_speed(bus, priv->clk_rate);\n+\treturn 0;\n+}\n+\n+static const struct dm_i2c_ops k1_i2c_ops = {\n+\t.xfer\t\t= k1_i2c_xfer,\n+\t.set_bus_speed\t= k1_i2c_set_bus_speed,\n+};\n+\n+static const struct udevice_id k1_i2c_ids[] = {\n+\t{ .compatible = \"spacemit,k1-i2c\" },\n+\t{ }\n+};\n+\n+U_BOOT_DRIVER(i2c_spacemit) = {\n+\t.name\t= \"i2c_spacemit\",\n+\t.id\t= UCLASS_I2C,\n+\t.of_match = k1_i2c_ids,\n+\t.probe\t= k1_i2c_probe,\n+\t.priv_auto = sizeof(struct k1_i2c_priv),\n+\t.ops\t= &k1_i2c_ops,\n+};\ndiff --git a/drivers/i2c/k1_i2c.h b/drivers/i2c/k1_i2c.h\nnew file mode 100644\nindex 00000000000..856947aa43b\n--- /dev/null\n+++ b/drivers/i2c/k1_i2c.h\n@@ -0,0 +1,69 @@\n+/* SPDX-License-Identifier: GPL-2.0+ */\n+/*\n+ * Copyright (C) 2023-2026 Spacemit Ltd.\n+ * Copyright (C) 2025-2026 RISCstar Ltd.\n+ */\n+\n+#ifndef __SPACEMIT_I2C_H\n+#define __SPACEMIT_I2C_H\n+\n+/* Shall the current transfer have a start/stop condition? */\n+#define I2C_COND_NORMAL\t\t0\n+#define I2C_COND_START\t\t1\n+#define I2C_COND_STOP\t\t2\n+\n+/* Shall the current transfer be ack/nacked or being waited for it? */\n+#define I2C_ACKNAK_WAITACK\t1\n+#define I2C_ACKNAK_SENDACK\t2\n+#define I2C_ACKNAK_SENDNAK\t4\n+\n+/* Specify who shall transfer the data (master or slave) */\n+#define I2C_READ\t\t0\n+#define I2C_WRITE\t\t1\n+\n+#if (CONFIG_SYS_I2C_SPEED == 400000)\n+#define I2C_ICR_INIT\t(ICR_FM | ICR_BEIE | ICR_IRFIE | ICR_ITEIE |\t\\\n+\t\t\t ICR_GCD | ICR_SCLE)\n+#else\n+#define I2C_ICR_INIT\t(ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD |\t\\\n+\t\t\t ICR_SCLE)\n+#endif\n+\n+/* ----- Control register bits ---------------------------------------- */\n+\n+#define ICR_START\t0x1\t\t/* start bit */\n+#define ICR_STOP\t0x2\t\t/* stop bit */\n+#define ICR_ACKNAK\t0x4\t\t/* send ACK(0) or NAK(1) */\n+#define ICR_TB\t\t0x8\t\t/* transfer byte bit */\n+#define ICR_MA\t\tBIT(12)\t\t/* master abort */\n+#define ICR_SCLE\tBIT(13)\t\t/* master clock enable, mona SCLEA */\n+#define ICR_IUE\t\tBIT(14)\t\t/* unit enable */\n+#define ICR_GCD\t\tBIT(21)\t\t/* general call disable */\n+#define ICR_ITEIE\tBIT(19)\t\t/* enable tx interrupts */\n+#define ICR_IRFIE\tBIT(20)\t\t/* enable rx interrupts, mona: DRFIE */\n+#define ICR_BEIE\tBIT(22)\t\t/* enable bus error ints */\n+#define ICR_SSDIE\tBIT(24)\t\t/* slave STOP detected int enable */\n+#define ICR_ALDIE\tBIT(18)\t\t/* enable arbitration interrupt */\n+#define ICR_SADIE\tBIT(23)\t\t/* slave address detected int enable */\n+#define ICR_UR\t\tBIT(10)\t\t/* unit reset */\n+#define ICR_SM\t\t(0x0)\t\t/* Standard Mode */\n+#define ICR_FM\t\tBIT(8)\t\t/* Fast Mode */\n+#define ICR_MODE_MASK\t(0x300)\t\t/* Mode mask */\n+\n+/* ----- Status register bits ----------------------------------------- */\n+\n+#define ISR_RWM\t\tBIT(13)\t\t/* read/write mode */\n+#define ISR_ACKNAK\tBIT(14)\t\t/* ack/nak status */\n+#define ISR_UB\t\tBIT(15)\t\t/* unit busy */\n+#define ISR_IBB\t\tBIT(16)\t\t/* bus busy */\n+#define ISR_SSD\t\tBIT(24)\t\t/* slave stop detected */\n+#define ISR_ALD\t\tBIT(18)\t\t/* arbitration loss detected */\n+#define ISR_ITE\t\tBIT(19)\t\t/* tx buffer empty */\n+#define ISR_IRF\t\tBIT(20)\t\t/* rx buffer full */\n+#define ISR_GCAD\tBIT(21)\t\t/* general call address detected */\n+#define ISR_SAD\t\tBIT(23)\t\t/* slave address detected */\n+#define ISR_BED\t\tBIT(22)\t\t/* bus error no ACK/NAK */\n+\n+#define I2C_ISR_INIT\t0x1FDE000\n+\n+#endif\n",
    "prefixes": [
        "v2",
        "11/16"
    ]
}