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..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,7 +7,9 @@ #include "meson-g12a.dtsi" #include +#include #include +#include / { compatible = "radxa,zero", "amlogic,g12a"; @@ -129,6 +131,25 @@ 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"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&ao_5v>; + }; + sound { compatible = "amlogic,axg-sound-card"; model = "RADXA-ZERO"; @@ -186,6 +207,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 +281,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 +507,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>; + }; + }; +}; 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; 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);