Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support
@ 2026-10-20  8:26 Val Packett
  2026-10-20  8:26 ` [PATCH v2 1/4] ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties Val Packett
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Val Packett @ 2026-10-20  8:26 UTC (permalink / raw)
  Cc: Val Packett, Srinivas Kandagatla, Liam Girdwood, Mark Brown,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jaroslav Kysela,
	Takashi Iwai, ~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel

Currently only wcd939x has support for USB-C SBU audio in mainline, but the
older WCD codecs can do the same thing 939x does with USBSS, with an
external 3rd party mux instead. This series adds support for that based on
wcd939x code.

Tested on sm7325-motorola-dubai.

v2:
  * Pull R-b for dt-bindings
  * Add missing `depends on TYPEC || !TYPEC` to kconfig (sashiko-bot)
  * Do not leak the of_graph device_node (sashiko-bot)
  * Guard against NULL wcd_mbhc / mbhc->cfg pointers because typec
    callbacks belong to the platform device which has a longer lifecycle
    than the soc codec part (sashiko-bot)
  * Also apply the same leak/null fixes to wcd939x, keeping it in sync
v1: https://lore.kernel.org/all/20261018231244.1266926-1-val@packett.cool/

Thanks,
~val

---
Val Packett (4):
  ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties
  ASoC: codecs: wcd937x: add USB Type-C analog audio mux support
  ASoC: codecs: wcd-mbhc: guard against NULL cfg in
    typec_report_(un)plug
  ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio

 .../bindings/sound/qcom,wcd937x.yaml          |  15 ++
 sound/soc/codecs/Kconfig                      |   2 +
 sound/soc/codecs/wcd-mbhc-v2.c                |   4 +-
 sound/soc/codecs/wcd937x.c                    | 167 +++++++++++++++++-
 sound/soc/codecs/wcd939x.c                    |  18 +-
 5 files changed, 194 insertions(+), 12 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/4] ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties
  2026-10-20  8:26 [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
@ 2026-10-20  8:26 ` Val Packett
  2026-10-20  8:26 ` [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Val Packett @ 2026-10-20  8:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: Val Packett, Jaroslav Kysela, Takashi Iwai,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel, Krzysztof Kozlowski

This codec can be used with a USB-C SBU mux to support analog headphone
adapters. Describe the mode-switch, orientation-switch and port
properties similarly to wcd939x.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Val Packett <val@packett.cool>
---
 .../devicetree/bindings/sound/qcom,wcd937x.yaml   | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml
index f94203798f24..f15b9a9d90b1 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd937x.yaml
@@ -25,6 +25,21 @@ properties:
           - const: qcom,wcd9375-codec
           - const: qcom,wcd9370-codec
 
+  mode-switch:
+    description: Flag the port as possible handler of altmode switching
+    type: boolean
+
+  orientation-switch:
+    description: Flag the port as possible handler of orientation switching
+    type: boolean
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      A port node to link the WCD937x Codec node to an external USB-C MUX IC for
+      handling altmode muxing and orientation switching to detect and enable
+      Audio Accessory Mode.
+
   vdd-px-supply:
     description: A reference to the 1.8V I/O supply
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support
  2026-10-20  8:26 [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
  2026-10-20  8:26 ` [PATCH v2 1/4] ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties Val Packett
