* [PATCH v3 0/2] pinctrl: ultrarisc: add DP1000 pinctrl support
@ 2026-06-08 7:50 ` Jia Wang
0 siblings, 0 replies; 7+ messages in thread
From: Jia Wang via B4 Relay @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
This series adds the devicetree schema and the pinctrl driver for the
DP1000 controller using generic pinctrl bindings.
Compared with v1, this series is narrowed down to the pinctrl binding
and driver only. v1 patches 1, 2, 3, 5, 7, 8, and 9 (vendor prefix,
CPU/SoC bindings, DTS files, and defconfig update) are not included in
v2 and will be sent separately.
Note:
- ARCH_ULTRARISC support is being reviewed separately:
* Link: https://lore.kernel.org/lkml/20260427-ultrarisc-pcie-v4-1-98935f6cdfb5@ultrarisc.com/
Testing:
- dt_binding_check and yamllint
- Kernel build for RISC-V and boot-tested on DP1000 (Milk-V Titan and
Rongda M0)
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
Changes in v3:
- Re-add the DT binding header and use numeric pin IDs in the binding.
- Replace instance-specific mux names with generic function names.
- Tighten the schema constraints for A-D and LPC pins.
- Switch the driver to pinctrl_generic_pins_function_dt_node_to_map()
and resolve mux routes from the pins + function combination.
- Link to v2: https://patch.msgid.link/20260601-ultrarisc-pinctrl-v2-0-07ac5130a96d@ultrarisc.com
Changes in v2:
- Split the vendor prefix, CPU binding, SoC binding, DTS, and defconfig
patches out of this series for separate submission.
- Drop the legacy DT node format from both the binding and the driver,
and switch to the generic pinctrl interface with
pinconf_generic_dt_node_to_map_all().
- Drop the DT binding header from the series.
- Replace the generic func0/func1 mux names with named hardware functions
in the binding and driver.
- Wire the driver through CONFIG_PINCTRL_ULTRARISC and add COMPILE_TEST
coverage.
- Restrict function selection to valid pins in the driver.
- Link to v1: https://patch.msgid.link/20260515-ultrarisc-pinctrl-v1-0-bf559589ea8a@ultrarisc.com
---
Jia Wang (2):
dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver
.../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 ++++++
MAINTAINERS | 7 +
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/ultrarisc/Kconfig | 21 +
drivers/pinctrl/ultrarisc/Makefile | 4 +
drivers/pinctrl/ultrarisc/pinctrl-dp1000.c | 168 +++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c | 503 +++++++++++++++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h | 63 +++
.../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h | 63 +++
10 files changed, 962 insertions(+)
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260316-ultrarisc-pinctrl-efa6e24c4803
Best regards,
--
Jia Wang <wangjia@ultrarisc.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 0/2] pinctrl: ultrarisc: add DP1000 pinctrl support
@ 2026-06-08 7:50 ` Jia Wang
0 siblings, 0 replies; 7+ messages in thread
From: Jia Wang @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
This series adds the devicetree schema and the pinctrl driver for the
DP1000 controller using generic pinctrl bindings.
Compared with v1, this series is narrowed down to the pinctrl binding
and driver only. v1 patches 1, 2, 3, 5, 7, 8, and 9 (vendor prefix,
CPU/SoC bindings, DTS files, and defconfig update) are not included in
v2 and will be sent separately.
Note:
- ARCH_ULTRARISC support is being reviewed separately:
* Link: https://lore.kernel.org/lkml/20260427-ultrarisc-pcie-v4-1-98935f6cdfb5@ultrarisc.com/
Testing:
- dt_binding_check and yamllint
- Kernel build for RISC-V and boot-tested on DP1000 (Milk-V Titan and
Rongda M0)
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
Changes in v3:
- Re-add the DT binding header and use numeric pin IDs in the binding.
- Replace instance-specific mux names with generic function names.
- Tighten the schema constraints for A-D and LPC pins.
- Switch the driver to pinctrl_generic_pins_function_dt_node_to_map()
and resolve mux routes from the pins + function combination.
- Link to v2: https://patch.msgid.link/20260601-ultrarisc-pinctrl-v2-0-07ac5130a96d@ultrarisc.com
Changes in v2:
- Split the vendor prefix, CPU binding, SoC binding, DTS, and defconfig
patches out of this series for separate submission.
- Drop the legacy DT node format from both the binding and the driver,
and switch to the generic pinctrl interface with
pinconf_generic_dt_node_to_map_all().
- Drop the DT binding header from the series.
- Replace the generic func0/func1 mux names with named hardware functions
in the binding and driver.
- Wire the driver through CONFIG_PINCTRL_ULTRARISC and add COMPILE_TEST
coverage.
- Restrict function selection to valid pins in the driver.
- Link to v1: https://patch.msgid.link/20260515-ultrarisc-pinctrl-v1-0-bf559589ea8a@ultrarisc.com
---
Jia Wang (2):
dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver
.../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 ++++++
MAINTAINERS | 7 +
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/ultrarisc/Kconfig | 21 +
drivers/pinctrl/ultrarisc/Makefile | 4 +
drivers/pinctrl/ultrarisc/pinctrl-dp1000.c | 168 +++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c | 503 +++++++++++++++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h | 63 +++
.../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h | 63 +++
10 files changed, 962 insertions(+)
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260316-ultrarisc-pinctrl-efa6e24c4803
Best regards,
--
Jia Wang <wangjia@ultrarisc.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
2026-06-08 7:50 ` Jia Wang
@ 2026-06-08 7:50 ` Jia Wang
-1 siblings, 0 replies; 7+ messages in thread
From: Jia Wang via B4 Relay @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
From: Jia Wang <wangjia@ultrarisc.com>
Add doc for the pinctrl controllers on the UltraRISC DP1000 RISC-V SoC.
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
.../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 +++++++++++++++++++++
MAINTAINERS | 6 +
.../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h | 63 ++++++++++
3 files changed, 200 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
new file mode 100644
index 000000000000..a64fbfc616db
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
@@ -0,0 +1,131 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/ultrarisc,dp1000-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UltraRISC DP1000 Pin Controller
+
+maintainers:
+ - Jia Wang <wangjia@ultrarisc.com>
+
+description: |
+ UltraRISC RISC-V SoC DP1000 pin controller.
+ The controller manages ports A, B, C, D and LPC. Ports A-D default to
+ GPIO and provide additional SPI, UART, I2C, and PWM mux functions.
+ LPC pins default to the LPC interface and can be muxed to eSPI.
+ All pins also support pin configuration, including drive strength,
+ pull-up, and pull-down settings.
+
+properties:
+ compatible:
+ const: ultrarisc,dp1000-pinctrl
+
+ reg:
+ items:
+ - description: pin controller registers
+
+required:
+ - compatible
+ - reg
+
+patternProperties:
+ '.*-pins$':
+ type: object
+ unevaluatedProperties: false
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml#
+ - $ref: /schemas/pinctrl/pinmux-node.yaml#
+ - if:
+ properties:
+ pins:
+ items:
+ minimum: 40
+ maximum: 52
+ then:
+ properties:
+ function:
+ enum:
+ - lpc
+ - espi
+ else:
+ properties:
+ pins:
+ items:
+ maximum: 39
+ function:
+ enum:
+ - gpio
+ - i2c
+ - pwm
+ - spi
+ - uart
+
+ properties:
+ pins:
+ description: |
+ List of pins affected by this state node, using the numeric pin IDs
+ defined in dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ uniqueItems: true
+ items:
+ minimum: 0
+ maximum: 52
+
+ function:
+ description: |
+ Mux function to select for the listed pins. Supported functions
+ depend on the selected pins and match the DP1000 hardware mux
+ table.
+ enum:
+ - gpio
+ - i2c
+ - pwm
+ - spi
+ - uart
+ - lpc
+ - espi
+
+ bias-disable: true
+ bias-high-impedance: true
+ bias-pull-up: true
+ bias-pull-down: true
+
+ drive-strength:
+ description: Output drive strength in mA.
+ enum: [20, 27, 33, 40]
+
+ required:
+ - pins
+ - function
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl@11081000 {
+ compatible = "ultrarisc,dp1000-pinctrl";
+ reg = <0x0 0x11081000 0x0 0x1000>;
+
+ i2c0-pins {
+ pins = <PA12 PA13>;
+ function = "i2c";
+ bias-pull-up;
+ drive-strength = <33>;
+ };
+
+ uart0-pins {
+ pins = <PA8 PA9>;
+ function = "uart";
+ bias-pull-up;
+ drive-strength = <33>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c..1ef874d342a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27357,6 +27357,12 @@ S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
+ULTRARISC DP1000 PINCTRL DRIVER
+M: Jia Wang <wangjia@ultrarisc.com>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+
ULTRATRONIK BOARD SUPPORT
M: Goran Rađenović <goran.radni@gmail.com>
M: Börge Strümpfel <boerge.struempfel@gmail.com>
diff --git a/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
new file mode 100644
index 000000000000..f800c9722471
--- /dev/null
+++ b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+#define _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+
+#define PA0 0
+#define PA1 1
+#define PA2 2
+#define PA3 3
+#define PA4 4
+#define PA5 5
+#define PA6 6
+#define PA7 7
+#define PA8 8
+#define PA9 9
+#define PA10 10
+#define PA11 11
+#define PA12 12
+#define PA13 13
+#define PA14 14
+#define PA15 15
+#define PB0 16
+#define PB1 17
+#define PB2 18
+#define PB3 19
+#define PB4 20
+#define PB5 21
+#define PB6 22
+#define PB7 23
+#define PC0 24
+#define PC1 25
+#define PC2 26
+#define PC3 27
+#define PC4 28
+#define PC5 29
+#define PC6 30
+#define PC7 31
+#define PD0 32
+#define PD1 33
+#define PD2 34
+#define PD3 35
+#define PD4 36
+#define PD5 37
+#define PD6 38
+#define PD7 39
+#define LPC0 40
+#define LPC1 41
+#define LPC2 42
+#define LPC3 43
+#define LPC4 44
+#define LPC5 45
+#define LPC6 46
+#define LPC7 47
+#define LPC8 48
+#define LPC9 49
+#define LPC10 50
+#define LPC11 51
+#define LPC12 52
+
+#endif /* _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
@ 2026-06-08 7:50 ` Jia Wang
0 siblings, 0 replies; 7+ messages in thread
From: Jia Wang @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
Add doc for the pinctrl controllers on the UltraRISC DP1000 RISC-V SoC.
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
.../bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml | 131 +++++++++++++++++++++
MAINTAINERS | 6 +
.../dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h | 63 ++++++++++
3 files changed, 200 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
new file mode 100644
index 000000000000..a64fbfc616db
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
@@ -0,0 +1,131 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/ultrarisc,dp1000-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UltraRISC DP1000 Pin Controller
+
+maintainers:
+ - Jia Wang <wangjia@ultrarisc.com>
+
+description: |
+ UltraRISC RISC-V SoC DP1000 pin controller.
+ The controller manages ports A, B, C, D and LPC. Ports A-D default to
+ GPIO and provide additional SPI, UART, I2C, and PWM mux functions.
+ LPC pins default to the LPC interface and can be muxed to eSPI.
+ All pins also support pin configuration, including drive strength,
+ pull-up, and pull-down settings.
+
+properties:
+ compatible:
+ const: ultrarisc,dp1000-pinctrl
+
+ reg:
+ items:
+ - description: pin controller registers
+
+required:
+ - compatible
+ - reg
+
+patternProperties:
+ '.*-pins$':
+ type: object
+ unevaluatedProperties: false
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml#
+ - $ref: /schemas/pinctrl/pinmux-node.yaml#
+ - if:
+ properties:
+ pins:
+ items:
+ minimum: 40
+ maximum: 52
+ then:
+ properties:
+ function:
+ enum:
+ - lpc
+ - espi
+ else:
+ properties:
+ pins:
+ items:
+ maximum: 39
+ function:
+ enum:
+ - gpio
+ - i2c
+ - pwm
+ - spi
+ - uart
+
+ properties:
+ pins:
+ description: |
+ List of pins affected by this state node, using the numeric pin IDs
+ defined in dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ uniqueItems: true
+ items:
+ minimum: 0
+ maximum: 52
+
+ function:
+ description: |
+ Mux function to select for the listed pins. Supported functions
+ depend on the selected pins and match the DP1000 hardware mux
+ table.
+ enum:
+ - gpio
+ - i2c
+ - pwm
+ - spi
+ - uart
+ - lpc
+ - espi
+
+ bias-disable: true
+ bias-high-impedance: true
+ bias-pull-up: true
+ bias-pull-down: true
+
+ drive-strength:
+ description: Output drive strength in mA.
+ enum: [20, 27, 33, 40]
+
+ required:
+ - pins
+ - function
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl@11081000 {
+ compatible = "ultrarisc,dp1000-pinctrl";
+ reg = <0x0 0x11081000 0x0 0x1000>;
+
+ i2c0-pins {
+ pins = <PA12 PA13>;
+ function = "i2c";
+ bias-pull-up;
+ drive-strength = <33>;
+ };
+
+ uart0-pins {
+ pins = <PA8 PA9>;
+ function = "uart";
+ bias-pull-up;
+ drive-strength = <33>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index e035a3be797c..1ef874d342a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27357,6 +27357,12 @@ S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
+ULTRARISC DP1000 PINCTRL DRIVER
+M: Jia Wang <wangjia@ultrarisc.com>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+
ULTRATRONIK BOARD SUPPORT
M: Goran Rađenović <goran.radni@gmail.com>
M: Börge Strümpfel <boerge.struempfel@gmail.com>
diff --git a/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
new file mode 100644
index 000000000000..f800c9722471
--- /dev/null
+++ b/include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+#define _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H
+
+#define PA0 0
+#define PA1 1
+#define PA2 2
+#define PA3 3
+#define PA4 4
+#define PA5 5
+#define PA6 6
+#define PA7 7
+#define PA8 8
+#define PA9 9
+#define PA10 10
+#define PA11 11
+#define PA12 12
+#define PA13 13
+#define PA14 14
+#define PA15 15
+#define PB0 16
+#define PB1 17
+#define PB2 18
+#define PB3 19
+#define PB4 20
+#define PB5 21
+#define PB6 22
+#define PB7 23
+#define PC0 24
+#define PC1 25
+#define PC2 26
+#define PC3 27
+#define PC4 28
+#define PC5 29
+#define PC6 30
+#define PC7 31
+#define PD0 32
+#define PD1 33
+#define PD2 34
+#define PD3 35
+#define PD4 36
+#define PD5 37
+#define PD6 38
+#define PD7 39
+#define LPC0 40
+#define LPC1 41
+#define LPC2 42
+#define LPC3 43
+#define LPC4 44
+#define LPC5 45
+#define LPC6 46
+#define LPC7 47
+#define LPC8 48
+#define LPC9 49
+#define LPC10 50
+#define LPC11 51
+#define LPC12 52
+
+#endif /* _DT_BINDINGS_PINCTRL_ULTRARISC_DP1000_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 2/2] pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver
2026-06-08 7:50 ` Jia Wang
@ 2026-06-08 7:50 ` Jia Wang
-1 siblings, 0 replies; 7+ messages in thread
From: Jia Wang via B4 Relay @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
From: Jia Wang <wangjia@ultrarisc.com>
Add support for the pin controller on the UltraRISC DP1000 SoC.
The controller provides mux selection for pins in ports A, B, C, D, and
LPC. Ports A-D default to GPIO and support peripheral muxing. LPC pins
can be switched to eSPI, but are not available as GPIOs. Basic pin
configuration controls such as drive strength, pull-up, and pull-down
are also supported.
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
MAINTAINERS | 1 +
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/ultrarisc/Kconfig | 21 ++
drivers/pinctrl/ultrarisc/Makefile | 4 +
drivers/pinctrl/ultrarisc/pinctrl-dp1000.c | 168 +++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c | 503 ++++++++++++++++++++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h | 63 ++++
8 files changed, 762 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1ef874d342a5..04f2126d8af5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27362,6 +27362,7 @@ M: Jia Wang <wangjia@ultrarisc.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+F: drivers/pinctrl/ultrarisc/*
ULTRATRONIK BOARD SUPPORT
M: Goran Rađenović <goran.radni@gmail.com>
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 03f2e3ee065f..2a5491e3fb47 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -708,6 +708,7 @@ source "drivers/pinctrl/sunplus/Kconfig"
source "drivers/pinctrl/sunxi/Kconfig"
source "drivers/pinctrl/tegra/Kconfig"
source "drivers/pinctrl/ti/Kconfig"
+source "drivers/pinctrl/ultrarisc/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
source "drivers/pinctrl/visconti/Kconfig"
source "drivers/pinctrl/vt8500/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f7d5d5f76d0c..61d502ba06b9 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -95,6 +95,7 @@ obj-y += sunplus/
obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
+obj-$(CONFIG_PINCTRL_ULTRARISC) += ultrarisc/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_PINCTRL_VISCONTI) += visconti/
obj-$(CONFIG_ARCH_VT8500) += vt8500/
diff --git a/drivers/pinctrl/ultrarisc/Kconfig b/drivers/pinctrl/ultrarisc/Kconfig
new file mode 100644
index 000000000000..d81a152f2f4b
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config PINCTRL_ULTRARISC
+ tristate
+ depends on OF
+ depends on ARCH_ULTRARISC || COMPILE_TEST
+ select GENERIC_PINCTRL
+ select PINMUX
+ select GPIOLIB
+
+config PINCTRL_ULTRARISC_DP1000
+ tristate "UltraRISC DP1000 SoC Pinctrl driver"
+ select PINCTRL_ULTRARISC
+ depends on OF && HAS_IOMEM
+ depends on ARCH_ULTRARISC || COMPILE_TEST
+ default ARCH_ULTRARISC
+ help
+ Say Y to select the pinctrl driver for UltraRISC DP1000 SoC.
+ This pin controller allows selecting the mux function for
+ each pin. This driver can also be built as a module called
+ pinctrl-dp1000.
diff --git a/drivers/pinctrl/ultrarisc/Makefile b/drivers/pinctrl/ultrarisc/Makefile
new file mode 100644
index 000000000000..5d49ce1c0af9
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_PINCTRL_ULTRARISC) += pinctrl-ultrarisc.o
+obj-$(CONFIG_PINCTRL_ULTRARISC_DP1000) += pinctrl-dp1000.o
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
new file mode 100644
index 000000000000..f9c85c8c4433
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-ultrarisc.h"
+
+/* Port indices. */
+#define UR_DP1000_PORT_A_IDX 0
+#define UR_DP1000_PORT_B_IDX 1
+#define UR_DP1000_PORT_C_IDX 2
+#define UR_DP1000_PORT_D_IDX 3
+#define UR_DP1000_PORT_LPC_IDX 4
+
+/* Port mux register offsets. */
+#define UR_DP1000_PORTA_FUNC_OFFSET 0x2c0
+#define UR_DP1000_PORTB_FUNC_OFFSET 0x2c4
+#define UR_DP1000_PORTC_FUNC_OFFSET 0x2c8
+#define UR_DP1000_PORTD_FUNC_OFFSET 0x2cc
+#define UR_DP1000_PORTLPC_FUNC_OFFSET 0x2d0
+
+/* Port pinconf register offsets. */
+#define UR_DP1000_PORTA_CONF_OFFSET 0x310
+#define UR_DP1000_PORTB_CONF_OFFSET 0x318
+#define UR_DP1000_PORTC_CONF_OFFSET 0x31c
+#define UR_DP1000_PORTD_CONF_OFFSET 0x320
+#define UR_DP1000_PORTLPC_CONF_OFFSET 0x324
+
+/* Pin ranges for function descriptors. */
+#define UR_DP1000_PINS_ABCD GENMASK_ULL(39, 0)
+#define UR_DP1000_PINS_LPC GENMASK_ULL(52, 40)
+
+/* Static table entry helpers. */
+#define UR_DP1000_PORT(_base, _npins, _func, _conf, _modes, _gpio) \
+ { .pin_base = (_base), .npins = (_npins), .func_offset = (_func), \
+ .conf_offset = (_conf), .supported_modes = (_modes), \
+ .supports_gpio = (_gpio) }
+
+#define UR_DP1000_PIN(_nr, _name, _port) \
+ { .number = (_nr), .name = (_name), .drv_data = (void *)&ur_dp1000_ports[_port] }
+
+static const struct ur_func_route ur_dp1000_routes[] = {
+ { "gpio", UR_FUNC_DEFAULT, UR_DP1000_PINS_ABCD },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(13, 12) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(23, 22) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(25, 24) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(27, 26) },
+ { "pwm", UR_FUNC_0, GENMASK_ULL(19, 16) },
+ { "spi", UR_FUNC_1, GENMASK_ULL(39, 32) },
+ { "spi", UR_FUNC_0, GENMASK_ULL(6, 0) },
+ { "uart", UR_FUNC_1, GENMASK_ULL(9, 8) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(21, 20) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(29, 28) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(31, 30) },
+ { "lpc", UR_FUNC_DEFAULT, UR_DP1000_PINS_LPC },
+ { "espi", UR_FUNC_0, UR_DP1000_PINS_LPC },
+};
+
+static const struct ur_port_desc ur_dp1000_ports[] = {
+ UR_DP1000_PORT(0, 16, UR_DP1000_PORTA_FUNC_OFFSET,
+ UR_DP1000_PORTA_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(16, 8, UR_DP1000_PORTB_FUNC_OFFSET,
+ UR_DP1000_PORTB_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(24, 8, UR_DP1000_PORTC_FUNC_OFFSET,
+ UR_DP1000_PORTC_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(32, 8, UR_DP1000_PORTD_FUNC_OFFSET,
+ UR_DP1000_PORTD_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(40, 13, UR_DP1000_PORTLPC_FUNC_OFFSET,
+ UR_DP1000_PORTLPC_CONF_OFFSET,
+ UR_FUNC_0, false),
+};
+
+static const struct pinctrl_pin_desc ur_dp1000_pins[] = {
+ UR_DP1000_PIN(0, "PA0", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(1, "PA1", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(2, "PA2", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(3, "PA3", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(4, "PA4", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(5, "PA5", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(6, "PA6", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(7, "PA7", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(8, "PA8", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(9, "PA9", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(10, "PA10", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(11, "PA11", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(12, "PA12", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(13, "PA13", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(14, "PA14", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(15, "PA15", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(16, "PB0", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(17, "PB1", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(18, "PB2", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(19, "PB3", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(20, "PB4", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(21, "PB5", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(22, "PB6", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(23, "PB7", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(24, "PC0", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(25, "PC1", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(26, "PC2", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(27, "PC3", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(28, "PC4", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(29, "PC5", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(30, "PC6", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(31, "PC7", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(32, "PD0", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(33, "PD1", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(34, "PD2", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(35, "PD3", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(36, "PD4", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(37, "PD5", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(38, "PD6", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(39, "PD7", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(40, "LPC0", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(41, "LPC1", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(42, "LPC2", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(43, "LPC3", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(44, "LPC4", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(45, "LPC5", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(46, "LPC6", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(47, "LPC7", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(48, "LPC8", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(49, "LPC9", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(50, "LPC10", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(51, "LPC11", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(52, "LPC12", UR_DP1000_PORT_LPC_IDX),
+};
+
+static const struct ur_pinctrl_data ur_dp1000_pinctrl_data = {
+ .pins = ur_dp1000_pins,
+ .npins = ARRAY_SIZE(ur_dp1000_pins),
+ .routes = ur_dp1000_routes,
+ .num_routes = ARRAY_SIZE(ur_dp1000_routes),
+};
+
+static const struct of_device_id ur_pinctrl_of_match[] = {
+ { .compatible = "ultrarisc,dp1000-pinctrl" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ur_pinctrl_of_match);
+
+static int ur_dp1000_pinctrl_probe(struct platform_device *pdev)
+{
+ return ur_pinctrl_probe(pdev, &ur_dp1000_pinctrl_data);
+}
+
+static struct platform_driver ur_pinctrl_driver = {
+ .driver = {
+ .name = "ultrarisc-pinctrl-dp1000",
+ .of_match_table = ur_pinctrl_of_match,
+ },
+ .probe = ur_dp1000_pinctrl_probe,
+};
+
+module_platform_driver(ur_pinctrl_driver);
+
+MODULE_DESCRIPTION("UltraRISC DP1000 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
new file mode 100644
index 000000000000..5c123873f50e
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../devicetree.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#include "pinctrl-ultrarisc.h"
+
+#define UR_CONF_BIT_PER_PIN 4
+#define UR_CONF_PIN_PER_REG (32 / UR_CONF_BIT_PER_PIN)
+static const u32 ur_drive_strengths[] = { 20, 27, 33, 40 };
+
+static const struct ur_port_desc *ur_get_pin_port(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ const struct pin_desc *desc = pin_desc_get(pctldev, pin);
+
+ if (!desc || !desc->drv_data)
+ return NULL;
+
+ return desc->drv_data;
+}
+
+static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin)
+{
+ return port_desc->conf_offset +
+ (pin / UR_CONF_PIN_PER_REG) * sizeof(u32);
+}
+
+static int ur_read_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 *conf)
+{
+ const struct ur_port_desc *port_desc;
+ u32 pin_offset;
+ u32 reg_offset;
+ u32 shift;
+ u32 mask;
+
+ port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ if (!port_desc)
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+ reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+ shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+ mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+ *conf = field_get(mask, readl_relaxed(pctrl->base + reg_offset));
+
+ return 0;
+}
+
+static int ur_write_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 conf)
+{
+ const struct ur_port_desc *port_desc;
+ unsigned long flags;
+ void __iomem *reg;
+ u32 pin_offset;
+ u32 reg_offset;
+ u32 shift;
+ u32 mask;
+ u32 val;
+
+ port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ if (!port_desc)
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+ reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+ reg = pctrl->base + reg_offset;
+ shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+ mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl_relaxed(reg);
+ val = (val & ~mask) | field_prep(mask, conf);
+ writel_relaxed(val, reg);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int ur_set_pin_mux(struct ur_pinctrl *pctrl,
+ const struct ur_port_desc *port_desc,
+ u32 pin_offset, u32 mode)
+{
+ void __iomem *reg = pctrl->base + port_desc->func_offset;
+ unsigned long flags;
+ u32 val;
+
+ if (WARN_ON(pin_offset >= UR_MAX_PINS_PER_PORT))
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl_relaxed(reg);
+ val &= ~((UR_FUNC_0 | UR_FUNC_1) << pin_offset);
+ val |= mode << pin_offset;
+ writel_relaxed(val, reg);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctrl, unsigned int pin, u32 mode)
+{
+ const struct ur_port_desc *port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ u32 pin_offset;
+
+ if (!port_desc)
+ return -EINVAL;
+
+ if (mode != UR_FUNC_DEFAULT && !(port_desc->supported_modes & mode))
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+
+ return ur_set_pin_mux(pctrl, port_desc, pin_offset, mode);
+}
+
+static int ur_hw_to_config(unsigned long *config, u32 conf)
+{
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 drive = FIELD_GET(UR_DRIVE_MASK, conf);
+ u32 pull = FIELD_GET(UR_PULL_MASK, conf);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ if (pull != UR_PULL_DIS)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pull != UR_PULL_UP)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+ if (pull != UR_PULL_DOWN)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (drive >= ARRAY_SIZE(ur_drive_strengths))
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, ur_drive_strengths[drive]);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ur_config_to_hw(unsigned long config, u32 *conf)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN);
+ return 0;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) {
+ if (ur_drive_strengths[i] != arg)
+ continue;
+ FIELD_MODIFY(UR_DRIVE_MASK, conf, i);
+ return 0;
+ }
+ return -EINVAL;
+ case PIN_CONFIG_PERSIST_STATE:
+ /*
+ * For PIN_CONFIG_PERSIST_STATE, gpiolib only treats
+ * -ENOTSUPP as an optional unsupported result.
+ * Do not use -EOPNOTSUPP here.
+ */
+ return -ENOTSUPP;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ur_find_group_route(struct ur_pinctrl *pctrl,
+ const char *function,
+ u64 group_mask,
+ const struct ur_func_route **route_out)
+{
+ const struct ur_func_route *match = NULL;
+
+ for (u32 i = 0; i < pctrl->data->num_routes; i++) {
+ const struct ur_func_route *route = &pctrl->data->routes[i];
+
+ if (strcmp(route->function, function))
+ continue;
+
+ if ((route->valid_pins & group_mask) != group_mask)
+ continue;
+
+ if (match) {
+ dev_err(pctrl->dev,
+ "ambiguous route for function %s group_mask=%#llx\n",
+ function, (unsigned long long)group_mask);
+ return -EINVAL;
+ }
+
+ match = route;
+ }
+
+ if (match) {
+ *route_out = match;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static const char *ur_get_group_function(struct pinctrl_dev *pctldev,
+ unsigned int group_selector,
+ unsigned int pin_index)
+{
+ const struct group_desc *group;
+ const char * const *functions;
+
+ group = pinctrl_generic_get_group(pctldev, group_selector);
+ if (!group || pin_index >= group->grp.npins || !group->data)
+ return NULL;
+
+ functions = group->data;
+
+ return functions[pin_index];
+}
+
+static int ur_resolve_group_mux(struct pinctrl_dev *pctldev,
+ struct ur_pinctrl *pctrl,
+ unsigned int group_selector,
+ const unsigned int *pins,
+ unsigned int npins,
+ const struct ur_func_route **route_out)
+{
+ const char *function;
+ u64 group_mask = 0;
+
+ if (!npins)
+ return -EINVAL;
+
+ function = ur_get_group_function(pctldev, group_selector, 0);
+ if (!function)
+ return -EINVAL;
+
+ for (u32 i = 0; i < npins; i++)
+ group_mask |= BIT_ULL(pins[i]);
+
+ return ur_find_group_route(pctrl, function, group_mask, route_out);
+}
+
+static bool ur_function_is_gpio(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ const struct function_desc *function;
+
+ function = pinmux_generic_get_function(pctldev, selector);
+ if (!function)
+ return false;
+
+ for (u32 i = 0; i < function->func->ngroups; i++) {
+ const char *func_name;
+ int group_selector;
+
+ group_selector = pinctrl_get_group_selector(pctldev,
+ function->func->groups[i]);
+ if (group_selector < 0)
+ return false;
+
+ func_name = ur_get_group_function(pctldev, group_selector, 0);
+ if (!func_name || strcmp(func_name, "gpio"))
+ return false;
+ }
+
+ return true;
+}
+
+static const struct pinctrl_ops ur_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ur_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct ur_port_desc *port_desc;
+ const struct ur_func_route *route;
+ int ret;
+
+ (void)range;
+
+ port_desc = ur_get_pin_port(pctldev, offset);
+ if (!port_desc || !port_desc->supports_gpio)
+ return -EINVAL;
+
+ ret = ur_find_group_route(pctrl, "gpio", BIT_ULL(offset), &route);
+ if (ret)
+ return ret;
+
+ return ur_set_pin_mux_by_num(pctrl, offset, route->mode);
+}
+
+static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct ur_func_route *route;
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ (void)func_selector;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins);
+ if (ret)
+ return ret;
+
+ ret = ur_resolve_group_mux(pctldev, pctrl, group_selector, pins, npins,
+ &route);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < npins; i++) {
+ ret = ur_set_pin_mux_by_num(pctrl, pins[i], route->mode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops ur_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .function_is_gpio = ur_function_is_gpio,
+ .set_mux = ur_set_mux,
+ .gpio_request_enable = ur_gpio_request_enable,
+ .strict = true,
+};
+
+static int ur_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *config)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ u32 conf;
+ int ret;
+
+ ret = ur_read_pin_conf(pctrl, pin, &conf);
+ if (ret)
+ return ret;
+
+ return ur_hw_to_config(config, conf);
+}
+
+static int ur_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ u32 conf;
+ int ret;
+
+ ret = ur_read_pin_conf(pctrl, pin, &conf);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < num_configs; i++) {
+ ret = ur_config_to_hw(configs[i], &conf);
+ if (ret)
+ return ret;
+ }
+
+ return ur_write_pin_conf(pctrl, pin, conf);
+}
+
+static int ur_pin_config_group_get(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *config)
+{
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret || !npins)
+ return ret ?: -EINVAL;
+
+ return ur_pin_config_get(pctldev, pins[0], config);
+}
+
+static int ur_pin_config_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < npins; i++) {
+ ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops ur_pinconf_ops = {
+ .pin_config_get = ur_pin_config_get,
+ .pin_config_set = ur_pin_config_set,
+ .pin_config_group_get = ur_pin_config_group_get,
+ .pin_config_group_set = ur_pin_config_group_set,
+#ifdef CONFIG_GENERIC_PINCONF
+ .is_generic = true,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+#endif
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+ const struct ur_pinctrl_data *data)
+{
+ struct pinctrl_desc *desc;
+ struct ur_pinctrl *pctrl;
+ int ret;
+
+ if (!data)
+ return -ENODEV;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pctrl->base))
+ return PTR_ERR(pctrl->base);
+ pctrl->dev = &pdev->dev;
+ pctrl->data = data;
+
+ raw_spin_lock_init(&pctrl->lock);
+
+ desc->name = dev_name(&pdev->dev);
+ desc->owner = THIS_MODULE;
+ desc->pins = data->pins;
+ desc->npins = data->npins;
+ desc->pctlops = &ur_pinctrl_ops;
+ desc->pmxops = &ur_pinmux_ops;
+ desc->confops = &ur_pinconf_ops;
+
+ ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctrl, &pctrl->pctl_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n");
+
+ platform_set_drvdata(pdev, pctrl);
+
+ return pinctrl_enable(pctrl->pctl_dev);
+}
+EXPORT_SYMBOL_GPL(ur_pinctrl_probe);
+
+MODULE_DESCRIPTION("UltraRISC pinctrl core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
new file mode 100644
index 000000000000..c874688aafca
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#ifndef __PINCTRL_ULTRARISC_H__
+#define __PINCTRL_ULTRARISC_H__
+
+#include <linux/io.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/spinlock.h>
+
+struct platform_device;
+
+#define UR_FUNC_DEFAULT 0U
+#define UR_FUNC_0 1U
+#define UR_FUNC_1 0x10000U
+
+#define UR_MAX_PINS_PER_PORT 16
+
+#define UR_BIAS_MASK 0x0000000F
+#define UR_PULL_MASK 0x0C
+#define UR_PULL_DIS 0
+#define UR_PULL_UP 1
+#define UR_PULL_DOWN 2
+#define UR_DRIVE_MASK 0x03
+
+struct ur_port_desc {
+ u32 pin_base;
+ u32 npins;
+ u32 func_offset;
+ u32 conf_offset;
+ u32 supported_modes;
+ bool supports_gpio;
+};
+
+struct ur_func_route {
+ const char *function;
+ u32 mode;
+ u64 valid_pins;
+};
+
+struct ur_pinctrl_data {
+ const struct pinctrl_pin_desc *pins;
+ u32 npins;
+ const struct ur_func_route *routes;
+ u32 num_routes;
+};
+
+struct ur_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl_dev;
+ const struct ur_pinctrl_data *data;
+ void __iomem *base;
+ raw_spinlock_t lock; /* Protects mux and conf registers */
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+ const struct ur_pinctrl_data *data);
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 2/2] pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver
@ 2026-06-08 7:50 ` Jia Wang
0 siblings, 0 replies; 7+ messages in thread
From: Jia Wang @ 2026-06-08 7:50 UTC (permalink / raw)
To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski
Cc: linux-gpio, devicetree, linux-kernel, Jia Wang
Add support for the pin controller on the UltraRISC DP1000 SoC.
The controller provides mux selection for pins in ports A, B, C, D, and
LPC. Ports A-D default to GPIO and support peripheral muxing. LPC pins
can be switched to eSPI, but are not available as GPIOs. Basic pin
configuration controls such as drive strength, pull-up, and pull-down
are also supported.
Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
MAINTAINERS | 1 +
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/ultrarisc/Kconfig | 21 ++
drivers/pinctrl/ultrarisc/Makefile | 4 +
drivers/pinctrl/ultrarisc/pinctrl-dp1000.c | 168 +++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c | 503 ++++++++++++++++++++++++++
drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h | 63 ++++
8 files changed, 762 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1ef874d342a5..04f2126d8af5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27362,6 +27362,7 @@ M: Jia Wang <wangjia@ultrarisc.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
+F: drivers/pinctrl/ultrarisc/*
ULTRATRONIK BOARD SUPPORT
M: Goran Rađenović <goran.radni@gmail.com>
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 03f2e3ee065f..2a5491e3fb47 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -708,6 +708,7 @@ source "drivers/pinctrl/sunplus/Kconfig"
source "drivers/pinctrl/sunxi/Kconfig"
source "drivers/pinctrl/tegra/Kconfig"
source "drivers/pinctrl/ti/Kconfig"
+source "drivers/pinctrl/ultrarisc/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
source "drivers/pinctrl/visconti/Kconfig"
source "drivers/pinctrl/vt8500/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f7d5d5f76d0c..61d502ba06b9 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -95,6 +95,7 @@ obj-y += sunplus/
obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
+obj-$(CONFIG_PINCTRL_ULTRARISC) += ultrarisc/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_PINCTRL_VISCONTI) += visconti/
obj-$(CONFIG_ARCH_VT8500) += vt8500/
diff --git a/drivers/pinctrl/ultrarisc/Kconfig b/drivers/pinctrl/ultrarisc/Kconfig
new file mode 100644
index 000000000000..d81a152f2f4b
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config PINCTRL_ULTRARISC
+ tristate
+ depends on OF
+ depends on ARCH_ULTRARISC || COMPILE_TEST
+ select GENERIC_PINCTRL
+ select PINMUX
+ select GPIOLIB
+
+config PINCTRL_ULTRARISC_DP1000
+ tristate "UltraRISC DP1000 SoC Pinctrl driver"
+ select PINCTRL_ULTRARISC
+ depends on OF && HAS_IOMEM
+ depends on ARCH_ULTRARISC || COMPILE_TEST
+ default ARCH_ULTRARISC
+ help
+ Say Y to select the pinctrl driver for UltraRISC DP1000 SoC.
+ This pin controller allows selecting the mux function for
+ each pin. This driver can also be built as a module called
+ pinctrl-dp1000.
diff --git a/drivers/pinctrl/ultrarisc/Makefile b/drivers/pinctrl/ultrarisc/Makefile
new file mode 100644
index 000000000000..5d49ce1c0af9
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_PINCTRL_ULTRARISC) += pinctrl-ultrarisc.o
+obj-$(CONFIG_PINCTRL_ULTRARISC_DP1000) += pinctrl-dp1000.o
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
new file mode 100644
index 000000000000..f9c85c8c4433
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-dp1000.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-ultrarisc.h"
+
+/* Port indices. */
+#define UR_DP1000_PORT_A_IDX 0
+#define UR_DP1000_PORT_B_IDX 1
+#define UR_DP1000_PORT_C_IDX 2
+#define UR_DP1000_PORT_D_IDX 3
+#define UR_DP1000_PORT_LPC_IDX 4
+
+/* Port mux register offsets. */
+#define UR_DP1000_PORTA_FUNC_OFFSET 0x2c0
+#define UR_DP1000_PORTB_FUNC_OFFSET 0x2c4
+#define UR_DP1000_PORTC_FUNC_OFFSET 0x2c8
+#define UR_DP1000_PORTD_FUNC_OFFSET 0x2cc
+#define UR_DP1000_PORTLPC_FUNC_OFFSET 0x2d0
+
+/* Port pinconf register offsets. */
+#define UR_DP1000_PORTA_CONF_OFFSET 0x310
+#define UR_DP1000_PORTB_CONF_OFFSET 0x318
+#define UR_DP1000_PORTC_CONF_OFFSET 0x31c
+#define UR_DP1000_PORTD_CONF_OFFSET 0x320
+#define UR_DP1000_PORTLPC_CONF_OFFSET 0x324
+
+/* Pin ranges for function descriptors. */
+#define UR_DP1000_PINS_ABCD GENMASK_ULL(39, 0)
+#define UR_DP1000_PINS_LPC GENMASK_ULL(52, 40)
+
+/* Static table entry helpers. */
+#define UR_DP1000_PORT(_base, _npins, _func, _conf, _modes, _gpio) \
+ { .pin_base = (_base), .npins = (_npins), .func_offset = (_func), \
+ .conf_offset = (_conf), .supported_modes = (_modes), \
+ .supports_gpio = (_gpio) }
+
+#define UR_DP1000_PIN(_nr, _name, _port) \
+ { .number = (_nr), .name = (_name), .drv_data = (void *)&ur_dp1000_ports[_port] }
+
+static const struct ur_func_route ur_dp1000_routes[] = {
+ { "gpio", UR_FUNC_DEFAULT, UR_DP1000_PINS_ABCD },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(13, 12) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(23, 22) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(25, 24) },
+ { "i2c", UR_FUNC_0, GENMASK_ULL(27, 26) },
+ { "pwm", UR_FUNC_0, GENMASK_ULL(19, 16) },
+ { "spi", UR_FUNC_1, GENMASK_ULL(39, 32) },
+ { "spi", UR_FUNC_0, GENMASK_ULL(6, 0) },
+ { "uart", UR_FUNC_1, GENMASK_ULL(9, 8) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(21, 20) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(29, 28) },
+ { "uart", UR_FUNC_0, GENMASK_ULL(31, 30) },
+ { "lpc", UR_FUNC_DEFAULT, UR_DP1000_PINS_LPC },
+ { "espi", UR_FUNC_0, UR_DP1000_PINS_LPC },
+};
+
+static const struct ur_port_desc ur_dp1000_ports[] = {
+ UR_DP1000_PORT(0, 16, UR_DP1000_PORTA_FUNC_OFFSET,
+ UR_DP1000_PORTA_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(16, 8, UR_DP1000_PORTB_FUNC_OFFSET,
+ UR_DP1000_PORTB_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(24, 8, UR_DP1000_PORTC_FUNC_OFFSET,
+ UR_DP1000_PORTC_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(32, 8, UR_DP1000_PORTD_FUNC_OFFSET,
+ UR_DP1000_PORTD_CONF_OFFSET,
+ UR_FUNC_0 | UR_FUNC_1, true),
+ UR_DP1000_PORT(40, 13, UR_DP1000_PORTLPC_FUNC_OFFSET,
+ UR_DP1000_PORTLPC_CONF_OFFSET,
+ UR_FUNC_0, false),
+};
+
+static const struct pinctrl_pin_desc ur_dp1000_pins[] = {
+ UR_DP1000_PIN(0, "PA0", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(1, "PA1", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(2, "PA2", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(3, "PA3", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(4, "PA4", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(5, "PA5", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(6, "PA6", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(7, "PA7", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(8, "PA8", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(9, "PA9", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(10, "PA10", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(11, "PA11", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(12, "PA12", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(13, "PA13", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(14, "PA14", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(15, "PA15", UR_DP1000_PORT_A_IDX),
+ UR_DP1000_PIN(16, "PB0", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(17, "PB1", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(18, "PB2", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(19, "PB3", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(20, "PB4", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(21, "PB5", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(22, "PB6", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(23, "PB7", UR_DP1000_PORT_B_IDX),
+ UR_DP1000_PIN(24, "PC0", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(25, "PC1", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(26, "PC2", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(27, "PC3", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(28, "PC4", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(29, "PC5", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(30, "PC6", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(31, "PC7", UR_DP1000_PORT_C_IDX),
+ UR_DP1000_PIN(32, "PD0", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(33, "PD1", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(34, "PD2", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(35, "PD3", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(36, "PD4", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(37, "PD5", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(38, "PD6", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(39, "PD7", UR_DP1000_PORT_D_IDX),
+ UR_DP1000_PIN(40, "LPC0", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(41, "LPC1", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(42, "LPC2", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(43, "LPC3", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(44, "LPC4", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(45, "LPC5", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(46, "LPC6", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(47, "LPC7", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(48, "LPC8", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(49, "LPC9", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(50, "LPC10", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(51, "LPC11", UR_DP1000_PORT_LPC_IDX),
+ UR_DP1000_PIN(52, "LPC12", UR_DP1000_PORT_LPC_IDX),
+};
+
+static const struct ur_pinctrl_data ur_dp1000_pinctrl_data = {
+ .pins = ur_dp1000_pins,
+ .npins = ARRAY_SIZE(ur_dp1000_pins),
+ .routes = ur_dp1000_routes,
+ .num_routes = ARRAY_SIZE(ur_dp1000_routes),
+};
+
+static const struct of_device_id ur_pinctrl_of_match[] = {
+ { .compatible = "ultrarisc,dp1000-pinctrl" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ur_pinctrl_of_match);
+
+static int ur_dp1000_pinctrl_probe(struct platform_device *pdev)
+{
+ return ur_pinctrl_probe(pdev, &ur_dp1000_pinctrl_data);
+}
+
+static struct platform_driver ur_pinctrl_driver = {
+ .driver = {
+ .name = "ultrarisc-pinctrl-dp1000",
+ .of_match_table = ur_pinctrl_of_match,
+ },
+ .probe = ur_dp1000_pinctrl_probe,
+};
+
+module_platform_driver(ur_pinctrl_driver);
+
+MODULE_DESCRIPTION("UltraRISC DP1000 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
new file mode 100644
index 000000000000..5c123873f50e
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../devicetree.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#include "pinctrl-ultrarisc.h"
+
+#define UR_CONF_BIT_PER_PIN 4
+#define UR_CONF_PIN_PER_REG (32 / UR_CONF_BIT_PER_PIN)
+static const u32 ur_drive_strengths[] = { 20, 27, 33, 40 };
+
+static const struct ur_port_desc *ur_get_pin_port(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ const struct pin_desc *desc = pin_desc_get(pctldev, pin);
+
+ if (!desc || !desc->drv_data)
+ return NULL;
+
+ return desc->drv_data;
+}
+
+static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin)
+{
+ return port_desc->conf_offset +
+ (pin / UR_CONF_PIN_PER_REG) * sizeof(u32);
+}
+
+static int ur_read_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 *conf)
+{
+ const struct ur_port_desc *port_desc;
+ u32 pin_offset;
+ u32 reg_offset;
+ u32 shift;
+ u32 mask;
+
+ port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ if (!port_desc)
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+ reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+ shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+ mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+ *conf = field_get(mask, readl_relaxed(pctrl->base + reg_offset));
+
+ return 0;
+}
+
+static int ur_write_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 conf)
+{
+ const struct ur_port_desc *port_desc;
+ unsigned long flags;
+ void __iomem *reg;
+ u32 pin_offset;
+ u32 reg_offset;
+ u32 shift;
+ u32 mask;
+ u32 val;
+
+ port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ if (!port_desc)
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+ reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
+ reg = pctrl->base + reg_offset;
+ shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
+ mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl_relaxed(reg);
+ val = (val & ~mask) | field_prep(mask, conf);
+ writel_relaxed(val, reg);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int ur_set_pin_mux(struct ur_pinctrl *pctrl,
+ const struct ur_port_desc *port_desc,
+ u32 pin_offset, u32 mode)
+{
+ void __iomem *reg = pctrl->base + port_desc->func_offset;
+ unsigned long flags;
+ u32 val;
+
+ if (WARN_ON(pin_offset >= UR_MAX_PINS_PER_PORT))
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl_relaxed(reg);
+ val &= ~((UR_FUNC_0 | UR_FUNC_1) << pin_offset);
+ val |= mode << pin_offset;
+ writel_relaxed(val, reg);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctrl, unsigned int pin, u32 mode)
+{
+ const struct ur_port_desc *port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
+ u32 pin_offset;
+
+ if (!port_desc)
+ return -EINVAL;
+
+ if (mode != UR_FUNC_DEFAULT && !(port_desc->supported_modes & mode))
+ return -EINVAL;
+
+ pin_offset = pin - port_desc->pin_base;
+
+ return ur_set_pin_mux(pctrl, port_desc, pin_offset, mode);
+}
+
+static int ur_hw_to_config(unsigned long *config, u32 conf)
+{
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 drive = FIELD_GET(UR_DRIVE_MASK, conf);
+ u32 pull = FIELD_GET(UR_PULL_MASK, conf);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ if (pull != UR_PULL_DIS)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pull != UR_PULL_UP)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+ if (pull != UR_PULL_DOWN)
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, 1);
+ return 0;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (drive >= ARRAY_SIZE(ur_drive_strengths))
+ return -EINVAL;
+ *config = pinconf_to_config_packed(param, ur_drive_strengths[drive]);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ur_config_to_hw(unsigned long config, u32 *conf)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP);
+ return 0;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+ FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN);
+ return 0;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) {
+ if (ur_drive_strengths[i] != arg)
+ continue;
+ FIELD_MODIFY(UR_DRIVE_MASK, conf, i);
+ return 0;
+ }
+ return -EINVAL;
+ case PIN_CONFIG_PERSIST_STATE:
+ /*
+ * For PIN_CONFIG_PERSIST_STATE, gpiolib only treats
+ * -ENOTSUPP as an optional unsupported result.
+ * Do not use -EOPNOTSUPP here.
+ */
+ return -ENOTSUPP;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ur_find_group_route(struct ur_pinctrl *pctrl,
+ const char *function,
+ u64 group_mask,
+ const struct ur_func_route **route_out)
+{
+ const struct ur_func_route *match = NULL;
+
+ for (u32 i = 0; i < pctrl->data->num_routes; i++) {
+ const struct ur_func_route *route = &pctrl->data->routes[i];
+
+ if (strcmp(route->function, function))
+ continue;
+
+ if ((route->valid_pins & group_mask) != group_mask)
+ continue;
+
+ if (match) {
+ dev_err(pctrl->dev,
+ "ambiguous route for function %s group_mask=%#llx\n",
+ function, (unsigned long long)group_mask);
+ return -EINVAL;
+ }
+
+ match = route;
+ }
+
+ if (match) {
+ *route_out = match;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static const char *ur_get_group_function(struct pinctrl_dev *pctldev,
+ unsigned int group_selector,
+ unsigned int pin_index)
+{
+ const struct group_desc *group;
+ const char * const *functions;
+
+ group = pinctrl_generic_get_group(pctldev, group_selector);
+ if (!group || pin_index >= group->grp.npins || !group->data)
+ return NULL;
+
+ functions = group->data;
+
+ return functions[pin_index];
+}
+
+static int ur_resolve_group_mux(struct pinctrl_dev *pctldev,
+ struct ur_pinctrl *pctrl,
+ unsigned int group_selector,
+ const unsigned int *pins,
+ unsigned int npins,
+ const struct ur_func_route **route_out)
+{
+ const char *function;
+ u64 group_mask = 0;
+
+ if (!npins)
+ return -EINVAL;
+
+ function = ur_get_group_function(pctldev, group_selector, 0);
+ if (!function)
+ return -EINVAL;
+
+ for (u32 i = 0; i < npins; i++)
+ group_mask |= BIT_ULL(pins[i]);
+
+ return ur_find_group_route(pctrl, function, group_mask, route_out);
+}
+
+static bool ur_function_is_gpio(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ const struct function_desc *function;
+
+ function = pinmux_generic_get_function(pctldev, selector);
+ if (!function)
+ return false;
+
+ for (u32 i = 0; i < function->func->ngroups; i++) {
+ const char *func_name;
+ int group_selector;
+
+ group_selector = pinctrl_get_group_selector(pctldev,
+ function->func->groups[i]);
+ if (group_selector < 0)
+ return false;
+
+ func_name = ur_get_group_function(pctldev, group_selector, 0);
+ if (!func_name || strcmp(func_name, "gpio"))
+ return false;
+ }
+
+ return true;
+}
+
+static const struct pinctrl_ops ur_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ur_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct ur_port_desc *port_desc;
+ const struct ur_func_route *route;
+ int ret;
+
+ (void)range;
+
+ port_desc = ur_get_pin_port(pctldev, offset);
+ if (!port_desc || !port_desc->supports_gpio)
+ return -EINVAL;
+
+ ret = ur_find_group_route(pctrl, "gpio", BIT_ULL(offset), &route);
+ if (ret)
+ return ret;
+
+ return ur_set_pin_mux_by_num(pctrl, offset, route->mode);
+}
+
+static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct ur_func_route *route;
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ (void)func_selector;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins);
+ if (ret)
+ return ret;
+
+ ret = ur_resolve_group_mux(pctldev, pctrl, group_selector, pins, npins,
+ &route);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < npins; i++) {
+ ret = ur_set_pin_mux_by_num(pctrl, pins[i], route->mode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops ur_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .function_is_gpio = ur_function_is_gpio,
+ .set_mux = ur_set_mux,
+ .gpio_request_enable = ur_gpio_request_enable,
+ .strict = true,
+};
+
+static int ur_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *config)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ u32 conf;
+ int ret;
+
+ ret = ur_read_pin_conf(pctrl, pin, &conf);
+ if (ret)
+ return ret;
+
+ return ur_hw_to_config(config, conf);
+}
+
+static int ur_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ u32 conf;
+ int ret;
+
+ ret = ur_read_pin_conf(pctrl, pin, &conf);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < num_configs; i++) {
+ ret = ur_config_to_hw(configs[i], &conf);
+ if (ret)
+ return ret;
+ }
+
+ return ur_write_pin_conf(pctrl, pin, conf);
+}
+
+static int ur_pin_config_group_get(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *config)
+{
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret || !npins)
+ return ret ?: -EINVAL;
+
+ return ur_pin_config_get(pctldev, pins[0], config);
+}
+
+static int ur_pin_config_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ const unsigned int *pins;
+ unsigned int npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (u32 i = 0; i < npins; i++) {
+ ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops ur_pinconf_ops = {
+ .pin_config_get = ur_pin_config_get,
+ .pin_config_set = ur_pin_config_set,
+ .pin_config_group_get = ur_pin_config_group_get,
+ .pin_config_group_set = ur_pin_config_group_set,
+#ifdef CONFIG_GENERIC_PINCONF
+ .is_generic = true,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+#endif
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+ const struct ur_pinctrl_data *data)
+{
+ struct pinctrl_desc *desc;
+ struct ur_pinctrl *pctrl;
+ int ret;
+
+ if (!data)
+ return -ENODEV;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pctrl->base))
+ return PTR_ERR(pctrl->base);
+ pctrl->dev = &pdev->dev;
+ pctrl->data = data;
+
+ raw_spin_lock_init(&pctrl->lock);
+
+ desc->name = dev_name(&pdev->dev);
+ desc->owner = THIS_MODULE;
+ desc->pins = data->pins;
+ desc->npins = data->npins;
+ desc->pctlops = &ur_pinctrl_ops;
+ desc->pmxops = &ur_pinmux_ops;
+ desc->confops = &ur_pinconf_ops;
+
+ ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctrl, &pctrl->pctl_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n");
+
+ platform_set_drvdata(pdev, pctrl);
+
+ return pinctrl_enable(pctrl->pctl_dev);
+}
+EXPORT_SYMBOL_GPL(ur_pinctrl_probe);
+
+MODULE_DESCRIPTION("UltraRISC pinctrl core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
new file mode 100644
index 000000000000..c874688aafca
--- /dev/null
+++ b/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
+ *
+ * Author: Jia Wang <wangjia@ultrarisc.com>
+ */
+
+#ifndef __PINCTRL_ULTRARISC_H__
+#define __PINCTRL_ULTRARISC_H__
+
+#include <linux/io.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/spinlock.h>
+
+struct platform_device;
+
+#define UR_FUNC_DEFAULT 0U
+#define UR_FUNC_0 1U
+#define UR_FUNC_1 0x10000U
+
+#define UR_MAX_PINS_PER_PORT 16
+
+#define UR_BIAS_MASK 0x0000000F
+#define UR_PULL_MASK 0x0C
+#define UR_PULL_DIS 0
+#define UR_PULL_UP 1
+#define UR_PULL_DOWN 2
+#define UR_DRIVE_MASK 0x03
+
+struct ur_port_desc {
+ u32 pin_base;
+ u32 npins;
+ u32 func_offset;
+ u32 conf_offset;
+ u32 supported_modes;
+ bool supports_gpio;
+};
+
+struct ur_func_route {
+ const char *function;
+ u32 mode;
+ u64 valid_pins;
+};
+
+struct ur_pinctrl_data {
+ const struct pinctrl_pin_desc *pins;
+ u32 npins;
+ const struct ur_func_route *routes;
+ u32 num_routes;
+};
+
+struct ur_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl_dev;
+ const struct ur_pinctrl_data *data;
+ void __iomem *base;
+ raw_spinlock_t lock; /* Protects mux and conf registers */
+};
+
+int ur_pinctrl_probe(struct platform_device *pdev,
+ const struct ur_pinctrl_data *data);
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
2026-06-08 7:50 ` Jia Wang
(?)
@ 2026-06-08 7:57 ` sashiko-bot
-1 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-06-08 7:57 UTC (permalink / raw)
To: Jia Wang via B4 Relay; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The newly added dt-bindings header file is not tracked in the MAINTAINERS entry.
--
commit f7f86b1233735eea88a3047d747f41d13c3dc00b
Author: Jia Wang <wangjia@ultrarisc.com>
dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller
This commit adds device tree binding documentation for the pin controllers
on the UltraRISC DP1000 RISC-V SoC. It also introduces a new header file
containing the corresponding pin definitions.
> diff --git a/MAINTAINERS b/MAINTAINERS
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
[ ... ]
> @@ -27357,6 +27357,12 @@ S: Maintained
> F: drivers/usb/common/ulpi.c
> F: include/linux/ulpi/
>
> +ULTRARISC DP1000 PINCTRL DRIVER
> +M: Jia Wang <wangjia@ultrarisc.com>
> +L: linux-gpio@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/pinctrl/ultrarisc,dp1000-pinctrl.yaml
> +
[Severity: Low]
This isn't a bug, but should the new header file
include/dt-bindings/pinctrl/ultrarisc,dp1000-pinctrl.h be added to this
MAINTAINERS block as well? Without it, get_maintainer.pl might miss CCing
the maintainer on future patches that modify the pin definitions.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260608-ultrarisc-pinctrl-v3-0-30a09ed74275@ultrarisc.com?part=1
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-08 7:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-08 7:50 [PATCH v3 0/2] pinctrl: ultrarisc: add DP1000 pinctrl support Jia Wang via B4 Relay
2026-06-08 7:50 ` Jia Wang
2026-06-08 7:50 ` [PATCH v3 1/2] dt-bindings: pinctrl: Add UltraRISC DP1000 pinctrl controller Jia Wang via B4 Relay
2026-06-08 7:50 ` Jia Wang
2026-06-08 7:57 ` sashiko-bot
2026-06-08 7:50 ` [PATCH v3 2/2] pinctrl: ultrarisc: Add UltraRISC DP1000 pinctrl driver Jia Wang via B4 Relay
2026-06-08 7:50 ` Jia Wang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.