pwm: Changes for v5.18-rc1

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmJESlMZHHRoaWVycnku
 cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zoWlXD/4o913wJIR1GPTQBD9ps3bd
 CrWlbg4v7OL1tsikMweJBj63+cq8ucBhXe6PBbiM3NEo/ztwo1Km5nTs0Fv+a+9L
 q3CzJn/RxgGeq/bA8ejG1LswOooNQXUKx3klEEYQyy1TGhea4/TucTRAjF3890Sj
 SyiyDtAs+n2OyFflnAdz43PeYLpX6n4jibXURD2UTHda8bi4U/1SCLFt4w50lVnI
 FHtY/aP7PhvmZ5AJRAAbhYwo/YkTbavX01GPXiVkKQaUyHz+iA5VWdvIgwfo/uKP
 UM9YiPgZxa2J+qOYfGf+B++90Bzen54cNFTaAWrXkIQqq1oQvu8IKl3bkWBlLYGI
 lT56RtpB4sO63CJKj979GOfTtP/8Byann+KLMPL+N9LaFLUrmvsbSJ+tuz6ZcI1v
 s8qPZZg/qsnjPBVAmDQPezxmWjPwGVRUrUAgHoKc5ymrA/k2Gs9eD5gc8qo6QG2R
 5t1cmb3DEhHPYiZGVHUMOwWOemBU4eX1a7BLPjZpgXGmK4whxFizloG45RfxCN1l
 mspETpOhxSm+zocdEcjAkbf+WWWIY26HLnz7iUlirMUvWVblYqlMP1S8q/wQIEX4
 mp+iKBCFocN4YGd2/xac65twldkXaEewltsAdHNiUiMi6gmh3tMQZOt6m0eyZH2G
 sy0T7mlx/4FmQsurkIHHbQ==
 =a1Ta
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2022-03-30 11:00:33 -07:00
commit 74164d284b
38 changed files with 484 additions and 393 deletions

View file

@ -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#"

View file

@ -52,33 +52,36 @@ properties:
resets:
maxItems: 1
if:
properties:
compatible:
contains:
const: allwinner,sun50i-h6-pwm
then:
properties:
clocks:
maxItems: 2
allOf:
- $ref: pwm.yaml#
clock-names:
items:
- const: mod
- const: bus
- if:
properties:
compatible:
contains:
const: allwinner,sun50i-h6-pwm
required:
- clock-names
- resets
then:
properties:
clocks:
maxItems: 2
else:
properties:
clocks:
maxItems: 1
clock-names:
items:
- const: mod
- const: bus
required:
- clock-names
- resets
else:
properties:
clocks:
maxItems: 1
required:
- "#pwm-cells"
- compatible
- reg
- clocks

View file

@ -28,7 +28,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
additionalProperties: false

View file

@ -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>;
};

View file

@ -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

View file

@ -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

View file

@ -31,7 +31,6 @@ required:
- compatible
- reg
- clocks
- '#pwm-cells'
additionalProperties: false

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -51,42 +51,44 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
if:
properties:
compatible:
contains:
enum:
- rockchip,rk3328-pwm
- rockchip,rv1108-pwm
allOf:
- $ref: pwm.yaml#
then:
properties:
clocks:
items:
- description: Used to derive the functional clock for the device.
- description: Used as the APB bus clock.
- if:
properties:
compatible:
contains:
enum:
- rockchip,rk3328-pwm
- rockchip,rv1108-pwm
clock-names:
items:
- const: pwm
- const: pclk
then:
properties:
clocks:
items:
- description: Used to derive the functional clock for the device.
- description: Used as the APB bus clock.
required:
- clocks
- clock-names
clock-names:
items:
- const: pwm
- const: pclk
else:
properties:
clocks:
maxItems: 1
description:
Used both to derive the functional clock
for the device and as the bus clock.
required:
- clocks
- clock-names
required:
- clocks
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

View file

@ -86,7 +86,6 @@ required:
- clocks
- clock-names
- compatible
- "#pwm-cells"
- reg
additionalProperties: false

View file

@ -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

View file

@ -47,7 +47,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
- clock-names

View file

@ -48,7 +48,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
- clock-names

View file

@ -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

View file

@ -68,7 +68,6 @@ properties:
required:
- compatible
- reg
- '#pwm-cells'
- clocks
- power-domains

View file

@ -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

View file

@ -152,6 +152,7 @@ patternProperties:
- enum:
- ingenic,jz4740-pwm
- ingenic,jz4725b-pwm
- ingenic,x1000-pwm
- items:
- enum:
- ingenic,jz4760-pwm

View file

@ -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);

View file

@ -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,
};

View file

@ -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 @@ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* 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 @@ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
/* 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;
if (!state->enabled) {
if (pwm->state.enabled)
brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
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);
return 0;
}
static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
}
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");

View file

@ -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 @@ static int img_pwm_probe(struct platform_device *pdev)
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),

View file

@ -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,
};

View file

@ -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);

View file

@ -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,29 +397,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT,
BIT(lpc18xx_pwm->period_event));
ret = pwmchip_add(&lpc18xx_pwm->chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
goto disable_pwmclk;
}
for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) {
struct lpc18xx_pwm_data *data;
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;
@ -425,10 +404,16 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
val |= LPC18XX_PWM_PRE(0);
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
ret = pwmchip_add(&lpc18xx_pwm->chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
goto disable_pwmclk;
}
platform_set_drvdata(pdev, lpc18xx_pwm);
return 0;
remove_pwmchip:
pwmchip_remove(&lpc18xx_pwm->chip);
disable_pwmclk:
clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
return ret;

View file

@ -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;
}

View file

@ -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) {
/*

View file

@ -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 */

View file

@ -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,
};

View file

@ -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,

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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;
}