From nobody Tue Aug 25 14:34:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84A3E1A5B8C; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; cv=none; b=bqhv/H6QncZ85KbiCRBUpoHrO7jMEEhuLV5fZM9jod/O6XZi5UcjjavXowybOIMLj4GgR6aQkFf9/pZCgRdivWOv9Q2n7TyvDw1bqxOycHYQzaq3N4vIo5tpCg9wIDHFhXgE4suEM7+9ino9/kHSar7XeNIC/7L0z8NbP1aDOxI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; c=relaxed/simple; bh=tivZ5BYNFH4W6I41+vAAaK6MuTK6IPDTNH6UPZleqPQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hKWb7NK8WcYVkSsXOuP8SVmityR1dJkOIR567zGDWmpCx2+6LTMNpFqhmkANhi7qc8fK70sqGxEIqoiIlthDbhfD5LEO5QtaExaEmCuh+JOFRIPO0HxGXONma228de91ca/cW3yn1rMkqzrjcrOXuki5lz2u3F2J+0zVUWBH5L0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Qx2YJx7X; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Qx2YJx7X" Received: by smtp.kernel.org (Postfix) with ESMTPS id 15DD9C2BCC7; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786688766; bh=tivZ5BYNFH4W6I41+vAAaK6MuTK6IPDTNH6UPZleqPQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Qx2YJx7X0+aP/+wYdJ83bvBXdHWsofmEBlSPjKCLlt2t7y4wyWw4MTERtWjETEhW2 Khasy0c8i6x0xHaocaAuzJ2ZFUwK64yDnwe0NUyvSHTHeOKtHCVoYifD47rNL/Sir+ wAb4oaA4yiAi/PSBtTtGSqopsePQicO0ZQ1BaHQlSXo8FSJQaa8hWdvXxEmJQAEGCc FH0T+r9egdMR+uF3jGcCec8eHaup+h7cw2XL7oFdVm6dtpNIWBgljcdgqRWVkW86Fb DFCRh6NrEY2k4kW5tjtulMWwfpn97Mwb71xYLSG/XTmwT4AFsCvRGfvJyqsnsf3yT3 tGdulo3DP9nAA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E75DEC5CFC1; Fri, 14 Aug 2026 06:26:05 +0000 (UTC) From: Long Zhao via B4 Relay Date: Fri, 14 Aug 2026 14:25:41 +0800 Subject: [PATCH v4 1/4] dt-bindings: pinctrl: add Ambarella CV75 pinctrl Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-cv75-v4-b-v4-1-ef2e83ec0eac@ambarella.com> References: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> In-Reply-To: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786688763; l=6392; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=nKtxPce2re61fXy+1qoLhWBCtRzuGBLrRckpr8oXxx4=; b=a7znp/pnlWhAgzN3TRpcMoERgnBeJ920ph/HZ3tle3KxQfiUaFKl2AmqV2MRDJtnfcFK+/YGm wp4iv38A6uABsR90+2KY7ZgmwIvmDZIXGRtupCgw+X3z5W3aa74riJC X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the CV75 pin controller binding using generic function and groups properties for pinmux configuration. Signed-off-by: Long Zhao --- .../bindings/pinctrl/ambarella,cv75-pinctrl.yaml | 240 +++++++++++++++++= ++++ 1 file changed, 240 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinct= rl.yaml b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.= yaml new file mode 100644 index 000000000000..9d65da32d3d2 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ambarella,cv75-pinctrl.yaml @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/ambarella,cv75-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ambarella CV75 Pin Controller + +maintainers: + - Long Zhao + +description: + The Ambarella CV75 pin controller configures pin multiplexing, bias and + drive strength for the main GPIO banks. Pin groups and their mux settings + are defined by the pin controller driver and selected by function and gr= oup + names. + +allOf: + - $ref: pinctrl.yaml# + +properties: + compatible: + const: ambarella,cv75-pinctrl + + reg: + maxItems: 1 + description: IOMUX registers + + ambarella,drive-strength-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: RCT syscon containing the drive-strength registers. + + ambarella,pull-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: Secure scratchpad syscon containing the pull registers. + +patternProperties: + "^[a-z0-9-]+-pins$": + type: object + allOf: + - $ref: pinmux-node.yaml# + - $ref: pincfg-node.yaml# + additionalProperties: false + + properties: + function: + enum: + - can0 + - can1 + - clk_au + - dmic0 + - enet0 + - hsync0 + - hsync1 + - i2c0 + - i2c1 + - i2c2 + - i2c3 + - i2cs + - i2s0 + - i2s1 + - ir + - pwm0 + - pwm1 + - pwm2 + - pwm3 + - pwm4 + - pwm5 + - pwm6 + - pwm7 + - pwm8 + - pwm9 + - pwm10 + - pwm11 + - sdmmc0 + - sdmmc1 + - snand + - spi0 + - spi1 + - spi2 + - spi3 + - spi_slave + - spinor + - uart0 + - uart1 + - uart2 + - uart3 + - uart4 + - vin_master_sync + - vsync0 + - vsync1 + - vsync2 + - vsync3 + - wdt + + groups: + $ref: /schemas/types.yaml#/definitions/string-array + items: + enum: + - can0 + - can1 + - clk_au + - dmic0 + - enet_2nd_ref_clk_a + - enet_2nd_ref_clk_b + - enet_ext_osc_clk + - enet0_ptp_pps_o + - hsync0 + - hsync1 + - i2c0_a + - i2c0_b + - i2c1_a + - i2c1_b + - i2c2 + - i2c3_a + - i2c3_b + - i2c3_c + - i2cs_a + - i2cs_b + - i2cs_c + - i2cs_d + - i2s0 + - i2s1 + - ir + - pwm0 + - pwm1 + - pwm2 + - pwm3 + - pwm4_a + - pwm4_b + - pwm5_a + - pwm5_b + - pwm6_a + - pwm6_b + - pwm7_a + - pwm7_b + - pwm8_a + - pwm8_b + - pwm9_a + - pwm9_b + - pwm10_a + - pwm10_b + - pwm11_a + - pwm11_b + - rgmii0 + - rmii0 + - sdmmc0_1bit + - sdmmc0_4bit + - sdmmc0_cd + - sdmmc0_hs_sel + - sdmmc0_reset + - sdmmc0_wp + - sdmmc1_1bit + - sdmmc1_4bit + - sdmmc1_cd + - sdmmc1_hs_sel + - sdmmc1_reset + - sdmmc1_wp + - snand + - spi0 + - spi1 + - spi2 + - spi3_a + - spi3_b + - spi3_c + - spi_slave_a + - spi_slave_b + - spi_slave_c + - spi_slave_d + - spi_slave_e + - spinor + - uart0 + - uart1 + - uart1_flow + - uart2_a + - uart2_b + - uart2_c + - uart2_flow_a + - uart2_flow_b + - uart3_a + - uart3_b + - uart3_flow_a + - uart3_flow_b + - uart4_a + - uart4_b + - uart4_flow_a + - uart4_flow_b + - vin_master_sync_a + - vin_master_sync_b + - vin_master_sync_c + - vin_master_sync_d + - vin_master_sync_e + - vsync0 + - vsync1 + - vsync2 + - vsync3 + - wdt_a + - wdt_b + - wdt_c + - wdt_d + - wdt_e + - wdt_f + minItems: 1 + maxItems: 6 + uniqueItems: true + + bias-disable: true + bias-pull-down: true + bias-pull-up: true + + drive-strength: + enum: [3, 4, 5, 6, 7, 8, 9, 12] + + required: + - function + - groups + +required: + - compatible + - reg + - ambarella,drive-strength-syscon + - ambarella,pull-syscon + +unevaluatedProperties: false + +examples: + - | + pinctrl: pinctrl@e4010000 { + compatible =3D "ambarella,cv75-pinctrl"; + reg =3D <0xe4010000 0x1000>; + ambarella,drive-strength-syscon =3D <&rct>; + ambarella,pull-syscon =3D <&scratchpad>; + + uart0-pins { + function =3D "uart0"; + groups =3D "uart0"; + bias-disable; + drive-strength =3D <8>; + }; + }; --=20 2.34.1 From nobody Tue Aug 25 14:34:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 887A83546C9; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; cv=none; b=H8Rbn+hNrMk9vYPodNx/5fv62V1E0oEQ/1hUfkpaUa/LSEp2y3ISXqxZ1TTqDQeqTcTa0umxFIO1YE1hiJxbjwOTJvcE4gRSqHvflNFypKtqkyKozg2mGGTqf0J51FZkB8ujMTyG+WDveM6yJK/nhibl7K01fzil1gvSy8MNJGM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; c=relaxed/simple; bh=jEcPzTS2r9CRkRuHf/bP0CLeDxdimN8/GXo8Hz0PSGQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hCo5Kx3TsbMWU5qim2NkCvZEJi07A2uR+XqIgmq5718fnfTy4vDlIhYAPetbse+eerY3vIgtomkv3NyZ6tQMbf3uBG2UF4ms5mbr/OCBA+j1rQHVwkY7SkXfZ2otDRG0HBKXWcrfp5L4P/7rJOHOPHjvSPzRDwujsU2r1sTCotI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cluIIJKX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cluIIJKX" Received: by smtp.kernel.org (Postfix) with ESMTPS id 1D865C2BCF7; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786688766; bh=jEcPzTS2r9CRkRuHf/bP0CLeDxdimN8/GXo8Hz0PSGQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=cluIIJKXuqBHZ52WdgHTuM7n2Y6Q10Fdb/oPdUxiAD/FDMi2lX0ibkR++omcjK1Dw 6c8t/rtEUoBHy4WtbuqyBOTIsNH99sverFbOtSyeJXqkkf8FExz0n9DJeBkT7E+am3 h5o1EyimxGqRJJUlyrs2tLlo707xsJxD4kQT50ZoxJYOk5hX9FERv7bydwT6BPSYBY aeqWrEIin2psXYWaahYqxxw34DYvW5IKqjRVxIGfMKXJB7GkvfGOvGVJMwgFjRbFSf eoXpFmEJhsi12tXJGGInuF+O3M3gB4XOmII283fEr1NOJflpMmtyA7AncyIsvxxOG+ vt9kUnXZJA/iQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 00242C5CFDB; Fri, 14 Aug 2026 06:26:05 +0000 (UTC) From: Long Zhao via B4 Relay Date: Fri, 14 Aug 2026 14:25:42 +0800 Subject: [PATCH v4 2/4] dt-bindings: gpio: pl061: add Ambarella CV75 variant Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-cv75-v4-b-v4-2-ef2e83ec0eac@ambarella.com> References: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> In-Reply-To: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786688764; l=1941; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=Pngr7p+U3E/qWLbm7iUMOUjiAHv8IZUzMpz2/ZKNyVk=; b=9gDEX+Je0r5Q2wLy6qzP4LRjhNA9Jm5Y17qdFenFRkBmS6C5TEkdv4mfj5//eQwNfdo1gNbZe AnDzcY4Zc+QAdoBtRImv+Xgcd58ndHF2UNlNVE1ZGjknMdPprU8pm+l X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Document the Ambarella CV75 GPIO bank compatible and the synthetic arm,primecell-periphid used with the PL061 binding. Signed-off-by: Long Zhao --- .../devicetree/bindings/gpio/pl061-gpio.yaml | 35 ++++++++++++++++++= +--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml b/Docum= entation/devicetree/bindings/gpio/pl061-gpio.yaml index 4d970e55104b..414f8d4a3976 100644 --- a/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/pl061-gpio.yaml @@ -15,7 +15,9 @@ select: properties: compatible: contains: - const: arm,pl061 + enum: + - arm,pl061 + - ambarella,cv75-gpio required: - compatible =20 @@ -24,9 +26,20 @@ properties: pattern: "^gpio@[0-9a-f]+$" =20 compatible: - items: - - const: arm,pl061 - - const: arm,primecell + oneOf: + - items: + - const: arm,pl061 + - const: arm,primecell + - items: + - const: ambarella,cv75-gpio + - const: arm,primecell + + arm,primecell-periphid: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Value to override the hardware PrimeCell peripheral ID. Ambarella + variants use a synthetic ID retaining the PL061 part number because + the hardware has no discoverable ID or assigned designer ID. =20 reg: maxItems: 1 @@ -57,6 +70,20 @@ properties: minItems: 1 maxItems: 8 =20 +allOf: + - if: + properties: + compatible: + contains: + const: ambarella,cv75-gpio + then: + properties: + arm,primecell-periphid: + const: 0x00000061 + required: + - arm,primecell-periphid + - gpio-ranges + required: - compatible - reg --=20 2.34.1 From nobody Tue Aug 25 14:34:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8FD6D3603E0; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; cv=none; b=NXCtJnraaSYa0t8uC0KDtynjWP5OKDfTSubEgw010uRDPZ1dFggr9rtTwRNPHNCycqesFRKHy1vWaWcYPdJfn0QwmzNtnAo2e+IptLFRLlZ582o1bWAYWkyKgjuvpyU1BMG/2K7F8XIZL3Zsv6hkC428hH8Un3+VOYgPeDN4c7Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; c=relaxed/simple; bh=wbVseZhpPlt2KFlH3SLPuXAByJHV4F8Ak5Lq7D1YEWw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hjAg0rqjxjgl4OKSF2bjSRwf4zK9Ri2j//cGXZId2vnkeWHRV952FyHcLHJ4/B6Lwymg+qRESQaORPzvKYSRJcDbSEKI9t7akcgD1QJXmcred+C6gyyq3qEPs5xuHF+odNJ6TPc2f1eJqh8kuHx6CnqGrhtKCc6CXaF9XamUGoQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Vrv4slb8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Vrv4slb8" Received: by smtp.kernel.org (Postfix) with ESMTPS id 2D751C2BCF6; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786688766; bh=wbVseZhpPlt2KFlH3SLPuXAByJHV4F8Ak5Lq7D1YEWw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Vrv4slb8zExMnZmtAuc9fbBBVxq8qvW+kqfpI8mmkmQx6wUvf26tJrSdUM/JlCjIg blnd1qMqlRpWBixfi5N7Q876NW7JDqQK3Mt5LDsixSkYYUZcUrTzn8yjSKqzfpnlXo gQL+27daaaREcaujd4j0aD6M/oQ/kv3l8KiBDO5IwnWvE2ecqpTUXLf2JhRZppfYpK VY9a8vsoe1QF5FrZIWkAnvSM04SAOAQBeimqmONAv0oMjT06u2Ii1DTHvwytWF1T1m ofIPFI2XIArGPdi1F34HydzybTMsurow0E4Dm8orr4HsZa0A7kF4bCjgVlSLIG6zHY 4ouOK3N8kNNaQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DD17C5CFCF; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) From: Long Zhao via B4 Relay Date: Fri, 14 Aug 2026 14:25:43 +0800 Subject: [PATCH v4 3/4] gpio: pl061: add Ambarella CV75 register layout variant Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-cv75-v4-b-v4-3-ef2e83ec0eac@ambarella.com> References: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> In-Reply-To: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786688764; l=15281; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=BNygLwvFI98HxioBBPvFse5JUwgCrPxmQSc2UUGJsTI=; b=sNi2oDKwQ4IZg04j/FjkXgMND8OeyXnaIFdFV20NCHwRgAuop71cA14ABFWFnTPOlRHeYqYdO 7clRqTJhawUD90IdZSTsjSP1rmYkUBJ+/DjeNkvWc/oPx/j06bJpwaq X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Extend gpio-pl061 with a per-variant register layout so the Ambarella CV75 GPIO banks can reuse the PL061 driver instead of a duplicate. Signed-off-by: Long Zhao --- drivers/gpio/gpio-pl061.c | 280 +++++++++++++++++++++++++++++++++++-------= ---- 1 file changed, 213 insertions(+), 67 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 919cf86fd590..d9e5a9f25681 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -26,41 +26,94 @@ #include #include =20 -#define GPIODIR 0x400 -#define GPIOIS 0x404 -#define GPIOIBE 0x408 -#define GPIOIEV 0x40C -#define GPIOIE 0x410 -#define GPIORIS 0x414 -#define GPIOMIS 0x418 -#define GPIOIC 0x41C - #define PL061_GPIO_NR 8 +#define PL061_REG_NONE U32_MAX +#define PL061_AMBARELLA_PERIPH_ID 0x00000061 + +struct pl061_variant_data { + u32 data; + u32 dir; + u32 is; + u32 ibe; + u32 iev; + u32 ie; + u32 ris; + u32 mis; + u32 ic; + u32 afsel; + u32 mask; + u32 enable; + unsigned int ngpio; + bool access_32bit; + bool masked_data_address; + bool write_data_after_dir; + bool clear_irq_on_type; +}; =20 struct pl061_context_save_regs { - u8 gpio_data; - u8 gpio_dir; - u8 gpio_is; - u8 gpio_ibe; - u8 gpio_iev; - u8 gpio_ie; + u32 gpio_data; + u32 gpio_dir; + u32 gpio_is; + u32 gpio_ibe; + u32 gpio_iev; + u32 gpio_ie; + u32 gpio_afsel; + u32 gpio_mask; }; =20 struct pl061 { raw_spinlock_t lock; =20 void __iomem *base; + const struct pl061_variant_data *variant; struct gpio_chip gc; int parent_irq; =20 struct pl061_context_save_regs csave_regs; }; =20 +static u32 pl061_read(struct pl061 *pl061, u32 offset) +{ + if (pl061->variant->access_32bit) + return readl_relaxed(pl061->base + offset); + + return readb_relaxed(pl061->base + offset); +} + +static void pl061_write(struct pl061 *pl061, u32 value, u32 offset) +{ + if (pl061->variant->access_32bit) + writel_relaxed(value, pl061->base + offset); + else + writeb_relaxed(value, pl061->base + offset); +} + +static int pl061_get_data(struct pl061 *pl061, unsigned int offset) +{ + if (pl061->variant->masked_data_address) + return !!readb_relaxed(pl061->base + BIT(offset + 2)); + + pl061_write(pl061, BIT(offset), pl061->variant->mask); + return !!(pl061_read(pl061, pl061->variant->data) & BIT(offset)); +} + +static void pl061_set_data(struct pl061 *pl061, unsigned int offset, int v= alue) +{ + if (pl061->variant->masked_data_address) { + writeb_relaxed(!!value << offset, + pl061->base + BIT(offset + 2)); + return; + } + + pl061_write(pl061, BIT(offset), pl061->variant->mask); + pl061_write(pl061, value ? BIT(offset) : 0, pl061->variant->data); +} + static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); =20 - if (readb(pl061->base + GPIODIR) & BIT(offset)) + if (pl061_read(pl061, pl061->variant->dir) & BIT(offset)) return GPIO_LINE_DIRECTION_OUT; =20 return GPIO_LINE_DIRECTION_IN; @@ -70,12 +123,12 @@ static int pl061_direction_input(struct gpio_chip *gc,= unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); unsigned long flags; - unsigned char gpiodir; + u32 gpiodir; =20 raw_spin_lock_irqsave(&pl061->lock, flags); - gpiodir =3D readb(pl061->base + GPIODIR); + gpiodir =3D pl061_read(pl061, pl061->variant->dir); gpiodir &=3D ~(BIT(offset)); - writeb(gpiodir, pl061->base + GPIODIR); + pl061_write(pl061, gpiodir, pl061->variant->dir); raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; @@ -86,19 +139,20 @@ static int pl061_direction_output(struct gpio_chip *gc= , unsigned offset, { struct pl061 *pl061 =3D gpiochip_get_data(gc); unsigned long flags; - unsigned char gpiodir; + u32 gpiodir; =20 raw_spin_lock_irqsave(&pl061->lock, flags); - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); - gpiodir =3D readb(pl061->base + GPIODIR); + pl061_set_data(pl061, offset, value); + gpiodir =3D pl061_read(pl061, pl061->variant->dir); gpiodir |=3D BIT(offset); - writeb(gpiodir, pl061->base + GPIODIR); + pl061_write(pl061, gpiodir, pl061->variant->dir); =20 /* * gpio value is set again, because pl061 doesn't allow to set value of * a gpio pin before configuring it in OUT mode. */ - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + if (pl061->variant->write_data_after_dir) + pl061_set_data(pl061, offset, value); raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; @@ -107,15 +161,24 @@ static int pl061_direction_output(struct gpio_chip *g= c, unsigned offset, static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 =3D gpiochip_get_data(gc); + unsigned long flags; + int value; =20 - return !!readb(pl061->base + (BIT(offset + 2))); + raw_spin_lock_irqsave(&pl061->lock, flags); + value =3D pl061_get_data(pl061, offset); + raw_spin_unlock_irqrestore(&pl061->lock, flags); + + return value; } =20 static int pl061_set_value(struct gpio_chip *gc, unsigned int offset, int = value) { struct pl061 *pl061 =3D gpiochip_get_data(gc); + unsigned long flags; =20 - writeb(!!value << offset, pl061->base + (BIT(offset + 2))); + raw_spin_lock_irqsave(&pl061->lock, flags); + pl061_set_data(pl061, offset, value); + raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; } @@ -126,15 +189,14 @@ static int pl061_irq_type(struct irq_data *d, unsigne= d trigger) struct pl061 *pl061 =3D gpiochip_get_data(gc); int offset =3D irqd_to_hwirq(d); unsigned long flags; - u8 gpiois, gpioibe, gpioiev; - u8 bit =3D BIT(offset); + u32 gpiois, gpioibe, gpioiev; + u32 bit =3D BIT(offset); =20 - if (offset < 0 || offset >=3D PL061_GPIO_NR) + if (offset < 0 || offset >=3D gc->ngpio) return -EINVAL; =20 if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) && - (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) - { + (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) { dev_err(gc->parent, "trying to configure line %d for both level and edge " "detection, choose one!\n", @@ -142,12 +204,11 @@ static int pl061_irq_type(struct irq_data *d, unsigne= d trigger) return -EINVAL; } =20 - raw_spin_lock_irqsave(&pl061->lock, flags); =20 - gpioiev =3D readb(pl061->base + GPIOIEV); - gpiois =3D readb(pl061->base + GPIOIS); - gpioibe =3D readb(pl061->base + GPIOIBE); + gpioiev =3D pl061_read(pl061, pl061->variant->iev); + gpiois =3D pl061_read(pl061, pl061->variant->is); + gpioibe =3D pl061_read(pl061, pl061->variant->ibe); =20 if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { bool polarity =3D trigger & IRQ_TYPE_LEVEL_HIGH; @@ -199,9 +260,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned= trigger) offset); } =20 - writeb(gpiois, pl061->base + GPIOIS); - writeb(gpioibe, pl061->base + GPIOIBE); - writeb(gpioiev, pl061->base + GPIOIEV); + pl061_write(pl061, gpiois, pl061->variant->is); + pl061_write(pl061, gpioibe, pl061->variant->ibe); + pl061_write(pl061, gpioiev, pl061->variant->iev); + if (pl061->variant->clear_irq_on_type) + pl061_write(pl061, bit, pl061->variant->ic); =20 raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 @@ -218,9 +281,9 @@ static void pl061_irq_handler(struct irq_desc *desc) =20 chained_irq_enter(irqchip, desc); =20 - pending =3D readb(pl061->base + GPIOMIS); + pending =3D pl061_read(pl061, pl061->variant->mis); if (pending) { - for_each_set_bit(offset, &pending, PL061_GPIO_NR) + for_each_set_bit(offset, &pending, gc->ngpio) generic_handle_domain_irq(gc->irq.domain, offset); } @@ -232,12 +295,12 @@ static void pl061_irq_mask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - u8 gpioie; + u32 mask =3D BIT(irqd_to_hwirq(d)); + u32 gpioie; =20 raw_spin_lock(&pl061->lock); - gpioie =3D readb(pl061->base + GPIOIE) & ~mask; - writeb(gpioie, pl061->base + GPIOIE); + gpioie =3D pl061_read(pl061, pl061->variant->ie) & ~mask; + pl061_write(pl061, gpioie, pl061->variant->ie); raw_spin_unlock(&pl061->lock); =20 gpiochip_disable_irq(gc, d->hwirq); @@ -247,14 +310,14 @@ static void pl061_irq_unmask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - u8 gpioie; + u32 mask =3D BIT(irqd_to_hwirq(d)); + u32 gpioie; =20 gpiochip_enable_irq(gc, d->hwirq); =20 raw_spin_lock(&pl061->lock); - gpioie =3D readb(pl061->base + GPIOIE) | mask; - writeb(gpioie, pl061->base + GPIOIE); + gpioie =3D pl061_read(pl061, pl061->variant->ie) | mask; + pl061_write(pl061, gpioie, pl061->variant->ie); raw_spin_unlock(&pl061->lock); } =20 @@ -270,10 +333,10 @@ static void pl061_irq_ack(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); struct pl061 *pl061 =3D gpiochip_get_data(gc); - u8 mask =3D BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); + u32 mask =3D BIT(irqd_to_hwirq(d)); =20 raw_spin_lock(&pl061->lock); - writeb(mask, pl061->base + GPIOIC); + pl061_write(pl061, mask, pl061->variant->ic); raw_spin_unlock(&pl061->lock); } =20 @@ -314,6 +377,10 @@ static int pl061_probe(struct amba_device *adev, const= struct amba_id *id) if (pl061 =3D=3D NULL) return -ENOMEM; =20 + pl061->variant =3D id->data; + if (!pl061->variant) + return dev_err_probe(dev, -EINVAL, "missing variant data\n"); + pl061->base =3D devm_ioremap_resource(dev, &adev->res); if (IS_ERR(pl061->base)) return PTR_ERR(pl061->base); @@ -327,7 +394,7 @@ static int pl061_probe(struct amba_device *adev, const = struct amba_id *id) pl061->gc.direction_output =3D pl061_direction_output; pl061->gc.get =3D pl061_get_value; pl061->gc.set =3D pl061_set_value; - pl061->gc.ngpio =3D PL061_GPIO_NR; + pl061->gc.ngpio =3D pl061->variant->ngpio; pl061->gc.label =3D dev_name(dev); pl061->gc.parent =3D dev; pl061->gc.owner =3D THIS_MODULE; @@ -335,7 +402,14 @@ static int pl061_probe(struct amba_device *adev, const= struct amba_id *id) /* * irq_chip support */ - writeb(0, pl061->base + GPIOIE); /* disable irqs */ + pl061_write(pl061, 0, pl061->variant->ie); /* disable irqs */ + if (pl061->variant->enable !=3D PL061_REG_NONE) + pl061_write(pl061, GENMASK(pl061->gc.ngpio - 1, 0), + pl061->variant->enable); + if (pl061->variant->afsel !=3D PL061_REG_NONE) + pl061_write(pl061, 0, pl061->variant->afsel); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, 0, pl061->variant->mask); irq =3D adev->irq[0]; if (!irq) dev_warn(&adev->dev, "IRQ support disabled\n"); @@ -366,20 +440,37 @@ static int pl061_probe(struct amba_device *adev, cons= t struct amba_id *id) static int pl061_suspend(struct device *dev) { struct pl061 *pl061 =3D dev_get_drvdata(dev); + unsigned long flags; int offset; =20 + raw_spin_lock_irqsave(&pl061->lock, flags); pl061->csave_regs.gpio_data =3D 0; - pl061->csave_regs.gpio_dir =3D readb(pl061->base + GPIODIR); - pl061->csave_regs.gpio_is =3D readb(pl061->base + GPIOIS); - pl061->csave_regs.gpio_ibe =3D readb(pl061->base + GPIOIBE); - pl061->csave_regs.gpio_iev =3D readb(pl061->base + GPIOIEV); - pl061->csave_regs.gpio_ie =3D readb(pl061->base + GPIOIE); - - for (offset =3D 0; offset < PL061_GPIO_NR; offset++) { - if (pl061->csave_regs.gpio_dir & (BIT(offset))) - pl061->csave_regs.gpio_data |=3D - pl061_get_value(&pl061->gc, offset) << offset; + pl061->csave_regs.gpio_dir =3D + pl061_read(pl061, pl061->variant->dir); + pl061->csave_regs.gpio_is =3D + pl061_read(pl061, pl061->variant->is); + pl061->csave_regs.gpio_ibe =3D + pl061_read(pl061, pl061->variant->ibe); + pl061->csave_regs.gpio_iev =3D + pl061_read(pl061, pl061->variant->iev); + pl061->csave_regs.gpio_ie =3D + pl061_read(pl061, pl061->variant->ie); + if (pl061->variant->afsel !=3D PL061_REG_NONE) + pl061->csave_regs.gpio_afsel =3D + pl061_read(pl061, pl061->variant->afsel); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061->csave_regs.gpio_mask =3D + pl061_read(pl061, pl061->variant->mask); + + for (offset =3D 0; offset < pl061->gc.ngpio; offset++) { + if ((pl061->csave_regs.gpio_dir & BIT(offset)) && + pl061_get_data(pl061, offset)) + pl061->csave_regs.gpio_data |=3D BIT(offset); } + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_mask, + pl061->variant->mask); + raw_spin_unlock_irqrestore(&pl061->lock, flags); =20 return 0; } @@ -389,7 +480,7 @@ static int pl061_resume(struct device *dev) struct pl061 *pl061 =3D dev_get_drvdata(dev); int offset; =20 - for (offset =3D 0; offset < PL061_GPIO_NR; offset++) { + for (offset =3D 0; offset < pl061->gc.ngpio; offset++) { if (pl061->csave_regs.gpio_dir & (BIT(offset))) pl061_direction_output(&pl061->gc, offset, pl061->csave_regs.gpio_data & @@ -398,20 +489,75 @@ static int pl061_resume(struct device *dev) pl061_direction_input(&pl061->gc, offset); } =20 - writeb(pl061->csave_regs.gpio_is, pl061->base + GPIOIS); - writeb(pl061->csave_regs.gpio_ibe, pl061->base + GPIOIBE); - writeb(pl061->csave_regs.gpio_iev, pl061->base + GPIOIEV); - writeb(pl061->csave_regs.gpio_ie, pl061->base + GPIOIE); + pl061_write(pl061, pl061->csave_regs.gpio_is, + pl061->variant->is); + pl061_write(pl061, pl061->csave_regs.gpio_ibe, + pl061->variant->ibe); + pl061_write(pl061, pl061->csave_regs.gpio_iev, + pl061->variant->iev); + pl061_write(pl061, pl061->csave_regs.gpio_ie, + pl061->variant->ie); + if (pl061->variant->afsel !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_afsel, + pl061->variant->afsel); + if (pl061->variant->mask !=3D PL061_REG_NONE) + pl061_write(pl061, pl061->csave_regs.gpio_mask, + pl061->variant->mask); + if (pl061->variant->enable !=3D PL061_REG_NONE) + pl061_write(pl061, GENMASK(pl061->gc.ngpio - 1, 0), + pl061->variant->enable); =20 return 0; } =20 static DEFINE_SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_res= ume); =20 +static struct pl061_variant_data pl061_arm =3D { + .data =3D 0x000, + .dir =3D 0x400, + .is =3D 0x404, + .ibe =3D 0x408, + .iev =3D 0x40c, + .ie =3D 0x410, + .ris =3D 0x414, + .mis =3D 0x418, + .ic =3D 0x41c, + .afsel =3D PL061_REG_NONE, + .mask =3D PL061_REG_NONE, + .enable =3D PL061_REG_NONE, + .ngpio =3D PL061_GPIO_NR, + .masked_data_address =3D true, + .write_data_after_dir =3D true, +}; + +static struct pl061_variant_data pl061_ambarella =3D { + .data =3D 0x00, + .dir =3D 0x04, + .is =3D 0x08, + .ibe =3D 0x0c, + .iev =3D 0x10, + .ie =3D 0x14, + .afsel =3D 0x18, + .ris =3D 0x1c, + .mis =3D 0x20, + .ic =3D 0x24, + .mask =3D 0x28, + .enable =3D 0x2c, + .ngpio =3D 32, + .access_32bit =3D true, + .clear_irq_on_type =3D true, +}; + static const struct amba_id pl061_ids[] =3D { { .id =3D 0x00041061, .mask =3D 0x000fffff, + .data =3D &pl061_arm, + }, + { + .id =3D PL061_AMBARELLA_PERIPH_ID, + .mask =3D 0xffffffff, + .data =3D &pl061_ambarella, }, { 0, 0 }, }; --=20 2.34.1 From nobody Tue Aug 25 14:34:37 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B9DF35E1AF; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; cv=none; b=m24PuHgPF+836XshHLnwbpXZOPgBsn/HQNivysb7hx/D/Cs18/T9rAfxMR/PTXA7rT5PW3DKvjd6w/EXL2bNVUMyKLjd+EdCO8cqlF+0uOfi840NMRHtOxgMJM48M6jnaW+KAbdDavhexidDF4Tux5KBAWjdmrtvP2BO/a/qJG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786688766; c=relaxed/simple; bh=5EBrps0pBkCA0cimk9tUsQFmsCIbs+DSik+HLHiS+fo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=awFmFSnSXe/ecLvpKgdbTvUX4NM0/T6yppNesRrUf8LqXHzdPIKO+TaE6kxKabowD8JUjBfk+5XdzK0HyyHB8ZzZTrMbwJpvbf8cMcz7M6d6IY55pJ/uhcda3qR4I87bPA986Pa+gYSYtbVmkFuEibEm8qqasaxBrzAYEZlQRMc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=f6fuX7+u; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="f6fuX7+u" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3CA89C4AF0E; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786688766; bh=5EBrps0pBkCA0cimk9tUsQFmsCIbs+DSik+HLHiS+fo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=f6fuX7+ungActPj3HJFD81ZJXZODeit/aYR/0gjPaegKRFeb0tn4E3+Kop73Lp4rG ad3KZz5Cs2aRTl+vyWa8HlnO/yp0ahMThAmUVGciTBfPL0tA5tW7JYqoWCX60ZledV S0w3WkRnkkxaIxnxZfaZiqhkFiE0pJUmCkptolXMYIffs8j5v9Xx1SDJGKLbhGbWZE mx9QoGO+Yuy/NodmFMgvsPT1w2qZ2Eql/93tLj1sCAnzeAXO/dzUXBSDtXpD/yz9DI fdYEwGMKmifLCrEGEphWa7QFvQhWfEITG+X1HmZNVRZDOEOpI4st1XbYMC6YyQ6CQE pT/hzReEMyjdw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E2DBC5DF6D; Fri, 14 Aug 2026 06:26:06 +0000 (UTC) From: Long Zhao via B4 Relay Date: Fri, 14 Aug 2026 14:25:44 +0800 Subject: [PATCH v4 4/4] pinctrl: ambarella: add CV75 pin controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-cv75-v4-b-v4-4-ef2e83ec0eac@ambarella.com> References: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> In-Reply-To: <20260814-cv75-v4-b-v4-0-ef2e83ec0eac@ambarella.com> To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Long Zhao X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786688764; l=45530; i=longzhao@ambarella.com; s=20260730; h=from:subject:message-id; bh=jGylPHgADr+PrQ8LYQ/hyHgOzomkJtfXVzMkjwDzk+o=; b=KgwSEV6tDemn2M3NZHETxvMSCFhlk9o3lR1EQQNO8bHE7dxJb91q9c16wF22aI++a8Fdda2Qw 9NscdebV52iA0kNhrz2auSnPORuAAcx6UllxcfPyncIT1GN2ALvZAHa X-Developer-Key: i=longzhao@ambarella.com; a=ed25519; pk=/xGhPTOX0/eYsyTWzyjjgAIW1Z/YD+IlnOnvcdRozow= X-Endpoint-Received: by B4 Relay for longzhao@ambarella.com/20260730 with auth_id=903 X-Original-From: Long Zhao Reply-To: longzhao@ambarella.com From: Long Zhao Add an Ambarella pinmux-only pinctrl driver with CV75 function/group tables. GPIO is handled by the PL061 driver. Signed-off-by: Long Zhao --- drivers/pinctrl/Kconfig | 13 + drivers/pinctrl/Makefile | 2 + drivers/pinctrl/pinctrl-ambarella-cv75.c | 561 +++++++++++++++++++++ drivers/pinctrl/pinctrl-ambarella.c | 839 +++++++++++++++++++++++++++= ++++ drivers/pinctrl/pinctrl-ambarella.h | 50 ++ 5 files changed, 1465 insertions(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c2cdd7b2c49b..119acde60a93 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -37,6 +37,19 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. =20 +config PINCTRL_AMB + bool "Ambarella pin controller support" + depends on ARCH_AMBARELLA || COMPILE_TEST + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + select GPIO_PL061 + select MFD_SYSCON + select PINCONF + select PINMUX + help + Say Y here to enable the Ambarella pin controller driver. + config PINCTRL_AMD bool "AMD GPIO pin control" depends on HAS_IOMEM diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a35d71135abf..ce0825f4fc1b 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -10,6 +10,8 @@ obj-$(CONFIG_GENERIC_PINCONF) +=3D pinconf-generic.o obj-$(CONFIG_GENERIC_PINCTRL) +=3D pinctrl-generic.o obj-$(CONFIG_OF) +=3D devicetree.o =20 +obj-$(CONFIG_PINCTRL_AMB) +=3D pinctrl-ambarella.o +obj-$(CONFIG_PINCTRL_AMB) +=3D pinctrl-ambarella-cv75.o obj-$(CONFIG_PINCTRL_AMD) +=3D pinctrl-amd.o obj-$(CONFIG_PINCTRL_AMDISP) +=3D pinctrl-amdisp.o obj-$(CONFIG_PINCTRL_APPLE_GPIO) +=3D pinctrl-apple-gpio.o diff --git a/drivers/pinctrl/pinctrl-ambarella-cv75.c b/drivers/pinctrl/pin= ctrl-ambarella-cv75.c new file mode 100644 index 000000000000..e617f0717b31 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella-cv75.c @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Ambarella CV75 pinctrl data + * + * Copyright (C) 2026, Ambarella, Inc. + */ + +#include + +#include "pinctrl-ambarella.h" + +#define CV75_PINMUX_GROUP(_name, ...) \ + static const u32 cv75_##_name##_pinmux[] =3D { __VA_ARGS__ } + +#define CV75_GROUP(_name) \ + { \ + .name =3D #_name, \ + .pinmux =3D cv75_##_name##_pinmux, \ + .num_pins =3D ARRAY_SIZE(cv75_##_name##_pinmux), \ + } + +#define CV75_FUNCTION(_name) \ + { \ + .name =3D #_name, \ + .groups =3D cv75_##_name##_groups, \ + .num_groups =3D ARRAY_SIZE(cv75_##_name##_groups), \ + } + +/* UART */ +CV75_PINMUX_GROUP(uart0, AMBA_PINMUX(44, 1), AMBA_PINMUX(45, 1)); +CV75_PINMUX_GROUP(uart1, AMBA_PINMUX(46, 1), AMBA_PINMUX(47, 1)); +CV75_PINMUX_GROUP(uart1_flow, AMBA_PINMUX(48, 1), AMBA_PINMUX(49, 1)); +CV75_PINMUX_GROUP(uart2_a, AMBA_PINMUX(46, 2), AMBA_PINMUX(47, 2)); +CV75_PINMUX_GROUP(uart2_b, AMBA_PINMUX(50, 2), AMBA_PINMUX(51, 2)); +CV75_PINMUX_GROUP(uart2_c, AMBA_PINMUX(66, 2), AMBA_PINMUX(68, 2)); +CV75_PINMUX_GROUP(uart2_flow_a, AMBA_PINMUX(48, 2), AMBA_PINMUX(49, 2)); +CV75_PINMUX_GROUP(uart2_flow_b, AMBA_PINMUX(65, 3), AMBA_PINMUX(67, 3)); +CV75_PINMUX_GROUP(uart3_a, AMBA_PINMUX(70, 3), AMBA_PINMUX(72, 3)); +CV75_PINMUX_GROUP(uart3_b, AMBA_PINMUX(80, 3), AMBA_PINMUX(79, 3)); +CV75_PINMUX_GROUP(uart3_flow_a, AMBA_PINMUX(71, 3), AMBA_PINMUX(69, 3)); +CV75_PINMUX_GROUP(uart3_flow_b, AMBA_PINMUX(81, 3), AMBA_PINMUX(82, 3)); +CV75_PINMUX_GROUP(uart4_a, AMBA_PINMUX(29, 3), AMBA_PINMUX(30, 3)); +CV75_PINMUX_GROUP(uart4_b, AMBA_PINMUX(76, 3), AMBA_PINMUX(77, 3)); +CV75_PINMUX_GROUP(uart4_flow_a, AMBA_PINMUX(28, 3), AMBA_PINMUX(31, 3)); +CV75_PINMUX_GROUP(uart4_flow_b, AMBA_PINMUX(74, 3), AMBA_PINMUX(75, 3)); + +/* Flash */ +CV75_PINMUX_GROUP(snand, AMBA_PINMUX(79, 1), AMBA_PINMUX(80, 1), + AMBA_PINMUX(81, 1), AMBA_PINMUX(82, 1), + AMBA_PINMUX(83, 1), AMBA_PINMUX(84, 1)); +CV75_PINMUX_GROUP(spinor, AMBA_PINMUX(79, 2), AMBA_PINMUX(80, 2), + AMBA_PINMUX(81, 2), AMBA_PINMUX(82, 2), + AMBA_PINMUX(83, 2), AMBA_PINMUX(84, 2), + AMBA_PINMUX(85, 2)); + +/* SD/MMC */ +CV75_PINMUX_GROUP(sdmmc0_cd, AMBA_PINMUX(6, 1)); +CV75_PINMUX_GROUP(sdmmc0_wp, AMBA_PINMUX(7, 1)); +CV75_PINMUX_GROUP(sdmmc0_reset, AMBA_PINMUX(8, 1)); +CV75_PINMUX_GROUP(sdmmc0_hs_sel, AMBA_PINMUX(93, 1)); +CV75_PINMUX_GROUP(sdmmc0_1bit, AMBA_PINMUX(0, 1), AMBA_PINMUX(4, 1), + AMBA_PINMUX(5, 1)); +CV75_PINMUX_GROUP(sdmmc0_4bit, AMBA_PINMUX(0, 1), AMBA_PINMUX(1, 1), + AMBA_PINMUX(2, 1), AMBA_PINMUX(3, 1), + AMBA_PINMUX(4, 1), AMBA_PINMUX(5, 1)); +CV75_PINMUX_GROUP(sdmmc1_cd, AMBA_PINMUX(15, 1)); +CV75_PINMUX_GROUP(sdmmc1_wp, AMBA_PINMUX(16, 1)); +CV75_PINMUX_GROUP(sdmmc1_reset, AMBA_PINMUX(17, 1)); +CV75_PINMUX_GROUP(sdmmc1_hs_sel, AMBA_PINMUX(94, 1)); +CV75_PINMUX_GROUP(sdmmc1_1bit, AMBA_PINMUX(9, 1), AMBA_PINMUX(13, 1), + AMBA_PINMUX(14, 1)); +CV75_PINMUX_GROUP(sdmmc1_4bit, AMBA_PINMUX(9, 1), AMBA_PINMUX(10, 1), + AMBA_PINMUX(11, 1), AMBA_PINMUX(12, 1), + AMBA_PINMUX(13, 1), AMBA_PINMUX(14, 1)); + +/* Ethernet */ +CV75_PINMUX_GROUP(enet_ext_osc_clk, AMBA_PINMUX(77, 1)); +CV75_PINMUX_GROUP(enet_2nd_ref_clk_a, AMBA_PINMUX(78, 1)); +CV75_PINMUX_GROUP(enet_2nd_ref_clk_b, AMBA_PINMUX(76, 2)); +CV75_PINMUX_GROUP(enet0_ptp_pps_o, AMBA_PINMUX(74, 1)); +CV75_PINMUX_GROUP(rgmii0, AMBA_PINMUX(62, 1), AMBA_PINMUX(63, 1), + AMBA_PINMUX(64, 1), AMBA_PINMUX(65, 1), + AMBA_PINMUX(66, 1), AMBA_PINMUX(67, 1), + AMBA_PINMUX(68, 1), AMBA_PINMUX(69, 1), + AMBA_PINMUX(70, 1), AMBA_PINMUX(71, 1), + AMBA_PINMUX(72, 1), AMBA_PINMUX(73, 1), + AMBA_PINMUX(75, 1), AMBA_PINMUX(76, 1)); +CV75_PINMUX_GROUP(rmii0, AMBA_PINMUX(62, 1), AMBA_PINMUX(63, 1), + AMBA_PINMUX(64, 1), AMBA_PINMUX(67, 1), + AMBA_PINMUX(68, 1), AMBA_PINMUX(71, 1), + AMBA_PINMUX(72, 1), AMBA_PINMUX(73, 1), + AMBA_PINMUX(75, 2)); + +/* I2C */ +CV75_PINMUX_GROUP(i2c0_a, AMBA_PINMUX(67, 2), AMBA_PINMUX(68, 2)); +CV75_PINMUX_GROUP(i2c0_b, AMBA_PINMUX(86, 1), AMBA_PINMUX(87, 1)); +CV75_PINMUX_GROUP(i2c1_a, AMBA_PINMUX(22, 2), AMBA_PINMUX(23, 2)); +CV75_PINMUX_GROUP(i2c1_b, AMBA_PINMUX(69, 2), AMBA_PINMUX(70, 2)); +CV75_PINMUX_GROUP(i2c2, AMBA_PINMUX(88, 1), AMBA_PINMUX(89, 1)); +CV75_PINMUX_GROUP(i2c3_a, AMBA_PINMUX(24, 2), AMBA_PINMUX(25, 2)); +CV75_PINMUX_GROUP(i2c3_b, AMBA_PINMUX(48, 3), AMBA_PINMUX(49, 3)); +CV75_PINMUX_GROUP(i2c3_c, AMBA_PINMUX(58, 3), AMBA_PINMUX(59, 3)); +CV75_PINMUX_GROUP(i2cs_a, AMBA_PINMUX(19, 2), AMBA_PINMUX(21, 2)); +CV75_PINMUX_GROUP(i2cs_b, AMBA_PINMUX(60, 3), AMBA_PINMUX(61, 3)); +CV75_PINMUX_GROUP(i2cs_c, AMBA_PINMUX(71, 2), AMBA_PINMUX(72, 2)); +CV75_PINMUX_GROUP(i2cs_d, AMBA_PINMUX(86, 2), AMBA_PINMUX(87, 2)); + +/* CAN, IR, WDT */ +CV75_PINMUX_GROUP(can0, AMBA_PINMUX(50, 1), AMBA_PINMUX(51, 1)); +CV75_PINMUX_GROUP(can1, AMBA_PINMUX(52, 1), AMBA_PINMUX(53, 1)); +CV75_PINMUX_GROUP(ir, AMBA_PINMUX(18, 1)); +CV75_PINMUX_GROUP(wdt_a, AMBA_PINMUX(20, 2)); +CV75_PINMUX_GROUP(wdt_b, AMBA_PINMUX(27, 3)); +CV75_PINMUX_GROUP(wdt_c, AMBA_PINMUX(39, 2)); +CV75_PINMUX_GROUP(wdt_d, AMBA_PINMUX(83, 3)); +CV75_PINMUX_GROUP(wdt_e, AMBA_PINMUX(85, 4)); +CV75_PINMUX_GROUP(wdt_f, AMBA_PINMUX(90, 1)); + +/* I2S */ +CV75_PINMUX_GROUP(i2s0, AMBA_PINMUX(54, 1), AMBA_PINMUX(55, 1), + AMBA_PINMUX(56, 1), AMBA_PINMUX(57, 1)); +CV75_PINMUX_GROUP(i2s1, AMBA_PINMUX(58, 1), AMBA_PINMUX(59, 1), + AMBA_PINMUX(60, 1), AMBA_PINMUX(61, 1)); +CV75_PINMUX_GROUP(clk_au, AMBA_PINMUX(96, 1)); +CV75_PINMUX_GROUP(dmic0, AMBA_PINMUX(54, 2), AMBA_PINMUX(55, 2)); + +/* PWM */ +CV75_PINMUX_GROUP(pwm0, AMBA_PINMUX(40, 1)); +CV75_PINMUX_GROUP(pwm1, AMBA_PINMUX(41, 1)); +CV75_PINMUX_GROUP(pwm2, AMBA_PINMUX(42, 1)); +CV75_PINMUX_GROUP(pwm3, AMBA_PINMUX(43, 1)); +CV75_PINMUX_GROUP(pwm4_a, AMBA_PINMUX(19, 3)); +CV75_PINMUX_GROUP(pwm4_b, AMBA_PINMUX(32, 4)); +CV75_PINMUX_GROUP(pwm5_a, AMBA_PINMUX(20, 3)); +CV75_PINMUX_GROUP(pwm5_b, AMBA_PINMUX(33, 4)); +CV75_PINMUX_GROUP(pwm6_a, AMBA_PINMUX(21, 3)); +CV75_PINMUX_GROUP(pwm6_b, AMBA_PINMUX(34, 4)); +CV75_PINMUX_GROUP(pwm7_a, AMBA_PINMUX(22, 3)); +CV75_PINMUX_GROUP(pwm7_b, AMBA_PINMUX(35, 4)); +CV75_PINMUX_GROUP(pwm8_a, AMBA_PINMUX(23, 3)); +CV75_PINMUX_GROUP(pwm8_b, AMBA_PINMUX(36, 4)); +CV75_PINMUX_GROUP(pwm9_a, AMBA_PINMUX(24, 3)); +CV75_PINMUX_GROUP(pwm9_b, AMBA_PINMUX(37, 4)); +CV75_PINMUX_GROUP(pwm10_a, AMBA_PINMUX(25, 3)); +CV75_PINMUX_GROUP(pwm10_b, AMBA_PINMUX(38, 4)); +CV75_PINMUX_GROUP(pwm11_a, AMBA_PINMUX(26, 3)); +CV75_PINMUX_GROUP(pwm11_b, AMBA_PINMUX(39, 4)); + +/* SPI */ +CV75_PINMUX_GROUP(spi0, AMBA_PINMUX(19, 1), AMBA_PINMUX(20, 1), + AMBA_PINMUX(21, 1)); +CV75_PINMUX_GROUP(spi1, AMBA_PINMUX(24, 1), AMBA_PINMUX(25, 1), + AMBA_PINMUX(26, 1)); +CV75_PINMUX_GROUP(spi2, AMBA_PINMUX(28, 1), AMBA_PINMUX(29, 1), + AMBA_PINMUX(30, 1)); +CV75_PINMUX_GROUP(spi3_a, AMBA_PINMUX(32, 5), AMBA_PINMUX(33, 5), + AMBA_PINMUX(34, 5)); +CV75_PINMUX_GROUP(spi3_b, AMBA_PINMUX(40, 2), AMBA_PINMUX(41, 2), + AMBA_PINMUX(43, 2)); +CV75_PINMUX_GROUP(spi3_c, AMBA_PINMUX(58, 2), AMBA_PINMUX(59, 2), + AMBA_PINMUX(60, 2)); +CV75_PINMUX_GROUP(spi_slave_a, AMBA_PINMUX(24, 4), AMBA_PINMUX(25, 4), + AMBA_PINMUX(26, 4), AMBA_PINMUX(27, 4)); +CV75_PINMUX_GROUP(spi_slave_b, AMBA_PINMUX(28, 2), AMBA_PINMUX(29, 2), + AMBA_PINMUX(30, 2), AMBA_PINMUX(31, 2)); +CV75_PINMUX_GROUP(spi_slave_c, AMBA_PINMUX(36, 5), AMBA_PINMUX(37, 5), + AMBA_PINMUX(38, 5), AMBA_PINMUX(39, 5)); +CV75_PINMUX_GROUP(spi_slave_d, AMBA_PINMUX(50, 3), AMBA_PINMUX(51, 3), + AMBA_PINMUX(52, 3), AMBA_PINMUX(53, 3)); +CV75_PINMUX_GROUP(spi_slave_e, AMBA_PINMUX(81, 4), AMBA_PINMUX(82, 4), + AMBA_PINMUX(83, 4), AMBA_PINMUX(84, 4)); + +/* VIN master sync */ +CV75_PINMUX_GROUP(vin_master_sync_a, AMBA_PINMUX(91, 1), + AMBA_PINMUX(92, 1)); +CV75_PINMUX_GROUP(vin_master_sync_b, AMBA_PINMUX(91, 2), + AMBA_PINMUX(92, 2)); +CV75_PINMUX_GROUP(vin_master_sync_c, AMBA_PINMUX(40, 3), + AMBA_PINMUX(41, 3)); +CV75_PINMUX_GROUP(vin_master_sync_d, AMBA_PINMUX(46, 3), + AMBA_PINMUX(47, 3)); +CV75_PINMUX_GROUP(vin_master_sync_e, AMBA_PINMUX(79, 4), + AMBA_PINMUX(80, 4)); +CV75_PINMUX_GROUP(vsync0, AMBA_PINMUX(32, 1)); +CV75_PINMUX_GROUP(vsync1, AMBA_PINMUX(33, 1)); +CV75_PINMUX_GROUP(vsync2, AMBA_PINMUX(34, 1)); +CV75_PINMUX_GROUP(vsync3, AMBA_PINMUX(35, 1)); +CV75_PINMUX_GROUP(hsync0, AMBA_PINMUX(36, 1)); +CV75_PINMUX_GROUP(hsync1, AMBA_PINMUX(37, 1)); + +static const struct ambpin_group_desc cv75_pin_groups[] =3D { + CV75_GROUP(uart0), + CV75_GROUP(uart1), CV75_GROUP(uart1_flow), + CV75_GROUP(uart2_a), CV75_GROUP(uart2_b), CV75_GROUP(uart2_c), + CV75_GROUP(uart2_flow_a), CV75_GROUP(uart2_flow_b), + CV75_GROUP(uart3_a), CV75_GROUP(uart3_b), + CV75_GROUP(uart3_flow_a), CV75_GROUP(uart3_flow_b), + CV75_GROUP(uart4_a), CV75_GROUP(uart4_b), + CV75_GROUP(uart4_flow_a), CV75_GROUP(uart4_flow_b), + CV75_GROUP(snand), CV75_GROUP(spinor), + CV75_GROUP(sdmmc0_cd), CV75_GROUP(sdmmc0_wp), + CV75_GROUP(sdmmc0_reset), CV75_GROUP(sdmmc0_hs_sel), + CV75_GROUP(sdmmc0_1bit), CV75_GROUP(sdmmc0_4bit), + CV75_GROUP(sdmmc1_cd), CV75_GROUP(sdmmc1_wp), + CV75_GROUP(sdmmc1_reset), CV75_GROUP(sdmmc1_hs_sel), + CV75_GROUP(sdmmc1_1bit), CV75_GROUP(sdmmc1_4bit), + CV75_GROUP(enet_ext_osc_clk), CV75_GROUP(enet_2nd_ref_clk_a), + CV75_GROUP(enet_2nd_ref_clk_b), CV75_GROUP(enet0_ptp_pps_o), + CV75_GROUP(rgmii0), CV75_GROUP(rmii0), + CV75_GROUP(i2c0_a), CV75_GROUP(i2c0_b), + CV75_GROUP(i2c1_a), CV75_GROUP(i2c1_b), CV75_GROUP(i2c2), + CV75_GROUP(i2c3_a), CV75_GROUP(i2c3_b), CV75_GROUP(i2c3_c), + CV75_GROUP(i2cs_a), CV75_GROUP(i2cs_b), + CV75_GROUP(i2cs_c), CV75_GROUP(i2cs_d), + CV75_GROUP(can0), CV75_GROUP(can1), CV75_GROUP(ir), + CV75_GROUP(wdt_a), CV75_GROUP(wdt_b), CV75_GROUP(wdt_c), + CV75_GROUP(wdt_d), CV75_GROUP(wdt_e), CV75_GROUP(wdt_f), + CV75_GROUP(i2s0), CV75_GROUP(i2s1), + CV75_GROUP(clk_au), CV75_GROUP(dmic0), + CV75_GROUP(pwm0), CV75_GROUP(pwm1), + CV75_GROUP(pwm2), CV75_GROUP(pwm3), + CV75_GROUP(pwm4_a), CV75_GROUP(pwm4_b), + CV75_GROUP(pwm5_a), CV75_GROUP(pwm5_b), + CV75_GROUP(pwm6_a), CV75_GROUP(pwm6_b), + CV75_GROUP(pwm7_a), CV75_GROUP(pwm7_b), + CV75_GROUP(pwm8_a), CV75_GROUP(pwm8_b), + CV75_GROUP(pwm9_a), CV75_GROUP(pwm9_b), + CV75_GROUP(pwm10_a), CV75_GROUP(pwm10_b), + CV75_GROUP(pwm11_a), CV75_GROUP(pwm11_b), + CV75_GROUP(spi0), CV75_GROUP(spi1), CV75_GROUP(spi2), + CV75_GROUP(spi3_a), CV75_GROUP(spi3_b), CV75_GROUP(spi3_c), + CV75_GROUP(spi_slave_a), CV75_GROUP(spi_slave_b), + CV75_GROUP(spi_slave_c), CV75_GROUP(spi_slave_d), + CV75_GROUP(spi_slave_e), + CV75_GROUP(vin_master_sync_a), CV75_GROUP(vin_master_sync_b), + CV75_GROUP(vin_master_sync_c), CV75_GROUP(vin_master_sync_d), + CV75_GROUP(vin_master_sync_e), + CV75_GROUP(vsync0), CV75_GROUP(vsync1), + CV75_GROUP(vsync2), CV75_GROUP(vsync3), + CV75_GROUP(hsync0), CV75_GROUP(hsync1), +}; + +static const char * const cv75_uart0_groups[] =3D { + "uart0", +}; + +static const char * const cv75_uart1_groups[] =3D { + "uart1", + "uart1_flow", +}; + +static const char * const cv75_uart2_groups[] =3D { + "uart2_a", + "uart2_b", + "uart2_c", + "uart2_flow_a", + "uart2_flow_b", +}; + +static const char * const cv75_uart3_groups[] =3D { + "uart3_a", + "uart3_b", + "uart3_flow_a", + "uart3_flow_b", +}; + +static const char * const cv75_uart4_groups[] =3D { + "uart4_a", + "uart4_b", + "uart4_flow_a", + "uart4_flow_b", +}; + +static const char * const cv75_snand_groups[] =3D { + "snand", +}; + +static const char * const cv75_spinor_groups[] =3D { + "spinor", +}; + +static const char * const cv75_sdmmc0_groups[] =3D { + "sdmmc0_cd", + "sdmmc0_wp", + "sdmmc0_reset", + "sdmmc0_hs_sel", + "sdmmc0_1bit", + "sdmmc0_4bit", +}; + +static const char * const cv75_sdmmc1_groups[] =3D { + "sdmmc1_cd", + "sdmmc1_wp", + "sdmmc1_reset", + "sdmmc1_hs_sel", + "sdmmc1_1bit", + "sdmmc1_4bit", +}; + +static const char * const cv75_enet0_groups[] =3D { + "enet_ext_osc_clk", + "enet_2nd_ref_clk_a", + "enet_2nd_ref_clk_b", + "enet0_ptp_pps_o", + "rgmii0", + "rmii0", +}; + +static const char * const cv75_i2c0_groups[] =3D { + "i2c0_a", + "i2c0_b", +}; + +static const char * const cv75_i2c1_groups[] =3D { + "i2c1_a", + "i2c1_b", +}; + +static const char * const cv75_i2c2_groups[] =3D { + "i2c2", +}; + +static const char * const cv75_i2c3_groups[] =3D { + "i2c3_a", + "i2c3_b", + "i2c3_c", +}; + +static const char * const cv75_i2cs_groups[] =3D { + "i2cs_a", + "i2cs_b", + "i2cs_c", + "i2cs_d", +}; + +static const char * const cv75_can0_groups[] =3D { + "can0", +}; + +static const char * const cv75_can1_groups[] =3D { + "can1", +}; + +static const char * const cv75_ir_groups[] =3D { + "ir", +}; + +static const char * const cv75_wdt_groups[] =3D { + "wdt_a", + "wdt_b", + "wdt_c", + "wdt_d", + "wdt_e", + "wdt_f", +}; + +static const char * const cv75_i2s0_groups[] =3D { + "i2s0", +}; + +static const char * const cv75_i2s1_groups[] =3D { + "i2s1", +}; + +static const char * const cv75_clk_au_groups[] =3D { + "clk_au", +}; + +static const char * const cv75_dmic0_groups[] =3D { + "dmic0", +}; + +static const char * const cv75_pwm0_groups[] =3D { + "pwm0", +}; + +static const char * const cv75_pwm1_groups[] =3D { + "pwm1", +}; + +static const char * const cv75_pwm2_groups[] =3D { + "pwm2", +}; + +static const char * const cv75_pwm3_groups[] =3D { + "pwm3", +}; + +static const char * const cv75_pwm4_groups[] =3D { + "pwm4_a", + "pwm4_b", +}; + +static const char * const cv75_pwm5_groups[] =3D { + "pwm5_a", + "pwm5_b", +}; + +static const char * const cv75_pwm6_groups[] =3D { + "pwm6_a", + "pwm6_b", +}; + +static const char * const cv75_pwm7_groups[] =3D { + "pwm7_a", + "pwm7_b", +}; + +static const char * const cv75_pwm8_groups[] =3D { + "pwm8_a", + "pwm8_b", +}; + +static const char * const cv75_pwm9_groups[] =3D { + "pwm9_a", + "pwm9_b", +}; + +static const char * const cv75_pwm10_groups[] =3D { + "pwm10_a", + "pwm10_b", +}; + +static const char * const cv75_pwm11_groups[] =3D { + "pwm11_a", + "pwm11_b", +}; + +static const char * const cv75_spi0_groups[] =3D { + "spi0", +}; + +static const char * const cv75_spi1_groups[] =3D { + "spi1", +}; + +static const char * const cv75_spi2_groups[] =3D { + "spi2", +}; + +static const char * const cv75_spi3_groups[] =3D { + "spi3_a", + "spi3_b", + "spi3_c", +}; + +static const char * const cv75_spi_slave_groups[] =3D { + "spi_slave_a", + "spi_slave_b", + "spi_slave_c", + "spi_slave_d", + "spi_slave_e", +}; + +static const char * const cv75_vin_master_sync_groups[] =3D { + "vin_master_sync_a", + "vin_master_sync_b", + "vin_master_sync_c", + "vin_master_sync_d", + "vin_master_sync_e", +}; + +static const char * const cv75_vsync0_groups[] =3D { + "vsync0", +}; + +static const char * const cv75_vsync1_groups[] =3D { + "vsync1", +}; + +static const char * const cv75_vsync2_groups[] =3D { + "vsync2", +}; + +static const char * const cv75_vsync3_groups[] =3D { + "vsync3", +}; + +static const char * const cv75_hsync0_groups[] =3D { + "hsync0", +}; + +static const char * const cv75_hsync1_groups[] =3D { + "hsync1", +}; + +static const struct ambpin_function cv75_pin_functions[] =3D { + CV75_FUNCTION(uart0), + CV75_FUNCTION(uart1), + CV75_FUNCTION(uart2), + CV75_FUNCTION(uart3), + CV75_FUNCTION(uart4), + CV75_FUNCTION(snand), + CV75_FUNCTION(spinor), + CV75_FUNCTION(sdmmc0), + CV75_FUNCTION(sdmmc1), + CV75_FUNCTION(enet0), + CV75_FUNCTION(i2c0), + CV75_FUNCTION(i2c1), + CV75_FUNCTION(i2c2), + CV75_FUNCTION(i2c3), + CV75_FUNCTION(i2cs), + CV75_FUNCTION(can0), + CV75_FUNCTION(can1), + CV75_FUNCTION(ir), + CV75_FUNCTION(wdt), + CV75_FUNCTION(i2s0), + CV75_FUNCTION(i2s1), + CV75_FUNCTION(clk_au), + CV75_FUNCTION(dmic0), + CV75_FUNCTION(pwm0), + CV75_FUNCTION(pwm1), + CV75_FUNCTION(pwm2), + CV75_FUNCTION(pwm3), + CV75_FUNCTION(pwm4), + CV75_FUNCTION(pwm5), + CV75_FUNCTION(pwm6), + CV75_FUNCTION(pwm7), + CV75_FUNCTION(pwm8), + CV75_FUNCTION(pwm9), + CV75_FUNCTION(pwm10), + CV75_FUNCTION(pwm11), + CV75_FUNCTION(spi0), + CV75_FUNCTION(spi1), + CV75_FUNCTION(spi2), + CV75_FUNCTION(spi3), + CV75_FUNCTION(spi_slave), + CV75_FUNCTION(vin_master_sync), + CV75_FUNCTION(vsync0), + CV75_FUNCTION(vsync1), + CV75_FUNCTION(vsync2), + CV75_FUNCTION(vsync3), + CV75_FUNCTION(hsync0), + CV75_FUNCTION(hsync1), +}; + +const struct amb_pinctrl_data ambarella_cv75_pinctrl_data =3D { + .ds0 =3D { + 0x314, 0x320, 0x32c, + }, + .ds1 =3D { + 0x318, 0x324, 0x330, + }, + .ds2 =3D { + 0x31c, 0x328, 0x334, + }, + .pull_en =3D { + 0x60, 0x64, 0x68, + }, + .pull_dir =3D { + 0x7c, 0x80, 0x84, + }, + .have_ds2 =3D true, + .clk_au_dedicated_pin =3D 96, + .nr_banks =3D 3, + .npins =3D 97, + .groups =3D cv75_pin_groups, + .nr_groups =3D ARRAY_SIZE(cv75_pin_groups), + .functions =3D cv75_pin_functions, + .nr_functions =3D ARRAY_SIZE(cv75_pin_functions), +}; diff --git a/drivers/pinctrl/pinctrl-ambarella.c b/drivers/pinctrl/pinctrl-= ambarella.c new file mode 100644 index 000000000000..fb79a8b02209 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella.c @@ -0,0 +1,839 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Pinctrl driver for Ambarella SoCs + * + * History: + * 2013/12/18 - [Cao Rongrong] created file + * + * Copyright (C) 2012-2026, Ambarella, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinconf.h" +#include "pinctrl-ambarella.h" + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ + +#define IOMUX_OFFSET(bank, n) (((bank) * 0xc) + ((n) * 4)) +#define IOMUX_CTRL_SET_OFFSET 0xf0 + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ + +#define AMBA_MAX_PINS (AMBA_MAX_BANKS * 32) + +#define PINID_TO_BANK(p) ((p) >> 5) +#define PINID_TO_OFFSET(p) ((p) & 0x1f) + +struct amb_pinctrl_pm_state { + u32 iomux[3]; + u32 pull[2]; + u32 ds[3]; +}; + +struct ambpin_group { + const char *name; + const u32 *pinmux; + unsigned int *pins; + unsigned int num_pins; +}; + +struct amb_pinctrl_soc_data { + struct device *dev; + const struct amb_pinctrl_data *data; + void __iomem *iomux_base; + struct regmap *ds_regmap; + struct regmap *pull_regmap; + unsigned int npins; + unsigned long used[BITS_TO_LONGS(AMBA_MAX_PINS)]; + raw_spinlock_t lock; + + struct pinctrl_dev *pctl; + + const struct ambpin_function *functions; + unsigned int nr_functions; + struct ambpin_group *groups; + unsigned int nr_groups; + + struct amb_pinctrl_pm_state pm[AMBA_MAX_BANKS]; +}; + +/* check if the selector is a valid pin group selector */ +static int amb_get_group_count(struct pinctrl_dev *pctldev) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *amb_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int amb_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *num_pins) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + *pins =3D soc->groups[selector].pins; + *num_pins =3D soc->groups[selector].num_pins; + + return 0; +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static void amb_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + seq_printf(s, " %s", pinctrl_dev_get_devname(pctldev)); +} +#endif + +/* list of pinctrl callbacks for the pinctrl core */ +static const struct pinctrl_ops amb_pctrl_ops =3D { + .get_groups_count =3D amb_get_group_count, + .get_group_name =3D amb_get_group_name, + .get_group_pins =3D amb_get_group_pins, +#if IS_ENABLED(CONFIG_DEBUG_FS) + .pin_dbg_show =3D amb_pin_dbg_show, +#endif + .dt_node_to_map =3D pinconf_generic_dt_node_to_map_all, + .dt_free_map =3D pinconf_generic_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_request(struct pinctrl_dev *pctldev, unsigned int pi= n) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + if (test_and_set_bit(pin, soc->used)) + return -EBUSY; + + return 0; +} + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_free(struct pinctrl_dev *pctldev, unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + clear_bit(pin, soc->used); + + return 0; +} + +/* check if the selector is a valid pin function selector */ +static int amb_pinmux_get_fcount(struct pinctrl_dev *pctldev) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *amb_pinmux_get_fname(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + return soc->functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int amb_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + *groups =3D soc->functions[selector].groups; + *num_groups =3D soc->functions[selector].num_groups; + + return 0; +} + +static bool amb_iomux_accessible(const struct amb_pinctrl_soc_data *soc) +{ + return soc->data->hsm_domain_id =3D=3D 0; +} + +static void amb_iomux_commit(struct amb_pinctrl_soc_data *soc) +{ + if (!amb_iomux_accessible(soc)) + return; + + writel_relaxed(0x1, soc->iomux_base + IOMUX_CTRL_SET_OFFSET); + writel_relaxed(0x0, soc->iomux_base + IOMUX_CTRL_SET_OFFSET); +} + +static void amb_iomux_save_bank(struct amb_pinctrl_soc_data *soc, u32 bank) +{ + if (!amb_iomux_accessible(soc) || bank >=3D AMBA_MAX_BANKS) + return; + + soc->pm[bank].iomux[0] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 0)); + soc->pm[bank].iomux[1] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 1)); + soc->pm[bank].iomux[2] =3D + readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, 2)); +} + +static void amb_iomux_restore_bank(struct amb_pinctrl_soc_data *soc, u32 b= ank) +{ + if (!amb_iomux_accessible(soc) || bank >=3D AMBA_MAX_BANKS) + return; + + writel_relaxed(soc->pm[bank].iomux[0], + soc->iomux_base + IOMUX_OFFSET(bank, 0)); + writel_relaxed(soc->pm[bank].iomux[1], + soc->iomux_base + IOMUX_OFFSET(bank, 1)); + writel_relaxed(soc->pm[bank].iomux[2], + soc->iomux_base + IOMUX_OFFSET(bank, 2)); +} + +static void amb_pinmux_set_altfunc(struct amb_pinctrl_soc_data *soc, + u32 bank, u32 offset, u32 altfunc) +{ + u32 i, data; + + if (!amb_iomux_accessible(soc)) + return; + + for (i =3D 0; i < 3; i++) { + data =3D readl_relaxed(soc->iomux_base + IOMUX_OFFSET(bank, i)); + data &=3D (~(0x1 << offset)); + data |=3D (((altfunc >> i) & 0x1) << offset); + writel_relaxed(data, soc->iomux_base + IOMUX_OFFSET(bank, i)); + } + + amb_iomux_commit(soc); +} + +/* enable a specified pinmux by writing to registers */ +static int amb_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + const struct ambpin_group *grp; + u32 i, pin, alt, bank, offset; + unsigned long flags; + + grp =3D &soc->groups[group]; + + raw_spin_lock_irqsave(&soc->lock, flags); + for (i =3D 0; i < grp->num_pins; i++) { + pin =3D AMBA_PINMUX_TO_PIN(grp->pinmux[i]); + alt =3D AMBA_PINMUX_TO_ALT(grp->pinmux[i]); + bank =3D PINID_TO_BANK(pin); + offset =3D PINID_TO_OFFSET(pin); + amb_pinmux_set_altfunc(soc, bank, offset, alt); + } + raw_spin_unlock_irqrestore(&soc->lock, flags); + + return 0; +} + +static int amb_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 bank, offset; + unsigned long flags; + + if (!range || !range->gc) { + dev_err(soc->dev, "invalid range: %p\n", range); + return -EINVAL; + } + + if (test_and_set_bit(pin, soc->used)) + return -EBUSY; + + bank =3D PINID_TO_BANK(pin); + offset =3D PINID_TO_OFFSET(pin); + + raw_spin_lock_irqsave(&soc->lock, flags); + amb_pinmux_set_altfunc(soc, bank, offset, 0); + raw_spin_unlock_irqrestore(&soc->lock, flags); + + return 0; +} + +static void amb_pinmux_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(soc->dev, "disable pin %u as GPIO\n", pin); + /* Set the pin to some default state, GPIO is usually default */ + + clear_bit(pin, soc->used); +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static const struct pinmux_ops amb_pinmux_ops =3D { + .request =3D amb_pinmux_request, + .free =3D amb_pinmux_free, + .get_functions_count =3D amb_pinmux_get_fcount, + .get_function_name =3D amb_pinmux_get_fname, + .get_function_groups =3D amb_pinmux_get_groups, + .set_mux =3D amb_pinmux_set_mux, + .gpio_request_enable =3D amb_pinmux_gpio_request_enable, + .gpio_disable_free =3D amb_pinmux_gpio_disable_free, +}; + +static int amb_drive_strength_to_reg(struct amb_pinctrl_soc_data *soc, + u32 strength) +{ + if (soc->data->have_ds2) { + switch (strength) { + case 3: + return 0; + case 4: + case 5: + return 1; + case 6: + return 2; + case 7: + case 8: + return 3; + case 9: + return 4; + case 12: + return 5; + default: + return -EINVAL; + } + } + + switch (strength) { + case 2: + return 0; + case 4: + return 1; + case 8: + return 2; + case 12: + return 3; + default: + return -EINVAL; + } +} + +static int amb_reg_to_drive_strength(struct amb_pinctrl_soc_data *soc, u32= ds) +{ + static const int ds2_ma[] =3D { 3, 4, 6, 8, 9, 12 }; + static const int ds_ma[] =3D { 2, 4, 8, 12 }; + + if (soc->data->have_ds2) { + if (ds >=3D ARRAY_SIZE(ds2_ma)) + return -EINVAL; + + return ds2_ma[ds]; + } + + if (ds >=3D ARRAY_SIZE(ds_ma)) + return -EINVAL; + + return ds_ma[ds]; +} + +/* set the pin config settings for a specified pin */ +static int amb_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 i, bank, offset; + unsigned long config; + enum pin_config_param param; + u32 arg; + int ds; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) + return -EINVAL; + + offset =3D PINID_TO_OFFSET(pin); + + for (i =3D 0; i < num_configs; i++) { + config =3D configs[i]; + param =3D pinconf_to_config_param(config); + arg =3D pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + regmap_update_bits(soc->pull_regmap, + soc->data->pull_en[bank], BIT(offset), 0); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + regmap_update_bits(soc->pull_regmap, soc->data->pull_dir[bank], + BIT(offset), + (param =3D=3D PIN_CONFIG_BIAS_PULL_UP) ? + BIT(offset) : 0); + regmap_update_bits(soc->pull_regmap, soc->data->pull_en[bank], + BIT(offset), BIT(offset)); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ds =3D amb_drive_strength_to_reg(soc, arg); + if (ds < 0) + return ds; + if (soc->data->have_ds2) { + regmap_update_bits(soc->ds_regmap, + soc->data->ds0[bank], BIT(offset), + (ds & BIT(0)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds1[bank], BIT(offset), + (ds & BIT(1)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds2[bank], BIT(offset), + (ds & BIT(2)) ? BIT(offset) : 0); + } else { + regmap_update_bits(soc->ds_regmap, + soc->data->ds0[bank], BIT(offset), + (ds & BIT(1)) ? BIT(offset) : 0); + regmap_update_bits(soc->ds_regmap, + soc->data->ds1[bank], BIT(offset), + (ds & BIT(0)) ? BIT(offset) : 0); + } + break; + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int amb_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + const struct ambpin_group *grp =3D &soc->groups[selector]; + int ret; + u32 i; + + for (i =3D 0; i < grp->num_pins; i++) { + ret =3D amb_pinconf_set(pctldev, grp->pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + +/* get the pin config settings for a specified pin */ +static int amb_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param =3D pinconf_to_config_param(*config); + u32 bank, offset, pull_en, pull_dir, ds0, ds1, ds2, ds; + int ret, strength; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) + return -EINVAL; + + offset =3D PINID_TO_OFFSET(pin); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_en[bank], + &pull_en); + if (ret) + return ret; + + ret =3D regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], + &pull_dir); + if (ret) + return ret; + + pull_en =3D (pull_en >> offset) & 1; + pull_dir =3D (pull_dir >> offset) & 1; + + if (param =3D=3D PIN_CONFIG_BIAS_DISABLE) { + if (pull_en) + return -EINVAL; + *config =3D pinconf_to_config_packed(param, 0); + return 0; + } + + if (!pull_en) + return -EINVAL; + if (param =3D=3D PIN_CONFIG_BIAS_PULL_UP && !pull_dir) + return -EINVAL; + if (param =3D=3D PIN_CONFIG_BIAS_PULL_DOWN && pull_dir) + return -EINVAL; + + *config =3D pinconf_to_config_packed(param, 1); + return 0; + + case PIN_CONFIG_DRIVE_STRENGTH: + ret =3D regmap_read(soc->ds_regmap, soc->data->ds0[bank], &ds0); + if (ret) + return ret; + + ret =3D regmap_read(soc->ds_regmap, soc->data->ds1[bank], &ds1); + if (ret) + return ret; + + ds0 =3D (ds0 >> offset) & 1; + ds1 =3D (ds1 >> offset) & 1; + if (soc->data->have_ds2) { + ret =3D regmap_read(soc->ds_regmap, soc->data->ds2[bank], &ds2); + if (ret) + return ret; + + ds2 =3D (ds2 >> offset) & 1; + ds =3D (ds2 << 2) | (ds1 << 1) | ds0; + } else { + ds =3D (ds0 << 1) | ds1; + } + + strength =3D amb_reg_to_drive_strength(soc, ds); + if (strength < 0) + return strength; + + *config =3D pinconf_to_config_packed(param, strength); + return 0; + + default: + return -EOPNOTSUPP; + } +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static void amb_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct amb_pinctrl_soc_data *soc =3D pinctrl_dev_get_drvdata(pctldev); + u32 pull_en, pull_dir, ds0, ds1, ds2, ds; + u32 bank, offset; + int strength; + + bank =3D PINID_TO_BANK(pin); + if (bank >=3D soc->data->nr_banks) { + seq_puts(s, " (no pinconf)"); + return; + } + + offset =3D PINID_TO_OFFSET(pin); + + regmap_read(soc->pull_regmap, soc->data->pull_en[bank], &pull_en); + pull_en =3D (pull_en >> offset) & 1; + regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], &pull_dir); + pull_dir =3D (pull_dir >> offset) & 1; + seq_printf(s, " pull: %s,", + pull_en ? (pull_dir ? "up" : "down") : "disable"); + + regmap_read(soc->ds_regmap, soc->data->ds0[bank], &ds0); + ds0 =3D (ds0 >> offset) & 1; + regmap_read(soc->ds_regmap, soc->data->ds1[bank], &ds1); + ds1 =3D (ds1 >> offset) & 1; + if (soc->data->have_ds2) { + regmap_read(soc->ds_regmap, soc->data->ds2[bank], &ds2); + ds2 =3D (ds2 >> offset) & 1; + ds =3D (ds2 << 2) | (ds1 << 1) | ds0; + } else { + ds =3D (ds0 << 1) | ds1; + } + + strength =3D amb_reg_to_drive_strength(soc, ds); + if (strength < 0) + seq_puts(s, " drive-strength: invalid"); + else + seq_printf(s, " drive-strength: %dmA", strength); +} +#endif + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code = */ +static const struct pinconf_ops amb_pinconf_ops =3D { + .is_generic =3D true, + .pin_config_get =3D amb_pinconf_get, + .pin_config_set =3D amb_pinconf_set, + .pin_config_group_set =3D amb_pinconf_group_set, +#if IS_ENABLED(CONFIG_DEBUG_FS) + .pin_config_dbg_show =3D amb_pinconf_dbg_show, +#endif +}; + +/* register the pinctrl interface with the pinctrl subsystem */ +static int amb_pinctrl_register(struct amb_pinctrl_soc_data *soc) +{ + struct pinctrl_pin_desc *pindesc; + struct pinctrl_desc *amb_pinctrl_desc; + unsigned int pin; + + /* dynamically populate the pin number and pin name for pindesc */ + pindesc =3D devm_kcalloc(soc->dev, soc->npins, sizeof(*pindesc), + GFP_KERNEL); + if (!pindesc) + return -ENOMEM; + + for (pin =3D 0; pin < soc->npins; pin++) { + pindesc[pin].number =3D pin; + pindesc[pin].name =3D devm_kasprintf(soc->dev, GFP_KERNEL, + "io%u", pin); + if (!pindesc[pin].name) + return -ENOMEM; + } + + amb_pinctrl_desc =3D devm_kzalloc(soc->dev, sizeof(*amb_pinctrl_desc), GF= P_KERNEL); + if (!amb_pinctrl_desc) + return -ENOMEM; + + amb_pinctrl_desc->name =3D dev_name(soc->dev); + amb_pinctrl_desc->pins =3D pindesc; + amb_pinctrl_desc->npins =3D soc->npins; + amb_pinctrl_desc->pctlops =3D &amb_pctrl_ops; + amb_pinctrl_desc->pmxops =3D &amb_pinmux_ops; + amb_pinctrl_desc->confops =3D &amb_pinconf_ops; + amb_pinctrl_desc->owner =3D THIS_MODULE; + + soc->pctl =3D devm_pinctrl_register(soc->dev, amb_pinctrl_desc, soc); + if (IS_ERR(soc->pctl)) { + dev_err(soc->dev, "could not register pinctrl driver\n"); + return PTR_ERR(soc->pctl); + } + + return 0; +} + +static int amb_pinctrl_probe(struct platform_device *pdev) +{ + struct amb_pinctrl_soc_data *soc; + struct device_node *np; + unsigned int *group_pins; + unsigned int group, group_pin; + size_t nr_group_pins =3D 0; + int rval; + + soc =3D devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL); + if (!soc) + return -ENOMEM; + + soc->dev =3D &pdev->dev; + soc->data =3D of_device_get_match_data(&pdev->dev); + if (!soc->data) + return dev_err_probe(&pdev->dev, -EINVAL, "missing soc data"); + if (!soc->data->nr_banks || + soc->data->nr_banks > AMBA_MAX_BANKS || + !soc->data->npins || + soc->data->npins > AMBA_MAX_PINS || + soc->data->nr_banks * 32 > soc->data->npins || + soc->data->clk_au_dedicated_pin >=3D soc->data->npins || + PINID_TO_BANK(soc->data->clk_au_dedicated_pin) >=3D AMBA_MAX_BANKS) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid bank or pin count\n"); + + soc->npins =3D soc->data->npins; + + np =3D pdev->dev.of_node; + soc->iomux_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(soc->iomux_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->iomux_base), + "couldn't get iomux reg"); + + soc->ds_regmap =3D syscon_regmap_lookup_by_phandle(np, "ambarella,drive-s= trength-syscon"); + if (IS_ERR(soc->ds_regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->ds_regmap), + "couldn't get drive-strength regmap"); + + soc->pull_regmap =3D syscon_regmap_lookup_by_phandle(np, "ambarella,pull-= syscon"); + if (IS_ERR(soc->pull_regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(soc->pull_regmap), + "couldn't get pull regmap"); + + soc->nr_groups =3D soc->data->nr_groups; + soc->functions =3D soc->data->functions; + soc->nr_functions =3D soc->data->nr_functions; + if (!soc->data->groups || !soc->nr_groups || + !soc->functions || !soc->nr_functions) + return dev_err_probe(&pdev->dev, -EINVAL, + "missing pin groups or functions\n"); + + soc->groups =3D devm_kcalloc(&pdev->dev, soc->nr_groups, + sizeof(*soc->groups), GFP_KERNEL); + if (!soc->groups) + return -ENOMEM; + + for (group =3D 0; group < soc->nr_groups; group++) { + const struct ambpin_group_desc *desc =3D + &soc->data->groups[group]; + + if (!desc->name || !desc->pinmux || !desc->num_pins) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid pin group %u\n", group); + + nr_group_pins +=3D desc->num_pins; + } + + group_pins =3D devm_kcalloc(&pdev->dev, nr_group_pins, + sizeof(*group_pins), GFP_KERNEL); + if (!group_pins) + return -ENOMEM; + + for (group =3D 0; group < soc->nr_groups; group++) { + const struct ambpin_group_desc *desc =3D + &soc->data->groups[group]; + struct ambpin_group *grp =3D &soc->groups[group]; + + grp->name =3D desc->name; + grp->pinmux =3D desc->pinmux; + grp->pins =3D group_pins; + grp->num_pins =3D desc->num_pins; + for (group_pin =3D 0; + group_pin < grp->num_pins; + group_pin++) { + u32 pinmux =3D grp->pinmux[group_pin]; + unsigned int pin =3D AMBA_PINMUX_TO_PIN(pinmux); + unsigned int alt =3D AMBA_PINMUX_TO_ALT(pinmux); + + if (pin >=3D soc->npins || alt > 7) + return dev_err_probe(&pdev->dev, -EINVAL, + "group %s has invalid pinmux %#x\n", + grp->name, pinmux); + + grp->pins[group_pin] =3D pin; + } + group_pins +=3D grp->num_pins; + } + + raw_spin_lock_init(&soc->lock); + + /* Mark all pins unavailable, then clear pins that exist. */ + bitmap_fill(soc->used, AMBA_MAX_PINS); + bitmap_clear(soc->used, 0, soc->data->nr_banks * 32); + clear_bit(soc->data->clk_au_dedicated_pin, soc->used); + + rval =3D amb_pinctrl_register(soc); + if (rval) + return dev_err_probe(&pdev->dev, rval, "pinctrl register failed!"); + + platform_set_drvdata(pdev, soc); + dev_info(&pdev->dev, "Ambarella pinctrl driver registered"); + + return 0; +} + +static int amb_pinctrl_suspend(struct device *dev) +{ + struct amb_pinctrl_soc_data *soc =3D dev_get_drvdata(dev); + u32 bank, dedicated =3D soc->data->clk_au_dedicated_pin; + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) { + regmap_read(soc->pull_regmap, soc->data->pull_en[bank], + &soc->pm[bank].pull[0]); + regmap_read(soc->pull_regmap, soc->data->pull_dir[bank], + &soc->pm[bank].pull[1]); + + regmap_read(soc->ds_regmap, soc->data->ds0[bank], + &soc->pm[bank].ds[0]); + regmap_read(soc->ds_regmap, soc->data->ds1[bank], + &soc->pm[bank].ds[1]); + if (soc->data->have_ds2) + regmap_read(soc->ds_regmap, soc->data->ds2[bank], + &soc->pm[bank].ds[2]); + + amb_iomux_save_bank(soc, bank); + } + + if (dedicated >=3D soc->data->nr_banks * 32) + amb_iomux_save_bank(soc, PINID_TO_BANK(dedicated)); + + return 0; +} + +static int amb_pinctrl_resume(struct device *dev) +{ + struct amb_pinctrl_soc_data *soc =3D dev_get_drvdata(dev); + u32 bank, dedicated =3D soc->data->clk_au_dedicated_pin; + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) + amb_iomux_restore_bank(soc, bank); + + if (dedicated >=3D soc->data->nr_banks * 32) + amb_iomux_restore_bank(soc, PINID_TO_BANK(dedicated)); + + wmb(); + amb_iomux_commit(soc); + + for (bank =3D 0; bank < soc->data->nr_banks; bank++) { + regmap_write(soc->ds_regmap, soc->data->ds0[bank], + soc->pm[bank].ds[0]); + regmap_write(soc->ds_regmap, soc->data->ds1[bank], + soc->pm[bank].ds[1]); + if (soc->data->have_ds2) + regmap_write(soc->ds_regmap, soc->data->ds2[bank], + soc->pm[bank].ds[2]); + + regmap_write(soc->pull_regmap, soc->data->pull_dir[bank], + soc->pm[bank].pull[1]); + regmap_write(soc->pull_regmap, soc->data->pull_en[bank], + soc->pm[bank].pull[0]); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(amb_pinctrl_pm_ops, + amb_pinctrl_suspend, + amb_pinctrl_resume); + +static const struct of_device_id amb_pinctrl_dt_match[] =3D { + { + .compatible =3D "ambarella,cv75-pinctrl", + .data =3D &ambarella_cv75_pinctrl_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, amb_pinctrl_dt_match); + +static struct platform_driver amb_pinctrl_driver =3D { + .probe =3D amb_pinctrl_probe, + .driver =3D { + .name =3D "ambarella-pinctrl", + .of_match_table =3D of_match_ptr(amb_pinctrl_dt_match), + .pm =3D pm_sleep_ptr(&amb_pinctrl_pm_ops), + }, +}; + +static int __init amb_pinctrl_drv_register(void) +{ + return platform_driver_register(&amb_pinctrl_driver); +} +arch_initcall(amb_pinctrl_drv_register); + +MODULE_AUTHOR("Cao Rongrong "); +MODULE_DESCRIPTION("Ambarella SoC pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-ambarella.h b/drivers/pinctrl/pinctrl-= ambarella.h new file mode 100644 index 000000000000..094639627131 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ambarella.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Ambarella pinctrl common data definitions + * + * Copyright (C) 2012-2026, Ambarella, Inc. + */ + +#ifndef _PINCTRL_AMBARELLA_H +#define _PINCTRL_AMBARELLA_H + +#include + +#define AMBA_MAX_BANKS 8 + +#define AMBA_PINMUX(pin, alt) (((alt) << 12) | (pin)) +#define AMBA_PINMUX_TO_PIN(mux) ((mux) & 0xfff) +#define AMBA_PINMUX_TO_ALT(mux) (((mux) >> 12) & 0xf) + +struct ambpin_group_desc { + const char *name; + const u32 *pinmux; + unsigned int num_pins; +}; + +struct ambpin_function { + const char *name; + const char * const *groups; + unsigned int num_groups; +}; + +struct amb_pinctrl_data { + unsigned int ds0[AMBA_MAX_BANKS]; + unsigned int ds1[AMBA_MAX_BANKS]; + unsigned int ds2[AMBA_MAX_BANKS]; + unsigned int pull_en[AMBA_MAX_BANKS]; + unsigned int pull_dir[AMBA_MAX_BANKS]; + bool have_ds2; + u32 hsm_domain_id; + u32 clk_au_dedicated_pin; + unsigned int nr_banks; + unsigned int npins; + const struct ambpin_group_desc *groups; + unsigned int nr_groups; + const struct ambpin_function *functions; + unsigned int nr_functions; +}; + +extern const struct amb_pinctrl_data ambarella_cv75_pinctrl_data; + +#endif /* _PINCTRL_AMBARELLA_H */ --=20 2.34.1