@ 2026-10-20  8:26 ` Val Packett
  2026-10-20  9:06   ` sashiko-bot
  2026-10-20  8:26 ` [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug Val Packett
  2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
  3 siblings, 1 reply; 11+ messages in thread
From: Val Packett @ 2026-10-20  8:26 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai,
	Srinivas Kandagatla
  Cc: Val Packett, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel

On mobile devices, this codec is frequently paired with a USB-C SBU mux
like the FSA4480 to support analog headphone adapters. To support this,
register the codec in the Type-C graph whenever one is present in the
device tree, handle the hotplug notifications and report detected GND-MIC
pin swap back to the external mux as Type-C orientation.

Based on code from the wcd939x driver.

Signed-off-by: Val Packett <val@packett.cool>
---
 sound/soc/codecs/Kconfig   |   2 +
 sound/soc/codecs/wcd937x.c | 167 +++++++++++++++++++++++++++++++++++--
 2 files changed, 163 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ba59dabeeccd..b77e62b0b517 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -2497,11 +2497,13 @@ config SND_SOC_WCD937X
 	depends on SND_SOC_WCD937X_SDW
 	tristate
 	depends on SOUNDWIRE || !SOUNDWIRE
+	depends on TYPEC || !TYPEC
 	select SND_SOC_WCD_CLASSH
 	select SND_SOC_WCD_COMMON
 
 config SND_SOC_WCD937X_SDW
 	tristate "WCD9370/WCD9375 Codec - SDW"
+	depends on TYPEC || !TYPEC
 	select SND_SOC_WCD937X
 	select SND_SOC_WCD_MBHC
 	select REGMAP_IRQ
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 0dd05604f5b8..ec489eb78d8c 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -8,12 +8,15 @@
 #include <linux/gpio/consumer.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_graph.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_altmode.h>
 #include <sound/jack.h>
 #include <sound/pcm_params.h>
 #include <sound/pcm.h>
@@ -82,6 +85,13 @@ struct wcd937x_priv {
 	struct regmap *regmap;
 	/* micb setup lock */
 	struct mutex micb_lock;
+	/* typec handling */
+	bool typec_analog_mux;
+#if IS_ENABLED(CONFIG_TYPEC)
+	enum typec_orientation typec_orientation;
+	unsigned long typec_mode;
+	struct typec_switch *typec_switch;
+#endif /* CONFIG_TYPEC */
 	/* mbhc module */
 	struct wcd_mbhc *wcd_mbhc;
 	struct wcd_mbhc_config mbhc_cfg;
@@ -1869,7 +1879,7 @@ static void wcd937x_mbhc_moisture_config(struct snd_soc_component *component)
 {
 	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
 
-	if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+	if (wcd937x->mbhc_cfg.moist_rref == R_OFF || wcd937x->typec_analog_mux) {
 		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
 					      WCD937X_M_RTH_CTL_MASK, R_OFF);
 		return;
@@ -1905,7 +1915,7 @@ static bool wcd937x_mbhc_get_moisture_status(struct snd_soc_component *component
 	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
 	bool ret = false;
 
-	if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+	if (wcd937x->mbhc_cfg.moist_rref == R_OFF || wcd937x->typec_analog_mux) {
 		snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
 					      WCD937X_M_RTH_CTL_MASK, R_OFF);
 		goto done;
@@ -2005,6 +2015,7 @@ static int wcd937x_mbhc_init(struct snd_soc_component *component)
 {
 	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
 	struct wcd_mbhc_intr *intr_ids = &wcd937x->intr_ids;
+	struct wcd_mbhc *mbhc;
 
 	intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd937x->irq_chip,
 						     WCD937X_IRQ_MBHC_SW_DET);
@@ -2021,9 +2032,12 @@ static int wcd937x_mbhc_init(struct snd_soc_component *component)
 	intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
 						      WCD937X_IRQ_HPHR_OCP_INT);
 
-	wcd937x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
-	if (IS_ERR(wcd937x->wcd_mbhc))
-		return PTR_ERR(wcd937x->wcd_mbhc);
+	mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+	if (IS_ERR(mbhc))
+		return PTR_ERR(mbhc);
+
+	/* May be accessed by platform dev typec callbacks, only set if valid */
+	wcd937x->wcd_mbhc = mbhc;
 
 	snd_soc_add_component_controls(component, impedance_detect_controls,
 				       ARRAY_SIZE(impedance_detect_controls));
@@ -2038,6 +2052,8 @@ static void wcd937x_mbhc_deinit(struct snd_soc_component *component)
 	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
 
 	wcd_mbhc_deinit(wcd937x->wcd_mbhc);
+	/* May be accessed by platform dev typec callbacks, clear */
+	wcd937x->wcd_mbhc = NULL;
 }
 
 /* END MBHC */
@@ -2624,6 +2640,40 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
 	.endianness = 1,
 };
 
+#if IS_ENABLED(CONFIG_TYPEC)
+/* Get USB-C plug orientation to provide swap event for MBHC */
+static int wcd937x_typec_switch_set(struct typec_switch_dev *sw,
+				    enum typec_orientation orientation)
+{
+	struct wcd937x_priv *wcd937x = typec_switch_get_drvdata(sw);
+
+	wcd937x->typec_orientation = orientation;
+
+	return 0;
+}
+
+static int wcd937x_typec_mux_set(struct typec_mux_dev *mux,
+				 struct typec_mux_state *state)
+{
+	struct wcd937x_priv *wcd937x = typec_mux_get_drvdata(mux);
+	unsigned int previous_mode = wcd937x->typec_mode;
+
+	if (!wcd937x->wcd_mbhc)
+		return -EINVAL;
+
+	if (wcd937x->typec_mode != state->mode) {
+		wcd937x->typec_mode = state->mode;
+
+		if (wcd937x->typec_mode == TYPEC_MODE_AUDIO)
+			return wcd_mbhc_typec_report_plug(wcd937x->wcd_mbhc);
+		else if (previous_mode == TYPEC_MODE_AUDIO)
+			return wcd_mbhc_typec_report_unplug(wcd937x->wcd_mbhc);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_TYPEC */
+
 static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component)
 {
 	int value;
@@ -2634,6 +2684,13 @@ static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component)
 	value = gpiod_get_value(wcd937x->us_euro_gpio);
 	gpiod_set_value(wcd937x->us_euro_gpio, !value);
 
+#if IS_ENABLED(CONFIG_TYPEC)
+	if (wcd937x->typec_analog_mux && wcd937x->typec_switch)
+		typec_switch_set(wcd937x->typec_switch,
+				 wcd937x->typec_orientation == TYPEC_ORIENTATION_REVERSE ?
+					TYPEC_ORIENTATION_NORMAL : TYPEC_ORIENTATION_REVERSE);
+#endif /* CONFIG_TYPEC */
+
 	return true;
 }
 
@@ -2751,10 +2808,24 @@ static int wcd937x_bind(struct device *dev)
 	/* Give the SDW subdevices some more time to settle */
 	usleep_range(5000, 5010);
 
+#if IS_ENABLED(CONFIG_TYPEC)
+	/*
+	 * Get the USB Type-C switch to send GND/MIC swap events.
+	 * typec_switch is fetched now to avoid a probe deadlock since
+	 * the switch depends on the typec_mux register in wcd937x_probe()
+	 */
+	if (wcd937x->typec_analog_mux) {
+		wcd937x->typec_switch = fwnode_typec_switch_get(dev->fwnode);
+		if (IS_ERR(wcd937x->typec_switch))
+			return dev_err_probe(dev, PTR_ERR(wcd937x->typec_switch),
+					     "failed to acquire orientation-switch\n");
+	}
+#endif /* CONFIG_TYPEC */
+
 	ret = component_bind_all(dev, wcd937x);
 	if (ret) {
 		dev_err(dev, "Slave bind failed, ret = %d\n", ret);
-		return ret;
+		goto err_put_typec_switch;
 	}
 
 	wcd937x->rxdev = of_sdw_find_device_by_node(wcd937x->rxnode);
@@ -2842,6 +2913,12 @@ static int wcd937x_bind(struct device *dev)
 	put_device(wcd937x->rxdev);
 err_component_unbind:
 	component_unbind_all(dev, wcd937x);
+err_put_typec_switch:
+#if IS_ENABLED(CONFIG_TYPEC)
+	if (wcd937x->typec_analog_mux)
+		typec_switch_put(wcd937x->typec_switch);
+#endif /* CONFIG_TYPEC */
+
 	return ret;
 }
 
@@ -2857,6 +2934,10 @@ static void wcd937x_unbind(struct device *dev)
 	mutex_destroy(&wcd937x->micb_lock);
 	put_device(wcd937x->txdev);
 	put_device(wcd937x->rxdev);
+#if IS_ENABLED(CONFIG_TYPEC)
+	if (wcd937x->typec_analog_mux)
+		typec_switch_put(wcd937x->typec_switch);
+#endif /* CONFIG_TYPEC */
 }
 
 static const struct component_master_ops wcd937x_comp_ops = {
@@ -2864,6 +2945,61 @@ static const struct component_master_ops wcd937x_comp_ops = {
 	.unbind = wcd937x_unbind,
 };
 
+#if IS_ENABLED(CONFIG_TYPEC)
+static void wcd937x_typec_mux_unregister(void *data)
+{
+	struct typec_mux_dev *typec_mux = data;
+
+	typec_mux_unregister(typec_mux);
+}
+
+static void wcd937x_typec_switch_unregister(void *data)
+{
+	struct typec_switch_dev *typec_sw = data;
+
+	typec_switch_unregister(typec_sw);
+}
+
+static int wcd937x_add_typec(struct wcd937x_priv *wcd937x, struct device *dev)
+{
+	int ret;
+	struct typec_mux_dev *typec_mux;
+	struct typec_switch_dev *typec_sw;
+	struct typec_mux_desc mux_desc = {
+		.drvdata = wcd937x,
+		.fwnode = dev_fwnode(dev),
+		.set = wcd937x_typec_mux_set,
+	};
+	struct typec_switch_desc sw_desc = {
+		.drvdata = wcd937x,
+		.fwnode = dev_fwnode(dev),
+		.set = wcd937x_typec_switch_set,
+	};
+
+	typec_mux = typec_mux_register(dev, &mux_desc);
+	if (IS_ERR(typec_mux))
+		return dev_err_probe(dev, PTR_ERR(typec_mux),
+				     "failed to register typec mux\n");
+
+	ret = devm_add_action_or_reset(dev, wcd937x_typec_mux_unregister,
+				       typec_mux);
+	if (ret)
+		return ret;
+
+	typec_sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(typec_sw))
+		return dev_err_probe(dev, PTR_ERR(typec_sw),
+				     "failed to register typec switch\n");
+
+	ret = devm_add_action_or_reset(dev, wcd937x_typec_switch_unregister,
+				       typec_sw);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#endif
+
 static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
 					struct device *dev,
 					struct component_match **matchptr)
@@ -2897,6 +3033,9 @@ static int wcd937x_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct wcd937x_priv *wcd937x;
 	struct wcd_mbhc_config *cfg;
+#if IS_ENABLED(CONFIG_TYPEC)
+	struct device_node *np __free(device_node);
+#endif /* CONFIG_TYPEC */
 	int ret;
 
 	wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
@@ -2941,6 +3080,22 @@ static int wcd937x_probe(struct platform_device *pdev)
 
 	wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg);
 
+#if IS_ENABLED(CONFIG_TYPEC)
+	/*
+	 * If the node has a port and a valid remote endpoint,
+	 * consider HP lines as connected to a USB-C SBU mux
+	 */
+	np = of_graph_get_remote_node(dev->of_node, 0, 0);
+	if (np) {
+		wcd937x->typec_analog_mux = true;
+		cfg->typec_analog_mux = true;
+
+		ret = wcd937x_add_typec(wcd937x, dev);
+		if (ret)
+			return ret;
+	}
+#endif /* CONFIG_TYPEC */
+
 	ret = wcd937x_add_slave_components(wcd937x, dev, &match);
 	if (ret)
 		return ret;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug
  2026-10-20  8:26 [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
  2026-10-20  8:26 ` [PATCH v2 1/4] ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties Val Packett
  2026-10-20  8:26 ` [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
@ 2026-10-20  8:26 ` Val Packett
  2026-10-20  9:19   ` Neil Armstrong
  2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
  3 siblings, 1 reply; 11+ messages in thread
From: Val Packett @ 2026-10-20  8:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Liam Girdwood, Mark Brown, Jaroslav Kysela,
	Takashi Iwai, Neil Armstrong
  Cc: Val Packett, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel, stable

mbhc->cfg is only set by wcd_mbhc_start() which is called by the codec's
set_jack op. wcd_mbhc_typec_report_plug/unplug are called by the platform
device's typec callbacks, which are not synchronized with codec ops, so
a hotplug could be reported before set_jack was called. Though unlikely
to happen in practice, add a check to be safe.

Found by sashiko-bot via review of wcd937x Type-C integration patches.

Cc: stable@vger.kernel.org
Fixes: 0c105997eefd ("ASoC: codec: wcd-mbhc-v2: add support when connected behind an USB-C audio mux")
Signed-off-by: Val Packett <val@packett.cool>
---
 sound/soc/codecs/wcd-mbhc-v2.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 850be84d65ce..fd40c1686d66 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -594,7 +594,7 @@ static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
 int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc)
 {
 
-	if (!mbhc || !mbhc->cfg->typec_analog_mux)
+	if (!mbhc || !mbhc->cfg || !mbhc->cfg->typec_analog_mux)
 		return -EINVAL;
 
 	if (mbhc->mbhc_cb->clk_setup)
@@ -611,7 +611,7 @@ EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug);
 
 int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc)
 {
-	if (!mbhc || !mbhc->cfg->typec_analog_mux)
+	if (!mbhc || !mbhc->cfg || !mbhc->cfg->typec_analog_mux)
 		return -EINVAL;
 
 	if (mbhc->mbhc_cb->clk_setup)
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio
  2026-10-20  8:26 [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
                   ` (2 preceding siblings ...)
  2026-10-20  8:26 ` [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug Val Packett
@ 2026-10-20  8:26 ` Val Packett
  2026-10-20  9:19   ` sashiko-bot
                     ` (2 more replies)
  3 siblings, 3 replies; 11+ messages in thread
