Skip to content

Commit

Permalink
Merge tag 'pwm/for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "The changes this time around are mostly janitorial in nature. A lot of
  this is simplifications of drivers using device-managed functions and
  improving compilation coverage.

  The Mediatek display PWM driver now supports the atomic API.

  Cleanups and minor fixes make up the remainder of this set"

* tag 'pwm/for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (54 commits)
  pwm: mtk-disp: Implement atomic API .get_state()
  pwm: mtk-disp: Fix overflow in period and duty calculation
  pwm: mtk-disp: Implement atomic API .apply()
  pwm: mtk-disp: Adjust the clocks to avoid them mismatch
  dt-bindings: pwm: rockchip: Add description for rk3568
  pwm: Make pwmchip_remove() return void
  pwm: sun4i: Don't check the return code of pwmchip_remove()
  pwm: sifive: Don't check the return code of pwmchip_remove()
  pwm: samsung: Don't check the return code of pwmchip_remove()
  pwm: renesas-tpu: Don't check the return code of pwmchip_remove()
  pwm: rcar: Don't check the return code of pwmchip_remove()
  pwm: pca9685: Don't check the return code of pwmchip_remove()
  pwm: omap-dmtimer: Don't check the return code of pwmchip_remove()
  pwm: mtk-disp: Don't check the return code of pwmchip_remove()
  pwm: imx-tpm: Don't check the return code of pwmchip_remove()
  pwm: img: Don't check the return code of pwmchip_remove()
  pwm: cros-ec: Don't check the return code of pwmchip_remove()
  pwm: brcmstb: Don't check the return code of pwmchip_remove()
  pwm: atmel-tcb: Don't check the return code of pwmchip_remove()
  pwm: atmel-hlcdc: Don't check the return code of pwmchip_remove()
  ...
  • Loading branch information
torvalds committed Sep 11, 2021
2 parents dd47038 + 3f2b167 commit 6701e7e
Show file tree
Hide file tree
Showing 43 changed files with 260 additions and 440 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/pwm/pwm-rockchip.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ properties:
- enum:
- rockchip,px30-pwm
- rockchip,rk3308-pwm
- rockchip,rk3568-pwm
- const: rockchip,rk3328-pwm

reg:
Expand Down
5 changes: 3 additions & 2 deletions drivers/pwm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ config PWM_IQS620A

config PWM_JZ4740
tristate "Ingenic JZ47xx PWM support"
depends on MIPS
depends on MIPS || COMPILE_TEST
depends on COMMON_CLK
select MFD_SYSCON
help
Expand All @@ -284,7 +284,8 @@ config PWM_JZ4740

config PWM_KEEMBAY
tristate "Intel Keem Bay PWM driver"
depends on ARCH_KEEMBAY || (ARM64 && COMPILE_TEST)
depends on ARCH_KEEMBAY || COMPILE_TEST
depends on COMMON_CLK && HAS_IOMEM
help
The platform driver for Intel Keem Bay PWM controller.

Expand Down
4 changes: 1 addition & 3 deletions drivers/pwm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
*
* Returns: 0 on success or a negative error code on failure.
*/
int pwmchip_remove(struct pwm_chip *chip)
void pwmchip_remove(struct pwm_chip *chip)
{
pwmchip_sysfs_unexport(chip);

Expand All @@ -318,8 +318,6 @@ int pwmchip_remove(struct pwm_chip *chip)
free_pwms(chip);

mutex_unlock(&pwm_lock);

return 0;
}
EXPORT_SYMBOL_GPL(pwmchip_remove);

Expand Down
35 changes: 15 additions & 20 deletions drivers/pwm/pwm-ab8500.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,29 @@

struct ab8500_pwm_chip {
struct pwm_chip chip;
unsigned int hwid;
};

static struct ab8500_pwm_chip *ab8500_pwm_from_chip(struct pwm_chip *chip)
{
return container_of(chip, struct ab8500_pwm_chip, chip);
}

static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
int ret;
u8 reg;
unsigned int higher_val, lower_val;
struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);

if (state->polarity != PWM_POLARITY_NORMAL)
return -EINVAL;

if (!state->enabled) {
ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
1 << (chip->base - 1), 0);
1 << ab8500->hwid, 0);

if (ret < 0)
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
Expand All @@ -56,7 +63,7 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
*/
higher_val = ((state->duty_cycle & 0x0300) >> 8);

reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2);
reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);

ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
reg, (u8)lower_val);
Expand All @@ -70,7 +77,7 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,

ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
1 << (chip->base - 1), 1 << (chip->base - 1));
1 << ab8500->hwid, 1 << ab8500->hwid);
if (ret < 0)
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
pwm->label, ret);
Expand All @@ -88,6 +95,9 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
struct ab8500_pwm_chip *ab8500;
int err;

