diff options
-rw-r--r-- | Documentation/devicetree/bindings/pwm/imx-pwm.txt | 12 | ||||
-rw-r--r-- | drivers/pwm/core.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-atmel-hlcdc.c | 4 | ||||
-rw-r--r-- | drivers/pwm/pwm-mxs.c | 8 | ||||
-rw-r--r-- | drivers/pwm/pwm-pca9685.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-samsung.c | 32 |
6 files changed, 54 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt index b50d7a6d9d7f..e00c2e9f484d 100644 --- a/Documentation/devicetree/bindings/pwm/imx-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt @@ -1,10 +1,17 @@ Freescale i.MX PWM controller Required properties: -- compatible: should be "fsl,<soc>-pwm" +- compatible : should be "fsl,<soc>-pwm" and one of the following + compatible strings: + - "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1 + - "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27 - reg: physical base address and length of the controller's registers - #pwm-cells: should be 2. See pwm.txt in this directory for a description of the cells format. +- clocks : Clock specifiers for both ipg and per clocks. +- clock-names : Clock names should include both "ipg" and "per" +See the clock consumer binding, + Documentation/devicetree/bindings/clock/clock-bindings.txt - interrupts: The interrupt for the pwm controller Example: @@ -13,5 +20,8 @@ pwm1: pwm@53fb4000 { #pwm-cells = <2>; compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; reg = <0x53fb4000 0x4000>; + clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, + <&clks IMX5_CLK_PWM1_HF_GATE>; + clock-names = "ipg", "per"; interrupts = <61>; }; diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 810aef3f4c3e..ba34c7d89042 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(of_pwm_get); * @table: array of consumers to register * @num: number of consumers in table */ -void __init pwm_add_table(struct pwm_lookup *table, size_t num) +void pwm_add_table(struct pwm_lookup *table, size_t num) { mutex_lock(&pwm_lookup_lock); diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 522f7075bb1a..fa5feaba25a5 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -225,6 +225,10 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_pwm_sama5d3_errata, }, + { + .compatible = "atmel,sama5d4-hlcdc", + .data = &atmel_hlcdc_pwm_sama5d3_errata, + }, { /* sentinel */ }, }; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index f75ecb09d97d..b430811e14f5 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -35,6 +35,10 @@ #define PERIOD_CDIV(div) (((div) & 0x7) << 20) #define PERIOD_CDIV_MAX 8 +static const unsigned int cdiv[PERIOD_CDIV_MAX] = { + 1, 2, 4, 8, 16, 64, 256, 1024 +}; + struct mxs_pwm_chip { struct pwm_chip chip; struct clk *clk; @@ -54,13 +58,13 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, rate = clk_get_rate(mxs->clk); while (1) { - c = rate / (1 << div); + c = rate / cdiv[div]; c = c * period_ns; do_div(c, 1000000000); if (c < PERIOD_PERIOD_MAX) break; div++; - if (div > PERIOD_CDIV_MAX) + if (div >= PERIOD_CDIV_MAX) return -EINVAL; } diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 3fb775ded0df..34b5c275a92a 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -202,7 +202,7 @@ static const struct pwm_ops pca9685_pwm_ops = { .owner = THIS_MODULE, }; -static struct regmap_config pca9685_regmap_i2c_config = { +static const struct regmap_config pca9685_regmap_i2c_config = { .reg_bits = 8, .val_bits = 8, .max_register = PCA9685_NUMREGS, diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 3e9b5835a4af..ff201e1b9219 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -269,12 +269,31 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock_irqrestore(&samsung_pwm_lock, flags); } +static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip, + struct pwm_device *pwm) +{ + unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm); + u32 tcon; + unsigned long flags; + + spin_lock_irqsave(&samsung_pwm_lock, flags); + + tcon = readl(chip->base + REG_TCON); + tcon |= TCON_MANUALUPDATE(tcon_chan); + writel(tcon, chip->base + REG_TCON); + + tcon &= ~TCON_MANUALUPDATE(tcon_chan); + writel(tcon, chip->base + REG_TCON); + + spin_unlock_irqrestore(&samsung_pwm_lock, flags); +} + static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm); - u32 tin_ns = chan->tin_ns, tcnt, tcmp; + u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp; /* * We currently avoid using 64bit arithmetic by using the @@ -288,6 +307,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, return 0; tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm)); + oldtcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm)); /* We need tick count for calculation, not last tick. */ ++tcnt; @@ -335,6 +355,16 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm)); writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm)); + /* + * In case the PWM is currently at 100% duty cycle, force a manual + * update to prevent the signal staying high if the PWM is disabled + * shortly afer this update (before it autoreloaded the new values). + */ + if (oldtcmp == (u32) -1) { + dev_dbg(our_chip->chip.dev, "Forcing manual update"); + pwm_samsung_manual_update(our_chip, pwm); + } + chan->period_ns = period_ns; chan->tin_ns = tin_ns; chan->duty_ns = duty_ns; |