From nobody Fri Oct 2 00:41:01 2026 Received: from mail-pz2-f38.google.com (mail-pz2-f38.google.com [74.125.228.38]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 095A248B389 for ; Thu, 1 Oct 2026 07:51:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.38 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841117; cv=none; b=DPNtYA3wMB+BIl0SZVZypOfm+KVsBrtwEpB0Elnm2FKyTWr+y5y8FTe+kEPzV6nfB1ILXpwtEdLjA8T91VPZV9kfaOY1C4WnRb0WLVf2ou304NV/3JUBW7AL7gcyK9I4XqZ44TRWzDb1S52QaB36sorvyOaQCXODnXeM0hMQwdc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841117; c=relaxed/simple; bh=O8MDKZM6orbok+3kIkwxaUSh/e4nFOYJeY8hZUI/E60=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=RzQB7y0swXBSoAEl04m07frt9FuLRBBGPTb47mlB3FYCUubGQxKDkUtFNNsaw19i3nqxgCiMk0Ydv649Q2AWDaGBdKdsqKG0CAQKRGxhfdQY/GeHIwMJ1Mks/aizXk/K4qN8mjxCA/XrsIWG/C+w6Va5I+QZ5829D8Cw4QRR9iw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BvAe9Sc2; arc=none smtp.client-ip=74.125.228.38 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BvAe9Sc2" Received: by mail-pz2-f38.google.com with SMTP id d2e1a72fcca58-882c2bcef77so3004474b3a.3 for ; Thu, 01 Oct 2026 00:51:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790841115; x=1791445915; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=W2FqaMzaGINgzjJOw7zufrrcqxjVM6pp3g9UOy5lEX8=; b=BvAe9Sc2eTAae9G4oxPdEQOZlgTIwenrxNaGl6xqz3VibE6aRc3c3T4TmwssnvjtVz tBwFuh2/YY0EayhotapN2f9+qgGT9P8Pm9Ds5bSNLLpW9l0IFJiG2aCnIbtEXDdY5DvP jfhl+8BHdK7uglcTRgAj6LQG1N4DXuco8pyzD4EKCRtcwGojE1Obirj0zQMgHKDcgc1j 5xumkfLcXJ/lapn7WOGtE/t9xloIPIeXM8JlFm2AN+iJybqhlRchEMJ2H+xkxaHAtfyX Nk/ffZ0i3QoQX0Ejb5YICb2e4EqXWKBAEMzy0hYKsS49GwCqdV6NiRBiaZVYjiqjwhBu Twfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790841115; x=1791445915; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=W2FqaMzaGINgzjJOw7zufrrcqxjVM6pp3g9UOy5lEX8=; b=vqlmgL/dpcpPZhuboHVlWUwrjDYkG88womA+dDfGhfbuGEQkb++SSIkCGRlFCUFH+s G2SVwyusjxJE33T5IwtB5Kk2MAnTW1tN++x7CtmC/OVsqv0JZMh3nqrXwKasQ3O8UJrc 2Dc2meBG2CaKp0f8xBjGhFcBUSpQ29xL+yfLYvYkr16Wp2QUfYd7an2uY6bFnySjJdQn Kb1NEX3HNcr08hK2N7AAg0RkkGvST/PnxHd1jmIvEQErHXEoluVSzAJs+5Mw5+7hDcEC ORh8XJaQAinnXNQblMIBApqRzVd8Y1s94gfsfqOAi+WHw+wpgGyvlREqb1zKOSfzKZMM mXaQ== X-Forwarded-Encrypted: i=1; AKwUvBz5Jvp1mIhVt2aexBBep+CQGpmb79YIxC+5XYtq4hgFu0/OzYSp8MOfWiNX/kd2RCYzI0a54f5FnXa6rUk=@vger.kernel.org X-Gm-Message-State: AFuF++mjnCJ3Oy8yzCPtEGy8ezi9vKQ+SkLlhMULQfuVD0cCM6gFCoeC pE5P2WKBplxpP0gqYS2Tr4xV5XmieVIZ76dxVkM2IS3RK6J2r3Y1IMP2 X-Gm-Gg: AYBFou2oIE+JWFM1Tk13Mi4/yt2ZIKS05eLDCgqZK9IdS2vAq4HsQQPqSff8G8aFKnd aErcz3Zr1cbsPNUMaX8h+gD/ItfCpO/Hw6kJ4yeJwArfH2UJGAlyhoPDE+0MwTeHF0TpuSnZ2Ge nduW/2W9F+8oj6T0S0AmXJqGnG3H2kKKIm6sXdIgHkpvHQDhqd9g9CnrTnflZsr3ya1UBrKsncA 6CnRbfAVFfwnfddvaVSuOAUhlAiBiihFbK4rhRRLPUyT6ntphsT3LJi0nNOz9/CSa5po5iNZ4A8 fq9BFonZNs35SnTgod3VctFBMUZHaostHwF7+52PwUA3mdzqXsdIJJIKUwVGndzDjY986QZtJ93 E6vK8pgVopJyLAG8xrZX+6NUZLBkhVndiH/whRG0/fYtEK8aSL6qFbSTxBmgZJZMQ0JGM193Tvh Ih48U01lbfCxlOQN9fJ1doqkdAXip0RZLtdIZfCByaQxlMCNXM5fcAygvjgs4AXZuu7pirdO5H2 VezAgHiTKBOCOl1lWv1lXi+4KhyI3F2bHBmL11MZkT4wsnqPwGz9Scb X-Received: by 2002:a05:6a00:218e:b0:879:2a08:99bb with SMTP id d2e1a72fcca58-8874dd6acddmr3330370b3a.56.1790841115325; Thu, 01 Oct 2026 00:51:55 -0700 (PDT) Received: from localhost.localdomain (60-250-196-139.hinet-ip.hinet.net. [60.250.196.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-88819db440csm666843b3a.60.2026.10.01.00.51.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Oct 2026 00:51:54 -0700 (PDT) From: Zi-Yu Chen To: Andi Shyti , linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Jacky Huang , Shan-Chun Hung , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Andrew Jeffery , Zi-Yu Chen , Krzysztof Kozlowski Subject: [PATCH v11 1/3] dt-bindings: i2c: nuvoton,ma35d1-i2c: Add MA35D1 I2C controller Date: Thu, 1 Oct 2026 15:50:59 +0800 Message-Id: <20261001075101.489660-2-zychennvt@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20261001075101.489660-1-zychennvt@gmail.com> References: <20261001075101.489660-1-zychennvt@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add device tree binding documentation for the I2C controller found in the Nuvoton MA35D1 SoC. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Zi-Yu Chen --- .../bindings/i2c/nuvoton,ma35d1-i2c.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/nuvoton,ma35d1-i2= c.yaml diff --git a/Documentation/devicetree/bindings/i2c/nuvoton,ma35d1-i2c.yaml = b/Documentation/devicetree/bindings/i2c/nuvoton,ma35d1-i2c.yaml new file mode 100644 index 000000000000..0713e1c1ecb8 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nuvoton,ma35d1-i2c.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/nuvoton,ma35d1-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton MA35D1 I2C Controller + +maintainers: + - Zi-Yu Chen + +description: + The Nuvoton MA35D1 I2C controller supports controller and optional targe= t mode. + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + const: nuvoton,ma35d1-i2c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-frequency: + description: + Desired I2C bus clock frequency in Hz. The absence of this property + indicates the default frequency 100 kHz. + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - resets + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + i2c0: i2c@40800000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x40800000 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C0_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C0>; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; --=20 2.34.1 From nobody Fri Oct 2 00:41:01 2026 Received: from mail-pz2-f37.google.com (mail-pz2-f37.google.com [74.125.228.37]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B00149B5D0 for ; Thu, 1 Oct 2026 07:51:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.37 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841121; cv=none; b=lVW8Sd89Xc3WaN5zu+caT9xe8dYK5qOs1xar7tEnxdnNu8CR7tqAPdaZ6E2F+dVmMUQcUabkBx3nJcCjr2f1ln1gJAQztL0KRyRKsQXW/EJGlSTpqI9ndp+ibNRXPL7HTDKLe7m1ANPl0LRrF89OGTx8to9EJs5YBX/h9FGlSiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841121; c=relaxed/simple; bh=PVxp4YzdGIvss+G8HzrKx1kyl482hM9aChHIh2r+8kU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Uh6r9wVzrLSCxVw6BmBb/d+jKTm8o0y0gKZ+NnZBTCHIGs8gz0CFs/NDkoOYeiEgk37UtAzC5qH3U4xlZTz6IbRK6xLELottSLGpkkRQ8f/rSABBv9FrqLFz/gm206UHM1TjuWPj4WL+w71e0/b2Ur1NeCO1O+uAkY8mw1a98fk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Ia6QdVEQ; arc=none smtp.client-ip=74.125.228.37 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ia6QdVEQ" Received: by mail-pz2-f37.google.com with SMTP id d2e1a72fcca58-886ce63c1c5so622403b3a.0 for ; Thu, 01 Oct 2026 00:51:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790841119; x=1791445919; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=YWdSr8vS+WbLbeKGbJC3k2Xj5wDMFQ4fqvZ+J+Ht3yg=; b=Ia6QdVEQrQB/OnE5RjO2Ojn6GJljRzbRQK5ijOf1/Rxvz9UoD2eK95ezwmgp6d1Fsk jaEwl/FdFM2Gd6w2cxZr+vfDiOG1SiN4ak2SbbJRzxBJUPpV84UflGZFT+KhAPIjOF2k 8LD6r8nGGADhYFMDkSuAe1S/2g1ZMKVpG/rk9uG2alaXL4zvPGUvylb5VOyHFYhur4i7 DxCNApUWIe+p2uCsrmyGic978Yl9HQT/foJjPan5XJjwzTamF65epabpAujLNAQ5elEq /7/MJZM/GGF3l5wPB5mATIdTJVGoiQLYTAbiBzNlkT9/u2sfBjBubl9bsjjJo56jEtc/ MkIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790841119; x=1791445919; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=YWdSr8vS+WbLbeKGbJC3k2Xj5wDMFQ4fqvZ+J+Ht3yg=; b=afJiHThKpSS21UfNT5iJjEusOHvJjo/IHpMkPHrOcWkaRJbw7wPwWmtfJME6jBZ1Xn +2E7oikJi9UKR/T234yT4ULSGEbifs7YK1EriDb0VD7oxpNkRHBBGv3py30tZaRtJWRV 2IHJDmmZSAqAuqhLIGDUHJA5GxSvmVvf27w+lJjlO4X8jxey5vzRfuUr26cPrrxmQheQ AY2bncJcdsEVr5s7/G12jP94xzOPxbY4L+GH1/uMntxjGN3fzI4pOPg75RTQBHadHYzh ngrVVzV3lwjH4yHtAwa0BiwJHGlFlrQei5lsN325/UuXZU4DHaod4cEP2FyvLxpvmRcP Ynzw== X-Forwarded-Encrypted: i=1; AKwUvBy+LRyg5mHJH7VyAWCMF6UlpeaABWB1I5mCZ0A1j+0wh5igMfc3xNzLSRiNfustcN1wNeobLcZUg8d8Aqk=@vger.kernel.org X-Gm-Message-State: AFuF++nV79USVmLqD/N98IYeoVHX08ixoP3FzKl4tmV9ZBMNV9F+lZtP 2UMz6dguoo9Ezv+RhxeH3IzacyjxTVoPwkidPS1iyiVAV6aZkXANiVKiO7FvEQ== X-Gm-Gg: AYBFou1pEZsKJryBp6FHIh+gKc9ktlFPI98lo8mHoLduP0vHMnLEEsMTiFsYQblIwIs xXH2OBC3R+7icrRircF+iS68JnektzPFe5shizCgmhBFAcs9PLUXcSrfr7kiBbQ1NWu/iYKhNiR 8xx9dzvpauuk2DUtlXCd4fPy3GxLZCjbplNo45H+sARKMZ4Y+vayhNJxIHasKQh26x9Bj6Jiggy SKdNK9UVngeJnscCE+JGrcDdBs1mhfE2D/ESGjxBjv4JgRnql/fQHKWXS5nU9xrTUTx2t8ux86m 08ICAYn6KuR7mXS0yXgq2l60T8Eosjq6T/jG4Xs4V+Qf/t6ATR2Np27ssw7xq1lO+5p8FVOVSg/ uXqFhj8yeLNdeVxg8zS1Bz3mB9Hu0LaYU1FxiKuzu+0IJkgyma6Rtm0ZZTgNT8omeUqGF1eucuO I2P0sh1U1sW0eWprD+kuD8OWZS/LniY0G8llb19ri5x8XfJ0cWlQjdMV+qPWBCpowUqMOvY2pvC ctWtE3KFjvDI+N4r5E6zdODU+AbcbihM7YFRtPmXZZeNQNtUhJOCE2N X-Received: by 2002:a05:6a00:a83:b0:886:dc5:ae03 with SMTP id d2e1a72fcca58-8874c8d319amr3278780b3a.51.1790841118638; Thu, 01 Oct 2026 00:51:58 -0700 (PDT) Received: from localhost.localdomain (60-250-196-139.hinet-ip.hinet.net. [60.250.196.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-88819db440csm666843b3a.60.2026.10.01.00.51.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Oct 2026 00:51:57 -0700 (PDT) From: Zi-Yu Chen To: Andi Shyti , linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Jacky Huang , Shan-Chun Hung , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Andrew Jeffery , Zi-Yu Chen Subject: [PATCH v11 2/3] i2c: ma35d1: Add Nuvoton MA35D1 I2C driver support Date: Thu, 1 Oct 2026 15:51:00 +0800 Message-Id: <20261001075101.489660-3-zychennvt@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20261001075101.489660-1-zychennvt@gmail.com> References: <20261001075101.489660-1-zychennvt@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add I2C support for Nuvoton MA35D1 SoC. The controller supports standard, fast and fast-plus modes, and provides controller/target functionality. Signed-off-by: Zi-Yu Chen --- drivers/i2c/busses/Kconfig | 13 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-ma35d1.c | 796 ++++++++++++++++++++++++++++++++ 3 files changed, 810 insertions(+) create mode 100644 drivers/i2c/busses/i2c-ma35d1.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d7b89508311f..e69120d46977 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1602,4 +1602,17 @@ config I2C_VIRTIO This driver can also be built as a module. If so, the module will be called i2c-virtio. =20 +config I2C_MA35D1 + tristate "Nuvoton MA35D1 I2C driver" + depends on ARCH_MA35 || COMPILE_TEST + select I2C_SLAVE + help + If you say yes to this option, support will be included for the + I2C controller in the Nuvoton MA35D1 SoC. This driver + supports the standard I2C bus protocols, including master and + slave modes. + + This driver can also be built as a module. If so, the module + will be called i2c-ma35d1. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3755c54b3d82..ca75dae4955c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_I2C_XILINX) +=3D i2c-xiic.o obj-$(CONFIG_I2C_XLP9XX) +=3D i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) +=3D i2c-rcar.o obj-$(CONFIG_I2C_GXP) +=3D i2c-gxp.o +obj-$(CONFIG_I2C_MA35D1) +=3D i2c-ma35d1.o =20 # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) +=3D i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-ma35d1.c b/drivers/i2c/busses/i2c-ma35d= 1.c new file mode 100644 index 000000000000..2a4985dc22c6 --- /dev/null +++ b/drivers/i2c/busses/i2c-ma35d1.c @@ -0,0 +1,796 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 Nuvoton technology corporation. + * + * Author: Zi-Yu Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* MA35D1 I2C registers offset */ +#define MA35_CTL0 0x00 +#define MA35_ADDR0 0x04 +#define MA35_DAT 0x08 +#define MA35_STATUS0 0x0c +#define MA35_CLKDIV 0x10 +#define MA35_TOCTL 0x14 +#define MA35_ADDR1 0x18 +#define MA35_ADDR2 0x1c +#define MA35_ADDR3 0x20 +#define MA35_ADDRMSK0 0x24 +#define MA35_ADDRMSK1 0x28 +#define MA35_ADDRMSK2 0x2c +#define MA35_ADDRMSK3 0x30 +#define MA35_WKCTL 0x3c +#define MA35_WKSTS 0x40 +#define MA35_CTL1 0x44 +#define MA35_STATUS1 0x48 +#define MA35_TMCTL 0x4c +#define MA35_BUSCTL 0x50 +#define MA35_BUSTCTL 0x54 +#define MA35_BUSSTS 0x58 +#define MA35_PKTSIZE 0x5c +#define MA35_PKTCRC 0x60 +#define MA35_BUSTOUT 0x64 +#define MA35_CLKTOUT 0x68 +#define MA35_AUTOCNT 0x78 + +/* MA35D1 I2C Status */ +/* Controller */ +#define MA35_M_START 0x08 /* Start */ +#define MA35_M_REPEAT_START 0x10 /* Controller Repeat Start */ +#define MA35_M_TRAN_ADDR_ACK 0x18 /* Controller Transmit Address ACK */ +#define MA35_M_TRAN_ADDR_NACK 0x20 /* Controller Transmit Address NACK */ +#define MA35_M_TRAN_DATA_ACK 0x28 /* Controller Transmit Data ACK */ +#define MA35_M_TRAN_DATA_NACK 0x30 /* Controller Transmit Data NACK */ +#define MA35_M_ARB_LOST 0x38 /* Controller Arbitration Lost */ +#define MA35_M_RECE_ADDR_ACK 0x40 /* Controller Receive Address ACK */ +#define MA35_M_RECE_ADDR_NACK 0x48 /* Controller Receive Address NACK */ +#define MA35_M_RECE_DATA_ACK 0x50 /* Controller Receive Data ACK */ +#define MA35_M_RECE_DATA_NACK 0x58 /* Controller Receive Data NACK */ +#define MA35_BUS_ERROR 0x00 /* Bus error */ + +/* Target */ +#define MA35_S_REPEAT_START_STOP 0xa0 /* Target Transmit Repeat Start or S= top */ +#define MA35_S_TRAN_ADDR_ACK 0xa8 /* Target Transmit Address ACK */ +#define MA35_S_TRAN_DATA_ACK 0xb8 /* Target Transmit Data ACK */ +#define MA35_S_TRAN_DATA_NACK 0xc0 /* Target Transmit Data NACK */ +#define MA35_S_TRAN_LAST_DATA_ACK 0xc8 /* Target Transmit Last Data ACK */ +#define MA35_S_RECE_ADDR_ACK 0x60 /* Target Receive Address ACK */ +#define MA35_S_RECE_ARB_LOST 0x68 /* Target Receive Arbitration Lost */ +#define MA35_S_RECE_DATA_ACK 0x80 /* Target Receive Data ACK */ +#define MA35_S_RECE_DATA_NACK 0x88 /* Target Receive Data NACK */ + +/* Other */ +#define MA35_ADDR_TRAN_ARB_LOST 0xb0 /* Address Transmit Arbitration Lost= */ +#define MA35_BUS_RELEASED 0xf8 /* Bus Released */ + +/* I2C_CTL constant definitions. */ +#define MA35_CTL_AA BIT(2) +#define MA35_CTL_SI BIT(3) +#define MA35_CTL_STO BIT(4) +#define MA35_CTL_STA BIT(5) +#define MA35_CTL_I2CEN BIT(6) +#define MA35_CTL_INTEN BIT(7) +#define MA35_CTL_SI_AA (MA35_CTL_SI | MA35_CTL_AA) +#define MA35_CTL_STO_SI (MA35_CTL_STO | MA35_CTL_SI) +#define MA35_CTL_STA_SI (MA35_CTL_STA | MA35_CTL_SI) + +/* Constants */ +#define MA35_CLKDIV_MSK GENMASK(9, 0) +#define MA35_I2C_PM_TIMEOUT_MS 5000 +#define MA35_STOP_TIMEOUT_MS 50 + +struct ma35d1_i2c { + spinlock_t lock; + wait_queue_head_t wait; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_idx; + unsigned int msg_ptr; + int err; + int irq; + void __iomem *regs; + struct clk *clk; + struct device *dev; + struct i2c_adapter adap; + struct i2c_client *target; + struct reset_control *rst; + bool target_reject; +}; + +static inline bool ma35d1_is_controller_status(unsigned int status) +{ + return status >=3D MA35_M_START && status <=3D MA35_M_RECE_DATA_NACK; +} + +/* + * ma35d1_i2c_write_ctl - Update the I2C control register + * @i2c: Pointer to the ma35d1 i2c instance + * @ctl: Control bits to set (e.g., MA35_CTL_STA, SI, AA) + * + * Read-modify-write the CTL0 register while preserving unrelated bits. + */ +static void ma35d1_i2c_write_ctl(struct ma35d1_i2c *i2c, unsigned int ctl) +{ + unsigned int val; + + guard(spinlock_irqsave)(&i2c->lock); + val =3D readl(i2c->regs + MA35_CTL0); + val &=3D ~(MA35_CTL_SI_AA); + val |=3D ctl; + writel(val, i2c->regs + MA35_CTL0); +} + +static void ma35d1_i2c_set_addr(struct ma35d1_i2c *i2c) +{ + unsigned int rw =3D i2c->msg->flags & I2C_M_RD; + + writel(((i2c->msg->addr & 0x7f) << 1) | rw, i2c->regs + MA35_DAT); +} + +static void ma35d1_i2c_controller_complete(struct ma35d1_i2c *i2c) +{ + i2c->msg_ptr =3D 0; + i2c->msg =3D NULL; + i2c->msg_idx++; + i2c->msg_num =3D 0; + + wake_up(&i2c->wait); +} + +static void ma35d1_i2c_reset(struct ma35d1_i2c *i2c) +{ + unsigned int clkdiv, slvaddr; + + clkdiv =3D readl(i2c->regs + MA35_CLKDIV); + slvaddr =3D readl(i2c->regs + MA35_ADDR0); + + disable_irq(i2c->irq); + i2c->msg =3D NULL; + reset_control_assert(i2c->rst); + usleep_range(10, 20); + reset_control_deassert(i2c->rst); + enable_irq(i2c->irq); + + writel(clkdiv, (i2c->regs + MA35_CLKDIV)); + ma35d1_i2c_write_ctl(i2c, MA35_CTL_I2CEN | MA35_CTL_INTEN); + + if (i2c->target) + writel(slvaddr, i2c->regs + MA35_ADDR0); +} + +static void ma35d1_i2c_stop(struct ma35d1_i2c *i2c, int ret) +{ + ma35d1_i2c_write_ctl(i2c, MA35_CTL_STO_SI); + + if (ret) + i2c->err =3D ret; + + ma35d1_i2c_controller_complete(i2c); +} + +/* + * ma35d1_i2c_restore_idle - restore controller state to idle + * @i2c: Pointer to the ma35d1 i2c instance + * + * Restore the controller to an idle state after an unexpected event. + * Abort an active controller transfer, otherwise re-arm target mode + * if enabled. + */ +static void ma35d1_i2c_restore_idle(struct ma35d1_i2c *i2c) +{ + if (i2c->msg) { + ma35d1_i2c_stop(i2c, -EIO); + } else if (i2c->target) { + i2c->target_reject =3D false; + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI_AA); + } else { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + } +} + +/* Check if this is the last message in the set */ +static inline bool is_last_msg(struct ma35d1_i2c *i2c) +{ + return i2c->msg_idx >=3D (i2c->msg_num - 1); +} + +/* Check if this is the last byte in the current message */ +static inline bool is_last_byte(struct ma35d1_i2c *i2c) +{ + return i2c->msg_ptr =3D=3D i2c->msg->len - 1; +} + +/* Check if reached the end of the current message */ +static inline bool is_msgend(struct ma35d1_i2c *i2c) +{ + return i2c->msg_ptr >=3D i2c->msg->len; +} + +/* + * ma35d1_i2c_irq_target_trx - I2C Target state machine handler + * @i2c: ma35d1 i2c instance + * @i2c_status: hardware status code from MA35_STATUS0 + */ +static irqreturn_t ma35d1_i2c_irq_target_trx(struct ma35d1_i2c *i2c, + unsigned long i2c_status) +{ + unsigned char byte =3D 0; + int ret; + + switch (i2c_status) { + case MA35_S_RECE_ARB_LOST: + /* + * Arbitration lost during address transmission phase. + * The hardware switches to Target Transmitter mode when + * our own SLA+W is detected on the bus. + */ + i2c->err =3D -EAGAIN; + ma35d1_i2c_controller_complete(i2c); + ret =3D i2c_slave_event(i2c->target, I2C_SLAVE_WRITE_REQUESTED, + &byte); + if (ret) + i2c->target_reject =3D true; + break; + + case MA35_S_RECE_ADDR_ACK: + /* Own SLA+W has been receive; ACK has been return */ + ret =3D i2c_slave_event(i2c->target, I2C_SLAVE_WRITE_REQUESTED, + &byte); + if (ret) + i2c->target_reject =3D true; + break; + + case MA35_S_TRAN_DATA_NACK: + case MA35_S_RECE_DATA_NACK: + /* + * Data byte or last data in I2CDAT has been transmitted and NACK receiv= ed, + * or previously addressed with own SLA address and NACK returned. + */ + i2c->target_reject =3D false; + break; + + case MA35_S_RECE_DATA_ACK: + /* + * Previously address with own SLA address Data has been received; + * ACK has been returned + */ + byte =3D readb(i2c->regs + MA35_DAT); + i2c_slave_event(i2c->target, I2C_SLAVE_WRITE_RECEIVED, &byte); + break; + + case MA35_ADDR_TRAN_ARB_LOST: + /* + * Arbitration lost during address transmission phase. + * The hardware switches to Target Receiver mode when + * our own SLA+R is detected on the bus. + */ + i2c->err =3D -EAGAIN; + ma35d1_i2c_controller_complete(i2c); + i2c_slave_event(i2c->target, I2C_SLAVE_READ_REQUESTED, &byte); + writel(byte, i2c->regs + MA35_DAT); + break; + + case MA35_S_TRAN_ADDR_ACK: + /* Own SLA+R has been receive; ACK has been return */ + i2c_slave_event(i2c->target, I2C_SLAVE_READ_REQUESTED, &byte); + writel(byte, i2c->regs + MA35_DAT); + break; + + case MA35_S_TRAN_DATA_ACK: + i2c_slave_event(i2c->target, I2C_SLAVE_READ_PROCESSED, &byte); + writel(byte, i2c->regs + MA35_DAT); + break; + + case MA35_S_REPEAT_START_STOP: + /* + * A STOP or repeated START has been received + * while still addressed as Target/Receiver + */ + i2c_slave_event(i2c->target, I2C_SLAVE_STOP, &byte); + i2c->target_reject =3D false; + break; + + default: + dev_err(i2c->dev, "Status 0x%02lx is NOT processed\n", + i2c_status); + ma35d1_i2c_restore_idle(i2c); + return IRQ_NONE; + } + if (i2c->target_reject) + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + else + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI_AA); + return IRQ_HANDLED; +} + +/* + * ma35d1_i2c_irq_controller_trx - I2C Controller state machine handler + * @i2c: ma35d1 i2c instance + * @i2c_status: hardware status code from MA35_STATUS0 + */ +static irqreturn_t ma35d1_i2c_irq_controller_trx(struct ma35d1_i2c *i2c, + unsigned long i2c_status) +{ + unsigned char byte; + + /* Ensuring messages are absolutely valid in Controller mode. */ + if (unlikely(!i2c->msg)) { + dev_err(i2c->dev, "Spurious controller interrupt (status: 0x%02lx)\n", i= 2c_status); + ma35d1_i2c_restore_idle(i2c); + return IRQ_HANDLED; + } + + switch (i2c_status) { + case MA35_M_START: + case MA35_M_REPEAT_START: + ma35d1_i2c_set_addr(i2c); + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + break; + + case MA35_M_TRAN_ADDR_ACK: + case MA35_M_TRAN_DATA_ACK: + /* SLA+W has been transmitted and ACK has been received */ + if (i2c_status =3D=3D MA35_M_TRAN_ADDR_ACK) { + if (is_last_msg(i2c) && i2c->msg->len =3D=3D 0) { + ma35d1_i2c_stop(i2c, 0); + return IRQ_HANDLED; + } + } + + if (!is_msgend(i2c)) { + byte =3D i2c->msg->buf[i2c->msg_ptr++]; + writel(byte, i2c->regs + MA35_DAT); + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + } else if (!is_last_msg(i2c)) { + dev_dbg(i2c->dev, "WRITE: Next Message\n"); + + i2c->msg_ptr =3D 0; + i2c->msg_idx++; + i2c->msg++; + + ma35d1_i2c_write_ctl(i2c, MA35_CTL_STA | MA35_CTL_SI); + } else { + ma35d1_i2c_stop(i2c, 0); + } + break; + + case MA35_M_TRAN_DATA_NACK: + ma35d1_i2c_stop(i2c, -EIO); + break; + + case MA35_M_TRAN_ADDR_NACK: + case MA35_M_RECE_ADDR_NACK: + /* + * Controller Transmit Address NACK + * 0x20: SLA+W has been transmitted and NACK has been received + * 0x48: SLA+R has been transmitted and NACK has been received + */ + dev_dbg(i2c->dev, "\n i2c: ack was not received\n"); + ma35d1_i2c_stop(i2c, -ENXIO); + break; + + case MA35_M_RECE_ADDR_ACK: + if (is_msgend(i2c)) { + if (is_last_msg(i2c)) { + ma35d1_i2c_stop(i2c, 0); + } else { + dev_dbg(i2c->dev, "READ: Next Transfer\n"); + + i2c->msg_ptr =3D 0; + i2c->msg_idx++; + i2c->msg++; + + ma35d1_i2c_write_ctl(i2c, MA35_CTL_STA_SI); + } + } else if (i2c->msg->len =3D=3D 1) { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + } else { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI_AA); + } + break; + + case MA35_M_RECE_DATA_ACK: + case MA35_M_RECE_DATA_NACK: + /* DATA has been received and ACK/NACK has been received */ + byte =3D readb(i2c->regs + MA35_DAT); + i2c->msg->buf[i2c->msg_ptr++] =3D byte; + + if (is_last_byte(i2c)) { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + } else if (is_msgend(i2c)) { + if (is_last_msg(i2c)) { + dev_dbg(i2c->dev, "READ: Send Stop\n"); + + ma35d1_i2c_stop(i2c, 0); + } else { + dev_dbg(i2c->dev, "READ: Next Transfer\n"); + + i2c->msg_ptr =3D 0; + i2c->msg_idx++; + i2c->msg++; + + ma35d1_i2c_write_ctl(i2c, MA35_CTL_STA_SI); + } + } else { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI_AA); + } + break; + + case MA35_M_ARB_LOST: + /* Arbitration Lost */ + i2c->err =3D -EAGAIN; + ma35d1_i2c_controller_complete(i2c); + ma35d1_i2c_write_ctl(i2c, MA35_CTL_SI); + break; + + default: + dev_err(i2c->dev, "Status 0x%02lx is NOT processed\n", + i2c_status); + ma35d1_i2c_restore_idle(i2c); + return IRQ_NONE; + } + return IRQ_HANDLED; +} + +static irqreturn_t ma35d1_i2c_irq(int irqno, void *dev_id) +{ + struct ma35d1_i2c *i2c =3D dev_id; + unsigned long status; + + status =3D readl(i2c->regs + MA35_STATUS0); + + if (status =3D=3D MA35_BUS_ERROR) { + dev_err(i2c->dev, "bus error\n"); + ma35d1_i2c_restore_idle(i2c); + return IRQ_HANDLED; + } + + if (ma35d1_is_controller_status(status)) + return ma35d1_i2c_irq_controller_trx(i2c, status); + else + return ma35d1_i2c_irq_target_trx(i2c, status); +} + +static int ma35d1_i2c_doxfer(struct ma35d1_i2c *i2c, struct i2c_msg *msgs, + int num) +{ + unsigned long timeout; + unsigned int val; + int ret, err; + + i2c->msg =3D msgs; + i2c->msg_num =3D num; + i2c->msg_ptr =3D 0; + i2c->msg_idx =3D 0; + i2c->err =3D 0; + + ma35d1_i2c_write_ctl(i2c, MA35_CTL_STA); + + timeout =3D wait_event_timeout(i2c->wait, i2c->msg_num =3D=3D 0, HZ * 5); + ret =3D i2c->msg_idx; + + if (timeout =3D=3D 0) { + dev_dbg(i2c->dev, "xfer timeout\n"); + ret =3D -ETIMEDOUT; + goto reset; + } + + err =3D readl_poll_timeout(i2c->regs + MA35_CTL0, val, + !(val & MA35_CTL_STO), 100, + MA35_STOP_TIMEOUT_MS * 1000); + if (err) { + dev_err(i2c->dev, "bus idle timeout\n"); + ret =3D -EBUSY; + goto reset; + } else if (i2c->err) { + dev_dbg(i2c->dev, "xfer error %d\n", i2c->err); + ret =3D i2c->err; + } + return ret; + +reset: + ma35d1_i2c_reset(i2c); + return ret; +} + +static int ma35d1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct ma35d1_i2c *i2c =3D i2c_get_adapdata(adap); + int ret; + + ret =3D pm_runtime_resume_and_get(i2c->dev); + if (ret) + return ret; + + ret =3D ma35d1_i2c_doxfer(i2c, msgs, num); + + if (i2c->target) + ma35d1_i2c_write_ctl(i2c, MA35_CTL_AA); + pm_runtime_put_autosuspend(i2c->dev); + + return ret; +} + +static int ma35d1_reg_target(struct i2c_client *target) +{ + struct ma35d1_i2c *i2c =3D i2c_get_adapdata(target->adapter); + unsigned int slvaddr; + int ret; + + if (i2c->target) + return -EBUSY; + + if (target->flags & I2C_CLIENT_TEN) + return -EAFNOSUPPORT; + + /* Keep device active for target mode listening. */ + ret =3D pm_runtime_resume_and_get(i2c->dev); + if (ret) { + dev_err(i2c->dev, "failed to resume i2c controller\n"); + return ret; + } + + i2c->target =3D target; + + slvaddr =3D target->addr << 1; + writel(slvaddr, i2c->regs + MA35_ADDR0); + + /* I2C enter SLV mode */ + ma35d1_i2c_write_ctl(i2c, MA35_CTL_AA); + + return 0; +} + +static int ma35d1_unreg_target(struct i2c_client *target) +{ + struct ma35d1_i2c *i2c =3D i2c_get_adapdata(target->adapter); + int ret; + + if (!i2c->target) + return -EINVAL; + + writel(0, i2c->regs + MA35_ADDR0); + /* Clear AA bit */ + ma35d1_i2c_write_ctl(i2c, 0); + + synchronize_irq(i2c->irq); + i2c->target =3D NULL; + + ret =3D pm_runtime_put_sync(i2c->dev); + if (ret < 0) + dev_err(i2c->dev, "failed to suspend i2c controller"); + + return 0; +} + +/* Declare Our I2C Functionality */ +static u32 ma35d1_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +/* I2C Bus Registration Info */ +static const struct i2c_algorithm ma35d1_i2c_algorithm =3D { + .xfer =3D ma35d1_i2c_xfer, + .functionality =3D ma35d1_i2c_func, + .reg_target =3D ma35d1_reg_target, + .unreg_target =3D ma35d1_unreg_target, +}; + +static const struct i2c_adapter_quirks ma35d1_i2c_quirks =3D { + .flags =3D I2C_AQ_NO_ZERO_LEN_READ, +}; + +static int ma35d1_i2c_suspend(struct device *dev) +{ + struct ma35d1_i2c *i2c =3D dev_get_drvdata(dev); + unsigned int val; + int ret; + + /* Prepare for wake-up from I2C events if target mode is active */ + if (i2c->target) { + ma35d1_i2c_write_ctl(i2c, MA35_CTL_AA); + + /* Setup wake-up control */ + writel(0x1, i2c->regs + MA35_WKCTL); + + /* Clear pending wake-up flags */ + val =3D readl(i2c->regs + MA35_WKSTS); + writel(val, i2c->regs + MA35_WKSTS); + + ret =3D enable_irq_wake(i2c->irq); + if (ret) + return ret; + return 0; + } + return pm_runtime_force_suspend(dev); +} + +static int ma35d1_i2c_resume(struct device *dev) +{ + struct ma35d1_i2c *i2c =3D dev_get_drvdata(dev); + unsigned int val; + + if (i2c->target) { + /* Disable wake-up */ + writel(0x0, i2c->regs + MA35_WKCTL); + + /* Clear pending wake-up flags */ + val =3D readl(i2c->regs + MA35_WKSTS); + writel(val, i2c->regs + MA35_WKSTS); + + disable_irq_wake(i2c->irq); + return 0; + } + return pm_runtime_force_resume(dev); +} + +static int ma35d1_i2c_runtime_suspend(struct device *dev) +{ + struct ma35d1_i2c *i2c =3D dev_get_drvdata(dev); + + clk_disable(i2c->clk); + + return 0; +} + +static int ma35d1_i2c_runtime_resume(struct device *dev) +{ + struct ma35d1_i2c *i2c =3D dev_get_drvdata(dev); + int ret; + + ret =3D clk_enable(i2c->clk); + if (ret) { + dev_err(dev, "failed to enable clock in resume\n"); + return ret; + } + + return 0; +} + +static void ma35d1_i2c_pm_cleanup(void *data) +{ + struct device *dev =3D data; + + pm_runtime_get_sync(dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +} + +static int ma35d1_i2c_probe(struct platform_device *pdev) +{ + unsigned int busfreq =3D I2C_MAX_STANDARD_MODE_FREQ; + struct device *dev =3D &pdev->dev; + struct ma35d1_i2c *i2c; + struct resource *res; + int ret, clkdiv; + u32 val; + + i2c =3D devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + init_waitqueue_head(&i2c->wait); + spin_lock_init(&i2c->lock); + + i2c->dev =3D dev; + + i2c->clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(i2c->clk)) + return dev_err_probe(dev, PTR_ERR(i2c->clk), + "failed to get core clk\n"); + + i2c->regs =3D devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(i2c->regs)) + return dev_err_probe(dev, PTR_ERR(i2c->regs), + "can't get IO memory\n"); + + i2c->rst =3D devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(i2c->rst)) + return dev_err_probe(dev, PTR_ERR(i2c->rst), + "failed to get reset control\n"); + + ret =3D reset_control_deassert(i2c->rst); + if (ret) + return dev_err_probe(dev, ret, "failed to deassert reset line\n"); + + /* Setup info block for the I2C core */ + strscpy(i2c->adap.name, "ma35d1-i2c", sizeof(i2c->adap.name)); + i2c->adap.owner =3D THIS_MODULE; + i2c->adap.algo =3D &ma35d1_i2c_algorithm; + i2c->adap.quirks =3D &ma35d1_i2c_quirks; + i2c->adap.retries =3D 2; + i2c->adap.algo_data =3D i2c; + i2c->adap.dev.parent =3D &pdev->dev; + i2c->adap.dev.of_node =3D pdev->dev.of_node; + i2c_set_adapdata(&i2c->adap, i2c); + + if (!device_property_read_u32(dev, "clock-frequency", &val)) { + if (val !=3D 0 && val <=3D MEGA) + busfreq =3D val; + } + /* Calculate divider based on the current peripheral clock rate */ + clkdiv =3D DIV_ROUND_CLOSEST(clk_get_rate(i2c->clk), busfreq * 4) - 1; + if (clkdiv < 0 || clkdiv > 0x3ff) + return dev_err_probe(dev, -EINVAL, "invalid clkdiv value: %d\n", + clkdiv); + + i2c->irq =3D platform_get_irq(pdev, 0); + if (i2c->irq < 0) + return dev_err_probe(dev, i2c->irq, "failed to get irq\n"); + + platform_set_drvdata(pdev, i2c); + + pm_runtime_set_autosuspend_delay(dev, MA35_I2C_PM_TIMEOUT_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret =3D devm_add_action_or_reset(dev, ma35d1_i2c_pm_cleanup, dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to add pm cleanup action\n"); + + writel(MA35_CTL_I2CEN | MA35_CTL_INTEN, i2c->regs + MA35_CTL0); + writel(FIELD_PREP(MA35_CLKDIV_MSK, clkdiv), i2c->regs + MA35_CLKDIV); + + ret =3D devm_request_irq(dev, i2c->irq, ma35d1_i2c_irq, 0, dev_name(dev), + i2c); + if (ret) + return dev_err_probe(dev, ret, "cannot claim IRQ %d\n", + i2c->irq); + + ret =3D devm_i2c_add_adapter(dev, &i2c->adap); + if (ret) + return dev_err_probe(dev, ret, + "failed to add bus to i2c core\n"); + + dev_info(&i2c->adap.dev, "%pa MA35D1 I2C adapter registered\n", + &res->start); + return 0; +} + +static const struct dev_pm_ops ma35d1_i2c_pmops =3D { + SYSTEM_SLEEP_PM_OPS(ma35d1_i2c_suspend, ma35d1_i2c_resume) + RUNTIME_PM_OPS(ma35d1_i2c_runtime_suspend, + ma35d1_i2c_runtime_resume, NULL) +}; + +static const struct of_device_id ma35d1_i2c_of_match[] =3D { + { .compatible =3D "nuvoton,ma35d1-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ma35d1_i2c_of_match); + +static struct platform_driver ma35d1_i2c_driver =3D { + .probe =3D ma35d1_i2c_probe, + .driver =3D { + .name =3D "ma35d1-i2c", + .of_match_table =3D ma35d1_i2c_of_match, + .pm =3D pm_ptr(&ma35d1_i2c_pmops), + }, +}; +module_platform_driver(ma35d1_i2c_driver); + +MODULE_AUTHOR("Zi-Yu Chen "); +MODULE_DESCRIPTION("MA35D1 I2C Bus Driver"); +MODULE_LICENSE("GPL"); --=20 2.34.1 From nobody Fri Oct 2 00:41:01 2026 Received: from mail-pz2-f39.google.com (mail-pz2-f39.google.com [74.125.228.39]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 18ABC4848AE for ; Thu, 1 Oct 2026 07:52:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.39 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841123; cv=none; b=BMTAUXC8yj8JtvZIy/qyJZRLuPAxM1djMur1foi6LcYaQwY2Ylrd1fv3x35wPo5LeUgawcVINCWSWGXLkVrTVOQH1Av9Z462RUSAOEq4L2csWCCTeXvclHbZ6gCN10TU/cZp0QkRV4A5tmLPdeNDg0jgXgBk6TEeqtAtrheJIeA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790841123; c=relaxed/simple; bh=0aVue5qlHixKUDgsg0/JaFYVf7jDnLSm4fZZkO8n+uE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=inMbVH0LprASuEJ2Zr/MXu4tsMljJ4F6+faJEWLmKE1kvTNP96PgInbBARLkHXCv+WzLISl19xTqohsqmlN4jzc2WtKUyzOF7Q5lP6vT90MHVvisXKlrfLyazyLAJmNgymDYZLkZ2fbwBXDuHwL7Hco0yQSEtDH+GRjCbePZStU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eQ2nQkl6; arc=none smtp.client-ip=74.125.228.39 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eQ2nQkl6" Received: by mail-pz2-f39.google.com with SMTP id d2e1a72fcca58-88098dbba5fso1370900b3a.1 for ; Thu, 01 Oct 2026 00:52:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790841121; x=1791445921; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=KjOU7YARtrXAbkjxgoW/D83MupO/fBHcHqOARUheMbc=; b=eQ2nQkl6xX4DO7OtJKlDC9LSi/pWn3aq/InuMEWwzSavkm3nYfWZmeabTiYHqpIexJ wYJLovMz8avshQIk/ZeOPryr/8R3Q22pm6vb50s9NGQMV5N9UeS9Slb32nnf8kxm4uDo jbEqcwQSXZgNAF4cWuN8SJbgv1DzXZmNGQCEpSWkpOZbfDDXZrnciucWN34D7HN26d9I XE8K7Vog1VcRYkAYRRYjwqnxkGZkCg1fmiuU5LrpdoHBBFa7cIVoNyJMUxHAlDrKNJ9N i3iv/9aWQreMfVYDVgK2rM6NQsQca+GEXBImBw0aCvv6zzwZDRepPWzzysNfKGXbRBUu 9M8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790841121; x=1791445921; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=KjOU7YARtrXAbkjxgoW/D83MupO/fBHcHqOARUheMbc=; b=Kub4uTWKW6YuylQYZuWYcarNh0dMxw4UTGzbrx3xi8iHYiqqMOabipjySp8y9bC7A9 ykxcki+nXYFf3Mizh1O5FgyqBZnHw5AzSZExPYlCQmYrAY4kkGjYH2i8iY9jKYPvUl23 0QppX2GRvzzKp6jht9YXUmRX0Egn4Lw2tDg/MjKGbgUnPfQ6xBcViypZfQjOs8Di3ZP4 LLTPatipSc+l6rIPbTQHbj5YNJTNKAskHsAlhJ57djrCwivwq3dFu3RxWUsnwNiFhgoM cplvQV6d2zlrrCzxikdqbYQ9eYuwypo9ZN7Xn+30T1nADr78nTDpikMDq3PkTL5VXoWK Oqkg== X-Forwarded-Encrypted: i=1; AKwUvBxGgoHTh2Wz6cP+dQZ74KyPtaD9pHG6AnoM27BKs0wC34GztdlfR8T1ey8YjHZ6P1Q4VbRKJNbvHCN3oGI=@vger.kernel.org X-Gm-Message-State: AFuF++mNSzoRrchosw1xSXcUwVBAwn5M7xG5waxGtjOLk/Kf6t50QGSY Gnn9KJ3tKxFVZqKL2jqYHUgRGBqJh3CX0OW4Fi0O7/p9esJjq52pfAU4 X-Gm-Gg: AYBFou15VP0BTuYCh5/QxGbCvAiEdJyz5BQq0LJTdavKzWg7yCLlB7600xPq1pzjl3M lu4Qi5ceo6ZDk8zuBkPmjxB0YJJsvqU4puEYlGAHNUal1Rjwh4rJlNw6nmy4ts4TqASDM5JIKFf zRmNCkm/CUyE2sIOC5ZOO+1teNamDv0xjgLtHxzlF3KGYXAUU8Bi0iZRB+dsAairqu7VYnkD3LC Du2yq7g2hNgRgOCvZ5y7GqGvZBP8mUNF8DtxQZfZ2/gbly1GqFDaQU8HRpNGb3ISmUa0sqlYn5f ELvksaumuCYxfgaYV9JoMEeZBRL5IwCfXZjsCS7sAU+aHgdWw0ldh157n2fzG8EdV3vmqIUYWW3 6Q1Tk5IPfdyFOfF+/z3VB1TDZehsXEtK7C93zipUluzUvcQzROCGveKooaKMUi0J45nfqgW/g4k erO87mp/93NgnvbQh8bNXdH0Q8LPv6yPULbXr4m0vLLXw6gu5bBq4vKcHBVed3M4JyXJ/m3/ZL1 RJQWXRwPv804loyOYsUp8TZhCzMJekPDpma8h5E4iKllUAnY1NLrFDn X-Received: by 2002:a05:6a00:2301:b0:886:95df:c50c with SMTP id d2e1a72fcca58-887fe5c8dddmr1176734b3a.26.1790841121413; Thu, 01 Oct 2026 00:52:01 -0700 (PDT) Received: from localhost.localdomain (60-250-196-139.hinet-ip.hinet.net. [60.250.196.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-88819db440csm666843b3a.60.2026.10.01.00.51.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Oct 2026 00:52:00 -0700 (PDT) From: Zi-Yu Chen To: Andi Shyti , linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Jacky Huang , Shan-Chun Hung , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Andrew Jeffery , Zi-Yu Chen Subject: [PATCH v11 3/3] arm64: dts: nuvoton: Add I2C nodes for MA35D1 SoC Date: Thu, 1 Oct 2026 15:51:01 +0800 Message-Id: <20261001075101.489660-4-zychennvt@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20261001075101.489660-1-zychennvt@gmail.com> References: <20261001075101.489660-1-zychennvt@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add I2C controller nodes to the MA35D1 SoC dtsi file. Also, enable the I2C2 interface on the MA35D1 SOM board and configure its pinctrl to allow communication with the onboard NAU8822 audio codec Signed-off-by: Zi-Yu Chen --- .../boot/dts/nuvoton/ma35d1-som-256m.dts | 20 ++++++ arch/arm64/boot/dts/nuvoton/ma35d1.dtsi | 72 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts b/arch/arm64/b= oot/dts/nuvoton/ma35d1-som-256m.dts index a029b660e8dc..488567f830a6 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts +++ b/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts @@ -57,6 +57,18 @@ &clk { "integer"; }; =20 +&i2c2 { + status =3D "okay"; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pinctrl_i2c2>; + + nau8822: audio-codec@1a { + compatible =3D "nuvoton,nau8822"; + reg =3D <0x1a>; + nuvoton,spk-btl; + }; +}; + &pinctrl { uart-grp { pinctrl_uart0: uart0-pins { @@ -100,6 +112,14 @@ pinctrl_uart16: uart16-pins { power-source =3D <1>; }; }; + + i2c-grp { + pinctrl_i2c2: i2c2-pins { + nuvoton,pins =3D <1 8 4>, + <1 9 4>; + bias-disable; + }; + }; }; =20 &uart0 { diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi b/arch/arm64/boot/dts/= nuvoton/ma35d1.dtsi index 7228ad4735b5..28488889f564 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi +++ b/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi @@ -372,6 +372,78 @@ uart15: serial@407f0000 { status =3D "disabled"; }; =20 + i2c0: i2c@40800000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40800000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C0_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C0>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + + i2c1: i2c@40810000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40810000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C1_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C1>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + + i2c2: i2c@40820000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40820000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C2_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C2>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + + i2c3: i2c@40830000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40830000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C3_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C3>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + + i2c4: i2c@40840000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40840000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C4_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C4>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + + i2c5: i2c@40850000 { + compatible =3D "nuvoton,ma35d1-i2c"; + reg =3D <0x0 0x40850000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&clk I2C5_GATE>; + clock-frequency =3D <100000>; + resets =3D <&sys MA35D1_RESET_I2C5>; + status =3D "disabled"; + #address-cells =3D <1>; + #size-cells =3D <0>; + }; + uart16: serial@40880000 { compatible =3D "nuvoton,ma35d1-uart"; reg =3D <0x0 0x40880000 0x0 0x100>; --=20 2.34.1