From: Val Packett @ 2026-10-20  8:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Liam Girdwood, Mark Brown, Jaroslav Kysela,
	Takashi Iwai, Neil Armstrong
  Cc: Val Packett, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel, stable

Some code issues were found during review of a port of typec code from
wcd939x to wcd937x, pointed out by sashiko-bot:

* wcd939x->wcd_mbhc may be accessed by the typec callbacks which are
  independent of the ASoC codec lifecycle, don't leave it as NULL/PTR_ERR;
* wcd939x->typec_switch reference was leaked on unbind, put it there;
* the device_node reference returned by of_graph_get_remote_node() was
  being leaked, add a __free annotation to the declaration.

Fix them in wcd939x as well.

Cc: stable@vger.kernel.org
Fixes: 10f514bd172a ("ASoC: codecs: Add WCD939x Codec driver")
Signed-off-by: Val Packett <val@packett.cool>
---
 sound/soc/codecs/wcd939x.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index 26fe0b6313cd..56e041e70fd4 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -2466,6 +2466,7 @@ static int wcd939x_mbhc_init(struct snd_soc_component *component)
 {
 	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
 	struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids;
+	struct wcd_mbhc *mbhc;
 
 	intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip,
 						     WCD939X_IRQ_MBHC_SW_DET);
