Merge tag 'pwm/for-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Apr 2015 17:11:24 +0000 (10:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Apr 2015 17:11:24 +0000 (10:11 -0700)
Pull pwm changes from Thierry Reding:
 "Not much has been happening in PWM land lately, so this contains
  mostly minor fixes that didn't seem urgent enough for a late
  pull-request last cycle"

* tag 'pwm/for-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: Remove __init initializer for pwm_add_table()
  pwm: samsung: Fix output race on disabling
  pwm: mxs: Fix period divider computation
  pwm: atmel-hlcdc: Add errata handling for sama5d4
  pwm: pca9685: Constify struct regmap_config
  pwm: imx-pwm: add explicit compatible strings and required clock properties

Documentation/devicetree/bindings/pwm/imx-pwm.txt
drivers/pwm/core.c
drivers/pwm/pwm-atmel-hlcdc.c
drivers/pwm/pwm-mxs.c
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-samsung.c

index b50d7a6..e00c2e9 100644 (file)
@@ -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>;
 };
index 810aef3..ba34c7d 100644 (file)
@@ -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);
 
index 522f707..fa5feab 100644 (file)
@@ -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 */ },
 };
 
index f75ecb0..b430811 100644 (file)
 #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;
        }
 
index 3fb775d..34b5c27 100644 (file)
@@ -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,
index 3e9b583..ff201e1 100644 (file)
@@ -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;