if (pdev->id < 1 || pdev->id > 31)
return dev_err_probe(&pdev->dev, EINVAL, "Invalid device id %d\n", pdev->id);

/*
* Nothing to be done in probe, this is required to get the
* device which is required for ab8500 read and write
Expand All @@ -99,27 +109,13 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
ab8500->chip.dev = &pdev->dev;
ab8500->chip.ops = &ab8500_pwm_ops;
ab8500->chip.npwm = 1;
ab8500->hwid = pdev->id - 1;

err = pwmchip_add(&ab8500->chip);
err = devm_pwmchip_add(&pdev->dev, &ab8500->chip);
if (err < 0)
return dev_err_probe(&pdev->dev, err, "Failed to add pwm chip\n");

dev_dbg(&pdev->dev, "pwm probe successful\n");
platform_set_drvdata(pdev, ab8500);

return 0;
}

static int ab8500_pwm_remove(struct platform_device *pdev)
{
struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev);
int err;

err = pwmchip_remove(&ab8500->chip);
if (err < 0)
return err;

dev_dbg(&pdev->dev, "pwm driver removed\n");

return 0;
}
Expand All @@ -129,7 +125,6 @@ static struct platform_driver ab8500_pwm_driver = {
.name = "ab8500-pwm",
},
.probe = ab8500_pwm_probe,
.remove = ab8500_pwm_remove,
};
module_platform_driver(ab8500_pwm_driver);

Expand Down
5 changes: 1 addition & 4 deletions drivers/pwm/pwm-atmel-hlcdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,8 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
static int atmel_hlcdc_pwm_remove(struct platform_device *pdev)
{
struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev);
int ret;

ret = pwmchip_remove(&chip->chip);
if (ret)
return ret;
pwmchip_remove(&chip->chip);

clk_disable_unprepare(chip->hlcdc->periph_clk);

Expand Down
5 changes: 1 addition & 4 deletions drivers/pwm/pwm-atmel-tcb.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,8 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
static int atmel_tcb_pwm_remove(struct platform_device *pdev)
{
struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
int err;

err = pwmchip_remove(&tcbpwm->chip);
if (err < 0)
return err;
pwmchip_remove(&tcbpwm->chip);

clk_disable_unprepare(tcbpwm->slow_clk);
clk_put(tcbpwm->slow_clk);
Expand Down
102 changes: 79 additions & 23 deletions drivers/pwm/pwm-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,19 @@ struct atmel_pwm_chip {
void __iomem *base;
const struct atmel_pwm_data *data;

unsigned int updated_pwms;
/* ISR is cleared when read, ensure only one thread does that */
struct mutex isr_lock;
/*
* The hardware supports a mechanism to update a channel's duty cycle at
* the end of the currently running period. When such an update is
* pending we delay disabling the PWM until the new configuration is
* active because otherwise pmw_config(duty_cycle=0); pwm_disable();
* might not result in an inactive output.
* This bitmask tracks for which channels an update is pending in
* hardware.
*/
u32 update_pending;

/* Protects .update_pending */
spinlock_t lock;
};

static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip)
Expand Down Expand Up @@ -123,6 +133,64 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
atmel_pwm_writel(chip, base + offset, val);
}

static void atmel_pwm_update_pending(struct atmel_pwm_chip *chip)
{
/*
* Each channel that has its bit in ISR set started a new period since
* ISR was cleared and so there is no more update pending. Note that
* reading ISR clears it, so this needs to handle all channels to not
* loose information.
*/
u32 isr = atmel_pwm_readl(chip, PWM_ISR);

chip->update_pending &= ~isr;
}

static void atmel_pwm_set_pending(struct atmel_pwm_chip *chip, unsigned int ch)
{
spin_lock(&chip->lock);

/*
* Clear pending flags in hardware because otherwise there might still
* be a stale flag in ISR.
*/
atmel_pwm_update_pending(chip);

chip->update_pending |= (1 << ch);

spin_unlock(&chip->lock);
}

static int atmel_pwm_test_pending(struct atmel_pwm_chip *chip, unsigned int ch)
{
int ret = 0;

spin_lock(&chip->lock);

if (chip->update_pending & (1 << ch)) {
atmel_pwm_update_pending(chip);

if (chip->update_pending & (1 << ch))
ret = 1;
}

spin_unlock(&chip->lock);

return ret;
}

static int atmel_pwm_wait_nonpending(struct atmel_pwm_chip *chip, unsigned int ch)
{
unsigned long timeout = jiffies + 2 * HZ;
int ret;

while ((ret = atmel_pwm_test_pending(chip, ch)) &&
time_before(jiffies, timeout))
usleep_range(10, 100);

return ret ? -ETIMEDOUT : 0;
}