@@ -2482,9 +2483,12 @@ static int wcd939x_mbhc_init(struct snd_soc_component *component)
 	intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip,
 						      WCD939X_IRQ_HPHR_OCP_INT);
 
-	wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
-	if (IS_ERR(wcd939x->wcd_mbhc))
-		return PTR_ERR(wcd939x->wcd_mbhc);
+	mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+	if (IS_ERR(mbhc))
+		return PTR_ERR(mbhc);
+
+	/* May be accessed by platform dev typec callbacks, only set if valid */
+	wcd939x->wcd_mbhc = mbhc;
 
 	snd_soc_add_component_controls(component, impedance_detect_controls,
 				       ARRAY_SIZE(impedance_detect_controls));
@@ -2499,6 +2503,8 @@ static void wcd939x_mbhc_deinit(struct snd_soc_component *component)
 	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
 
 	wcd_mbhc_deinit(wcd939x->wcd_mbhc);
+	/* May be accessed by platform dev typec callbacks, clear */
+	wcd939x->wcd_mbhc = NULL;
 }
 
 /* END MBHC */
@@ -3171,7 +3177,7 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device
 {
 	struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg;
 #if IS_ENABLED(CONFIG_TYPEC)
-	struct device_node *np;
+	struct device_node *np __free(device_node);
 #endif /* CONFIG_TYPEC */
 	int ret;
 
@@ -3434,6 +3440,10 @@ static void wcd939x_unbind(struct device *dev)
 	put_device(wcd939x->txdev);
 	put_device(wcd939x->rxdev);
 	component_unbind_all(dev, wcd939x);
+#if IS_ENABLED(CONFIG_TYPEC)
+	if (wcd939x->typec_analog_mux)
+		typec_switch_put(wcd939x->typec_switch);
+#endif /* CONFIG_TYPEC */
 }
 
 static const struct component_master_ops wcd939x_comp_ops = {
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support
  2026-10-20  8:26 ` [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
@ 2026-10-20  9:06   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-20  9:06 UTC (permalink / raw)
  To: Val Packett; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ASoC: wcd937x: uninitialized __free(device_node) pointer in wcd937x_probe()
- [High] ASoC: codecs: wcd937x: use-after-free race in wcd937x_mbhc_deinit()
--

commit 4c12f167e90fb501eb42394e2202994cfc931062
Author: Val Packett <val@packett.cool>

ASoC: codecs: wcd937x: add USB Type-C analog audio mux support

This commit adds USB Type-C analog audio mux and orientation switch
support to the WCD937x codec driver, handling hotplug notifications via
MBHC and reporting GND-MIC pin swap orientation back to the external mux.

> diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
> index 7ffbb445f8ac4..48f8852d34513 100644
> --- a/sound/soc/codecs/wcd937x.c
> +++ b/sound/soc/codecs/wcd937x.c

[ ... ]

> @@ -2038,6 +2052,8 @@ static void wcd937x_mbhc_deinit(struct snd_soc_component *component)
>  	struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
>  
>  	wcd_mbhc_deinit(wcd937x->wcd_mbhc);
> +	/* May be accessed by platform dev typec callbacks, clear */
> +	wcd937x->wcd_mbhc = NULL;
>  }
>  
>  /* END MBHC */
> @@ -2634,6 +2650,40 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
>  	.endianness = 1,
>  };
>  
> +#if IS_ENABLED(CONFIG_TYPEC)
> +/* Get USB-C plug orientation to provide swap event for MBHC */
> +static int wcd937x_typec_switch_set(struct typec_switch_dev *sw,
> +				    enum typec_orientation orientation)
> +{
> +	struct wcd937x_priv *wcd937x = typec_switch_get_drvdata(sw);
> +
> +	wcd937x->typec_orientation = orientation;
> +
> +	return 0;
> +}
> +
> +static int wcd937x_typec_mux_set(struct typec_mux_dev *mux,
> +				 struct typec_mux_state *state)
> +{
> +	struct wcd937x_priv *wcd937x = typec_mux_get_drvdata(mux);
> +	unsigned int previous_mode = wcd937x->typec_mode;
> +
> +	if (!wcd937x->wcd_mbhc)
> +		return -EINVAL;
> +
> +	if (wcd937x->typec_mode != state->mode) {
> +		wcd937x->typec_mode = state->mode;
> +
> +		if (wcd937x->typec_mode == TYPEC_MODE_AUDIO)
> +			return wcd_mbhc_typec_report_plug(wcd937x->wcd_mbhc);
> +		else if (previous_mode == TYPEC_MODE_AUDIO)
> +			return wcd_mbhc_typec_report_unplug(wcd937x->wcd_mbhc);
> +	}
> +
> +	return 0;
> +}
> +#endif /* CONFIG_TYPEC */

[Severity: High]
Can wcd937x_typec_mux_set() race with wcd937x_mbhc_deinit() and cause a
use-after-free on wcd937x->wcd_mbhc?

The Type-C mux is registered in wcd937x_probe() via devres, so it remains
active during component teardown:

wcd937x_unbind()
  snd_soc_unregister_component()
    wcd937x_soc_codec_remove()
      wcd937x_mbhc_deinit()
        wcd_mbhc_deinit(wcd937x->wcd_mbhc)

Inside wcd_mbhc_deinit(), the driver frees IRQs, cancels
mbhc->mbhc_plug_detect_work, and calls kfree(mbhc), all before
wcd937x_mbhc_deinit() sets wcd937x->wcd_mbhc = NULL:

sound/soc/codecs/wcd-mbhc-v2.c:wcd_mbhc_deinit() {
	...
	mutex_lock(&mbhc->lock);
	wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
	cancel_work_sync(&mbhc->mbhc_plug_detect_work);
	mutex_unlock(&mbhc->lock);

	kfree(mbhc);
}

Because there is no synchronization between wcd937x_typec_mux_set() and
wcd937x_mbhc_deinit(), a concurrent wcd937x_typec_mux_set() callback can
observe a non-NULL wcd937x->wcd_mbhc while or after wcd_mbhc_deinit() runs,
calling wcd_mbhc_typec_report_plug() or wcd_mbhc_typec_report_unplug() on
freed memory and scheduling mbhc->mbhc_plug_detect_work after
cancel_work_sync() and kfree(mbhc).

[ ... ]

> @@ -2907,6 +3043,9 @@ static int wcd937x_probe(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	struct wcd937x_priv *wcd937x;
>  	struct wcd_mbhc_config *cfg;
> +#if IS_ENABLED(CONFIG_TYPEC)
> +	struct device_node *np __free(device_node);
> +#endif /* CONFIG_TYPEC */
>  	int ret;
>  
>  	wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
> @@ -2951,6 +3090,22 @@ static int wcd937x_probe(struct platform_device *pdev)
>  
>  	wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg);
>  
> +#if IS_ENABLED(CONFIG_TYPEC)
> +	/*
> +	 * If the node has a port and a valid remote endpoint,
> +	 * consider HP lines as connected to a USB-C SBU mux
> +	 */
> +	np = of_graph_get_remote_node(dev->of_node, 0, 0);
> +	if (np) {
> +		wcd937x->typec_analog_mux = true;
> +		cfg->typec_analog_mux = true;
> +
> +		ret = wcd937x_add_typec(wcd937x, dev);
> +		if (ret)
> +			return ret;
> +	}
> +#endif /* CONFIG_TYPEC */

[Severity: High]
Does wcd937x_probe() pass an uninitialized np pointer to of_node_put() on
early return when CONFIG_TYPEC is enabled?

In wcd937x_probe(), np is declared with __free(device_node) without being
initialized to NULL, and is not assigned until of_graph_get_remote_node()
is called later in the function.

Between the declaration and that assignment, there are five early return
paths if devm_kzalloc(), devm_gpiod_get(), devm_gpiod_get_optional(),
devm_regulator_bulk_get_enable(), or wcd_dt_parse_micbias_info() fails:

sound/soc/codecs/wcd937x.c:wcd937x_probe() {
	...
	wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
	if (!wcd937x)
		return -ENOMEM;
	...
	wcd937x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(wcd937x->reset_gpio))
		return dev_err_probe(dev, PTR_ERR(wcd937x->reset_gpio),
				     "failed to reset wcd gpio\n");
	...
}

If any of those early returns is taken, the __free(device_node) cleanup
handler runs on the uninitialized stack variable np. Should np be
initialized to NULL at declaration, or declared where
of_graph_get_remote_node() is called?

[ ... ]

>  
>  	ret = wcd937x_add_slave_components(wcd937x, dev, &match);
>  	if (ret)
>  		return ret;

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020082631.1509275-1-val@packett.cool?part=2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio
  2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
@ 2026-10-20  9:19   ` sashiko-bot
  2026-10-20  9:19   ` Neil Armstrong
  2026-10-20 11:35   ` Markus Elfring
  2 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-10-20  9:19 UTC (permalink / raw)
  To: Val Packett; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ASoC: wcd939x: uninitialized __free() pointer in wcd939x_populate_dt_data()
- [High] ASoC: wcd939x: use-after-free race in wcd939x_mbhc_deinit() with typec mux
--

commit 263e4868f28e72190c4609440782fec0a736dcae
Author: Val Packett <val@packett.cool>

ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio

This commit addresses three issues with USB-C audio support in wcd939x:
preventing wcd939x->wcd_mbhc from holding an error pointer or stale pointer
for Type-C callbacks, releasing wcd939x->typec_switch on unbind, and
adding a __free(device_node) cleanup annotation for the node returned by
of_graph_get_remote_node().

> diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
> index 2d463f062e6d7..17503e4785e2c 100644
> --- a/sound/soc/codecs/wcd939x.c
> +++ b/sound/soc/codecs/wcd939x.c
[ ... ]
> @@ -2503,6 +2507,8 @@ static void wcd939x_mbhc_deinit(struct snd_soc_component *component)
>  	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
>  
>  	wcd_mbhc_deinit(wcd939x->wcd_mbhc);
> +	/* May be accessed by platform dev typec callbacks, clear */
> +	wcd939x->wcd_mbhc = NULL;
>  }

