diff options
author | John Audia <graysky@archlinux.us> | 2021-04-14 07:25:24 -0400 |
---|---|---|
committer | Hauke Mehrtens <hauke@hauke-m.de> | 2021-04-17 21:50:08 +0200 |
commit | 79fdd68103d226bd4837e285fc12ebdc2ab81632 (patch) | |
tree | 0e8c2b18963f1fde5c3ff059a4f372cfb6b75546 /target/linux/sunxi | |
parent | 33f419bf2acec1baa490cb93624acda7c3456a72 (diff) | |
download | upstream-79fdd68103d226bd4837e285fc12ebdc2ab81632.tar.gz upstream-79fdd68103d226bd4837e285fc12ebdc2ab81632.tar.bz2 upstream-79fdd68103d226bd4837e285fc12ebdc2ab81632.zip |
kernel: bump 5.4 to 5.4.112
Ran update_kernel.sh in a fresh clone without any existing toolchains.
Removed upstreamed:
mvebu/patches-5.4/319-ARM-dts-turris-omnia-configure-LED-2--INTn-pin-as-interrupt-pin.patch
Build system : x86_64
Build-tested : ipq806x/R7800
Run-tested : ipq806x/R7800
No dmesg regressions, everything functional
Signed-off-by: John Audia <graysky@archlinux.us>
Diffstat (limited to 'target/linux/sunxi')
4 files changed, 205 insertions, 304 deletions
diff --git a/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch b/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch index 64ffd719ac..eb254ee74d 100644 --- a/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch +++ b/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch @@ -1,8 +1,17 @@ -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 581d23287333..487899d4cc3f 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c -@@ -16,6 +16,7 @@ +@@ -3,6 +3,10 @@ + * Driver for Allwinner sun4i Pulse Width Modulation Controller + * + * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com> ++ * ++ * Limitations: ++ * - When outputing the source clock directly, the PWM logic will be bypassed ++ * and the currently running period is not guaranteed to be completed + */ + + #include <linux/bitops.h> +@@ -16,6 +20,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pwm.h> @@ -10,182 +19,70 @@ index 581d23287333..487899d4cc3f 100644 #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/time.h> -@@ -78,6 +79,7 @@ struct sun4i_pwm_data { +@@ -72,12 +77,15 @@ static const u32 prescaler_table[] = { + + struct sun4i_pwm_data { + bool has_prescaler_bypass; ++ bool has_direct_mod_clk_output; + unsigned int npwm; + }; + struct sun4i_pwm_chip { struct pwm_chip chip; ++ struct clk *bus_clk; struct clk *clk; + struct reset_control *rst; void __iomem *base; spinlock_t ctrl_lock; const struct sun4i_pwm_data *data; -@@ -364,6 +366,22 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); - -+ pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); -+ if (IS_ERR(pwm->rst)) { -+ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "get reset failed %pe\n", -+ pwm->rst); -+ return PTR_ERR(pwm->rst); -+ } -+ -+ /* Deassert reset */ -+ ret = reset_control_deassert(pwm->rst); -+ if (ret) { -+ dev_err(&pdev->dev, "cannot deassert reset control: %pe\n", -+ ERR_PTR(ret)); -+ return ret; -+ } -+ - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &sun4i_pwm_ops; - pwm->chip.base = -1; -@@ -376,19 +394,31 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - ret = pwmchip_add(&pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); -- return ret; -+ goto err_pwm_add; - } - - platform_set_drvdata(pdev, pwm); - - return 0; -+ -+err_pwm_add: -+ reset_control_assert(pwm->rst); -+ -+ return ret; - } - - static int sun4i_pwm_remove(struct platform_device *pdev) - { - struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev); -+ int ret; -+ -+ ret = pwmchip_remove(&pwm->chip); -+ if (ret) -+ return ret; -+ -+ reset_control_assert(pwm->rst); +@@ -115,6 +123,20 @@ static void sun4i_pwm_get_state(struct p -- return pwmchip_remove(&pwm->chip); -+ return 0; - } - - static struct platform_driver sun4i_pwm_driver = { - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 487899d4cc3f..80026167044b 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -362,9 +362,34 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - if (IS_ERR(pwm->base)) - return PTR_ERR(pwm->base); + val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); -- pwm->clk = devm_clk_get(&pdev->dev, NULL); -- if (IS_ERR(pwm->clk)) + /* -+ * All hardware variants need a source clock that is divided and -+ * then feeds the counter that defines the output wave form. In the -+ * device tree this clock is either unnamed or called "mod". -+ * Some variants (e.g. H6) need another clock to access the -+ * hardware registers; this is called "bus". -+ * So we request "mod" first (and ignore the corner case that a -+ * parent provides a "mod" clock while the right one would be the -+ * unnamed one of the PWM device) and if this is not found we fall -+ * back to the first clock of the PWM. ++ * PWM chapter in H6 manual has a diagram which explains that if bypass ++ * bit is set, no other setting has any meaning. Even more, experiment ++ * proved that also enable bit is ignored in this case. + */ -+ pwm->clk = devm_clk_get_optional(&pdev->dev, "mod"); -+ if (IS_ERR(pwm->clk)) { -+ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "get mod clock failed %pe\n", -+ pwm->clk); - return PTR_ERR(pwm->clk); ++ if ((val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) && ++ sun4i_pwm->data->has_direct_mod_clk_output) { ++ state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate); ++ state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2); ++ state->polarity = PWM_POLARITY_NORMAL; ++ state->enabled = true; ++ return; + } + -+ if (!pwm->clk) { -+ pwm->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(pwm->clk)) { -+ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "get unnamed clock failed %pe\n", -+ pwm->clk); -+ return PTR_ERR(pwm->clk); -+ } -+ } + if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && + sun4i_pwm->data->has_prescaler_bypass) + prescaler = 1; +@@ -146,13 +168,24 @@ static void sun4i_pwm_get_state(struct p - pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); - if (IS_ERR(pwm->rst)) { - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 80026167044b..a6727dd89e28 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -78,6 +78,7 @@ struct sun4i_pwm_data { + static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, + const struct pwm_state *state, +- u32 *dty, u32 *prd, unsigned int *prsclr) ++ u32 *dty, u32 *prd, unsigned int *prsclr, ++ bool *bypass) + { + u64 clk_rate, div = 0; + unsigned int pval, prescaler = 0; - struct sun4i_pwm_chip { - struct pwm_chip chip; -+ struct clk *bus_clk; - struct clk *clk; - struct reset_control *rst; - void __iomem *base; -@@ -391,6 +392,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - } - } + clk_rate = clk_get_rate(sun4i_pwm->clk); -+ pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); -+ if (IS_ERR(pwm->bus_clk)) { -+ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "get bus clock failed %pe\n", -+ pwm->bus_clk); -+ return PTR_ERR(pwm->bus_clk); -+ } ++ *bypass = sun4i_pwm->data->has_direct_mod_clk_output && ++ state->enabled && ++ (state->period * clk_rate >= NSEC_PER_SEC) && ++ (state->period * clk_rate < 2 * NSEC_PER_SEC) && ++ (state->duty_cycle * clk_rate * 2 >= NSEC_PER_SEC); + - pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); - if (IS_ERR(pwm->rst)) { - if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) -@@ -407,6 +416,17 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - return ret; - } - -+ /* -+ * We're keeping the bus clock on for the sake of simplicity. -+ * Actually it only needs to be on for hardware register accesses. -+ */ -+ ret = clk_prepare_enable(pwm->bus_clk); -+ if (ret) { -+ dev_err(&pdev->dev, "cannot prepare and enable bus_clk %pe\n", -+ ERR_PTR(ret)); -+ goto err_bus; -+ } ++ /* Skip calculation of other parameters if we bypass them */ ++ if (*bypass) ++ return 0; + - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &sun4i_pwm_ops; - pwm->chip.base = -1; -@@ -427,6 +447,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - return 0; - - err_pwm_add: -+ clk_disable_unprepare(pwm->bus_clk); -+err_bus: - reset_control_assert(pwm->rst); - - return ret; -@@ -441,6 +463,7 @@ static int sun4i_pwm_remove(struct platform_device *pdev) - if (ret) - return ret; - -+ clk_disable_unprepare(pwm->bus_clk); - reset_control_assert(pwm->rst); - - return 0; - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index a6727dd89e28..e369b5a398f4 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -202,9 +202,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + if (sun4i_pwm->data->has_prescaler_bypass) { + /* First, test without any prescaler when available */ + prescaler = PWM_PRESCAL_MASK; +@@ -200,10 +233,11 @@ static int sun4i_pwm_apply(struct pwm_ch { struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); struct pwm_state cstate; @@ -195,9 +92,11 @@ index a6727dd89e28..e369b5a398f4 100644 - unsigned int delay_us; + unsigned int delay_us, prescaler; unsigned long now; ++ bool bypass; pwm_get_state(pwm, &cstate); -@@ -220,43 +220,37 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + +@@ -218,43 +252,50 @@ static int sun4i_pwm_apply(struct pwm_ch spin_lock(&sun4i_pwm->ctrl_lock); ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); @@ -205,30 +104,40 @@ index a6727dd89e28..e369b5a398f4 100644 - (cstate.duty_cycle != state->duty_cycle)) { - u32 period, duty, val; - unsigned int prescaler; -- ++ ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler, ++ &bypass); ++ if (ret) { ++ dev_err(chip->dev, "period exceeds the maximum value\n"); ++ spin_unlock(&sun4i_pwm->ctrl_lock); ++ if (!cstate.enabled) ++ clk_disable_unprepare(sun4i_pwm->clk); ++ return ret; ++ } + - ret = sun4i_pwm_calculate(sun4i_pwm, state, - &duty, &period, &prescaler); - if (ret) { - dev_err(chip->dev, "period exceeds the maximum value\n"); -- spin_unlock(&sun4i_pwm->ctrl_lock); ++ if (sun4i_pwm->data->has_direct_mod_clk_output) { ++ if (bypass) { ++ ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm); ++ /* We can skip other parameter */ ++ sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); + spin_unlock(&sun4i_pwm->ctrl_lock); - if (!cstate.enabled) - clk_disable_unprepare(sun4i_pwm->clk); - return ret; -- } -- ++ return 0; ++ } else { ++ ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm); + } ++ } + - if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { - /* Prescaler changed, the clock has to be gated */ - ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); -+ ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler); -+ if (ret) { -+ dev_err(chip->dev, "period exceeds the maximum value\n"); -+ spin_unlock(&sun4i_pwm->ctrl_lock); -+ if (!cstate.enabled) -+ clk_disable_unprepare(sun4i_pwm->clk); -+ return ret; -+ } - +- - ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm); - ctrl |= BIT_CH(prescaler, pwm->hwpwm); - } @@ -262,120 +171,7 @@ index a6727dd89e28..e369b5a398f4 100644 if (state->enabled) { ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) { - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index e369b5a398f4..07bf7be6074b 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -3,6 +3,10 @@ - * Driver for Allwinner sun4i Pulse Width Modulation Controller - * - * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com> -+ * -+ * Limitations: -+ * - When outputing the source clock directly, the PWM logic will be bypassed -+ * and the currently running period is not guaranteed to be completed - */ - - #include <linux/bitops.h> -@@ -73,6 +77,7 @@ static const u32 prescaler_table[] = { - - struct sun4i_pwm_data { - bool has_prescaler_bypass; -+ bool has_direct_mod_clk_output; - unsigned int npwm; - }; - -@@ -118,6 +123,20 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, - - val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); - -+ /* -+ * PWM chapter in H6 manual has a diagram which explains that if bypass -+ * bit is set, no other setting has any meaning. Even more, experiment -+ * proved that also enable bit is ignored in this case. -+ */ -+ if ((val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) && -+ sun4i_pwm->data->has_direct_mod_clk_output) { -+ state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate); -+ state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2); -+ state->polarity = PWM_POLARITY_NORMAL; -+ state->enabled = true; -+ return; -+ } -+ - if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && - sun4i_pwm->data->has_prescaler_bypass) - prescaler = 1; -@@ -149,13 +168,24 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, - - static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, - const struct pwm_state *state, -- u32 *dty, u32 *prd, unsigned int *prsclr) -+ u32 *dty, u32 *prd, unsigned int *prsclr, -+ bool *bypass) - { - u64 clk_rate, div = 0; - unsigned int pval, prescaler = 0; - - clk_rate = clk_get_rate(sun4i_pwm->clk); - -+ *bypass = sun4i_pwm->data->has_direct_mod_clk_output && -+ state->enabled && -+ (state->period * clk_rate >= NSEC_PER_SEC) && -+ (state->period * clk_rate < 2 * NSEC_PER_SEC) && -+ (state->duty_cycle * clk_rate * 2 >= NSEC_PER_SEC); -+ -+ /* Skip calculation of other parameters if we bypass them */ -+ if (*bypass) -+ return 0; -+ - if (sun4i_pwm->data->has_prescaler_bypass) { - /* First, test without any prescaler when available */ - prescaler = PWM_PRESCAL_MASK; -@@ -206,6 +236,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - int ret; - unsigned int delay_us, prescaler; - unsigned long now; -+ bool bypass; - - pwm_get_state(pwm, &cstate); - -@@ -220,7 +251,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - spin_lock(&sun4i_pwm->ctrl_lock); - ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); - -- ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler); -+ ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler, -+ &bypass); - if (ret) { - dev_err(chip->dev, "period exceeds the maximum value\n"); - spin_unlock(&sun4i_pwm->ctrl_lock); -@@ -229,6 +261,18 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - return ret; - } - -+ if (sun4i_pwm->data->has_direct_mod_clk_output) { -+ if (bypass) { -+ ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm); -+ /* We can skip other parameter */ -+ sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); -+ spin_unlock(&sun4i_pwm->ctrl_lock); -+ return 0; -+ } else { -+ ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm); -+ } -+ } -+ - if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { - /* Prescaler changed, the clock has to be gated */ - ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 07bf7be6074b..c394878c7e5d 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -360,6 +360,12 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = { +@@ -320,6 +361,12 @@ static const struct sun4i_pwm_data sun4i .npwm = 1, }; @@ -388,13 +184,122 @@ index 07bf7be6074b..c394878c7e5d 100644 static const struct of_device_id sun4i_pwm_dt_ids[] = { { .compatible = "allwinner,sun4i-a10-pwm", -@@ -376,6 +382,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { - }, { +@@ -337,6 +384,9 @@ static const struct of_device_id sun4i_p .compatible = "allwinner,sun8i-h3-pwm", .data = &sun4i_pwm_single_bypass, -+ }, { + }, { + .compatible = "allwinner,sun50i-h6-pwm", + .data = &sun50i_h6_pwm_data, - }, { ++ }, { /* sentinel */ }, + }; +@@ -361,9 +411,69 @@ static int sun4i_pwm_probe(struct platfo + if (IS_ERR(pwm->base)) + return PTR_ERR(pwm->base); + +- pwm->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(pwm->clk)) ++ /* ++ * All hardware variants need a source clock that is divided and ++ * then feeds the counter that defines the output wave form. In the ++ * device tree this clock is either unnamed or called "mod". ++ * Some variants (e.g. H6) need another clock to access the ++ * hardware registers; this is called "bus". ++ * So we request "mod" first (and ignore the corner case that a ++ * parent provides a "mod" clock while the right one would be the ++ * unnamed one of the PWM device) and if this is not found we fall ++ * back to the first clock of the PWM. ++ */ ++ pwm->clk = devm_clk_get_optional(&pdev->dev, "mod"); ++ if (IS_ERR(pwm->clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get mod clock failed %pe\n", ++ pwm->clk); + return PTR_ERR(pwm->clk); ++ } ++ ++ if (!pwm->clk) { ++ pwm->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pwm->clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get unnamed clock failed %pe\n", ++ pwm->clk); ++ return PTR_ERR(pwm->clk); ++ } ++ } ++ ++ pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); ++ if (IS_ERR(pwm->bus_clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get bus clock failed %pe\n", ++ pwm->bus_clk); ++ return PTR_ERR(pwm->bus_clk); ++ } ++ ++ pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); ++ if (IS_ERR(pwm->rst)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get reset failed %pe\n", ++ pwm->rst); ++ return PTR_ERR(pwm->rst); ++ } ++ ++ /* Deassert reset */ ++ ret = reset_control_deassert(pwm->rst); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot deassert reset control: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++ /* ++ * We're keeping the bus clock on for the sake of simplicity. ++ * Actually it only needs to be on for hardware register accesses. ++ */ ++ ret = clk_prepare_enable(pwm->bus_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot prepare and enable bus_clk %pe\n", ++ ERR_PTR(ret)); ++ goto err_bus; ++ } + + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &sun4i_pwm_ops; +@@ -377,19 +487,34 @@ static int sun4i_pwm_probe(struct platfo + ret = pwmchip_add(&pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); +- return ret; ++ goto err_pwm_add; + } + + platform_set_drvdata(pdev, pwm); + + return 0; ++ ++err_pwm_add: ++ clk_disable_unprepare(pwm->bus_clk); ++err_bus: ++ reset_control_assert(pwm->rst); ++ ++ return ret; + } + + static int sun4i_pwm_remove(struct platform_device *pdev) + { + struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = pwmchip_remove(&pwm->chip); ++ if (ret) ++ return ret; + +- return pwmchip_remove(&pwm->chip); ++ clk_disable_unprepare(pwm->bus_clk); ++ reset_control_assert(pwm->rst); ++ ++ return 0; + } + + static struct platform_driver sun4i_pwm_driver = { diff --git a/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch b/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch index 60e653dcba..c14e729539 100644 --- a/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch +++ b/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch @@ -14,11 +14,9 @@ Signed-off-by: Clément Péron <peron.clem@gmail.com> arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -index 29824081b43b..6d4bde488f15 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -@@ -245,6 +245,16 @@ +@@ -231,6 +231,16 @@ status = "disabled"; }; diff --git a/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch b/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch index d95c3c8987..8ebbe3fad8 100644 --- a/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch +++ b/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch @@ -1,10 +1,8 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts -index f335f7482a73..cf684bc7374d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts -@@ -45,3 +45,7 @@ - reg = <1>; - }; +@@ -10,3 +10,7 @@ + model = "OrangePi One Plus"; + compatible = "xunlong,orangepi-one-plus", "allwinner,sun50i-h6"; }; + +&pwm { diff --git a/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch b/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch index 5f7974c609..88c466d9b9 100644 --- a/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch +++ b/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch @@ -1,8 +1,6 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts -index 12e1756..79139f3 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts -@@ -9,4 +9,39 @@ +@@ -9,6 +9,41 @@ / { model = "OrangePi One Plus"; compatible = "xunlong,orangepi-one-plus", "allwinner,sun50i-h6"; @@ -42,3 +40,5 @@ index 12e1756..79139f3 100644 + reg = <1>; + }; }; + + &pwm { |