static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
unsigned long clkrate,
const struct pwm_state *state,
Expand Down Expand Up @@ -185,6 +253,7 @@ static void atmel_pwm_update_cdty(struct pwm_chip *chip, struct pwm_device *pwm,

atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm,
atmel_pwm->data->regs.duty_upd, cdty);
atmel_pwm_set_pending(atmel_pwm, pwm->hwpwm);
}

static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip,
Expand All @@ -205,20 +274,8 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm,
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
unsigned long timeout = jiffies + 2 * HZ;

/*
* Wait for at least a complete period to have passed before disabling a
* channel to be sure that CDTY has been updated
*/
mutex_lock(&atmel_pwm->isr_lock);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);

while (!(atmel_pwm->updated_pwms & (1 << pwm->hwpwm)) &&
time_before(jiffies, timeout)) {
usleep_range(10, 100);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
}
atmel_pwm_wait_nonpending(atmel_pwm, pwm->hwpwm);

mutex_unlock(&atmel_pwm->isr_lock);
atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm);

/*
Expand Down Expand Up @@ -292,10 +349,6 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
val |= PWM_CMR_CPOL;
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty);
mutex_lock(&atmel_pwm->isr_lock);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm);
mutex_unlock(&atmel_pwm->isr_lock);
atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm);
} else if (cstate.enabled) {
atmel_pwm_disable(chip, pwm, true);
Expand Down Expand Up @@ -326,6 +379,9 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
tmp <<= pres;
state->period = DIV64_U64_ROUND_UP(tmp, rate);

/* Wait for an updated duty_cycle queued in hardware */
atmel_pwm_wait_nonpending(atmel_pwm, pwm->hwpwm);

cdty = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
atmel_pwm->data->regs.duty);
tmp = (u64)(cprd - cdty) * NSEC_PER_SEC;
Expand Down Expand Up @@ -416,9 +472,10 @@ static int atmel_pwm_probe(struct platform_device *pdev)
if (!atmel_pwm)
return -ENOMEM;

mutex_init(&atmel_pwm->isr_lock);
atmel_pwm->data = of_device_get_match_data(&pdev->dev);
atmel_pwm->updated_pwms = 0;

atmel_pwm->update_pending = 0;
spin_lock_init(&atmel_pwm->lock);

atmel_pwm->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(atmel_pwm->base))
Expand Down Expand Up @@ -460,7 +517,6 @@ static int atmel_pwm_remove(struct platform_device *pdev)
pwmchip_remove(&atmel_pwm->chip);

clk_unprepare(atmel_pwm->clk);
mutex_destroy(&atmel_pwm->isr_lock);

return 0;
}
Expand Down
12 changes: 1 addition & 11 deletions drivers/pwm/pwm-bcm-kona.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
if (kp == NULL)
return -ENOMEM;

platform_set_drvdata(pdev, kp);

kp->chip.dev = &pdev->dev;
kp->chip.ops = &kona_pwm_ops;
kp->chip.npwm = 6;
Expand Down Expand Up @@ -298,20 +296,13 @@ static int kona_pwmc_probe(struct platform_device *pdev)

clk_disable_unprepare(kp->clk);

ret = pwmchip_add(&kp->chip);
ret = devm_pwmchip_add(&pdev->dev, &kp->chip);
if (ret < 0)
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);

return ret;
}

static int kona_pwmc_remove(struct platform_device *pdev)
{
struct kona_pwmc *kp = platform_get_drvdata(pdev);

return pwmchip_remove(&kp->chip);
}

static const struct of_device_id bcm_kona_pwmc_dt[] = {
{ .compatible = "brcm,kona-pwm" },
{ },
Expand All @@ -324,7 +315,6 @@ static struct platform_driver kona_pwmc_driver = {
.of_match_table = bcm_kona_pwmc_dt,
},
.probe = kona_pwmc_probe,
.remove = kona_pwmc_remove,
};
module_platform_driver(kona_pwmc_driver);

Expand Down
5 changes: 2 additions & 3 deletions drivers/pwm/pwm-brcmstb.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,11 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
static int brcmstb_pwm_remove(struct platform_device *pdev)
{
struct brcmstb_pwm *p = platform_get_drvdata(pdev);
int ret;

ret = pwmchip_remove(&p->chip);
pwmchip_remove(&p->chip);
clk_disable_unprepare(p->clk);

return ret;
return 0;
}

#ifdef CONFIG_PM_SLEEP
Expand Down
4 changes: 3 additions & 1 deletion drivers/pwm/pwm-cros-ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ static int cros_ec_pwm_remove(struct platform_device *dev)
struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev);
struct pwm_chip *chip = &ec_pwm->chip;

return pwmchip_remove(chip);
pwmchip_remove(chip);

return 0;
}

#ifdef CONFIG_OF
Expand Down
Loading

0 comments on commit 6701e7e

Please sign in to comment.