[Severity: High]
Can wcd939x_typec_mux_set() race with wcd939x_mbhc_deinit() and access a
freed wcd939x->wcd_mbhc?

In wcd939x_mbhc_deinit(), wcd939x->wcd_mbhc is only set to NULL after
wcd_mbhc_deinit() has already returned, and without synchronization against
wcd939x_typec_mux_set(). Inside wcd_mbhc_deinit(), execution sleeps across
free_irq() and cancel_work_sync(&mbhc->mbhc_plug_detect_work) before calling
kfree(mbhc):

sound/soc/codecs/wcd-mbhc-v2.c:wcd_mbhc_deinit() {
	...
	mutex_lock(&mbhc->lock);
	wcd_cancel_hs_detect_plug(mbhc,	&mbhc->correct_plug_swch);
	cancel_work_sync(&mbhc->mbhc_plug_detect_work);
	mutex_unlock(&mbhc->lock);

	kfree(mbhc);
}

During that window, wcd939x_typec_mux_set() can still see a non-NULL
wcd939x->wcd_mbhc:

sound/soc/codecs/wcd939x.c:wcd939x_typec_mux_set() {
	...
	if (!wcd939x->wcd_mbhc)
		return -EINVAL;

	if (wcd939x->typec_mode != state->mode) {
		wcd939x->typec_mode = state->mode;

		if (wcd939x->typec_mode == TYPEC_MODE_AUDIO)
			return wcd_mbhc_typec_report_plug(wcd939x->wcd_mbhc);
		else if (previous_mode == TYPEC_MODE_AUDIO)
			return wcd_mbhc_typec_report_unplug(wcd939x->wcd_mbhc);
	}
	...
}

