Unverified Commit 9f3ae72c authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Mark Brown
Browse files

ASoC: codecs: wcd939x: Fix typec mux and switch leak during device removal



Driver does not unregister typec structures (typec_mux_dev and
typec_switch_desc) during removal leading to leaks.  Fix this by moving
typec registering parts to separate function and using devm interface to
release them.  This also makes code a bit simpler:
 - Smaller probe() function with less error paths and no #ifdefs,
 - No need to store typec_mux_dev and typec_switch_desc in driver state
   container structure.

Cc: stable@vger.kernel.org
Fixes: 10f514bd ("ASoC: codecs: Add WCD939x Codec driver")
Signed-off-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: default avatarNeil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20240701122616.414158-1-krzysztof.kozlowski@linaro.org


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1e0dff74
Loading
Loading
Loading
Loading
+66 −47
Original line number Diff line number Diff line
@@ -181,8 +181,6 @@ struct wcd939x_priv {
	/* typec handling */
	bool typec_analog_mux;
#if IS_ENABLED(CONFIG_TYPEC)
	struct typec_mux_dev *typec_mux;
	struct typec_switch_dev *typec_sw;
	enum typec_orientation typec_orientation;
	unsigned long typec_mode;
	struct typec_switch *typec_switch;
@@ -3519,6 +3517,68 @@ static const struct component_master_ops wcd939x_comp_ops = {
	.unbind = wcd939x_unbind,
};

static void __maybe_unused wcd939x_typec_mux_unregister(void *data)
{
	struct typec_mux_dev *typec_mux = data;

	typec_mux_unregister(typec_mux);
}

static void __maybe_unused wcd939x_typec_switch_unregister(void *data)
{
	struct typec_switch_dev *typec_sw = data;

	typec_switch_unregister(typec_sw);
}

static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev)
{
#if IS_ENABLED(CONFIG_TYPEC)
	int ret;
	struct typec_mux_dev *typec_mux;
	struct typec_switch_dev *typec_sw;
	struct typec_mux_desc mux_desc = {
		.drvdata = wcd939x,
		.fwnode = dev_fwnode(dev),
		.set = wcd939x_typec_mux_set,
	};
	struct typec_switch_desc sw_desc = {
		.drvdata = wcd939x,
		.fwnode = dev_fwnode(dev),
		.set = wcd939x_typec_switch_set,
	};

	/*
	 * Is USBSS is used to mux analog lines,
	 * register a typec mux/switch to get typec events
	 */
	if (!wcd939x->typec_analog_mux)
		return 0;

	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, wcd939x_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, wcd939x_typec_switch_unregister,
				       typec_sw);
	if (ret)
		return ret;
#endif

	return 0;
}

static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
					struct device *dev,
					struct component_match **matchptr)
@@ -3567,42 +3627,13 @@ static int wcd939x_probe(struct platform_device *pdev)
		return -EINVAL;
	}

#if IS_ENABLED(CONFIG_TYPEC)
	/*
	 * Is USBSS is used to mux analog lines,
	 * register a typec mux/switch to get typec events
	 */
	if (wcd939x->typec_analog_mux) {
		struct typec_mux_desc mux_desc = {
			.drvdata = wcd939x,
			.fwnode = dev_fwnode(dev),
			.set = wcd939x_typec_mux_set,
		};
		struct typec_switch_desc sw_desc = {
			.drvdata = wcd939x,
			.fwnode = dev_fwnode(dev),
			.set = wcd939x_typec_switch_set,
		};

		wcd939x->typec_mux = typec_mux_register(dev, &mux_desc);
		if (IS_ERR(wcd939x->typec_mux)) {
			ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux),
					    "failed to register typec mux\n");
	ret = wcd939x_add_typec(wcd939x, dev);
	if (ret)
		goto err_disable_regulators;
		}

		wcd939x->typec_sw = typec_switch_register(dev, &sw_desc);
		if (IS_ERR(wcd939x->typec_sw)) {
			ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw),
					    "failed to register typec switch\n");
			goto err_unregister_typec_mux;
		}
	}
#endif /* CONFIG_TYPEC */

	ret = wcd939x_add_slave_components(wcd939x, dev, &match);
	if (ret)
		goto err_unregister_typec_switch;
		goto err_disable_regulators;

	wcd939x_reset(wcd939x);

@@ -3619,18 +3650,6 @@ static int wcd939x_probe(struct platform_device *pdev)

	return 0;

#if IS_ENABLED(CONFIG_TYPEC)
err_unregister_typec_mux:
	if (wcd939x->typec_analog_mux)
		typec_mux_unregister(wcd939x->typec_mux);
#endif /* CONFIG_TYPEC */

err_unregister_typec_switch:
#if IS_ENABLED(CONFIG_TYPEC)
	if (wcd939x->typec_analog_mux)
		typec_switch_unregister(wcd939x->typec_sw);
#endif /* CONFIG_TYPEC */

err_disable_regulators:
	regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies);
	regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies);