From fbfd6d0d3596d072f7546b25228e4eb599f68a95 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 30 Aug 2026 11:02:01 +0800 Subject: [PATCH 01/12] pinctrl: qcom: nord: Split QUP1 SE2/SE3 into lane-pair functions QUP1 SE2 and SE3 pack all four of their lanes pair-wise onto only two pins each: lanes 0/1 (I2C SDA/SCL) at mux value 2 and lanes 2/3 (UART TX/RX) at mux value 1, on gpio127/gpio128 and gpio129/gpio130 respectively. Both mux values were named "qup1_se2" (respectively "qup1_se3"), so the two distinct lane pairs became indistinguishable. msm_pinmux_set_mux() stops at the first entry matching the requested function, which means mux value 1 was always selected and the I2C lanes could never be muxed out. In practice i2c9 and i2c10 got the UART lanes and did not work, while uart9 and uart10 happened to be muxed correctly. Give each lane pair its own function, following the _01/_23 naming already used for the same hardware arrangement by the shikra, eliza, hawi and maili TLMM drivers. Both functions still cover the full pin pair, so a single pinctrl state per protocol remains sufficient. Drop gpio129/gpio130 from the SE2 group list, since those pins belong to SE3 and were never reachable through the SE2 function. Also rename QUP1 SE2/SE3 functions in the binding doc accordingly. While at it, add missing "gpio", "qup3_se0_mira" and "qup3_se0_mirb" to the binding function enum to get the list complete. Fixes: c24dd0826f06 ("pinctrl: qcom: add the TLMM driver for the Nord platforms") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Shawn Guo Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260830030201.135637-1-shengchao.guo@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- .../bindings/pinctrl/qcom,nord-tlmm.yaml | 7 ++-- drivers/pinctrl/qcom/pinctrl-nord.c | 34 +++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml index 4bb511719f31..56758a85ead8 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,nord-tlmm.yaml @@ -67,7 +67,7 @@ $defs: Specify the alternative function to be configured for the specified pins. - enum: [ aoss_cti, atest_char, atest_usb20, atest_usb21, + enum: [ gpio, aoss_cti, atest_char, atest_usb20, atest_usb21, aud_intfc0_clk, aud_intfc0_data, aud_intfc0_ws, aud_intfc10_clk, aud_intfc10_data, aud_intfc10_ws, aud_intfc1_clk, aud_intfc1_data, aud_intfc1_ws, @@ -98,9 +98,10 @@ $defs: pcie3_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux, prng_rosc0, prng_rosc1, pwrbrk_i_n, qdss, qdss_cti, qspi, qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5, - qup1_se0, qup1_se1, qup1_se3, qup1_se2, qup1_se4, qup1_se5, + qup1_se0, qup1_se1, qup1_se2_01, qup1_se2_23, qup1_se3_01, + qup1_se3_23, qup1_se4, qup1_se5, qup1_se6, qup2_se0, qup2_se1, qup2_se2, qup2_se3, qup2_se4, - qup2_se5, qup2_se6, + qup2_se5, qup2_se6, qup3_se0_mira, qup3_se0_mirb, sailss_ospi, sdc4_clk, sdc4_cmd, sdc4_data, smb_alert, smb_alert_n, smb_clk, smb_dat, tb_trig_sdc4, tmess_prng0, tmess_prng1, tsc_timer, tsense_pwm, usb0_hs, diff --git a/drivers/pinctrl/qcom/pinctrl-nord.c b/drivers/pinctrl/qcom/pinctrl-nord.c index 7c21306e77ff..7f37f8e819ba 100644 --- a/drivers/pinctrl/qcom/pinctrl-nord.c +++ b/drivers/pinctrl/qcom/pinctrl-nord.c @@ -570,8 +570,10 @@ enum nord_functions { msm_mux_qup0_se5, msm_mux_qup1_se0, msm_mux_qup1_se1, - msm_mux_qup1_se2, - msm_mux_qup1_se3, + msm_mux_qup1_se2_01, + msm_mux_qup1_se2_23, + msm_mux_qup1_se3_01, + msm_mux_qup1_se3_23, msm_mux_qup1_se4, msm_mux_qup1_se5, msm_mux_qup1_se6, @@ -1152,11 +1154,19 @@ static const char *const qup1_se1_groups[] = { "gpio123", "gpio124", "gpio125", "gpio126", }; -static const char *const qup1_se2_groups[] = { - "gpio127", "gpio128", "gpio129", "gpio130", +static const char *const qup1_se2_01_groups[] = { + "gpio127", "gpio128", }; -static const char *const qup1_se3_groups[] = { +static const char *const qup1_se2_23_groups[] = { + "gpio127", "gpio128", +}; + +static const char *const qup1_se3_01_groups[] = { + "gpio129", "gpio130", +}; + +static const char *const qup1_se3_23_groups[] = { "gpio129", "gpio130", }; @@ -1428,8 +1438,10 @@ static const struct pinfunction nord_functions[] = { MSM_PIN_FUNCTION(qup0_se5), MSM_PIN_FUNCTION(qup1_se0), MSM_PIN_FUNCTION(qup1_se1), - MSM_PIN_FUNCTION(qup1_se2), - MSM_PIN_FUNCTION(qup1_se3), + MSM_PIN_FUNCTION(qup1_se2_01), + MSM_PIN_FUNCTION(qup1_se2_23), + MSM_PIN_FUNCTION(qup1_se3_01), + MSM_PIN_FUNCTION(qup1_se3_23), MSM_PIN_FUNCTION(qup1_se4), MSM_PIN_FUNCTION(qup1_se5), MSM_PIN_FUNCTION(qup1_se6), @@ -1633,13 +1645,13 @@ static const struct msm_pingroup nord_groups[] = { _, _, _, _, _, _, _), [126] = PINGROUP(126, qup1_se1, qup1_se0, ccu_i2c_scl, mdp1_vsync_out, _, atest_usb20, ddr_pxi, _, _, _, _), - [127] = PINGROUP(127, qup1_se2, qup1_se2, _, atest_usb21, ddr_pxi, + [127] = PINGROUP(127, qup1_se2_23, qup1_se2_01, _, atest_usb21, ddr_pxi, _, _, _, _, _, _), - [128] = PINGROUP(128, qup1_se2, qup1_se2, _, atest_usb20, ddr_pxi, + [128] = PINGROUP(128, qup1_se2_23, qup1_se2_01, _, atest_usb20, ddr_pxi, _, _, _, _, _, _), - [129] = PINGROUP(129, qup1_se3, qup1_se3, ccu_i2c_sda, mdp1_vsync_out, + [129] = PINGROUP(129, qup1_se3_23, qup1_se3_01, ccu_i2c_sda, mdp1_vsync_out, _, atest_usb21, ddr_pxi, _, _, _, _), - [130] = PINGROUP(130, qup1_se3, qup1_se3, ccu_i2c_scl, mdp1_vsync_out, + [130] = PINGROUP(130, qup1_se3_23, qup1_se3_01, ccu_i2c_scl, mdp1_vsync_out, _, atest_usb20, ddr_pxi, _, _, _, _), [131] = PINGROUP(131, qup1_se4, qup1_se6, ccu_i2c_sda, mdp1_vsync_out, _, atest_usb21, ddr_pxi, _, _, _, _), From 818103dc7f5998a0d7957fb71d4deecdf4d579e1 Mon Sep 17 00:00:00 2001 From: "hpp.iscas" Date: Sat, 5 Sep 2026 21:43:40 +0800 Subject: [PATCH 02/12] pinctrl: qcom: ipq5210: Publish the OF module alias The IPQ5210 TLMM platform driver can be a module and matches through ipq5210_tlmm_of_match. This table is not published for OF modalias matching. Publish the existing table, preserving arch_initcall ordering and the shared MSM pinctrl probe. Fixes: a549fe22376f ("pinctrl: qcom: Introduce IPQ5210 TLMM driver") Signed-off-by: hpp.iscas Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260905134340.67477-1-hppiscas@163.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-ipq5210.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5210.c b/drivers/pinctrl/qcom/pinctrl-ipq5210.c index 827a4ad07a6b..d5b4eb3e7343 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5210.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5210.c @@ -867,6 +867,7 @@ static const struct of_device_id ipq5210_tlmm_of_match[] = { { .compatible = "qcom,ipq5210-tlmm", }, { }, }; +MODULE_DEVICE_TABLE(of, ipq5210_tlmm_of_match); static int ipq5210_tlmm_probe(struct platform_device *pdev) { From 68ab4a6a84b92f52650508acb60317eb76454250 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Wed, 16 Sep 2026 16:57:20 +0800 Subject: [PATCH 03/12] pinctrl: qcom: nord: fix GPIO interrupt target width The TARGET_PROC field in the Nord GPIO_INTR_CFG registers occupies bits 11:8. Describe it as four bits wide so the common Qualcomm pinctrl code clears the complete field before routing an interrupt to the application processor. Without intr_target_width, the common code uses its three-bit default mask. Since GPIO_INTR_CFG resets with TARGET_PROC set to 0xf (NONE), bit 11 remains set when the driver programs HMSS target 3. The resulting target is 0xb (HPASS_DSP_1), observed as an interrupt configuration value of 0xb1b instead of 0x31b. The GPIO interrupt status is consequently latched, but the HMSS TLMM summary interrupt at GIC SPI 208 is never asserted. This affects all Nord GPIO interrupts using the TLMM summary path, including the Ethernet PHY interrupts on GPIO55 and GPIO141. Fixes: c24dd0826f06 ("pinctrl: qcom: add the TLMM driver for the Nord platforms") Signed-off-by: Zhangfei Gao Reviewed-by: Konrad Dybcio Reviewed-by: Shawn Guo Link: https://patch.msgid.link/20260916085720.771498-1-zhangfei.gao@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-nord.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/qcom/pinctrl-nord.c b/drivers/pinctrl/qcom/pinctrl-nord.c index 7f37f8e819ba..010760cf0bf5 100644 --- a/drivers/pinctrl/qcom/pinctrl-nord.c +++ b/drivers/pinctrl/qcom/pinctrl-nord.c @@ -32,6 +32,7 @@ .intr_wakeup_present_bit = 6, \ .intr_wakeup_enable_bit = 7, \ .intr_target_bit = 8, \ + .intr_target_width = 4, \ .intr_target_kpss_val = 3, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ From 9d4c3e0c6a53eb390d58b8d7aaf08885e46f93fd Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 17 Sep 2026 11:03:25 +0200 Subject: [PATCH 04/12] pinctrl: qcom: hawi: Fix intr_target_width The default width of the interrupt target field doesn't match the actual register layout. Fix it. Fixes: 90700e10d2ad ("pinctrl: qcom: Add Hawi pinctrl driver") Assisted-by: LLM Signed-off-by: Konrad Dybcio Reviewed-by: Shawn Guo Link: https://patch.msgid.link/20260917-topic-tlmm_intr_width_fixes-v1-1-3bc1d056aa6b@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-hawi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/qcom/pinctrl-hawi.c b/drivers/pinctrl/qcom/pinctrl-hawi.c index cdde69e954a7..3486a6d63d10 100644 --- a/drivers/pinctrl/qcom/pinctrl-hawi.c +++ b/drivers/pinctrl/qcom/pinctrl-hawi.c @@ -47,6 +47,7 @@ .intr_wakeup_present_bit = 6, \ .intr_wakeup_enable_bit = 7, \ .intr_target_bit = 8, \ + .intr_target_width = 4, \ .intr_target_kpss_val = 3, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ From 912df33f296e6c4ced8c0a5e7998d570a0b82214 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 17 Sep 2026 11:03:26 +0200 Subject: [PATCH 05/12] pinctrl: qcom: maili: Fix intr_target_width The default width of the interrupt target field doesn't match the actual register layout. Fix it. Fixes: 251b53103a2e ("pinctrl: qcom: Add the tlmm driver for Maili platform") Assisted-by: LLM Signed-off-by: Konrad Dybcio Reviewed-by: Shawn Guo Link: https://patch.msgid.link/20260917-topic-tlmm_intr_width_fixes-v1-2-3bc1d056aa6b@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-maili.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/qcom/pinctrl-maili.c b/drivers/pinctrl/qcom/pinctrl-maili.c index ffa084cfad64..b9ff0f447941 100644 --- a/drivers/pinctrl/qcom/pinctrl-maili.c +++ b/drivers/pinctrl/qcom/pinctrl-maili.c @@ -47,6 +47,7 @@ .intr_wakeup_present_bit = 6, \ .intr_wakeup_enable_bit = 7, \ .intr_target_bit = 8, \ + .intr_target_width = 4, \ .intr_target_kpss_val = 3, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ From dcb5df182b37587d5ad6bb4388751bf5180957ac Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 17 Sep 2026 11:03:27 +0200 Subject: [PATCH 06/12] pinctrl: qcom: qcs8300: Fix intr_target_width The default width of the interrupt target field doesn't match the actual register layout. Fix it. Fixes: 0c4cd2cc87c8 ("pinctrl: qcom: add the tlmm driver for QCS8300 platforms") Assisted-by: LLM Signed-off-by: Konrad Dybcio Reviewed-by: Shawn Guo Link: https://patch.msgid.link/20260917-topic-tlmm_intr_width_fixes-v1-3-3bc1d056aa6b@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-qcs8300.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs8300.c b/drivers/pinctrl/qcom/pinctrl-qcs8300.c index 9a904d809e11..fec86818c511 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs8300.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs8300.c @@ -45,6 +45,7 @@ .intr_enable_bit = 0, \ .intr_status_bit = 0, \ .intr_target_bit = 5, \ + .intr_target_width = 4, \ .intr_target_kpss_val = 3, \ .intr_raw_status_bit = 4, \ .intr_polarity_bit = 1, \ From c6c159fcdb4e9a678eda0831f971e4a3a488ec47 Mon Sep 17 00:00:00 2001 From: Gilberto Conde Date: Mon, 21 Sep 2026 10:34:19 +0100 Subject: [PATCH 07/12] pinctrl: qcom: ipq5018: add missing pwm3 function on gpio13 GPIO13 supports the PWM3 function at mux select value 4, but the pingroup table leaves that slot empty and gpio13 is not listed in pwm3_groups. Selecting pwm3 on gpio13 is therefore rejected by the pinmux core: ipq5018-tlmm: invalid group "gpio13" for function "pwm3" The GL.iNet GL-X2000 drives its fan from PWM3 on this pin, and the vendor firmware muxes it with select value 4: gpio13 : out low func4 8mA no pull Add pwm3 to the fourth function slot of gpio13 and list gpio13 in pwm3_groups. With this the pin muxes as expected: pin 13 (GPIO_13): device 1941010.pwm function pwm3 group gpio13 Fixes: 725d1c891658 ("pinctrl: qcom: Add IPQ5018 pinctrl driver") Signed-off-by: Gilberto Conde Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260921093419.2870168-1-gilbertorconde@gmail.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-ipq5018.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index 03cfba9534f8..84392fe258c9 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -563,7 +563,7 @@ static const char * const qdss_cti_trig_out_b1_groups[] = { }; static const char * const pwm3_groups[] = { - "gpio45", + "gpio45", "gpio13", }; static const char * const qdss_cti_trig_in_b1_groups[] = { @@ -689,7 +689,7 @@ static const struct msm_pingroup ipq5018_groups[] = { PINGROUP(10, blsp0_spi, blsp1_uart0, led0, gcc_plltest, qdss_tracedata_a, _, _, _, _), PINGROUP(11, blsp0_spi, blsp1_uart0, _, gcc_tlmm, qdss_tracedata_a, _, _, _, _), PINGROUP(12, blsp0_spi, blsp0_i2c, blsp1_uart0, _, gcc_plltest, qdss_tracedata_a, _, _, _), - PINGROUP(13, blsp0_spi, blsp0_i2c, blsp1_uart0, _, qdss_tracedata_a, _, _, _, _), + PINGROUP(13, blsp0_spi, blsp0_i2c, blsp1_uart0, pwm3, qdss_tracedata_a, _, _, _, _), PINGROUP(14, pcie0_clk, _, _, cri_trng0, qdss_tracedata_a, _, _, _, _), PINGROUP(15, _, _, cri_trng1, qdss_tracedata_a, _, _, _, _, _), PINGROUP(16, pcie0_wake, _, _, cri_trng, qdss_tracedata_a, _, _, _, _), From 19fc4240358be2a25ce8e0a49a2819588ed61c5d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 27 Sep 2026 09:09:13 +0800 Subject: [PATCH 08/12] pinctrl: qcom: spmi-gpio: make direction changes exclusive Neither direction callback clears the opposite buffer: .direction_output() only packs PIN_CONFIG_LEVEL and .direction_input() only packs PIN_CONFIG_INPUT_ENABLE. As pmic_gpio_populate() seeds input_enabled and output_enabled from MODE_CTL, a pad left in DIGITAL_INPUT[_OUTPUT] by the bootloader ends up in DIGITAL_INPUT_OUTPUT whichever direction is requested. That leaves an input still driving the line, and makes pmic_gpio_get_direction() report an output as an input, which breaks consumers that read the direction back: reg-fixed-voltage regulator-wcn-core-vm-1p35: setup of GPIO (default) failed: -1 reg-fixed-voltage regulator-wcn-core-vm-1p35: error -EPERM: can't get GPIO Pack the opposite buffer's PIN_CONFIG_*_ENABLE along with the requested direction, so MODE_CTL becomes DIGITAL_INPUT or DIGITAL_OUTPUT, never both. pmic_gpio_config_set() writes the registers once after walking all configs, so this stays a single write. An open-drain or open-source output is the exception: it only drives one rail, so pmic_gpio_get() needs the input buffer to sample the line rather than return the value last written. Program the input buffer from pad->buffer_type, which gpiolib has already updated via PIN_CONFIG_DRIVE_OPEN_DRAIN, and key pmic_gpio_get_direction() off output_enabled so such pads still read back as outputs. Genuinely bidirectional pads can still be described that way through pinconf; the gpiolib callbacks now mean what gpiolib says they mean. Fixes: 263447532463 ("pinctrl: qcom: spmi-gpio: implement .get_direction()") Assisted-by: LLM Reviewed-by: Linus Walleij Signed-off-by: Shawn Guo Link: https://patch.msgid.link/20260927010913.1212600-1-shengchao.guo@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 37 +++++++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 922c27177b5a..c6f93fb1dc20 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -734,29 +734,50 @@ static int pmic_gpio_get_direction(struct gpio_chip *chip, unsigned pin) (!pad->input_enabled && !pad->output_enabled)) return -EINVAL; - /* Make sure the state is aligned on what pmic_gpio_get() returns */ - return pad->input_enabled ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; + /* + * An open-drain or open-source pad keeps its input buffer enabled while + * driving, so the output buffer is what tells the direction. + */ + return pad->output_enabled ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { struct pmic_gpio_state *state = gpiochip_get_data(chip); - unsigned long config; + unsigned long configs[2]; - config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); + configs[0] = pinconf_to_config_packed(PIN_CONFIG_OUTPUT_ENABLE, 0); + configs[1] = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); - return pmic_gpio_config_set(state->ctrl, pin, &config, 1); + return pmic_gpio_config_set(state->ctrl, pin, configs, + ARRAY_SIZE(configs)); } static int pmic_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int val) { struct pmic_gpio_state *state = gpiochip_get_data(chip); - unsigned long config; + struct pmic_gpio_pad *pad = state->ctrl->desc->pins[pin].drv_data; + unsigned long configs[2]; - config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val); + /* + * An open-drain or open-source pad only ever drives one rail, so the + * line can still be sampled while the pad is an output. Keep the input + * buffer enabled for those, so that pmic_gpio_get() reports what is on + * the wire rather than the value last written, and disable it for a + * CMOS pad, so that the pad ends up in DIGITAL_OUTPUT rather than + * DIGITAL_INPUT_OUTPUT. Program it either way, as the buffer may have + * been left in the opposite state by the bootloader or by an earlier + * direction change with a different buffer type. gpiolib applies + * PIN_CONFIG_DRIVE_OPEN_DRAIN before calling this, so buffer_type is + * already up to date here. + */ + configs[0] = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, + pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS); + configs[1] = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val); - return pmic_gpio_config_set(state->ctrl, pin, &config, 1); + return pmic_gpio_config_set(state->ctrl, pin, configs, + ARRAY_SIZE(configs)); } static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin) From 65db42a9fae05c46a5df5b7ca5c175b80f9c4278 Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Mon, 28 Sep 2026 13:48:47 +0400 Subject: [PATCH 09/12] pinctrl: qcom: ipq5018: update PWM groups and corresponding pin functions On multiple Linksys routers, GPIOs 1, 30, and 46 drive the PWM LED on the PWM1, PWM3, and PWM0 channels, respectively. Update the corresponding PWM groups to include these GPIOs and allocate the PWM functions to empty slots in the relevant pin groups. Signed-off-by: George Moussalem Link: https://patch.msgid.link/20260928-ipq5018-pwm-functions-v2-1-87bbcd706bc6@outlook.com Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-ipq5018.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index 84392fe258c9..74fccdd5146a 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -539,7 +539,7 @@ static const char * const qdss_tracectl_b_groups[] = { }; static const char * const pwm0_groups[] = { - "gpio42", + "gpio42", "gpio46", }; static const char * const qdss_cti_trig_out_b0_groups[] = { @@ -547,7 +547,7 @@ static const char * const qdss_cti_trig_out_b0_groups[] = { }; static const char * const pwm1_groups[] = { - "gpio43", + "gpio43", "gpio1", }; static const char * const qdss_cti_trig_in_b0_groups[] = { @@ -563,7 +563,7 @@ static const char * const qdss_cti_trig_out_b1_groups[] = { }; static const char * const pwm3_groups[] = { - "gpio45", "gpio13", + "gpio45", "gpio30", "gpio13", }; static const char * const qdss_cti_trig_in_b1_groups[] = { @@ -677,7 +677,7 @@ static const struct pinfunction ipq5018_functions[] = { static const struct msm_pingroup ipq5018_groups[] = { PINGROUP(0, atest_char, _, qdss_cti_trig_out_a0, wci_txd, wci_rxd, xfem, _, _, _), - PINGROUP(1, atest_char, _, qdss_cti_trig_in_a0, wci_txd, wci_rxd, xfem, _, _, _), + PINGROUP(1, atest_char, pwm1, qdss_cti_trig_in_a0, wci_txd, wci_rxd, xfem, _, _, _), PINGROUP(2, atest_char, _, qdss_cti_trig_out_a1, wci_txd, wci_rxd, xfem, _, _, _), PINGROUP(3, atest_char, _, qdss_cti_trig_in_a1, wci_txd, wci_rxd, xfem, _, _, _), PINGROUP(4, sdc1_data, qspi_data, blsp1_spi1, btss, dbg_out, qdss_traceclk_a, _, burn0, _), @@ -706,7 +706,7 @@ static const struct msm_pingroup ipq5018_groups[] = { PINGROUP(27, audio_txmclk, wsa_swrm, audio_txmclk, blsp2_spi, btss, _, qdss_tracedata_b, _, _), PINGROUP(28, audio_txbclk, wsa_swrm, blsp0_uart1, btss, qdss_tracedata_b, _, _, _, _), PINGROUP(29, audio_txfsync, _, blsp0_uart1, _, qdss_tracedata_b, _, _, _, _), - PINGROUP(30, audio_txd, led2, led0, _, _, _, _, _, _), + PINGROUP(30, audio_txd, led2, led0, pwm3, _, _, _, _, _), PINGROUP(31, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _, _), PINGROUP(32, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _, _), PINGROUP(33, blsp2_i2c0, blsp2_spi0, blsp1_uart1, _, qdss_tracedata_b, eud_gpio, _, _, _), @@ -722,7 +722,7 @@ static const struct msm_pingroup ipq5018_groups[] = { PINGROUP(43, pwm1, qdss_cti_trig_in_b0, wci_txd, wci_rxd, xfem, _, _, _, _), PINGROUP(44, pwm2, qdss_cti_trig_out_b1, wci_txd, wci_rxd, xfem, _, _, _, _), PINGROUP(45, pwm3, qdss_cti_trig_in_b1, wci_txd, wci_rxd, xfem, _, _, _, _), - PINGROUP(46, led0, _, _, _, _, _, _, _, _), + PINGROUP(46, led0, pwm0, _, _, _, _, _, _, _), }; static const struct msm_pinctrl_soc_data ipq5018_pinctrl = { From 709ba1c547eaf37da36ded2ecf3ea4e304cdfa9a Mon Sep 17 00:00:00 2001 From: Adriel Santos Date: Fri, 2 Oct 2026 13:09:58 -0300 Subject: [PATCH 10/12] pinctrl: qcom: ipq5018: replace gcc_plltest with pwm2 on gpio12 The pingroup table has gcc_plltest at function 5 of gpio12 and does not offer pwm2 on that pin, so the pinmux core rejects a request for pwm2 on gpio12 as an invalid group. On the hardware, function 5 of gpio12 carries the PWM2 output: the Xiaomi AX3000T v2 drives its blue status LED from PWM2 on gpio12. The vendor kernel shipped on that router (Linux 4.4, stock firmware 2.0.28) has pwm2 in this slot. Its pingroup table, as read from the firmware image, lists these functions for gpio12: gpio, blsp0_spi, blsp0_i2c, blsp1_uart0, _, pwm2, qdss_tracedata_a, _, _, _ and has pwm3 at function 4 of gpio13, matching commit c6c159fcdb4e ("pinctrl: qcom: ipq5018: add missing pwm3 function on gpio13"). Measured on the board: with gpio12 set to each of the 16 function values in turn, and PWM2 held at 0% and then at 100% duty, the pad level read back from GPIO_IN follows PWM2 only at function 5. There it does not follow PWM channels 0, 1 or 3, and the LED switches with PWM2. Functions 4 and 7, which the table leaves empty, do not carry PWM2. Put pwm2 in function 5 of gpio12 and list gpio12 in pwm2_groups. Drop gpio12 from gcc_plltest_groups: none of its functions is gcc_plltest any more, and selecting it would trigger the WARN_ON() in msm_pinmux_set_mux(). Fixes: 725d1c891658 ("pinctrl: qcom: Add IPQ5018 pinctrl driver") Assisted-by: LLM Signed-off-by: Adriel Santos Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20261002160958.908424-1-adriel@adriel.eu Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/qcom/pinctrl-ipq5018.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index 74fccdd5146a..1660004edad7 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -361,7 +361,7 @@ static const char * const blsp1_uart0_groups[] = { }; static const char * const gcc_plltest_groups[] = { - "gpio10", "gpio12", + "gpio10", }; static const char * const gcc_tlmm_groups[] = { @@ -555,7 +555,7 @@ static const char * const qdss_cti_trig_in_b0_groups[] = { }; static const char * const pwm2_groups[] = { - "gpio44", + "gpio12", "gpio44", }; static const char * const qdss_cti_trig_out_b1_groups[] = { @@ -688,7 +688,7 @@ static const struct msm_pingroup ipq5018_groups[] = { PINGROUP(9, sdc1_clk, qspi_clk, _, qdss_tracedata_a, _, _, _, _, _), PINGROUP(10, blsp0_spi, blsp1_uart0, led0, gcc_plltest, qdss_tracedata_a, _, _, _, _), PINGROUP(11, blsp0_spi, blsp1_uart0, _, gcc_tlmm, qdss_tracedata_a, _, _, _, _), - PINGROUP(12, blsp0_spi, blsp0_i2c, blsp1_uart0, _, gcc_plltest, qdss_tracedata_a, _, _, _), + PINGROUP(12, blsp0_spi, blsp0_i2c, blsp1_uart0, _, pwm2, qdss_tracedata_a, _, _, _), PINGROUP(13, blsp0_spi, blsp0_i2c, blsp1_uart0, pwm3, qdss_tracedata_a, _, _, _, _), PINGROUP(14, pcie0_clk, _, _, cri_trng0, qdss_tracedata_a, _, _, _, _), PINGROUP(15, _, _, cri_trng1, qdss_tracedata_a, _, _, _, _, _), From 1cca81a683da7f0ef2fbaf34442376044cbbad22 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 5 Oct 2026 13:01:47 -0500 Subject: [PATCH 11/12] pinctrl: amd: Clear S4 wake bits when firmware has _AEI Commit ffe8a0c6b552 ("pinctrl-amd: Don't clear S4 wake bits at probe") preserves firmware-programmed S4 wake sources because some PCIe devices rely on them for Wake-on-LAN. The system that motivated that change does not expose ACPI GPIO events through _AEI. On a Chuwi CoreBook Plus, firmware exposes _AEI but also leaves the S4/S5 wake bit set for GPIO 24. This causes the machine to power back on immediately after shutdown even though Wake-on-LAN is not enabled. GPIO register dumps show that the only relevant difference is bit 15 on GPIO 24. Clearing that bit makes the machine remain off. GPIO 24 is not itself listed in _AEI, so _AEI is not a per-pin indication of which pins the OS manages; it is a platform level signal of which wake model the firmware follows. Use that signal to decide what to clear. Continue clearing S0i3/S3 bits on every system. Clear S4 bits when firmware exposes _AEI, indicating that the platform hands GPIO events to the OS, but preserve S4 bits when _AEI is absent so that firmware-programmed sources such as PCIe PME that bypass the GPIO IRQ wake API keep working. A platform that exposes _AEI for some pins while routing a wake capable device through a raw GPIO not listed in _AEI would lose that wake source unless firmware re-arms it during the sleep transition. No such system has been reported. Fixes: ffe8a0c6b552 ("pinctrl-amd: Don't clear S4 wake bits at probe") Reported-by: Olzhas Marat Closes: https://bugzilla.kernel.org/show_bug.cgi?id=222041 Cc: stable@vger.kernel.org Tested-by: Olzhas Marat Reviewed-by: Shyam Sundar S K Signed-off-by: Mario Limonciello Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 15a398bb3be2..6835e943909c 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -886,6 +886,15 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev) mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3); +#ifdef CONFIG_ACPI + /* + * Platforms without _AEI leave GPIO wake sources to firmware, so + * preserve their S4 wake bits. + */ + if (acpi_has_method(ACPI_HANDLE(&gpio_dev->pdev->dev), "_AEI")) + mask |= BIT(WAKE_CNTRL_OFF_S4); +#endif + for (i = 0; i < desc->npins; i++) { int pin = desc->pins[i].number; const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); From c5895eadf287116434b7b01d67b92e8146f7ff61 Mon Sep 17 00:00:00 2001 From: Pablo Mazzini Date: Wed, 7 Oct 2026 07:01:07 +0100 Subject: [PATCH 12/12] pinctrl: sunxi: dt: do not accumulate npins across probe attempts init_pins_table() adds to npins in the driver's static descriptor, so after a probe deferral the count doubles and the next probe fails with "pin 0 already registered". Reset it first. Signed-off-by: Pablo Mazzini Fixes: f5e2cd34b12f ("pinctrl: sunxi: allow reading mux values from DT") Reviewed-by: Andre Przywara Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c index 50a16f3bd131..8bcd566593ae 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c @@ -84,6 +84,7 @@ static struct sunxi_desc_pin *init_pins_table(struct device *dev, * Find the total number of pins. * Also work out how much memory we need to store all the pin names. */ + desc->npins = 0; for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) { desc->npins += pins_per_bank[i]; if (pins_per_bank[i] < 10) {