Wouldn't a concurrent wcd939x_typec_mux_set() call dereference freed mbhc
memory or reschedule mbhc_plug_detect_work after cancel_work_sync() has
completed?

>  
>  /* END MBHC */
> @@ -3175,7 +3181,7 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device
>  {
>  	struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg;
>  #if IS_ENABLED(CONFIG_TYPEC)
> -	struct device_node *np;
> +	struct device_node *np __free(device_node);
>  #endif /* CONFIG_TYPEC */
>  	int ret;

[Severity: High]
Does wcd939x_populate_dt_data() pass an uninitialized np pointer to
of_node_put() on early return?

Here np is declared with __free(device_node) without being initialized to
NULL, while three early return paths precede its assignment at
of_graph_get_remote_node():

sound/soc/codecs/wcd939x.c:wcd939x_populate_dt_data() {
	...
	wcd939x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(wcd939x->reset_gpio))
		return dev_err_probe(dev, PTR_ERR(wcd939x->reset_gpio),
				     "Failed to get reset gpio\n");

	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd939x_supplies),
					     wcd939x_supplies);
	if (ret)
		return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");

	ret = wcd_dt_parse_micbias_info(&wcd939x->common);
	if (ret)
		return dev_err_probe(dev, ret, "Failed to get micbias\n");
	...
	np = of_graph_get_remote_node(dev->of_node, 0, 0);
}

