pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Wed, 10 Nov 2021 08:49:48 +0000 (09:49 +0100)
committerThierry Reding <thierry.reding@gmail.com>
Wed, 2 Feb 2022 16:03:46 +0000 (17:03 +0100)
When a driver calls pwmchip_add() it has to be prepared to immediately
get its callbacks called. So move allocation of driver data and hardware
initialization before the call to pwmchip_add().

This fixes a potential NULL pointer exception and a race condition on
register writes.

Fixes: 841e6f90bb78 ("pwm: NXP LPC18xx PWM/SCT driver")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
drivers/pwm/pwm-lpc18xx-sct.c

index 8e461f3..8cc8ae1 100644 (file)
@@ -395,12 +395,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
        lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT,
                           BIT(lpc18xx_pwm->period_event));
 
-       ret = pwmchip_add(&lpc18xx_pwm->chip);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
-               goto disable_pwmclk;
-       }
-
        for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) {
                struct lpc18xx_pwm_data *data;
 
@@ -410,14 +404,12 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
                                    GFP_KERNEL);
                if (!data) {
                        ret = -ENOMEM;
-                       goto remove_pwmchip;
+                       goto disable_pwmclk;
                }
 
                pwm_set_chip_data(pwm, data);
        }
 
-       platform_set_drvdata(pdev, lpc18xx_pwm);
-
        val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
        val &= ~LPC18XX_PWM_BIDIR;
        val &= ~LPC18XX_PWM_CTRL_HALT;
@@ -425,10 +417,16 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
        val |= LPC18XX_PWM_PRE(0);
        lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
 
+       ret = pwmchip_add(&lpc18xx_pwm->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
+               goto disable_pwmclk;
+       }
+
+       platform_set_drvdata(pdev, lpc18xx_pwm);
+
        return 0;
 
-remove_pwmchip:
-       pwmchip_remove(&lpc18xx_pwm->chip);
 disable_pwmclk:
        clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
        return ret;