Starfive JH8100 SoC consists of 4 pinctrl domains - sys_east,
sys_west, sys_gmac, and aon. This patch series adds pinctrl
drivers for these 4 pinctrl domains and this patch series is
depending on the JH8100 base patch series in [1] and [2].
The relevant dt-binding documentation for each pinctrl domain has
been updated accordingly.
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]/
---
Changes in v3:
- Replace "additionalProperties: false" in dt-bindings docs by
"unevaluatedProperties: false" to allow reference to properties in generic
pinmux and pincfg schema.
- Remove redundant keyword "allOf" from the "compatible" property definition.
- Drop all PAD_GPIO*_* macros from dt-bindings header "starfive,jh8100-pinctrl.h"
and move them to DTS header "jh8100-pinfunc.h".
- Drop "GPOUT_LOW", "GPOUT_HIGH", "GPOEN_ENABLE", "GPOEN_DISABLE", and "GPI_NONE"
from dt-bindings header.
- Add macros "PAD_SLEW_RATE_FAST"and "PAD_SLEW_RATE_SLOW" to dt-bindings header.
- Change the commit message of the main driver and sys_east domain subdriver to
inform what SoC they run on, and to explain that the main driver provides
common APIs to all domain subdrivers to perform their respective tasks,
and how the main driver and domain drivers work together.
- Add macros JH8100_SYS_E_NGPIO, JH8100_SYS_W_NGPIO, JH8100_SYS_G_NGPIO,
JH8100_AON_NGPIO to header pinctrl-starfive-jh8100.h to represent total
number of GPIO_PADs in sys-east, sys-west, sys-gmac, and aon (always-on)
domains.
- In function jh8100_get_padcfg_base() of main driver, macros: PAD_GPIO47_E,
PAD_GPIO15_W, PAD_RGPIO15 are replaced by JH8100_SYS_E_NGPIO,
JH8100_SYS_W_NGPIO, and JH8100_AON_NGPIO respectively.
- Add function jh8100_padcfg_ds_from_uA() to main driver to convert uA
(microamperes) from dts property drive-strength-microamp to drive strength
value when setting the pin configuration register.
- Add function jh8100_padcfg_ds_to_uA() to main driver to convert drive
strength value from pin configuration register to uA (microamperes) when
reading pin configuration.
- Remove "of_gpio.h" and use only the gpiod interfaces in
<linux/gpio/consumer.h>.
- Remove cross-include "../core.h" from the main driver and move it to
header "pinctrl-starfive-jh8100.h".
- Remove cross-include "../pinctrl-utils.h" from the main driver and
add the function prototype "pinctrl_utils_free_map()" to header
"pinctrl-starfive-jh8100.h".
- Remove cross-include "../pinmux.h" from the main driver and add the
"pinmux_generic_*" function prototypes to header "pinctrl-starfive-jh8100.h".
- Remove cross-include “../pinconf.h” from the main driver and add the
function prototype "pinconf_generic_parse_dt_config()" to header
"pinctrl-starfive-jh8100.h".
- Replace "GPOUT_LOW", "GPOUT_HIGH", "GPOEN_ENABLE", "GPOEN_DISABLE", and
"GPI_NONE" in the main driver by constant numbers 0, 1, 0, 1, and 255
respectively.
- Update function jh8100_get_padcfg_base() to return base address of pad
configuration registers for sys-west and aon domains.
- Update function jh8100_set_one_pin_mux() to support pad function selection
in sys-west domain.
- Update function jh8100_gpio_direction_output() to remove
JH8100_PADCFG_BIAS_MASK from mask so that when gpioset configure a pin
as output, the pin bias setting (pull-up/pull-down) will not be cleared
by the driver.
- Remove function jh8100_gpio_irq_setup() and the GPIO wakeup irq
enablement in probe function from main driver. It is replaced by
function gpiochip_wakeup_irq_setup() in gpiolib core
"drivers/gpio/gpiolib.c".
The function gpiochip_wakeup_irq_setup() is added as the wakeup gpio
irq setup function in the gpiolib core.
- The interrupt handler jh8100_gpio_wake_irq_handler() in the main driver
is removed. It is replaced by gpio_wake_irq_handler() in gpiolib core
"drivers/gpio/gpiolib.c".
- Remove the inline function pin_to_hwirq() from driver header file
"pinctrl-starfive-jh8100.h".
- Remove cross-include "../core.h", “../pinmux.h”, and “../pinconf.h” from
the sys-east, sys-west, sys-gmac, and aon domain sub-drivers.
- In sys_east domain sub-driver, macros PAD_GPIO0_E through PAD_GPIO47_E are
replaced by constant numbers 0 through 47.
- In sys_west domain sub-driver, macros PAD_GPIO0_W through PAD_GPIO15_W are
replaced by constant numbers 0 through 15.
- In AON domain sub-driver, macros PAD_RGPIO0 through PAD_RGPIO15 are
replaced by constant numbers 0 through 15.
Changes in v2:
- Add "(always-on)" to document title to clarify acronym AON.
- Replace "drive-strength" by "drive-strength-microamp".
- Update "slew-rate" property in sys-east, sys-west, and aon document.
- remove redundant "bindings" from commit subject and message.
- Change regular expression "-[0-9]+$" to "-grp$" to standardize client
node names to end with suffix "-grp" instead of "-<numerical _number>".
- Use 4 spaces indentation for DTS examples.
- Update DTS examples in sys-east, sys-west, and aon document with client
driver pinmuxing.
- Remove redundant syscon and gmac macros from dt-binding header file.
- Remove redundant register macros from dt-binding header file.
- Add "wakeup-gpios" and "wakeup-source" to aon document.
- Add "gpio-line-names" to sys-east and sys-west document.
- Update the description of syscon register usage in each document.
- Update sys-gmac and aon document with information of GMAC voltage.
reference syscon and GMAC pad syscon.
- Fix the pinctrl device nodes compatible string too long issue.
- Move all common codes from subdrivers to the main driver.
- Change the commit log to "add main and sys_east driver" to indicate
the commit of both main and sys-east driver.
- Turn pin_to_hwirq macro to a static inline function to hide gpio
internal detail, and also, for easier code readability.
- Change "JH8100_PADCFG_BIAS" to "JH8100_PADCFG_BIAS_MASK".
- Change "#define JH8100_PADCFG_DS_4MA BIT(1)" to
#define JH8100_PADCFG_DS_4MA (1U << 1)".
- Replace "jh8100_gpio_request" by "pinctrl_gpio_request".
- Replace "jh8100_gpio_free" by "pinctrl_gpio_free".
- Replace "jh8100_gpio_set_config" by "gpiochip_generic_config".
- Use irq_print_chip function to display irqchip name to user space.
- Use girq to represent GPIO interrupt controller.
- Update code to ensure wakeup-gpios is always an input line.
- Remove the jh8100_gpio_add_pin_ranges function and use gpio-ranges
in device tree to provide information for GPIO core to add pin range
for each pinctrl.
- Change "StarFive GPIO chip registered" to "StarFive JH8100 GPIO chip
registered".
---
Alex Soo (7):
dt-bindings: pinctrl: starfive: Add JH8100 pinctrl
pinctrl: starfive: jh8100: add main driver and sys_east domain
sub-driver
pinctrl: starfive: jh8100: add sys_west domain sub-driver
pinctrl: starfive: jh8100: add sys_gmac domain sub-driver
pinctrl: starfive: jh8100: add AON domain sub-driver
gpiolib: enable GPIO interrupt to wake up a system from sleep
riscv: dts: starfive: jh8100: add pinctrl device tree nodes
.../pinctrl/starfive,jh8100-aon-pinctrl.yaml | 260 ++++
.../starfive,jh8100-sys-east-pinctrl.yaml | 222 ++++
.../starfive,jh8100-sys-gmac-pinctrl.yaml | 162 +++
.../starfive,jh8100-sys-west-pinctrl.yaml | 219 ++++
MAINTAINERS | 7 +
arch/riscv/boot/dts/starfive/jh8100-evb.dts | 7 +
arch/riscv/boot/dts/starfive/jh8100-pinfunc.h | 504 ++++++++
arch/riscv/boot/dts/starfive/jh8100.dtsi | 46 +
drivers/gpio/gpiolib.c | 87 ++
drivers/pinctrl/starfive/Kconfig | 59 +
drivers/pinctrl/starfive/Makefile | 6 +
.../starfive/pinctrl-starfive-jh8100-aon.c | 150 +++
.../pinctrl-starfive-jh8100-sys-east.c | 220 ++++
.../pinctrl-starfive-jh8100-sys-gmac.c | 89 ++
.../pinctrl-starfive-jh8100-sys-west.c | 164 +++
.../starfive/pinctrl-starfive-jh8100.c | 1103 +++++++++++++++++
.../starfive/pinctrl-starfive-jh8100.h | 125 ++
.../pinctrl/starfive,jh8100-pinctrl.h | 13 +
18 files changed, 3443 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml
create mode 100644 arch/riscv/boot/dts/starfive/jh8100-pinfunc.h
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-aon.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-east.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-gmac.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-west.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
create mode 100644 include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
--
2.43.2
Add sys_gmac domain sub-driver.
Signed-off-by: Alex Soo <[email protected]>
---
drivers/pinctrl/starfive/Kconfig | 12 +++
drivers/pinctrl/starfive/Makefile | 1 +
.../pinctrl-starfive-jh8100-sys-gmac.c | 89 +++++++++++++++++++
.../starfive/pinctrl-starfive-jh8100.h | 4 +
4 files changed, 106 insertions(+)
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-gmac.c
diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index d78f161a636c..bc123c0bf35e 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -82,3 +82,15 @@ config PINCTRL_STARFIVE_JH8100_SYS_WEST
This also provides an interface to the GPIO pins not used by other
peripherals supporting inputs, outputs, configuring pull-up/pull-down
and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JH8100_SYS_GMAC
+ tristate "StarFive JH8100 SoC System IOMUX-GMAC pinctrl and GPIO driver"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ depends on OF
+ select PINCTRL_STARFIVE_JH8100
+ default ARCH_STARFIVE
+ help
+ Say yes here to support system iomux-gmac pin control on the StarFive JH8100 SoC.
+ This provides syscon registers to indicate voltage level on SDIO1/GMAC1, to indicate
+ GMAC1 pads voltage level under different GMAC interface modes, and to configure
+ GMAC1 interface slew rate.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 784465157ae2..236a693a8aef 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON) += pinctrl-starfive-jh7110-aon.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH8100) += pinctrl-starfive-jh8100.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_EAST) += pinctrl-starfive-jh8100-sys-east.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_WEST) += pinctrl-starfive-jh8100-sys-west.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_GMAC) += pinctrl-starfive-jh8100-sys-gmac.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-gmac.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-gmac.c
new file mode 100644
index 000000000000..3758280e3660
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-gmac.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JH8100 SoC sys gmac controller
+ *
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <[email protected]>
+ *
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/pinctrl/starfive,jh8100-pinctrl.h>
+
+#include "pinctrl-starfive-jh8100.h"
+
+#define JH8100_SYS_G_GC_BASE -1
+#define JH8100_SYS_G_DOMAIN_NAME "jh8100-sys-gmac"
+
+#ifdef CONFIG_PM_SLEEP
+static int jh8100_sys_gmac_pinctrl_suspend(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ sfp->jh8100_sys_gmac_regs[i] = readl_relaxed(sfp->base + (i * 4));
+
+ return pinctrl_force_sleep(sfp->pctl);
+}
+
+static int jh8100_sys_gmac_pinctrl_resume(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ writel_relaxed(sfp->jh8100_sys_gmac_regs[i], sfp->base + (i * 4));
+
+ return pinctrl_force_default(sfp->pctl);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(jh8100_sys_gmac_pinctrl_dev_pm_ops,
+ jh8100_sys_gmac_pinctrl_suspend,
+ jh8100_sys_gmac_pinctrl_resume);
+
+static const struct jh8100_pinctrl_domain_info jh8100_sys_gmac_pinctrl_info = {
+ .ngpios = JH8100_SYS_G_NGPIO,
+ .gc_base = JH8100_SYS_G_GC_BASE,
+ .name = JH8100_SYS_G_DOMAIN_NAME,
+ .nregs = JH8100_SYS_G_REG_NUM,
+};
+
+static const struct of_device_id jh8100_sys_gmac_pinctrl_of_match[] = {
+ {
+ .compatible = "starfive,jh8100-sys-pinctrl-gmac",
+ .data = &jh8100_sys_gmac_pinctrl_info,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh8100_sys_gmac_pinctrl_of_match);
+
+static struct platform_driver jh8100_sys_gmac_pinctrl_driver = {
+ .probe = jh8100_pinctrl_probe,
+ .driver = {
+ .name = "starfive-jh8100-sys-pinctrl-gmac",
+#ifdef CONFIG_PM_SLEEP
+ .pm = &jh8100_sys_gmac_pinctrl_dev_pm_ops,
+#endif
+ .of_match_table = jh8100_sys_gmac_pinctrl_of_match,
+ },
+};
+module_platform_driver(jh8100_sys_gmac_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JH8100 SoC sys gmac controller");
+MODULE_AUTHOR("Alex Soo <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
index 7c7a05c1c828..90eef6417dd7 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
@@ -14,12 +14,15 @@
#define JH8100_SYS_W_DOMAIN_NAME "jh8100-sys-west"
#define JH8100_SYS_E_DOMAIN_NAME "jh8100-sys-east"
+#define JH8100_SYS_G_DOMAIN_NAME "jh8100-sys-gmac"
#define JH8100_SYS_W_NGPIO 16
#define JH8100_SYS_E_NGPIO 48
+#define JH8100_SYS_G_NGPIO 0
#define JH8100_SYS_W_REG_NUM 44
#define JH8100_SYS_E_REG_NUM 116
+#define JH8100_SYS_G_REG_NUM 19
#define JH8100_SYS_W_GPO_PDA_00_15_CFG 0x074
#define JH8100_SYS_E_GPO_PDA_00_47_CFG 0x114
@@ -36,6 +39,7 @@ struct jh8100_pinctrl {
const struct jh8100_pinctrl_domain_info *info;
unsigned int jh8100_sys_west_regs[JH8100_SYS_W_REG_NUM];
unsigned int jh8100_sys_east_regs[JH8100_SYS_E_REG_NUM];
+ unsigned int jh8100_sys_gmac_regs[JH8100_SYS_G_REG_NUM];
/* wakeup */
struct irq_domain *irq_domain;
struct gpio_desc *wakeup_gpio;
--
2.25.1
Add Starfive JH8100 SoC pinctrl main driver to provide the
common APIs that are used by the sub-drivers of pinctrl
domains:
- sys_east,
- sys_west,
- sys_gmac,
- aon (always-on)
to implement the following tasks:
- applies pin multiplexing, function selection, and pin
configuration for devices during system initialization
or change of pinctrl state due to power management.
- read or set pin configuration from user space.
Also, add the sys_east domain sub-driver since it requires
at least one domain sub-driver to run the probe function in
the main driver to enable the basic pinctrl functionalities
on the system.
Signed-off-by: Alex Soo <[email protected]>
---
drivers/pinctrl/starfive/Kconfig | 21 +
drivers/pinctrl/starfive/Makefile | 3 +
.../pinctrl-starfive-jh8100-sys-east.c | 220 ++++
.../starfive/pinctrl-starfive-jh8100.c | 1094 +++++++++++++++++
.../starfive/pinctrl-starfive-jh8100.h | 111 ++
5 files changed, 1449 insertions(+)
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-east.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 8192ac2087fc..afcbf9d4dc8d 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -49,3 +49,24 @@ config PINCTRL_STARFIVE_JH7110_AON
This also provides an interface to the GPIO pins not used by other
peripherals supporting inputs, outputs, configuring pull-up/pull-down
and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JH8100
+ bool
+ select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select OF_GPIO
+
+config PINCTRL_STARFIVE_JH8100_SYS_EAST
+ tristate "StarFive JH8100 SoC System IOMUX-East pinctrl and GPIO driver"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ depends on OF
+ select PINCTRL_STARFIVE_JH8100
+ default ARCH_STARFIVE
+ help
+ Say yes here to support system iomux-east pin control on the StarFive JH8100 SoC.
+ This also provides an interface to the GPIO pins not used by other
+ peripherals supporting inputs, outputs, configuring pull-up/pull-down
+ and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index ee0d32d085cb..45698c502b48 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -5,3 +5,6 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7100) += pinctrl-starfive-jh7100.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH7110) += pinctrl-starfive-jh7110.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS) += pinctrl-starfive-jh7110-sys.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON) += pinctrl-starfive-jh7110-aon.o
+
+obj-$(CONFIG_PINCTRL_STARFIVE_JH8100) += pinctrl-starfive-jh8100.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_EAST) += pinctrl-starfive-jh8100-sys-east.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-east.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-east.c
new file mode 100644
index 000000000000..45ade4d68d66
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-east.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JH8100 SoC sys east controller
+ *
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <[email protected]>
+ *
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/pinctrl/starfive,jh8100-pinctrl.h>
+
+#include "pinctrl-starfive-jh8100.h"
+
+#define JH8100_SYS_E_GC_BASE 16
+
+/* registers */
+#define JH8100_SYS_E_DOEN 0x000
+#define JH8100_SYS_E_DOUT 0x030
+#define JH8100_SYS_E_GPI 0x060
+#define JH8100_SYS_E_GPIOIN 0x0f4
+
+#define JH8100_SYS_E_GPIOEN 0x0b8
+#define JH8100_SYS_E_GPIOIS0 0x0bc
+#define JH8100_SYS_E_GPIOIS1 0x0c0
+#define JH8100_SYS_E_GPIOIC0 0x0c4
+#define JH8100_SYS_E_GPIOIC1 0x0c8
+#define JH8100_SYS_E_GPIOIBE0 0x0cc
+#define JH8100_SYS_E_GPIOIBE1 0x0d0
+#define JH8100_SYS_E_GPIOIEV0 0x0d4
+#define JH8100_SYS_E_GPIOIEV1 0x0d8
+#define JH8100_SYS_E_GPIOIE0 0x0dc
+#define JH8100_SYS_E_GPIOIE1 0x0e0
+#define JH8100_SYS_E_GPIORIS0 0x0e4
+#define JH8100_SYS_E_GPIORIS1 0x0e8
+#define JH8100_SYS_E_GPIOMIS0 0x0ec
+#define JH8100_SYS_E_GPIOMIS1 0x0f0
+
+static const struct pinctrl_pin_desc jh8100_sys_e_pins[] = {
+ PINCTRL_PIN(0, "SYS_E_GPIO0"),
+ PINCTRL_PIN(1, "SYS_E_GPIO1"),
+ PINCTRL_PIN(2, "SYS_E_GPIO2"),
+ PINCTRL_PIN(3, "SYS_E_GPIO3"),
+ PINCTRL_PIN(4, "SYS_E_GPIO4"),
+ PINCTRL_PIN(5, "SYS_E_GPIO5"),
+ PINCTRL_PIN(6, "SYS_E_GPIO6"),
+ PINCTRL_PIN(7, "SYS_E_GPIO7"),
+ PINCTRL_PIN(8, "SYS_E_GPIO8"),
+ PINCTRL_PIN(9, "SYS_E_GPIO9"),
+ PINCTRL_PIN(10, "SYS_E_GPIO10"),
+ PINCTRL_PIN(11, "SYS_E_GPIO11"),
+ PINCTRL_PIN(12, "SYS_E_GPIO12"),
+ PINCTRL_PIN(13, "SYS_E_GPIO13"),
+ PINCTRL_PIN(14, "SYS_E_GPIO14"),
+ PINCTRL_PIN(15, "SYS_E_GPIO15"),
+ PINCTRL_PIN(16, "SYS_E_GPIO16"),
+ PINCTRL_PIN(17, "SYS_E_GPIO17"),
+ PINCTRL_PIN(18, "SYS_E_GPIO18"),
+ PINCTRL_PIN(19, "SYS_E_GPIO19"),
+ PINCTRL_PIN(20, "SYS_E_GPIO20"),
+ PINCTRL_PIN(21, "SYS_E_GPIO21"),
+ PINCTRL_PIN(22, "SYS_E_GPIO22"),
+ PINCTRL_PIN(23, "SYS_E_GPIO23"),
+ PINCTRL_PIN(24, "SYS_E_GPIO24"),
+ PINCTRL_PIN(25, "SYS_E_GPIO25"),
+ PINCTRL_PIN(26, "SYS_E_GPIO26"),
+ PINCTRL_PIN(27, "SYS_E_GPIO27"),
+ PINCTRL_PIN(28, "SYS_E_GPIO28"),
+ PINCTRL_PIN(29, "SYS_E_GPIO29"),
+ PINCTRL_PIN(30, "SYS_E_GPIO30"),
+ PINCTRL_PIN(31, "SYS_E_GPIO31"),
+ PINCTRL_PIN(32, "SYS_E_GPIO32"),
+ PINCTRL_PIN(33, "SYS_E_GPIO33"),
+ PINCTRL_PIN(34, "SYS_E_GPIO34"),
+ PINCTRL_PIN(35, "SYS_E_GPIO35"),
+ PINCTRL_PIN(36, "SYS_E_GPIO36"),
+ PINCTRL_PIN(37, "SYS_E_GPIO37"),
+ PINCTRL_PIN(38, "SYS_E_GPIO38"),
+ PINCTRL_PIN(39, "SYS_E_GPIO39"),
+ PINCTRL_PIN(40, "SYS_E_GPIO40"),
+ PINCTRL_PIN(41, "SYS_E_GPIO41"),
+ PINCTRL_PIN(42, "SYS_E_GPIO42"),
+ PINCTRL_PIN(43, "SYS_E_GPIO43"),
+ PINCTRL_PIN(44, "SYS_E_GPIO44"),
+ PINCTRL_PIN(45, "SYS_E_GPIO45"),
+ PINCTRL_PIN(46, "SYS_E_GPIO46"),
+ PINCTRL_PIN(47, "SYS_E_GPIO47"),
+};
+
+static const struct jh8100_gpio_func_sel
+ jh8100_sys_e_func_sel[ARRAY_SIZE(jh8100_sys_e_pins)] = {
+ [20] = { 0x1d4, 0, 2 },
+ [21] = { 0x1d4, 2, 2 },
+ [22] = { 0x1d4, 4, 2 },
+ [23] = { 0x1d4, 6, 2 },
+ [24] = { 0x1d4, 8, 2 },
+ [25] = { 0x1d4, 10, 2 },
+ [26] = { 0x1d4, 12, 2 },
+ [27] = { 0x1d4, 14, 2 },
+ [28] = { 0x1d4, 16, 2 },
+ [29] = { 0x1d4, 18, 2 },
+ [30] = { 0x1d4, 20, 2 },
+ [31] = { 0x1d4, 22, 2 },
+ [32] = { 0x1d4, 24, 2 },
+ [33] = { 0x1d4, 26, 2 },
+ [34] = { 0x1d4, 28, 2 },
+ [35] = { 0x1d4, 30, 2 },
+
+ [36] = { 0x1d8, 0, 2 },
+ [37] = { 0x1d8, 2, 2 },
+ [38] = { 0x1d8, 4, 2 },
+ [39] = { 0x1d8, 6, 2 },
+ [40] = { 0x1d8, 8, 2 },
+ [41] = { 0x1d8, 10, 2 },
+ [42] = { 0x1d8, 12, 2 },
+ [43] = { 0x1d8, 14, 2 },
+ [44] = { 0x1d8, 16, 2 },
+ [45] = { 0x1d8, 18, 2 },
+ [46] = { 0x1d8, 20, 2 },
+ [47] = { 0x1d8, 22, 2 },
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int jh8100_sys_e_pinctrl_suspend(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ sfp->jh8100_sys_east_regs[i] = readl_relaxed(sfp->base + (i * 4));
+
+ return pinctrl_force_sleep(sfp->pctl);
+}
+
+static int jh8100_sys_e_pinctrl_resume(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ writel_relaxed(sfp->jh8100_sys_east_regs[i], sfp->base + (i * 4));
+
+ return pinctrl_force_default(sfp->pctl);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(jh8100_sys_e_pinctrl_dev_pm_ops,
+ jh8100_sys_e_pinctrl_suspend,
+ jh8100_sys_e_pinctrl_resume);
+
+static const struct jh8100_gpio_irq_reg jh8100_sys_e_irq_reg = {
+ .is_reg_base = JH8100_SYS_E_GPIOIS0,
+ .ic_reg_base = JH8100_SYS_E_GPIOIC0,
+ .ic1_reg_base = JH8100_SYS_E_GPIOIC1,
+ .ibe_reg_base = JH8100_SYS_E_GPIOIBE0,
+ .iev_reg_base = JH8100_SYS_E_GPIOIEV0,
+ .ie_reg_base = JH8100_SYS_E_GPIOIE0,
+ .ris_reg_base = JH8100_SYS_E_GPIORIS0,
+ .mis_reg_base = JH8100_SYS_E_GPIOMIS0,
+ .mis1_reg_base = JH8100_SYS_E_GPIOMIS1,
+ .ien_reg_base = JH8100_SYS_E_GPIOEN,
+};
+
+static const struct jh8100_pinctrl_domain_info jh8100_sys_e_pinctrl_info = {
+ .pins = jh8100_sys_e_pins,
+ .npins = ARRAY_SIZE(jh8100_sys_e_pins),
+ .ngpios = JH8100_SYS_E_NGPIO,
+ .gc_base = JH8100_SYS_E_GC_BASE,
+ .name = JH8100_SYS_E_DOMAIN_NAME,
+ .nregs = JH8100_SYS_E_REG_NUM,
+ .dout_reg_base = JH8100_SYS_E_DOUT,
+ .dout_mask = GENMASK(6, 0),
+ .doen_reg_base = JH8100_SYS_E_DOEN,
+ .doen_mask = GENMASK(5, 0),
+ .gpi_reg_base = JH8100_SYS_E_GPI,
+ .gpi_mask = GENMASK(5, 0),
+ .gpioin_reg_base = JH8100_SYS_E_GPIOIN,
+ .func_sel = jh8100_sys_e_func_sel,
+ .irq_reg = &jh8100_sys_e_irq_reg,
+ .mis_pin_num = 32,
+ .mis1_pin_num = 16,
+};
+
+static const struct of_device_id jh8100_sys_e_pinctrl_of_match[] = {
+ {
+ .compatible = "starfive,jh8100-sys-pinctrl-east",
+ .data = &jh8100_sys_e_pinctrl_info,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh8100_sys_e_pinctrl_of_match);
+
+static struct platform_driver jh8100_sys_e_pinctrl_driver = {
+ .probe = jh8100_pinctrl_probe,
+ .driver = {
+ .name = "starfive-jh8100-sys-pinctrl-east",
+#ifdef CONFIG_PM_SLEEP
+ .pm = &jh8100_sys_e_pinctrl_dev_pm_ops,
+#endif
+ .of_match_table = jh8100_sys_e_pinctrl_of_match,
+ },
+};
+module_platform_driver(jh8100_sys_e_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JH8100 SoC sys east controller");
+MODULE_AUTHOR("Alex Soo <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
new file mode 100644
index 000000000000..4b68463ff5a5
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
@@ -0,0 +1,1094 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JH8100 SoC
+ *
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <[email protected]>
+ *
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include <dt-bindings/pinctrl/starfive,jh8100-pinctrl.h>
+
+#include "pinctrl-starfive-jh8100.h"
+
+/* pad control bits */
+#define JH8100_PADCFG_POS BIT(7)
+#define JH8100_PADCFG_SMT BIT(6)
+#define JH8100_PADCFG_SLEW BIT(5)
+#define JH8100_PADCFG_PD BIT(4)
+#define JH8100_PADCFG_PU BIT(3)
+#define JH8100_PADCFG_BIAS_MASK (JH8100_PADCFG_PD | JH8100_PADCFG_PU)
+#define JH8100_PADCFG_DS_MASK GENMASK(2, 1)
+#define JH8100_PADCFG_DS_2MA (0U << 1)
+#define JH8100_PADCFG_DS_4MA (1U << 1)
+#define JH8100_PADCFG_DS_8MA (2U << 1)
+#define JH8100_PADCFG_DS_12MA (3U << 1)
+#define JH8100_PADCFG_IE BIT(0)
+
+/*
+ * The packed pinmux values from the device tree look like this:
+ *
+ * | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 |
+ * | din | dout | doen | function | pin |
+ */
+static unsigned int jh8100_pinmux_din(u32 v)
+{
+ return (v & GENMASK(31, 24)) >> 24;
+}
+
+static u32 jh8100_pinmux_dout(u32 v)
+{
+ return (v & GENMASK(23, 16)) >> 16;
+}
+
+static u32 jh8100_pinmux_doen(u32 v)
+{
+ return (v & GENMASK(15, 10)) >> 10;
+}
+
+static u32 jh8100_pinmux_function(u32 v)
+{
+ return (v & GENMASK(9, 8)) >> 8;
+}
+
+static unsigned int jh8100_pinmux_pin(u32 v)
+{
+ return v & GENMASK(7, 0);
+}
+
+static struct jh8100_pinctrl *jh8100_from_irq_data(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ return container_of(gc, struct jh8100_pinctrl, gc);
+}
+
+struct jh8100_pinctrl *jh8100_from_irq_desc(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+
+ return container_of(gc, struct jh8100_pinctrl, gc);
+}
+EXPORT_SYMBOL_GPL(jh8100_from_irq_desc);
+
+#ifdef CONFIG_DEBUG_FS
+static void jh8100_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned int pin)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct jh8100_pinctrl_domain_info *info = sfp->info;
+
+ seq_printf(s, "%s", dev_name(pctldev->dev));
+
+ if (pin < sfp->gc.ngpio) {
+ unsigned int offset = 4 * (pin / 4);
+ unsigned int shift = 8 * (pin % 4);
+ u32 dout = readl_relaxed(sfp->base + info->dout_reg_base + offset);
+ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
+ u32 gpi = readl_relaxed(sfp->base + info->gpi_reg_base + offset);
+
+ dout = (dout >> shift) & info->dout_mask;
+ doen = (doen >> shift) & info->doen_mask;
+ gpi = ((gpi >> shift) - 2) & info->gpi_mask;
+
+ seq_printf(s, " dout=%u doen=%u din=%u", dout, doen, gpi);
+ }
+}
+#else
+#define jh8100_pin_dbg_show NULL
+#endif
+
+static int jh8100_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **maps,
+ unsigned int *num_maps)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ struct device *dev = sfp->gc.parent;
+ struct device_node *child;
+ struct pinctrl_map *map;
+ const char **pgnames;
+ const char *grpname;
+ int ngroups;
+ int nmaps;
+ int ret;
+
+ ngroups = 0;
+ for_each_child_of_node(np, child)
+ ngroups += 1;
+ nmaps = 2 * ngroups;
+
+ pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);
+ if (!pgnames)
+ return -ENOMEM;
+
+ map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ nmaps = 0;
+ ngroups = 0;
+ mutex_lock(&sfp->mutex);
+ for_each_child_of_node(np, child) {
+ int npins = of_property_count_u32_elems(child, "pinmux");
+ int *pins;
+ u32 *pinmux;
+ int i;
+
+ if (npins < 1) {
+ dev_err(dev,
+ "invalid pinctrl group %pOFn.%pOFn: pinmux not set\n",
+ np, child);
+ ret = -EINVAL;
+ goto put_child;
+ }
+
+ grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child);
+ if (!grpname) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ pgnames[ngroups++] = grpname;
+
+ pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL);
+ if (!pinmux) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ ret = of_property_read_u32_array(child, "pinmux", pinmux, npins);
+ if (ret)
+ goto put_child;
+
+ for (i = 0; i < npins; i++)
+ pins[i] = jh8100_pinmux_pin(pinmux[i]);
+
+ map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
+ map[nmaps].data.mux.function = np->name;
+ map[nmaps].data.mux.group = grpname;
+ nmaps += 1;
+
+ ret = pinctrl_generic_add_group(pctldev, grpname,
+ pins, npins, pinmux);
+ if (ret < 0) {
+ dev_err(dev, "error adding group %s: %d\n", grpname, ret);
+ goto put_child;
+ }
+
+ ret = pinconf_generic_parse_dt_config(child, pctldev,
+ &map[nmaps].data.configs.configs,
+ &map[nmaps].data.configs.num_configs);
+ if (ret) {
+ dev_err(dev, "error parsing pin config of group %s: %d\n",
+ grpname, ret);
+ goto put_child;
+ }
+
+ /* don't create a map if there are no pinconf settings */
+ if (map[nmaps].data.configs.num_configs == 0)
+ continue;
+
+ map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ map[nmaps].data.configs.group_or_pin = grpname;
+ nmaps += 1;
+ }
+
+ ret = pinmux_generic_add_function(pctldev, np->name,
+ pgnames, ngroups, NULL);
+ if (ret < 0) {
+ dev_err(dev, "error adding function %s: %d\n", np->name, ret);
+ goto free_map;
+ }
+ mutex_unlock(&sfp->mutex);
+
+ *maps = map;
+ *num_maps = nmaps;
+ return 0;
+
+put_child:
+ of_node_put(child);
+free_map:
+ pinctrl_utils_free_map(pctldev, map, nmaps);
+ mutex_unlock(&sfp->mutex);
+ return ret;
+}
+
+static const struct pinctrl_ops jh8100_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .pin_dbg_show = jh8100_pin_dbg_show,
+ .dt_node_to_map = jh8100_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+void jh8100_set_gpiomux(struct jh8100_pinctrl *sfp, unsigned int pin,
+ unsigned int din, u32 dout, u32 doen)
+{
+ const struct jh8100_pinctrl_domain_info *info = sfp->info;
+
+ unsigned int offset = 4 * (pin / 4);
+ unsigned int shift = 8 * (pin % 4);
+ u32 dout_mask = info->dout_mask << shift;
+ u32 done_mask = info->doen_mask << shift;
+ u32 ival, imask;
+ u32 tmp;
+ void __iomem *reg_dout;
+ void __iomem *reg_doen;
+ void __iomem *reg_din;
+ unsigned long flags;
+
+ reg_dout = sfp->base + info->dout_reg_base + offset;
+ reg_doen = sfp->base + info->doen_reg_base + offset;
+ dout <<= shift;
+ doen <<= shift;
+ if (din != 255) {
+ unsigned int ioffset = 4 * (din / 4);
+ unsigned int ishift = 8 * (din % 4);
+
+ reg_din = sfp->base + info->gpi_reg_base + ioffset;
+ ival = (pin + 2) << ishift;
+ imask = info->gpi_mask << ishift;
+ } else {
+ reg_din = NULL;
+ }
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ dout |= readl_relaxed(reg_dout) & ~dout_mask;
+ writel_relaxed(dout, reg_dout);
+ doen |= readl_relaxed(reg_doen) & ~done_mask;
+ writel_relaxed(doen, reg_doen);
+ if (reg_din) {
+ tmp = readl_relaxed(reg_din) & ~imask;
+ writel_relaxed(tmp, reg_din);
+ ival |= readl_relaxed(reg_din) & ~imask;
+ writel_relaxed(ival, reg_din);
+ }
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh8100_set_function(struct jh8100_pinctrl *sfp,
+ unsigned int pin, u32 func)
+{
+ const struct jh8100_gpio_func_sel *fs = &sfp->info->func_sel[pin];
+ unsigned long flags;
+ void __iomem *reg;
+ u32 mask;
+
+ if (!fs->offset)
+ return;
+
+ if (func > fs->max)
+ return;
+
+ reg = sfp->base + fs->offset;
+ func = func << fs->shift;
+ mask = 0x3U << fs->shift;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ func |= readl_relaxed(reg) & ~mask;
+ writel_relaxed(func, reg);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh8100_set_one_pin_mux(struct jh8100_pinctrl *sfp,
+ unsigned int pin,
+ unsigned int din, u32 dout,
+ u32 doen, u32 func)
+{
+ if (pin < sfp->gc.ngpio && func == 0)
+ jh8100_set_gpiomux(sfp, pin, din, dout, doen);
+
+ if (!strcmp(sfp->info->name, JH8100_SYS_E_DOMAIN_NAME) &&
+ pin < sfp->gc.ngpio && func == 1)
+ jh8100_set_function(sfp, pin, func);
+
+ return 0;
+}
+
+static int jh8100_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int fsel, unsigned int gsel)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct group_desc *group;
+ const u32 *pinmux;
+ unsigned int i;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ pinmux = group->data;
+
+ for (i = 0; i < group->grp.npins; i++) {
+ u32 v = pinmux[i];
+
+ jh8100_set_one_pin_mux(sfp,
+ jh8100_pinmux_pin(v),
+ jh8100_pinmux_din(v),
+ jh8100_pinmux_dout(v),
+ jh8100_pinmux_doen(v),
+ jh8100_pinmux_function(v));
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops jh8100_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = jh8100_set_mux,
+ .strict = true,
+};
+
+static const u8 jh8100_drive_strength_mA[4] = { 2, 4, 8, 12 };
+
+static u32 jh8100_padcfg_ds_to_mA(u32 padcfg)
+{
+ return jh8100_drive_strength_mA[(padcfg >> 1) & 3U];
+}
+
+static u32 jh8100_padcfg_ds_to_uA(u32 padcfg)
+{
+ return jh8100_drive_strength_mA[(padcfg >> 1) & 3U] * 1000;
+}
+
+static u32 jh8100_padcfg_ds_from_mA(u32 v)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(jh8100_drive_strength_mA); i++) {
+ if (v <= jh8100_drive_strength_mA[i])
+ break;
+ }
+ return i << 1;
+}
+
+static u32 jh8100_padcfg_ds_from_uA(u32 v)
+{
+ /* Convert from uA to mA */
+ v /= 1000;
+
+ return jh8100_padcfg_ds_from_mA(v);
+}
+
+static int jh8100_get_padcfg_base(struct jh8100_pinctrl *sfp,
+ unsigned int pin)
+{
+ if (!strcmp(sfp->info->name, JH8100_SYS_E_DOMAIN_NAME)) {
+ if (pin < JH8100_SYS_E_NGPIO)
+ return JH8100_SYS_E_GPO_PDA_00_47_CFG;
+ }
+
+ return -ENXIO;
+}
+
+static void jh8100_padcfg_rmw(struct jh8100_pinctrl *sfp,
+ unsigned int pin, u32 mask, u32 value)
+{
+ void __iomem *reg;
+ unsigned long flags;
+ int padcfg_base;
+
+ padcfg_base = jh8100_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return;
+
+ reg = sfp->base + padcfg_base + 4 * pin;
+ value &= mask;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value |= readl_relaxed(reg) & ~mask;
+ writel_relaxed(value, reg);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh8100_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ int param = pinconf_to_config_param(*config);
+ u32 padcfg, arg;
+ bool enabled;
+ int padcfg_base;
+
+ padcfg_base = jh8100_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return 0;
+
+ padcfg = readl_relaxed(sfp->base + padcfg_base + 4 * pin);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ enabled = !(padcfg & JH8100_PADCFG_BIAS_MASK);
+ arg = 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ enabled = padcfg & JH8100_PADCFG_PD;
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ enabled = padcfg & JH8100_PADCFG_PU;
+ arg = 1;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ enabled = true;
+ arg = jh8100_padcfg_ds_to_mA(padcfg);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ enabled = true;
+ arg = jh8100_padcfg_ds_to_uA(padcfg);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ enabled = padcfg & JH8100_PADCFG_IE;
+ arg = enabled;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ enabled = padcfg & JH8100_PADCFG_SMT;
+ arg = enabled;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ enabled = true;
+ arg = !!(padcfg & JH8100_PADCFG_SLEW);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return enabled ? 0 : -EINVAL;
+}
+
+static int jh8100_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned int gpio, unsigned long *config,
+ unsigned int num_configs)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ u32 param;
+ u32 arg;
+ u32 value;
+ u32 mask;
+ int i;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(config[i]);
+ arg = pinconf_to_config_argument(config[i]);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ mask = JH8100_PADCFG_BIAS_MASK;
+ value = 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask = JH8100_PADCFG_BIAS_MASK;
+ value = JH8100_PADCFG_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask = JH8100_PADCFG_BIAS_MASK;
+ value = JH8100_PADCFG_PU;
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return 0;
+ case PIN_CONFIG_INPUT_ENABLE:
+ mask = JH8100_PADCFG_IE;
+ value = arg ? JH8100_PADCFG_IE : 0;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ mask = JH8100_PADCFG_SMT;
+ value = arg ? JH8100_PADCFG_SMT : 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ jh8100_padcfg_rmw(sfp, gpio, mask, value);
+ }
+
+ return 0;
+}
+
+static int jh8100_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned int gsel,
+ unsigned long *config)
+{
+ const struct group_desc *group;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ return jh8100_pinconf_get(pctldev, group->grp.pins[0], config);
+}
+
+static int jh8100_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int gsel,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct group_desc *group;
+ u16 mask, value;
+ int i;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ mask = 0;
+ value = 0;
+ for (i = 0; i < num_configs; i++) {
+ int param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ mask |= JH8100_PADCFG_BIAS_MASK;
+ value &= ~JH8100_PADCFG_BIAS_MASK;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask |= JH8100_PADCFG_BIAS_MASK;
+ value = (value & ~JH8100_PADCFG_BIAS_MASK) | JH8100_PADCFG_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask |= JH8100_PADCFG_BIAS_MASK;
+ value = (value & ~JH8100_PADCFG_BIAS_MASK) | JH8100_PADCFG_PU;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ mask |= JH8100_PADCFG_DS_MASK;
+ value = (value & ~JH8100_PADCFG_DS_MASK) |
+ jh8100_padcfg_ds_from_mA(arg);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ mask |= JH8100_PADCFG_DS_MASK;
+ value = (value & ~JH8100_PADCFG_DS_MASK) |
+ jh8100_padcfg_ds_from_uA(arg);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ mask |= JH8100_PADCFG_IE;
+ if (arg)
+ value |= JH8100_PADCFG_IE;
+ else
+ value &= ~JH8100_PADCFG_IE;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ mask |= JH8100_PADCFG_SMT;
+ if (arg)
+ value |= JH8100_PADCFG_SMT;
+ else
+ value &= ~JH8100_PADCFG_SMT;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ mask |= JH8100_PADCFG_SLEW;
+ if (arg)
+ value |= JH8100_PADCFG_SLEW;
+ else
+ value &= ~JH8100_PADCFG_SLEW;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ for (i = 0; i < group->grp.npins; i++)
+ jh8100_padcfg_rmw(sfp, group->grp.pins[i], mask, value);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void jh8100_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned int pin)
+{
+ struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ u32 value;
+ int padcfg_base;
+
+ padcfg_base = jh8100_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return;
+
+ value = readl_relaxed(sfp->base + padcfg_base + 4 * pin);
+ seq_printf(s, " (0x%02x)", value);
+}
+#else
+#define jh8100_pinconf_dbg_show NULL
+#endif
+
+static const struct pinconf_ops jh8100_pinconf_ops = {
+ .pin_config_get = jh8100_pinconf_get,
+ .pin_config_set = jh8100_pinconf_set,
+ .pin_config_group_get = jh8100_pinconf_group_get,
+ .pin_config_group_set = jh8100_pinconf_group_set,
+ .pin_config_dbg_show = jh8100_pinconf_dbg_show,
+ .is_generic = true,
+};
+
+static int jh8100_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+ const struct jh8100_pinctrl_domain_info *info = sfp->info;
+ unsigned int offset = 4 * (gpio / 4);
+ unsigned int shift = 8 * (gpio % 4);
+ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
+
+ doen = (doen >> shift) & info->doen_mask;
+
+ return doen == 0 ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int jh8100_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+
+ /* enable input and schmitt trigger */
+ jh8100_padcfg_rmw(sfp, gpio,
+ JH8100_PADCFG_IE | JH8100_PADCFG_SMT,
+ JH8100_PADCFG_IE | JH8100_PADCFG_SMT);
+
+ jh8100_set_one_pin_mux(sfp, gpio, 255, 0, 1, 0);
+
+ return 0;
+}
+
+static int jh8100_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int gpio, int value)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+
+ jh8100_set_one_pin_mux(sfp, gpio,
+ 255, value ? 1 : 0,
+ 0, 0);
+
+ /* disable input, schmitt trigger and bias */
+ jh8100_padcfg_rmw(sfp, gpio,
+ JH8100_PADCFG_IE | JH8100_PADCFG_SMT,
+ 0);
+ return 0;
+}
+
+static int jh8100_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+ const struct jh8100_pinctrl_domain_info *info = sfp->info;
+ void __iomem *reg = sfp->base + info->gpioin_reg_base
+ + 4 * (gpio / 32);
+
+ return !!(readl_relaxed(reg) & BIT(gpio % 32));
+}
+
+static void jh8100_gpio_set(struct gpio_chip *gc,
+ unsigned int gpio, int value)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+ const struct jh8100_pinctrl_domain_info *info = sfp->info;
+ unsigned int offset = 4 * (gpio / 4);
+ unsigned int shift = 8 * (gpio % 4);
+ void __iomem *reg_dout = sfp->base + info->dout_reg_base + offset;
+ u32 dout = (value ? 1 : 0) << shift;
+ u32 mask = info->dout_mask << shift;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ dout |= readl_relaxed(reg_dout) & ~mask;
+ writel_relaxed(dout, reg_dout);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh8100_irq_ack(struct irq_data *d)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ic = sfp->base + irq_reg->ic_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ic) & ~mask;
+ writel_relaxed(value, ic);
+ writel_relaxed(value | mask, ic);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh8100_irq_mask(struct irq_data *d)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) & ~mask;
+ writel_relaxed(value, ie);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+ gpiochip_disable_irq(&sfp->gc, d->hwirq);
+}
+
+static void jh8100_irq_mask_ack(struct irq_data *d)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ void __iomem *ic = sfp->base + irq_reg->ic_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) & ~mask;
+ writel_relaxed(value, ie);
+
+ value = readl_relaxed(ic) & ~mask;
+ writel_relaxed(value, ic);
+ writel_relaxed(value | mask, ic);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh8100_irq_unmask(struct irq_data *d)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ gpiochip_enable_irq(&sfp->gc, d->hwirq);
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) | mask;
+ writel_relaxed(value, ie);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh8100_irq_set_type(struct irq_data *d, unsigned int trigger)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *base = sfp->base + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ u32 irq_type, edge_both, polarity;
+ unsigned long flags;
+
+ switch (trigger) {
+ case IRQ_TYPE_EDGE_RISING:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = 0; /* 0: single edge */
+ polarity = mask; /* 1: rising edge */
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = 0; /* 0: single edge */
+ polarity = 0; /* 0: falling edge */
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = mask; /* 1: both edges */
+ polarity = 0; /* 0: ignored */
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ irq_type = 0; /* 0: level triggered */
+ edge_both = 0; /* 0: ignored */
+ polarity = mask; /* 1: high level */
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_type = 0; /* 0: level triggered */
+ edge_both = 0; /* 0: ignored */
+ polarity = 0; /* 0: low level */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (trigger & IRQ_TYPE_EDGE_BOTH)
+ irq_set_handler_locked(d, handle_edge_irq);
+ else
+ irq_set_handler_locked(d, handle_level_irq);
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ irq_type |= readl_relaxed(base + irq_reg->is_reg_base) & ~mask;
+ writel_relaxed(irq_type, base + irq_reg->is_reg_base);
+
+ edge_both |= readl_relaxed(base + irq_reg->ibe_reg_base) & ~mask;
+ writel_relaxed(edge_both, base + irq_reg->ibe_reg_base);
+
+ polarity |= readl_relaxed(base + irq_reg->iev_reg_base) & ~mask;
+ writel_relaxed(polarity, base + irq_reg->iev_reg_base);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+ return 0;
+}
+
+static int jh8100_irq_set_wake(struct irq_data *d, unsigned int enable)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+ int ret = 0;
+
+ if (enable)
+ ret = enable_irq_wake(sfp->wakeup_irq);
+ else
+ ret = disable_irq_wake(sfp->wakeup_irq);
+ if (ret)
+ dev_err(sfp->dev, "failed to %s wake-up interrupt\n",
+ enable ? "enable" : "disable");
+
+ return ret;
+}
+
+static void jh8100_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
+
+ seq_printf(p, sfp->gc.label);
+}
+
+static const struct irq_chip jh8100_irq_chip = {
+ .irq_ack = jh8100_irq_ack,
+ .irq_mask = jh8100_irq_mask,
+ .irq_mask_ack = jh8100_irq_mask_ack,
+ .irq_unmask = jh8100_irq_unmask,
+ .irq_set_type = jh8100_irq_set_type,
+ .irq_set_wake = jh8100_irq_set_wake,
+ .irq_print_chip = jh8100_irq_print_chip,
+ .flags = IRQCHIP_SET_TYPE_MASKED |
+ IRQCHIP_IMMUTABLE |
+ IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND |
+ IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SKIP_SET_WAKE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void jh8100_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct jh8100_pinctrl *sfp = jh8100_from_irq_desc(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct gpio_irq_chip *girq = &sfp->gc.irq;
+ unsigned long mis;
+ unsigned int pin;
+
+ chained_irq_enter(chip, desc);
+
+ mis = readl_relaxed(sfp->base + sfp->info->irq_reg->mis_reg_base);
+ for_each_set_bit(pin, &mis, sfp->info->mis_pin_num)
+ generic_handle_domain_irq(girq->domain, pin);
+
+ if (sfp->info->irq_reg->mis1_reg_base) {
+ mis = readl_relaxed(sfp->base + sfp->info->irq_reg->mis1_reg_base);
+ for_each_set_bit(pin, &mis, sfp->info->mis1_pin_num)
+ generic_handle_domain_irq(girq->domain, pin + 32);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int jh8100_gpio_init_hw(struct gpio_chip *gc)
+{
+ struct jh8100_pinctrl *sfp = container_of(gc,
+ struct jh8100_pinctrl, gc);
+
+ /* mask all GPIO interrupts */
+ writel_relaxed(0U, sfp->base + sfp->info->irq_reg->ie_reg_base);
+ /* clear edge interrupt flags */
+ writel_relaxed(0U, sfp->base + sfp->info->irq_reg->ic_reg_base);
+ writel_relaxed(~0U, sfp->base + sfp->info->irq_reg->ic_reg_base);
+ if (sfp->info->irq_reg->ic1_reg_base) {
+ writel_relaxed(0U, sfp->base + sfp->info->irq_reg->ic1_reg_base);
+ writel_relaxed(~0U, sfp->base + sfp->info->irq_reg->ic1_reg_base);
+ }
+ /* enable GPIO interrupts */
+ writel_relaxed(1, sfp->base + sfp->info->irq_reg->ien_reg_base);
+
+ return 0;
+}
+
+static void jh8100_disable_clock(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+int jh8100_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_irq_chip *girq;
+ const struct jh8100_pinctrl_domain_info *info;
+ struct jh8100_pinctrl *sfp;
+ struct pinctrl_desc *jh8100_pinctrl_desc;
+ struct reset_control *rst;
+ struct clk *clk;
+ int ret;
+
+ info = of_device_get_match_data(&pdev->dev);
+ if (!info)
+ return -ENODEV;
+
+ sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);
+ if (!sfp)
+ return -ENOMEM;
+
+ sfp->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sfp->base))
+ return PTR_ERR(sfp->base);
+
+ clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "could not get clock\n");
+
+ rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst), "could not get reset control\n");
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not enable clock\n");
+
+ ret = devm_add_action_or_reset(dev, jh8100_disable_clock, clk);
+ if (ret)
+ return ret;
+
+ /*
+ * we don't want to assert reset and risk undoing pin muxing for the
+ * early boot serial console, but let's make sure the reset line is
+ * deasserted in case someone runs a really minimal bootloader.
+ */
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not deassert reset\n");
+
+ jh8100_pinctrl_desc = devm_kzalloc(&pdev->dev,
+ sizeof(*jh8100_pinctrl_desc),
+ GFP_KERNEL);
+ if (!jh8100_pinctrl_desc)
+ return -ENOMEM;
+
+ jh8100_pinctrl_desc->name = dev_name(dev);
+ jh8100_pinctrl_desc->pins = info->pins;
+ jh8100_pinctrl_desc->npins = info->npins;
+ jh8100_pinctrl_desc->pctlops = &jh8100_pinctrl_ops;
+ jh8100_pinctrl_desc->pmxops = &jh8100_pinmux_ops;
+ jh8100_pinctrl_desc->confops = &jh8100_pinconf_ops;
+ jh8100_pinctrl_desc->owner = THIS_MODULE;
+
+ sfp->info = info;
+ sfp->dev = dev;
+ platform_set_drvdata(pdev, sfp);
+ sfp->gc.parent = dev;
+ raw_spin_lock_init(&sfp->lock);
+ mutex_init(&sfp->mutex);
+
+ ret = devm_pinctrl_register_and_init(dev,
+ jh8100_pinctrl_desc,
+ sfp, &sfp->pctl);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not register pinctrl driver\n");
+
+ sfp->gc.label = dev_name(dev);
+ sfp->gc.owner = THIS_MODULE;
+ sfp->gc.request = pinctrl_gpio_request;
+ sfp->gc.free = pinctrl_gpio_free;
+ sfp->gc.get_direction = jh8100_gpio_get_direction;
+ sfp->gc.direction_input = jh8100_gpio_direction_input;
+ sfp->gc.direction_output = jh8100_gpio_direction_output;
+ sfp->gc.get = jh8100_gpio_get;
+ sfp->gc.set = jh8100_gpio_set;
+ sfp->gc.set_config = gpiochip_generic_config;
+ sfp->gc.base = info->gc_base;
+ sfp->gc.ngpio = info->ngpios;
+
+ girq = &sfp->gc.irq;
+
+ if (info->irq_reg) {
+ gpio_irq_chip_set_chip(girq, &jh8100_irq_chip);
+ girq->parent_handler = jh8100_gpio_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, girq->num_parents,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->init_hw = jh8100_gpio_init_hw;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+ girq->parents[0] = ret;
+ }
+
+ ret = pinctrl_enable(sfp->pctl);
+ if (ret)
+ return ret;
+
+ if (sfp->gc.ngpio > 0) {
+ ret = devm_gpiochip_add_data(dev, &sfp->gc, sfp);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not register gpiochip\n");
+
+ dev_info(dev, "StarFive JH8100 GPIO chip registered %d GPIOs\n", sfp->gc.ngpio);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(jh8100_pinctrl_probe);
+
+MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH8100 SoC");
+MODULE_AUTHOR("Alex Soo <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
new file mode 100644
index 000000000000..6eb4f1896a90
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Pinctrl / GPIO driver for StarFive JH8100 SoC
+ *
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <[email protected]>
+ *
+ */
+
+#ifndef __PINCTRL_STARFIVE_JH8100_H__
+#define __PINCTRL_STARFIVE_JH8100_H__
+
+#include "../core.h"
+
+#define JH8100_SYS_E_DOMAIN_NAME "jh8100-sys-east"
+
+#define JH8100_SYS_E_NGPIO 48
+
+#define JH8100_SYS_E_REG_NUM 116
+
+#define JH8100_SYS_E_GPO_PDA_00_47_CFG 0x114
+
+struct jh8100_pinctrl {
+ struct device *dev;
+ struct gpio_chip gc;
+ struct pinctrl_gpio_range gpios;
+ raw_spinlock_t lock;
+ void __iomem *base;
+ struct pinctrl_dev *pctl;
+ /* register read/write mutex */
+ struct mutex mutex;
+ const struct jh8100_pinctrl_domain_info *info;
+ unsigned int jh8100_sys_east_regs[JH8100_SYS_E_REG_NUM];
+ /* wakeup */
+ struct irq_domain *irq_domain;
+ struct gpio_desc *wakeup_gpio;
+ int wakeup_irq;
+};
+
+struct jh8100_gpio_func_sel {
+ unsigned short offset;
+ unsigned char shift;
+ unsigned char max;
+};
+
+struct jh8100_gpio_irq_reg {
+ unsigned int is_reg_base;
+ unsigned int ic_reg_base;
+ unsigned int ic1_reg_base;
+ unsigned int ibe_reg_base;
+ unsigned int iev_reg_base;
+ unsigned int ie_reg_base;
+ unsigned int ris_reg_base;
+ unsigned int mis_reg_base;
+ unsigned int mis1_reg_base;
+ unsigned int ien_reg_base;
+};
+
+struct jh8100_pinctrl_domain_info {
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ unsigned int ngpios;
+ unsigned int gc_base;
+
+ const char *name;
+ unsigned int nregs;
+
+ /* gpio dout/doen/din/gpioinput register */
+ unsigned int dout_reg_base;
+ unsigned int dout_mask;
+ unsigned int doen_reg_base;
+ unsigned int doen_mask;
+ unsigned int gpi_reg_base;
+ unsigned int gpi_mask;
+ unsigned int gpioin_reg_base;
+
+ const struct jh8100_gpio_func_sel *func_sel;
+ const struct jh8100_gpio_irq_reg *irq_reg;
+
+ /* gpio chip */
+ unsigned int mis_pin_num;
+ unsigned int mis1_pin_num;
+};
+
+int jh8100_pinctrl_probe(struct platform_device *pdev);
+void jh8100_set_gpiomux(struct jh8100_pinctrl *sfp, unsigned int pin,
+ unsigned int din, u32 dout, u32 doen);
+struct jh8100_pinctrl *jh8100_from_irq_desc(struct irq_desc *desc);
+void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned int num_maps);
+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);
+const char *pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector);
+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int * const num_groups);
+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
+ const char *name,
+ const char * const *groups,
+ unsigned int const num_groups,
+ void *data);
+
+#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
+int pinconf_generic_parse_dt_config(struct device_node *np,
+ struct pinctrl_dev *pctldev,
+ unsigned long **configs,
+ unsigned int *nconfigs);
+#endif
+
+#endif /* __PINCTRL_STARFIVE_JH8100_H__ */
--
2.25.1
Add documentation and header file for JH8100 pinctrl driver.
Signed-off-by: Alex Soo <[email protected]>
---
.../pinctrl/starfive,jh8100-aon-pinctrl.yaml | 260 ++++++++++++++++++
.../starfive,jh8100-sys-east-pinctrl.yaml | 222 +++++++++++++++
.../starfive,jh8100-sys-gmac-pinctrl.yaml | 162 +++++++++++
.../starfive,jh8100-sys-west-pinctrl.yaml | 219 +++++++++++++++
.../pinctrl/starfive,jh8100-pinctrl.h | 13 +
5 files changed, 876 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml
create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml
create mode 100644 include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml
new file mode 100644
index 000000000000..abd2a7570a54
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml
@@ -0,0 +1,260 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jh8100-aon-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH8100 AON (always-on) Pin Controller
+
+description: |
+ Pinctrl bindings for JH8100 RISC-V SoC from StarFive Technology Ltd.
+
+ The JH8100 SoC has 4 pinctrl domains - sys_east, sys_west, sys_gmac, and aon.
+ This document provides an overview of the "aon" pinctrl domain.
+
+ The "aon" domain has a pin controller which provides
+ - I/O multiplexing for peripheral signals specific to this domain.
+ - GPIO pins which support external GPIO interrupts or external wake-up.
+ - syscon registers to configure device I/O reference voltage.
+
+ In the AON Pin Controller, the pins named PAD_RGPIO0 to PAD_GPIO15 can be
+ multiplexed and have configurable bias, drive strength, schmitt trigger etc.
+ Only peripherals in the AON domain can have their I/O go through the 16
+ "PAD_RGPIOs". This includes I2C, UART, watchdog, eMMC, SDIO0, XSPI etc.
+
+ All these peripherals can be connected to any of the 16 PAD_RGPIOs in such a way
+ that any iopad can be set up to be controlled by any of the peripherals.
+
+ The pin muxing is illustrated by the diagram below.
+ _____________
+ | |
+ RGPIO0 --------------| |--- PAD_RGPIO0
+ RGPIO1 --------------| AON I/O MUX |--- PAD_RGPIO1
+ ... | | ...
+ I2C8 SDA interface --| |--- PAD_RGPIO15
+ | |
+ -------------
+
+ The AON Pin Controller provides syscon registers to configure
+
+ 1. reference voltage of
+ - eMMC I/O interface
+ supported voltage - 1.8V
+ - SDIO0 I/O interface
+ supported voltage - 3.3V, 1.8V
+ - PAD_RGPIO bank
+ - 16 PAD_RGPIOs (PAD_RGPIO0 to PAD_GPIO15)
+ - all devices attached to PAD_RGPIOs must use I/O voltage 3.3V.
+ - XSPI I/O interface
+ supported voltage level - 3.3V
+
+ Regulator supplies the device voltage, and each device has a corresponding syscon
+ register bit [1:0] that must be configured to indicate the device voltage level.
+
+ +--------+--------+-------------------+
+ | Bit[1] | Bit[0] | Reference Voltage |
+ +--------+--------+-------------------+
+ | 0 | 0 | 3.3 V |
+ +--------+--------+-------------------+
+ | 0 | 1 | 2.5 V |
+ +--------+--------+-------------------+
+ | 1 | x | 1.8 V |
+ +--------+--------+-------------------+
+
+ 2. reference voltage and slew rate of GMAC0
+
+ Voltage level on GMAC0 interface is dependent on the PHY that it is pairing with. The
+ supported voltage levels are 3.3V, 2.5V, and 1.8V.
+
+ GMAC0 has 2 set of syscon registers -
+
+ 2.1 PAD_VREF_GMAC0_syscon - bit [1:0] must be configured to indicate the voltage level on
+ GMAC0 interface. The default setting is 3.3V.
+
+ +--------+--------+-----------------------------------+
+ | Bit[1] | Bit[0] | GMAC0 Interface Reference Voltage |
+ +--------+--------+-----------------------------------+
+ | 0 | 0 | 3.3V |
+ +--------+--------+-----------------------------------+
+ | 0 | 1 | 2.5V |
+ +--------+--------+-----------------------------------+
+ | 1 | x | 1.8V |
+ +--------+--------+-----------------------------------+
+
+ 2.2 PAD_GMAC0_<SIGNAL_NAME>_syscon - each GMAC0 pad has a corresponding syscon bit [0] set
+ to 0 by default. When GMAC0 mode is RGMII and voltage level is 2.5V, the bit [0] must be
+ set to 1.
+
+ +-------------+-----------------------+---------+
+ | GMAC0 Mode | GMAC0 Voltage Level | Bit[0] |
+ +-------------+-----------------------+---------+
+ | | 3.3V | 0 |
+ | |-----------------------+---------+
+ | RGMII | 2.5V | 1 |
+ | |-----------------------+---------+
+ | | 1.8V | 0 |
+ +-------------+-----------------------+---------+
+ | | 3.3V | 0 |
+ | |-----------------------+---------+
+ | RMII | 2.5V | 0 |
+ | |-----------------------+---------+
+ | | 1.8V | 0 |
+ +-------------+-----------------------+---------+
+
+ the bit [2] can be used to configure GMAC0 signal slew rate,
+
+ +--------+-----------+
+ | Bit[2] | Slew Rate |
+ +--------+-----------+
+ | 0 | Fast |
+ +--------+-----------+
+ | 1 | Slow |
+ +--------+-----------+
+
+ Under any circumstances, the syscon register's reference voltage setting must not be
+ lower than the actual device voltage, otherwise, the device I/O pads will get damaged.
+
+ Follow the guidelines below when configure reference voltage -
+
+ To increase the device voltage, set bit [1:0] to the new operating state first before
+ raising the actual voltage to the higher operating point.
+
+ To decrease the device voltage, hold bit [1:0] to the current operating state until
+ the actual voltage has stabilized at the lower operating point before changing the
+ setting.
+
+ Alternatively, a device voltage change can always be initiated by first setting syscon
+ register bit [1:0] = 0, the safe 3.3V startup condition, before changing the device
+ voltage. Then once the actual voltage is changed and has stabilized at the new operating
+ point, bit [1:0] can be reset as appropriate.
+
+maintainers:
+ - Alex Soo <[email protected]>
+
+properties:
+ compatible:
+ - items:
+ - const: starfive,jh8100-aon-pinctrl
+ - const: syscon
+ - const: simple-mfd
+
+ reg:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+ wakeup-gpios:
+ maxItems: 1
+ description: GPIO pin to be used for waking up the system from sleep mode.
+
+ wakeup-source:
+ maxItems: 1
+ description: to indicate pinctrl has wakeup capability.
+
+patternProperties:
+ '-grp$':
+ type: object
+ additionalProperties: false
+ patternProperties:
+ '-pins$':
+ type: object
+ description: |
+ A pinctrl node should contain at least one subnode representing the
+ pinctrl groups available in the domain. Each subnode will list the
+ pins it needs, and how they should be configured, with regard to
+ muxer configuration, bias, input enable/disable, input schmitt
+ trigger enable/disable, slew-rate and drive strength.
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml
+ - $ref: /schemas/pinctrl/pinmux-node.yaml
+ unevaluatedProperties: false
+
+ properties:
+ pinmux:
+ description: |
+ The list of GPIOs and their mux settings or function select.
+ The GPIOMUX and PINMUX macros are used to configure the
+ I/O multiplexing and function selection respectively.
+
+ bias-disable: true
+
+ bias-pull-up:
+ type: boolean
+
+ bias-pull-down:
+ type: boolean
+
+ drive-strength-microamp:
+ enum: [ 2000, 4000, 8000, 12000 ]
+
+ input-enable: true
+
+ input-disable: true
+
+ input-schmitt-enable: true
+
+ input-schmitt-disable: true
+
+ slew-rate:
+ enum: [ 0, 1 ]
+ default: 0
+ description: |
+ 0: slow (half frequency)
+ 1: fast
+
+required:
+ - compatible
+ - reg
+ - resets
+ - interrupts
+ - interrupt-controller
+ - gpio-controller
+ - '#gpio-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl_aon: pinctrl@1f300000 {
+ compatible = "starfive,jh8100-aon-pinctrl", "syscon", "simple-mfd";
+ reg = <0x0 0x1f300000 0x0 0x10000>;
+ resets = <&aoncrg 0>;
+ interrupts = <160>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_aon 0 0 16>;
+
+ i2c7_pins: i2c7-grp {
+ i2c7-scl-pins {
+ pinmux = <0x23265409>;
+ bias-pull-up;
+ input-enable;
+ };
+
+ i2c7-sda-pins {
+ pinmux = <0x2427580a>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml
new file mode 100644
index 000000000000..6ad518e9bee2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml
@@ -0,0 +1,222 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH8100 SYS_EAST Pin Controller
+
+description: |
+ Pinctrl bindings for JH8100 RISC-V SoC from StarFive Technology Ltd.
+
+ The JH8100 SoC has 4 pinctrl domains - sys_east, sys_west, sys_gmac, and aon.
+ This document provides an overview of the "sys_east" pinctrl domain.
+
+ The "sys_east" domain has a pin controller which provides
+ - I/O multiplexing for peripheral signals specific to this domain.
+ - function selection for GPIO pads.
+ - GPIO interrupt handling.
+ - syscon for device voltage reference.
+
+ In the SYS_EAST Pin Controller, the pins named PAD_GPIO0_E to PAD_GPIO47_E can
+ be multiplexed and have configurable bias, drive strength, schmitt trigger etc.
+ Only peripherals in the SYS_EAST domain can have their I/O go through the 48
+ "PAD_GPIOs". This includes CANs, I2Cs, I2Ss, SPIs, UARTs, PWMs, SMBUS0, SDIO1 etc.
+
+ All these peripherals can be connected to any of the 48 PAD_GPIOs in such a way
+ that any iopad can be set up to be controlled by any of the peripherals.
+
+ The pin muxing is illustrated by the diagram below.
+ __________________
+ | |
+ GPIO0 ----------------------| |--- PAD_GPIO0_E
+ GPIO1 ----------------------| SYS_EAST I/O MUX |--- PAD_GPIO1_E
+ GPIO2 ----------------------| |--- PAD_GPIO2_E
+ ... | | ...
+ I2C0 Clock interface -------| |--- PAD_GPIO9_E
+ I2C0 Data interface -------| |--- PAD_GPIO10_E
+ ... | | ...
+ UART0 transmit interface ---| |--- PAD_GPIO20_E
+ UART0 receive interface ----| |--- PAD_GPIO21_E
+ ... | | ...
+ GPIO47 ---------------------| |--- PAD_GPIO47_E
+ | |
+ ------------------
+
+ Alternatively, the "PAD_GPIOs" can be multiplexed to other peripherals through
+ function selection. Each iopad has a maximum of up to 3 functions - 0, 1, and 2.
+ Function 0 is the default function or peripheral signal of an iopad.
+ The function 1 and function 2 are other optional functions or peripheral signals
+ available to an iopad. The function selection can be carried out by writing the
+ function number to the iopad function select register.
+
+ The "sys_east" domain has 4 PAD_GPIO banks -
+ E0 - 16 PAD_GPIOs (PAD_GPIO0_E to PAD_GPIO15_E)
+ E1 - 16 PAD_GPIOs (PAD_GPIO16_E to PAD_GPIO31_E)
+ E2 - 8 PAD_GPIOs (PAD_GPIO32_E to PAD_GPIO39_E)
+ E3 - 8 PAD_GPIOs (PAD_GPIO40_E to PAD_GPIO47_E)
+
+ Each PAD_GPIO bank can be set to a voltage level 3.3V or 1.8V. All devices attached
+ to the PAD_GPIOs must use the same I/O voltage level as the bank voltage setting.
+ This allows user to select different I/O voltages for their devices. For instance,
+ the UART have 3.3V/1.8V requirement, the UART devices that use 1.8V are attached
+ to a PAD_GPIO bank which is configured to 1.8V.
+
+ Regulators supply voltages to the PAD_GPIO banks, and each PAD_GPIO bank has a corresponding
+ syscon bit [1:0] that must be configured to indicate its voltage level. The default setting
+ is 3.3V.
+
+ +--------+--------+-------------------+
+ | Bit[1] | Bit[0] | Reference Voltage |
+ +--------+--------+-------------------+
+ | 0 | 0 | 3.3 V |
+ +--------+--------+-------------------+
+ | 1 | x | 1.8 V |
+ +--------+--------+-------------------+
+
+ Under any circumstances, the syscon register's reference voltage setting must not be
+ lower than the actual device voltage, otherwise, the device I/O pads will get damaged.
+
+ Follow the guidelines below when configure reference voltage -
+
+ To increase the device voltage, set bit [1:0] to the new operating state first before
+ raising the actual voltage to the higher operating point.
+
+ To decrease the device voltage, hold bit [1:0] to the current operating state until
+ the actual voltage has stabilized at the lower operating point before changing the
+ setting.
+
+ Alternatively, a device voltage change can always be initiated by first setting syscon
+ register bit [1:0] = 0, the safe 3.3V startup condition, before changing the device
+ voltage. Then once the actual voltage is changed and has stabilized at the new operating
+ point, bit [1:0] can be reset as appropriate.
+
+maintainers:
+ - Alex Soo <[email protected]>
+
+properties:
+ compatible:
+ - items:
+ - const: starfive,jh8100-sys-pinctrl-east
+ - const: syscon
+ - const: simple-mfd
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+ gpio-line-names: true
+
+patternProperties:
+ '-grp$':
+ type: object
+ additionalProperties: false
+ patternProperties:
+ '-pins$':
+ type: object
+ description: |
+ A pinctrl node should contain at least one subnode representing the
+ pinctrl groups available in the domain. Each subnode will list the
+ pins it needs, and how they should be configured, with regard to
+ muxer configuration, bias, input enable/disable, input schmitt
+ trigger enable/disable, slew-rate and drive strength.
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml
+ - $ref: /schemas/pinctrl/pinmux-node.yaml
+ unevaluatedProperties: false
+
+ properties:
+ pinmux:
+ description: |
+ The list of GPIOs and their mux settings or function select.
+ The GPIOMUX and PINMUX macros are used to configure the
+ I/O multiplexing and function selection respectively.
+
+ bias-disable: true
+
+ bias-pull-up:
+ type: boolean
+
+ bias-pull-down:
+ type: boolean
+
+ drive-strength-microamp:
+ enum: [ 2000, 4000, 8000, 12000 ]
+
+ input-enable: true
+
+ input-disable: true
+
+ input-schmitt-enable: true
+
+ input-schmitt-disable: true
+
+ slew-rate:
+ enum: [ 0, 1 ]
+ default: 0
+ description: |
+ 0: slow (half frequency)
+ 1: fast
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - interrupts
+ - interrupt-controller
+ - gpio-controller
+ - '#gpio-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl_east: pinctrl@122d0000 {
+ compatible = "starfive,jh8100-sys-pinctrl-east", "syscon", "simple-mfd";
+ reg = <0x0 0x122d0000 0x0 0x10000>;
+ clocks = <&syscrg_ne 153>;
+ resets = <&syscrg_ne 48>;
+ interrupts = <182>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_east 0 0 48>;
+
+ smbus0_pins: smbus0-grp {
+ smbus0-scl-pins {
+ pinmux = <0x1122480b>;
+ bias-pull-up;
+ input-enable;
+ };
+
+ smbus0-sda-pins {
+ pinmux = <0x12234c0c>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml
new file mode 100644
index 000000000000..567ff0d9fd6c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml
@@ -0,0 +1,162 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH8100 SYS_GMAC Pin Controller
+
+description: |
+ Pinctrl bindings for JH8100 RISC-V SoC from StarFive Technology Ltd.
+
+ The JH8100 SoC has 4 pinctrl domains - sys_east, sys_west, sys_gmac, and aon.
+ This document provides an overview of the "sys_gmac" pinctrl domain.
+
+ The "sys_gmac" domain has a pin-controller which provides syscon registers to
+ configure device reference voltage and slew rate.
+
+ The SYS_GMAC Pin Controller does not have any PAD_GPIOs, therefore, it does not
+ support the GPIO pad I/O Multiplexing and interrupt handling.
+
+ The SYS_GMAC Pin Controller provides syscon registers to configure
+
+ 1. reference voltage of SDIO1
+
+ The supported voltage levels are 3.3V and 1.8V
+
+ The bit [1:0] must be configured to indicate the SDIO1 voltage level.
+
+ +--------+--------+--------------------------+
+ | Bit[1] | Bit[0] | SDIO1 Reference Voltage |
+ +--------+--------+--------------------------+
+ | 0 | 0 | 3.3 V |
+ +--------+--------+--------------------------+
+ | 1 | 0 | 1.8 V |
+ +--------+--------+--------------------------+
+
+ 2. reference voltage and slew rate of GMAC1
+
+ Voltage level on GMAC1 interface is dependent on the PHY that it is pairing with. The
+ supported voltage levels are 3.3V, 2.5V, and 1.8V.
+
+ GMAC1 has 2 set of syscon registers -
+
+ 2.1 PAD_VREF_GMAC1_syscon - bit [1:0] must be configured to indicate the voltage level on
+ GMAC1 interface. The default setting is 3.3V.
+
+ +--------+--------+-----------------------------------+
+ | Bit[1] | Bit[0] | GMAC1 Interface Reference Voltage |
+ +--------+--------+-----------------------------------+
+ | 0 | 0 | 3.3V |
+ +--------+--------+-----------------------------------+
+ | 0 | 1 | 2.5V |
+ +--------+--------+-----------------------------------+
+ | 1 | x | 1.8V |
+ +--------+--------+-----------------------------------+
+
+ 2.2 PAD_GMAC1_<SIGNAL_NAME>_syscon - each GMAC1 pad has a corresponding syscon bit [0] set
+ to 0 by default. When GMAC1 mode is RGMII and voltage level is 2.5V, the bit [0] must be
+ set to 1.
+
+ +-------------+-----------------------+---------+
+ | GMAC1 Mode | GMAC1 Voltage Level | Bit[0] |
+ +-------------+-----------------------+---------+
+ | | 3.3V | 0 |
+ | |-----------------------+---------+
+ | RGMII | 2.5V | 1 |
+ | |-----------------------+---------+
+ | | 1.8V | 0 |
+ +-------------+-----------------------+---------+
+ | | 3.3V | 0 |
+ | |-----------------------+---------+
+ | RMII | 2.5V | 0 |
+ | |-----------------------+---------+
+ | | 1.8V | 0 |
+ +-------------+-----------------------+---------+
+
+ the bit [2] can be used to configure the GMAC1 signal slew rate,
+
+ +--------+-----------+
+ | Bit[2] | Slew Rate |
+ +--------+-----------+
+ | 0 | Fast |
+ +--------+-----------+
+ | 1 | Slow |
+ +--------+-----------+
+
+ Under any circumstances, the syscon register's reference voltage setting must not be
+ lower than the actual voltage, otherwise, the device I/O pads will get damaged.
+
+ Follow the guidelines below when configure reference voltage -
+
+ To increase the device voltage, set bit [1:0] to the new operating state first before
+ raising the actual voltage to the higher operating point.
+
+ To decrease the device voltage, hold bit [1:0] to the current operating state until
+ the actual voltage has stabilized at the lower operating point before changing the
+ setting.
+
+ Alternatively, a device voltage change can always be initiated by first setting syscon
+ register bit [1:0] = 0, the safe 3.3V startup condition, before changing the device
+ voltage. Then once the actual voltage is changed and has stabilized at the new operating
+ point, bit [1:0] can be reset as appropriate.
+
+maintainers:
+ - Alex Soo <[email protected]>
+
+properties:
+ compatible:
+ - items:
+ - const: starfive,jh8100-sys-pinctrl-gmac
+ - const: syscon
+ - const: simple-mfd
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+patternProperties:
+ '-grp$':
+ type: object
+ additionalProperties: false
+ patternProperties:
+ '-pins$':
+ type: object
+ description: |
+ A pinctrl node should contain at least one subnode representing the
+ pinctrl groups available in the domain. Each subnode will list the
+ pins it needs, and how they should be configured, with regard to
+ muxer configuration, bias, input enable/disable, input schmitt
+ trigger enable/disable, slew-rate and drive strength.
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml
+ - $ref: /schemas/pinctrl/pinmux-node.yaml
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl_gmac: pinctrl@12770000 {
+ compatible = "starfive,jh8100-sys-pinctrl-gmac", "syscon", "simple-mfd";
+ reg = <0x0 0x12770000 0x0 0x10000>;
+ clocks = <&gmac_sdio_crg 16>;
+ resets = <&gmac_sdio_crg 3>;
+ };
+
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml
new file mode 100644
index 000000000000..ecff5656ecc3
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml
@@ -0,0 +1,219 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH8100 SYS_WEST Pin Controller
+
+description: |
+ Pinctrl bindings for JH8100 RISC-V SoC from StarFive Technology Ltd.
+
+ The JH8100 SoC has 4 pinctrl domains - sys_east, sys_west, sys_gmac, and aon.
+ This document provides an overview of the "sys_west" pinctrl domain.
+
+ The "sys_west" domain has a pin-controller which provides
+ - I/O multiplexing for peripheral signals specific to this domain.
+ - function selection for GPIO pads.
+ - GPIO interrupt handling.
+ - syscon for device voltage reference.
+
+ In the SYS_WEST Pin Controller, the pins named PAD_GPIO0_W to PAD_GPIO15_W can
+ be multiplexed and have configurable bias, drive strength, schmitt trigger etc.
+ Only peripherals in the SYS_WEST domain can have their I/O go through the 16
+ "PAD_GPIOs". This includes I2Cs, HD_AUDIO, HIFI4, SPIs, UARTs, SMBUS1 etc.
+
+ All these peripherals can be connected to any of the 16 PAD_GPIOs in such a way
+ that any iopad can be set up to be controlled by any of the peripherals.
+
+ The pin muxing is illustrated by the diagram below.
+ __________________
+ | |
+ GPIO0 ----------------------| |--- PAD_GPIO0_W
+ GPIO1 ----------------------| SYS_WEST I/O MUX |--- PAD_GPIO1_W
+ GPIO2 ----------------------| |--- PAD_GPIO2_W
+ ... | | ...
+ HIFI4 JTAG TDO interface ---| |--- PAD_GPIO10_W
+ HIFI4 JTAG TDI interface ---| |--- PAD_GPIO11_W
+ SMBUS1 Data interface -----| |--- PAD_GPIO12_W
+ SMBUS1 Clock interface -----| |--- PAD_GPIO13_W
+ ... | | ...
+ GPIO14 ---------------------| |--- PAD_GPIO14_W
+ GPIO15 ---------------------| |--- PAD_GPIO15_W
+ | |
+ ------------------
+
+ Alternatively, the "PAD_GPIOs" can be multiplexed to other peripherals through
+ function selection. Each iopad has a maximum of up to 3 functions - 0, 1, and 2.
+ Function 0 is the default function or peripheral signal of an iopad.
+ The function 1 and function 2 are other optional functions or peripheral signals
+ available to an iopad. The function selection can be carried out by writing the
+ function number to the iopad function select register.
+
+ The "sys_west" domain has one PAD_GPIO bank -
+ W0 - 16 PAD_GPIOs (PAD_GPIO0_W to PAD_GPIO15_W)
+
+ The PAD_GPIO bank can be set to voltage level 3.3V or 1.8V. All devices attached
+ to the PAD_GPIOs must use the same I/O voltage level as the bank voltage setting.
+ This allows user to select different I/O voltages for their devices. For instance,
+ the UART have 3.3V/1.8V requirement, the UART devices that use 1.8V are attached
+ to a PAD_GPIO bank which is configured to 1.8V.
+
+ Regulator supplies voltage to the PAD_GPIO bank, and the PAD_GPIO bank has a
+ corresponding syscon bit [1:0] that must be configured to indicate its voltage
+ level. The default voltage setting of each PAD_GPIO bank is 3.3V.
+
+ +--------+--------+-------------------+
+ | Bit[1] | Bit[0] | Reference Voltage |
+ +--------+--------+-------------------+
+ | 0 | 0 | 3.3 V |
+ +--------+--------+-------------------+
+ | 1 | x | 1.8 V |
+ +--------+--------+-------------------+
+
+ Under any circumstances, the syscon register's reference voltage setting must not be
+ lower than the actual device voltage, otherwise, the device I/O pads will get damaged.
+
+ Follow the guidelines below when configure reference voltage -
+
+ To increase the device voltage, set bit [1:0] to the new operating state first before
+ raising the actual voltage to the higher operating point.
+
+ To decrease the device voltage, hold bit [1:0] to the current operating state until
+ the actual voltage has stabilized at the lower operating point before changing the
+ setting.
+
+ Alternatively, a device voltage change can always be initiated by first setting syscon
+ register bit [1:0] = 0, the safe 3.3V startup condition, before changing the device
+ voltage. Then once the actual voltage is changed and has stabilized at the new operating
+ point, bit [1:0] can be reset as appropriate.
+
+maintainers:
+ - Alex Soo <[email protected]>
+
+properties:
+ compatible:
+ - items:
+ - const: starfive,jh8100-sys-pinctrl-west
+ - const: syscon
+ - const: simple-mfd
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+ gpio-line-names: true
+
+patternProperties:
+ '-grp$':
+ type: object
+ additionalProperties: false
+ patternProperties:
+ '-pins$':
+ type: object
+ description: |
+ A pinctrl node should contain at least one subnode representing the
+ pinctrl groups available in the domain. Each subnode will list the
+ pins it needs, and how they should be configured, with regard to
+ muxer configuration, bias, input enable/disable, input schmitt
+ trigger enable/disable, slew-rate and drive strength.
+ allOf:
+ - $ref: /schemas/pinctrl/pincfg-node.yaml
+ - $ref: /schemas/pinctrl/pinmux-node.yaml
+ unevaluatedProperties: false
+
+ properties:
+ pinmux:
+ description: |
+ The list of GPIOs and their mux settings or function select.
+ The GPIOMUX and PINMUX macros are used to configure the
+ I/O multiplexing and function selection respectively.
+
+ bias-disable: true
+
+ bias-pull-up:
+ type: boolean
+
+ bias-pull-down:
+ type: boolean
+
+ drive-strength-microamp:
+ enum: [ 2000, 4000, 8000, 12000 ]
+
+ input-enable: true
+
+ input-disable: true
+
+ input-schmitt-enable: true
+
+ input-schmitt-disable: true
+
+ slew-rate:
+ enum: [ 0, 1 ]
+ default: 0
+ description: |
+ 0: slow (half frequency)
+ 1: fast
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - interrupts
+ - interrupt-controller
+ - gpio-controller
+ - '#gpio-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pinctrl_west: pinctrl@123e0000 {
+ compatible = "starfive,jh8100-sys-pinctrl-west", "syscon", "simple-mfd";
+ reg = <0x0 0x123e0000 0x0 0x10000>;
+ clocks = <&syscrg_nw 6>;
+ resets = <&syscrg_nw 1>;
+ interrupts = <183>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_west 0 0 16>;
+
+ smbus1_pins: smbus1-grp {
+ smbus1-scl-pins {
+ pinmux = <0x1014300d>;
+ bias-pull-up;
+ input-enable;
+ };
+
+ smbus1-sda-pins {
+ pinmux = <0x1115340c>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+ };
+ };
diff --git a/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
new file mode 100644
index 000000000000..153ba950c062
--- /dev/null
+++ b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
+#define __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
+
+/* Pad Slew Rates */
+#define PAD_SLEW_RATE_FAST 1
+#define PAD_SLEW_RATE_SLOW 0
+
+#endif
--
2.25.1
Add sys_west domain sub-driver.
Signed-off-by: Alex Soo <[email protected]>
---
drivers/pinctrl/starfive/Kconfig | 12 ++
drivers/pinctrl/starfive/Makefile | 1 +
.../pinctrl-starfive-jh8100-sys-west.c | 164 ++++++++++++++++++
.../starfive/pinctrl-starfive-jh8100.c | 6 +
.../starfive/pinctrl-starfive-jh8100.h | 5 +
5 files changed, 188 insertions(+)
create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-west.c
diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index afcbf9d4dc8d..d78f161a636c 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -70,3 +70,15 @@ config PINCTRL_STARFIVE_JH8100_SYS_EAST
This also provides an interface to the GPIO pins not used by other
peripherals supporting inputs, outputs, configuring pull-up/pull-down
and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JH8100_SYS_WEST
+ tristate "StarFive JH8100 SoC System IOMUX-West pinctrl and GPIO driver"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ depends on OF
+ select PINCTRL_STARFIVE_JH8100
+ default ARCH_STARFIVE
+ help
+ Say yes here to support system iomux-west pin control on the StarFive JH8100 SoC.
+ This also provides an interface to the GPIO pins not used by other
+ peripherals supporting inputs, outputs, configuring pull-up/pull-down
+ and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 45698c502b48..784465157ae2 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON) += pinctrl-starfive-jh7110-aon.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH8100) += pinctrl-starfive-jh8100.o
obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_EAST) += pinctrl-starfive-jh8100-sys-east.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JH8100_SYS_WEST) += pinctrl-starfive-jh8100-sys-west.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-west.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-west.c
new file mode 100644
index 000000000000..b97d89777aa3
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100-sys-west.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JH8100 SoC sys west controller
+ *
+ * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <[email protected]>
+ *
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/pinctrl/starfive,jh8100-pinctrl.h>
+
+#include "pinctrl-starfive-jh8100.h"
+
+#define JH8100_SYS_W_GC_BASE 0
+
+/* registers */
+#define JH8100_SYS_W_DOEN 0x000
+#define JH8100_SYS_W_DOUT 0x010
+#define JH8100_SYS_W_GPI 0x020
+#define JH8100_SYS_W_GPIOIN 0x068
+
+#define JH8100_SYS_W_GPIOEN 0x048
+#define JH8100_SYS_W_GPIOIS0 0x04c
+#define JH8100_SYS_W_GPIOIC0 0x050
+#define JH8100_SYS_W_GPIOIBE0 0x054
+#define JH8100_SYS_W_GPIOIEV0 0x058
+#define JH8100_SYS_W_GPIOIE0 0x05c
+#define JH8100_SYS_W_GPIORIS0 0x060
+#define JH8100_SYS_W_GPIOMIS0 0x064
+
+static const struct pinctrl_pin_desc jh8100_sys_w_pins[] = {
+ PINCTRL_PIN(0, "SYS_W_GPIO0"),
+ PINCTRL_PIN(1, "SYS_W_GPIO1"),
+ PINCTRL_PIN(2, "SYS_W_GPIO2"),
+ PINCTRL_PIN(3, "SYS_W_GPIO3"),
+ PINCTRL_PIN(4, "SYS_W_GPIO4"),
+ PINCTRL_PIN(5, "SYS_W_GPIO5"),
+ PINCTRL_PIN(6, "SYS_W_GPIO6"),
+ PINCTRL_PIN(7, "SYS_W_GPIO7"),
+ PINCTRL_PIN(8, "SYS_W_GPIO8"),
+ PINCTRL_PIN(9, "SYS_W_GPIO9"),
+ PINCTRL_PIN(10, "SYS_W_GPIO10"),
+ PINCTRL_PIN(11, "SYS_W_GPIO11"),
+ PINCTRL_PIN(12, "SYS_W_GPIO12"),
+ PINCTRL_PIN(13, "SYS_W_GPIO13"),
+ PINCTRL_PIN(14, "SYS_W_GPIO14"),
+ PINCTRL_PIN(15, "SYS_W_GPIO15"),
+};
+
+static const struct jh8100_gpio_func_sel
+ jh8100_sys_w_func_sel[ARRAY_SIZE(jh8100_sys_w_pins)] = {
+ [0] = { 0xb4, 0, 2 },
+ [1] = { 0xb4, 12, 2 },
+ [2] = { 0xb4, 14, 2 },
+ [3] = { 0xb4, 16, 2 },
+ [4] = { 0xb4, 18, 2 },
+ [5] = { 0xb4, 20, 2 },
+ [6] = { 0xb4, 22, 2 },
+ [7] = { 0xb4, 24, 2 },
+ [8] = { 0xb4, 26, 2 },
+ [9] = { 0xb4, 28, 2 },
+ [10] = { 0xb4, 2, 2 },
+ [11] = { 0xb4, 4, 2 },
+ [12] = { 0xb4, 6, 2 },
+ [13] = { 0xb4, 8, 2 },
+ [14] = { 0xb4, 10, 2 },
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int jh8100_sys_w_pinctrl_suspend(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ sfp->jh8100_sys_west_regs[i] = readl_relaxed(sfp->base + (i * 4));
+
+ return pinctrl_force_sleep(sfp->pctl);
+}
+
+static int jh8100_sys_w_pinctrl_resume(struct device *dev)
+{
+ struct jh8100_pinctrl *sfp;
+ int i;
+
+ sfp = dev_get_drvdata(dev);
+ if (!sfp)
+ return -EINVAL;
+
+ for (i = 0; i < sfp->info->nregs; i++)
+ writel_relaxed(sfp->jh8100_sys_west_regs[i], sfp->base + (i * 4));
+
+ return pinctrl_force_default(sfp->pctl);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(jh8100_sys_w_pinctrl_dev_pm_ops,
+ jh8100_sys_w_pinctrl_suspend,
+ jh8100_sys_w_pinctrl_resume);
+
+static const struct jh8100_gpio_irq_reg jh8100_sys_w_irq_reg = {
+ .is_reg_base = JH8100_SYS_W_GPIOIS0,
+ .ic_reg_base = JH8100_SYS_W_GPIOIC0,
+ .ibe_reg_base = JH8100_SYS_W_GPIOIBE0,
+ .iev_reg_base = JH8100_SYS_W_GPIOIEV0,
+ .ie_reg_base = JH8100_SYS_W_GPIOIE0,
+ .ris_reg_base = JH8100_SYS_W_GPIORIS0,
+ .mis_reg_base = JH8100_SYS_W_GPIOMIS0,
+ .ien_reg_base = JH8100_SYS_W_GPIOEN,
+};
+
+static const struct jh8100_pinctrl_domain_info jh8100_sys_w_pinctrl_info = {
+ .pins = jh8100_sys_w_pins,
+ .npins = ARRAY_SIZE(jh8100_sys_w_pins),
+ .ngpios = JH8100_SYS_W_NGPIO,
+ .gc_base = JH8100_SYS_W_GC_BASE,
+ .name = JH8100_SYS_W_DOMAIN_NAME,
+ .nregs = JH8100_SYS_W_REG_NUM,
+ .dout_reg_base = JH8100_SYS_W_DOUT,
+ .dout_mask = GENMASK(5, 0),
+ .doen_reg_base = JH8100_SYS_W_DOEN,
+ .doen_mask = GENMASK(4, 0),
+ .gpi_reg_base = JH8100_SYS_W_GPI,
+ .gpi_mask = GENMASK(4, 0),
+ .gpioin_reg_base = JH8100_SYS_W_GPIOIN,
+ .func_sel = jh8100_sys_w_func_sel,
+ .irq_reg = &jh8100_sys_w_irq_reg,
+ .mis_pin_num = JH8100_SYS_W_NGPIO,
+};
+
+static const struct of_device_id jh8100_sys_w_pinctrl_of_match[] = {
+ {
+ .compatible = "starfive,jh8100-sys-pinctrl-west",
+ .data = &jh8100_sys_w_pinctrl_info,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh8100_sys_w_pinctrl_of_match);
+
+static struct platform_driver jh8100_sys_w_pinctrl_driver = {
+ .probe = jh8100_pinctrl_probe,
+ .driver = {
+ .name = "starfive-jh8100-sys-pinctrl-west",
+#ifdef CONFIG_PM_SLEEP
+ .pm = &jh8100_sys_w_pinctrl_dev_pm_ops,
+#endif
+ .of_match_table = jh8100_sys_w_pinctrl_of_match,
+ },
+};
+module_platform_driver(jh8100_sys_w_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JH8100 SoC sys west controller");
+MODULE_AUTHOR("Alex Soo <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
index 4b68463ff5a5..8c3e4a90d68d 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.c
@@ -333,6 +333,9 @@ static int jh8100_set_one_pin_mux(struct jh8100_pinctrl *sfp,
if (!strcmp(sfp->info->name, JH8100_SYS_E_DOMAIN_NAME) &&
pin < sfp->gc.ngpio && func == 1)
jh8100_set_function(sfp, pin, func);
+ else if (!strcmp(sfp->info->name, JH8100_SYS_W_DOMAIN_NAME) &&
+ pin < sfp->gc.ngpio - 1 && func == 2)
+ jh8100_set_function(sfp, pin, func);
return 0;
}
@@ -410,6 +413,9 @@ static int jh8100_get_padcfg_base(struct jh8100_pinctrl *sfp,
if (!strcmp(sfp->info->name, JH8100_SYS_E_DOMAIN_NAME)) {
if (pin < JH8100_SYS_E_NGPIO)
return JH8100_SYS_E_GPO_PDA_00_47_CFG;
+ } else if (!strcmp(sfp->info->name, JH8100_SYS_W_DOMAIN_NAME)) {
+ if (pin < JH8100_SYS_W_NGPIO)
+ return JH8100_SYS_W_GPO_PDA_00_15_CFG;
}
return -ENXIO;
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
index 6eb4f1896a90..7c7a05c1c828 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh8100.h
@@ -12,12 +12,16 @@
#include "../core.h"
+#define JH8100_SYS_W_DOMAIN_NAME "jh8100-sys-west"
#define JH8100_SYS_E_DOMAIN_NAME "jh8100-sys-east"
+#define JH8100_SYS_W_NGPIO 16
#define JH8100_SYS_E_NGPIO 48
+#define JH8100_SYS_W_REG_NUM 44
#define JH8100_SYS_E_REG_NUM 116
+#define JH8100_SYS_W_GPO_PDA_00_15_CFG 0x074
#define JH8100_SYS_E_GPO_PDA_00_47_CFG 0x114
struct jh8100_pinctrl {
@@ -30,6 +34,7 @@ struct jh8100_pinctrl {
/* register read/write mutex */
struct mutex mutex;
const struct jh8100_pinctrl_domain_info *info;
+ unsigned int jh8100_sys_west_regs[JH8100_SYS_W_REG_NUM];
unsigned int jh8100_sys_east_regs[JH8100_SYS_E_REG_NUM];
/* wakeup */
struct irq_domain *irq_domain;
--
2.25.1
On Fri, 03 May 2024 19:14:30 +0800, Alex Soo wrote:
> Add documentation and header file for JH8100 pinctrl driver.
>
> Signed-off-by: Alex Soo <[email protected]>
> ---
> .../pinctrl/starfive,jh8100-aon-pinctrl.yaml | 260 ++++++++++++++++++
> .../starfive,jh8100-sys-east-pinctrl.yaml | 222 +++++++++++++++
> .../starfive,jh8100-sys-gmac-pinctrl.yaml | 162 +++++++++++
> .../starfive,jh8100-sys-west-pinctrl.yaml | 219 +++++++++++++++
> .../pinctrl/starfive,jh8100-pinctrl.h | 13 +
> 5 files changed, 876 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml
> create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml
> create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml
> create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml
> create mode 100644 include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml:109:7: [warning] wrong indentation: expected 4 but found 6 (indentation)
/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml:96:7: [warning] wrong indentation: expected 4 but found 6 (indentation)
/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml:99:7: [warning] wrong indentation: expected 4 but found 6 (indentation)
/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml:136:7: [warning] wrong indentation: expected 4 but found 6 (indentation)
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-gmac'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-gmac'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-west'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-west'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-east'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-sys-pinctrl-east'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-aon-pinctrl'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://json-schema.org/draft-07/schema#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml: properties:compatible: [{'items': [{'const': 'starfive,jh8100-aon-pinctrl'}, {'const': 'syscon'}, {'const': 'simple-mfd'}]}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.yaml: ignoring, error in schema: properties: compatible
Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-west-pinctrl.example.dtb: /example-0/soc/pinctrl@123e0000: failed to match any schema with compatible: ['starfive,jh8100-sys-pinctrl-west', 'syscon', 'simple-mfd']
Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-gmac-pinctrl.example.dtb: /example-0/soc/pinctrl@12770000: failed to match any schema with compatible: ['starfive,jh8100-sys-pinctrl-gmac', 'syscon', 'simple-mfd']
Documentation/devicetree/bindings/pinctrl/starfive,jh8100-sys-east-pinctrl.example.dtb: /example-0/soc/pinctrl@122d0000: failed to match any schema with compatible: ['starfive,jh8100-sys-pinctrl-east', 'syscon', 'simple-mfd']
Documentation/devicetree/bindings/pinctrl/starfive,jh8100-aon-pinctrl.example.dtb: /example-0/soc/pinctrl@1f300000: failed to match any schema with compatible: ['starfive,jh8100-aon-pinctrl', 'syscon', 'simple-mfd']
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
On Fri, May 03, 2024 at 07:14:30PM +0800, Alex Soo wrote:
> Add documentation and header file for JH8100 pinctrl driver.
>
> Signed-off-by: Alex Soo <[email protected]>
> diff --git a/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
> new file mode 100644
> index 000000000000..153ba950c062
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> +/*
> + * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
> + */
> +
> +#ifndef __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
> +#define __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
> +
> +/* Pad Slew Rates */
> +#define PAD_SLEW_RATE_FAST 1
> +#define PAD_SLEW_RATE_SLOW 0
Should this really be in the bindings? I don't see it having a direct
user in the driver.
Also, if this is the only header you have, I think the RFC tag could be
dropped, since there'll not be a header we need to worry about getting
into U-Boot etc with values that may change when the SoC moves from an
FPGA etc to tape out.
Cheers,
Conor.
On Fri, May 3, 2024 at 1:14 PM Alex Soo <[email protected]> wrote:
> Starfive JH8100 SoC consists of 4 pinctrl domains - sys_east,
> sys_west, sys_gmac, and aon. This patch series adds pinctrl
> drivers for these 4 pinctrl domains and this patch series is
> depending on the JH8100 base patch series in [1] and [2].
> The relevant dt-binding documentation for each pinctrl domain has
> been updated accordingly.
>
> [1] https://lore.kernel.org/lkml/[email protected]/
> [2] https://lore.kernel.org/lkml/[email protected]/
v3 is starting to look very nice, why is this patch set still in "RFC"?
I would like some proper review from the StarFive maintainers
at this point so we can get it finished.
Yours,
Linus Walleij
> -----Original Message-----
> From: Linus Walleij <[email protected]>
> Sent: Monday, May 6, 2024 2:35 PM
> To: Yuklin Soo <[email protected]>
> Cc: Bartosz Golaszewski <[email protected]>; Hal Feng
> <[email protected]>; Leyfoon Tan <[email protected]>;
> Jianlong Huang <[email protected]>; Emil Renner Berthing
> <[email protected]>; Rob Herring <[email protected]>; Krzysztof Kozlowski
> <[email protected]>; Conor Dooley <[email protected]>;
> Drew Fustini <[email protected]>; [email protected]; linux-
> [email protected]; [email protected]; linux-
> [email protected]; Paul Walmsley <[email protected]>; Palmer
> Dabbelt <[email protected]>; Albert Ou <[email protected]>
> Subject: Re: [RFC PATCH v3 0/7] Add Pinctrl driver for Starfive JH8100 SoC
>
> On Fri, May 3, 2024 at 1:14 PM Alex Soo <[email protected]>
> wrote:
>
> > Starfive JH8100 SoC consists of 4 pinctrl domains - sys_east,
> > sys_west, sys_gmac, and aon. This patch series adds pinctrl drivers
> > for these 4 pinctrl domains and this patch series is depending on the
> > JH8100 base patch series in [1] and [2].
> > The relevant dt-binding documentation for each pinctrl domain has been
> > updated accordingly.
> >
> > [1]
> > https://lore.kernel.org/lkml/20231201121410.95298-1-jeeheng.sia@starfi
> > vetech.com/ [2]
> > https://lore.kernel.org/lkml/20231206115000.295825-1-
> jeeheng.sia@starf
> > ivetech.com/
>
> v3 is starting to look very nice, why is this patch set still in "RFC"?
>
> I would like some proper review from the StarFive maintainers at this point so
> we can get it finished.
>
> Yours,
> Linus Walleij
Hi Linus
Thanks for reviewing the patches.
There is a discussion in another thread about the JH8100 SoC being validated on FPGA/Emulation only now. The suggestion is to send the patches as "RFC" before the real silicon availability.
https://patchew.org/linux/[email protected]/[email protected]/
Regards
Ley Foon
On Mon, May 06, 2024 at 07:31:19AM +0000, Leyfoon Tan wrote:
>
>
> > -----Original Message-----
> > From: Linus Walleij <[email protected]>
> > Sent: Monday, May 6, 2024 2:35 PM
> > To: Yuklin Soo <[email protected]>
> > Cc: Bartosz Golaszewski <[email protected]>; Hal Feng
> > <[email protected]>; Leyfoon Tan <[email protected]>;
> > Jianlong Huang <[email protected]>; Emil Renner Berthing
> > <[email protected]>; Rob Herring <[email protected]>; Krzysztof Kozlowski
> > <[email protected]>; Conor Dooley <[email protected]>;
> > Drew Fustini <[email protected]>; [email protected]; linux-
> > [email protected]; [email protected]; linux-
> > [email protected]; Paul Walmsley <[email protected]>; Palmer
> > Dabbelt <[email protected]>; Albert Ou <[email protected]>
> > Subject: Re: [RFC PATCH v3 0/7] Add Pinctrl driver for Starfive JH8100 SoC
> >
> > On Fri, May 3, 2024 at 1:14 PM Alex Soo <[email protected]>
> > wrote:
> >
> > > Starfive JH8100 SoC consists of 4 pinctrl domains - sys_east,
> > > sys_west, sys_gmac, and aon. This patch series adds pinctrl drivers
> > > for these 4 pinctrl domains and this patch series is depending on the
> > > JH8100 base patch series in [1] and [2].
> > > The relevant dt-binding documentation for each pinctrl domain has been
> > > updated accordingly.
> > >
> > > [1]
> > > https://lore.kernel.org/lkml/20231201121410.95298-1-jeeheng.sia@starfi
> > > vetech.com/ [2]
> > > https://lore.kernel.org/lkml/20231206115000.295825-1-
> > jeeheng.sia@starf
> > > ivetech.com/
> >
> > v3 is starting to look very nice, why is this patch set still in "RFC"?
> >
> > I would like some proper review from the StarFive maintainers at this point so
> > we can get it finished.
> >
> > Yours,
> > Linus Walleij
>
> Hi Linus
>
> Thanks for reviewing the patches.
>
> There is a discussion in another thread about the JH8100 SoC being validated on FPGA/Emulation only now. The suggestion is to send the patches as "RFC" before the real silicon availability.
>
> https://patchew.org/linux/[email protected]/[email protected]/
I know I said "drivers" in that mail you link to, but I was mostly
concerned about binding headers etc, of which I think there are actually
none here, so see my reply to this thread a few days ago:
https://lore.kernel.org/all/20240503-undress-mantra-e5e46b2f6360@spud/
Fri, May 03, 2024 at 07:14:31PM +0800, Alex Soo kirjoitti:
> Add Starfive JH8100 SoC pinctrl main driver to provide the
> common APIs that are used by the sub-drivers of pinctrl
> domains:
> - sys_east,
> - sys_west,
> - sys_gmac,
> - aon (always-on)
>
> to implement the following tasks:
>
> - applies pin multiplexing, function selection, and pin
> configuration for devices during system initialization
> or change of pinctrl state due to power management.
> - read or set pin configuration from user space.
>
> Also, add the sys_east domain sub-driver since it requires
> at least one domain sub-driver to run the probe function in
> the main driver to enable the basic pinctrl functionalities
> on the system.
..
> +config PINCTRL_STARFIVE_JH8100
> + bool
> + select GENERIC_PINCONF
> + select GENERIC_PINCTRL_GROUPS
> + select GENERIC_PINMUX_FUNCTIONS
> + select GPIOLIB
> + select GPIOLIB_IRQCHIP
> + select OF_GPIO
Why?
..
> +/*
> + * Pinctrl / GPIO driver for StarFive JH8100 SoC sys east controller
> + *
> + * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
> + * Author: Alex Soo <[email protected]>
> + *
Unneeded blank line.
> + */
..
> +#include <linux/gpio/driver.h>
> +#include <linux/module.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
This lacks some of inclusions.
E.g., array_size.h, mod_devicetable.h, io.h.
..
> +#ifdef CONFIG_PM_SLEEP
SHouldn't be in a new code. Use proper PM macros.
> +static int jh8100_sys_e_pinctrl_suspend(struct device *dev)
> +{
> + struct jh8100_pinctrl *sfp;
> + int i;
> +
> + sfp = dev_get_drvdata(dev);
> + if (!sfp)
> + return -EINVAL;
When this check can be true?
> + for (i = 0; i < sfp->info->nregs; i++)
> + sfp->jh8100_sys_east_regs[i] = readl_relaxed(sfp->base + (i * 4));
> +
> + return pinctrl_force_sleep(sfp->pctl);
> +}
> +
> +static int jh8100_sys_e_pinctrl_resume(struct device *dev)
> +{
> + struct jh8100_pinctrl *sfp;
> + int i;
> + sfp = dev_get_drvdata(dev);
> + if (!sfp)
> + return -EINVAL;
Ditto.
> + for (i = 0; i < sfp->info->nregs; i++)
> + writel_relaxed(sfp->jh8100_sys_east_regs[i], sfp->base + (i * 4));
Too many parentheses.
> + return pinctrl_force_default(sfp->pctl);
> +}
> +#endif
..
> +static SIMPLE_DEV_PM_OPS(jh8100_sys_e_pinctrl_dev_pm_ops,
> + jh8100_sys_e_pinctrl_suspend,
> + jh8100_sys_e_pinctrl_resume);
Don't use obsoleted macros, use new ones.
..
> +#ifdef CONFIG_PM_SLEEP
> + .pm = &jh8100_sys_e_pinctrl_dev_pm_ops,
> +#endif
Ditto, no ugly ifdeffery.
> + .of_match_table = jh8100_sys_e_pinctrl_of_match,
> + },
> +};
..
> +/*
> + * Pinctrl / GPIO driver for StarFive JH8100 SoC
> + *
> + * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
> + * Author: Alex Soo <[email protected]>
> + *
Unneeded blank line.
> + */
..
+ array_size.h
> +#include <linux/bits.h>
> +#include <linux/clk.h>
+ container_of.h
> +#include <linux/gpio/consumer.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/reset.h>
> +#include <linux/seq_file.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
+ types.h
..
> +static unsigned int jh8100_pinmux_din(u32 v)
> +{
> + return (v & GENMASK(31, 24)) >> 24;
> +}
> +
> +static u32 jh8100_pinmux_dout(u32 v)
> +{
> + return (v & GENMASK(23, 16)) >> 16;
> +}
> +
> +static u32 jh8100_pinmux_doen(u32 v)
> +{
> + return (v & GENMASK(15, 10)) >> 10;
> +}
> +
> +static u32 jh8100_pinmux_function(u32 v)
> +{
> + return (v & GENMASK(9, 8)) >> 8;
> +}
> +
> +static unsigned int jh8100_pinmux_pin(u32 v)
> +{
> + return v & GENMASK(7, 0);
> +}
These all are reinventions of bitfield.h.
..
> +static void jh8100_pin_dbg_show(struct pinctrl_dev *pctldev,
> + struct seq_file *s, unsigned int pin)
> +{
> + struct jh8100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
> + const struct jh8100_pinctrl_domain_info *info = sfp->info;
> +
> + seq_printf(s, "%s", dev_name(pctldev->dev));
> + if (pin < sfp->gc.ngpio) {
When this is not true?
If that case even possible, invert the conditional to reduce the indentation
level.
> + unsigned int offset = 4 * (pin / 4);
> + unsigned int shift = 8 * (pin % 4);
> + u32 dout = readl_relaxed(sfp->base + info->dout_reg_base + offset);
> + u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
> + u32 gpi = readl_relaxed(sfp->base + info->gpi_reg_base + offset);
> +
> + dout = (dout >> shift) & info->dout_mask;
> + doen = (doen >> shift) & info->doen_mask;
> + gpi = ((gpi >> shift) - 2) & info->gpi_mask;
> +
> + seq_printf(s, " dout=%u doen=%u din=%u", dout, doen, gpi);
> + }
> +}
..
> + pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);
> + if (!pgnames)
> + return -ENOMEM;
> +
> + map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL);
> + if (!map)
> + return -ENOMEM;
Why one is managed and another is not? Shouldn't be both either managed or not?
..
> + mutex_lock(&sfp->mutex);
Don't you want to use cleanup.h from day 1?
..
> + for_each_child_of_node(np, child) {
Why not using _scoped() variant?
..
> + int npins = of_property_count_u32_elems(child, "pinmux");
Why signed?
Please, decouple definition and assignment.
> + int *pins;
> + u32 *pinmux;
> + int i;
> +
> + if (npins < 1) {
> + dev_err(dev,
> + "invalid pinctrl group %pOFn.%pOFn: pinmux not set\n",
> + np, child);
> + ret = -EINVAL;
Can npins be negative? In such case why shadowing an error code?
> + goto put_child;
> + }
..
> + ret = pinctrl_generic_add_group(pctldev, grpname,
> + pins, npins, pinmux);
One line?
..
> + for (i = 0; i < group->grp.npins; i++) {
> + u32 v = pinmux[i];
> +
> + jh8100_set_one_pin_mux(sfp,
> + jh8100_pinmux_pin(v),
> + jh8100_pinmux_din(v),
> + jh8100_pinmux_dout(v),
> + jh8100_pinmux_doen(v),
> + jh8100_pinmux_function(v));
> + }
Indentation?
..
> +static u32 jh8100_padcfg_ds_to_mA(u32 padcfg)
> +{
> + return jh8100_drive_strength_mA[(padcfg >> 1) & 3U];
GENMASK() ?
> +}
> +
> +static u32 jh8100_padcfg_ds_to_uA(u32 padcfg)
> +{
> + return jh8100_drive_strength_mA[(padcfg >> 1) & 3U] * 1000;
Ditto.
> +}
..
> +static u32 jh8100_padcfg_ds_from_mA(u32 v)
> +{
> + int i;
Why signed?
> + for (i = 0; i < ARRAY_SIZE(jh8100_drive_strength_mA); i++) {
> + if (v <= jh8100_drive_strength_mA[i])
> + break;
> + }
> + return i << 1;
> +}
..
> +static int jh8100_gpio_get_direction(struct gpio_chip *gc,
> + unsigned int gpio)
One line?
> +{
> + struct jh8100_pinctrl *sfp = container_of(gc,
> + struct jh8100_pinctrl, gc);
> + const struct jh8100_pinctrl_domain_info *info = sfp->info;
> + unsigned int offset = 4 * (gpio / 4);
> + unsigned int shift = 8 * (gpio % 4);
> + u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
> + doen = (doen >> shift) & info->doen_mask;
> +
> + return doen == 0 ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
if ((doen >> shift) & info->doen_mask)
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
> +}
..
> +static int jh8100_gpio_direction_input(struct gpio_chip *gc,
> + unsigned int gpio)
> +{
> + struct jh8100_pinctrl *sfp = container_of(gc,
> + struct jh8100_pinctrl, gc);
Broken indentation, just put on one line.
> + /* enable input and schmitt trigger */
> + jh8100_padcfg_rmw(sfp, gpio,
> + JH8100_PADCFG_IE | JH8100_PADCFG_SMT,
> + JH8100_PADCFG_IE | JH8100_PADCFG_SMT);
> +
> + jh8100_set_one_pin_mux(sfp, gpio, 255, 0, 1, 0);
> +
> + return 0;
> +}
..
> +static int jh8100_gpio_direction_output(struct gpio_chip *gc,
> + unsigned int gpio, int value)
> +{
> + struct jh8100_pinctrl *sfp = container_of(gc,
> + struct jh8100_pinctrl, gc);
> + jh8100_set_one_pin_mux(sfp, gpio,
> + 255, value ? 1 : 0,
> + 0, 0);
Use room on the previous lines.
> + /* disable input, schmitt trigger and bias */
> + jh8100_padcfg_rmw(sfp, gpio,
> + JH8100_PADCFG_IE | JH8100_PADCFG_SMT,
> + 0);
> + return 0;
> +}
..
> +{
> + struct jh8100_pinctrl *sfp = container_of(gc,
> + struct jh8100_pinctrl, gc);
One line. You may create a helper to_jh8100_pinctrl() and use everywhere,
> + const struct jh8100_pinctrl_domain_info *info = sfp->info;
> + void __iomem *reg = sfp->base + info->gpioin_reg_base
> + + 4 * (gpio / 32);
Split definition and assignment. It will increase readability.
> + return !!(readl_relaxed(reg) & BIT(gpio % 32));
> +}
..
> +static void jh8100_gpio_set(struct gpio_chip *gc,
> + unsigned int gpio, int value)
> +{
> + struct jh8100_pinctrl *sfp = container_of(gc,
> + struct jh8100_pinctrl, gc);
> + const struct jh8100_pinctrl_domain_info *info = sfp->info;
> + unsigned int offset = 4 * (gpio / 4);
> + unsigned int shift = 8 * (gpio % 4);
> + void __iomem *reg_dout = sfp->base + info->dout_reg_base + offset;
> + u32 dout = (value ? 1 : 0) << shift;
u32 dout = value ? BIT(shift) : 0;
> + u32 mask = info->dout_mask << shift;
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&sfp->lock, flags);
> + dout |= readl_relaxed(reg_dout) & ~mask;
> + writel_relaxed(dout, reg_dout);
> + raw_spin_unlock_irqrestore(&sfp->lock, flags);
> +}
..
> +static void jh8100_irq_mask(struct irq_data *d)
> +{
> + struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
> + const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
> + irq_hw_number_t gpio = irqd_to_hwirq(d);
> + void __iomem *ie = sfp->base + irq_reg->ie_reg_base
> + + 4 * (gpio / 32);
> + u32 mask = BIT(gpio % 32);
> + unsigned long flags;
> + u32 value;
> +
> + raw_spin_lock_irqsave(&sfp->lock, flags);
> + value = readl_relaxed(ie) & ~mask;
> + writel_relaxed(value, ie);
> + raw_spin_unlock_irqrestore(&sfp->lock, flags);
> +
> + gpiochip_disable_irq(&sfp->gc, d->hwirq);
You have gpio, why not use it here?
> +}
..
> +static void jh8100_irq_unmask(struct irq_data *d)
> +{
> + struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
> + const struct jh8100_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
> + irq_hw_number_t gpio = irqd_to_hwirq(d);
> + void __iomem *ie = sfp->base + irq_reg->ie_reg_base
> + + 4 * (gpio / 32);
> + u32 mask = BIT(gpio % 32);
> + unsigned long flags;
> + u32 value;
> +
> + gpiochip_enable_irq(&sfp->gc, d->hwirq);
Ditto.
> + raw_spin_lock_irqsave(&sfp->lock, flags);
> + value = readl_relaxed(ie) | mask;
> + writel_relaxed(value, ie);
> + raw_spin_unlock_irqrestore(&sfp->lock, flags);
> +}
..
> +static int jh8100_irq_set_wake(struct irq_data *d, unsigned int enable)
> +{
> + struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
> + int ret = 0;
> +
> + if (enable)
> + ret = enable_irq_wake(sfp->wakeup_irq);
> + else
> + ret = disable_irq_wake(sfp->wakeup_irq);
> + if (ret)
> + dev_err(sfp->dev, "failed to %s wake-up interrupt\n",
> + enable ? "enable" : "disable");
str_enable_disable() (will require string_choices.h).
> + return ret;
> +}
..
> +static void jh8100_irq_print_chip(struct irq_data *d, struct seq_file *p)
> +{
> + struct jh8100_pinctrl *sfp = jh8100_from_irq_data(d);
> +
> + seq_printf(p, sfp->gc.label);
This is bad. Use seq_puts() or proper formatting string.
> +}
..
> + writel_relaxed(~0U, sfp->base + sfp->info->irq_reg->ic_reg_base);
GENMASK() ?
..
> + writel_relaxed(~0U, sfp->base + sfp->info->irq_reg->ic1_reg_base);
Ditto.
..
> + info = of_device_get_match_data(&pdev->dev);
> + if (!info)
> + return -ENODEV;
Use device_get_match_data() from property.h.
..
> + clk = devm_clk_get_optional(dev, NULL);
> + if (IS_ERR(clk))
> + return dev_err_probe(dev, PTR_ERR(clk), "could not get clock\n");
Why not _enabled() variant?
..
> + /*
> + * we don't want to assert reset and risk undoing pin muxing for the
We
> + * early boot serial console, but let's make sure the reset line is
> + * deasserted in case someone runs a really minimal bootloader.
> + */
..
> + ret = devm_pinctrl_register_and_init(dev,
> + jh8100_pinctrl_desc,
> + sfp, &sfp->pctl);
Can occupy less lines.
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "could not register pinctrl driver\n");
..
> + if (sfp->gc.ngpio > 0) {
Is it really can be not true?
> + ret = devm_gpiochip_add_data(dev, &sfp->gc, sfp);
> + if (ret)
> + return dev_err_probe(dev, ret, "could not register gpiochip\n");
> +
> + dev_info(dev, "StarFive JH8100 GPIO chip registered %d GPIOs\n", sfp->gc.ngpio);
> + }
..
> +/*
> + * Pinctrl / GPIO driver for StarFive JH8100 SoC
> + *
> + * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
> + * Author: Alex Soo <[email protected]>
> + *
Unneeded blank line.
> + */
> +
> +#ifndef __PINCTRL_STARFIVE_JH8100_H__
> +#define __PINCTRL_STARFIVE_JH8100_H__
A lot of inclusions are missed, like
types.h
> +#include "../core.h"
Some of the forward declarations are missed, like
struct device;
> +#endif /* __PINCTRL_STARFIVE_JH8100_H__ */
--
With Best Regards,
Andy Shevchenko
Fri, May 03, 2024 at 07:14:29PM +0800, Alex Soo kirjoitti:
> Starfive JH8100 SoC consists of 4 pinctrl domains - sys_east,
> sys_west, sys_gmac, and aon. This patch series adds pinctrl
> drivers for these 4 pinctrl domains and this patch series is
> depending on the JH8100 base patch series in [1] and [2].
> The relevant dt-binding documentation for each pinctrl domain has
> been updated accordingly.
I commented one of pinctrl: prefixed patch, but it looks like the same comments
are applicable to all of them.
--
With Best Regards,
Andy Shevchenko
> -----Original Message-----
> From: Conor Dooley <[email protected]>
> Sent: Saturday, May 4, 2024 12:07 AM
> To: Yuklin Soo <[email protected]>
> Cc: Linus Walleij <[email protected]>; Bartosz Golaszewski
> <[email protected]>; Hal Feng <[email protected]>;
> Leyfoon Tan <[email protected]>; Jianlong Huang
> <[email protected]>; Emil Renner Berthing <[email protected]>;
> Rob Herring <[email protected]>; Krzysztof Kozlowski
> <[email protected]>; Conor Dooley <[email protected]>;
> Drew Fustini <[email protected]>; [email protected]; linux-
> [email protected]; [email protected]; linux-
> [email protected]; Paul Walmsley <[email protected]>; Palmer
> Dabbelt <[email protected]>; Albert Ou <[email protected]>
> Subject: Re: [RFC PATCH v3 1/7] dt-bindings: pinctrl: starfive: Add JH8100 pinctrl
>
> On Fri, May 03, 2024 at 07:14:30PM +0800, Alex Soo wrote:
> > Add documentation and header file for JH8100 pinctrl driver.
> >
> > Signed-off-by: Alex Soo <[email protected]>
>
> > diff --git a/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
> > b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
> > new file mode 100644
> > index 000000000000..153ba950c062
> > --- /dev/null
> > +++ b/include/dt-bindings/pinctrl/starfive,jh8100-pinctrl.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> > +/*
> > + * Copyright (C) 2023-2024 StarFive Technology Co., Ltd.
> > + */
> > +
> > +#ifndef __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
> > +#define __DT_BINDINGS_PINCTRL_STARFIVE_JH8100_H__
> > +
> > +/* Pad Slew Rates */
> > +#define PAD_SLEW_RATE_FAST 1
> > +#define PAD_SLEW_RATE_SLOW 0
>
> Should this really be in the bindings? I don't see it having a direct user in the
> driver.
>
> Also, if this is the only header you have, I think the RFC tag could be dropped,
> since there'll not be a header we need to worry about getting into U-Boot etc
> with values that may change when the SoC moves from an FPGA etc to tape out.
I will drop the PAD_SLEW_RATE_* macros from dt-bindings header and move them
to the DTS header file. Will submit the next version (V4) without the "RFC PATCH"
subject prefix.
>
> Cheers,
> Conor.