diff options
42 files changed, 299 insertions, 229 deletions
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml index 1c94acbc2b4a..4c8097010687 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml @@ -35,6 +35,7 @@ properties: - renesas,pwm-r8a77980 # R-Car V3H - renesas,pwm-r8a77990 # R-Car E3 - renesas,pwm-r8a77995 # R-Car D3 + - renesas,pwm-r8a779g0 # R-Car V4H - const: renesas,pwm-rcar reg: diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml index c6b2ab56b7fe..a3e52b22dd18 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml @@ -40,6 +40,7 @@ properties: - renesas,tpu-r8a77970 # R-Car V3M - renesas,tpu-r8a77980 # R-Car V3H - renesas,tpu-r8a779a0 # R-Car V3U + - renesas,tpu-r8a779g0 # R-Car V4H - const: renesas,tpu reg: diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1bb317b8dcce..91a4232ee58c 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -657,9 +657,10 @@ static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock_irqrestore(&mvpwm->lock, flags); } -static void mvebu_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) { +static int mvebu_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; @@ -693,6 +694,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, state->enabled = false; spin_unlock_irqrestore(&mvpwm->lock, flags); + + return 0; } static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index eb24322df721..05f8756d1aaf 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1500,8 +1500,8 @@ out: return ret; } -static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct ti_sn65dsi86 *pdata = pwm_chip_to_ti_sn_bridge(chip); unsigned int pwm_en_inv; @@ -1512,19 +1512,19 @@ static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(pdata->regmap, SN_PWM_EN_INV_REG, &pwm_en_inv); if (ret) - return; + return ret; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_SCALE_REG, &scale); if (ret) - return; + return ret; ret = ti_sn65dsi86_read_u16(pdata, SN_BACKLIGHT_REG, &backlight); if (ret) - return; + return ret; ret = regmap_read(pdata->regmap, SN_PWM_PRE_DIV_REG, &pre_div); if (ret) - return; + return ret; state->enabled = FIELD_GET(SN_PWM_EN_MASK, pwm_en_inv); if (FIELD_GET(SN_PWM_INV_MASK, pwm_en_inv)) @@ -1539,6 +1539,8 @@ static void ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (state->duty_cycle > state->period) state->duty_cycle = state->period; + + return 0; } static const struct pwm_ops ti_sn_pwm_ops = { diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index c1a56259226f..67f48f222109 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -972,8 +972,8 @@ out_unlock: return ret; } -static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct lpg *lpg = container_of(chip, struct lpg, pwm); struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; @@ -986,20 +986,20 @@ static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + LPG_SIZE_CLK_REG, &val); if (ret) - return; + return ret; refclk = lpg_clk_rates[val & PWM_CLK_SELECT_MASK]; if (refclk) { ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); if (ret) - return; + return ret; pre_div = lpg_pre_divs[FIELD_GET(PWM_FREQ_PRE_DIV_MASK, val)]; m = FIELD_GET(PWM_FREQ_EXP_MASK, val); ret = regmap_bulk_read(lpg->map, chan->base + PWM_VALUE_REG, &pwm_value, sizeof(pwm_value)); if (ret) - return; + return ret; state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * LPG_RESOLUTION * pre_div * (1 << m), refclk); state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); @@ -1010,13 +1010,15 @@ static void lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_read(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, &val); if (ret) - return; + return ret; state->enabled = FIELD_GET(LPG_ENABLE_CONTROL_OUTPUT, val); state->polarity = PWM_POLARITY_NORMAL; if (state->duty_cycle > state->period) state->duty_cycle = state->period; + + return 0; } static const struct pwm_ops lpg_pwm_ops = { diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 60d13a949bc5..dae023d783a2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -282,8 +282,8 @@ config PWM_IQS620A config PWM_JZ4740 tristate "Ingenic JZ47xx PWM support" - depends on MIPS || COMPILE_TEST - depends on COMMON_CLK + depends on MACH_INGENIC || COMPILE_TEST + depends on COMMON_CLK && OF select MFD_SYSCON help Generic PWM framework driver for Ingenic JZ47xx based @@ -434,7 +434,7 @@ config PWM_PCA9685 config PWM_PXA tristate "PXA PWM support" - depends on ARCH_PXA || COMPILE_TEST + depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST depends on HAS_IOMEM help Generic PWM framework driver for PXA. diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index d333e7422f4a..e01147f66e15 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -27,7 +27,10 @@ static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); + +/* protects access to pwm_chips, allocated_pwms, and pwm_tree */ static DEFINE_MUTEX(pwm_lock); + static LIST_HEAD(pwm_chips); static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); static RADIX_TREE(pwm_tree, GFP_KERNEL); @@ -37,6 +40,7 @@ static struct pwm_device *pwm_to_device(unsigned int pwm) return radix_tree_lookup(&pwm_tree, pwm); } +/* Called with pwm_lock held */ static int alloc_pwms(unsigned int count) { unsigned int start; @@ -47,9 +51,12 @@ static int alloc_pwms(unsigned int count) if (start + count > MAX_PWMS) return -ENOSPC; + bitmap_set(allocated_pwms, start, count); + return start; } +/* Called with pwm_lock held */ static void free_pwms(struct pwm_chip *chip) { unsigned int i; @@ -108,8 +115,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } if (pwm->chip->ops->get_state) { - pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); - trace_pwm_get(pwm, &pwm->state); + struct pwm_state state; + + err = pwm->chip->ops->get_state(pwm->chip, pwm, &state); + trace_pwm_get(pwm, &state, err); + + if (!err) + pwm->state = state; if (IS_ENABLED(CONFIG_PWM_DEBUG)) pwm->last = pwm->state; @@ -267,20 +279,21 @@ int pwmchip_add(struct pwm_chip *chip) if (!pwm_ops_check(chip)) return -EINVAL; + chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); + if (!chip->pwms) + return -ENOMEM; + mutex_lock(&pwm_lock); ret = alloc_pwms(chip->npwm); - if (ret < 0) - goto out; + if (ret < 0) { + mutex_unlock(&pwm_lock); + kfree(chip->pwms); + return ret; + } chip->base = ret; - chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); - if (!chip->pwms) { - ret = -ENOMEM; - goto out; - } - for (i = 0; i < chip->npwm; i++) { pwm = &chip->pwms[i]; @@ -291,23 +304,16 @@ int pwmchip_add(struct pwm_chip *chip) radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } - bitmap_set(allocated_pwms, chip->base, chip->npwm); - - INIT_LIST_HEAD(&chip->list); list_add(&chip->list, &pwm_chips); - ret = 0; + mutex_unlock(&pwm_lock); if (IS_ENABLED(CONFIG_OF)) of_pwmchip_add(chip); -out: - mutex_unlock(&pwm_lock); - - if (!ret) - pwmchip_sysfs_export(chip); + pwmchip_sysfs_export(chip); - return ret; + return 0; } EXPORT_SYMBOL_GPL(pwmchip_add); @@ -457,8 +463,11 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, * checks. */ - chip->ops->get_state(chip, pwm, &s1); - trace_pwm_get(pwm, &s1); + err = chip->ops->get_state(chip, pwm, &s1); + trace_pwm_get(pwm, &s1, err); + if (err) + /* If that failed there isn't much to debug */ + return; /* * The lowlevel driver either ignored .polarity (which is a bug) or as @@ -514,16 +523,17 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, /* reapply the state that the driver reported being configured. */ err = chip->ops->apply(chip, pwm, &s1); + trace_pwm_apply(pwm, &s1, err); if (err) { *last = s1; dev_err(chip->dev, "failed to reapply current setting\n"); return; } - trace_pwm_apply(pwm, &s1); - - chip->ops->get_state(chip, pwm, last); - trace_pwm_get(pwm, last); + err = chip->ops->get_state(chip, pwm, last); + trace_pwm_get(pwm, last, err); + if (err) + return; /* reapplication of the current state should give an exact match */ if (s1.enabled != last->enabled || @@ -571,11 +581,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) return 0; err = chip->ops->apply(chip, pwm, state); + trace_pwm_apply(pwm, state, err); if (err) return err; - trace_pwm_apply(pwm, state); - pwm->state = *state; /* @@ -1179,8 +1188,7 @@ DEFINE_SEQ_ATTRIBUTE(pwm_debugfs); static int __init pwm_debugfs_init(void) { - debugfs_create_file("pwm", S_IFREG | 0444, NULL, NULL, - &pwm_debugfs_fops); + debugfs_create_file("pwm", 0444, NULL, NULL, &pwm_debugfs_fops); return 0; } diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 8e00a4286145..cdbc23649032 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -356,8 +356,8 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); u32 sr, cmr; @@ -396,6 +396,8 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->polarity = PWM_POLARITY_INVERSED; else state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static const struct pwm_ops atmel_pwm_ops = { diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 7251037d4dd5..97ec131eb7c1 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -68,8 +68,8 @@ static void iproc_pwmc_disable(struct iproc_pwmc *ip, unsigned int channel) ndelay(400); } -static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct iproc_pwmc *ip = to_iproc_pwmc(chip); u64 tmp, multi, rate; @@ -91,7 +91,7 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (rate == 0) { state->period = 0; state->duty_cycle = 0; - return; + return 0; } value = readl(ip->base + IPROC_PWM_PRESCALE_OFFSET); @@ -107,6 +107,8 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, value = readl(ip->base + IPROC_PWM_DUTY_CYCLE_OFFSET(pwm->hwpwm)); tmp = (value & IPROC_PWM_PERIOD_MAX) * multi; state->duty_cycle = div64_u64(tmp, rate); + + return 0; } static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 7b357d1cf642..4703b4a0b6e4 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -121,8 +121,8 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip); struct device *dev = crc_pwm->chip.dev; @@ -132,13 +132,13 @@ static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg); if (error) { dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error); - return; + return error; } error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg); if (error) { dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error); - return; + return error; } clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1; @@ -149,6 +149,8 @@ static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, DIV_ROUND_UP_ULL(duty_cycle_reg * state->period, PWM_MAX_LEVEL); state->polarity = PWM_POLARITY_NORMAL; state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE); + + return 0; } static const struct pwm_ops crc_pwm_ops = { diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 7f10f56c3eb6..86df6702cb83 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -183,8 +183,8 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); struct cros_ec_pwm *channel = pwm_get_chip_data(pwm); @@ -193,7 +193,7 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm); if (ret < 0) { dev_err(chip->dev, "error getting initial duty: %d\n", ret); - return; + return ret; } state->enabled = (ret > 0); @@ -212,6 +212,8 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = channel->duty_cycle; else state->duty_cycle = ret; + + return 0; } static struct pwm_device * diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c index 7568300bb11e..bd2308812096 100644 --- a/drivers/pwm/pwm-dwc.c +++ b/drivers/pwm/pwm-dwc.c @@ -163,8 +163,8 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct dwc_pwm *dwc = to_dwc_pwm(chip); u64 duty, period; @@ -188,6 +188,8 @@ static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->polarity = PWM_POLARITY_INVERSED; pm_runtime_put_sync(chip->dev); + + return 0; } static const struct pwm_ops dwc_pwm_ops = { diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 0247757f9a72..5caadbd6194e 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -65,13 +65,12 @@ static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc) regmap_read(fpc->regmap, FTM_FMS, &val); if (val & FTM_FMS_WPEN) - regmap_update_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS, - FTM_MODE_WPDIS); + regmap_set_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS); } static void ftm_set_write_protection(struct fsl_pwm_chip *fpc) { - regmap_update_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN, FTM_FMS_WPEN); + regmap_set_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN); } static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a, @@ -94,8 +93,7 @@ static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ret = clk_prepare_enable(fpc->ipg_clk); if (!ret && fpc->soc->has_enable_bits) { mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), - BIT(pwm->hwpwm + 16)); + regmap_set_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); mutex_unlock(&fpc->lock); } @@ -108,8 +106,7 @@ static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) if (fpc->soc->has_enable_bits) { mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), - 0); + regmap_clear_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); mutex_unlock(&fpc->lock); } @@ -317,8 +314,8 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (!newstate->enabled) { if (oldstate->enabled) { - regmap_update_bits(fpc->regmap, FTM_OUTMASK, - BIT(pwm->hwpwm), BIT(pwm->hwpwm)); + regmap_set_bits(fpc->regmap, FTM_OUTMASK, + BIT(pwm->hwpwm)); clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); } @@ -342,8 +339,7 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, goto end_mutex; } - regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), - 0); + regmap_clear_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm)); } end_mutex: diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 333f1b18ff4e..12c05c155cab 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -128,8 +128,8 @@ static void hibvt_pwm_set_polarity(struct pwm_chip *chip, PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT)); } -static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); void __iomem *base; @@ -146,6 +146,8 @@ static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm)); state->enabled = (PWM_ENABLE_MASK & value); + + return 0; } static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 0fccf061ab95..89362afe3c91 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -161,9 +161,9 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) val |= BIT(pwm->hwpwm); img_pwm_writel(imgchip, PWM_CTRL_CFG, val); - regmap_update_bits(imgchip->periph_regs, PERIP_PWM_PDM_CONTROL, - PERIP_PWM_PDM_CONTROL_CH_MASK << - PERIP_PWM_PDM_CONTROL_CH_SHIFT(pwm->hwpwm), 0); + regmap_clear_bits(imgchip->periph_regs, PERIP_PWM_PDM_CONTROL, + PERIP_PWM_PDM_CONTROL_CH_MASK << + PERIP_PWM_PDM_CONTROL_CH_SHIFT(pwm->hwpwm)); return 0; } @@ -397,11 +397,10 @@ static int img_pwm_resume(struct device *dev) for (i = 0; i < imgchip->chip.npwm; i++) if (imgchip->suspend_ctrl_cfg & BIT(i)) - regmap_update_bits(imgchip->periph_regs, - PERIP_PWM_PDM_CONTROL, - PERIP_PWM_PDM_CONTROL_CH_MASK << - PERIP_PWM_PDM_CONTROL_CH_SHIFT(i), - 0); + regmap_clear_bits(imgchip->periph_regs, + PERIP_PWM_PDM_CONTROL, + PERIP_PWM_PDM_CONTROL_CH_MASK << + PERIP_PWM_PDM_CONTROL_CH_SHIFT(i)); if (pm_runtime_status_suspended(dev)) img_pwm_runtime_suspend(dev); diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index e5e7b7c339a8..ed1aad96fff0 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -132,9 +132,9 @@ static int pwm_imx_tpm_round_state(struct pwm_chip *chip, return 0; } -static void pwm_imx_tpm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_imx_tpm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); u32 rate, val, prescale; @@ -164,6 +164,8 @@ static void pwm_imx_tpm_get_state(struct pwm_chip *chip, /* get channel status */ state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false; + + return 0; } /* this function is supposed to be called with mutex hold */ diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index ea91a2f81a9f..29a3089c534c 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -118,8 +118,8 @@ static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx) clk_disable_unprepare(imx->clk_ipg); } -static void pwm_imx27_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, struct pwm_state *state) +static int pwm_imx27_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, struct pwm_state *state) { struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); u32 period, prescaler, pwm_clk, val; @@ -128,7 +128,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, ret = pwm_imx27_clk_prepare_enable(imx); if (ret < 0) - return; + return ret; val = readl(imx->mmio_base + MX3_PWMCR); @@ -170,6 +170,8 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk); pwm_imx27_clk_disable_unprepare(imx); + + return 0; } static void pwm_imx27_sw_reset(struct pwm_chip *chip) diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c index b66c35074087..0cd7dd548e82 100644 --- a/drivers/pwm/pwm-intel-lgm.c +++ b/drivers/pwm/pwm-intel-lgm.c @@ -86,8 +86,8 @@ static int lgm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return lgm_pwm_enable(chip, 1); } -static void lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip); u32 duty, val; @@ -100,6 +100,8 @@ static void lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, regmap_read(pc->regmap, LGM_PWM_FAN_CON0, &val); duty = FIELD_GET(LGM_PWM_FAN_DC_MSK, val); state->duty_cycle = DIV_ROUND_UP(duty * pc->period, LGM_PWM_MAX_DUTY_CYCLE); + + return 0; } static const struct pwm_ops lgm_pwm_ops = { diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 54bd95a5cab0..4987ca940b64 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -47,8 +47,8 @@ static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm, int ret; if (!duty_scale) - return regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, - IQS620_PWR_SETTINGS_PWM_OUT, 0); + return regmap_clear_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, + IQS620_PWR_SETTINGS_PWM_OUT); ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, duty_scale - 1); @@ -104,8 +104,8 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct iqs620_pwm_private *iqs620_pwm; @@ -126,6 +126,8 @@ static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, mutex_unlock(&iqs620_pwm->lock); state->period = IQS620_PWM_PERIOD_NS; + + return 0; } static int iqs620_pwm_notifier(struct notifier_block *notifier, diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index a5fdf97c0d2e..3b7067f6cd0d 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -88,8 +88,7 @@ static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct jz4740_pwm_chip *jz = to_jz4740(chip); /* Enable PWM output */ - regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN); + regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); /* Start counter */ regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm)); @@ -113,8 +112,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the * counter is stopped, while in TCU1 mode the order does not matter. */ - regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_EN, 0); + regmap_clear_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_EN); /* Stop counter */ regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm)); @@ -184,8 +182,8 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period); /* Set abrupt shutdown */ - regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), - TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD); + regmap_set_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), + TCU_TCSR_PWM_SD); /* * Set polarity. @@ -248,19 +246,18 @@ static int jz4740_pwm_probe(struct platform_device *pdev) return devm_pwmchip_add(dev, &jz4740->chip); } -static const struct soc_info __maybe_unused jz4740_soc_info = { +static const struct soc_info jz4740_soc_info = { .num_pwms = 8, }; -static const struct soc_info __maybe_unused jz4725b_soc_info = { +static const struct soc_info jz4725b_soc_info = { .num_pwms = 6, }; -static const struct soc_info __maybe_unused x1000_soc_info = { +static const struct soc_info x1000_soc_info = { .num_pwms = 5, }; -#ifdef CONFIG_OF static const struct of_device_id jz4740_pwm_dt_ids[] = { { .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info }, @@ -268,12 +265,11 @@ static const struct of_device_id jz4740_pwm_dt_ids[] = { {}, }; MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); -#endif static struct platform_driver jz4740_pwm_driver = { .driver = { .name = "jz4740-pwm", - .of_match_table = of_match_ptr(jz4740_pwm_dt_ids), + .of_match_table = jz4740_pwm_dt_ids, }, .probe = jz4740_pwm_probe, }; diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c index 733811b05721..ac02d8bb4a0b 100644 --- a/drivers/pwm/pwm-keembay.c +++ b/drivers/pwm/pwm-keembay.c @@ -89,8 +89,8 @@ static void keembay_pwm_disable(struct keembay_pwm *priv, int ch) KMB_PWM_LEADIN_OFFSET(ch)); } -static void keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct keembay_pwm *priv = to_keembay_pwm_dev(chip); unsigned long long high, low; @@ -113,6 +113,8 @@ static void keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = DIV_ROUND_UP_ULL(high, clk_rate); state->period = DIV_ROUND_UP_ULL(high + low, clk_rate); state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static int keembay_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 763f2e3a146d..378e1df944dc 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -175,7 +175,7 @@ static void lpc18xx_pwm_config_duty(struct pwm_chip *chip, u32 val; /* - * With clk_rate < NSEC_PER_SEC this cannot overflow. + * With clk_rate <= NSEC_PER_SEC this cannot overflow. * With duty_ns <= period_ns < max_period_ns this also fits into an u32. */ val = mul_u64_u64_div_u64(duty_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC); diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index bb740346b699..23fe332b2394 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -205,8 +205,8 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pwm_lpss_chip *lpwm = to_lpwm(chip); unsigned long base_unit_range; @@ -236,6 +236,8 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->enabled = !!(ctrl & PWM_ENABLE); pm_runtime_put(chip->dev); + + return 0; } static const struct pwm_ops pwm_lpss_ops = { diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6901a44dc428..5b5eeaff35da 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -296,7 +296,7 @@ static const struct pwm_mediatek_of_data mt6795_pwm_data = { static const struct pwm_mediatek_of_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, - .has_ck_26m_sel = false, + .has_ck_26m_sel = true, }; static const struct pwm_mediatek_of_data mt7623_pwm_data = { @@ -329,6 +329,12 @@ static const struct pwm_mediatek_of_data mt8365_pwm_data = { .has_ck_26m_sel = true, }; +static const struct pwm_mediatek_of_data mt7986_pwm_data = { + .num_pwms = 2, + .pwm45_fixup = false, + .has_ck_26m_sel = true, +}; + static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, @@ -342,6 +348,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = { { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, + { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data }, { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data }, { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 57112f438c6d..16d79ca5d8f5 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -318,8 +318,8 @@ static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip, return cnt * fin_ns * (channel->pre_div + 1); } -static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct meson_pwm *meson = to_meson_pwm(chip); struct meson_pwm_channel_data *channel_data; @@ -327,7 +327,7 @@ static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, u32 value, tmp; if (!state) - return; + return 0; channel = &meson->channels[pwm->hwpwm]; channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; @@ -357,6 +357,8 @@ static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->period = 0; state->duty_cycle = 0; } + + return 0; } static const struct pwm_ops meson_pwm_ops = { diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index c605013e4114..692a06121b28 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -172,32 +172,33 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void mtk_disp_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int mtk_disp_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); u64 rate, period, high_width; - u32 clk_div, con0, con1; + u32 clk_div, pwm_en, con0, con1; int err; err = clk_prepare_enable(mdp->clk_main); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err)); - return; + return err; } err = clk_prepare_enable(mdp->clk_mm); if (err < 0) { dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err)); clk_disable_unprepare(mdp->clk_main); - return; + return err; } rate = clk_get_rate(mdp->clk_main); con0 = readl(mdp->base + mdp->data->con0); con1 = readl(mdp->base + mdp->data->con1); - state->enabled = !!(con0 & BIT(0)); + pwm_en = readl(mdp->base + DISP_PWM_EN); + state->enabled = !!(pwm_en & mdp->data->enable_mask); clk_div = FIELD_GET(PWM_CLKDIV_MASK, con0); period = FIELD_GET(PWM_PERIOD_MASK, con1); /* @@ -211,6 +212,8 @@ static void mtk_disp_pwm_get_state(struct pwm_chip *chip, state->polarity = PWM_POLARITY_NORMAL; clk_disable_unprepare(mdp->clk_mm); clk_disable_unprepare(mdp->clk_main); + + return 0; } static const struct pwm_ops mtk_disp_pwm_ops = { diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index f230c10d28bb..3ed5a48ca581 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -431,8 +431,8 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pca9685 *pca = to_pca(chip); unsigned long long duty; @@ -458,12 +458,14 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, */ state->duty_cycle = 0; state->enabled = false; - return; + return 0; } state->enabled = true; duty = pca9685_pwm_get_duty(pca, pwm->hwpwm); state->duty_cycle = DIV_ROUND_DOWN_ULL(duty * state->period, PCA9685_COUNTER_RANGE); + + return 0; } static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) @@ -513,8 +515,7 @@ static const struct regmap_config pca9685_regmap_i2c_config = { .cache_type = REGCACHE_NONE, }; -static int pca9685_pwm_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pca9685_pwm_probe(struct i2c_client *client) { struct pca9685 *pca; unsigned int reg; @@ -664,7 +665,7 @@ static struct i2c_driver pca9685_i2c_driver = { .of_match_table = of_match_ptr(pca9685_dt_ids), .pm = &pca9685_pwm_pm, }, - .probe = pca9685_pwm_probe, + .probe_new = pca9685_pwm_probe, .remove = pca9685_pwm_remove, .id_table = pca9685_id, }; diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 0bcaa58c6a91..46ed668bd141 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -6,6 +6,13 @@ * * 2008-02-13 initial version * eric miao <eric.miao@marvell.com> + * + * Links to reference manuals for some of the supported PWM chips can be found + * in Documentation/arm/marvell.rst. + * + * Limitations: + * - When PWM is stopped, the current PWM period stops abruptly at the next + * input clock (PWMCR_SD is set) and the output is driven to inactive. */ #include <linux/module.h> @@ -64,7 +71,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long long c; unsigned long period_cycles, prescale, pv, dc; unsigned long offset; - int rc; offset = pwm->hwpwm ? 0x10 : 0; @@ -86,56 +92,42 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, else dc = mul_u64_u64_div_u64(pv + 1, duty_ns, period_ns); - /* NOTE: the clock to PWM has to be enabled first - * before writing to the registers - */ - rc = clk_prepare_enable(pc->clk); - if (rc < 0) - return rc; - - writel(prescale, pc->mmio_base + offset + PWMCR); + writel(prescale | PWMCR_SD, pc->mmio_base + offset + PWMCR); writel(dc, pc->mmio_base + offset + PWMDCR); writel(pv, pc->mmio_base + offset + PWMPCR); - clk_disable_unprepare(pc->clk); return 0; } -static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - - return clk_prepare_enable(pc->clk); -} - -static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); - - clk_disable_unprepare(pc->clk); -} - static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { + struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); + u64 duty_cycle; int err; if (state->polarity != PWM_POLARITY_NORMAL) return -EINVAL; - if (!state->enabled) { - if (pwm->state.enabled) - pxa_pwm_disable(chip, pwm); + err = clk_prepare_enable(pc->clk); + if (err) + return err; - return 0; - } + duty_cycle = state->enabled ? state->duty_cycle : 0; - err = pxa_pwm_config(chip, pwm, state->duty_cycle, state->period); - if (err) + err = pxa_pwm_config(chip, pwm, duty_cycle, state->period); + if (err) { + clk_disable_unprepare(pc->clk); return err; + } + + if (state->enabled && !pwm->state.enabled) + return 0; + + clk_disable_unprepare(pc->clk); - if (!pwm->state.enabled) - return pxa_pwm_enable(chip, pwm); + if (!state->enabled && pwm->state.enabled) + clk_disable_unprepare(pc->clk); return 0; } diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c index 6ff73029f367..2939b71a7ba7 100644 --- a/drivers/pwm/pwm-raspberrypi-poe.c +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -82,9 +82,9 @@ static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, return 0; } -static void raspberrypi_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct raspberrypi_pwm *rpipwm = raspberrypi_pwm_from_chip(chip); @@ -93,6 +93,8 @@ static void raspberrypi_pwm_get_state(struct pwm_chip *chip, RPI_PWM_MAX_DUTY); state->enabled = !!(rpipwm->duty_cycle); state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index a5af859217c1..7f084eb34092 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -57,9 +57,9 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) return container_of(c, struct rockchip_pwm_chip, chip); } -static void rockchip_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int rockchip_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); u32 enable_conf = pc->data->enable_conf; @@ -70,11 +70,11 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, ret = clk_enable(pc->pclk); if (ret) - return; + return ret; ret = clk_enable(pc->clk); if (ret) - return; + return ret; clk_rate = clk_get_rate(pc->clk); @@ -96,6 +96,8 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, clk_disable(pc->clk); clk_disable(pc->pclk); + + return 0; } static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 2d4fa5e5fdd4..62b6acc6373d 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -105,8 +105,8 @@ static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, "New real_period = %u ns\n", ddata->real_period); } -static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); u32 duty, val; @@ -123,6 +123,8 @@ static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; state->polarity = PWM_POLARITY_INVERSED; + + return 0; } static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, @@ -204,8 +206,11 @@ static int pwm_sifive_clock_notifier(struct notifier_block *nb, struct pwm_sifive_ddata *ddata = container_of(nb, struct pwm_sifive_ddata, notifier); - if (event == POST_RATE_CHANGE) + if (event == POST_RATE_CHANGE) { + mutex_lock(&ddata->lock); pwm_sifive_update_clock(ddata, ndata->new_rate); + mutex_unlock(&ddata->lock); + } return NOTIFY_OK; } diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index 589aeaaa6ac8..e64900ad4ba1 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -87,9 +87,9 @@ struct sl28cpld_pwm { #define sl28cpld_pwm_from_chip(_chip) \ container_of(_chip, struct sl28cpld_pwm, pwm_chip) -static void sl28cpld_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int sl28cpld_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct sl28cpld_pwm *priv = sl28cpld_pwm_from_chip(chip); unsigned int reg; @@ -115,6 +115,8 @@ static void sl28cpld_pwm_get_state(struct pwm_chip *chip, * the PWM core. */ state->duty_cycle = min(state->duty_cycle, state->period); + + return 0; } static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 7004f55bbf11..d866ce345f97 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -65,8 +65,8 @@ static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid, writel_relaxed(val, spc->base + offset); } -static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct sprd_pwm_chip *spc = container_of(chip, struct sprd_pwm_chip, chip); @@ -83,7 +83,7 @@ static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) { dev_err(spc->dev, "failed to enable pwm%u clocks\n", pwm->hwpwm); - return; + return ret; } val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE); @@ -113,6 +113,8 @@ static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, /* Disable PWM clocks if the PWM channel is not in enable state. */ if (!state->enabled) clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks); + + return 0; } static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm, diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 3115abb3f52a..514ff58a4471 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -140,9 +140,8 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (reenable) { /* Start LP timer in continuous mode */ - ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CR, - STM32_LPTIM_CNTSTRT, - STM32_LPTIM_CNTSTRT); + ret = regmap_set_bits(priv->regmap, STM32_LPTIM_CR, + STM32_LPTIM_CNTSTRT); if (ret) { regmap_write(priv->regmap, STM32_LPTIM_CR, 0); goto err; @@ -157,9 +156,9 @@ err: return ret; } -static void stm32_pwm_lp_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int stm32_pwm_lp_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); unsigned long rate = clk_get_rate(priv->clk); @@ -185,6 +184,8 @@ static void stm32_pwm_lp_get_state(struct pwm_chip *chip, tmp = prd - val; tmp = (tmp << presc) * NSEC_PER_SEC; state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); + + return 0; } static const struct pwm_ops stm32_pwm_lp_ops = { diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 794ca5b02968..21e4a34dfff3 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -115,14 +115,14 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, int ret; /* Ensure registers have been updated, enable counter and capture */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); /* Use cc1 or cc3 DMA resp for PWM input channels 1 & 2 or 3 & 4 */ dma_id = pwm->hwpwm < 2 ? STM32_TIMERS_DMA_CH1 : STM32_TIMERS_DMA_CH3; ccen = pwm->hwpwm < 2 ? TIM_CCER_CC12E : TIM_CCER_CC34E; ccr = pwm->hwpwm < 2 ? TIM_CCR1 : TIM_CCR3; - regmap_update_bits(priv->regmap, TIM_CCER, ccen, ccen); + regmap_set_bits(priv->regmap, TIM_CCER, ccen); /* * Timer DMA burst mode. Request 2 registers, 2 bursts, to get both @@ -160,8 +160,8 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, } stop: - regmap_update_bits(priv->regmap, TIM_CCER, ccen, 0); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, ccen); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); return ret; } @@ -359,7 +359,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, regmap_write(priv->regmap, TIM_PSC, prescaler); regmap_write(priv->regmap, TIM_ARR, prd - 1); - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); /* Calculate the duty cycles */ dty = prd * duty_ns; @@ -377,7 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, else regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); - regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE); + regmap_set_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE); return 0; } @@ -411,13 +411,13 @@ static int stm32_pwm_enable(struct stm32_pwm *priv, int ch) if (priv->have_complementary_output) mask |= TIM_CCER_CC1NE << (ch * 4); - regmap_update_bits(priv->regmap, TIM_CCER, mask, mask); + regmap_set_bits(priv->regmap, TIM_CCER, mask); /* Make sure that registers are updated */ - regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); /* Enable controller */ - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); return 0; } @@ -431,11 +431,11 @@ static void stm32_pwm_disable(struct stm32_pwm *priv, int ch) if (priv->have_complementary_output) mask |= TIM_CCER_CC1NE << (ch * 4); - regmap_update_bits(priv->regmap, TIM_CCER, mask, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, mask); /* When all channels are disabled, we can disable the controller */ if (!active_channels(priv)) - regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); clk_disable(priv->clk); } @@ -568,10 +568,9 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv) * If complementary bit doesn't exist writing 1 will have no * effect so we can detect it. */ - regmap_update_bits(priv->regmap, - TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE); regmap_read(priv->regmap, TIM_CCER, &ccer); - regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE); priv->have_complementary_output = (ccer != 0); } @@ -585,10 +584,9 @@ static int stm32_pwm_detect_channels(struct stm32_pwm *priv) * If channels enable bits don't exist writing 1 will have no * effect so we can detect and count them. */ - regmap_update_bits(priv->regmap, - TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); regmap_read(priv->regmap, TIM_CCER, &ccer); - regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0); + regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); if (ccer & TIM_CCER_CC1E) npwm++; diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index c8445b0a3339..b973da73e9ab 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -108,9 +108,9 @@ static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip, writel(val, chip->base + offset); } -static void sun4i_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, - struct pwm_state *state) +static int sun4i_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); u64 clk_rate, tmp; @@ -118,6 +118,8 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, unsigned int prescaler; clk_rate = clk_get_rate(sun4i_pwm->clk); + if (!clk_rate) + return -EINVAL; val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); @@ -132,7 +134,7 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2); state->polarity = PWM_POLARITY_NORMAL; state->enabled = true; - return; + return 0; } if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && @@ -142,7 +144,7 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)]; if (prescaler == 0) - return; + return -EINVAL; if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm)) state->polarity = PWM_POLARITY_NORMAL; @@ -162,6 +164,8 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, tmp = (u64)prescaler * NSEC_PER_SEC * PWM_REG_PRD(val); state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate); + + return 0; } static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c index e776fd16512d..d6ebe9f03b35 100644 --- a/drivers/pwm/pwm-sunplus.c +++ b/drivers/pwm/pwm-sunplus.c @@ -124,8 +124,8 @@ static int sunplus_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct sunplus_pwm *priv = to_sunplus_pwm(chip); u32 mode0, dd_freq, duty; @@ -155,6 +155,8 @@ static void sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } state->polarity = PWM_POLARITY_NORMAL; + + return 0; } static const struct pwm_ops sunplus_pwm_ops = { diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index dad9978c9186..249dc0193297 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -145,8 +145,19 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * source clock rate as required_clk_rate, PWM controller will * be able to configure the requested period. */ - required_clk_rate = - (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH; + required_clk_rate = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC << PWM_DUTY_WIDTH, + period_ns); + + if (required_clk_rate > clk_round_rate(pc->clk, required_clk_rate)) + /* + * required_clk_rate is a lower bound for the input + * rate; for lower rates there is no value for PWM_SCALE + * that yields a period less than or equal to the + * requested period. Hence, for lower rates, double the + * required_clk_rate to get a clock rate that can meet + * the requested period. + */ + required_clk_rate *= 2; err = dev_pm_opp_set_rate(pc->dev, required_clk_rate); if (err < 0) diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c index 927c4cbb1daf..e3fb79b3e2a7 100644 --- a/drivers/pwm/pwm-visconti.c +++ b/drivers/pwm/pwm-visconti.c @@ -103,8 +103,8 @@ static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -static void visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct visconti_pwm_chip *priv = visconti_pwm_from_chip(chip); u32 period, duty, pwmc0, pwmc0_clk; @@ -122,6 +122,8 @@ static void visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm state->polarity = PWM_POLARITY_NORMAL; state->enabled = true; + + return 0; } static const struct pwm_ops visconti_pwm_ops = { diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c index 4dab2b86c427..f7a50fdcd9a5 100644 --- a/drivers/pwm/pwm-xilinx.c +++ b/drivers/pwm/pwm-xilinx.c @@ -169,9 +169,9 @@ static int xilinx_pwm_apply(struct pwm_chip *chip, struct pwm_device *unused, return 0; } -static void xilinx_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *unused, - struct pwm_state *state) +static int xilinx_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *unused, + struct pwm_state *state) { struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip); u32 tlr0, tlr1, tcsr0, tcsr1; @@ -191,6 +191,8 @@ static void xilinx_pwm_get_state(struct pwm_chip *chip, */ if (state->period == state->duty_cycle) state->duty_cycle = 0; + + return 0; } static const struct pwm_ops xilinx_pwm_ops = { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index bba492eea96c..161e91167b9c 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -276,8 +276,8 @@ struct pwm_ops { struct pwm_capture *result, unsigned long timeout); int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state); - void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state); + int (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state); struct module *owner; }; diff --git a/include/trace/events/pwm.h b/include/trace/events/pwm.h index cf243de41cc8..12b35e4ff917 100644 --- a/include/trace/events/pwm.h +++ b/include/trace/events/pwm.h @@ -10,9 +10,9 @@ DECLARE_EVENT_CLASS(pwm, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), - TP_ARGS(pwm, state), + TP_ARGS(pwm, state, err), TP_STRUCT__entry( __field(struct pwm_device *, pwm) @@ -20,6 +20,7 @@ DECLARE_EVENT_CLASS(pwm, __field(u64, duty_cycle) __field(enum pwm_polarity, polarity) __field(bool, enabled) + __field(int, err) ), TP_fast_assign( @@ -28,28 +29,27 @@ DECLARE_EVENT_CLASS(pwm, __entry->duty_cycle = state->duty_cycle; __entry->polarity = state->polarity; __entry->enabled = state->enabled; + __entry->err = err; ), - TP_printk("%p: period=%llu duty_cycle=%llu polarity=%d enabled=%d", + TP_printk("%p: period=%llu duty_cycle=%llu polarity=%d enabled=%d err=%d", __entry->pwm, __entry->period, __entry->duty_cycle, - __entry->polarity, __entry->enabled) + __entry->polarity, __entry->enabled, __entry->err) ); DEFINE_EVENT(pwm, pwm_apply, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), - - TP_ARGS(pwm, state) + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), + TP_ARGS(pwm, state, err) ); DEFINE_EVENT(pwm, pwm_get, - TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state), - - TP_ARGS(pwm, state) + TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state, int err), + TP_ARGS(pwm, state, err) ); #endif /* _TRACE_PWM_H */ |