If any of those three calls fails or defers probe when CONFIG_TYPEC is
enabled, the cleanup handler will run on an uninitialized np pointer. Should
np be initialized to NULL (or declared at the point of assignment)?

[ ... ]

>dari

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020082631.1509275-1-val@packett.cool?part=4

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio
  2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
  2026-10-20  9:19   ` sashiko-bot
@ 2026-10-20  9:19   ` Neil Armstrong
  2026-10-20 11:35   ` Markus Elfring
  2 siblings, 0 replies; 11+ messages in thread
From: Neil Armstrong @ 2026-10-20  9:19 UTC (permalink / raw)
  To: Val Packett, Srinivas Kandagatla, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel, stable

On 10/20/26 10:26, Val Packett wrote:
> Some code issues were found during review of a port of typec code from
> wcd939x to wcd937x, pointed out by sashiko-bot:
> 
> * wcd939x->wcd_mbhc may be accessed by the typec callbacks which are
>    independent of the ASoC codec lifecycle, don't leave it as NULL/PTR_ERR;
> * wcd939x->typec_switch reference was leaked on unbind, put it there;
> * the device_node reference returned by of_graph_get_remote_node() was
>    being leaked, add a __free annotation to the declaration.
> 
> Fix them in wcd939x as well.
> 
> Cc: stable@vger.kernel.org
> Fixes: 10f514bd172a ("ASoC: codecs: Add WCD939x Codec driver")
> Signed-off-by: Val Packett <val@packett.cool>
> ---
>   sound/soc/codecs/wcd939x.c | 18 ++++++++++++++----
>   1 file changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
> index 26fe0b6313cd..56e041e70fd4 100644
> --- a/sound/soc/codecs/wcd939x.c
> +++ b/sound/soc/codecs/wcd939x.c
> @@ -2466,6 +2466,7 @@ static int wcd939x_mbhc_init(struct snd_soc_component *component)
>   {
>   	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
>   	struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids;
> +	struct wcd_mbhc *mbhc;
>   
>   	intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip,
>   						     WCD939X_IRQ_MBHC_SW_DET);
> @@ -2482,9 +2483,12 @@ static int wcd939x_mbhc_init(struct snd_soc_component *component)
>   	intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip,
>   						      WCD939X_IRQ_HPHR_OCP_INT);
>   
> -	wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
> -	if (IS_ERR(wcd939x->wcd_mbhc))
> -		return PTR_ERR(wcd939x->wcd_mbhc);
> +	mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
> +	if (IS_ERR(mbhc))
> +		return PTR_ERR(mbhc);
> +
> +	/* May be accessed by platform dev typec callbacks, only set if valid */
> +	wcd939x->wcd_mbhc = mbhc;
>   
>   	snd_soc_add_component_controls(component, impedance_detect_controls,
>   				       ARRAY_SIZE(impedance_detect_controls));
> @@ -2499,6 +2503,8 @@ static void wcd939x_mbhc_deinit(struct snd_soc_component *component)
>   	struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
>   
>   	wcd_mbhc_deinit(wcd939x->wcd_mbhc);
> +	/* May be accessed by platform dev typec callbacks, clear */
> +	wcd939x->wcd_mbhc = NULL;
>   }
>   
>   /* END MBHC */
> @@ -3171,7 +3177,7 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device
>   {
>   	struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg;
>   #if IS_ENABLED(CONFIG_TYPEC)
> -	struct device_node *np;
> +	struct device_node *np __free(device_node);
>   #endif /* CONFIG_TYPEC */
>   	int ret;
>   
> @@ -3434,6 +3440,10 @@ static void wcd939x_unbind(struct device *dev)
>   	put_device(wcd939x->txdev);
>   	put_device(wcd939x->rxdev);
>   	component_unbind_all(dev, wcd939x);
> +#if IS_ENABLED(CONFIG_TYPEC)
> +	if (wcd939x->typec_analog_mux)
> +		typec_switch_put(wcd939x->typec_switch);
> +#endif /* CONFIG_TYPEC */
>   }
>   
>   static const struct component_master_ops wcd939x_comp_ops = {

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>

Thanks,
Neil

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug
  2026-10-20  8:26 ` [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug Val Packett
@ 2026-10-20  9:19   ` Neil Armstrong
  0 siblings, 0 replies; 11+ messages in thread
From: Neil Armstrong @ 2026-10-20  9:19 UTC (permalink / raw)
  To: Val Packett, Srinivas Kandagatla, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	~postmarketos/upstreaming, phone-devel, linux-sound,
	linux-arm-msm, devicetree, linux-kernel, stable

On 10/20/26 10:26, Val Packett wrote:
> mbhc->cfg is only set by wcd_mbhc_start() which is called by the codec's
> set_jack op. wcd_mbhc_typec_report_plug/unplug are called by the platform
> device's typec callbacks, which are not synchronized with codec ops, so
> a hotplug could be reported before set_jack was called. Though unlikely
> to happen in practice, add a check to be safe.
> 
> Found by sashiko-bot via review of wcd937x Type-C integration patches.
> 
> Cc: stable@vger.kernel.org
> Fixes: 0c105997eefd ("ASoC: codec: wcd-mbhc-v2: add support when connected behind an USB-C audio mux")
> Signed-off-by: Val Packett <val@packett.cool>
> ---
>   sound/soc/codecs/wcd-mbhc-v2.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
> index 850be84d65ce..fd40c1686d66 100644
> --- a/sound/soc/codecs/wcd-mbhc-v2.c
> +++ b/sound/soc/codecs/wcd-mbhc-v2.c
> @@ -594,7 +594,7 @@ static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
>   int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc)
>   {
>   
> -	if (!mbhc || !mbhc->cfg->typec_analog_mux)
> +	if (!mbhc || !mbhc->cfg || !mbhc->cfg->typec_analog_mux)
>   		return -EINVAL;
>   
>   	if (mbhc->mbhc_cb->clk_setup)
> @@ -611,7 +611,7 @@ EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug);
>   
>   int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc)
>   {
> -	if (!mbhc || !mbhc->cfg->typec_analog_mux)
> +	if (!mbhc || !mbhc->cfg || !mbhc->cfg->typec_analog_mux)
>   		return -EINVAL;
>   
>   	if (mbhc->mbhc_cb->clk_setup)

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>

Thanks,
Neil

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio
  2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
  2026-10-20  9:19   ` sashiko-bot
  2026-10-20  9:19   ` Neil Armstrong
@ 2026-10-20 11:35   ` Markus Elfring
  2026-10-20 13:48     ` Mark Brown
  2 siblings, 1 reply; 11+ messages in thread
From: Markus Elfring @ 2026-10-20 11:35 UTC (permalink / raw)
  To: Val Packett, linux-sound, linux-arm-msm, devicetree, phone-devel,
	~postmarketos/upstreaming, Jaroslav Kysela, Liam Girdwood,
	Mark Brown, Neil Armstrong, Srinivas Kandagatla, Takashi Iwai
  Cc: stable, LKML, Conor Dooley, Krzysztof Kozlowski, Rob Herring

> Some code issues were found during review of a port of typec code from
> wcd939x to wcd937x, pointed out by sashiko-bot:
…

Would there be a need to offer corresponding adjustments as separate patches?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v7.3#n81

Regards,
Markus

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio
  2026-10-20 11:35   ` Markus Elfring
@ 2026-10-20 13:48     ` Mark Brown
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2026-10-20 13:48 UTC (permalink / raw)
  To: Markus Elfring
  Cc: Val Packett, linux-sound, linux-arm-msm, devicetree, phone-devel,
	~postmarketos/upstreaming, Jaroslav Kysela, Liam Girdwood,
	Neil Armstrong, Srinivas Kandagatla, Takashi Iwai, stable, LKML,
	Conor Dooley, Krzysztof Kozlowski, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 560 bytes --]

On Tue, Oct 20, 2026 at 01:35:02PM +0200, Markus Elfring wrote:
> > Some code issues were found during review of a port of typec code from
> > wcd939x to wcd937x, pointed out by sashiko-bot:
> …
> 
> Would there be a need to offer corresponding adjustments as separate patches?
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v7.3#n81

Feel free to ignore Markus, he has a long history of sending
unhelpful review comments and continues to ignore repeated requests
to stop.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-10-20 13:48 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20  8:26 [PATCH v2 0/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
2026-10-20  8:26 ` [PATCH v2 1/4] ASoC: dt-bindings: qcom,wcd937x: Add USB-C graph properties Val Packett
2026-10-20  8:26 ` [PATCH v2 2/4] ASoC: codecs: wcd937x: add USB Type-C analog audio mux support Val Packett
2026-10-20  9:06   ` sashiko-bot
2026-10-20  8:26 ` [PATCH v2 3/4] ASoC: codecs: wcd-mbhc: guard against NULL cfg in typec_report_(un)plug Val Packett
2026-10-20  9:19   ` Neil Armstrong
2026-10-20  8:26 ` [PATCH v2 4/4] ASoC: codecs: wcd939x: fix ref leak and NULL deref with USB-C audio Val Packett
2026-10-20  9:19   ` sashiko-bot
2026-10-20  9:19   ` Neil Armstrong
2026-10-20 11:35   ` Markus Elfring
2026-10-20 13:48     ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox