Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 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>

authored by

Krzysztof Kozlowski and committed by
Mark Brown
9f3ae72c 1e0dff74

+66 -47
+66 -47
sound/soc/codecs/wcd939x.c
··· 181 181 /* typec handling */ 182 182 bool typec_analog_mux; 183 183 #if IS_ENABLED(CONFIG_TYPEC) 184 - struct typec_mux_dev *typec_mux; 185 - struct typec_switch_dev *typec_sw; 186 184 enum typec_orientation typec_orientation; 187 185 unsigned long typec_mode; 188 186 struct typec_switch *typec_switch; ··· 3517 3519 .unbind = wcd939x_unbind, 3518 3520 }; 3519 3521 3522 + static void __maybe_unused wcd939x_typec_mux_unregister(void *data) 3523 + { 3524 + struct typec_mux_dev *typec_mux = data; 3525 + 3526 + typec_mux_unregister(typec_mux); 3527 + } 3528 + 3529 + static void __maybe_unused wcd939x_typec_switch_unregister(void *data) 3530 + { 3531 + struct typec_switch_dev *typec_sw = data; 3532 + 3533 + typec_switch_unregister(typec_sw); 3534 + } 3535 + 3536 + static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev) 3537 + { 3538 + #if IS_ENABLED(CONFIG_TYPEC) 3539 + int ret; 3540 + struct typec_mux_dev *typec_mux; 3541 + struct typec_switch_dev *typec_sw; 3542 + struct typec_mux_desc mux_desc = { 3543 + .drvdata = wcd939x, 3544 + .fwnode = dev_fwnode(dev), 3545 + .set = wcd939x_typec_mux_set, 3546 + }; 3547 + struct typec_switch_desc sw_desc = { 3548 + .drvdata = wcd939x, 3549 + .fwnode = dev_fwnode(dev), 3550 + .set = wcd939x_typec_switch_set, 3551 + }; 3552 + 3553 + /* 3554 + * Is USBSS is used to mux analog lines, 3555 + * register a typec mux/switch to get typec events 3556 + */ 3557 + if (!wcd939x->typec_analog_mux) 3558 + return 0; 3559 + 3560 + typec_mux = typec_mux_register(dev, &mux_desc); 3561 + if (IS_ERR(typec_mux)) 3562 + return dev_err_probe(dev, PTR_ERR(typec_mux), 3563 + "failed to register typec mux\n"); 3564 + 3565 + ret = devm_add_action_or_reset(dev, wcd939x_typec_mux_unregister, 3566 + typec_mux); 3567 + if (ret) 3568 + return ret; 3569 + 3570 + typec_sw = typec_switch_register(dev, &sw_desc); 3571 + if (IS_ERR(typec_sw)) 3572 + return dev_err_probe(dev, PTR_ERR(typec_sw), 3573 + "failed to register typec switch\n"); 3574 + 3575 + ret = devm_add_action_or_reset(dev, wcd939x_typec_switch_unregister, 3576 + typec_sw); 3577 + if (ret) 3578 + return ret; 3579 + #endif 3580 + 3581 + return 0; 3582 + } 3583 + 3520 3584 static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, 3521 3585 struct device *dev, 3522 3586 struct component_match **matchptr) ··· 3627 3567 return -EINVAL; 3628 3568 } 3629 3569 3630 - #if IS_ENABLED(CONFIG_TYPEC) 3631 - /* 3632 - * Is USBSS is used to mux analog lines, 3633 - * register a typec mux/switch to get typec events 3634 - */ 3635 - if (wcd939x->typec_analog_mux) { 3636 - struct typec_mux_desc mux_desc = { 3637 - .drvdata = wcd939x, 3638 - .fwnode = dev_fwnode(dev), 3639 - .set = wcd939x_typec_mux_set, 3640 - }; 3641 - struct typec_switch_desc sw_desc = { 3642 - .drvdata = wcd939x, 3643 - .fwnode = dev_fwnode(dev), 3644 - .set = wcd939x_typec_switch_set, 3645 - }; 3646 - 3647 - wcd939x->typec_mux = typec_mux_register(dev, &mux_desc); 3648 - if (IS_ERR(wcd939x->typec_mux)) { 3649 - ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux), 3650 - "failed to register typec mux\n"); 3651 - goto err_disable_regulators; 3652 - } 3653 - 3654 - wcd939x->typec_sw = typec_switch_register(dev, &sw_desc); 3655 - if (IS_ERR(wcd939x->typec_sw)) { 3656 - ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw), 3657 - "failed to register typec switch\n"); 3658 - goto err_unregister_typec_mux; 3659 - } 3660 - } 3661 - #endif /* CONFIG_TYPEC */ 3570 + ret = wcd939x_add_typec(wcd939x, dev); 3571 + if (ret) 3572 + goto err_disable_regulators; 3662 3573 3663 3574 ret = wcd939x_add_slave_components(wcd939x, dev, &match); 3664 3575 if (ret) 3665 - goto err_unregister_typec_switch; 3576 + goto err_disable_regulators; 3666 3577 3667 3578 wcd939x_reset(wcd939x); 3668 3579 ··· 3649 3618 pm_runtime_idle(dev); 3650 3619 3651 3620 return 0; 3652 - 3653 - #if IS_ENABLED(CONFIG_TYPEC) 3654 - err_unregister_typec_mux: 3655 - if (wcd939x->typec_analog_mux) 3656 - typec_mux_unregister(wcd939x->typec_mux); 3657 - #endif /* CONFIG_TYPEC */ 3658 - 3659 - err_unregister_typec_switch: 3660 - #if IS_ENABLED(CONFIG_TYPEC) 3661 - if (wcd939x->typec_analog_mux) 3662 - typec_switch_unregister(wcd939x->typec_sw); 3663 - #endif /* CONFIG_TYPEC */ 3664 3621 3665 3622 err_disable_regulators: 3666 3623 regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies);