diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-30 11:00:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-30 11:00:33 -0700 |
commit | 74164d284b2909de0ba13518cc063e9ea9334749 (patch) | |
tree | e96684ad26e842d05ee8975153ccccd31f1a7599 | |
parent | 4f3730117f162b17147795eaad44421cc65178c7 (diff) | |
parent | ed14d36498c8d15be098df4af9ca324f96e9de74 (diff) | |
download | linux-74164d284b2909de0ba13518cc063e9ea9334749.tar.bz2 |
Merge tag 'pwm/for-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding:
"This contains conversions of some more drivers to the atomic API as
well as the addition of new chip support for some existing drivers.
There are also various minor fixes and cleanups across the board, from
drivers to device tree bindings"
* tag 'pwm/for-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (45 commits)
pwm: rcar: Simplify multiplication/shift logic
dt-bindings: pwm: renesas,tpu: Do not require pwm-cells twice
dt-bindings: pwm: tiehrpwm: Do not require pwm-cells twice
dt-bindings: pwm: tiecap: Do not require pwm-cells twice
dt-bindings: pwm: samsung: Do not require pwm-cells twice
dt-bindings: pwm: intel,keembay: Do not require pwm-cells twice
dt-bindings: pwm: brcm,bcm7038: Do not require pwm-cells twice
dt-bindings: pwm: toshiba,visconti: Include generic PWM schema
dt-bindings: pwm: renesas,pwm: Include generic PWM schema
dt-bindings: pwm: sifive: Include generic PWM schema
dt-bindings: pwm: rockchip: Include generic PWM schema
dt-bindings: pwm: mxs: Include generic PWM schema
dt-bindings: pwm: iqs620a: Include generic PWM schema
dt-bindings: pwm: intel,lgm: Include generic PWM schema
dt-bindings: pwm: imx: Include generic PWM schema
dt-bindings: pwm: allwinner,sun4i-a10: Include generic PWM schema
pwm: pwm-mediatek: Beautify error messages text
pwm: pwm-mediatek: Allocate clk_pwms with devm_kmalloc_array
pwm: pwm-mediatek: Simplify error handling with dev_err_probe()
pwm: brcmstb: Remove useless locking
...
38 files changed, 492 insertions, 401 deletions
diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index d8b495f71282..afec0bd2f1de 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -85,6 +85,10 @@ properties: ec-pwm: $ref: "/schemas/pwm/google,cros-ec-pwm.yaml#" + deprecated: true + + pwm: + $ref: "/schemas/pwm/google,cros-ec-pwm.yaml#" keyboard-controller: $ref: "/schemas/input/google,cros-ec-keyb.yaml#" diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml index 800d511502c4..e93e935564fb 100644 --- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml @@ -52,33 +52,36 @@ properties: resets: maxItems: 1 -if: - properties: - compatible: - contains: - const: allwinner,sun50i-h6-pwm - -then: - properties: - clocks: - maxItems: 2 - - clock-names: - items: - - const: mod - - const: bus - - required: - - clock-names - - resets - -else: - properties: - clocks: - maxItems: 1 + +allOf: + - $ref: pwm.yaml# + + - if: + properties: + compatible: + contains: + const: allwinner,sun50i-h6-pwm + + then: + properties: + clocks: + maxItems: 2 + + clock-names: + items: + - const: mod + - const: bus + + required: + - clock-names + - resets + + else: + properties: + clocks: + maxItems: 1 required: - - "#pwm-cells" - compatible - reg - clocks diff --git a/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.yaml b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.yaml index 4080e098f746..119de3d7f9dd 100644 --- a/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.yaml @@ -28,7 +28,6 @@ properties: required: - compatible - reg - - "#pwm-cells" - clocks additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml index 4cfbffd8414a..7ab6912a845f 100644 --- a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml @@ -16,6 +16,9 @@ description: | An EC PWM node should be only found as a sub-node of the EC node (see Documentation/devicetree/bindings/mfd/google,cros-ec.yaml). +allOf: + - $ref: pwm.yaml# + properties: compatible: const: google,cros-ec-pwm @@ -39,7 +42,7 @@ examples: compatible = "google,cros-ec-spi"; reg = <0>; - cros_ec_pwm: ec-pwm { + cros_ec_pwm: pwm { compatible = "google,cros-ec-pwm"; #pwm-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.yaml b/Documentation/devicetree/bindings/pwm/imx-pwm.yaml index 379d693889f6..b3da4e629341 100644 --- a/Documentation/devicetree/bindings/pwm/imx-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/imx-pwm.yaml @@ -9,6 +9,9 @@ title: Freescale i.MX PWM controller maintainers: - Philipp Zabel <p.zabel@pengutronix.de> +allOf: + - $ref: pwm.yaml# + properties: "#pwm-cells": description: | @@ -59,7 +62,6 @@ properties: maxItems: 1 required: - - "#pwm-cells" - compatible - reg - clocks diff --git a/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.yaml b/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.yaml index fe9ef42544f1..8bef9dfeba9a 100644 --- a/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.yaml @@ -13,6 +13,9 @@ description: | The TPM counter and period counter are shared between multiple channels, so all channels should use same period setting. +allOf: + - $ref: pwm.yaml# + properties: "#pwm-cells": const: 3 @@ -34,7 +37,6 @@ properties: maxItems: 1 required: - - "#pwm-cells" - compatible - reg - clocks diff --git a/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml b/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml index ff6880a02ce6..ec9f6bab798c 100644 --- a/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml @@ -31,7 +31,6 @@ required: - compatible - reg - clocks - - '#pwm-cells' additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml b/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml index 11a606536169..59d7c4d864c1 100644 --- a/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml @@ -9,6 +9,9 @@ title: LGM SoC PWM fan controller maintainers: - Rahul Tanwar <rtanwar@maxlinear.com> +allOf: + - $ref: pwm.yaml# + properties: compatible: const: intel,lgm-pwm diff --git a/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml b/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml index 1d7c27be50da..0a46af240d83 100644 --- a/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml @@ -15,6 +15,9 @@ description: | Documentation/devicetree/bindings/mfd/iqs62x.yaml for further details as well as an example. +allOf: + - $ref: pwm.yaml# + properties: compatible: enum: @@ -25,7 +28,6 @@ properties: required: - compatible - - "#pwm-cells" additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml index 8740e076061e..a34cbc13f691 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml @@ -10,6 +10,9 @@ maintainers: - Shawn Guo <shawnguo@kernel.org> - Anson Huang <anson.huang@nxp.com> +allOf: + - $ref: pwm.yaml# + properties: compatible: enum: @@ -28,7 +31,6 @@ properties: required: - compatible - reg - - "#pwm-cells" - fsl,pwm-number additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt index 902b271891ae..691e58b6c223 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt @@ -6,6 +6,7 @@ Required properties: - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. - "mediatek,mt8167-disp-pwm", "mediatek,mt8173-disp-pwm": found on mt8167 SoC. - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. + - "mediatek,mt8183-disp-pwm": found on mt8183 SoC.$ - reg: physical base address and length of the controller's registers. - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of the cell format. diff --git a/Documentation/devicetree/bindings/pwm/pwm-rockchip.yaml b/Documentation/devicetree/bindings/pwm/pwm-rockchip.yaml index 81a54a4e8e3e..a336ff9364a9 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-rockchip.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-rockchip.yaml @@ -51,42 +51,44 @@ properties: required: - compatible - reg - - "#pwm-cells" - -if: - properties: - compatible: - contains: - enum: - - rockchip,rk3328-pwm - - rockchip,rv1108-pwm - -then: - properties: - clocks: - items: - - description: Used to derive the functional clock for the device. - - description: Used as the APB bus clock. - - clock-names: - items: - - const: pwm - - const: pclk - - required: - - clocks - - clock-names - -else: - properties: - clocks: - maxItems: 1 - description: - Used both to derive the functional clock - for the device and as the bus clock. - - required: - - clocks + +allOf: + - $ref: pwm.yaml# + + - if: + properties: + compatible: + contains: + enum: + - rockchip,rk3328-pwm + - rockchip,rv1108-pwm + + then: + properties: + clocks: + items: + - description: Used to derive the functional clock for the device. + - description: Used as the APB bus clock. + + clock-names: + items: + - const: pwm + - const: pclk + + required: + - clocks + - clock-names + + else: + properties: + clocks: + maxItems: 1 + description: + Used both to derive the functional clock + for the device and as the bus clock. + + required: + - clocks additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml index 188679cb8b8c..fe603fb1b2cc 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml @@ -86,7 +86,6 @@ required: - clocks - clock-names - compatible - - "#pwm-cells" - reg additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/pwm-sifive.yaml b/Documentation/devicetree/bindings/pwm/pwm-sifive.yaml index db41cd7bf150..605c1766dba8 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-sifive.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-sifive.yaml @@ -21,6 +21,9 @@ description: https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/pwm +allOf: + - $ref: pwm.yaml# + properties: compatible: items: @@ -54,7 +57,6 @@ required: - compatible - reg - clocks - - "#pwm-cells" - interrupts additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml b/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml index ed35b6cc48d5..3840ae709bc6 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml @@ -47,7 +47,6 @@ properties: required: - compatible - reg - - "#pwm-cells" - clocks - clock-names diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml index ee312cb210e6..70a8f766212e 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml @@ -48,7 +48,6 @@ properties: required: - compatible - reg - - "#pwm-cells" - clocks - clock-names diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml index 7ea1070b4b3a..1c94acbc2b4a 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml @@ -59,21 +59,23 @@ properties: required: - compatible - reg - - '#pwm-cells' - clocks - power-domains -if: - not: - properties: - compatible: - contains: - enum: - - renesas,pwm-r8a7778 - - renesas,pwm-r8a7779 -then: - required: - - resets +allOf: + - $ref: pwm.yaml# + + - if: + not: + properties: + compatible: + contains: + enum: + - renesas,pwm-r8a7778 + - renesas,pwm-r8a7779 + then: + required: + - resets additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml index 1f5c6384182e..c6b2ab56b7fe 100644 --- a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.yaml @@ -68,7 +68,6 @@ properties: required: - compatible - reg - - '#pwm-cells' - clocks - power-domains diff --git a/Documentation/devicetree/bindings/pwm/toshiba,pwm-visconti.yaml b/Documentation/devicetree/bindings/pwm/toshiba,pwm-visconti.yaml index d350f5edfb67..46622661e5fb 100644 --- a/Documentation/devicetree/bindings/pwm/toshiba,pwm-visconti.yaml +++ b/Documentation/devicetree/bindings/pwm/toshiba,pwm-visconti.yaml @@ -9,6 +9,9 @@ title: Toshiba Visconti PWM Controller maintainers: - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> +allOf: + - $ref: pwm.yaml# + properties: compatible: items: @@ -23,7 +26,6 @@ properties: required: - compatible - reg - - '#pwm-cells' additionalProperties: false diff --git a/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml b/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml index 7fb37eae9da7..d541cf2067bc 100644 --- a/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml +++ b/Documentation/devicetree/bindings/timer/ingenic,tcu.yaml @@ -152,6 +152,7 @@ patternProperties: - enum: - ingenic,jz4740-pwm - ingenic,jz4725b-pwm + - ingenic,x1000-pwm - items: - enum: - ingenic,jz4760-pwm diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 98b34ea9f38e..8e00a4286145 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -271,7 +271,7 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, bool disable_clk) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - unsigned long timeout = jiffies + 2 * HZ; + unsigned long timeout; atmel_pwm_wait_nonpending(atmel_pwm, pwm->hwpwm); diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 64148f5f81d0..f171169c1c1f 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -109,10 +109,10 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan) } static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + u64 duty_ns, u64 period_ns) { struct kona_pwmc *kp = to_kona_pwmc(chip); - u64 val, div, rate; + u64 div, rate; unsigned long prescale = PRESCALE_MIN, pc, dc; unsigned int value, chan = pwm->hwpwm; @@ -132,10 +132,8 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, while (1) { div = 1000000000; div *= 1 + prescale; - val = rate * period_ns; - pc = div64_u64(val, div); - val = rate * duty_ns; - dc = div64_u64(val, div); + pc = mul_u64_u64_div_u64(rate, period_ns, div); + dc = mul_u64_u64_div_u64(rate, duty_ns, div); /* If duty_ns or period_ns are not achievable then return */ if (pc < PERIOD_COUNT_MIN) @@ -150,25 +148,18 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; } - /* - * Don't apply settings if disabled. The period and duty cycle are - * always calculated above to ensure the new values are - * validated immediately instead of on enable. - */ - if (pwm_is_enabled(pwm)) { - kona_pwmc_prepare_for_settings(kp, chan); + kona_pwmc_prepare_for_settings(kp, chan); - value = readl(kp->base + PRESCALE_OFFSET); - value &= ~PRESCALE_MASK(chan); - value |= prescale << PRESCALE_SHIFT(chan); - writel(value, kp->base + PRESCALE_OFFSET); + value = readl(kp->base + PRESCALE_OFFSET); + value &= ~PRESCALE_MASK(chan); + value |= prescale << PRESCALE_SHIFT(chan); + writel(value, kp->base + PRESCALE_OFFSET); - writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); + writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); - writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); + writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); - kona_pwmc_apply_settings(kp, chan); - } + kona_pwmc_apply_settings(kp, chan); return 0; } @@ -216,13 +207,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm), - pwm_get_period(pwm)); - if (ret < 0) { - clk_disable_unprepare(kp->clk); - return ret; - } - return 0; } @@ -248,11 +232,53 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(kp->clk); } +static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + struct kona_pwmc *kp = to_kona_pwmc(chip); + bool enabled = pwm->state.enabled; + + if (state->polarity != pwm->state.polarity) { + if (enabled) { + kona_pwmc_disable(chip, pwm); + enabled = false; + } + + err = kona_pwmc_set_polarity(chip, pwm, state->polarity); + if (err) + return err; + + pwm->state.polarity = state->polarity; + } + + if (!state->enabled) { + if (enabled) + kona_pwmc_disable(chip, pwm); + return 0; + } else if (!enabled) { + /* + * This is a bit special here, usually the PWM should only be + * enabled when duty and period are setup. But before this + * driver was converted to .apply it was done the other way + * around and so this behaviour was kept even though this might + * result in a glitch. This might be improvable by someone with + * hardware and/or documentation. + */ + err = kona_pwmc_enable(chip, pwm); + if (err) + return err; + } + + err = kona_pwmc_config(pwm->chip, pwm, state->duty_cycle, state->period); + if (err && !pwm->state.enabled) + clk_disable_unprepare(kp->clk); + + return err; +} + static const struct pwm_ops kona_pwm_ops = { - .config = kona_pwmc_config, - .set_polarity = kona_pwmc_set_polarity, - .enable = kona_pwmc_enable, - .disable = kona_pwmc_disable, + .apply = kona_pwmc_apply, .owner = THIS_MODULE, }; diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 3b529f82b97c..3db3f96edf78 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -53,7 +53,6 @@ struct brcmstb_pwm { void __iomem *base; - spinlock_t lock; struct clk *clk; struct pwm_chip chip; }; @@ -95,7 +94,7 @@ static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip) * "on" time, so this translates directly into our HW programming here. */ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + u64 duty_ns, u64 period_ns) { struct brcmstb_pwm *p = to_brcmstb_pwm(chip); unsigned long pc, dc, cword = CONST_VAR_F_MAX; @@ -114,22 +113,17 @@ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, } while (1) { - u64 rate, tmp; + u64 rate; /* * Calculate the base rate from base frequency and current * cword */ rate = (u64)clk_get_rate(p->clk) * (u64)cword; - do_div(rate, 1 << CWORD_BIT_SIZE); + rate >>= CWORD_BIT_SIZE; - tmp = period_ns * rate; - do_div(tmp, NSEC_PER_SEC); - pc = tmp; - - tmp = (duty_ns + 1) * rate; - do_div(tmp, NSEC_PER_SEC); - dc = tmp; + pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC); + dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC); /* * We can be called with separate duty and period updates, @@ -164,7 +158,6 @@ done: * generator output a base frequency for the constant frequency * generator to derive from. */ - spin_lock(&p->lock); brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel)); brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel)); @@ -176,7 +169,6 @@ done: /* Configure on and period value */ brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel)); brcmstb_pwm_writel(p, dc, PWM_ON(channel)); - spin_unlock(&p->lock); return 0; } @@ -187,7 +179,6 @@ static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p, unsigned int shift = channel * CTRL_CHAN_OFFS; u32 value; - spin_lock(&p->lock); value = brcmstb_pwm_readl(p, PWM_CTRL); if (enable) { @@ -199,29 +190,36 @@ static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p, } brcmstb_pwm_writel(p, value, PWM_CTRL); - spin_unlock(&p->lock); } -static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int brcmstb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { struct brcmstb_pwm *p = to_brcmstb_pwm(chip); + int err; - brcmstb_pwm_enable_set(p, pwm->hwpwm, true); + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; - return 0; -} + if (!state->enabled) { + if (pwm->state.enabled) + brcmstb_pwm_enable_set(p, pwm->hwpwm, false); -static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct brcmstb_pwm *p = to_brcmstb_pwm(chip); + return 0; + } + + err = brcmstb_pwm_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + + if (!pwm->state.enabled) + brcmstb_pwm_enable_set(p, pwm->hwpwm, true); - brcmstb_pwm_enable_set(p, pwm->hwpwm, false); + return 0; } static const struct pwm_ops brcmstb_pwm_ops = { - .config = brcmstb_pwm_config, - .enable = brcmstb_pwm_enable, - .disable = brcmstb_pwm_disable, + .apply = brcmstb_pwm_apply, .owner = THIS_MODULE, }; @@ -240,8 +238,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) if (!p) return -ENOMEM; - spin_lock_init(&p->lock); - p->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(p->clk)) { dev_err(&pdev->dev, "failed to obtain clock\n"); diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 5996049f66ec..0fccf061ab95 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -77,16 +77,15 @@ static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct img_pwm_chip, chip); } -static inline void img_pwm_writel(struct img_pwm_chip *chip, +static inline void img_pwm_writel(struct img_pwm_chip *imgchip, u32 reg, u32 val) { - writel(val, chip->base + reg); + writel(val, imgchip->base + reg); } -static inline u32 img_pwm_readl(struct img_pwm_chip *chip, - u32 reg) +static inline u32 img_pwm_readl(struct img_pwm_chip *imgchip, u32 reg) { - return readl(chip->base + reg); + return readl(imgchip->base + reg); } static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, @@ -94,17 +93,17 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, { u32 val, div, duty, timebase; unsigned long mul, output_clk_hz, input_clk_hz; - struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); - unsigned int max_timebase = pwm_chip->data->max_timebase; + struct img_pwm_chip *imgchip = to_img_pwm_chip(chip); + unsigned int max_timebase = imgchip->data->max_timebase; int ret; - if (period_ns < pwm_chip->min_period_ns || - period_ns > pwm_chip->max_period_ns) { + if (period_ns < imgchip->min_period_ns || + period_ns > imgchip->max_period_ns) { dev_err(chip->dev, "configured period not in range\n"); return -ERANGE; } - input_clk_hz = clk_get_rate(pwm_chip->pwm_clk); + input_clk_hz = clk_get_rate(imgchip->pwm_clk); output_clk_hz = DIV_ROUND_UP(NSEC_PER_SEC, period_ns); mul = DIV_ROUND_UP(input_clk_hz, output_clk_hz); @@ -132,15 +131,15 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (ret < 0) return ret; - val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); + val = img_pwm_readl(imgchip, PWM_CTRL_CFG); val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm)); val |= (div & PWM_CTRL_CFG_DIV_MASK) << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm); - img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); + img_pwm_writel(imgchip, PWM_CTRL_CFG, val); val = (duty << PWM_CH_CFG_DUTY_SHIFT) | (timebase << PWM_CH_CFG_TMBASE_SHIFT); - img_pwm_writel(pwm_chip, PWM_CH_CFG(pwm->hwpwm), val); + img_pwm_writel(imgchip, PWM_CH_CFG(pwm->hwpwm), val); pm_runtime_mark_last_busy(chip->dev); pm_runtime_put_autosuspend(chip->dev); @@ -151,18 +150,18 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { u32 val; - struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); + struct img_pwm_chip *imgchip = to_img_pwm_chip(chip); int ret; ret = pm_runtime_resume_and_get(chip->dev); if (ret < 0) return ret; - val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); + val = img_pwm_readl(imgchip, PWM_CTRL_CFG); val |= BIT(pwm->hwpwm); - img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); + img_pwm_writel(imgchip, PWM_CTRL_CFG, val); - regmap_update_bits(pwm_chip->periph_regs, PERIP_PWM_PDM_CONTROL, + 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); @@ -172,11 +171,11 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { u32 val; - struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); + struct img_pwm_chip *imgchip = to_img_pwm_chip(chip); - val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); + val = img_pwm_readl(imgchip, PWM_CTRL_CFG); val &= ~BIT(pwm->hwpwm); - img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val); + img_pwm_writel(imgchip, PWM_CTRL_CFG, val); pm_runtime_mark_last_busy(chip->dev); pm_runtime_put_autosuspend(chip->dev); @@ -227,29 +226,29 @@ MODULE_DEVICE_TABLE(of, img_pwm_of_match); static int img_pwm_runtime_suspend(struct device *dev) { - struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); + struct img_pwm_chip *imgchip = dev_get_drvdata(dev); - clk_disable_unprepare(pwm_chip->pwm_clk); - clk_disable_unprepare(pwm_chip->sys_clk); + clk_disable_unprepare(imgchip->pwm_clk); + clk_disable_unprepare(imgchip->sys_clk); return 0; } static int img_pwm_runtime_resume(struct device *dev) { - struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); + struct img_pwm_chip *imgchip = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(pwm_chip->sys_clk); + ret = clk_prepare_enable(imgchip->sys_clk); if (ret < 0) { dev_err(dev, "could not prepare or enable sys clock\n"); return ret; } - ret = clk_prepare_enable(pwm_chip->pwm_clk); + ret = clk_prepare_enable(imgchip->pwm_clk); if (ret < 0) { dev_err(dev, "could not prepare or enable pwm clock\n"); - clk_disable_unprepare(pwm_chip->sys_clk); + clk_disable_unprepare(imgchip->sys_clk); return ret; } @@ -261,42 +260,42 @@ static int img_pwm_probe(struct platform_device *pdev) int ret; u64 val; unsigned long clk_rate; - struct img_pwm_chip *pwm; + struct img_pwm_chip *imgchip; const struct of_device_id *of_dev_id; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) + imgchip = devm_kzalloc(&pdev->dev, sizeof(*imgchip), GFP_KERNEL); + if (!imgchip) return -ENOMEM; - pwm->dev = &pdev->dev; + imgchip->dev = &pdev->dev; - pwm->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(pwm->base)) - return PTR_ERR(pwm->base); + imgchip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(imgchip->base)) + return PTR_ERR(imgchip->base); of_dev_id = of_match_device(img_pwm_of_match, &pdev->dev); if (!of_dev_id) return -ENODEV; - pwm->data = of_dev_id->data; + imgchip->data = of_dev_id->data; - pwm->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "img,cr-periph"); - if (IS_ERR(pwm->periph_regs)) - return PTR_ERR(pwm->periph_regs); + imgchip->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "img,cr-periph"); + if (IS_ERR(imgchip->periph_regs)) + return PTR_ERR(imgchip->periph_regs); - pwm->sys_clk = devm_clk_get(&pdev->dev, "sys"); - if (IS_ERR(pwm->sys_clk)) { + imgchip->sys_clk = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(imgchip->sys_clk)) { dev_err(&pdev->dev, "failed to get system clock\n"); - return PTR_ERR(pwm->sys_clk); + return PTR_ERR(imgchip->sys_clk); } - pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm"); - if (IS_ERR(pwm->pwm_clk)) { - dev_err(&pdev->dev, "failed to get pwm clock\n"); - return PTR_ERR(pwm->pwm_clk); + imgchip->pwm_clk = devm_clk_get(&pdev->dev, "imgchip"); + if (IS_ERR(imgchip->pwm_clk)) { + dev_err(&pdev->dev, "failed to get imgchip clock\n"); + return PTR_ERR(imgchip->pwm_clk); } - platform_set_drvdata(pdev, pwm); + platform_set_drvdata(pdev, imgchip); pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); @@ -307,27 +306,27 @@ static int img_pwm_probe(struct platform_device *pdev) goto err_pm_disable; } - clk_rate = clk_get_rate(pwm->pwm_clk); + clk_rate = clk_get_rate(imgchip->pwm_clk); if (!clk_rate) { - dev_err(&pdev->dev, "pwm clock has no frequency\n"); + dev_err(&pdev->dev, "imgchip clock has no frequency\n"); ret = -EINVAL; goto err_suspend; } /* The maximum input clock divider is 512 */ - val = (u64)NSEC_PER_SEC * 512 * pwm->data->max_timebase; + val = (u64)NSEC_PER_SEC * 512 * imgchip->data->max_timebase; do_div(val, clk_rate); - pwm->max_period_ns = val; + imgchip->max_period_ns = val; val = (u64)NSEC_PER_SEC * MIN_TMBASE_STEPS; do_div(val, clk_rate); - pwm->min_period_ns = val; + imgchip->min_period_ns = val; - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &img_pwm_ops; - pwm->chip.npwm = IMG_PWM_NPWM; + imgchip->chip.dev = &pdev->dev; + imgchip->chip.ops = &img_pwm_ops; + imgchip->chip.npwm = IMG_PWM_NPWM; - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&imgchip->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); goto err_suspend; @@ -346,13 +345,13 @@ err_pm_disable: static int img_pwm_remove(struct platform_device *pdev) { - struct img_pwm_chip *pwm_chip = platform_get_drvdata(pdev); + struct img_pwm_chip *imgchip = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) img_pwm_runtime_suspend(&pdev->dev); - pwmchip_remove(&pwm_chip->chip); + pwmchip_remove(&imgchip->chip); return 0; } @@ -360,7 +359,7 @@ static int img_pwm_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int img_pwm_suspend(struct device *dev) { - struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); + struct img_pwm_chip *imgchip = dev_get_drvdata(dev); int i, ret; if (pm_runtime_status_suspended(dev)) { @@ -369,11 +368,11 @@ static int img_pwm_suspend(struct device *dev) return ret; } - for (i = 0; i < pwm_chip->chip.npwm; i++) - pwm_chip->suspend_ch_cfg[i] = img_pwm_readl(pwm_chip, - PWM_CH_CFG(i)); + for (i = 0; i < imgchip->chip.npwm; i++) + imgchip->suspend_ch_cfg[i] = img_pwm_readl(imgchip, + PWM_CH_CFG(i)); - pwm_chip->suspend_ctrl_cfg = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); + imgchip->suspend_ctrl_cfg = img_pwm_readl(imgchip, PWM_CTRL_CFG); img_pwm_runtime_suspend(dev); @@ -382,7 +381,7 @@ static int img_pwm_suspend(struct device *dev) static int img_pwm_resume(struct device *dev) { - struct img_pwm_chip *pwm_chip = dev_get_drvdata(dev); + struct img_pwm_chip *imgchip = dev_get_drvdata(dev); int ret; int i; @@ -390,15 +389,15 @@ static int img_pwm_resume(struct device *dev) if (ret) return ret; - for (i = 0; i < pwm_chip->chip.npwm; i++) - img_pwm_writel(pwm_chip, PWM_CH_CFG(i), - pwm_chip->suspend_ch_cfg[i]); + for (i = 0; i < imgchip->chip.npwm; i++) + img_pwm_writel(imgchip, PWM_CH_CFG(i), + imgchip->suspend_ch_cfg[i]); - img_pwm_writel(pwm_chip, PWM_CTRL_CFG, pwm_chip->suspend_ctrl_cfg); + img_pwm_writel(imgchip, PWM_CTRL_CFG, imgchip->suspend_ctrl_cfg); - for (i = 0; i < pwm_chip->chip.npwm; i++) - if (pwm_chip->suspend_ctrl_cfg & BIT(i)) - regmap_update_bits(pwm_chip->periph_regs, + 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), diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index bcd849496f8d..1f2eb1c8ff6c 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -61,7 +61,7 @@ static void pwm_imx1_clk_disable_unprepare(struct pwm_chip *chip) } static int pwm_imx1_config(struct pwm_chip *chip, - struct pwm_device *pwm, int duty_ns, int period_ns) + struct pwm_device *pwm, u64 duty_ns, u64 period_ns) { struct pwm_imx1_chip *imx = to_pwm_imx1_chip(chip); u32 max, p; @@ -84,7 +84,7 @@ static int pwm_imx1_config(struct pwm_chip *chip, * (/2 .. /16). */ max = readl(imx->mmio_base + MX1_PWMP); - p = max * duty_ns / period_ns; + p = mul_u64_u64_div_u64(max, duty_ns, period_ns); writel(max - p, imx->mmio_base + MX1_PWMS); @@ -120,10 +120,33 @@ static void pwm_imx1_disable(struct pwm_chip *chip, struct pwm_device *pwm) pwm_imx1_clk_disable_unprepare(chip); } +static int pwm_imx1_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) { + if (pwm->state.enabled) + pwm_imx1_disable(chip, pwm); + + return 0; + } + + err = pwm_imx1_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + + if (!pwm->state.enabled) + return pwm_imx1_enable(chip, pwm); + + return 0; +} + static const struct pwm_ops pwm_imx1_ops = { - .enable = pwm_imx1_enable, - .disable = pwm_imx1_disable, - .config = pwm_imx1_config, + .apply = pwm_imx1_apply, .owner = THIS_MODULE, }; diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 23dc1fb770e2..a5fdf97c0d2e 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -256,10 +256,15 @@ static const struct soc_info __maybe_unused jz4725b_soc_info = { .num_pwms = 6, }; +static const struct soc_info __maybe_unused 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 }, + { .compatible = "ingenic,x1000-pwm", .data = &x1000_soc_info }, {}, }; MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 8e461f3baa05..b909096dba2f 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -76,6 +76,8 @@ #define LPC18XX_PWM_EVENT_PERIOD 0 #define LPC18XX_PWM_EVENT_MAX 16 +#define LPC18XX_NUM_PWMS 16 + /* SCT conflict resolution */ enum lpc18xx_pwm_res_action { LPC18XX_PWM_RES_NONE, @@ -101,6 +103,7 @@ struct lpc18xx_pwm_chip { unsigned long event_map; struct mutex res_lock; struct mutex period_lock; + struct lpc18xx_pwm_data channeldata[LPC18XX_NUM_PWMS]; }; static inline struct lpc18xx_pwm_chip * @@ -163,7 +166,7 @@ static void lpc18xx_pwm_config_duty(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns) { struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); - struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; u64 val; val = (u64)duty_ns * lpc18xx_pwm->clk_rate; @@ -233,7 +236,7 @@ static int lpc18xx_pwm_set_polarity(struct pwm_chip *chip, static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); - struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; enum lpc18xx_pwm_res_action res_action; unsigned int set_event, clear_event; @@ -268,7 +271,7 @@ static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); - struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0); @@ -279,7 +282,7 @@ static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); - struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; unsigned long event; event = find_first_zero_bit(&lpc18xx_pwm->event_map, @@ -300,7 +303,7 @@ static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); - struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm]; clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map); } @@ -324,8 +327,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match); static int lpc18xx_pwm_probe(struct platform_device *pdev) { struct lpc18xx_pwm_chip *lpc18xx_pwm; - struct pwm_device *pwm; - int ret, i; + int ret; u64 val; lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm), @@ -370,7 +372,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm->chip.dev = &pdev->dev; lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops; - lpc18xx_pwm->chip.npwm = 16; + lpc18xx_pwm->chip.npwm = LPC18XX_NUM_PWMS; /* SCT counter must be in unify (32 bit) mode */ lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG, @@ -395,40 +397,23 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT, BIT(lpc18xx_pwm->period_event)); + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); + val &= ~LPC18XX_PWM_BIDIR; + val &= ~LPC18XX_PWM_CTRL_HALT; + val &= ~LPC18XX_PWM_PRE_MASK; + 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; } - for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { - struct lpc18xx_pwm_data *data; - - pwm = &lpc18xx_pwm->chip.pwms[i]; - - data = devm_kzalloc(lpc18xx_pwm->dev, sizeof(*data), - GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto remove_pwmchip; - } - - 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; - val &= ~LPC18XX_PWM_PRE_MASK; - val |= LPC18XX_PWM_PRE(0); - lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); - return 0; -remove_pwmchip: - pwmchip_remove(&lpc18xx_pwm->chip); disable_pwmclk: clk_disable_unprepare(lpc18xx_pwm->pwm_clk); return ret; diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 0d4dd80e9f07..568b13a48717 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -146,7 +146,7 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, if (clkdiv > PWM_CLK_DIV_MAX) { pwm_mediatek_clk_disable(chip, pwm); - dev_err(chip->dev, "period %d not supported\n", period_ns); + dev_err(chip->dev, "period of %d ns not supported\n", period_ns); return -EINVAL; } @@ -221,24 +221,20 @@ static int pwm_mediatek_probe(struct platform_device *pdev) if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - pc->clk_pwms = devm_kcalloc(&pdev->dev, pc->soc->num_pwms, + pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms, sizeof(*pc->clk_pwms), GFP_KERNEL); if (!pc->clk_pwms) return -ENOMEM; pc->clk_top = devm_clk_get(&pdev->dev, "top"); - if (IS_ERR(pc->clk_top)) { - dev_err(&pdev->dev, "clock: top fail: %ld\n", - PTR_ERR(pc->clk_top)); - return PTR_ERR(pc->clk_top); - } + if (IS_ERR(pc->clk_top)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_top), + "Failed to get top clock\n"); pc->clk_main = devm_clk_get(&pdev->dev, "main"); - if (IS_ERR(pc->clk_main)) { - dev_err(&pdev->dev, "clock: main fail: %ld\n", - PTR_ERR(pc->clk_main)); - return PTR_ERR(pc->clk_main); - } + if (IS_ERR(pc->clk_main)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main), + "Failed to get main clock\n"); for (i = 0; i < pc->soc->num_pwms; i++) { char name[8]; @@ -246,11 +242,9 @@ static int pwm_mediatek_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "pwm%d", i + 1); pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); - if (IS_ERR(pc->clk_pwms[i])) { - dev_err(&pdev->dev, "clock: %s fail: %ld\n", - name, PTR_ERR(pc->clk_pwms[i])); - return PTR_ERR(pc->clk_pwms[i]); - } + if (IS_ERR(pc->clk_pwms[i])) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]), + "Failed to get %s clock\n", name); } pc->chip.dev = &pdev->dev; @@ -258,10 +252,8 @@ static int pwm_mediatek_probe(struct platform_device *pdev) pc->chip.npwm = pc->soc->num_pwms; ret = devm_pwmchip_add(&pdev->dev, &pc->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); return 0; } diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 3cf3bcf5ddfc..57112f438c6d 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -120,16 +120,10 @@ static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip) static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct meson_pwm *meson = to_meson_pwm(chip); - struct meson_pwm_channel *channel; + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; struct device *dev = chip->dev; int err; - channel = pwm_get_chip_data(pwm); - if (channel) - return 0; - - channel = &meson->channels[pwm->hwpwm]; - if (channel->clk_parent) { err = clk_set_parent(channel->clk, channel->clk_parent); if (err < 0) { @@ -147,21 +141,21 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) return err; } - return pwm_set_chip_data(pwm, channel); + return 0; } static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm *meson = to_meson_pwm(chip); + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; - if (channel) - clk_disable_unprepare(channel->clk); + clk_disable_unprepare(channel->clk); } static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, const struct pwm_state *state) { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; unsigned int duty, period, pre_div, cnt, duty_cnt; unsigned long fin_freq; @@ -224,7 +218,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm) { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; struct meson_pwm_channel_data *channel_data; unsigned long flags; u32 value; @@ -267,13 +261,10 @@ static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm) static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); struct meson_pwm *meson = to_meson_pwm(chip); + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; int err = 0; - if (!state) - return -EINVAL; - if (!state->enabled) { if (state->polarity == PWM_POLARITY_INVERSED) { /* diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index c56001a790d0..c91fa7f9e33d 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -560,10 +560,10 @@ static int pca9685_pwm_probe(struct i2c_client *client, pca9685_write_reg(pca, PCA9685_MODE1, reg); /* Reset OFF/ON registers to POR default */ - pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, LED_FULL); + pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, 0); pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_H, LED_FULL); pca9685_write_reg(pca, PCA9685_ALL_LED_ON_L, 0); - pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, 0); + pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, LED_FULL); pca->chip.ops = &pca9685_pwm_ops; /* Add an extra channel for ALL_LED */ diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 238ec88c130b..0bcaa58c6a91 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -58,7 +58,7 @@ static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip) * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE */ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + u64 duty_ns, u64 period_ns) { struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); unsigned long long c; @@ -84,7 +84,7 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (duty_ns == period_ns) dc = PWMDCR_FD; else - dc = (pv + 1) * duty_ns / period_ns; + 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 @@ -115,10 +115,33 @@ static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(pc->clk); } +static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) { + if (pwm->state.enabled) + pxa_pwm_disable(chip, pwm); + + return 0; + } + + err = pxa_pwm_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + + if (!pwm->state.enabled) + return pxa_pwm_enable(chip, pwm); + + return 0; +} + static const struct pwm_ops pxa_pwm_ops = { - .config = pxa_pwm_config, - .enable = pxa_pwm_enable, - .disable = pxa_pwm_disable, + .apply = pxa_pwm_apply, .owner = THIS_MODULE, }; diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c index 579a15240e0a..e52e29fc8231 100644 --- a/drivers/pwm/pwm-raspberrypi-poe.c +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -163,7 +163,6 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev) rpipwm->firmware = firmware; rpipwm->chip.dev = dev; rpipwm->chip.ops = &raspberrypi_pwm_ops; - rpipwm->chip.base = -1; rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index b437192380e2..55f46d09602b 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -110,7 +110,7 @@ static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns, unsigned long clk_rate = clk_get_rate(rp->clk); u32 cyc, ph; - one_cycle = (unsigned long long)NSEC_PER_SEC * 100ULL * (1 << div); + one_cycle = NSEC_PER_SEC * 100ULL << div; do_div(one_cycle, clk_rate); tmp = period_ns * 100ULL; diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c index 9dc983a3cbf1..c4336d3bace3 100644 --- a/drivers/pwm/pwm-stmpe.c +++ b/drivers/pwm/pwm-stmpe.c @@ -269,19 +269,19 @@ static const struct pwm_ops stmpe_24xx_pwm_ops = { static int __init stmpe_pwm_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - struct stmpe_pwm *pwm; + struct stmpe_pwm *stmpe_pwm; int ret; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) + stmpe_pwm = devm_kzalloc(&pdev->dev, sizeof(*stmpe_pwm), GFP_KERNEL); + if (!stmpe_pwm) return -ENOMEM; - pwm->stmpe = stmpe; - pwm->chip.dev = &pdev->dev; + stmpe_pwm->stmpe = stmpe; + stmpe_pwm->chip.dev = &pdev->dev; if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) { - pwm->chip.ops = &stmpe_24xx_pwm_ops; - pwm->chip.npwm = 3; + stmpe_pwm->chip.ops = &stmpe_24xx_pwm_ops; + stmpe_pwm->chip.npwm = 3; } else { if (stmpe->partnum == STMPE1601) dev_err(&pdev->dev, "STMPE1601 not yet supported\n"); @@ -295,14 +295,12 @@ static int __init stmpe_pwm_probe(struct platform_device *pdev) if (ret) return ret; - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&stmpe_pwm->chip); if (ret) { stmpe_disable(stmpe, STMPE_BLOCK_PWM); return ret; } - platform_set_drvdata(pdev, pwm); - return 0; } diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 91ca67651abd..16d75f9aa36a 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -390,20 +390,20 @@ MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids); static int sun4i_pwm_probe(struct platform_device *pdev) { - struct sun4i_pwm_chip *pwm; + struct sun4i_pwm_chip *sun4ichip; int ret; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) + sun4ichip = devm_kzalloc(&pdev->dev, sizeof(*sun4ichip), GFP_KERNEL); + if (!sun4ichip) return -ENOMEM; - pwm->data = of_device_get_match_data(&pdev->dev); - if (!pwm->data) + sun4ichip->data = of_device_get_match_data(&pdev->dev); + if (!sun4ichip->data) return -ENODEV; - pwm->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(pwm->base)) - return PTR_ERR(pwm->base); + sun4ichip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sun4ichip->base)) + return PTR_ERR(sun4ichip->base); /* * All hardware variants need a source clock that is divided and @@ -416,30 +416,30 @@ static int sun4i_pwm_probe(struct platform_device *pdev) * 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)) - return dev_err_probe(&pdev->dev, PTR_ERR(pwm->clk), + sun4ichip->clk = devm_clk_get_optional(&pdev->dev, "mod"); + if (IS_ERR(sun4ichip->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sun4ichip->clk), "get mod clock failed\n"); - if (!pwm->clk) { - pwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(pwm->clk), + if (!sun4ichip->clk) { + sun4ichip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sun4ichip->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sun4ichip->clk), "get unnamed clock failed\n"); } - pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); - if (IS_ERR(pwm->bus_clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(pwm->bus_clk), + sun4ichip->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); + if (IS_ERR(sun4ichip->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sun4ichip->bus_clk), "get bus clock failed\n"); - pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); - if (IS_ERR(pwm->rst)) - return dev_err_probe(&pdev->dev, PTR_ERR(pwm->rst), + sun4ichip->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(sun4ichip->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(sun4ichip->rst), "get reset failed\n"); /* Deassert reset */ - ret = reset_control_deassert(pwm->rst); + ret = reset_control_deassert(sun4ichip->rst); if (ret) { dev_err(&pdev->dev, "cannot deassert reset control: %pe\n", ERR_PTR(ret)); @@ -450,45 +450,45 @@ static int sun4i_pwm_probe(struct platform_device *pdev) * 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); + ret = clk_prepare_enable(sun4ichip->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; - pwm->chip.npwm = pwm->data->npwm; + sun4ichip->chip.dev = &pdev->dev; + sun4ichip->chip.ops = &sun4i_pwm_ops; + sun4ichip->chip.npwm = sun4ichip->data->npwm; - spin_lock_init(&pwm->ctrl_lock); + spin_lock_init(&sun4ichip->ctrl_lock); - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&sun4ichip->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); goto err_pwm_add; } - platform_set_drvdata(pdev, pwm); + platform_set_drvdata(pdev, sun4ichip); return 0; err_pwm_add: - clk_disable_unprepare(pwm->bus_clk); + clk_disable_unprepare(sun4ichip->bus_clk); err_bus: - reset_control_assert(pwm->rst); + reset_control_assert(sun4ichip->rst); return ret; } static int sun4i_pwm_remove(struct platform_device *pdev) { - struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev); + struct sun4i_pwm_chip *sun4ichip = platform_get_drvdata(pdev); - pwmchip_remove(&pwm->chip); + pwmchip_remove(&sun4ichip->chip); - clk_disable_unprepare(pwm->bus_clk); - reset_control_assert(pwm->rst); + clk_disable_unprepare(sun4ichip->bus_clk); + reset_control_assert(sun4ichip->rst); return 0; } diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 18cf974ac776..e5a9ffef4a71 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -85,15 +85,14 @@ static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct tegra_pwm_chip, chip); } -static inline u32 pwm_readl(struct tegra_pwm_chip *chip, unsigned int num) +static inline u32 pwm_readl(struct tegra_pwm_chip *pc, unsigned int offset) { - return readl(chip->regs + (num << 4)); + return readl(pc->regs + (offset << 4)); } -static inline void pwm_writel(struct tegra_pwm_chip *chip, unsigned int num, - unsigned long val) +static inline void pwm_writel(struct tegra_pwm_chip *pc, unsigned int offset, u32 value) { - writel(val, chip->regs + (num << 4)); + writel(value, pc->regs + (offset << 4)); } static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, @@ -240,25 +239,25 @@ static const struct pwm_ops tegra_pwm_ops = { static int tegra_pwm_probe(struct platform_device *pdev) { - struct tegra_pwm_chip *pwm; + struct tegra_pwm_chip *pc; int ret; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (!pc) return -ENOMEM; - pwm->soc = of_device_get_match_data(&pdev->dev); - pwm->dev = &pdev->dev; + pc->soc = of_device_get_match_data(&pdev->dev); + pc->dev = &pdev->dev; - pwm->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(pwm->regs)) - return PTR_ERR(pwm->regs); + pc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pc->regs)) + return PTR_ERR(pc->regs); - platform_set_drvdata(pdev, pwm); + platform_set_drvdata(pdev, pc); - pwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); + pc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pc->clk)) + return PTR_ERR(pc->clk); ret = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (ret) @@ -270,7 +269,7 @@ static int tegra_pwm_probe(struct platform_device *pdev) return ret; /* Set maximum frequency of the IP */ - ret = dev_pm_opp_set_rate(pwm->dev, pwm->soc->max_frequency); + ret = dev_pm_opp_set_rate(pc->dev, pc->soc->max_frequency); if (ret < 0) { dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret); goto put_pm; @@ -281,29 +280,29 @@ static int tegra_pwm_probe(struct platform_device *pdev) * clock register resolutions. Get the configured frequency * so that PWM period can be calculated more accurately. */ - pwm->clk_rate = clk_get_rate(pwm->clk); + pc->clk_rate = clk_get_rate(pc->clk); /* Set minimum limit of PWM period for the IP */ - pwm->min_period_ns = - (NSEC_PER_SEC / (pwm->soc->max_frequency >> PWM_DUTY_WIDTH)) + 1; + pc->min_period_ns = + (NSEC_PER_SEC / (pc->soc->max_frequency >> PWM_DUTY_WIDTH)) + 1; - pwm->rst = devm_reset_control_get_exclusive(&pdev->dev, "pwm"); - if (IS_ERR(pwm->rst)) { - ret = PTR_ERR(pwm->rst); + pc->rst = devm_reset_control_get_exclusive(&pdev->dev, "pwm"); + if (IS_ERR(pc->rst)) { + ret = PTR_ERR(pc->rst); dev_err(&pdev->dev, "Reset control is not found: %d\n", ret); goto put_pm; } - reset_control_deassert(pwm->rst); + reset_control_deassert(pc->rst); - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &tegra_pwm_ops; - pwm->chip.npwm = pwm->soc->num_channels; + pc->chip.dev = &pdev->dev; + pc->chip.ops = &tegra_pwm_ops; + pc->chip.npwm = pc->soc->num_channels; - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&pc->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - reset_control_assert(pwm->rst); + reset_control_assert(pc->rst); goto put_pm; } diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 5b723a48c5f1..48ca0ff690ae 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -216,7 +216,7 @@ static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan) * duty_ns = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE */ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + u64 duty_ns, u64 period_ns) { struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); u32 period_cycles, duty_cycles; @@ -401,12 +401,42 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) pc->period_cycles[pwm->hwpwm] = 0; } +static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + bool enabled = pwm->state.enabled; + + if (state->polarity != pwm->state.polarity) { + if (enabled) { + ehrpwm_pwm_disable(chip, pwm); + enabled = false; + } + + err = ehrpwm_pwm_set_polarity(chip, pwm, state->polarity); + if (err) + return err; + } + + if (!state->enabled) { + if (enabled) + ehrpwm_pwm_disable(chip, pwm); + return 0; + } + + err = ehrpwm_pwm_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + + if (!enabled) + err = ehrpwm_pwm_enable(chip, pwm); + + return err; +} + static const struct pwm_ops ehrpwm_pwm_ops = { .free = ehrpwm_pwm_free, - .config = ehrpwm_pwm_config, - .set_polarity = ehrpwm_pwm_set_polarity, - .enable = ehrpwm_pwm_enable, - .disable = ehrpwm_pwm_disable, + .apply = ehrpwm_pwm_apply, .owner = THIS_MODULE, }; diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 7170a315535b..f1ff9940b37c 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -235,7 +235,7 @@ MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids); static int vt8500_pwm_probe(struct platform_device *pdev) { - struct vt8500_chip *chip; + struct vt8500_chip *vt8500; struct device_node *np = pdev->dev.of_node; int ret; @@ -244,48 +244,48 @@ static int vt8500_pwm_probe(struct platform_device *pdev) return -EINVAL; } - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL); + if (vt8500 == NULL) return -ENOMEM; - chip->chip.dev = &pdev->dev; - chip->chip.ops = &vt8500_pwm_ops; - chip->chip.npwm = VT8500_NR_PWMS; + vt8500->chip.dev = &pdev->dev; + vt8500->chip.ops = &vt8500_pwm_ops; + vt8500->chip.npwm = VT8500_NR_PWMS; - chip->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(chip->clk)) { + vt8500->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(vt8500->clk)) { dev_err(&pdev->dev, "clock source not specified\n"); - return PTR_ERR(chip->clk); + return PTR_ERR(vt8500->clk); } - chip->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(chip->base)) - return PTR_ERR(chip->base); + vt8500->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(vt8500->base)) + return PTR_ERR(vt8500->base); - ret = clk_prepare(chip->clk); + ret = clk_prepare(vt8500->clk); if (ret < 0) { dev_err(&pdev->dev, "failed to prepare clock\n"); return ret; } - ret = pwmchip_add(&chip->chip); + ret = pwmchip_add(&vt8500->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip\n"); - clk_unprepare(chip->clk); + clk_unprepare(vt8500->clk); return ret; } - platform_set_drvdata(pdev, chip); + platform_set_drvdata(pdev, vt8500); return ret; } static int vt8500_pwm_remove(struct platform_device *pdev) { - struct vt8500_chip *chip = platform_get_drvdata(pdev); + struct vt8500_chip *vt8500 = platform_get_drvdata(pdev); - pwmchip_remove(&chip->chip); + pwmchip_remove(&vt8500->chip); - clk_unprepare(chip->clk); + clk_unprepare(vt8500->clk); return 0; } |