From 5dea2ac16062e708b8a86cf65835873ce04fc31a Mon Sep 17 00:00:00 2001 From: Jiali Chen Date: Tue, 30 Dec 2025 09:34:06 +0000 Subject: [PATCH 1/4] usb: typec: tcpm: support skipping VSafe0V check On some hardware designs, the 5V VBUS output cannot be controlled or disabled by the TCPM (e.g., fixed 5V supply or lack of a load switch). Consequently, the VBUS voltage is unable to drop to the VSafe0V level required by the standard state machine. Currently, the TCPM blocks the transition from SRC_STARTUP to SRC_ATTACHED until VSafe0V is detected. On hardware that cannot switch off VBUS, this causes the port to hang or fail negotiation. This patch adds a new device property "tcpm,skip-vsafe0v-check". When set, the TCPM ignores the VSafe0V requirement and allows the state machine to proceed, enabling support for hardware with uncontrollable VBUS. Signed-off-by: Jiali Chen --- drivers/usb/typec/tcpm/tcpm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index b2a568a5bc9b0..fdf17b2c742ed 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -388,6 +388,7 @@ struct tcpm_port { * Set to false when vbus is greater than VSAFE0V max. */ bool vbus_vsafe0v; + bool skip_vsafe0v_check; bool vbus_never_low; bool vbus_source; @@ -4805,7 +4806,8 @@ static void run_state_machine(struct tcpm_port *port) else if (tcpm_port_is_audio(port)) tcpm_set_state(port, AUDIO_ACC_ATTACHED, port->timings.cc_debounce_time); - else if (tcpm_port_is_source(port) && port->vbus_vsafe0v) + else if (tcpm_port_is_source(port) && + (port->vbus_vsafe0v || port->skip_vsafe0v_check)) tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED, @@ -7902,6 +7904,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) goto out_unregister_pd; } + port->skip_vsafe0v_check = device_property_read_bool(dev, "tcpm,skip-vsafe0v-check"); + typec_port_register_altmodes(port->typec_port, &tcpm_altmode_ops, port, port->port_altmode, ALTMODE_DISCOVERY_MAX); From ea2ea8ddb67bb441806f59c03b7f8019fca82051 Mon Sep 17 00:00:00 2001 From: Jiali Chen Date: Tue, 30 Dec 2025 09:41:46 +0000 Subject: [PATCH 2/4] usb: typec: fusb302: workaround for fixed VBUS hardware On some hardware designs where the 5V VBUS is fixed (always on) or cannot be controlled by the FUSB302, the TCPM state machine may hang during the transition to SRC_ATTACHED. Normally, when TCPM instructs the driver to enable VBUS, it waits for a VBUS_PRESENT signal from the port driver. However, if VBUS is already physically present (because it's hardwired), the FUSB302 does not generate a new interrupt or status change, causing the TCPM to time out waiting for VBUS. This patch introduces a new device property "fcs,force-vbus-toggle". When set, the driver manually toggles the internal VBUS presence state and notifies the TCPM during the VBUS enabling phase. This simulates a VBUS rising edge, satisfying the state machine's requirement to proceed. Signed-off-by: Jiali Chen --- drivers/usb/typec/tcpm/fusb302.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 870a71f953f6c..a867d031ee8dd 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -99,6 +99,7 @@ struct fusb302_chip { bool intr_togdone; bool intr_bc_lvl; bool intr_comp_chng; + bool force_vbus_toggle; /* port status */ bool vconn_on; @@ -776,6 +777,13 @@ static int tcpm_set_vbus(struct tcpc_dev *dev, bool on, bool charge) } chip->vbus_on = on; fusb302_log(chip, "vbus := %s", str_on_off(on)); + if (on && chip->force_vbus_toggle) { + fusb302_log(chip, "WORKAROUND: Forcing VBUS toggle for TCPM state machine"); + chip->vbus_present = false; + tcpm_vbus_change(chip->tcpm_port); + chip->vbus_present = true; + tcpm_vbus_change(chip->tcpm_port); + } } if (chip->charge_on == charge) fusb302_log(chip, "charge is already %s", str_on_off(charge)); @@ -1723,6 +1731,8 @@ static int fusb302_probe(struct i2c_client *client) if (IS_ERR(chip->vbus)) return PTR_ERR(chip->vbus); + chip->force_vbus_toggle = device_property_read_bool(chip->dev, "fcs,force-vbus-toggle"); + chip->wq = create_singlethread_workqueue(dev_name(chip->dev)); if (!chip->wq) return -ENOMEM; From 8fe9354f3ebb6e88bab2d5d0f08c3da84902044a Mon Sep 17 00:00:00 2001 From: Jiali Chen Date: Tue, 30 Dec 2025 09:48:22 +0000 Subject: [PATCH 3/4] arm64: dts: meson: radxa-zero: add USB Type-C support via FUSB302 Enable the FUSB302 USB Type-C controller on the Radxa Zero board. The FUSB302 is connected via I2C3 and handles the CC communication. Since the VBUS on this board is derived from the system 5V and cannot be independently switched off or regulated to 0V, we configure the node with specific properties to handle this hardware limitation: - 'tcpm,skip-vsafe0v-check': To bypass the VSafe0V requirement. - 'fcs,force-vbus-toggle': To simulate VBUS toggle for the TCPM state machine. This patch also: - Adds the fixed 5V VBUS regulator. - Adds a GPIO-based SBU mux for orientation switching. - Links the DWC3 USB controller to the Type-C connector via OF graph. - Configures the port as a Source (Power) and Host (Data) by default. Signed-off-by: Jiali Chen --- .../dts/amlogic/meson-g12a-radxa-zero.dts | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts index 4353485c6f26b..d6a117b49b1b7 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts @@ -8,6 +8,7 @@ #include "meson-g12a.dtsi" #include #include +#include / { compatible = "radxa,zero", "amlogic,g12a"; @@ -129,6 +130,14 @@ regulator-always-on; }; + typec_vbus: regulator-typec-vbus { + compatible = "regulator-fixed"; + regulator-name = "TYPEC_VBUS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&ao_5v>; + }; + sound { compatible = "amlogic,axg-sound-card"; model = "RADXA-ZERO"; @@ -186,6 +195,20 @@ }; }; + usb-sbu-mux { + compatible = "gpio-sbu-mux"; + select-gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb_sbu_default>; + pinctrl-names = "default"; + orientation-switch; + + port { + usb0_sbu_mux: endpoint { + remote-endpoint = <&ucsi0_sbu>; + }; + }; + }; + wifi32k: wifi32k { compatible = "pwm-clock"; #clock-cells = <0>; @@ -246,6 +269,81 @@ }; }; +&dwc3 { + ports { + usb_dwc2_out: endpoint@0 { + remote-endpoint = <&ucsi0_hs_in>; + }; + + usb_dwc3_out: endpoint@1 { + remote-endpoint = <&ucsi0_ss_in>; + }; + }; +}; + +&i2c3 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; + pinctrl-names = "default"; + status = "okay"; + + fusb302@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + + pinctrl-0 = <&fusb302_irq_pins>; + pinctrl-names = "default"; + interrupt-parent = <&gpio_intc>; + interrupts = ; + tcpm,skip-vsafe0v-check; + fcs,force-vbus-toggle; + + vbus-supply = <&typec_vbus>; + + status = "okay"; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "host"; + /* fusb302 supports PD Rev 2.0 Ver 1.2 */ + pd-revision = /bits/ 8 <0x2 0x0 0x1 0x2>; + power-role = "source"; + source-pdos = ; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + ucsi0_hs_in: endpoint { + remote-endpoint = <&usb_dwc2_out>; + }; + }; + + port@1 { + reg = <1>; + + ucsi0_ss_in: endpoint { + remote-endpoint = <&usb_dwc3_out>; + }; + }; + + port@2 { + reg = <2>; + + ucsi0_sbu: endpoint { + remote-endpoint = <&usb0_sbu_mux>; + }; + }; + }; + }; + }; +}; + &frddr_a { status = "okay"; }; @@ -397,3 +495,23 @@ &usb { status = "okay"; }; + +&ao_pinctrl { + fusb302_irq_pins: fusb302_irq { + mux { + groups = "GPIOAO_5"; + function = "gpio_aobus"; + bias-pull-up; + output-disable; + }; + }; + + usb_sbu_default: usb0-sbu-state { + mux { + groups = "GPIOAO_6"; + function = "gpio_aobus"; + bias-pull-down; + drive-strength-microamp = <4000>; + }; + }; +}; From 7e8c46fd3ff221f5fe98292415875dfed8315a55 Mon Sep 17 00:00:00 2001 From: Jiali Chen Date: Tue, 30 Dec 2025 09:50:31 +0000 Subject: [PATCH 4/4] arm64: dts: meson: radxa-zero: add status LED Add the device tree node for the green status LED found on the Radxa Zero. The LED is connected to GPIOAO_10 and is configured to use the 'heartbeat' trigger by default to indicate system activity. Signed-off-by: Jiali Chen --- .../arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts index d6a117b49b1b7..f8d427b3d2f79 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts @@ -7,6 +7,7 @@ #include "meson-g12a.dtsi" #include +#include #include #include @@ -130,6 +131,17 @@ regulator-always-on; }; + leds { + compatible = "gpio-leds"; + + led-green { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio_ao GPIOAO_10 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + typec_vbus: regulator-typec-vbus { compatible = "regulator-fixed"; regulator-name = "TYPEC_VBUS";