]> www.infradead.org Git - users/hch/configfs.git/commitdiff
ASoC: codecs: wcd939x: Fix typec mux and switch leak during device removal
authorKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Mon, 1 Jul 2024 12:26:16 +0000 (14:26 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 4 Jul 2024 11:42:24 +0000 (12:42 +0100)
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: 10f514bd172a ("ASoC: codecs: Add WCD939x Codec driver")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20240701122616.414158-1-krzysztof.kozlowski@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wcd939x.c

index 66af035bd0e5847b52073d87b8557755d26cc33f..68fc591670dc84b340be5bb89e16e4ab45c40591 100644 (file)
@@ -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");
-                       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_typec(wcd939x, dev);
+       if (ret)
+               goto err_disable_regulators;
 
        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);