* [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC
@ 2024-10-01 17:29 Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 1/5] dt-bindings: arm: airoha: Add the chip-scu node for " Lorenzo Bianconi
` (4 more replies)
0 siblings, 5 replies; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
Introduce airoha-mfd driver in order to load pinctrl and pwm drivers for
EN7581 SoC. airoha-mfd is needed since both pinctrl and pwm drivers
needs to access the same memory block (gpio memory region) to configure
{gio,irq}_chip and pwm functionalities respectively, so model them as
childs of a parent mfd driver.
Current EN7581 pinctrl driver supports the following functionalities:
- pin multiplexing via chip_scu syscon
- pin pull-up, pull-down, open-drain, current strength,
{input,output}_enable, output_{low,high} via chip_scu syscon
- gpio controller
- irq controller
---
Changes in v5:
- use spin_lock in airoha_pinctrl_rmw instead of a mutex since it can run
in interrupt context
- remove unused includes in pinctrl driver
- since the irq_chip is immutable, allocate the gpio_irq_chip struct
statically in pinctrl driver
- rely on regmap APIs in pinctrl driver but keep the spin_lock local to the
driver
- rely on guard/guard_scope APIs in pinctrl driver
- improve naming convention pinctrl driver
- introduce airoha_pinconf_set_pin_value utility routine
- Link to v4: https://lore.kernel.org/r/20240911-en7581-pinctrl-v4-0-60ac93d760bb@kernel.org
Changes in v4:
- add 'Limitation' description in pwm driver
- fix comments in pwm driver
- rely on mfd->base __iomem pointer in pwm driver, modify register
offsets according to it and get rid of sgpio_cfg, flash_cfg and
cycle_cfg pointers
- simplify register utility routines in pwm driver
- use 'generator' instead of 'waveform' suffix for pwm routines
- fix possible overflow calculating duty cycle in pwm driver
- do not modify pwm state in free callback in pwm driver
- cap the maximum period in pwm driver
- do not allow inverse polarity in pwm driver
- do not set of_xlate callback in the pwm driver and allow the stack to
do it
- fix MAINTAINERS file for airoha pinctrl driver
- fix undefined reference to __ffsdi2 in pinctrl driver
- simplify airoha,en7581-gpio-sysctl.yam binding
- Link to v3: https://lore.kernel.org/r/20240831-en7581-pinctrl-v3-0-98eebfb4da66@kernel.org
Changes in v3:
- introduce airoha-mfd driver
- add pwm driver to the same series
- model pinctrl and pwm drivers as childs of a parent mfd driver.
- access chip-scu memory region in pinctrl driver via syscon
- introduce a single airoha,en7581-gpio-sysctl.yaml binding and get rid
of dedicated bindings for pinctrl and pwm
- add airoha,en7581-chip-scu.yaml binding do the series
- Link to v2: https://lore.kernel.org/r/20240822-en7581-pinctrl-v2-0-ba1559173a7f@kernel.org
Changes in v2:
- Fix compilation errors
- Collapse some register mappings for gpio and irq controllers
- update dt-bindings according to new register mapping
- fix some dt-bindings errors
- Link to v1: https://lore.kernel.org/all/cover.1723392444.git.lorenzo@kernel.org/
---
Benjamin Larsson (1):
pwm: airoha: Add support for EN7581 SoC
Christian Marangi (2):
dt-bindings: mfd: Add support for Airoha EN7581 GPIO System Controller
mfd: airoha: Add support for Airoha EN7581 MFD
Lorenzo Bianconi (2):
dt-bindings: arm: airoha: Add the chip-scu node for EN7581 SoC
pinctrl: airoha: Add support for EN7581 SoC
.../bindings/arm/airoha,en7581-chip-scu.yaml | 42 +
.../bindings/mfd/airoha,en7581-gpio-sysctl.yaml | 433 +++
MAINTAINERS | 7 +
drivers/mfd/Kconfig | 8 +
drivers/mfd/Makefile | 2 +
drivers/mfd/airoha-en7581-gpio-mfd.c | 72 +
drivers/pinctrl/mediatek/Kconfig | 17 +-
drivers/pinctrl/mediatek/Makefile | 1 +
drivers/pinctrl/mediatek/pinctrl-airoha.c | 3007 ++++++++++++++++++++
drivers/pwm/Kconfig | 10 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-airoha.c | 414 +++
include/linux/mfd/airoha-en7581-mfd.h | 9 +
13 files changed, 4022 insertions(+), 1 deletion(-)
---
base-commit: 437d220f284a16e52c7d7f819e4a1a7e25fe8fe9
change-id: 20240818-en7581-pinctrl-1bf120154be0
prerequisite-change-id: 20240705-for-6-11-bpf-a349efc08df8:v2
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v5 1/5] dt-bindings: arm: airoha: Add the chip-scu node for EN7581 SoC
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
@ 2024-10-01 17:29 ` Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 2/5] dt-bindings: mfd: Add support for Airoha EN7581 GPIO System Controller Lorenzo Bianconi
` (3 subsequent siblings)
4 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
This patch adds the chip-scu document bindings for EN7581 SoC.
The airoha chip-scu block provides a configuration interface for clock,
io-muxing and other functionalities used by multiple controllers (e.g.
clock, pinctrl, ecc.) on EN7581 SoC.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../bindings/arm/airoha,en7581-chip-scu.yaml | 42 ++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml b/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml
new file mode 100644
index 000000000000..67c449d804c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/airoha,en7581-chip-scu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha Chip SCU Controller for EN7581 SoC
+
+maintainers:
+ - Lorenzo Bianconi <lorenzo@kernel.org>
+
+description:
+ The airoha chip-scu block provides a configuration interface for clock,
+ io-muxing and other functionalities used by multiple controllers (e.g. clock,
+ pinctrl, ecc) on EN7581 SoC.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - airoha,en7581-chip-scu
+ - const: syscon
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ syscon@1fa20000 {
+ compatible = "airoha,en7581-chip-scu", "syscon";
+ reg = <0x0 0x1fa20000 0x0 0x388>;
+ };
+ };
--
2.46.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 2/5] dt-bindings: mfd: Add support for Airoha EN7581 GPIO System Controller
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 1/5] dt-bindings: arm: airoha: Add the chip-scu node for " Lorenzo Bianconi
@ 2024-10-01 17:29 ` Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD Lorenzo Bianconi
` (2 subsequent siblings)
4 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
From: Christian Marangi <ansuelsmth@gmail.com>
Add support for Airoha EN7581 GPIO System Controller which provide a
register map for controlling the GPIO, pinctrl and PWM of the SoC.
Schema define cells for both gpio/interrupt controller and PWM.
Moreover it provides a dedicated pinctrl node for pins and config
definitions.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../bindings/mfd/airoha,en7581-gpio-sysctl.yaml | 433 +++++++++++++++++++++
1 file changed, 433 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml b/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml
new file mode 100644
index 000000000000..98396db40e67
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml
@@ -0,0 +1,433 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/airoha,en7581-gpio-sysctl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha EN7581 GPIO System Controller
+
+maintainers:
+ - Christian Marangi <ansuelsmth@gmail.com>
+ - Lorenzo Bianconi <lorenzo@kernel.org>
+
+description:
+ Airoha EN7581 SoC GPIO system controller which provided a register map
+ for controlling the GPIO, pins and PWM of the SoC.
+
+properties:
+ compatible:
+ const: airoha,en7581-gpio-sysctl
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ "#pwm-cells":
+ const: 3
+
+ pinctrl:
+ type: object
+
+ $ref: /schemas/pinctrl/pinctrl.yaml
+
+ patternProperties:
+ '-pins$':
+ type: object
+
+ patternProperties:
+ '^mux(-|$)':
+ type: object
+
+ description:
+ pinmux configuration nodes.
+
+ $ref: /schemas/pinctrl/pinmux-node.yaml
+
+ properties:
+ function:
+ description:
+ A string containing the name of the function to mux to the group.
+ enum: [pon, tod_1pps, sipo, mdio, uart, i2c, jtag, pcm, spi,
+ pcm_spi, i2s, emmc, pnand, pcie_reset, pwm, phy1_led0,
+ phy2_led0, phy3_led0, phy4_led0, phy1_led1, phy2_led1,
+ phy3_led1, phy4_led1]
+
+ groups:
+ description:
+ An array of strings. Each string contains the name of a group.
+
+ required:
+ - function
+ - groups
+
+ allOf:
+ - if:
+ properties:
+ function:
+ const: pon
+ then:
+ properties:
+ groups:
+ enum: [pon]
+ - if:
+ properties:
+ function:
+ const: tod_1pps
+ then:
+ properties:
+ groups:
+ enum: [pon_tod_1pps, gsw_tod_1pps]
+ - if:
+ properties:
+ function:
+ const: sipo
+ then:
+ properties:
+ groups:
+ enum: [sipo, sipo_rclk]
+ - if:
+ properties:
+ function:
+ const: mdio
+ then:
+ properties:
+ groups:
+ enum: [mdio]
+ - if:
+ properties:
+ function:
+ const: uart
+ then:
+ properties:
+ groups:
+ items:
+ enum: [uart2, uart2_cts_rts, hsuart, hsuart_cts_rts, uart4,
+ uart5]
+ maxItems: 2
+ - if:
+ properties:
+ function:
+ const: i2c
+ then:
+ properties:
+ groups:
+ enum: [i2c1]
+ - if:
+ properties:
+ function:
+ const: jtag
+ then:
+ properties:
+ groups:
+ enum: [jtag_udi, jtag_dfd]
+ - if:
+ properties:
+ function:
+ const: pcm
+ then:
+ properties:
+ groups:
+ enum: [pcm1, pcm2]
+ - if:
+ properties:
+ function:
+ const: spi
+ then:
+ properties:
+ groups:
+ items:
+ enum: [spi_quad, spi_cs1]
+ maxItems: 2
+ - if:
+ properties:
+ function:
+ const: pcm_spi
+ then:
+ properties:
+ groups:
+ items:
+ enum: [pcm_spi, pcm_spi_int, pcm_spi_rst, pcm_spi_cs1,
+ pcm_spi_cs2_p156, pcm_spi_cs2_p128, pcm_spi_cs3,
+ pcm_spi_cs4]
+ maxItems: 7
+ - if:
+ properties:
+ function:
+ const: i2c
+ then:
+ properties:
+ groups:
+ enum: [i2s]
+ - if:
+ properties:
+ function:
+ const: emmc
+ then:
+ properties:
+ groups:
+ enum: [emmc]
+ - if:
+ properties:
+ function:
+ const: pnand
+ then:
+ properties:
+ groups:
+ enum: [pnand]
+ - if:
+ properties:
+ function:
+ const: pcie_reset
+ then:
+ properties:
+ groups:
+ enum: [pcie_reset0, pcie_reset1, pcie_reset2]
+ - if:
+ properties:
+ function:
+ const: pwm
+ then:
+ properties:
+ groups:
+ enum: [gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6,
+ gpio7, gpio8, gpio9, gpio10, gpio11, gpio12, gpio13,
+ gpio14, gpio15, gpio16, gpio17, gpio18, gpio19,
+ gpio20, gpio21, gpio22, gpio23, gpio24, gpio25,
+ gpio26, gpio27, gpio28, gpio29, gpio30, gpio31,
+ gpio36, gpio37, gpio38, gpio39, gpio40, gpio41,
+ gpio42, gpio43, gpio44, gpio45, gpio46, gpio47]
+ - if:
+ properties:
+ function:
+ const: phy1_led0
+ then:
+ properties:
+ groups:
+ enum: [gpio33, gpio34, gpio35, gpio42]
+ - if:
+ properties:
+ function:
+ const: phy2_led0
+ then:
+ properties:
+ groups:
+ enum: [gpio33, gpio34, gpio35, gpio42]
+ - if:
+ properties:
+ function:
+ const: phy3_led0
+ then:
+ properties:
+ groups:
+ enum: [gpio33, gpio34, gpio35, gpio42]
+ - if:
+ properties:
+ function:
+ const: phy4_led0
+ then:
+ properties:
+ groups:
+ enum: [gpio33, gpio34, gpio35, gpio42]
+ - if:
+ properties:
+ function:
+ const: phy1_led1
+ then:
+ properties:
+ groups:
+ enum: [gpio43, gpio44, gpio45, gpio46]
+ - if:
+ properties:
+ function:
+ const: phy2_led1
+ then:
+ properties:
+ groups:
+ enum: [gpio43, gpio44, gpio45, gpio46]
+ - if:
+ properties:
+ function:
+ const: phy3_led1
+ then:
+ properties:
+ groups:
+ enum: [gpio43, gpio44, gpio45, gpio46]
+ - if:
+ properties:
+ function:
+ const: phy4_led1
+ then:
+ properties:
+ groups:
+ enum: [gpio43, gpio44, gpio45, gpio46]
+
+ additionalProperties: false
+
+ '^conf(-|$)':
+ type: object
+
+ description:
+ pinconf configuration nodes.
+
+ $ref: /schemas/pinctrl/pincfg-node.yaml
+
+ properties:
+ pins:
+ description:
+ An array of strings. Each string contains the name of a pin.
+ items:
+ enum: [uart1_txd, uart1_rxd, i2c_scl, i2c_sda, spi_cs0, spi_clk,
+ spi_mosi, spi_miso, gpio0, gpio1, gpio2, gpio3, gpio4,
+ gpio5, gpio6, gpio7, gpio8, gpio9, gpio10, gpio11, gpio12,
+ gpio13, gpio14, gpio15, gpio16, gpio17, gpio18, gpio19,
+ gpio20, gpio21, gpio22, gpio23, gpio24, gpio25, gpio26,
+ gpio27, gpio28, gpio29, gpio30, gpio31, gpio32, gpio33,
+ gpio34, gpio35, gpio36, gpio37, gpio38, gpio39, gpio40,
+ gpio41, gpio42, gpio43, gpio44, gpio45, gpio46,
+ pcie_reset0, pcie_reset1, pcie_reset2]
+ minItems: 1
+ maxItems: 58
+
+ bias-disable: true
+
+ bias-pull-up: true
+
+ bias-pull-down: true
+
+ input-enable: true
+
+ output-enable: true
+
+ output-low: true
+
+ output-high: true
+
+ drive-open-drain: true
+
+ drive-strength:
+ description:
+ Selects the drive strength for MIO pins, in mA.
+ enum: [2, 4, 6, 8]
+
+ required:
+ - pins
+
+ additionalProperties: false
+
+ additionalProperties: false
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - gpio-controller
+ - "#gpio-cells"
+ - "#pwm-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mfd@1fbf0200 {
+ compatible = "airoha,en7581-gpio-sysctl";
+ reg = <0x1fbf0200 0xc0>;
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ #pwm-cells = <3>;
+
+ pinctrl {
+ pcie1-rst-pins {
+ conf {
+ pins = "pcie_reset1";
+ drive-open-drain = <1>;
+ };
+ };
+
+ pwm-pins {
+ mux {
+ function = "pwm";
+ groups = "gpio18";
+ };
+ };
+
+ spi-pins {
+ mux {
+ function = "spi";
+ groups = "spi_quad", "spi_cs1";
+ };
+ };
+
+ uart2-pins {
+ mux {
+ function = "uart";
+ groups = "uart2", "uart2_cts_rts";
+ };
+ };
+
+ uar5-pins {
+ mux {
+ function = "uart";
+ groups = "uart5";
+ };
+ };
+
+ mmc-pins {
+ mux {
+ function = "emmc";
+ groups = "emmc";
+ };
+ };
+
+ mdio-pins {
+ mux {
+ function = "mdio";
+ groups = "mdio";
+ };
+
+ conf {
+ pins = "gpio2";
+ output-enable;
+ };
+ };
+
+ gswp1-led0-pins {
+ mux {
+ function = "phy1_led0";
+ groups = "gpio33";
+ };
+ };
+
+ gswp2-led1-pins {
+ mux {
+ function = "phy2_led1";
+ groups = "gpio44";
+ };
+ };
+ };
+ };
+
+...
--
2.46.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 1/5] dt-bindings: arm: airoha: Add the chip-scu node for " Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 2/5] dt-bindings: mfd: Add support for Airoha EN7581 GPIO System Controller Lorenzo Bianconi
@ 2024-10-01 17:29 ` Lorenzo Bianconi
2024-10-02 13:25 ` Lee Jones
2024-10-01 17:29 ` [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 5/5] pwm: " Lorenzo Bianconi
4 siblings, 1 reply; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
From: Christian Marangi <ansuelsmth@gmail.com>
Support for Airoha EN7581 Multi Function Device that
expose PINCTRL functionality and PWM functionality.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/mfd/Kconfig | 8 ++++
drivers/mfd/Makefile | 2 +
drivers/mfd/airoha-en7581-gpio-mfd.c | 72 +++++++++++++++++++++++++++++++++++
include/linux/mfd/airoha-en7581-mfd.h | 9 +++++
4 files changed, 91 insertions(+)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f9325bcce1b9..eca221351ab7 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -32,6 +32,14 @@ config MFD_ADP5585
the core APIs _only_, you have to select individual components like
the GPIO and PWM functions under the corresponding menus.
+config MFD_AIROHA_EN7581
+ bool "Airoha EN7581 Multi Function Device"
+ depends on (ARCH_AIROHA || COMPILE_TEST) && OF
+ select MFD_CORE
+ help
+ Support for Airoha EN7581 Multi Function Device that
+ expose PINCTRL functionality and PWM functionality.
+
config MFD_ALTERA_A10SR
bool "Altera Arria10 DevKit System Resource chip"
depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2a9f91e81af8..be8448e81a5b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -257,6 +257,8 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
+obj-$(CONFIG_MFD_AIROHA_EN7581) += airoha-en7581-gpio-mfd.o
+
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o
diff --git a/drivers/mfd/airoha-en7581-gpio-mfd.c b/drivers/mfd/airoha-en7581-gpio-mfd.c
new file mode 100644
index 000000000000..88407ce5747e
--- /dev/null
+++ b/drivers/mfd/airoha-en7581-gpio-mfd.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MFD driver for Airoha EN7581
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/mfd/airoha-en7581-mfd.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+
+static struct resource airoha_mfd_pinctrl_intr[] = {
+ {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct mfd_cell airoha_mfd_devs[] = {
+ {
+ .name = "pinctrl-airoha",
+ .resources = airoha_mfd_pinctrl_intr,
+ .num_resources = ARRAY_SIZE(airoha_mfd_pinctrl_intr),
+ }, {
+ .name = "pwm-airoha",
+ },
+};
+
+static int airoha_mfd_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct airoha_mfd *mfd;
+ int irq;
+
+ mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
+ if (!mfd)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mfd);
+
+ mfd->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mfd->base))
+ return PTR_ERR(mfd->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ airoha_mfd_pinctrl_intr[0].start = irq;
+ airoha_mfd_pinctrl_intr[0].end = irq;
+
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, airoha_mfd_devs,
+ ARRAY_SIZE(airoha_mfd_devs), NULL, 0,
+ NULL);
+}
+
+static const struct of_device_id airoha_mfd_of_match[] = {
+ { .compatible = "airoha,en7581-gpio-sysctl" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, airoha_mfd_of_match);
+
+static struct platform_driver airoha_mfd_driver = {
+ .probe = airoha_mfd_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = airoha_mfd_of_match,
+ },
+};
+module_platform_driver(airoha_mfd_driver);
+
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Driver for Airoha EN7581 MFD");
diff --git a/include/linux/mfd/airoha-en7581-mfd.h b/include/linux/mfd/airoha-en7581-mfd.h
new file mode 100644
index 000000000000..25e73952a777
--- /dev/null
+++ b/include/linux/mfd/airoha-en7581-mfd.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
+#define _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
+
+struct airoha_mfd {
+ void __iomem *base;
+};
+
+#endif /* _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_ */
--
2.46.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
` (2 preceding siblings ...)
2024-10-01 17:29 ` [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD Lorenzo Bianconi
@ 2024-10-01 17:29 ` Lorenzo Bianconi
2024-10-02 13:27 ` Linus Walleij
2024-10-01 17:29 ` [PATCH v5 5/5] pwm: " Lorenzo Bianconi
4 siblings, 1 reply; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
Introduce pinctrl driver for EN7581 SoC. Current EN7581 pinctrl driver
supports the following functionalities:
- pin multiplexing
- pin pull-up, pull-down, open-drain, current strength,
{input,output}_enable, output_{low,high}
- gpio controller
- irq controller
Tested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Co-developed-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
MAINTAINERS | 7 +
drivers/pinctrl/mediatek/Kconfig | 17 +-
drivers/pinctrl/mediatek/Makefile | 1 +
drivers/pinctrl/mediatek/pinctrl-airoha.c | 3007 +++++++++++++++++++++++++++++
4 files changed, 3031 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 67634f0ea30e..f7a78911d356 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18232,6 +18232,13 @@ F: drivers/pinctrl/
F: include/dt-bindings/pinctrl/
F: include/linux/pinctrl/
+PIN CONTROLLER - AIROHA
+M: Lorenzo Bianconi <lorenzo@kernel.org>
+L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml
+F: drivers/pinctrl/mediatek/pinctrl-airoha.c
+
PIN CONTROLLER - AMD
M: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 7af287252834..a417a031659c 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "MediaTek pinctrl drivers"
- depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST
+ depends on ARCH_MEDIATEK || ARCH_AIROHA || RALINK || COMPILE_TEST
config EINT_MTK
tristate "MediaTek External Interrupt Support"
@@ -126,6 +126,21 @@ config PINCTRL_MT8127
select PINCTRL_MTK
# For ARMv8 SoCs
+config PINCTRL_AIROHA
+ tristate "Airoha EN7581 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ select PINMUX
+ select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select REGMAP_MMIO
+ help
+ Say yes here to support pin controller and gpio driver
+ on Airoha EN7581 SoC.
+
config PINCTRL_MT2712
bool "MediaTek MT2712 pin control"
depends on OF
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 680f7e8526e0..1405d434218e 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o
obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o
# SoC Drivers
+obj-$(CONFIG_PINCTRL_AIROHA) += pinctrl-airoha.o
obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o
obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o
obj-$(CONFIG_PINCTRL_MT76X8) += pinctrl-mt76x8.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-airoha.c b/drivers/pinctrl/mediatek/pinctrl-airoha.c
new file mode 100644
index 000000000000..77eeb1c712e9
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-airoha.c
@@ -0,0 +1,3007 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ * Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
+ * Author: Markus Gothe <markus.gothe@genexis.eu>
+ */
+
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/airoha-en7581-mfd.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+
+#define PINCTRL_PIN_GROUP(id) \
+ PINCTRL_PINGROUP(#id, id##_pins, ARRAY_SIZE(id##_pins))
+
+#define PINCTRL_FUNC_DESC(id) \
+ { \
+ .desc = { \
+ .func = { \
+ .name = #id, \
+ .groups = id##_groups, \
+ .ngroups = ARRAY_SIZE(id##_groups), \
+ } \
+ }, \
+ .groups = id##_func_group, \
+ .group_size = ARRAY_SIZE(id##_func_group), \
+ }
+
+#define PINCTRL_CONF_DESC(p, offset, mask) \
+ { \
+ .pin = p, \
+ .reg = { offset, mask }, \
+ }
+
+/* MUX */
+#define REG_GPIO_2ND_I2C_MODE 0x0214
+#define GPIO_MDC_IO_MASTER_MODE_MODE BIT(14)
+#define GPIO_I2C_MASTER_MODE_MODE BIT(13)
+#define GPIO_I2S_MODE_MASK BIT(12)
+#define GPIO_I2C_SLAVE_MODE_MODE BIT(11)
+#define GPIO_LAN3_LED1_MODE_MASK BIT(10)
+#define GPIO_LAN3_LED0_MODE_MASK BIT(9)
+#define GPIO_LAN2_LED1_MODE_MASK BIT(8)
+#define GPIO_LAN2_LED0_MODE_MASK BIT(7)
+#define GPIO_LAN1_LED1_MODE_MASK BIT(6)
+#define GPIO_LAN1_LED0_MODE_MASK BIT(5)
+#define GPIO_LAN0_LED1_MODE_MASK BIT(4)
+#define GPIO_LAN0_LED0_MODE_MASK BIT(3)
+#define PON_TOD_1PPS_MODE_MASK BIT(2)
+#define GSW_TOD_1PPS_MODE_MASK BIT(1)
+#define GPIO_2ND_I2C_MODE_MASK BIT(0)
+
+#define REG_GPIO_SPI_CS1_MODE 0x0218
+#define GPIO_PCM_SPI_CS4_MODE_MASK BIT(21)
+#define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20)
+#define GPIO_PCM_SPI_CS2_MODE_P156_MASK BIT(19)
+#define GPIO_PCM_SPI_CS2_MODE_P128_MASK BIT(18)
+#define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17)
+#define GPIO_PCM_SPI_MODE_MASK BIT(16)
+#define GPIO_PCM2_MODE_MASK BIT(13)
+#define GPIO_PCM1_MODE_MASK BIT(12)
+#define GPIO_PCM_INT_MODE_MASK BIT(9)
+#define GPIO_PCM_RESET_MODE_MASK BIT(8)
+#define GPIO_SPI_QUAD_MODE_MASK BIT(4)
+#define GPIO_SPI_CS4_MODE_MASK BIT(3)
+#define GPIO_SPI_CS3_MODE_MASK BIT(2)
+#define GPIO_SPI_CS2_MODE_MASK BIT(1)
+#define GPIO_SPI_CS1_MODE_MASK BIT(0)
+
+#define REG_GPIO_PON_MODE 0x021c
+#define GPIO_PARALLEL_NAND_MODE_MASK BIT(14)
+#define GPIO_SGMII_MDIO_MODE_MASK BIT(13)
+#define GPIO_PCIE_RESET2_MASK BIT(12)
+#define SIPO_RCLK_MODE_MASK BIT(11)
+#define GPIO_PCIE_RESET1_MASK BIT(10)
+#define GPIO_PCIE_RESET0_MASK BIT(9)
+#define GPIO_UART5_MODE_MASK BIT(8)
+#define GPIO_UART4_MODE_MASK BIT(7)
+#define GPIO_HSUART_CTS_RTS_MODE_MASK BIT(6)
+#define GPIO_HSUART_MODE_MASK BIT(5)
+#define GPIO_UART2_CTS_RTS_MODE_MASK BIT(4)
+#define GPIO_UART2_MODE_MASK BIT(3)
+#define GPIO_SIPO_MODE_MASK BIT(2)
+#define GPIO_EMMC_MODE_MASK BIT(1)
+#define GPIO_PON_MODE_MASK BIT(0)
+
+#define REG_NPU_UART_EN 0x0224
+#define JTAG_UDI_EN_MASK BIT(4)
+#define JTAG_DFD_EN_MASK BIT(3)
+
+/* LED MAP */
+#define REG_LAN_LED0_MAPPING 0x027c
+#define REG_LAN_LED1_MAPPING 0x0280
+
+#define LAN4_LED_MAPPING_MASK GENMASK(18, 16)
+#define LAN4_PHY4_LED_MAP BIT(18)
+#define LAN4_PHY2_LED_MAP BIT(17)
+#define LAN4_PHY1_LED_MAP BIT(16)
+#define LAN4_PHY0_LED_MAP 0
+#define LAN4_PHY3_LED_MAP GENMASK(17, 16)
+
+#define LAN3_LED_MAPPING_MASK GENMASK(14, 12)
+#define LAN3_PHY4_LED_MAP BIT(14)
+#define LAN3_PHY2_LED_MAP BIT(13)
+#define LAN3_PHY1_LED_MAP BIT(12)
+#define LAN3_PHY0_LED_MAP 0
+#define LAN3_PHY3_LED_MAP GENMASK(13, 12)
+
+#define LAN2_LED_MAPPING_MASK GENMASK(10, 8)
+#define LAN2_PHY4_LED_MAP BIT(12)
+#define LAN2_PHY2_LED_MAP BIT(11)
+#define LAN2_PHY1_LED_MAP BIT(10)
+#define LAN2_PHY0_LED_MAP 0
+#define LAN2_PHY3_LED_MAP GENMASK(11, 10)
+
+#define LAN1_LED_MAPPING_MASK GENMASK(6, 4)
+#define LAN1_PHY4_LED_MAP BIT(6)
+#define LAN1_PHY2_LED_MAP BIT(5)
+#define LAN1_PHY1_LED_MAP BIT(4)
+#define LAN1_PHY0_LED_MAP 0
+#define LAN1_PHY3_LED_MAP GENMASK(5, 4)
+
+#define LAN0_LED_MAPPING_MASK GENMASK(2, 0)
+#define LAN0_PHY4_LED_MAP BIT(3)
+#define LAN0_PHY2_LED_MAP BIT(2)
+#define LAN0_PHY1_LED_MAP BIT(1)
+#define LAN0_PHY0_LED_MAP 0
+#define LAN0_PHY3_LED_MAP GENMASK(2, 1)
+
+/* CONF */
+#define REG_I2C_SDA_E2 0x001c
+#define SPI_MISO_E2_MASK BIT(14)
+#define SPI_MOSI_E2_MASK BIT(13)
+#define SPI_CLK_E2_MASK BIT(12)
+#define SPI_CS0_E2_MASK BIT(11)
+#define PCIE2_RESET_E2_MASK BIT(10)
+#define PCIE1_RESET_E2_MASK BIT(9)
+#define PCIE0_RESET_E2_MASK BIT(8)
+#define UART1_RXD_E2_MASK BIT(3)
+#define UART1_TXD_E2_MASK BIT(2)
+#define I2C_SCL_E2_MASK BIT(1)
+#define I2C_SDA_E2_MASK BIT(0)
+
+#define REG_I2C_SDA_E4 0x0020
+#define SPI_MISO_E4_MASK BIT(14)
+#define SPI_MOSI_E4_MASK BIT(13)
+#define SPI_CLK_E4_MASK BIT(12)
+#define SPI_CS0_E4_MASK BIT(11)
+#define PCIE2_RESET_E4_MASK BIT(10)
+#define PCIE1_RESET_E4_MASK BIT(9)
+#define PCIE0_RESET_E4_MASK BIT(8)
+#define UART1_RXD_E4_MASK BIT(3)
+#define UART1_TXD_E4_MASK BIT(2)
+#define I2C_SCL_E4_MASK BIT(1)
+#define I2C_SDA_E4_MASK BIT(0)
+
+#define REG_GPIO_L_E2 0x0024
+#define REG_GPIO_L_E4 0x0028
+#define REG_GPIO_H_E2 0x002c
+#define REG_GPIO_H_E4 0x0030
+
+#define REG_I2C_SDA_PU 0x0044
+#define SPI_MISO_PU_MASK BIT(14)
+#define SPI_MOSI_PU_MASK BIT(13)
+#define SPI_CLK_PU_MASK BIT(12)
+#define SPI_CS0_PU_MASK BIT(11)
+#define PCIE2_RESET_PU_MASK BIT(10)
+#define PCIE1_RESET_PU_MASK BIT(9)
+#define PCIE0_RESET_PU_MASK BIT(8)
+#define UART1_RXD_PU_MASK BIT(3)
+#define UART1_TXD_PU_MASK BIT(2)
+#define I2C_SCL_PU_MASK BIT(1)
+#define I2C_SDA_PU_MASK BIT(0)
+
+#define REG_I2C_SDA_PD 0x0048
+#define SPI_MISO_PD_MASK BIT(14)
+#define SPI_MOSI_PD_MASK BIT(13)
+#define SPI_CLK_PD_MASK BIT(12)
+#define SPI_CS0_PD_MASK BIT(11)
+#define PCIE2_RESET_PD_MASK BIT(10)
+#define PCIE1_RESET_PD_MASK BIT(9)
+#define PCIE0_RESET_PD_MASK BIT(8)
+#define UART1_RXD_PD_MASK BIT(3)
+#define UART1_TXD_PD_MASK BIT(2)
+#define I2C_SCL_PD_MASK BIT(1)
+#define I2C_SDA_PD_MASK BIT(0)
+
+#define REG_GPIO_L_PU 0x004c
+#define REG_GPIO_L_PD 0x0050
+#define REG_GPIO_H_PU 0x0054
+#define REG_GPIO_H_PD 0x0058
+
+#define REG_PCIE_RESET_OD 0x018c
+#define PCIE2_RESET_OD_MASK BIT(2)
+#define PCIE1_RESET_OD_MASK BIT(1)
+#define PCIE0_RESET_OD_MASK BIT(0)
+
+/* GPIOs */
+#define REG_GPIO_CTRL 0x0000
+#define REG_GPIO_DATA 0x0004
+#define REG_GPIO_INT 0x0008
+#define REG_GPIO_INT_EDGE 0x000c
+#define REG_GPIO_INT_LEVEL 0x0010
+#define REG_GPIO_OE 0x0014
+#define REG_GPIO_CTRL1 0x0020
+
+/* PWM MODE CONF */
+#define REG_GPIO_FLASH_MODE_CFG 0x0034
+#define GPIO15_FLASH_MODE_CFG BIT(15)
+#define GPIO14_FLASH_MODE_CFG BIT(14)
+#define GPIO13_FLASH_MODE_CFG BIT(13)
+#define GPIO12_FLASH_MODE_CFG BIT(12)
+#define GPIO11_FLASH_MODE_CFG BIT(11)
+#define GPIO10_FLASH_MODE_CFG BIT(10)
+#define GPIO9_FLASH_MODE_CFG BIT(9)
+#define GPIO8_FLASH_MODE_CFG BIT(8)
+#define GPIO7_FLASH_MODE_CFG BIT(7)
+#define GPIO6_FLASH_MODE_CFG BIT(6)
+#define GPIO5_FLASH_MODE_CFG BIT(5)
+#define GPIO4_FLASH_MODE_CFG BIT(4)
+#define GPIO3_FLASH_MODE_CFG BIT(3)
+#define GPIO2_FLASH_MODE_CFG BIT(2)
+#define GPIO1_FLASH_MODE_CFG BIT(1)
+#define GPIO0_FLASH_MODE_CFG BIT(0)
+
+#define REG_GPIO_CTRL2 0x0060
+#define REG_GPIO_CTRL3 0x0064
+
+/* PWM MODE CONF EXT */
+#define REG_GPIO_FLASH_MODE_CFG_EXT 0x0068
+#define GPIO51_FLASH_MODE_CFG BIT(31)
+#define GPIO50_FLASH_MODE_CFG BIT(30)
+#define GPIO49_FLASH_MODE_CFG BIT(29)
+#define GPIO48_FLASH_MODE_CFG BIT(28)
+#define GPIO47_FLASH_MODE_CFG BIT(27)
+#define GPIO46_FLASH_MODE_CFG BIT(26)
+#define GPIO45_FLASH_MODE_CFG BIT(25)
+#define GPIO44_FLASH_MODE_CFG BIT(24)
+#define GPIO43_FLASH_MODE_CFG BIT(23)
+#define GPIO42_FLASH_MODE_CFG BIT(22)
+#define GPIO41_FLASH_MODE_CFG BIT(21)
+#define GPIO40_FLASH_MODE_CFG BIT(20)
+#define GPIO39_FLASH_MODE_CFG BIT(19)
+#define GPIO38_FLASH_MODE_CFG BIT(18)
+#define GPIO37_FLASH_MODE_CFG BIT(17)
+#define GPIO36_FLASH_MODE_CFG BIT(16)
+#define GPIO31_FLASH_MODE_CFG BIT(15)
+#define GPIO30_FLASH_MODE_CFG BIT(14)
+#define GPIO29_FLASH_MODE_CFG BIT(13)
+#define GPIO28_FLASH_MODE_CFG BIT(12)
+#define GPIO27_FLASH_MODE_CFG BIT(11)
+#define GPIO26_FLASH_MODE_CFG BIT(10)
+#define GPIO25_FLASH_MODE_CFG BIT(9)
+#define GPIO24_FLASH_MODE_CFG BIT(8)
+#define GPIO23_FLASH_MODE_CFG BIT(7)
+#define GPIO22_FLASH_MODE_CFG BIT(6)
+#define GPIO21_FLASH_MODE_CFG BIT(5)
+#define GPIO20_FLASH_MODE_CFG BIT(4)
+#define GPIO19_FLASH_MODE_CFG BIT(3)
+#define GPIO18_FLASH_MODE_CFG BIT(2)
+#define GPIO17_FLASH_MODE_CFG BIT(1)
+#define GPIO16_FLASH_MODE_CFG BIT(0)
+
+#define REG_GPIO_DATA1 0x0070
+#define REG_GPIO_OE1 0x0078
+#define REG_GPIO_INT1 0x007c
+#define REG_GPIO_INT_EDGE1 0x0080
+#define REG_GPIO_INT_EDGE2 0x0084
+#define REG_GPIO_INT_EDGE3 0x0088
+#define REG_GPIO_INT_LEVEL1 0x008c
+#define REG_GPIO_INT_LEVEL2 0x0090
+#define REG_GPIO_INT_LEVEL3 0x0094
+
+#define AIROHA_NUM_GPIOS 64
+#define AIROHA_GPIO_BANK_SIZE (AIROHA_NUM_GPIOS / 2)
+#define AIROHA_REG_GPIOCTRL_NUM_GPIO (AIROHA_NUM_GPIOS / 4)
+
+static const u32 gpio_data_regs[] = {
+ REG_GPIO_DATA,
+ REG_GPIO_DATA1
+};
+
+static const u32 gpio_out_regs[] = {
+ REG_GPIO_OE,
+ REG_GPIO_OE1
+};
+
+static const u32 gpio_dir_regs[] = {
+ REG_GPIO_CTRL,
+ REG_GPIO_CTRL1,
+ REG_GPIO_CTRL2,
+ REG_GPIO_CTRL3
+};
+
+static const u32 irq_status_regs[] = {
+ REG_GPIO_INT,
+ REG_GPIO_INT1
+};
+
+static const u32 irq_level_regs[] = {
+ REG_GPIO_INT_LEVEL,
+ REG_GPIO_INT_LEVEL1,
+ REG_GPIO_INT_LEVEL2,
+ REG_GPIO_INT_LEVEL3
+};
+
+static const u32 irq_edge_regs[] = {
+ REG_GPIO_INT_EDGE,
+ REG_GPIO_INT_EDGE1,
+ REG_GPIO_INT_EDGE2,
+ REG_GPIO_INT_EDGE3
+};
+
+struct airoha_pinctrl_reg {
+ u32 offset;
+ u32 mask;
+};
+
+enum airoha_pinctrl_mux_func {
+ AIROHA_FUNC_MUX,
+ AIROHA_FUNC_PWM_MUX,
+ AIROHA_FUNC_PWM_EXT_MUX,
+};
+
+struct airoha_pinctrl_func_group {
+ const char *name;
+ struct {
+ enum airoha_pinctrl_mux_func mux;
+ u32 offset;
+ u32 mask;
+ u32 val;
+ } regmap[2];
+ int regmap_size;
+};
+
+struct airoha_pinctrl_func {
+ const struct function_desc desc;
+ const struct airoha_pinctrl_func_group *groups;
+ u8 group_size;
+};
+
+struct airoha_pinctrl_conf {
+ u32 pin;
+ struct airoha_pinctrl_reg reg;
+};
+
+struct airoha_pinctrl_gpiochip {
+ struct gpio_chip chip;
+
+ /* gpio */
+ const u32 *data;
+ const u32 *dir;
+ const u32 *out;
+ /* irq */
+ const u32 *status;
+ const u32 *level;
+ const u32 *edge;
+
+ u32 irq_type[AIROHA_NUM_GPIOS];
+};
+
+struct airoha_pinctrl {
+ struct pinctrl_dev *ctrl;
+
+ struct regmap *chip_scu;
+
+ /* protect concurrent register accesses */
+ spinlock_t lock;
+ struct regmap *regmap;
+
+ struct airoha_pinctrl_gpiochip gpiochip;
+};
+
+static struct pinctrl_pin_desc airoha_pinctrl_pins[] = {
+ PINCTRL_PIN(0, "uart1_txd"),
+ PINCTRL_PIN(1, "uart1_rxd"),
+ PINCTRL_PIN(2, "i2c_scl"),
+ PINCTRL_PIN(3, "i2c_sda"),
+ PINCTRL_PIN(4, "spi_cs0"),
+ PINCTRL_PIN(5, "spi_clk"),
+ PINCTRL_PIN(6, "spi_mosi"),
+ PINCTRL_PIN(7, "spi_miso"),
+ PINCTRL_PIN(13, "gpio0"),
+ PINCTRL_PIN(14, "gpio1"),
+ PINCTRL_PIN(15, "gpio2"),
+ PINCTRL_PIN(16, "gpio3"),
+ PINCTRL_PIN(17, "gpio4"),
+ PINCTRL_PIN(18, "gpio5"),
+ PINCTRL_PIN(19, "gpio6"),
+ PINCTRL_PIN(20, "gpio7"),
+ PINCTRL_PIN(21, "gpio8"),
+ PINCTRL_PIN(22, "gpio9"),
+ PINCTRL_PIN(23, "gpio10"),
+ PINCTRL_PIN(24, "gpio11"),
+ PINCTRL_PIN(25, "gpio12"),
+ PINCTRL_PIN(26, "gpio13"),
+ PINCTRL_PIN(27, "gpio14"),
+ PINCTRL_PIN(28, "gpio15"),
+ PINCTRL_PIN(29, "gpio16"),
+ PINCTRL_PIN(30, "gpio17"),
+ PINCTRL_PIN(31, "gpio18"),
+ PINCTRL_PIN(32, "gpio19"),
+ PINCTRL_PIN(33, "gpio20"),
+ PINCTRL_PIN(34, "gpio21"),
+ PINCTRL_PIN(35, "gpio22"),
+ PINCTRL_PIN(36, "gpio23"),
+ PINCTRL_PIN(37, "gpio24"),
+ PINCTRL_PIN(38, "gpio25"),
+ PINCTRL_PIN(39, "gpio26"),
+ PINCTRL_PIN(40, "gpio27"),
+ PINCTRL_PIN(41, "gpio28"),
+ PINCTRL_PIN(42, "gpio29"),
+ PINCTRL_PIN(43, "gpio30"),
+ PINCTRL_PIN(44, "gpio31"),
+ PINCTRL_PIN(45, "gpio32"),
+ PINCTRL_PIN(46, "gpio33"),
+ PINCTRL_PIN(47, "gpio34"),
+ PINCTRL_PIN(48, "gpio35"),
+ PINCTRL_PIN(49, "gpio36"),
+ PINCTRL_PIN(50, "gpio37"),
+ PINCTRL_PIN(51, "gpio38"),
+ PINCTRL_PIN(52, "gpio39"),
+ PINCTRL_PIN(53, "gpio40"),
+ PINCTRL_PIN(54, "gpio41"),
+ PINCTRL_PIN(55, "gpio42"),
+ PINCTRL_PIN(56, "gpio43"),
+ PINCTRL_PIN(57, "gpio44"),
+ PINCTRL_PIN(58, "gpio45"),
+ PINCTRL_PIN(59, "gpio46"),
+ PINCTRL_PIN(61, "pcie_reset0"),
+ PINCTRL_PIN(62, "pcie_reset1"),
+ PINCTRL_PIN(63, "pcie_reset2"),
+};
+
+static const int pon_pins[] = { 49, 50, 51, 52, 53, 54 };
+static const int pon_tod_1pps_pins[] = { 46 };
+static const int gsw_tod_1pps_pins[] = { 46 };
+static const int sipo_pins[] = { 16, 17 };
+static const int sipo_rclk_pins[] = { 16, 17, 43 };
+static const int mdio_pins[] = { 14, 15 };
+static const int uart2_pins[] = { 48, 55 };
+static const int uart2_cts_rts_pins[] = { 46, 47 };
+static const int hsuart_pins[] = { 28, 29 };
+static const int hsuart_cts_rts_pins[] = { 26, 27 };
+static const int uart4_pins[] = { 38, 39 };
+static const int uart5_pins[] = { 18, 19 };
+static const int i2c0_pins[] = { 2, 3 };
+static const int i2c1_pins[] = { 14, 15 };
+static const int jtag_udi_pins[] = { 16, 17, 18, 19, 20 };
+static const int jtag_dfd_pins[] = { 16, 17, 18, 19, 20 };
+static const int i2s_pins[] = { 26, 27, 28, 29 };
+static const int pcm1_pins[] = { 22, 23, 24, 25 };
+static const int pcm2_pins[] = { 18, 19, 20, 21 };
+static const int spi_quad_pins[] = { 32, 33 };
+static const int spi_pins[] = { 4, 5, 6, 7 };
+static const int spi_cs1_pins[] = { 34 };
+static const int pcm_spi_pins[] = { 18, 19, 20, 21, 22, 23, 24, 25 };
+static const int pcm_spi_int_pins[] = { 14 };
+static const int pcm_spi_rst_pins[] = { 15 };
+static const int pcm_spi_cs1_pins[] = { 43 };
+static const int pcm_spi_cs2_pins[] = { 40 };
+static const int pcm_spi_cs2_p128_pins[] = { 40 };
+static const int pcm_spi_cs2_p156_pins[] = { 40 };
+static const int pcm_spi_cs3_pins[] = { 41 };
+static const int pcm_spi_cs4_pins[] = { 42 };
+static const int emmc_pins[] = { 4, 5, 6, 30, 31, 32, 33, 34, 35, 36, 37 };
+static const int pnand_pins[] = { 4, 5, 6, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 };
+static const int gpio0_pins[] = { 13 };
+static const int gpio1_pins[] = { 14 };
+static const int gpio2_pins[] = { 15 };
+static const int gpio3_pins[] = { 16 };
+static const int gpio4_pins[] = { 17 };
+static const int gpio5_pins[] = { 18 };
+static const int gpio6_pins[] = { 19 };
+static const int gpio7_pins[] = { 20 };
+static const int gpio8_pins[] = { 21 };
+static const int gpio9_pins[] = { 22 };
+static const int gpio10_pins[] = { 23 };
+static const int gpio11_pins[] = { 24 };
+static const int gpio12_pins[] = { 25 };
+static const int gpio13_pins[] = { 26 };
+static const int gpio14_pins[] = { 27 };
+static const int gpio15_pins[] = { 28 };
+static const int gpio16_pins[] = { 29 };
+static const int gpio17_pins[] = { 30 };
+static const int gpio18_pins[] = { 31 };
+static const int gpio19_pins[] = { 32 };
+static const int gpio20_pins[] = { 33 };
+static const int gpio21_pins[] = { 34 };
+static const int gpio22_pins[] = { 35 };
+static const int gpio23_pins[] = { 36 };
+static const int gpio24_pins[] = { 37 };
+static const int gpio25_pins[] = { 38 };
+static const int gpio26_pins[] = { 39 };
+static const int gpio27_pins[] = { 40 };
+static const int gpio28_pins[] = { 41 };
+static const int gpio29_pins[] = { 42 };
+static const int gpio30_pins[] = { 43 };
+static const int gpio31_pins[] = { 44 };
+static const int gpio33_pins[] = { 46 };
+static const int gpio34_pins[] = { 47 };
+static const int gpio35_pins[] = { 48 };
+static const int gpio36_pins[] = { 49 };
+static const int gpio37_pins[] = { 50 };
+static const int gpio38_pins[] = { 51 };
+static const int gpio39_pins[] = { 52 };
+static const int gpio40_pins[] = { 53 };
+static const int gpio41_pins[] = { 54 };
+static const int gpio42_pins[] = { 55 };
+static const int gpio43_pins[] = { 56 };
+static const int gpio44_pins[] = { 57 };
+static const int gpio45_pins[] = { 58 };
+static const int gpio46_pins[] = { 59 };
+static const int pcie_reset0_pins[] = { 61 };
+static const int pcie_reset1_pins[] = { 62 };
+static const int pcie_reset2_pins[] = { 63 };
+
+static const struct pingroup airoha_pinctrl_groups[] = {
+ PINCTRL_PIN_GROUP(pon),
+ PINCTRL_PIN_GROUP(pon_tod_1pps),
+ PINCTRL_PIN_GROUP(gsw_tod_1pps),
+ PINCTRL_PIN_GROUP(sipo),
+ PINCTRL_PIN_GROUP(sipo_rclk),
+ PINCTRL_PIN_GROUP(mdio),
+ PINCTRL_PIN_GROUP(uart2),
+ PINCTRL_PIN_GROUP(uart2_cts_rts),
+ PINCTRL_PIN_GROUP(hsuart),
+ PINCTRL_PIN_GROUP(hsuart_cts_rts),
+ PINCTRL_PIN_GROUP(uart4),
+ PINCTRL_PIN_GROUP(uart5),
+ PINCTRL_PIN_GROUP(i2c0),
+ PINCTRL_PIN_GROUP(i2c1),
+ PINCTRL_PIN_GROUP(jtag_udi),
+ PINCTRL_PIN_GROUP(jtag_dfd),
+ PINCTRL_PIN_GROUP(i2s),
+ PINCTRL_PIN_GROUP(pcm1),
+ PINCTRL_PIN_GROUP(pcm2),
+ PINCTRL_PIN_GROUP(spi),
+ PINCTRL_PIN_GROUP(spi_quad),
+ PINCTRL_PIN_GROUP(spi_cs1),
+ PINCTRL_PIN_GROUP(pcm_spi),
+ PINCTRL_PIN_GROUP(pcm_spi_int),
+ PINCTRL_PIN_GROUP(pcm_spi_rst),
+ PINCTRL_PIN_GROUP(pcm_spi_cs1),
+ PINCTRL_PIN_GROUP(pcm_spi_cs2_p128),
+ PINCTRL_PIN_GROUP(pcm_spi_cs2_p156),
+ PINCTRL_PIN_GROUP(pcm_spi_cs2),
+ PINCTRL_PIN_GROUP(pcm_spi_cs3),
+ PINCTRL_PIN_GROUP(pcm_spi_cs4),
+ PINCTRL_PIN_GROUP(emmc),
+ PINCTRL_PIN_GROUP(pnand),
+ PINCTRL_PIN_GROUP(gpio0),
+ PINCTRL_PIN_GROUP(gpio1),
+ PINCTRL_PIN_GROUP(gpio2),
+ PINCTRL_PIN_GROUP(gpio3),
+ PINCTRL_PIN_GROUP(gpio4),
+ PINCTRL_PIN_GROUP(gpio5),
+ PINCTRL_PIN_GROUP(gpio6),
+ PINCTRL_PIN_GROUP(gpio7),
+ PINCTRL_PIN_GROUP(gpio8),
+ PINCTRL_PIN_GROUP(gpio9),
+ PINCTRL_PIN_GROUP(gpio10),
+ PINCTRL_PIN_GROUP(gpio11),
+ PINCTRL_PIN_GROUP(gpio12),
+ PINCTRL_PIN_GROUP(gpio13),
+ PINCTRL_PIN_GROUP(gpio14),
+ PINCTRL_PIN_GROUP(gpio15),
+ PINCTRL_PIN_GROUP(gpio16),
+ PINCTRL_PIN_GROUP(gpio17),
+ PINCTRL_PIN_GROUP(gpio18),
+ PINCTRL_PIN_GROUP(gpio19),
+ PINCTRL_PIN_GROUP(gpio20),
+ PINCTRL_PIN_GROUP(gpio21),
+ PINCTRL_PIN_GROUP(gpio22),
+ PINCTRL_PIN_GROUP(gpio23),
+ PINCTRL_PIN_GROUP(gpio24),
+ PINCTRL_PIN_GROUP(gpio25),
+ PINCTRL_PIN_GROUP(gpio26),
+ PINCTRL_PIN_GROUP(gpio27),
+ PINCTRL_PIN_GROUP(gpio28),
+ PINCTRL_PIN_GROUP(gpio29),
+ PINCTRL_PIN_GROUP(gpio30),
+ PINCTRL_PIN_GROUP(gpio31),
+ PINCTRL_PIN_GROUP(gpio33),
+ PINCTRL_PIN_GROUP(gpio34),
+ PINCTRL_PIN_GROUP(gpio35),
+ PINCTRL_PIN_GROUP(gpio36),
+ PINCTRL_PIN_GROUP(gpio37),
+ PINCTRL_PIN_GROUP(gpio38),
+ PINCTRL_PIN_GROUP(gpio39),
+ PINCTRL_PIN_GROUP(gpio40),
+ PINCTRL_PIN_GROUP(gpio41),
+ PINCTRL_PIN_GROUP(gpio42),
+ PINCTRL_PIN_GROUP(gpio43),
+ PINCTRL_PIN_GROUP(gpio44),
+ PINCTRL_PIN_GROUP(gpio45),
+ PINCTRL_PIN_GROUP(gpio46),
+ PINCTRL_PIN_GROUP(pcie_reset0),
+ PINCTRL_PIN_GROUP(pcie_reset1),
+ PINCTRL_PIN_GROUP(pcie_reset2),
+};
+
+static const char *const pon_groups[] = { "pon" };
+static const char *const tod_1pps_groups[] = { "pon_tod_1pps", "gsw_tod_1pps" };
+static const char *const sipo_groups[] = { "sipo", "sipo_rclk" };
+static const char *const mdio_groups[] = { "mdio" };
+static const char *const uart_groups[] = { "uart2", "uart2_cts_rts", "hsuart",
+ "hsuart_cts_rts", "uart4",
+ "uart5" };
+static const char *const i2c_groups[] = { "i2c1" };
+static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" };
+static const char *const pcm_groups[] = { "pcm1", "pcm2" };
+static const char *const spi_groups[] = { "spi_quad", "spi_cs1" };
+static const char *const pcm_spi_groups[] = { "pcm_spi", "pcm_spi_int",
+ "pcm_spi_rst", "pcm_spi_cs1",
+ "pcm_spi_cs2_p156",
+ "pcm_spi_cs2_p128",
+ "pcm_spi_cs3", "pcm_spi_cs4" };
+static const char *const i2s_groups[] = { "i2s" };
+static const char *const emmc_groups[] = { "emmc" };
+static const char *const pnand_groups[] = { "pnand" };
+static const char *const pcie_reset_groups[] = { "pcie_reset0", "pcie_reset1",
+ "pcie_reset2" };
+static const char *const pwm_groups[] = { "gpio0", "gpio1",
+ "gpio2", "gpio3",
+ "gpio4", "gpio5",
+ "gpio6", "gpio7",
+ "gpio8", "gpio9",
+ "gpio10", "gpio11",
+ "gpio12", "gpio13",
+ "gpio14", "gpio15",
+ "gpio16", "gpio17",
+ "gpio18", "gpio19",
+ "gpio20", "gpio21",
+ "gpio22", "gpio23",
+ "gpio24", "gpio25",
+ "gpio26", "gpio27",
+ "gpio28", "gpio29",
+ "gpio30", "gpio31",
+ "gpio36", "gpio37",
+ "gpio38", "gpio39",
+ "gpio40", "gpio41",
+ "gpio42", "gpio43",
+ "gpio44", "gpio45",
+ "gpio46", "gpio47" };
+static const char *const phy1_led0_groups[] = { "gpio33", "gpio34",
+ "gpio35", "gpio42" };
+static const char *const phy2_led0_groups[] = { "gpio33", "gpio34",
+ "gpio35", "gpio42" };
+static const char *const phy3_led0_groups[] = { "gpio33", "gpio34",
+ "gpio35", "gpio42" };
+static const char *const phy4_led0_groups[] = { "gpio33", "gpio34",
+ "gpio35", "gpio42" };
+static const char *const phy1_led1_groups[] = { "gpio43", "gpio44",
+ "gpio45", "gpio46" };
+static const char *const phy2_led1_groups[] = { "gpio43", "gpio44",
+ "gpio45", "gpio46" };
+static const char *const phy3_led1_groups[] = { "gpio43", "gpio44",
+ "gpio45", "gpio46" };
+static const char *const phy4_led1_groups[] = { "gpio43", "gpio44",
+ "gpio45", "gpio46" };
+
+static const struct airoha_pinctrl_func_group pon_func_group[] = {
+ {
+ .name = "pon",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_PON_MODE_MASK,
+ GPIO_PON_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
+ {
+ .name = "pon_tod_1pps",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ PON_TOD_1PPS_MODE_MASK,
+ PON_TOD_1PPS_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gsw_tod_1pps",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GSW_TOD_1PPS_MODE_MASK,
+ GSW_TOD_1PPS_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group sipo_func_group[] = {
+ {
+ .name = "sipo",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
+ GPIO_SIPO_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "sipo_rclk",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
+ GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group mdio_func_group[] = {
+ {
+ .name = "mdio",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_SGMII_MDIO_MODE_MASK,
+ GPIO_SGMII_MDIO_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_MDC_IO_MASTER_MODE_MODE,
+ GPIO_MDC_IO_MASTER_MODE_MODE
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group uart_func_group[] = {
+ {
+ .name = "uart2",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_UART2_MODE_MASK,
+ GPIO_UART2_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "uart2_cts_rts",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK,
+ GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "hsuart",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
+ GPIO_HSUART_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+ {
+ .name = "hsuart_cts_rts",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
+ GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "uart4",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_UART4_MODE_MASK,
+ GPIO_UART4_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "uart5",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_UART5_MODE_MASK,
+ GPIO_UART5_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group i2c_func_group[] = {
+ {
+ .name = "i2c1",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_2ND_I2C_MODE_MASK,
+ GPIO_2ND_I2C_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group jtag_func_group[] = {
+ {
+ .name = "jtag_udi",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_NPU_UART_EN,
+ JTAG_UDI_EN_MASK,
+ JTAG_UDI_EN_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "jtag_dfd",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_NPU_UART_EN,
+ JTAG_DFD_EN_MASK,
+ JTAG_DFD_EN_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group pcm_func_group[] = {
+ {
+ .name = "pcm1",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM1_MODE_MASK,
+ GPIO_PCM1_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm2",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM2_MODE_MASK,
+ GPIO_PCM2_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group spi_func_group[] = {
+ {
+ .name = "spi_quad",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_SPI_QUAD_MODE_MASK,
+ GPIO_SPI_QUAD_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "spi_cs1",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_SPI_CS1_MODE_MASK,
+ GPIO_SPI_CS1_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "spi_cs2",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_SPI_CS2_MODE_MASK,
+ GPIO_SPI_CS2_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "spi_cs3",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_SPI_CS3_MODE_MASK,
+ GPIO_SPI_CS3_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "spi_cs4",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_SPI_CS4_MODE_MASK,
+ GPIO_SPI_CS4_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
+ {
+ .name = "pcm_spi",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_MODE_MASK,
+ GPIO_PCM_SPI_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_int",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_INT_MODE_MASK,
+ GPIO_PCM_INT_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_rst",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_RESET_MODE_MASK,
+ GPIO_PCM_RESET_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_cs1",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_CS1_MODE_MASK,
+ GPIO_PCM_SPI_CS1_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_cs2_p128",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_CS2_MODE_P128_MASK,
+ GPIO_PCM_SPI_CS2_MODE_P128_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_cs2_p156",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_CS2_MODE_P156_MASK,
+ GPIO_PCM_SPI_CS2_MODE_P156_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_cs3",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_CS3_MODE_MASK,
+ GPIO_PCM_SPI_CS3_MODE_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcm_spi_cs4",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_SPI_CS1_MODE,
+ GPIO_PCM_SPI_CS4_MODE_MASK,
+ GPIO_PCM_SPI_CS4_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group i2s_func_group[] = {
+ {
+ .name = "i2s",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_I2S_MODE_MASK,
+ GPIO_I2S_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group emmc_func_group[] = {
+ {
+ .name = "emmc",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_EMMC_MODE_MASK,
+ GPIO_EMMC_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group pnand_func_group[] = {
+ {
+ .name = "pnand",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_PARALLEL_NAND_MODE_MASK,
+ GPIO_PARALLEL_NAND_MODE_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
+ {
+ .name = "pcie_reset0",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_PCIE_RESET0_MASK,
+ GPIO_PCIE_RESET0_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcie_reset1",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_PCIE_RESET1_MASK,
+ GPIO_PCIE_RESET1_MASK
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "pcie_reset2",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_PON_MODE,
+ GPIO_PCIE_RESET2_MASK,
+ GPIO_PCIE_RESET2_MASK
+ },
+ .regmap_size = 1,
+ },
+};
+
+/* PWM */
+static const struct airoha_pinctrl_func_group pwm_func_group[] = {
+ {
+ .name = "gpio0",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO0_FLASH_MODE_CFG,
+ GPIO0_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio1",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO1_FLASH_MODE_CFG,
+ GPIO1_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio2",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO2_FLASH_MODE_CFG,
+ GPIO2_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio3",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO3_FLASH_MODE_CFG,
+ GPIO3_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio4",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO4_FLASH_MODE_CFG,
+ GPIO4_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio5",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO5_FLASH_MODE_CFG,
+ GPIO5_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio6",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO6_FLASH_MODE_CFG,
+ GPIO6_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio7",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO7_FLASH_MODE_CFG,
+ GPIO7_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio8",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO8_FLASH_MODE_CFG,
+ GPIO8_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio9",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO9_FLASH_MODE_CFG,
+ GPIO9_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio10",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO10_FLASH_MODE_CFG,
+ GPIO10_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio11",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO11_FLASH_MODE_CFG,
+ GPIO11_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio12",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO12_FLASH_MODE_CFG,
+ GPIO12_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio13",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO13_FLASH_MODE_CFG,
+ GPIO13_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio14",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO14_FLASH_MODE_CFG,
+ GPIO14_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio15",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_MUX,
+ REG_GPIO_FLASH_MODE_CFG,
+ GPIO15_FLASH_MODE_CFG,
+ GPIO15_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio16",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO16_FLASH_MODE_CFG,
+ GPIO16_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio17",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO17_FLASH_MODE_CFG,
+ GPIO17_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio18",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO18_FLASH_MODE_CFG,
+ GPIO18_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio19",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO19_FLASH_MODE_CFG,
+ GPIO19_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio20",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO20_FLASH_MODE_CFG,
+ GPIO20_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio21",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO21_FLASH_MODE_CFG,
+ GPIO21_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio22",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO22_FLASH_MODE_CFG,
+ GPIO22_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio23",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO23_FLASH_MODE_CFG,
+ GPIO23_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio24",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO24_FLASH_MODE_CFG,
+ GPIO24_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio25",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO25_FLASH_MODE_CFG,
+ GPIO25_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio26",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO26_FLASH_MODE_CFG,
+ GPIO26_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio27",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO27_FLASH_MODE_CFG,
+ GPIO27_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio28",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO28_FLASH_MODE_CFG,
+ GPIO28_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio29",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO29_FLASH_MODE_CFG,
+ GPIO29_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio30",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO30_FLASH_MODE_CFG,
+ GPIO30_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio31",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO31_FLASH_MODE_CFG,
+ GPIO31_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio36",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO36_FLASH_MODE_CFG,
+ GPIO36_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio37",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO37_FLASH_MODE_CFG,
+ GPIO37_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio38",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO38_FLASH_MODE_CFG,
+ GPIO38_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio39",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO39_FLASH_MODE_CFG,
+ GPIO39_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio40",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO40_FLASH_MODE_CFG,
+ GPIO40_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio41",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO41_FLASH_MODE_CFG,
+ GPIO41_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio42",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO42_FLASH_MODE_CFG,
+ GPIO42_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio43",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO43_FLASH_MODE_CFG,
+ GPIO43_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio44",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO44_FLASH_MODE_CFG,
+ GPIO44_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio45",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO45_FLASH_MODE_CFG,
+ GPIO45_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio46",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO46_FLASH_MODE_CFG,
+ GPIO46_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ }, {
+ .name = "gpio47",
+ .regmap[0] = {
+ AIROHA_FUNC_PWM_EXT_MUX,
+ REG_GPIO_FLASH_MODE_CFG_EXT,
+ GPIO47_FLASH_MODE_CFG,
+ GPIO47_FLASH_MODE_CFG
+ },
+ .regmap_size = 1,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = {
+ {
+ .name = "gpio33",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED0_MODE_MASK,
+ GPIO_LAN0_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio34",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED0_MODE_MASK,
+ GPIO_LAN1_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio35",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED0_MODE_MASK,
+ GPIO_LAN2_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio42",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = {
+ {
+ .name = "gpio33",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED0_MODE_MASK,
+ GPIO_LAN0_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio34",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED0_MODE_MASK,
+ GPIO_LAN1_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio35",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED0_MODE_MASK,
+ GPIO_LAN2_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio42",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = {
+ {
+ .name = "gpio33",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED0_MODE_MASK,
+ GPIO_LAN0_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio34",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED0_MODE_MASK,
+ GPIO_LAN1_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio35",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED0_MODE_MASK,
+ GPIO_LAN2_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio42",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = {
+ {
+ .name = "gpio33",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED0_MODE_MASK,
+ GPIO_LAN0_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio34",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED0_MODE_MASK,
+ GPIO_LAN1_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio35",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED0_MODE_MASK,
+ GPIO_LAN2_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio42",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED0_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = {
+ {
+ .name = "gpio43",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED1_MODE_MASK,
+ GPIO_LAN0_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio44",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED1_MODE_MASK,
+ GPIO_LAN1_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio45",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED1_MODE_MASK,
+ GPIO_LAN2_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio46",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY1_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = {
+ {
+ .name = "gpio43",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED1_MODE_MASK,
+ GPIO_LAN0_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio44",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED1_MODE_MASK,
+ GPIO_LAN1_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio45",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED1_MODE_MASK,
+ GPIO_LAN2_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio46",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY2_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = {
+ {
+ .name = "gpio43",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED1_MODE_MASK,
+ GPIO_LAN0_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio44",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED1_MODE_MASK,
+ GPIO_LAN1_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio45",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED1_MODE_MASK,
+ GPIO_LAN2_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio46",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY3_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = {
+ {
+ .name = "gpio43",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN0_LED1_MODE_MASK,
+ GPIO_LAN0_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN1_LED_MAPPING_MASK,
+ LAN1_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio44",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN1_LED1_MODE_MASK,
+ GPIO_LAN1_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN2_LED_MAPPING_MASK,
+ LAN2_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio45",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN2_LED1_MODE_MASK,
+ GPIO_LAN2_LED1_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN3_LED_MAPPING_MASK,
+ LAN3_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ }, {
+ .name = "gpio46",
+ .regmap[0] = {
+ AIROHA_FUNC_MUX,
+ REG_GPIO_2ND_I2C_MODE,
+ GPIO_LAN3_LED0_MODE_MASK,
+ GPIO_LAN3_LED0_MODE_MASK
+ },
+ .regmap[1] = {
+ AIROHA_FUNC_MUX,
+ REG_LAN_LED1_MAPPING,
+ LAN4_LED_MAPPING_MASK,
+ LAN4_PHY4_LED_MAP
+ },
+ .regmap_size = 2,
+ },
+};
+
+static const struct airoha_pinctrl_func airoha_pinctrl_funcs[] = {
+ PINCTRL_FUNC_DESC(pon),
+ PINCTRL_FUNC_DESC(tod_1pps),
+ PINCTRL_FUNC_DESC(sipo),
+ PINCTRL_FUNC_DESC(mdio),
+ PINCTRL_FUNC_DESC(uart),
+ PINCTRL_FUNC_DESC(i2c),
+ PINCTRL_FUNC_DESC(jtag),
+ PINCTRL_FUNC_DESC(pcm),
+ PINCTRL_FUNC_DESC(spi),
+ PINCTRL_FUNC_DESC(pcm_spi),
+ PINCTRL_FUNC_DESC(i2s),
+ PINCTRL_FUNC_DESC(emmc),
+ PINCTRL_FUNC_DESC(pnand),
+ PINCTRL_FUNC_DESC(pcie_reset),
+ PINCTRL_FUNC_DESC(pwm),
+ PINCTRL_FUNC_DESC(phy1_led0),
+ PINCTRL_FUNC_DESC(phy2_led0),
+ PINCTRL_FUNC_DESC(phy3_led0),
+ PINCTRL_FUNC_DESC(phy4_led0),
+ PINCTRL_FUNC_DESC(phy1_led1),
+ PINCTRL_FUNC_DESC(phy2_led1),
+ PINCTRL_FUNC_DESC(phy3_led1),
+ PINCTRL_FUNC_DESC(phy4_led1),
+};
+
+static const struct airoha_pinctrl_conf airoha_pinctrl_pullup_conf[] = {
+ PINCTRL_CONF_DESC(0, REG_I2C_SDA_PU, UART1_TXD_PU_MASK),
+ PINCTRL_CONF_DESC(1, REG_I2C_SDA_PU, UART1_RXD_PU_MASK),
+ PINCTRL_CONF_DESC(2, REG_I2C_SDA_PU, I2C_SDA_PU_MASK),
+ PINCTRL_CONF_DESC(3, REG_I2C_SDA_PU, I2C_SCL_PU_MASK),
+ PINCTRL_CONF_DESC(4, REG_I2C_SDA_PU, SPI_CS0_PU_MASK),
+ PINCTRL_CONF_DESC(5, REG_I2C_SDA_PU, SPI_CLK_PU_MASK),
+ PINCTRL_CONF_DESC(6, REG_I2C_SDA_PU, SPI_MOSI_PU_MASK),
+ PINCTRL_CONF_DESC(7, REG_I2C_SDA_PU, SPI_MISO_PU_MASK),
+ PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(0)),
+ PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(1)),
+ PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(2)),
+ PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(3)),
+ PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(4)),
+ PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(5)),
+ PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(6)),
+ PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(7)),
+ PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(8)),
+ PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(9)),
+ PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(10)),
+ PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(11)),
+ PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(12)),
+ PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(13)),
+ PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(14)),
+ PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(15)),
+ PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(16)),
+ PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(17)),
+ PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(18)),
+ PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(18)),
+ PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(20)),
+ PINCTRL_CONF_DESC(34, REG_GPIO_L_PU, BIT(21)),
+ PINCTRL_CONF_DESC(35, REG_GPIO_L_PU, BIT(22)),
+ PINCTRL_CONF_DESC(36, REG_GPIO_L_PU, BIT(23)),
+ PINCTRL_CONF_DESC(37, REG_GPIO_L_PU, BIT(24)),
+ PINCTRL_CONF_DESC(38, REG_GPIO_L_PU, BIT(25)),
+ PINCTRL_CONF_DESC(39, REG_GPIO_L_PU, BIT(26)),
+ PINCTRL_CONF_DESC(40, REG_GPIO_L_PU, BIT(27)),
+ PINCTRL_CONF_DESC(41, REG_GPIO_L_PU, BIT(28)),
+ PINCTRL_CONF_DESC(42, REG_GPIO_L_PU, BIT(29)),
+ PINCTRL_CONF_DESC(43, REG_GPIO_L_PU, BIT(30)),
+ PINCTRL_CONF_DESC(44, REG_GPIO_L_PU, BIT(31)),
+ PINCTRL_CONF_DESC(45, REG_GPIO_H_PU, BIT(0)),
+ PINCTRL_CONF_DESC(46, REG_GPIO_H_PU, BIT(1)),
+ PINCTRL_CONF_DESC(47, REG_GPIO_H_PU, BIT(2)),
+ PINCTRL_CONF_DESC(48, REG_GPIO_H_PU, BIT(3)),
+ PINCTRL_CONF_DESC(49, REG_GPIO_H_PU, BIT(4)),
+ PINCTRL_CONF_DESC(50, REG_GPIO_H_PU, BIT(5)),
+ PINCTRL_CONF_DESC(51, REG_GPIO_H_PU, BIT(6)),
+ PINCTRL_CONF_DESC(52, REG_GPIO_H_PU, BIT(7)),
+ PINCTRL_CONF_DESC(53, REG_GPIO_H_PU, BIT(8)),
+ PINCTRL_CONF_DESC(54, REG_GPIO_H_PU, BIT(9)),
+ PINCTRL_CONF_DESC(55, REG_GPIO_H_PU, BIT(10)),
+ PINCTRL_CONF_DESC(56, REG_GPIO_H_PU, BIT(11)),
+ PINCTRL_CONF_DESC(57, REG_GPIO_H_PU, BIT(12)),
+ PINCTRL_CONF_DESC(58, REG_GPIO_H_PU, BIT(13)),
+ PINCTRL_CONF_DESC(59, REG_GPIO_H_PU, BIT(14)),
+ PINCTRL_CONF_DESC(61, REG_I2C_SDA_PU, PCIE0_RESET_PU_MASK),
+ PINCTRL_CONF_DESC(62, REG_I2C_SDA_PU, PCIE1_RESET_PU_MASK),
+ PINCTRL_CONF_DESC(63, REG_I2C_SDA_PU, PCIE2_RESET_PU_MASK),
+};
+
+static const struct airoha_pinctrl_conf airoha_pinctrl_pulldown_conf[] = {
+ PINCTRL_CONF_DESC(0, REG_I2C_SDA_PD, UART1_TXD_PD_MASK),
+ PINCTRL_CONF_DESC(1, REG_I2C_SDA_PD, UART1_RXD_PD_MASK),
+ PINCTRL_CONF_DESC(2, REG_I2C_SDA_PD, I2C_SDA_PD_MASK),
+ PINCTRL_CONF_DESC(3, REG_I2C_SDA_PD, I2C_SCL_PD_MASK),
+ PINCTRL_CONF_DESC(4, REG_I2C_SDA_PD, SPI_CS0_PD_MASK),
+ PINCTRL_CONF_DESC(5, REG_I2C_SDA_PD, SPI_CLK_PD_MASK),
+ PINCTRL_CONF_DESC(6, REG_I2C_SDA_PD, SPI_MOSI_PD_MASK),
+ PINCTRL_CONF_DESC(7, REG_I2C_SDA_PD, SPI_MISO_PD_MASK),
+ PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(0)),
+ PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(1)),
+ PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(2)),
+ PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(3)),
+ PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(4)),
+ PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(5)),
+ PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(6)),
+ PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(7)),
+ PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(8)),
+ PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(9)),
+ PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(10)),
+ PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(11)),
+ PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(12)),
+ PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(13)),
+ PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(14)),
+ PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(15)),
+ PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(16)),
+ PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(17)),
+ PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(18)),
+ PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(18)),
+ PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(20)),
+ PINCTRL_CONF_DESC(34, REG_GPIO_L_PD, BIT(21)),
+ PINCTRL_CONF_DESC(35, REG_GPIO_L_PD, BIT(22)),
+ PINCTRL_CONF_DESC(36, REG_GPIO_L_PD, BIT(23)),
+ PINCTRL_CONF_DESC(37, REG_GPIO_L_PD, BIT(24)),
+ PINCTRL_CONF_DESC(38, REG_GPIO_L_PD, BIT(25)),
+ PINCTRL_CONF_DESC(39, REG_GPIO_L_PD, BIT(26)),
+ PINCTRL_CONF_DESC(40, REG_GPIO_L_PD, BIT(27)),
+ PINCTRL_CONF_DESC(41, REG_GPIO_L_PD, BIT(28)),
+ PINCTRL_CONF_DESC(42, REG_GPIO_L_PD, BIT(29)),
+ PINCTRL_CONF_DESC(43, REG_GPIO_L_PD, BIT(30)),
+ PINCTRL_CONF_DESC(44, REG_GPIO_L_PD, BIT(31)),
+ PINCTRL_CONF_DESC(45, REG_GPIO_H_PD, BIT(0)),
+ PINCTRL_CONF_DESC(46, REG_GPIO_H_PD, BIT(1)),
+ PINCTRL_CONF_DESC(47, REG_GPIO_H_PD, BIT(2)),
+ PINCTRL_CONF_DESC(48, REG_GPIO_H_PD, BIT(3)),
+ PINCTRL_CONF_DESC(49, REG_GPIO_H_PD, BIT(4)),
+ PINCTRL_CONF_DESC(50, REG_GPIO_H_PD, BIT(5)),
+ PINCTRL_CONF_DESC(51, REG_GPIO_H_PD, BIT(6)),
+ PINCTRL_CONF_DESC(52, REG_GPIO_H_PD, BIT(7)),
+ PINCTRL_CONF_DESC(53, REG_GPIO_H_PD, BIT(8)),
+ PINCTRL_CONF_DESC(54, REG_GPIO_H_PD, BIT(9)),
+ PINCTRL_CONF_DESC(55, REG_GPIO_H_PD, BIT(10)),
+ PINCTRL_CONF_DESC(56, REG_GPIO_H_PD, BIT(11)),
+ PINCTRL_CONF_DESC(57, REG_GPIO_H_PD, BIT(12)),
+ PINCTRL_CONF_DESC(58, REG_GPIO_H_PD, BIT(13)),
+ PINCTRL_CONF_DESC(59, REG_GPIO_H_PD, BIT(14)),
+ PINCTRL_CONF_DESC(61, REG_I2C_SDA_PD, PCIE0_RESET_PD_MASK),
+ PINCTRL_CONF_DESC(62, REG_I2C_SDA_PD, PCIE1_RESET_PD_MASK),
+ PINCTRL_CONF_DESC(63, REG_I2C_SDA_PD, PCIE2_RESET_PD_MASK),
+};
+
+static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e2_conf[] = {
+ PINCTRL_CONF_DESC(0, REG_I2C_SDA_E2, UART1_TXD_E2_MASK),
+ PINCTRL_CONF_DESC(1, REG_I2C_SDA_E2, UART1_RXD_E2_MASK),
+ PINCTRL_CONF_DESC(2, REG_I2C_SDA_E2, I2C_SDA_E2_MASK),
+ PINCTRL_CONF_DESC(3, REG_I2C_SDA_E2, I2C_SCL_E2_MASK),
+ PINCTRL_CONF_DESC(4, REG_I2C_SDA_E2, SPI_CS0_E2_MASK),
+ PINCTRL_CONF_DESC(5, REG_I2C_SDA_E2, SPI_CLK_E2_MASK),
+ PINCTRL_CONF_DESC(6, REG_I2C_SDA_E2, SPI_MOSI_E2_MASK),
+ PINCTRL_CONF_DESC(7, REG_I2C_SDA_E2, SPI_MISO_E2_MASK),
+ PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(0)),
+ PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(1)),
+ PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(2)),
+ PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(3)),
+ PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(4)),
+ PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(5)),
+ PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(6)),
+ PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(7)),
+ PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(8)),
+ PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(9)),
+ PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(10)),
+ PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(11)),
+ PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(12)),
+ PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(13)),
+ PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(14)),
+ PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(15)),
+ PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(16)),
+ PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(17)),
+ PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(18)),
+ PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(18)),
+ PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(20)),
+ PINCTRL_CONF_DESC(34, REG_GPIO_L_E2, BIT(21)),
+ PINCTRL_CONF_DESC(35, REG_GPIO_L_E2, BIT(22)),
+ PINCTRL_CONF_DESC(36, REG_GPIO_L_E2, BIT(23)),
+ PINCTRL_CONF_DESC(37, REG_GPIO_L_E2, BIT(24)),
+ PINCTRL_CONF_DESC(38, REG_GPIO_L_E2, BIT(25)),
+ PINCTRL_CONF_DESC(39, REG_GPIO_L_E2, BIT(26)),
+ PINCTRL_CONF_DESC(40, REG_GPIO_L_E2, BIT(27)),
+ PINCTRL_CONF_DESC(41, REG_GPIO_L_E2, BIT(28)),
+ PINCTRL_CONF_DESC(42, REG_GPIO_L_E2, BIT(29)),
+ PINCTRL_CONF_DESC(43, REG_GPIO_L_E2, BIT(30)),
+ PINCTRL_CONF_DESC(44, REG_GPIO_L_E2, BIT(31)),
+ PINCTRL_CONF_DESC(45, REG_GPIO_H_E2, BIT(0)),
+ PINCTRL_CONF_DESC(46, REG_GPIO_H_E2, BIT(1)),
+ PINCTRL_CONF_DESC(47, REG_GPIO_H_E2, BIT(2)),
+ PINCTRL_CONF_DESC(48, REG_GPIO_H_E2, BIT(3)),
+ PINCTRL_CONF_DESC(49, REG_GPIO_H_E2, BIT(4)),
+ PINCTRL_CONF_DESC(50, REG_GPIO_H_E2, BIT(5)),
+ PINCTRL_CONF_DESC(51, REG_GPIO_H_E2, BIT(6)),
+ PINCTRL_CONF_DESC(52, REG_GPIO_H_E2, BIT(7)),
+ PINCTRL_CONF_DESC(53, REG_GPIO_H_E2, BIT(8)),
+ PINCTRL_CONF_DESC(54, REG_GPIO_H_E2, BIT(9)),
+ PINCTRL_CONF_DESC(55, REG_GPIO_H_E2, BIT(10)),
+ PINCTRL_CONF_DESC(56, REG_GPIO_H_E2, BIT(11)),
+ PINCTRL_CONF_DESC(57, REG_GPIO_H_E2, BIT(12)),
+ PINCTRL_CONF_DESC(58, REG_GPIO_H_E2, BIT(13)),
+ PINCTRL_CONF_DESC(59, REG_GPIO_H_E2, BIT(14)),
+ PINCTRL_CONF_DESC(61, REG_I2C_SDA_E2, PCIE0_RESET_E2_MASK),
+ PINCTRL_CONF_DESC(62, REG_I2C_SDA_E2, PCIE1_RESET_E2_MASK),
+ PINCTRL_CONF_DESC(63, REG_I2C_SDA_E2, PCIE2_RESET_E2_MASK),
+};
+
+static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e4_conf[] = {
+ PINCTRL_CONF_DESC(0, REG_I2C_SDA_E4, UART1_TXD_E4_MASK),
+ PINCTRL_CONF_DESC(1, REG_I2C_SDA_E4, UART1_RXD_E4_MASK),
+ PINCTRL_CONF_DESC(2, REG_I2C_SDA_E4, I2C_SDA_E4_MASK),
+ PINCTRL_CONF_DESC(3, REG_I2C_SDA_E4, I2C_SCL_E4_MASK),
+ PINCTRL_CONF_DESC(4, REG_I2C_SDA_E4, SPI_CS0_E4_MASK),
+ PINCTRL_CONF_DESC(5, REG_I2C_SDA_E4, SPI_CLK_E4_MASK),
+ PINCTRL_CONF_DESC(6, REG_I2C_SDA_E4, SPI_MOSI_E4_MASK),
+ PINCTRL_CONF_DESC(7, REG_I2C_SDA_E4, SPI_MISO_E4_MASK),
+ PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(0)),
+ PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(1)),
+ PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(2)),
+ PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(3)),
+ PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(4)),
+ PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(5)),
+ PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(6)),
+ PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(7)),
+ PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(8)),
+ PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(9)),
+ PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(10)),
+ PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(11)),
+ PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(12)),
+ PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(13)),
+ PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(14)),
+ PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(15)),
+ PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(16)),
+ PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(17)),
+ PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(18)),
+ PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(18)),
+ PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(20)),
+ PINCTRL_CONF_DESC(34, REG_GPIO_L_E4, BIT(21)),
+ PINCTRL_CONF_DESC(35, REG_GPIO_L_E4, BIT(22)),
+ PINCTRL_CONF_DESC(36, REG_GPIO_L_E4, BIT(23)),
+ PINCTRL_CONF_DESC(37, REG_GPIO_L_E4, BIT(24)),
+ PINCTRL_CONF_DESC(38, REG_GPIO_L_E4, BIT(25)),
+ PINCTRL_CONF_DESC(39, REG_GPIO_L_E4, BIT(26)),
+ PINCTRL_CONF_DESC(40, REG_GPIO_L_E4, BIT(27)),
+ PINCTRL_CONF_DESC(41, REG_GPIO_L_E4, BIT(28)),
+ PINCTRL_CONF_DESC(42, REG_GPIO_L_E4, BIT(29)),
+ PINCTRL_CONF_DESC(43, REG_GPIO_L_E4, BIT(30)),
+ PINCTRL_CONF_DESC(44, REG_GPIO_L_E4, BIT(31)),
+ PINCTRL_CONF_DESC(45, REG_GPIO_H_E4, BIT(0)),
+ PINCTRL_CONF_DESC(46, REG_GPIO_H_E4, BIT(1)),
+ PINCTRL_CONF_DESC(47, REG_GPIO_H_E4, BIT(2)),
+ PINCTRL_CONF_DESC(48, REG_GPIO_H_E4, BIT(3)),
+ PINCTRL_CONF_DESC(49, REG_GPIO_H_E4, BIT(4)),
+ PINCTRL_CONF_DESC(50, REG_GPIO_H_E4, BIT(5)),
+ PINCTRL_CONF_DESC(51, REG_GPIO_H_E4, BIT(6)),
+ PINCTRL_CONF_DESC(52, REG_GPIO_H_E4, BIT(7)),
+ PINCTRL_CONF_DESC(53, REG_GPIO_H_E4, BIT(8)),
+ PINCTRL_CONF_DESC(54, REG_GPIO_H_E4, BIT(9)),
+ PINCTRL_CONF_DESC(55, REG_GPIO_H_E4, BIT(10)),
+ PINCTRL_CONF_DESC(56, REG_GPIO_H_E4, BIT(11)),
+ PINCTRL_CONF_DESC(57, REG_GPIO_H_E4, BIT(12)),
+ PINCTRL_CONF_DESC(58, REG_GPIO_H_E4, BIT(13)),
+ PINCTRL_CONF_DESC(59, REG_GPIO_H_E4, BIT(14)),
+ PINCTRL_CONF_DESC(61, REG_I2C_SDA_E4, PCIE0_RESET_E4_MASK),
+ PINCTRL_CONF_DESC(62, REG_I2C_SDA_E4, PCIE1_RESET_E4_MASK),
+ PINCTRL_CONF_DESC(63, REG_I2C_SDA_E4, PCIE2_RESET_E4_MASK),
+};
+
+static const struct airoha_pinctrl_conf airoha_pinctrl_pcie_rst_od_conf[] = {
+ PINCTRL_CONF_DESC(61, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK),
+ PINCTRL_CONF_DESC(62, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK),
+ PINCTRL_CONF_DESC(63, REG_PCIE_RESET_OD, PCIE2_RESET_OD_MASK),
+};
+
+static int airoha_convert_pin_to_gpio(struct pinctrl_dev *pctrl_dev,
+ struct pinctrl_gpio_range *range,
+ int pin)
+{
+ if (!range)
+ range = pinctrl_find_gpio_range_from_pin_nolock(pctrl_dev,
+ pin);
+ if (!range)
+ return -EINVAL;
+
+ return pin - range->pin_base;
+}
+
+/* gpio callbacks */
+static void airoha_gpio_set(struct gpio_chip *chip, unsigned int gpio,
+ int value)
+{
+ struct airoha_pinctrl *pinctrl = gpiochip_get_data(chip);
+ u32 offset = gpio % AIROHA_GPIO_BANK_SIZE;
+ u8 index = gpio / AIROHA_GPIO_BANK_SIZE;
+
+ guard(spinlock_irqsave)(&pinctrl->lock);
+ regmap_update_bits(pinctrl->regmap, pinctrl->gpiochip.data[index],
+ BIT(offset), value ? BIT(offset) : 0);
+}
+
+static int airoha_gpio_get(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct airoha_pinctrl *pinctrl = gpiochip_get_data(chip);
+ u32 val, pin = gpio % AIROHA_GPIO_BANK_SIZE;
+ u8 index = gpio / AIROHA_GPIO_BANK_SIZE;
+ int err;
+
+ err = regmap_read(pinctrl->regmap,
+ pinctrl->gpiochip.data[index], &val);
+
+ return err ? err : !!(val & BIT(pin));
+}
+
+static int airoha_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int gpio, int value)
+{
+ int err;
+
+ err = pinctrl_gpio_direction_output(chip, gpio);
+ if (err)
+ return err;
+
+ airoha_gpio_set(chip, gpio, value);
+
+ return 0;
+}
+
+/* irq callbacks */
+static void airoha_irq_unmask(struct irq_data *data)
+{
+ u8 offset = data->hwirq % AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ u32 mask = GENMASK(2 * offset + 1, 2 * offset);
+ struct airoha_pinctrl_gpiochip *gpiochip;
+ struct airoha_pinctrl *pinctrl;
+ u32 val = BIT(2 * offset);
+
+ gpiochip = irq_data_get_irq_chip_data(data);
+ if (WARN_ON_ONCE(data->hwirq >= ARRAY_SIZE(gpiochip->irq_type)))
+ return;
+
+ pinctrl = container_of(gpiochip, struct airoha_pinctrl, gpiochip);
+ guard(spinlock_irqsave)(&pinctrl->lock);
+
+ switch (gpiochip->irq_type[data->hwirq] & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_LEVEL_LOW:
+ val = val << 1;
+ fallthrough;
+ case IRQ_TYPE_LEVEL_HIGH:
+ regmap_update_bits(pinctrl->regmap, gpiochip->level[index],
+ mask, val);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ val = val << 1;
+ fallthrough;
+ case IRQ_TYPE_EDGE_RISING:
+ regmap_update_bits(pinctrl->regmap, gpiochip->edge[index],
+ mask, val);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ regmap_set_bits(pinctrl->regmap, gpiochip->edge[index], mask);
+ break;
+ default:
+ break;
+ }
+}
+
+static void airoha_irq_mask(struct irq_data *data)
+{
+ u8 offset = data->hwirq % AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ u32 mask = GENMASK(2 * offset + 1, 2 * offset);
+ struct airoha_pinctrl_gpiochip *gpiochip;
+ struct airoha_pinctrl *pinctrl;
+
+ gpiochip = irq_data_get_irq_chip_data(data);
+ pinctrl = container_of(gpiochip, struct airoha_pinctrl, gpiochip);
+
+ guard(spinlock_irqsave)(&pinctrl->lock);
+ regmap_clear_bits(pinctrl->regmap, gpiochip->level[index], mask);
+ regmap_clear_bits(pinctrl->regmap, gpiochip->edge[index], mask);
+}
+
+static int airoha_irq_type(struct irq_data *data, unsigned int type)
+{
+ struct airoha_pinctrl_gpiochip *gpiochip;
+ struct airoha_pinctrl *pinctrl;
+
+ gpiochip = irq_data_get_irq_chip_data(data);
+ if (data->hwirq >= ARRAY_SIZE(gpiochip->irq_type))
+ return -EINVAL;
+
+ pinctrl = container_of(gpiochip, struct airoha_pinctrl, gpiochip);
+ guard(spinlock_irqsave)(&pinctrl->lock);
+
+ if (type == IRQ_TYPE_PROBE) {
+ if (gpiochip->irq_type[data->hwirq])
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+ gpiochip->irq_type[data->hwirq] = type & IRQ_TYPE_SENSE_MASK;
+
+ return 0;
+}
+
+static irqreturn_t airoha_irq_handler(int irq, void *data)
+{
+ struct airoha_pinctrl *pinctrl = data;
+ bool handled = false;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
+ struct gpio_irq_chip *girq = &pinctrl->gpiochip.chip.irq;
+ u32 status;
+ int irq;
+
+ if (regmap_read(pinctrl->regmap, pinctrl->gpiochip.status[i],
+ &status))
+ continue;
+
+ for_each_set_bit(irq, (unsigned long *)&status,
+ AIROHA_GPIO_BANK_SIZE) {
+ u32 offset = irq + i * AIROHA_GPIO_BANK_SIZE;
+
+ generic_handle_irq(irq_find_mapping(girq->domain,
+ offset));
+ regmap_write(pinctrl->regmap,
+ pinctrl->gpiochip.status[i], BIT(irq));
+ }
+ handled |= !!status;
+ }
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct irq_chip airoha_gpio_irq_chip = {
+ .name = "airoha-gpio-irq",
+ .irq_unmask = airoha_irq_unmask,
+ .irq_mask = airoha_irq_mask,
+ .irq_mask_ack = airoha_irq_mask,
+ .irq_set_type = airoha_irq_type,
+ .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_IMMUTABLE,
+};
+
+static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
+ struct platform_device *pdev)
+{
+ struct gpio_chip *chip = &pinctrl->gpiochip.chip;
+ struct device *dev = &pdev->dev;
+ int irq, err;
+
+ pinctrl->gpiochip.data = gpio_data_regs;
+ pinctrl->gpiochip.dir = gpio_dir_regs;
+ pinctrl->gpiochip.out = gpio_out_regs;
+ pinctrl->gpiochip.status = irq_status_regs;
+ pinctrl->gpiochip.level = irq_level_regs;
+ pinctrl->gpiochip.edge = irq_edge_regs;
+
+ chip->parent = dev;
+ chip->label = dev_name(dev);
+ chip->request = gpiochip_generic_request;
+ chip->free = gpiochip_generic_free;
+ chip->direction_input = pinctrl_gpio_direction_input;
+ chip->direction_output = airoha_gpio_direction_output;
+ chip->set = airoha_gpio_set;
+ chip->get = airoha_gpio_get;
+ chip->base = -1;
+ chip->ngpio = AIROHA_NUM_GPIOS;
+
+ if (!of_property_read_bool(dev->of_node, "interrupt-controller"))
+ goto out;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(dev, irq, airoha_irq_handler, IRQF_SHARED,
+ dev_name(dev), pinctrl);
+ if (err) {
+ dev_err(dev, "error requesting irq %d: %d\n", irq, err);
+ return err;
+ }
+
+ gpio_irq_chip_set_chip(&chip->irq, &airoha_gpio_irq_chip);
+ chip->irq.default_type = IRQ_TYPE_NONE;
+ chip->irq.handler = handle_simple_irq;
+out:
+ return devm_gpiochip_add_data(dev, chip, pinctrl);
+}
+
+/* pinmux callbacks */
+static int airoha_pinmux_set_mux(struct pinctrl_dev *pctrl_dev,
+ unsigned int selector,
+ unsigned int group)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ const struct airoha_pinctrl_func *func;
+ struct function_desc *desc;
+ struct group_desc *grp;
+ int i;
+
+ desc = pinmux_generic_get_function(pctrl_dev, selector);
+ if (!desc)
+ return -EINVAL;
+
+ grp = pinctrl_generic_get_group(pctrl_dev, group);
+ if (!grp)
+ return -EINVAL;
+
+ dev_dbg(pctrl_dev->dev, "enable function %s group %s\n",
+ desc->func.name, grp->grp.name);
+
+ func = desc->data;
+ for (i = 0; i < func->group_size; i++) {
+ const struct airoha_pinctrl_func_group *group;
+ int j;
+
+ group = &func->groups[i];
+ if (strcmp(group->name, grp->grp.name))
+ continue;
+
+ for (j = 0; j < group->regmap_size; j++) {
+ switch (group->regmap[j].mux) {
+ case AIROHA_FUNC_PWM_EXT_MUX:
+ case AIROHA_FUNC_PWM_MUX:
+ scoped_guard(spinlock_irqsave, &pinctrl->lock) {
+ regmap_update_bits(pinctrl->regmap,
+ group->regmap[j].offset,
+ group->regmap[j].mask,
+ group->regmap[j].val);
+ }
+ break;
+ default:
+ regmap_update_bits(pinctrl->chip_scu,
+ group->regmap[j].offset,
+ group->regmap[j].mask,
+ group->regmap[j].val);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin, bool input)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ u32 mask, index;
+ int err, gpio;
+
+ /*
+ * Here we need to convert the pin into the respective gpio since out
+ * and direction hw registers are indexed using gpio value.
+ */
+ gpio = airoha_convert_pin_to_gpio(pctrl_dev, range, pin);
+ if (gpio < 0)
+ return gpio;
+
+ guard(spinlock_irqsave)(&pinctrl->lock);
+
+ /* set output enable */
+ mask = BIT(gpio % AIROHA_GPIO_BANK_SIZE);
+ index = gpio / AIROHA_GPIO_BANK_SIZE;
+ err = regmap_update_bits(pinctrl->regmap, pinctrl->gpiochip.out[index],
+ mask, !input ? mask : 0);
+ if (err)
+ return err;
+
+ /* set gpio direction */
+ mask = BIT(2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_GPIO));
+ index = gpio / AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ return regmap_update_bits(pinctrl->regmap,
+ pinctrl->gpiochip.dir[index], mask,
+ !input ? mask : 0);
+}
+
+static const struct pinmux_ops airoha_pmxops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .gpio_set_direction = airoha_pinmux_set_direction,
+ .set_mux = airoha_pinmux_set_mux,
+ .strict = true,
+};
+
+/* pinconf callbacks */
+static const struct airoha_pinctrl_reg *
+airoha_pinctrl_get_conf_reg(const struct airoha_pinctrl_conf *conf,
+ int conf_size, int pin)
+{
+ int i;
+
+ for (i = 0; i < conf_size; i++) {
+ if (conf[i].pin == pin)
+ return &conf[i].reg;
+ }
+
+ return NULL;
+}
+
+static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl,
+ const struct airoha_pinctrl_conf *conf,
+ int conf_size, int pin, u32 *val)
+{
+ const struct airoha_pinctrl_reg *reg;
+
+ reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin);
+ if (!reg)
+ return -EINVAL;
+
+ if (regmap_read(pinctrl->chip_scu, reg->offset, val))
+ return -EINVAL;
+
+ *val = (*val & reg->mask) >> __ffs(reg->mask);
+
+ return 0;
+}
+
+static int airoha_pinctrl_set_conf(struct airoha_pinctrl *pinctrl,
+ const struct airoha_pinctrl_conf *conf,
+ int conf_size, int pin, u32 val)
+{
+ const struct airoha_pinctrl_reg *reg = NULL;
+
+ reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin);
+ if (!reg)
+ return -EINVAL;
+
+
+ if (regmap_update_bits(pinctrl->chip_scu, reg->offset, reg->mask,
+ val << __ffs(reg->mask)))
+ return -EINVAL;
+
+ return 0;
+}
+
+#define airoha_pinctrl_get_pullup_conf(pinctrl, pin, val) \
+ airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pullup_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pullup_conf), \
+ (pin), (val))
+#define airoha_pinctrl_get_pulldown_conf(pinctrl, pin, val) \
+ airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pulldown_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \
+ (pin), (val))
+#define airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, val) \
+ airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \
+ ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \
+ (pin), (val))
+#define airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, val) \
+ airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \
+ ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \
+ (pin), (val))
+#define airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, val) \
+ airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \
+ (pin), (val))
+#define airoha_pinctrl_set_pullup_conf(pinctrl, pin, val) \
+ airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pullup_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pullup_conf), \
+ (pin), (val))
+#define airoha_pinctrl_set_pulldown_conf(pinctrl, pin, val) \
+ airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pulldown_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \
+ (pin), (val))
+#define airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, val) \
+ airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \
+ ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \
+ (pin), (val))
+#define airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, val) \
+ airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \
+ ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \
+ (pin), (val))
+#define airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, val) \
+ airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \
+ ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \
+ (pin), (val))
+
+static int airoha_pinconf_get_direction(struct pinctrl_dev *pctrl_dev, u32 pin)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ int err, gpio;
+ u32 val, mask;
+ u8 index;
+
+ /*
+ * Here we need to convert the pin into the respective gpio since
+ * direction hw registers are indexed using gpio value.
+ */
+ gpio = airoha_convert_pin_to_gpio(pctrl_dev, NULL, pin);
+ if (gpio < 0)
+ return gpio;
+
+ index = gpio / AIROHA_REG_GPIOCTRL_NUM_GPIO;
+ err = regmap_read(pinctrl->regmap, pinctrl->gpiochip.dir[index], &val);
+ if (err)
+ return err;
+
+ mask = BIT(2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_GPIO));
+ return val & mask ? PIN_CONFIG_OUTPUT_ENABLE : PIN_CONFIG_INPUT_ENABLE;
+}
+
+static int airoha_pinconf_get(struct pinctrl_dev *pctrl_dev,
+ unsigned int pin, unsigned long *config)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 arg;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP: {
+ u32 pull_up, pull_down;
+
+ if (airoha_pinctrl_get_pullup_conf(pinctrl, pin, &pull_up) ||
+ airoha_pinctrl_get_pulldown_conf(pinctrl, pin, &pull_down))
+ return -EINVAL;
+
+ if (param == PIN_CONFIG_BIAS_PULL_UP &&
+ !(pull_up && !pull_down))
+ return -EINVAL;
+ else if (param == PIN_CONFIG_BIAS_PULL_DOWN &&
+ !(pull_down && !pull_up))
+ return -EINVAL;
+ else if (pull_up || pull_down)
+ return -EINVAL;
+
+ arg = 1;
+ break;
+ }
+ case PIN_CONFIG_DRIVE_STRENGTH: {
+ u32 e2, e4;
+
+ if (airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, &e2) ||
+ airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, &e4))
+ return -EINVAL;
+
+ arg = e4 << 1 | e2;
+ break;
+ }
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ if (airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, &arg))
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = airoha_pinconf_get_direction(pctrl_dev, pin);
+ if (arg != param)
+ return -EINVAL;
+
+ arg = 1;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int airoha_pinconf_set_pin_value(struct pinctrl_dev *pctrl_dev,
+ unsigned int pin, bool value)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ int gpio;
+
+ /*
+ * Here we need to convert the pin into the respective gpio since
+ * data hw registers are indexed using gpio value.
+ */
+ gpio = airoha_convert_pin_to_gpio(pctrl_dev, NULL, pin);
+ if (gpio < 0)
+ return gpio;
+
+ airoha_gpio_set(&pinctrl->gpiochip.chip, gpio, value);
+
+ return 0;
+}
+
+static int airoha_pinconf_set(struct pinctrl_dev *pctrl_dev,
+ unsigned int pin, unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ int i;
+
+ for (i = 0; i < num_configs; i++) {
+ u32 param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0);
+ airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0);
+ airoha_pinctrl_set_pullup_conf(pinctrl, pin, 1);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 1);
+ airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH: {
+ u32 e2 = 0, e4 = 0;
+
+ switch (arg) {
+ case MTK_DRIVE_2mA:
+ break;
+ case MTK_DRIVE_4mA:
+ e2 = 1;
+ break;
+ case MTK_DRIVE_6mA:
+ e4 = 1;
+ break;
+ case MTK_DRIVE_8mA:
+ e2 = 1;
+ e4 = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, e2);
+ airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, e4);
+ break;
+ }
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, !!arg);
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ case PIN_CONFIG_INPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT: {
+ bool input = param == PIN_CONFIG_INPUT_ENABLE;
+ int err;
+
+ err = airoha_pinmux_set_direction(pctrl_dev, NULL, pin,
+ input);
+ if (err)
+ return err;
+
+ if (param == PIN_CONFIG_OUTPUT) {
+ err = airoha_pinconf_set_pin_value(pctrl_dev,
+ pin, !!arg);
+ if (err)
+ return err;
+ }
+ break;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int airoha_pinconf_group_get(struct pinctrl_dev *pctrl_dev,
+ unsigned int group, unsigned long *config)
+{
+ u32 cur_config = 0;
+ int i;
+
+ for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) {
+ if (airoha_pinconf_get(pctrl_dev,
+ airoha_pinctrl_groups[group].pins[i],
+ config))
+ return -EOPNOTSUPP;
+
+ if (i && cur_config != *config)
+ return -EOPNOTSUPP;
+
+ cur_config = *config;
+ }
+
+ return 0;
+}
+
+static int airoha_pinconf_group_set(struct pinctrl_dev *pctrl_dev,
+ unsigned int group, unsigned long *configs,
+ unsigned int num_configs)
+{
+ int i;
+
+ for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) {
+ int err;
+
+ err = airoha_pinconf_set(pctrl_dev,
+ airoha_pinctrl_groups[group].pins[i],
+ configs, num_configs);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops airoha_confops = {
+ .is_generic = true,
+ .pin_config_get = airoha_pinconf_get,
+ .pin_config_set = airoha_pinconf_set,
+ .pin_config_group_get = airoha_pinconf_group_get,
+ .pin_config_group_set = airoha_pinconf_group_set,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static const struct pinctrl_ops airoha_pctlops = {
+ .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 = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static struct pinctrl_desc airoha_pinctrl_desc = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .pctlops = &airoha_pctlops,
+ .pmxops = &airoha_pmxops,
+ .confops = &airoha_confops,
+ .pins = airoha_pinctrl_pins,
+ .npins = ARRAY_SIZE(airoha_pinctrl_pins),
+};
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .fast_io = true,
+ .disable_locking = true,
+};
+
+static int airoha_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct airoha_pinctrl *pinctrl;
+ struct airoha_mfd *mfd;
+ struct regmap *map;
+ int err, i;
+
+ /* Assign parent MFD of_node to dev */
+ device_set_of_node_from_dev(dev, dev->parent);
+ mfd = dev_get_drvdata(dev->parent);
+
+ pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL);
+ if (!pinctrl)
+ return -ENOMEM;
+
+ spin_lock_init(&pinctrl->lock);
+ pinctrl->regmap = devm_regmap_init_mmio(dev, mfd->base,
+ ®map_config);
+ if (IS_ERR(pinctrl->regmap))
+ return PTR_ERR(pinctrl->regmap);
+
+ map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ pinctrl->chip_scu = map;
+
+ err = devm_pinctrl_register_and_init(dev, &airoha_pinctrl_desc,
+ pinctrl, &pinctrl->ctrl);
+ if (err)
+ return err;
+
+ /* build pin groups */
+ for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_groups); i++) {
+ const struct pingroup *grp = &airoha_pinctrl_groups[i];
+
+ err = pinctrl_generic_add_group(pinctrl->ctrl, grp->name,
+ grp->pins, grp->npins,
+ (void *)grp);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Failed to register group %s\n",
+ grp->name);
+ return err;
+ }
+ }
+
+ /* build functions */
+ for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_funcs); i++) {
+ const struct airoha_pinctrl_func *func;
+
+ func = &airoha_pinctrl_funcs[i];
+ err = pinmux_generic_add_function(pinctrl->ctrl,
+ func->desc.func.name,
+ func->desc.func.groups,
+ func->desc.func.ngroups,
+ (void *)func);
+ if (err < 0) {
+ dev_err(dev, "Failed to register function %s\n",
+ func->desc.func.name);
+ return err;
+ }
+ }
+
+ err = pinctrl_enable(pinctrl->ctrl);
+ if (err)
+ return err;
+
+ /* build gpio-chip */
+ return airoha_pinctrl_add_gpiochip(pinctrl, pdev);
+}
+
+static struct platform_driver airoha_pinctrl_driver = {
+ .probe = airoha_pinctrl_probe,
+ .driver = {
+ .name = "pinctrl-airoha",
+ },
+};
+module_platform_driver(airoha_pinctrl_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
+MODULE_AUTHOR("Markus Gothe <markus.gothe@genexis.eu>");
+MODULE_DESCRIPTION("Pinctrl driver for Airoha SoC");
--
2.46.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v5 5/5] pwm: airoha: Add support for EN7581 SoC
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
` (3 preceding siblings ...)
2024-10-01 17:29 ` [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC Lorenzo Bianconi
@ 2024-10-01 17:29 ` Lorenzo Bianconi
4 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-01 17:29 UTC (permalink / raw)
To: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, Uwe Kleine-König
Cc: linux-mediatek, linux-gpio, devicetree, linux-arm-kernel,
upstream, benjamin.larsson, ansuelsmth, linux-pwm
From: Benjamin Larsson <benjamin.larsson@genexis.eu>
Introduce driver for PWM module available on EN7581 SoC.
Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/pwm/Kconfig | 10 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-airoha.c | 414 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 425 insertions(+)
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0915c1e7df16..af63c3a7b645 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -54,6 +54,16 @@ config PWM_ADP5585
This option enables support for the PWM function found in the Analog
Devices ADP5585.
+config PWM_AIROHA
+ tristate "Airoha PWM support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ help
+ Generic PWM framework driver for Airoha SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-airoha.
+
config PWM_APPLE
tristate "Apple SoC PWM support"
depends on ARCH_APPLE || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9081e0c0e9e0..fbf7723d8458 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
obj-$(CONFIG_PWM_ADP5585) += pwm-adp5585.o
+obj-$(CONFIG_PWM_AIROHA) += pwm-airoha.o
obj-$(CONFIG_PWM_APPLE) += pwm-apple.o
obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
diff --git a/drivers/pwm/pwm-airoha.c b/drivers/pwm/pwm-airoha.c
new file mode 100644
index 000000000000..bab2e15e06e7
--- /dev/null
+++ b/drivers/pwm/pwm-airoha.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 Markus Gothe <markus.gothe@genexis.eu>
+ *
+ * Limitations:
+ * - No disable bit, so a disabled PWM is simulated by setting duty_cycle to 0
+ * - Only 8 concurrent waveform generators are available for 8 combinations of
+ * duty_cycle and period. Waveform generators are shared between 16 GPIO
+ * pins and 17 SIPO GPIO pins.
+ * - Supports only normal polarity.
+ * - On configuration the currently running period is completed.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/airoha-en7581-mfd.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+#include <asm/div64.h>
+
+#define REG_SGPIO_LED_DATA 0x0024
+#define SGPIO_LED_DATA_SHIFT_FLAG BIT(31)
+#define SGPIO_LED_DATA_DATA GENMASK(16, 0)
+
+#define REG_SGPIO_CLK_DIVR 0x0028
+#define REG_SGPIO_CLK_DLY 0x002c
+
+#define REG_SIPO_FLASH_MODE_CFG 0x0030
+#define SERIAL_GPIO_FLASH_MODE BIT(1)
+#define SERIAL_GPIO_MODE BIT(0)
+
+#define REG_GPIO_FLASH_PRD_SET(_n) (0x003c + ((_n) << 2))
+#define GPIO_FLASH_PRD_MASK(_n) GENMASK(15 + ((_n) << 4), ((_n) << 4))
+
+#define REG_GPIO_FLASH_MAP(_n) (0x004c + ((_n) << 2))
+#define GPIO_FLASH_SETID_MASK(_n) GENMASK(2 + ((_n) << 2), ((_n) << 2))
+#define GPIO_FLASH_EN(_n) BIT(3 + ((_n) << 2))
+
+#define REG_SIPO_FLASH_MAP(_n) (0x0054 + ((_n) << 2))
+
+#define REG_CYCLE_CFG_VALUE(_n) (0x0098 + ((_n) << 2))
+#define WAVE_GEN_CYCLE_MASK(_n) GENMASK(7 + ((_n) << 3), ((_n) << 3))
+
+struct airoha_pwm {
+ void __iomem *base;
+
+ struct device_node *np;
+ u64 initialized;
+
+ struct {
+ /* Bitmask of PWM channels using this bucket */
+ u64 used;
+ u64 period_ns;
+ u64 duty_ns;
+ } bucket[8];
+};
+
+/*
+ * The first 16 GPIO pins, GPIO0-GPIO15, are mapped into 16 PWM channels, 0-15.
+ * The SIPO GPIO pins are 17 pins which are mapped into 17 PWM channels, 16-32.
+ * However, we've only got 8 concurrent waveform generators and can therefore
+ * only use up to 8 different combinations of duty cycle and period at a time.
+ */
+#define PWM_NUM_GPIO 16
+#define PWM_NUM_SIPO 17
+
+/* The PWM hardware supports periods between 4 ms and 1 s */
+#define PERIOD_MIN_NS (4 * NSEC_PER_MSEC)
+#define PERIOD_MAX_NS (1 * NSEC_PER_SEC)
+/* It is represented internally as 1/250 s between 1 and 250 */
+#define PERIOD_MIN 1
+#define PERIOD_MAX 250
+/* Duty cycle is relative with 255 corresponding to 100% */
+#define DUTY_FULL 255
+
+static u32 airoha_pwm_rmw(struct airoha_pwm *pc, u32 addr, u32 mask, u32 val)
+{
+ val |= (readl(pc->base + addr) & ~mask);
+ writel(val, pc->base + addr);
+
+ return val;
+}
+
+#define airoha_pwm_set_bits(pc, addr, val) \
+ airoha_pwm_rmw((pc), (addr), (val), (val))
+
+#define airoha_pwm_clear_bit(pc, addr, mask) \
+ airoha_pwm_rmw(pc, addr, mask, 0)
+
+static int airoha_pwm_get_generator(struct airoha_pwm *pc, u64 duty_ns,
+ u64 period_ns)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (!pc->bucket[i].used)
+ continue;
+
+ if (duty_ns == pc->bucket[i].duty_ns &&
+ period_ns == pc->bucket[i].period_ns)
+ return i;
+
+ /*
+ * Unlike duty cycle zero, which can be handled by
+ * disabling PWM, a generator is needed for full duty
+ * cycle but it can be reused regardless of period
+ */
+ if (duty_ns == DUTY_FULL && pc->bucket[i].duty_ns == DUTY_FULL)
+ return i;
+ }
+
+ return -1;
+}
+
+static void airoha_pwm_release_bucket_config(struct airoha_pwm *pc,
+ unsigned int hwpwm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++)
+ pc->bucket[i].used &= ~BIT_ULL(hwpwm);
+}
+
+static int airoha_pwm_consume_generator(struct airoha_pwm *pc,
+ u64 duty_ns, u64 period_ns,
+ unsigned int hwpwm)
+{
+ int id = airoha_pwm_get_generator(pc, duty_ns, period_ns);
+
+ if (id < 0) {
+ int i;
+
+ /* find an unused waveform generator */
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (!(pc->bucket[i].used & ~BIT_ULL(hwpwm))) {
+ id = i;
+ break;
+ }
+ }
+ }
+
+ if (id >= 0) {
+ airoha_pwm_release_bucket_config(pc, hwpwm);
+ pc->bucket[id].used |= BIT_ULL(hwpwm);
+ pc->bucket[id].period_ns = period_ns;
+ pc->bucket[id].duty_ns = duty_ns;
+ }
+
+ return id;
+}
+
+static int airoha_pwm_sipo_init(struct airoha_pwm *pc)
+{
+ u32 clk_divr_val = 3, sipo_clock_delay = 1;
+ u32 val, sipo_clock_divisor = 32;
+
+ if (!(pc->initialized >> PWM_NUM_GPIO))
+ return 0;
+
+ /* Select the right shift register chip */
+ if (of_property_read_bool(pc->np, "hc74595"))
+ airoha_pwm_set_bits(pc, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_MODE);
+ else
+ airoha_pwm_clear_bit(pc, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_MODE);
+
+ if (!of_property_read_u32(pc->np, "sipo-clock-divisor",
+ &sipo_clock_divisor)) {
+ switch (sipo_clock_divisor) {
+ case 4:
+ clk_divr_val = 0;
+ break;
+ case 8:
+ clk_divr_val = 1;
+ break;
+ case 16:
+ clk_divr_val = 2;
+ break;
+ case 32:
+ clk_divr_val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* Configure shift register timings */
+ writel(clk_divr_val, pc->base + REG_SGPIO_CLK_DIVR);
+
+ of_property_read_u32(pc->np, "sipo-clock-delay", &sipo_clock_delay);
+ if (sipo_clock_delay < 1 || sipo_clock_delay > sipo_clock_divisor / 2)
+ return -EINVAL;
+
+ /*
+ * The actual delay is sclkdly + 1 so subtract 1 from
+ * sipo-clock-delay to calculate the register value
+ */
+ sipo_clock_delay--;
+ writel(sipo_clock_delay, pc->base + REG_SGPIO_CLK_DLY);
+
+ /*
+ * It it necessary to after muxing explicitly shift out all
+ * zeroes to initialize the shift register before enabling PWM
+ * mode because in PWM mode SIPO will not start shifting until
+ * it needs to output a non-zero value (bit 31 of led_data
+ * indicates shifting in progress and it must return to zero
+ * before led_data can be written or PWM mode can be set)
+ */
+ if (readl_poll_timeout(pc->base + REG_SGPIO_LED_DATA, val,
+ !(val & SGPIO_LED_DATA_SHIFT_FLAG), 10,
+ 200 * USEC_PER_MSEC))
+ return -ETIMEDOUT;
+
+ airoha_pwm_clear_bit(pc, REG_SGPIO_LED_DATA, SGPIO_LED_DATA_DATA);
+ if (readl_poll_timeout(pc->base + REG_SGPIO_LED_DATA, val,
+ !(val & SGPIO_LED_DATA_SHIFT_FLAG), 10,
+ 200 * USEC_PER_MSEC))
+ return -ETIMEDOUT;
+
+ /* Set SIPO in PWM mode */
+ airoha_pwm_set_bits(pc, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_FLASH_MODE);
+
+ return 0;
+}
+
+static void airoha_pwm_calc_bucket_config(struct airoha_pwm *pc, int index,
+ u64 duty_ns, u64 period_ns)
+{
+ u32 period, duty, mask, val;
+ u64 tmp;
+
+ tmp = duty_ns * DUTY_FULL;
+ duty = clamp_val(div64_u64(tmp, period_ns), 0, DUTY_FULL);
+ tmp = period_ns * 25;
+ period = clamp_val(div64_u64(tmp, 100000000), PERIOD_MIN, PERIOD_MAX);
+
+ /* Configure frequency divisor */
+ mask = WAVE_GEN_CYCLE_MASK(index % 4);
+ val = (period << __ffs(mask)) & mask;
+ airoha_pwm_rmw(pc, REG_CYCLE_CFG_VALUE(index / 4), mask, val);
+
+ /* Configure duty cycle */
+ duty = ((DUTY_FULL - duty) << 8) | duty;
+ mask = GPIO_FLASH_PRD_MASK(index % 2);
+ val = (duty << __ffs(mask)) & mask;
+ airoha_pwm_rmw(pc, REG_GPIO_FLASH_PRD_SET(index / 2), mask, val);
+}
+
+static void airoha_pwm_config_flash_map(struct airoha_pwm *pc,
+ unsigned int hwpwm, int index)
+{
+ u32 addr, mask, val;
+
+ if (hwpwm < PWM_NUM_GPIO) {
+ addr = REG_GPIO_FLASH_MAP(hwpwm / 8);
+ } else {
+ addr = REG_SIPO_FLASH_MAP(hwpwm / 8);
+ hwpwm -= PWM_NUM_GPIO;
+ }
+
+ if (index < 0) {
+ /*
+ * Change of waveform takes effect immediately but
+ * disabling has some delay so to prevent glitching
+ * only the enable bit is touched when disabling
+ */
+ airoha_pwm_clear_bit(pc, addr, GPIO_FLASH_EN(hwpwm % 8));
+ return;
+ }
+
+ mask = GPIO_FLASH_SETID_MASK(hwpwm % 8);
+ val = ((index & 7) << __ffs(mask)) & mask;
+ airoha_pwm_rmw(pc, addr, mask, val);
+ airoha_pwm_set_bits(pc, addr, GPIO_FLASH_EN(hwpwm % 8));
+}
+
+static int airoha_pwm_config(struct airoha_pwm *pc, struct pwm_device *pwm,
+ u64 duty_ns, u64 period_ns)
+{
+ int index = -1;
+
+ index = airoha_pwm_consume_generator(pc, duty_ns, period_ns,
+ pwm->hwpwm);
+ if (index < 0)
+ return -EBUSY;
+
+ if (!(pc->initialized & BIT_ULL(pwm->hwpwm)) &&
+ pwm->hwpwm >= PWM_NUM_GPIO)
+ airoha_pwm_sipo_init(pc);
+
+ if (index >= 0) {
+ airoha_pwm_calc_bucket_config(pc, index, duty_ns, period_ns);
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, index);
+ } else {
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, index);
+ airoha_pwm_release_bucket_config(pc, pwm->hwpwm);
+ }
+
+ pc->initialized |= BIT_ULL(pwm->hwpwm);
+
+ return 0;
+}
+
+static void airoha_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+
+ /* Disable PWM and release the waveform */
+ airoha_pwm_config_flash_map(pc, pwm->hwpwm, -1);
+ airoha_pwm_release_bucket_config(pc, pwm->hwpwm);
+
+ pc->initialized &= ~BIT_ULL(pwm->hwpwm);
+ if (!(pc->initialized >> PWM_NUM_GPIO))
+ airoha_pwm_clear_bit(pc, REG_SIPO_FLASH_MODE_CFG,
+ SERIAL_GPIO_FLASH_MODE);
+}
+
+static int airoha_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+ u64 duty = state->enabled ? state->duty_cycle : 0;
+ u64 period = state->period;
+
+ /* Only normal polarity is supported */
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ return -EINVAL;
+
+ if (!state->enabled) {
+ airoha_pwm_disable(chip, pwm);
+ return 0;
+ }
+
+ if (period < PERIOD_MIN_NS)
+ return -EINVAL;
+
+ if (period > PERIOD_MAX_NS)
+ period = PERIOD_MAX_NS;
+
+ return airoha_pwm_config(pc, pwm, duty, period);
+}
+
+static int airoha_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct airoha_pwm *pc = pwmchip_get_drvdata(chip);
+ int i;
+
+ /* find hwpwm in waveform generator bucket */
+ for (i = 0; i < ARRAY_SIZE(pc->bucket); i++) {
+ if (pc->bucket[i].used & BIT_ULL(pwm->hwpwm)) {
+ state->enabled = pc->initialized & BIT_ULL(pwm->hwpwm);
+ state->polarity = PWM_POLARITY_NORMAL;
+ state->period = pc->bucket[i].period_ns;
+ state->duty_cycle = pc->bucket[i].duty_ns;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(pc->bucket))
+ state->enabled = false;
+
+ return 0;
+}
+
+static const struct pwm_ops airoha_pwm_ops = {
+ .get_state = airoha_pwm_get_state,
+ .apply = airoha_pwm_apply,
+};
+
+static int airoha_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct airoha_mfd *mfd;
+ struct airoha_pwm *pc;
+ struct pwm_chip *chip;
+
+ /* Assign parent MFD of_node to dev */
+ device_set_of_node_from_dev(dev, dev->parent);
+ mfd = dev_get_drvdata(dev->parent);
+
+ chip = devm_pwmchip_alloc(dev, PWM_NUM_GPIO + PWM_NUM_SIPO,
+ sizeof(*pc));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ pc = pwmchip_get_drvdata(chip);
+ pc->np = dev->of_node;
+ pc->base = mfd->base;
+ chip->ops = &airoha_pwm_ops;
+
+ return devm_pwmchip_add(&pdev->dev, chip);
+}
+
+static struct platform_driver airoha_pwm_driver = {
+ .driver = {
+ .name = "pwm-airoha",
+ },
+ .probe = airoha_pwm_probe,
+};
+module_platform_driver(airoha_pwm_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_AUTHOR("Markus Gothe <markus.gothe@genexis.eu>");
+MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
+MODULE_DESCRIPTION("Airoha EN7581 PWM driver");
+MODULE_LICENSE("GPL");
--
2.46.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-01 17:29 ` [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD Lorenzo Bianconi
@ 2024-10-02 13:25 ` Lee Jones
2024-10-02 22:42 ` Christian Marangi
2024-10-08 22:04 ` Lorenzo Bianconi
0 siblings, 2 replies; 19+ messages in thread
From: Lee Jones @ 2024-10-02 13:25 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> From: Christian Marangi <ansuelsmth@gmail.com>
>
> Support for Airoha EN7581 Multi Function Device that
> expose PINCTRL functionality and PWM functionality.
The device is a jumble of pinctrl registers, some of which can oscillate.
This is *still* not an MFD.
If you wish to spread this functionality over 2 drivers, use syscon to
obtain the registers and simple-mfd to automatically probe the drivers.
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
> drivers/mfd/Kconfig | 8 ++++
> drivers/mfd/Makefile | 2 +
> drivers/mfd/airoha-en7581-gpio-mfd.c | 72 +++++++++++++++++++++++++++++++++++
> include/linux/mfd/airoha-en7581-mfd.h | 9 +++++
> 4 files changed, 91 insertions(+)
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index f9325bcce1b9..eca221351ab7 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -32,6 +32,14 @@ config MFD_ADP5585
> the core APIs _only_, you have to select individual components like
> the GPIO and PWM functions under the corresponding menus.
>
> +config MFD_AIROHA_EN7581
> + bool "Airoha EN7581 Multi Function Device"
> + depends on (ARCH_AIROHA || COMPILE_TEST) && OF
> + select MFD_CORE
> + help
> + Support for Airoha EN7581 Multi Function Device that
> + expose PINCTRL functionality and PWM functionality.
> +
> config MFD_ALTERA_A10SR
> bool "Altera Arria10 DevKit System Resource chip"
> depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 2a9f91e81af8..be8448e81a5b 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -257,6 +257,8 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
> obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
> obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
>
> +obj-$(CONFIG_MFD_AIROHA_EN7581) += airoha-en7581-gpio-mfd.o
> +
> obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
> obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
> obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o
> diff --git a/drivers/mfd/airoha-en7581-gpio-mfd.c b/drivers/mfd/airoha-en7581-gpio-mfd.c
> new file mode 100644
> index 000000000000..88407ce5747e
> --- /dev/null
> +++ b/drivers/mfd/airoha-en7581-gpio-mfd.c
> @@ -0,0 +1,72 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * MFD driver for Airoha EN7581
> + */
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/mfd/airoha-en7581-mfd.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +
> +static struct resource airoha_mfd_pinctrl_intr[] = {
> + {
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static const struct mfd_cell airoha_mfd_devs[] = {
> + {
> + .name = "pinctrl-airoha",
> + .resources = airoha_mfd_pinctrl_intr,
> + .num_resources = ARRAY_SIZE(airoha_mfd_pinctrl_intr),
> + }, {
> + .name = "pwm-airoha",
> + },
> +};
> +
> +static int airoha_mfd_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct airoha_mfd *mfd;
> + int irq;
> +
> + mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> + if (!mfd)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, mfd);
> +
> + mfd->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(mfd->base))
> + return PTR_ERR(mfd->base);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0)
> + return irq;
> +
> + airoha_mfd_pinctrl_intr[0].start = irq;
> + airoha_mfd_pinctrl_intr[0].end = irq;
> +
> + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, airoha_mfd_devs,
> + ARRAY_SIZE(airoha_mfd_devs), NULL, 0,
> + NULL);
> +}
> +
> +static const struct of_device_id airoha_mfd_of_match[] = {
> + { .compatible = "airoha,en7581-gpio-sysctl" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, airoha_mfd_of_match);
> +
> +static struct platform_driver airoha_mfd_driver = {
> + .probe = airoha_mfd_probe,
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .of_match_table = airoha_mfd_of_match,
> + },
> +};
> +module_platform_driver(airoha_mfd_driver);
> +
> +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
> +MODULE_DESCRIPTION("Driver for Airoha EN7581 MFD");
> diff --git a/include/linux/mfd/airoha-en7581-mfd.h b/include/linux/mfd/airoha-en7581-mfd.h
> new file mode 100644
> index 000000000000..25e73952a777
> --- /dev/null
> +++ b/include/linux/mfd/airoha-en7581-mfd.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
> +#define _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
> +
> +struct airoha_mfd {
> + void __iomem *base;
> +};
> +
> +#endif /* _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_ */
>
> --
> 2.46.2
>
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC
2024-10-01 17:29 ` [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC Lorenzo Bianconi
@ 2024-10-02 13:27 ` Linus Walleij
2024-10-02 15:37 ` Lorenzo Bianconi
0 siblings, 1 reply; 19+ messages in thread
From: Linus Walleij @ 2024-10-02 13:27 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Lee Jones,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
On Tue, Oct 1, 2024 at 7:30 PM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
> Introduce pinctrl driver for EN7581 SoC. Current EN7581 pinctrl driver
> supports the following functionalities:
> - pin multiplexing
> - pin pull-up, pull-down, open-drain, current strength,
> {input,output}_enable, output_{low,high}
> - gpio controller
> - irq controller
>
> Tested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> Co-developed-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
I missed that there was a v5 out and responded more to v4.
Anyway, I think the last comments on v4 still need to be
adressed:
https://lore.kernel.org/linux-gpio/CACRpkdbXWMU+wq6DvviCQPQ0EzKUm9oOnyFh34Bm=Y8K-HmT0Q@mail.gmail.com/
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC
2024-10-02 13:27 ` Linus Walleij
@ 2024-10-02 15:37 ` Lorenzo Bianconi
0 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-02 15:37 UTC (permalink / raw)
To: Linus Walleij
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Lee Jones,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
[-- Attachment #1: Type: text/plain, Size: 1007 bytes --]
On Oct 02, Linus Walleij wrote:
> On Tue, Oct 1, 2024 at 7:30 PM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
>
> > Introduce pinctrl driver for EN7581 SoC. Current EN7581 pinctrl driver
> > supports the following functionalities:
> > - pin multiplexing
> > - pin pull-up, pull-down, open-drain, current strength,
> > {input,output}_enable, output_{low,high}
> > - gpio controller
> > - irq controller
> >
> > Tested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> > Co-developed-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> > Signed-off-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
> > Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
>
> I missed that there was a v5 out and responded more to v4.
>
> Anyway, I think the last comments on v4 still need to be
> adressed:
> https://lore.kernel.org/linux-gpio/CACRpkdbXWMU+wq6DvviCQPQ0EzKUm9oOnyFh34Bm=Y8K-HmT0Q@mail.gmail.com/
ack, I will do in v6.
Regards,
Lorenzo
>
> Yours,
> Linus Walleij
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-02 13:25 ` Lee Jones
@ 2024-10-02 22:42 ` Christian Marangi
2024-10-08 22:04 ` Lorenzo Bianconi
1 sibling, 0 replies; 19+ messages in thread
From: Christian Marangi @ 2024-10-02 22:42 UTC (permalink / raw)
To: Lee Jones
Cc: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
On Wed, Oct 02, 2024 at 02:25:18PM +0100, Lee Jones wrote:
> On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
>
> > From: Christian Marangi <ansuelsmth@gmail.com>
> >
> > Support for Airoha EN7581 Multi Function Device that
> > expose PINCTRL functionality and PWM functionality.
>
> The device is a jumble of pinctrl registers, some of which can oscillate.
>
> This is *still* not an MFD.
>
> If you wish to spread this functionality over 2 drivers, use syscon to
> obtain the registers and simple-mfd to automatically probe the drivers.
>
Hi Lee,
let me summarize the situation so it's more clear why
this additional mfd driver.
There were various iteration for these 2 driver (pinctrl and PWM).
Due to the fact that these 2 are placed in the same register block
with the PWM register in the middle, we proposed various .yaml schema
that could better model it.
The first idea was to map the single register used by the 2 driver.
pio: pinctrl@1fa20214 {
compatible = "airoha,en7581-pinctrl";
reg = <0x0 0x1fa20214 0x0 0x30>,
<0x0 0x1fa2027c 0x0 0x8>,
<0x0 0x1fbf0234 0x0 0x4>,
<0x0 0x1fbf0268 0x0 0x4>,
<0x0 0x1fa2001c 0x0 0x50>,
<0x0 0x1fa2018c 0x0 0x4>,
<0x0 0x1fbf0204 0x0 0x4>,
<0x0 0x1fbf0270 0x0 0x4>,
<0x0 0x1fbf0200 0x0 0x4>,
<0x0 0x1fbf0220 0x0 0x4>,
<0x0 0x1fbf0260 0x0 0x4>,
<0x0 0x1fbf0264 0x0 0x4>,
<0x0 0x1fbf0214 0x0 0x4>,
<0x0 0x1fbf0278 0x0 0x4>,
<0x0 0x1fbf0208 0x0 0x4>,
<0x0 0x1fbf027c 0x0 0x4>,
<0x0 0x1fbf0210 0x0 0x4>,
<0x0 0x1fbf028c 0x0 0x4>,
<0x0 0x1fbf0290 0x0 0x4>,
<0x0 0x1fbf0294 0x0 0x4>,
<0x0 0x1fbf020c 0x0 0x4>,
<0x0 0x1fbf0280 0x0 0x4>,
<0x0 0x1fbf0284 0x0 0x4>,
<0x0 0x1fbf0288 0x0 0x4>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pio 0 13 47>;
...
};
pwm@1fbf0224 {
compatible = "airoha,en7581-pwm";
reg = <0x1fbf0224 0x10>,
<0x1fbf0238 0x28>,
<0x1fbf0298 0x8>;
#pwm-cells = <3>;
};
This was quickly rejected as it introduced way more complication
to workaround the overlapping addresses. (the device should map the
entire register space)
The second proposal was a parent+child implementation with the
pinctrl parent and the PWM child by referencing a syscon from
the parent.
pio: pinctrl@1fbf0200 {
compatible = "airoha,en7581-pinctrl", "simple-mfd", "syscon";
reg = <0x1fbf0200 0x0 0xbc>;
airoha,chip-scu = <&chip_scu>;
....
pwm {
compatible = "airoha,en7581-pwm";
...
};
};
Also this second proposal was rejected by device tree folks
as the device implement both pinctrl and PWM in the register
space and they are not actually separate devices.
There was also an additional proposal with the entire register
map in a dedicated node with syscon and pwm + pinctrl using it.
This was also rejected by device tree folks. (node that have only
a syscon are a nono)
It was suggested that this is a case of MFD (multi-functional-device)
As suggested we proposed a simple-mfd implementation following
common pattern. Parent node with simple-mfd and syscon compatible
and 2 child nodes, one with pinctrl and the other with PWM with each
his own compatible.
mfd@1fbf0200 {
compatible = "airoha,en7581-gpio-mfd";
reg = <0x0 0x1fbf0200 0x0 0xc0>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
pio: pinctrl {
compatible = "airoha,en7581-pinctrl";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
pwm: pwm {
compatible = "airoha,en7581-pwm";
#pwm-cells = <3>;
status = "disabled";
};
};
Also this was rejected by device tree folks as the property for
pinctrl and pwm needed to be in the MFD node and there should't
be child node with single compatible.
This comes from the fact that DT needs to describe how the HW is
modelled and not how the drivers are implemented.
Finally Rob agreed and added the Reviwed-by on the current
implementation with single MFD node with pinctrl and pwm.
Also Conor and Krzysztof agreed on this solution for the task.
mfd@1fbf0200 {
compatible = "airoha,en7581-gpio-sysctl";
reg = <0x1fbf0200 0xc0>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
#pwm-cells = <3>;
pinctrl {
...
};
};
With the following implementation, the only way to probe the
additional driver is with a specialized mfd driver that probe the
2 driver by name and we can't really use a simple-mfd implementation
as that requires child nodes with compatibles.
Sorry for the long message and I honestly hope we can find together
a common path for this between driver and Documentation.
Is it clear now why we had to ultimely had to implement and model things
this way?
--
Ansuel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-02 13:25 ` Lee Jones
2024-10-02 22:42 ` Christian Marangi
@ 2024-10-08 22:04 ` Lorenzo Bianconi
2024-10-09 10:48 ` Lee Jones
1 sibling, 1 reply; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-08 22:04 UTC (permalink / raw)
To: Lee Jones
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
[-- Attachment #1: Type: text/plain, Size: 6747 bytes --]
On Oct 02, Lee Jones wrote:
> On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
>
> > From: Christian Marangi <ansuelsmth@gmail.com>
> >
> > Support for Airoha EN7581 Multi Function Device that
> > expose PINCTRL functionality and PWM functionality.
>
> The device is a jumble of pinctrl registers, some of which can oscillate.
>
> This is *still* not an MFD.
>
> If you wish to spread this functionality over 2 drivers, use syscon to
> obtain the registers and simple-mfd to automatically probe the drivers.
Hi Lee,
IIUC you are suggesting two possible approaches here:
1- have a single driver implementing both pinctrl and pwm functionalities.
This approach will not let us reuse the code for future devices that
have just one of them in common, like pwm (but we can live with that).
2- use a device node like the one below (something similar to [0])
system-controller@1fbf0200 {
compatible = "syscon", "simple-mfd";
reg = <0x0 0x1fbf0200 0x0 0xc0>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
pio: pinctrl {
compatible = "airoha,en7581-pinctrl";
[ some pinctrl properties here ]
};
#pwm-cells = <3>;
pwm {
compatible = "airoha,en7581-pwm";
};
};
Please correct me if I am wrong, but using syscon/simple-mfd as compatible
string for the 'parent' device, will require to introduce the compatible strings
even for the child devices in order to probe them, correct?
If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
(this is the main reason why we introduced a full mfd driver here).
@Rob, Krzysztof, Conor: am I right?
I guess we need to find a middle ground here between mfd and dts to support this
uncommon hw device.
Regards,
Lorenzo
[0] https://elixir.bootlin.com/linux/v6.11.2/source/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi#L269
>
> > Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> > ---
> > drivers/mfd/Kconfig | 8 ++++
> > drivers/mfd/Makefile | 2 +
> > drivers/mfd/airoha-en7581-gpio-mfd.c | 72 +++++++++++++++++++++++++++++++++++
> > include/linux/mfd/airoha-en7581-mfd.h | 9 +++++
> > 4 files changed, 91 insertions(+)
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index f9325bcce1b9..eca221351ab7 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -32,6 +32,14 @@ config MFD_ADP5585
> > the core APIs _only_, you have to select individual components like
> > the GPIO and PWM functions under the corresponding menus.
> >
> > +config MFD_AIROHA_EN7581
> > + bool "Airoha EN7581 Multi Function Device"
> > + depends on (ARCH_AIROHA || COMPILE_TEST) && OF
> > + select MFD_CORE
> > + help
> > + Support for Airoha EN7581 Multi Function Device that
> > + expose PINCTRL functionality and PWM functionality.
> > +
> > config MFD_ALTERA_A10SR
> > bool "Altera Arria10 DevKit System Resource chip"
> > depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 2a9f91e81af8..be8448e81a5b 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -257,6 +257,8 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
> > obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
> > obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
> >
> > +obj-$(CONFIG_MFD_AIROHA_EN7581) += airoha-en7581-gpio-mfd.o
> > +
> > obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
> > obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
> > obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o
> > diff --git a/drivers/mfd/airoha-en7581-gpio-mfd.c b/drivers/mfd/airoha-en7581-gpio-mfd.c
> > new file mode 100644
> > index 000000000000..88407ce5747e
> > --- /dev/null
> > +++ b/drivers/mfd/airoha-en7581-gpio-mfd.c
> > @@ -0,0 +1,72 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * MFD driver for Airoha EN7581
> > + */
> > +
> > +#include <linux/io.h>
> > +#include <linux/of.h>
> > +#include <linux/mfd/airoha-en7581-mfd.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/module.h>
> > +
> > +static struct resource airoha_mfd_pinctrl_intr[] = {
> > + {
> > + .flags = IORESOURCE_IRQ,
> > + },
> > +};
> > +
> > +static const struct mfd_cell airoha_mfd_devs[] = {
> > + {
> > + .name = "pinctrl-airoha",
> > + .resources = airoha_mfd_pinctrl_intr,
> > + .num_resources = ARRAY_SIZE(airoha_mfd_pinctrl_intr),
> > + }, {
> > + .name = "pwm-airoha",
> > + },
> > +};
> > +
> > +static int airoha_mfd_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct airoha_mfd *mfd;
> > + int irq;
> > +
> > + mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> > + if (!mfd)
> > + return -ENOMEM;
> > +
> > + platform_set_drvdata(pdev, mfd);
> > +
> > + mfd->base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(mfd->base))
> > + return PTR_ERR(mfd->base);
> > +
> > + irq = platform_get_irq(pdev, 0);
> > + if (irq < 0)
> > + return irq;
> > +
> > + airoha_mfd_pinctrl_intr[0].start = irq;
> > + airoha_mfd_pinctrl_intr[0].end = irq;
> > +
> > + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, airoha_mfd_devs,
> > + ARRAY_SIZE(airoha_mfd_devs), NULL, 0,
> > + NULL);
> > +}
> > +
> > +static const struct of_device_id airoha_mfd_of_match[] = {
> > + { .compatible = "airoha,en7581-gpio-sysctl" },
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, airoha_mfd_of_match);
> > +
> > +static struct platform_driver airoha_mfd_driver = {
> > + .probe = airoha_mfd_probe,
> > + .driver = {
> > + .name = KBUILD_MODNAME,
> > + .of_match_table = airoha_mfd_of_match,
> > + },
> > +};
> > +module_platform_driver(airoha_mfd_driver);
> > +
> > +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
> > +MODULE_DESCRIPTION("Driver for Airoha EN7581 MFD");
> > diff --git a/include/linux/mfd/airoha-en7581-mfd.h b/include/linux/mfd/airoha-en7581-mfd.h
> > new file mode 100644
> > index 000000000000..25e73952a777
> > --- /dev/null
> > +++ b/include/linux/mfd/airoha-en7581-mfd.h
> > @@ -0,0 +1,9 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
> > +#define _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_
> > +
> > +struct airoha_mfd {
> > + void __iomem *base;
> > +};
> > +
> > +#endif /* _LINUX_INCLUDE_MFD_AIROHA_EN7581_MFD_H_ */
> >
> > --
> > 2.46.2
> >
>
> --
> Lee Jones [李琼斯]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-08 22:04 ` Lorenzo Bianconi
@ 2024-10-09 10:48 ` Lee Jones
2024-10-09 10:55 ` Lee Jones
0 siblings, 1 reply; 19+ messages in thread
From: Lee Jones @ 2024-10-09 10:48 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
On Wed, 09 Oct 2024, Lorenzo Bianconi wrote:
> On Oct 02, Lee Jones wrote:
> > On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> >
> > > From: Christian Marangi <ansuelsmth@gmail.com>
> > >
> > > Support for Airoha EN7581 Multi Function Device that
> > > expose PINCTRL functionality and PWM functionality.
> >
> > The device is a jumble of pinctrl registers, some of which can oscillate.
> >
> > This is *still* not an MFD.
> >
> > If you wish to spread this functionality over 2 drivers, use syscon to
> > obtain the registers and simple-mfd to automatically probe the drivers.
>
> Hi Lee,
>
> IIUC you are suggesting two possible approaches here:
>
> 1- have a single driver implementing both pinctrl and pwm functionalities.
> This approach will not let us reuse the code for future devices that
> have just one of them in common, like pwm (but we can live with that).
If you can have one without the other, then they are separate devices.
> 2- use a device node like the one below (something similar to [0])
>
> system-controller@1fbf0200 {
> compatible = "syscon", "simple-mfd";
> reg = <0x0 0x1fbf0200 0x0 0xc0>;
>
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>
> gpio-controller;
> #gpio-cells = <2>;
>
> interrupt-controller;
> #interrupt-cells = <2>;
>
> pio: pinctrl {
> compatible = "airoha,en7581-pinctrl";
>
> [ some pinctrl properties here ]
> };
>
> #pwm-cells = <3>;
>
> pwm {
> compatible = "airoha,en7581-pwm";
> };
> };
>
> Please correct me if I am wrong, but using syscon/simple-mfd as compatible
> string for the 'parent' device, will require to introduce the compatible strings
> even for the child devices in order to probe them, correct?
> If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
> (this is the main reason why we introduced a full mfd driver here).
>
> @Rob, Krzysztof, Conor: am I right?
I don't see why separate functionality shouldn't have separate
compatible strings, even if the registers are together. Register layout
and functionality separation are not related.
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-09 10:48 ` Lee Jones
@ 2024-10-09 10:55 ` Lee Jones
2024-10-10 10:14 ` Christian Marangi
0 siblings, 1 reply; 19+ messages in thread
From: Lee Jones @ 2024-10-09 10:55 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, ansuelsmth,
linux-pwm
On Wed, 09 Oct 2024, Lee Jones wrote:
> On Wed, 09 Oct 2024, Lorenzo Bianconi wrote:
>
> > On Oct 02, Lee Jones wrote:
> > > On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> > >
> > > > From: Christian Marangi <ansuelsmth@gmail.com>
> > > >
> > > > Support for Airoha EN7581 Multi Function Device that
> > > > expose PINCTRL functionality and PWM functionality.
> > >
> > > The device is a jumble of pinctrl registers, some of which can oscillate.
> > >
> > > This is *still* not an MFD.
> > >
> > > If you wish to spread this functionality over 2 drivers, use syscon to
> > > obtain the registers and simple-mfd to automatically probe the drivers.
> >
> > Hi Lee,
> >
> > IIUC you are suggesting two possible approaches here:
> >
> > 1- have a single driver implementing both pinctrl and pwm functionalities.
> > This approach will not let us reuse the code for future devices that
> > have just one of them in common, like pwm (but we can live with that).
>
> If you can have one without the other, then they are separate devices.
>
> > 2- use a device node like the one below (something similar to [0])
> >
> > system-controller@1fbf0200 {
> > compatible = "syscon", "simple-mfd";
> > reg = <0x0 0x1fbf0200 0x0 0xc0>;
> >
> > interrupt-parent = <&gic>;
> > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> >
> > gpio-controller;
> > #gpio-cells = <2>;
> >
> > interrupt-controller;
> > #interrupt-cells = <2>;
> >
> > pio: pinctrl {
> > compatible = "airoha,en7581-pinctrl";
> >
> > [ some pinctrl properties here ]
> > };
> >
> > #pwm-cells = <3>;
> >
> > pwm {
> > compatible = "airoha,en7581-pwm";
> > };
> > };
> >
> > Please correct me if I am wrong, but using syscon/simple-mfd as compatible
> > string for the 'parent' device, will require to introduce the compatible strings
> > even for the child devices in order to probe them, correct?
> > If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
> > (this is the main reason why we introduced a full mfd driver here).
> >
> > @Rob, Krzysztof, Conor: am I right?
>
> I don't see why separate functionality shouldn't have separate
> compatible strings, even if the registers are together. Register layout
> and functionality separation are not related.
We've been happy to support both pinctrl and pwm devices before:
git grep "\-pinctrl\|\-pwm" -- drivers/mfd
git grep "\-pinctrl\|\-pwm" -- arch/*/boot/dts
git grep "\-pinctrl" -- arch/*/boot/dts | wc -l
602
git grep "\-pwm" -- arch/*/boot/dts | wc -l
856
What makes this particular device different to all of the others?
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-09 10:55 ` Lee Jones
@ 2024-10-10 10:14 ` Christian Marangi
2024-10-10 10:41 ` Christian Marangi
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Christian Marangi @ 2024-10-10 10:14 UTC (permalink / raw)
To: Lee Jones
Cc: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
On Wed, Oct 09, 2024 at 11:55:50AM +0100, Lee Jones wrote:
> On Wed, 09 Oct 2024, Lee Jones wrote:
>
> > On Wed, 09 Oct 2024, Lorenzo Bianconi wrote:
> >
> > > On Oct 02, Lee Jones wrote:
> > > > On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> > > >
> > > > > From: Christian Marangi <ansuelsmth@gmail.com>
> > > > >
> > > > > Support for Airoha EN7581 Multi Function Device that
> > > > > expose PINCTRL functionality and PWM functionality.
> > > >
> > > > The device is a jumble of pinctrl registers, some of which can oscillate.
> > > >
> > > > This is *still* not an MFD.
> > > >
> > > > If you wish to spread this functionality over 2 drivers, use syscon to
> > > > obtain the registers and simple-mfd to automatically probe the drivers.
> > >
> > > Hi Lee,
> > >
> > > IIUC you are suggesting two possible approaches here:
> > >
> > > 1- have a single driver implementing both pinctrl and pwm functionalities.
> > > This approach will not let us reuse the code for future devices that
> > > have just one of them in common, like pwm (but we can live with that).
> >
> > If you can have one without the other, then they are separate devices.
> >
> > > 2- use a device node like the one below (something similar to [0])
> > >
> > > system-controller@1fbf0200 {
> > > compatible = "syscon", "simple-mfd";
> > > reg = <0x0 0x1fbf0200 0x0 0xc0>;
> > >
> > > interrupt-parent = <&gic>;
> > > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> > >
> > > gpio-controller;
> > > #gpio-cells = <2>;
> > >
> > > interrupt-controller;
> > > #interrupt-cells = <2>;
> > >
> > > pio: pinctrl {
> > > compatible = "airoha,en7581-pinctrl";
> > >
> > > [ some pinctrl properties here ]
> > > };
> > >
> > > #pwm-cells = <3>;
> > >
> > > pwm {
> > > compatible = "airoha,en7581-pwm";
> > > };
> > > };
> > >
> > > Please correct me if I am wrong, but using syscon/simple-mfd as compatible
> > > string for the 'parent' device, will require to introduce the compatible strings
> > > even for the child devices in order to probe them, correct?
> > > If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
> > > (this is the main reason why we introduced a full mfd driver here).
> > >
> > > @Rob, Krzysztof, Conor: am I right?
> >
> > I don't see why separate functionality shouldn't have separate
> > compatible strings, even if the registers are together. Register layout
> > and functionality separation are not related.
>
> We've been happy to support both pinctrl and pwm devices before:
>
> git grep "\-pinctrl\|\-pwm" -- drivers/mfd
> git grep "\-pinctrl\|\-pwm" -- arch/*/boot/dts
>
> git grep "\-pinctrl" -- arch/*/boot/dts | wc -l
> 602
> git grep "\-pwm" -- arch/*/boot/dts | wc -l
> 856
>
> What makes this particular device different to all of the others?
>
Hi Lee,
this would be the final DTS following the "simple-mfd" pattern.
Can you confirm it's correct?
mfd: system-controller@1fbf0200 {
compatible = "syscon", "simple-mfd";
reg = <0x0 0x1fbf0200 0x0 0xc0>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&mfd 0 13 47>;
#pwm-cells = <3>;
pio: pinctrl {
compatible = "airoha,en7581-pinctrl";
mdio_pins: mdio-pins {
mux {
function = "mdio";
groups = "mdio";
};
conf {
pins = "gpio2";
output-high;
};
};
pcie0_rst_pins: pcie0-rst-pins {
conf {
pins = "pcie_reset0";
drive-open-drain = <1>;
};
};
pcie1_rst_pins: pcie1-rst-pins {
conf {
pins = "pcie_reset1";
drive-open-drain = <1>;
};
};
};
pwm {
compatible = "airoha,en7581-pwm";
};
};
--
Ansuel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-10 10:14 ` Christian Marangi
@ 2024-10-10 10:41 ` Christian Marangi
2024-10-10 16:25 ` Lee Jones
2024-10-10 19:34 ` Linus Walleij
2 siblings, 0 replies; 19+ messages in thread
From: Christian Marangi @ 2024-10-10 10:41 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Lee Jones, Lorenzo Bianconi, Linus Walleij, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno,
Uwe Kleine-König, linux-mediatek, linux-gpio, devicetree,
linux-arm-kernel, upstream, benjamin.larsson, linux-pwm
On Thu, Oct 10, 2024 at 12:14:01PM +0200, Christian Marangi wrote:
> On Wed, Oct 09, 2024 at 11:55:50AM +0100, Lee Jones wrote:
> > On Wed, 09 Oct 2024, Lee Jones wrote:
> >
> > > On Wed, 09 Oct 2024, Lorenzo Bianconi wrote:
> > >
> > > > On Oct 02, Lee Jones wrote:
> > > > > On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> > > > >
> > > > > > From: Christian Marangi <ansuelsmth@gmail.com>
> > > > > >
> > > > > > Support for Airoha EN7581 Multi Function Device that
> > > > > > expose PINCTRL functionality and PWM functionality.
> > > > >
> > > > > The device is a jumble of pinctrl registers, some of which can oscillate.
> > > > >
> > > > > This is *still* not an MFD.
> > > > >
> > > > > If you wish to spread this functionality over 2 drivers, use syscon to
> > > > > obtain the registers and simple-mfd to automatically probe the drivers.
> > > >
> > > > Hi Lee,
> > > >
> > > > IIUC you are suggesting two possible approaches here:
> > > >
> > > > 1- have a single driver implementing both pinctrl and pwm functionalities.
> > > > This approach will not let us reuse the code for future devices that
> > > > have just one of them in common, like pwm (but we can live with that).
> > >
> > > If you can have one without the other, then they are separate devices.
> > >
> > > > 2- use a device node like the one below (something similar to [0])
> > > >
> > > > system-controller@1fbf0200 {
> > > > compatible = "syscon", "simple-mfd";
> > > > reg = <0x0 0x1fbf0200 0x0 0xc0>;
> > > >
> > > > interrupt-parent = <&gic>;
> > > > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> > > >
> > > > gpio-controller;
> > > > #gpio-cells = <2>;
> > > >
> > > > interrupt-controller;
> > > > #interrupt-cells = <2>;
> > > >
> > > > pio: pinctrl {
> > > > compatible = "airoha,en7581-pinctrl";
> > > >
> > > > [ some pinctrl properties here ]
> > > > };
> > > >
> > > > #pwm-cells = <3>;
> > > >
> > > > pwm {
> > > > compatible = "airoha,en7581-pwm";
> > > > };
> > > > };
> > > >
> > > > Please correct me if I am wrong, but using syscon/simple-mfd as compatible
> > > > string for the 'parent' device, will require to introduce the compatible strings
> > > > even for the child devices in order to probe them, correct?
> > > > If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
> > > > (this is the main reason why we introduced a full mfd driver here).
> > > >
> > > > @Rob, Krzysztof, Conor: am I right?
> > >
> > > I don't see why separate functionality shouldn't have separate
> > > compatible strings, even if the registers are together. Register layout
> > > and functionality separation are not related.
> >
> > We've been happy to support both pinctrl and pwm devices before:
> >
> > git grep "\-pinctrl\|\-pwm" -- drivers/mfd
> > git grep "\-pinctrl\|\-pwm" -- arch/*/boot/dts
> >
> > git grep "\-pinctrl" -- arch/*/boot/dts | wc -l
> > 602
> > git grep "\-pwm" -- arch/*/boot/dts | wc -l
> > 856
> >
> > What makes this particular device different to all of the others?
> >
>
> Hi Lee,
>
> this would be the final DTS following the "simple-mfd" pattern.
>
> Can you confirm it's correct?
>
> mfd: system-controller@1fbf0200 {
> compatible = "syscon", "simple-mfd";
> reg = <0x0 0x1fbf0200 0x0 0xc0>;
>
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>
> gpio-controller;
> #gpio-cells = <2>;
>
> interrupt-controller;
> #interrupt-cells = <2>;
>
> gpio-ranges = <&mfd 0 13 47>;
>
> #pwm-cells = <3>;
>
> pio: pinctrl {
> compatible = "airoha,en7581-pinctrl";
>
> mdio_pins: mdio-pins {
> mux {
> function = "mdio";
> groups = "mdio";
> };
>
> conf {
> pins = "gpio2";
> output-high;
> };
> };
>
> pcie0_rst_pins: pcie0-rst-pins {
> conf {
> pins = "pcie_reset0";
> drive-open-drain = <1>;
> };
> };
>
> pcie1_rst_pins: pcie1-rst-pins {
> conf {
> pins = "pcie_reset1";
> drive-open-drain = <1>;
> };
> };
> };
>
> pwm {
> compatible = "airoha,en7581-pwm";
> };
> };
>
Also asking to Rob, Krzysztof and Conor.
Is this DTS OK for you?
--
Ansuel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-10 10:14 ` Christian Marangi
2024-10-10 10:41 ` Christian Marangi
@ 2024-10-10 16:25 ` Lee Jones
2024-10-10 19:34 ` Linus Walleij
2 siblings, 0 replies; 19+ messages in thread
From: Lee Jones @ 2024-10-10 16:25 UTC (permalink / raw)
To: Christian Marangi
Cc: Lorenzo Bianconi, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
On Thu, 10 Oct 2024, Christian Marangi wrote:
> On Wed, Oct 09, 2024 at 11:55:50AM +0100, Lee Jones wrote:
> > On Wed, 09 Oct 2024, Lee Jones wrote:
> >
> > > On Wed, 09 Oct 2024, Lorenzo Bianconi wrote:
> > >
> > > > On Oct 02, Lee Jones wrote:
> > > > > On Tue, 01 Oct 2024, Lorenzo Bianconi wrote:
> > > > >
> > > > > > From: Christian Marangi <ansuelsmth@gmail.com>
> > > > > >
> > > > > > Support for Airoha EN7581 Multi Function Device that
> > > > > > expose PINCTRL functionality and PWM functionality.
> > > > >
> > > > > The device is a jumble of pinctrl registers, some of which can oscillate.
> > > > >
> > > > > This is *still* not an MFD.
> > > > >
> > > > > If you wish to spread this functionality over 2 drivers, use syscon to
> > > > > obtain the registers and simple-mfd to automatically probe the drivers.
> > > >
> > > > Hi Lee,
> > > >
> > > > IIUC you are suggesting two possible approaches here:
> > > >
> > > > 1- have a single driver implementing both pinctrl and pwm functionalities.
> > > > This approach will not let us reuse the code for future devices that
> > > > have just one of them in common, like pwm (but we can live with that).
> > >
> > > If you can have one without the other, then they are separate devices.
> > >
> > > > 2- use a device node like the one below (something similar to [0])
> > > >
> > > > system-controller@1fbf0200 {
> > > > compatible = "syscon", "simple-mfd";
> > > > reg = <0x0 0x1fbf0200 0x0 0xc0>;
> > > >
> > > > interrupt-parent = <&gic>;
> > > > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> > > >
> > > > gpio-controller;
> > > > #gpio-cells = <2>;
> > > >
> > > > interrupt-controller;
> > > > #interrupt-cells = <2>;
> > > >
> > > > pio: pinctrl {
> > > > compatible = "airoha,en7581-pinctrl";
> > > >
> > > > [ some pinctrl properties here ]
> > > > };
> > > >
> > > > #pwm-cells = <3>;
> > > >
> > > > pwm {
> > > > compatible = "airoha,en7581-pwm";
> > > > };
> > > > };
> > > >
> > > > Please correct me if I am wrong, but using syscon/simple-mfd as compatible
> > > > string for the 'parent' device, will require to introduce the compatible strings
> > > > even for the child devices in order to probe them, correct?
> > > > If so, as pointed out by Christian, this is something nacked by Rob/Krzysztof/Conor
> > > > (this is the main reason why we introduced a full mfd driver here).
> > > >
> > > > @Rob, Krzysztof, Conor: am I right?
> > >
> > > I don't see why separate functionality shouldn't have separate
> > > compatible strings, even if the registers are together. Register layout
> > > and functionality separation are not related.
> >
> > We've been happy to support both pinctrl and pwm devices before:
> >
> > git grep "\-pinctrl\|\-pwm" -- drivers/mfd
> > git grep "\-pinctrl\|\-pwm" -- arch/*/boot/dts
> >
> > git grep "\-pinctrl" -- arch/*/boot/dts | wc -l
> > 602
> > git grep "\-pwm" -- arch/*/boot/dts | wc -l
> > 856
> >
> > What makes this particular device different to all of the others?
> >
>
> Hi Lee,
>
> this would be the final DTS following the "simple-mfd" pattern.
>
> Can you confirm it's correct?
I can't confirm that it's 100% correct, but it looks okay to me.
> mfd: system-controller@1fbf0200 {
Not sure about the mfd: label though.
What is the device?
> compatible = "syscon", "simple-mfd";
> reg = <0x0 0x1fbf0200 0x0 0xc0>;
>
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>
> gpio-controller;
> #gpio-cells = <2>;
>
> interrupt-controller;
> #interrupt-cells = <2>;
>
> gpio-ranges = <&mfd 0 13 47>;
>
> #pwm-cells = <3>;
>
> pio: pinctrl {
> compatible = "airoha,en7581-pinctrl";
>
> mdio_pins: mdio-pins {
> mux {
> function = "mdio";
> groups = "mdio";
> };
>
> conf {
> pins = "gpio2";
> output-high;
> };
> };
>
> pcie0_rst_pins: pcie0-rst-pins {
> conf {
> pins = "pcie_reset0";
> drive-open-drain = <1>;
> };
> };
>
> pcie1_rst_pins: pcie1-rst-pins {
> conf {
> pins = "pcie_reset1";
> drive-open-drain = <1>;
> };
> };
> };
>
> pwm {
> compatible = "airoha,en7581-pwm";
> };
> };
>
> --
> Ansuel
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-10 10:14 ` Christian Marangi
2024-10-10 10:41 ` Christian Marangi
2024-10-10 16:25 ` Lee Jones
@ 2024-10-10 19:34 ` Linus Walleij
2024-10-10 21:41 ` Lorenzo Bianconi
2 siblings, 1 reply; 19+ messages in thread
From: Linus Walleij @ 2024-10-10 19:34 UTC (permalink / raw)
To: Christian Marangi
Cc: Lee Jones, Lorenzo Bianconi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
On Thu, Oct 10, 2024 at 12:14 PM Christian Marangi <ansuelsmth@gmail.com> wrote:
> mfd: system-controller@1fbf0200 {
Drop the mfd: thing, you probably don't want to reference the syscon
node directly
in the device tree. If you still give it a label just say
en7581_syscon: system-controller...
> compatible = "syscon", "simple-mfd";
> reg = <0x0 0x1fbf0200 0x0 0xc0>;
>
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>
> gpio-controller;
> #gpio-cells = <2>;
>
> interrupt-controller;
> #interrupt-cells = <2>;
>
> gpio-ranges = <&mfd 0 13 47>;
I think you want a separate GPIO node inside the system controller:
en7581_gpio: gpio {
compatible = "airhoa,en7581-gpio";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&en7581_pinctrl 0 13 47>;
};
So users pick GPIOs:
foo-gpios = <&en7581_gpio ...>;
Notice that the gpio-ranges should refer to the pin controller
node.
>
> #pwm-cells = <3>;
Shouldn't this be inside the pwm node?
en7581_pwm: pwm {
compatible = "airoha,en7581-pwm";
#pwm-cells = <3>;
};
So PWM users can pick a PWM with pwms = <&en7581_pwm ...>;
> pio: pinctrl {
I would use the label en7581_pinctrl:
> compatible = "airoha,en7581-pinctrl";
>
> mdio_pins: mdio-pins {
> mux {
> function = "mdio";
> groups = "mdio";
> };
>
> conf {
> pins = "gpio2";
> output-high;
> };
> };
>
> pcie0_rst_pins: pcie0-rst-pins {
> conf {
> pins = "pcie_reset0";
> drive-open-drain = <1>;
> };
> };
>
> pcie1_rst_pins: pcie1-rst-pins {
> conf {
> pins = "pcie_reset1";
> drive-open-drain = <1>;
> };
> };
> };
>
> pwm {
> compatible = "airoha,en7581-pwm";
> };
> };
This will make subdevices probe and you can put the pure GPIO
driver in drivers/gpio/gpio-en7581.c
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-10 19:34 ` Linus Walleij
@ 2024-10-10 21:41 ` Lorenzo Bianconi
2024-10-11 6:51 ` Linus Walleij
0 siblings, 1 reply; 19+ messages in thread
From: Lorenzo Bianconi @ 2024-10-10 21:41 UTC (permalink / raw)
To: Linus Walleij
Cc: Christian Marangi, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
[-- Attachment #1: Type: text/plain, Size: 3479 bytes --]
> On Thu, Oct 10, 2024 at 12:14 PM Christian Marangi <ansuelsmth@gmail.com> wrote:
>
> > mfd: system-controller@1fbf0200 {
>
> Drop the mfd: thing, you probably don't want to reference the syscon
> node directly
> in the device tree. If you still give it a label just say
> en7581_syscon: system-controller...
ack, I am fine with it.
>
> > compatible = "syscon", "simple-mfd";
> > reg = <0x0 0x1fbf0200 0x0 0xc0>;
> >
> > interrupt-parent = <&gic>;
> > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> >
> > gpio-controller;
> > #gpio-cells = <2>;
> >
> > interrupt-controller;
> > #interrupt-cells = <2>;
> >
> > gpio-ranges = <&mfd 0 13 47>;
>
> I think you want a separate GPIO node inside the system controller:
>
> en7581_gpio: gpio {
> compatible = "airhoa,en7581-gpio";
> interrupt-parent = <&gic>;
> interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>
> gpio-controller;
> #gpio-cells = <2>;
>
> interrupt-controller;
> #interrupt-cells = <2>;
>
> gpio-ranges = <&en7581_pinctrl 0 13 47>;
> };
So far I implemented the gpio functionalities in the en7581 pinctrl driver
(as it is done for other mtk pinctrl drivers) but I am fine to reuse the
gpio-en7523 driver for it. Do you prefer this second approach?
>
> So users pick GPIOs:
>
> foo-gpios = <&en7581_gpio ...>;
>
> Notice that the gpio-ranges should refer to the pin controller
> node.
>
> >
> > #pwm-cells = <3>;
>
> Shouldn't this be inside the pwm node?
>
> en7581_pwm: pwm {
> compatible = "airoha,en7581-pwm";
> #pwm-cells = <3>;
> };
>
> So PWM users can pick a PWM with pwms = <&en7581_pwm ...>;
ack, I am fine with it.
>
> > pio: pinctrl {
>
> I would use the label en7581_pinctrl:
ack, I am fine with it.
>
> > compatible = "airoha,en7581-pinctrl";
> >
> > mdio_pins: mdio-pins {
> > mux {
> > function = "mdio";
> > groups = "mdio";
> > };
> >
> > conf {
> > pins = "gpio2";
> > output-high;
> > };
> > };
> >
> > pcie0_rst_pins: pcie0-rst-pins {
> > conf {
> > pins = "pcie_reset0";
> > drive-open-drain = <1>;
> > };
> > };
> >
> > pcie1_rst_pins: pcie1-rst-pins {
> > conf {
> > pins = "pcie_reset1";
> > drive-open-drain = <1>;
> > };
> > };
> > };
> >
> > pwm {
> > compatible = "airoha,en7581-pwm";
> > };
> > };
>
> This will make subdevices probe and you can put the pure GPIO
> driver in drivers/gpio/gpio-en7581.c
We could actually reuse gpio-en7523 driver (removing the gpio part from en7581
pinctrl driver) and extend it to support irq_chip. I do not have a strong
opinion about it.
Regards,
Lorenzo
>
> Yours,
> Linus Walleij
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD
2024-10-10 21:41 ` Lorenzo Bianconi
@ 2024-10-11 6:51 ` Linus Walleij
0 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2024-10-11 6:51 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Christian Marangi, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Uwe Kleine-König, linux-mediatek,
linux-gpio, devicetree, linux-arm-kernel, upstream,
benjamin.larsson, linux-pwm
On Thu, Oct 10, 2024 at 11:41 PM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
> > On Thu, Oct 10, 2024 at 12:14 PM Christian Marangi <ansuelsmth@gmail.com> wrote:
> > I think you want a separate GPIO node inside the system controller:
> >
> > en7581_gpio: gpio {
> > compatible = "airhoa,en7581-gpio";
> > interrupt-parent = <&gic>;
> > interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
> >
> > gpio-controller;
> > #gpio-cells = <2>;
> >
> > interrupt-controller;
> > #interrupt-cells = <2>;
> >
> > gpio-ranges = <&en7581_pinctrl 0 13 47>;
> > };
>
> So far I implemented the gpio functionalities in the en7581 pinctrl driver
> (as it is done for other mtk pinctrl drivers) but I am fine to reuse the
> gpio-en7523 driver for it. Do you prefer this second approach?
It's fine to combine GPIO and pin control into the same node, especially
if you will have a combined driver for it, then it's more or less mandatory.
I only wrote this looking at ansuel's sketch.
> > This will make subdevices probe and you can put the pure GPIO
> > driver in drivers/gpio/gpio-en7581.c
>
> We could actually reuse gpio-en7523 driver (removing the gpio part from en7581
> pinctrl driver) and extend it to support irq_chip. I do not have a strong
> opinion about it.
Code reuse is always preferred, if possible.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2024-10-11 6:52 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-01 17:29 [PATCH v5 0/5] Add mfd, pinctrl and pwm support to EN7581 SoC Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 1/5] dt-bindings: arm: airoha: Add the chip-scu node for " Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 2/5] dt-bindings: mfd: Add support for Airoha EN7581 GPIO System Controller Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 3/5] mfd: airoha: Add support for Airoha EN7581 MFD Lorenzo Bianconi
2024-10-02 13:25 ` Lee Jones
2024-10-02 22:42 ` Christian Marangi
2024-10-08 22:04 ` Lorenzo Bianconi
2024-10-09 10:48 ` Lee Jones
2024-10-09 10:55 ` Lee Jones
2024-10-10 10:14 ` Christian Marangi
2024-10-10 10:41 ` Christian Marangi
2024-10-10 16:25 ` Lee Jones
2024-10-10 19:34 ` Linus Walleij
2024-10-10 21:41 ` Lorenzo Bianconi
2024-10-11 6:51 ` Linus Walleij
2024-10-01 17:29 ` [PATCH v5 4/5] pinctrl: airoha: Add support for EN7581 SoC Lorenzo Bianconi
2024-10-02 13:27 ` Linus Walleij
2024-10-02 15:37 ` Lorenzo Bianconi
2024-10-01 17:29 ` [PATCH v5 5/5] pwm: " Lorenzo Bianconi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).