Merge tag 'pwm/for-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Sep 2015 17:55:32 +0000 (10:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Sep 2015 17:55:32 +0000 (10:55 -0700)
Pull pwm updates from Thierry Reding:
 "This set of changes introduces the beginnings of a new API that's
  based around the concept of states that can be atomically applied.
  Drivers go to various lengths to implement something similar, which
  indicates that the core should really be providing the necessary
  framework.

  On top of that, there is a bit of cleanup as well as improved
  kerneldoc and integration into the device-drivers DocBook.

  Regarding drivers there is a new one for the NXP LPC18xx family of
  SoCs and a couple of fixes for existing drivers (pca9685, Broadcom
  Kona and Atmel HLCDC)"

* tag 'pwm/for-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  ARM: at91: pwm: atmel-hlcdc: Add at91sam9n12 errata
  pwm: Add NXP LPC18xx PWM/SCT DT binding documentation
  pwm: NXP LPC18xx PWM/SCT driver
  pwm-pca9685: Support changing the output frequency
  pwm-pca9685: Fix several driver bugs
  pwm: kona: Modify settings application sequence
  pwm: pca9685: Drop owner assignment
  pwm: Add to device-drivers documentation
  pwm: Clean up kerneldoc
  pwm: Remove useless whitespace
  pwm: sysfs: Remove unnecessary padding
  pwm: sysfs: Properly convert from enum to string
  pwm: Make use of pwm_get_xxx() helpers where appropriate
  pwm: Add pwm_get_polarity() helper function
  pwm: Constify PWM device where possible
  pwm: Add the pwm_is_enabled() helper

21 files changed:
Documentation/DocBook/device-drivers.tmpl
Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt [new file with mode: 0644]
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-atmel-hlcdc.c
drivers/pwm/pwm-atmel-tcb.c
drivers/pwm/pwm-atmel.c
drivers/pwm/pwm-bcm-kona.c
drivers/pwm/pwm-ep93xx.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-lpc18xx-sct.c [new file with mode: 0644]
drivers/pwm/pwm-mxs.c
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-renesas-tpu.c
drivers/pwm/pwm-rockchip.c
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/sysfs.c
include/linux/pwm.h

index abba93f..1d6008d 100644 (file)
@@ -490,4 +490,31 @@ X!Ilib/fonts/fonts.c
 !Edrivers/hsi/hsi.c
   </chapter>
 
+  <chapter id="pwm">
+    <title>Pulse-Width Modulation (PWM)</title>
+    <para>
+      Pulse-width modulation is a modulation technique primarily used to
+      control power supplied to electrical devices.
+    </para>
+    <para>
+      The PWM framework provides an abstraction for providers and consumers
+      of PWM signals. A controller that provides one or more PWM signals is
+      registered as <structname>struct pwm_chip</structname>. Providers are
+      expected to embed this structure in a driver-specific structure. This
+      structure contains fields that describe a particular chip.
+    </para>
+    <para>
+      A chip exposes one or more PWM signal sources, each of which exposed
+      as a <structname>struct pwm_device</structname>. Operations can be
+      performed on PWM devices to control the period, duty cycle, polarity
+      and active state of the signal.
+    </para>
+    <para>
+      Note that PWM devices are exclusive resources: they can always only be
+      used by one consumer at a time.
+    </para>
+!Iinclude/linux/pwm.h
+!Edrivers/pwm/core.c
+  </chapter>
+
 </book>
diff --git a/Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt b/Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt
new file mode 100644 (file)
index 0000000..36e49d4
--- /dev/null
@@ -0,0 +1,20 @@
+* NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
+
+Required properties:
+  - compatible: Should be "nxp,lpc1850-sct-pwm"
+  - reg: Should contain physical base address and length of pwm registers.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clock/clock-bindings.txt for details.
+  - clock-names: Must include the following entries.
+    - pwm: PWM operating clock.
+  - #pwm-cells: Should be 3. See pwm.txt in this directory for the description
+    of the cells format.
+
+Example:
+  pwm: pwm@40000000 {
+    compatible = "nxp,lpc1850-sct-pwm";
+    reg = <0x40000000 0x1000>;
+    clocks =<&ccu1 CLK_CPU_SCT>;
+    clock-names = "pwm";
+    #pwm-cells = <3>;
+  };
index 948d9ab..062630a 100644 (file)
@@ -180,6 +180,18 @@ config PWM_LP3943
          To compile this driver as a module, choose M here: the module
          will be called pwm-lp3943.
 
+config PWM_LPC18XX_SCT
+       tristate "LPC18xx/43xx PWM/SCT support"
+       depends on ARCH_LPC18XX
+       help
+         Generic PWM framework driver for NXP LPC18xx PWM/SCT which
+         supports 16 channels.
+         A maximum of 15 channels can be requested simultaneously and
+         must have the same period.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-lpc18xx-sct.
+
 config PWM_LPC32XX
        tristate "LPC32XX PWM support"
        depends on ARCH_LPC32XX
index d186f35..a0e00c0 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_IMG)         += pwm-img.o
 obj-$(CONFIG_PWM_IMX)          += pwm-imx.o
 obj-$(CONFIG_PWM_JZ4740)       += pwm-jz4740.o
 obj-$(CONFIG_PWM_LP3943)       += pwm-lp3943.o
+obj-$(CONFIG_PWM_LPC18XX_SCT)  += pwm-lpc18xx-sct.o
 obj-$(CONFIG_PWM_LPC32XX)      += pwm-lpc32xx.o
 obj-$(CONFIG_PWM_LPSS)         += pwm-lpss.o
 obj-$(CONFIG_PWM_LPSS_PCI)     += pwm-lpss-pci.o
index 3a7769f..3f9df3e 100644 (file)
@@ -200,6 +200,8 @@ static void of_pwmchip_remove(struct pwm_chip *chip)
  * pwm_set_chip_data() - set private chip data for a PWM
  * @pwm: PWM device
  * @data: pointer to chip-specific data
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwm_set_chip_data(struct pwm_device *pwm, void *data)
 {
@@ -215,6 +217,8 @@ EXPORT_SYMBOL_GPL(pwm_set_chip_data);
 /**
  * pwm_get_chip_data() - get private chip data for a PWM
  * @pwm: PWM device
+ *
+ * Returns: A pointer to the chip-private data for the PWM device.
  */
 void *pwm_get_chip_data(struct pwm_device *pwm)
 {
@@ -230,6 +234,8 @@ EXPORT_SYMBOL_GPL(pwm_get_chip_data);
  * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
  * will be used. The initial polarity for all channels is specified by the
  * @polarity parameter.
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwmchip_add_with_polarity(struct pwm_chip *chip,
                              enum pwm_polarity polarity)
@@ -291,6 +297,8 @@ EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity);
  *
  * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
  * will be used. The initial polarity for all channels is normal.
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwmchip_add(struct pwm_chip *chip)
 {
@@ -304,6 +312,8 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
  *
  * Removes a PWM chip. This function may return busy if the PWM chip provides
  * a PWM device that is still requested.
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwmchip_remove(struct pwm_chip *chip)
 {
@@ -338,10 +348,13 @@ EXPORT_SYMBOL_GPL(pwmchip_remove);
 
 /**
  * pwm_request() - request a PWM device
- * @pwm_id: global PWM device index
+ * @pwm: global PWM device index
  * @label: PWM device label
  *
  * This function is deprecated, use pwm_get() instead.
+ *
+ * Returns: A pointer to a PWM device or an ERR_PTR()-encoded error code on
+ * failure.
  */
 struct pwm_device *pwm_request(int pwm, const char *label)
 {
@@ -376,9 +389,9 @@ EXPORT_SYMBOL_GPL(pwm_request);
  * @index: per-chip index of the PWM to request
  * @label: a literal description string of this PWM
  *
- * Returns the PWM at the given index of the given PWM chip. A negative error
- * code is returned if the index is not valid for the specified PWM chip or
- * if the PWM device cannot be requested.
+ * Returns: A pointer to the PWM device at the given index of the given PWM
+ * chip. A negative error code is returned if the index is not valid for the
+ * specified PWM chip or if the PWM device cannot be requested.
  */
 struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
                                         unsigned int index,
@@ -419,6 +432,8 @@ EXPORT_SYMBOL_GPL(pwm_free);
  * @pwm: PWM device
  * @duty_ns: "on" time (in nanoseconds)
  * @period_ns: duration (in nanoseconds) of one cycle
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
@@ -443,7 +458,10 @@ EXPORT_SYMBOL_GPL(pwm_config);
  * @pwm: PWM device
  * @polarity: new polarity of the PWM signal
  *
- * Note that the polarity cannot be configured while the PWM device is enabled
+ * Note that the polarity cannot be configured while the PWM device is
+ * enabled.
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
 {
@@ -455,7 +473,7 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
        if (!pwm->chip->ops->set_polarity)
                return -ENOSYS;
 
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
+       if (pwm_is_enabled(pwm))
                return -EBUSY;
 
        err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
@@ -471,6 +489,8 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
 /**
  * pwm_enable() - start a PWM output toggling
  * @pwm: PWM device
+ *
+ * Returns: 0 on success or a negative error code on failure.
  */
 int pwm_enable(struct pwm_device *pwm)
 {
@@ -524,6 +544,9 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
  * lookup of the PWM index. This also means that the "pwm-names" property
  * becomes mandatory for devices that look up the PWM device via the con_id
  * parameter.
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
  */
 struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
 {
@@ -630,6 +653,9 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
  *
  * Once a PWM chip has been found the specified PWM device will be requested
  * and is ready to be used.
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
  */
 struct pwm_device *pwm_get(struct device *dev, const char *con_id)
 {
@@ -752,6 +778,9 @@ static void devm_pwm_release(struct device *dev, void *res)
  *
  * This function performs like pwm_get() but the acquired PWM device will
  * automatically be released on driver detach.
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
  */
 struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
 {
@@ -781,6 +810,9 @@ EXPORT_SYMBOL_GPL(devm_pwm_get);
  *
  * This function performs like of_pwm_get() but the acquired PWM device will
  * automatically be released on driver detach.
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
  */
 struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
                                   const char *con_id)
@@ -832,7 +864,7 @@ EXPORT_SYMBOL_GPL(devm_pwm_put);
   * pwm_can_sleep() - report whether PWM access will sleep
   * @pwm: PWM device
   *
-  * It returns true if accessing the PWM can sleep, false otherwise.
+  * Returns: True if accessing the PWM can sleep, false otherwise.
   */
 bool pwm_can_sleep(struct pwm_device *pwm)
 {
@@ -853,7 +885,7 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
                if (test_bit(PWMF_REQUESTED, &pwm->flags))
                        seq_puts(s, " requested");
 
-               if (test_bit(PWMF_ENABLED, &pwm->flags))
+               if (pwm_is_enabled(pwm))
                        seq_puts(s, " enabled");
 
                seq_puts(s, "\n");
@@ -924,6 +956,5 @@ static int __init pwm_debugfs_init(void)
 
        return 0;
 }
-
 subsys_initcall(pwm_debugfs_init);
 #endif /* CONFIG_DEBUG_FS */
index fa5feab..5df1db4 100644 (file)
@@ -218,6 +218,11 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
 
 static const struct of_device_id atmel_hlcdc_dt_ids[] = {
        {
+               .compatible = "atmel,at91sam9n12-hlcdc",
+               /* 9n12 has same errata as 9x5 HLCDC PWM */
+               .data = &atmel_hlcdc_pwm_at91sam9x5_errata,
+       },
+       {
                .compatible = "atmel,at91sam9x5-hlcdc",
                .data = &atmel_hlcdc_pwm_at91sam9x5_errata,
        },
index d14e067..6da01b3 100644 (file)
@@ -347,7 +347,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        tcbpwm->duty = duty;
 
        /* If the PWM is enabled, call enable to apply the new conf */
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
+       if (pwm_is_enabled(pwm))
                atmel_tcb_pwm_enable(chip, pwm);
 
        return 0;
index a947c90..0e4bd4e 100644 (file)
@@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        u32 val;
        int ret;
 
-       if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) {
+       if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) {
                dev_err(chip->dev, "cannot change PWM period while enabled\n");
                return -EBUSY;
        }
@@ -176,7 +176,7 @@ static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm,
         * If the PWM channel is enabled, only update CDTY by using the update
         * register, it needs to set bit 10 of CMR to 0
         */
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
+       if (pwm_is_enabled(pwm))
                return;
        /*
         * If the PWM channel is disabled, write value to duty and period
@@ -191,7 +191,7 @@ static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm,
 {
        struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
 
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (pwm_is_enabled(pwm)) {
                /*
                 * If the PWM channel is enabled, using the duty update register
                 * to update the value.
index 7af8fea..c634183 100644 (file)
@@ -76,19 +76,36 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
        return container_of(_chip, struct kona_pwmc, chip);
 }
 
-static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+/*
+ * Clear trigger bit but set smooth bit to maintain old output.
+ */
+static void kona_pwmc_prepare_for_settings(struct kona_pwmc *kp,
+       unsigned int chan)
 {
        unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-       /* Clear trigger bit but set smooth bit to maintain old output */
        value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
        value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
        writel(value, kp->base + PWM_CONTROL_OFFSET);
 
+       /*
+        * There must be a min 400ns delay between clearing trigger and setting
+        * it. Failing to do this may result in no PWM signal.
+        */
+       ndelay(400);
+}
+
+static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
+{
+       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
        /* Set trigger bit and clear smooth bit to apply new settings */
        value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
        value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
        writel(value, kp->base + PWM_CONTROL_OFFSET);
+
+       /* Trigger bit must be held high for at least 400 ns. */
+       ndelay(400);
 }
 
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -133,8 +150,14 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
                        return -EINVAL;
        }
 
-       /* If the PWM channel is enabled, write the settings to the HW */
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+       /*
+        * 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);
+
                value = readl(kp->base + PRESCALE_OFFSET);
                value &= ~PRESCALE_MASK(chan);
                value |= prescale << PRESCALE_SHIFT(chan);
@@ -164,6 +187,8 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
                return ret;
        }
 
+       kona_pwmc_prepare_for_settings(kp, chan);
+
        value = readl(kp->base + PWM_CONTROL_OFFSET);
 
        if (polarity == PWM_POLARITY_NORMAL)
@@ -175,9 +200,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
        kona_pwmc_apply_settings(kp, chan);
 
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
-
        clk_disable_unprepare(kp->clk);
 
        return 0;
@@ -194,7 +216,8 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
                return ret;
        }
 
-       ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
+       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;
@@ -207,13 +230,20 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct kona_pwmc *kp = to_kona_pwmc(chip);
        unsigned int chan = pwm->hwpwm;
+       unsigned int value;
+
+       kona_pwmc_prepare_for_settings(kp, chan);
 
        /* Simulate a disable by configuring for zero duty */
        writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-       kona_pwmc_apply_settings(kp, chan);
+       writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
 
-       /* Wait for waveform to settle before gating off the clock */
-       ndelay(400);
+       /* Set prescale to 0 for this channel */
+       value = readl(kp->base + PRESCALE_OFFSET);
+       value &= ~PRESCALE_MASK(chan);
+       writel(value, kp->base + PRESCALE_OFFSET);
+
+       kona_pwmc_apply_settings(kp, chan);
 
        clk_disable_unprepare(kp->clk);
 }
@@ -287,7 +317,7 @@ static int kona_pwmc_remove(struct platform_device *pdev)
        unsigned int chan;
 
        for (chan = 0; chan < kp->chip.npwm; chan++)
-               if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags))
+               if (pwm_is_enabled(&kp->chip.pwms[chan]))
                        clk_disable_unprepare(kp->clk);
 
        return pwmchip_remove(&kp->chip);
index e593e9c..bbf10ae 100644 (file)
@@ -82,7 +82,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
         * The clock needs to be enabled to access the PWM registers.
         * Configuration can be changed at any time.
         */
-       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (!pwm_is_enabled(pwm)) {
                ret = clk_enable(ep93xx_pwm->clk);
                if (ret)
                        return ret;
@@ -113,7 +113,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                ret = -EINVAL;
        }
 
-       if (!test_bit(PWMF_ENABLED, &pwm->flags))
+       if (!pwm_is_enabled(pwm))
                clk_disable(ep93xx_pwm->clk);
 
        return ret;
index 66d6f0c..d600fd5 100644 (file)
@@ -114,7 +114,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip,
        unsigned long long c;
        unsigned long period_cycles, duty_cycles, prescale;
        unsigned int period_ms;
-       bool enable = test_bit(PWMF_ENABLED, &pwm->flags);
+       bool enable = pwm_is_enabled(pwm);
        int wait_count = 0, fifoav;
        u32 cr, sr;
 
@@ -129,7 +129,8 @@ static int imx_pwm_config_v2(struct pwm_chip *chip,
                sr = readl(imx->mmio_base + MX3_PWMSR);
                fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
                if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
-                       period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC);
+                       period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
+                                                NSEC_PER_MSEC);
                        msleep(period_ms);
 
                        sr = readl(imx->mmio_base + MX3_PWMSR);
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
new file mode 100644 (file)
index 0000000..9163085
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver
+ *
+ * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * Notes
+ * =====
+ * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured
+ * as a Pulse Width Modulator.
+ *
+ * SCT supports 16 outputs, 16 events and 16 registers. Each event will be
+ * triggered when its related register matches the SCT counter value, and it
+ * will set or clear a selected output.
+ *
+ * One of the events is preselected to generate the period, thus the maximum
+ * number of simultaneous channels is limited to 15. Notice that period is
+ * global to all the channels, thus PWM driver will refuse setting different
+ * values to it, unless there's only one channel requested.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+/* LPC18xx SCT registers */
+#define LPC18XX_PWM_CONFIG             0x000
+#define LPC18XX_PWM_CONFIG_UNIFY       BIT(0)
+#define LPC18XX_PWM_CONFIG_NORELOAD    BIT(7)
+
+#define LPC18XX_PWM_CTRL               0x004
+#define LPC18XX_PWM_CTRL_HALT          BIT(2)
+#define LPC18XX_PWM_BIDIR              BIT(4)
+#define LPC18XX_PWM_PRE_SHIFT          5
+#define LPC18XX_PWM_PRE_MASK           (0xff << LPC18XX_PWM_PRE_SHIFT)
+#define LPC18XX_PWM_PRE(x)             (x << LPC18XX_PWM_PRE_SHIFT)
+
+#define LPC18XX_PWM_LIMIT              0x008
+
+#define LPC18XX_PWM_RES_BASE           0x058
+#define LPC18XX_PWM_RES_SHIFT(_ch)     (_ch * 2)
+#define LPC18XX_PWM_RES(_ch, _action)  (_action << LPC18XX_PWM_RES_SHIFT(_ch))
+#define LPC18XX_PWM_RES_MASK(_ch)      (0x3 << LPC18XX_PWM_RES_SHIFT(_ch))
+
+#define LPC18XX_PWM_MATCH_BASE         0x100
+#define LPC18XX_PWM_MATCH(_ch)         (LPC18XX_PWM_MATCH_BASE + _ch * 4)
+
+#define LPC18XX_PWM_MATCHREL_BASE      0x200
+#define LPC18XX_PWM_MATCHREL(_ch)      (LPC18XX_PWM_MATCHREL_BASE + _ch * 4)
+
+#define LPC18XX_PWM_EVSTATEMSK_BASE    0x300
+#define LPC18XX_PWM_EVSTATEMSK(_ch)    (LPC18XX_PWM_EVSTATEMSK_BASE + _ch * 8)
+#define LPC18XX_PWM_EVSTATEMSK_ALL     0xffffffff
+
+#define LPC18XX_PWM_EVCTRL_BASE                0x304
+#define LPC18XX_PWM_EVCTRL(_ev)                (LPC18XX_PWM_EVCTRL_BASE + _ev * 8)
+
+#define LPC18XX_PWM_EVCTRL_MATCH(_ch)  _ch
+
+#define LPC18XX_PWM_EVCTRL_COMB_SHIFT  12
+#define LPC18XX_PWM_EVCTRL_COMB_MATCH  (0x1 << LPC18XX_PWM_EVCTRL_COMB_SHIFT)
+
+#define LPC18XX_PWM_OUTPUTSET_BASE     0x500
+#define LPC18XX_PWM_OUTPUTSET(_ch)     (LPC18XX_PWM_OUTPUTSET_BASE + _ch * 8)
+
+#define LPC18XX_PWM_OUTPUTCL_BASE      0x504
+#define LPC18XX_PWM_OUTPUTCL(_ch)      (LPC18XX_PWM_OUTPUTCL_BASE + _ch * 8)
+
+/* LPC18xx SCT unified counter */
+#define LPC18XX_PWM_TIMER_MAX          0xffffffff
+
+/* LPC18xx SCT events */
+#define LPC18XX_PWM_EVENT_PERIOD       0
+#define LPC18XX_PWM_EVENT_MAX          16
+
+/* SCT conflict resolution */
+enum lpc18xx_pwm_res_action {
+       LPC18XX_PWM_RES_NONE,
+       LPC18XX_PWM_RES_SET,
+       LPC18XX_PWM_RES_CLEAR,
+       LPC18XX_PWM_RES_TOGGLE,
+};
+
+struct lpc18xx_pwm_data {
+       unsigned int duty_event;
+};
+
+struct lpc18xx_pwm_chip {
+       struct device *dev;
+       struct pwm_chip chip;
+       void __iomem *base;
+       struct clk *pwm_clk;
+       unsigned long clk_rate;
+       unsigned int period_ns;
+       unsigned int min_period_ns;
+       unsigned int max_period_ns;
+       unsigned int period_event;
+       unsigned long event_map;
+       struct mutex res_lock;
+       struct mutex period_lock;
+};
+
+static inline struct lpc18xx_pwm_chip *
+to_lpc18xx_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct lpc18xx_pwm_chip, chip);
+}
+
+static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
+                                     u32 reg, u32 val)
+{
+       writel(val, lpc18xx_pwm->base + reg);
+}
+
+static inline u32 lpc18xx_pwm_readl(struct lpc18xx_pwm_chip *lpc18xx_pwm,
+                                   u32 reg)
+{
+       return readl(lpc18xx_pwm->base + reg);
+}
+
+static void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm,
+                                        struct pwm_device *pwm,
+                                        enum lpc18xx_pwm_res_action action)
+{
+       u32 val;
+
+       mutex_lock(&lpc18xx_pwm->res_lock);
+
+       /*
+        * Simultaneous set and clear may happen on an output, that is the case
+        * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict
+        * resolution action to be taken in such a case.
+        */
+       val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_RES_BASE);
+       val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm);
+       val |= LPC18XX_PWM_RES(pwm->hwpwm, action);
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_RES_BASE, val);
+
+       mutex_unlock(&lpc18xx_pwm->res_lock);
+}
+
+static void lpc18xx_pwm_config_period(struct pwm_chip *chip, int period_ns)
+{
+       struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
+       u64 val;
+
+       val = (u64)period_ns * lpc18xx_pwm->clk_rate;
+       do_div(val, NSEC_PER_SEC);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event),
+                          (u32)val - 1);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event),
+                          (u32)val - 1);
+}
+
+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);
+       u64 val;
+
+       val = (u64)duty_ns * lpc18xx_pwm->clk_rate;
+       do_div(val, NSEC_PER_SEC);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_MATCH(lpc18xx_data->duty_event),
+                          (u32)val);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event),
+                          (u32)val);
+}
+
+static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
+       int requested_events, i;
+
+       if (period_ns < lpc18xx_pwm->min_period_ns ||
+           period_ns > lpc18xx_pwm->max_period_ns) {
+               dev_err(chip->dev, "period %d not in range\n", period_ns);
+               return -ERANGE;
+       }
+
+       mutex_lock(&lpc18xx_pwm->period_lock);
+
+       requested_events = bitmap_weight(&lpc18xx_pwm->event_map,
+                                        LPC18XX_PWM_EVENT_MAX);
+
+       /*
+        * The PWM supports only a single period for all PWM channels.
+        * Once the period is set, it can only be changed if no more than one
+        * channel is requested at that moment.
+        */
+       if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
+           lpc18xx_pwm->period_ns) {
+               dev_err(chip->dev, "conflicting period requested for PWM %u\n",
+                       pwm->hwpwm);
+               mutex_unlock(&lpc18xx_pwm->period_lock);
+               return -EBUSY;
+       }
+
+       if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
+           !lpc18xx_pwm->period_ns) {
+               lpc18xx_pwm->period_ns = period_ns;
+               for (i = 0; i < chip->npwm; i++)
+                       pwm_set_period(&chip->pwms[i], period_ns);
+               lpc18xx_pwm_config_period(chip, period_ns);
+       }
+
+       mutex_unlock(&lpc18xx_pwm->period_lock);
+
+       lpc18xx_pwm_config_duty(chip, pwm, duty_ns);
+
+       return 0;
+}
+
+static int lpc18xx_pwm_set_polarity(struct pwm_chip *chip,
+                                   struct pwm_device *pwm,
+                                   enum pwm_polarity polarity)
+{
+       return 0;
+}
+
+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);
+       enum lpc18xx_pwm_res_action res_action;
+       unsigned int set_event, clear_event;
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event),
+                          LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) |
+                          LPC18XX_PWM_EVCTRL_COMB_MATCH);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event),
+                          LPC18XX_PWM_EVSTATEMSK_ALL);
+
+       if (pwm->polarity == PWM_POLARITY_NORMAL) {
+               set_event = lpc18xx_pwm->period_event;
+               clear_event = lpc18xx_data->duty_event;
+               res_action = LPC18XX_PWM_RES_SET;
+       } else {
+               set_event = lpc18xx_data->duty_event;
+               clear_event = lpc18xx_pwm->period_event;
+               res_action = LPC18XX_PWM_RES_CLEAR;
+       }
+
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm),
+                          BIT(set_event));
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm),
+                          BIT(clear_event));
+       lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action);
+
+       return 0;
+}
+
+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);
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0);
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0);
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0);
+}
+
+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);
+       unsigned long event;
+
+       event = find_first_zero_bit(&lpc18xx_pwm->event_map,
+                                   LPC18XX_PWM_EVENT_MAX);
+
+       if (event >= LPC18XX_PWM_EVENT_MAX) {
+               dev_err(lpc18xx_pwm->dev,
+                       "maximum number of simultaneous channels reached\n");
+               return -EBUSY;
+       };
+
+       set_bit(event, &lpc18xx_pwm->event_map);
+       lpc18xx_data->duty_event = event;
+       lpc18xx_pwm_config_duty(chip, pwm, pwm_get_duty_cycle(pwm));
+
+       return 0;
+}
+
+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);
+
+       pwm_disable(pwm);
+       pwm_set_duty_cycle(pwm, 0);
+       clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map);
+}
+
+static const struct pwm_ops lpc18xx_pwm_ops = {
+       .config = lpc18xx_pwm_config,
+       .set_polarity = lpc18xx_pwm_set_polarity,
+       .enable = lpc18xx_pwm_enable,
+       .disable = lpc18xx_pwm_disable,
+       .request = lpc18xx_pwm_request,
+       .free = lpc18xx_pwm_free,
+       .owner = THIS_MODULE,
+};
+
+static const struct of_device_id lpc18xx_pwm_of_match[] = {
+       { .compatible = "nxp,lpc1850-sct-pwm" },
+       {}
+};
+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;
+       struct resource *res;
+       int ret, i;
+       u64 val;
+
+       lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
+                                  GFP_KERNEL);
+       if (!lpc18xx_pwm)
+               return -ENOMEM;
+
+       lpc18xx_pwm->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       lpc18xx_pwm->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(lpc18xx_pwm->base))
+               return PTR_ERR(lpc18xx_pwm->base);
+
+       lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm");
+       if (IS_ERR(lpc18xx_pwm->pwm_clk)) {
+               dev_err(&pdev->dev, "failed to get pwm clock\n");
+               return PTR_ERR(lpc18xx_pwm->pwm_clk);
+       }
+
+       ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "could not prepare or enable pwm clock\n");
+               return ret;
+       }
+
+       lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk);
+
+       mutex_init(&lpc18xx_pwm->res_lock);
+       mutex_init(&lpc18xx_pwm->period_lock);
+
+       val = (u64)NSEC_PER_SEC * LPC18XX_PWM_TIMER_MAX;
+       do_div(val, lpc18xx_pwm->clk_rate);
+       lpc18xx_pwm->max_period_ns = val;
+
+       lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
+                                                 lpc18xx_pwm->clk_rate);
+
+       lpc18xx_pwm->chip.dev = &pdev->dev;
+       lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
+       lpc18xx_pwm->chip.base = -1;
+       lpc18xx_pwm->chip.npwm = 16;
+       lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+       lpc18xx_pwm->chip.of_pwm_n_cells = 3;
+
+       /* SCT counter must be in unify (32 bit) mode */
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
+                          LPC18XX_PWM_CONFIG_UNIFY);
+
+       /*
+        * Everytime the timer counter reaches the period value, the related
+        * event will be triggered and the counter reset to 0.
+        */
+       set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map);
+       lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD;
+
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event),
+                          LPC18XX_PWM_EVSTATEMSK_ALL);
+
+       val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) |
+             LPC18XX_PWM_EVCTRL_COMB_MATCH;
+       lpc18xx_pwm_writel(lpc18xx_pwm,
+                          LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val);
+
+       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++) {
+               pwm = &lpc18xx_pwm->chip.pwms[i];
+               pwm->chip_data = devm_kzalloc(lpc18xx_pwm->dev,
+                                             sizeof(struct lpc18xx_pwm_data),
+                                             GFP_KERNEL);
+               if (!pwm->chip_data) {
+                       ret = -ENOMEM;
+                       goto remove_pwmchip;
+               }
+       }
+
+       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;
+}
+
+static int lpc18xx_pwm_remove(struct platform_device *pdev)
+{
+       struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
+       u32 val;
+
+       val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
+       lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
+                          val | LPC18XX_PWM_CTRL_HALT);
+
+       clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
+
+       return pwmchip_remove(&lpc18xx_pwm->chip);
+}
+
+static struct platform_driver lpc18xx_pwm_driver = {
+       .driver = {
+               .name = "lpc18xx-sct-pwm",
+               .of_match_table = lpc18xx_pwm_of_match,
+       },
+       .probe = lpc18xx_pwm_probe,
+       .remove = lpc18xx_pwm_remove,
+};
+module_platform_driver(lpc18xx_pwm_driver);
+
+MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
+MODULE_DESCRIPTION("NXP LPC18xx PWM driver");
+MODULE_LICENSE("GPL v2");
index b430811..9a59632 100644 (file)
@@ -77,7 +77,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
         * If the PWM channel is disabled, make sure to turn on the clock
         * before writing the register. Otherwise, keep it enabled.
         */
-       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (!pwm_is_enabled(pwm)) {
                ret = clk_prepare_enable(mxs->clk);
                if (ret)
                        return ret;
@@ -92,7 +92,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        /*
         * If the PWM is not enabled, turn the clock off again to save power.
         */
-       if (!test_bit(PWMF_ENABLED, &pwm->flags))
+       if (!pwm_is_enabled(pwm))
                clk_disable_unprepare(mxs->clk);
 
        return 0;
index 34b5c27..70448a6 100644 (file)
@@ -2,6 +2,7 @@
  * Driver for PCA9685 16-channel 12-bit PWM LED controller
  *
  * Copyright (C) 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ * Copyright (C) 2015 Clemens Gruber <clemens.gruber@pqgruber.com>
  *
  * based on the pwm-twl-led.c driver
  *
 #include <linux/pwm.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
+
+/*
+ * Because the PCA9685 has only one prescaler per chip, changing the period of
+ * one channel affects the period of all 16 PWM outputs!
+ * However, the ratio between each configured duty cycle and the chip-wide
+ * period remains constant, because the OFF time is set in proportion to the
+ * counter range.
+ */
 
 #define PCA9685_MODE1          0x00
 #define PCA9685_MODE2          0x01
 #define PCA9685_ALL_LED_OFF_H  0xFD
 #define PCA9685_PRESCALE       0xFE
 
+#define PCA9685_PRESCALE_MIN   0x03    /* => max. frequency of 1526 Hz */
+#define PCA9685_PRESCALE_MAX   0xFF    /* => min. frequency of 24 Hz */
+
+#define PCA9685_COUNTER_RANGE  4096
+#define PCA9685_DEFAULT_PERIOD 5000000 /* Default period_ns = 1/200 Hz */
+#define PCA9685_OSC_CLOCK_MHZ  25      /* Internal oscillator with 25 MHz */
+
 #define PCA9685_NUMREGS                0xFF
 #define PCA9685_MAXCHAN                0x10
 
 #define LED_FULL               (1 << 4)
+#define MODE1_RESTART          (1 << 7)
 #define MODE1_SLEEP            (1 << 4)
 #define MODE2_INVRT            (1 << 4)
 #define MODE2_OUTDRV           (1 << 2)
@@ -59,6 +77,8 @@ struct pca9685 {
        struct pwm_chip chip;
        struct regmap *regmap;
        int active_cnt;
+       int duty_ns;
+       int period_ns;
 };
 
 static inline struct pca9685 *to_pca(struct pwm_chip *chip)
@@ -72,6 +92,47 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        struct pca9685 *pca = to_pca(chip);
        unsigned long long duty;
        unsigned int reg;
+       int prescale;
+
+       if (period_ns != pca->period_ns) {
+               prescale = DIV_ROUND_CLOSEST(PCA9685_OSC_CLOCK_MHZ * period_ns,
+                                            PCA9685_COUNTER_RANGE * 1000) - 1;
+
+               if (prescale >= PCA9685_PRESCALE_MIN &&
+                       prescale <= PCA9685_PRESCALE_MAX) {
+                       /* Put chip into sleep mode */
+                       regmap_update_bits(pca->regmap, PCA9685_MODE1,
+                                          MODE1_SLEEP, MODE1_SLEEP);
+
+                       /* Change the chip-wide output frequency */
+                       regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
+
+                       /* Wake the chip up */
+                       regmap_update_bits(pca->regmap, PCA9685_MODE1,
+                                          MODE1_SLEEP, 0x0);
+
+                       /* Wait 500us for the oscillator to be back up */
+                       udelay(500);
+
+                       pca->period_ns = period_ns;
+
+                       /*
+                        * If the duty cycle did not change, restart PWM with
+                        * the same duty cycle to period ratio and return.
+                        */
+                       if (duty_ns == pca->duty_ns) {
+                               regmap_update_bits(pca->regmap, PCA9685_MODE1,
+                                                  MODE1_RESTART, 0x1);
+                               return 0;
+                       }
+               } else {
+                       dev_err(chip->dev,
+                               "prescaler not set: period out of bounds!\n");
+                       return -EINVAL;
+               }
+       }
+
+       pca->duty_ns = duty_ns;
 
        if (duty_ns < 1) {
                if (pwm->hwpwm >= PCA9685_MAXCHAN)
@@ -85,6 +146,22 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        }
 
        if (duty_ns == period_ns) {
+               /* Clear both OFF registers */
+               if (pwm->hwpwm >= PCA9685_MAXCHAN)
+                       reg = PCA9685_ALL_LED_OFF_L;
+               else
+                       reg = LED_N_OFF_L(pwm->hwpwm);
+
+               regmap_write(pca->regmap, reg, 0x0);
+
+               if (pwm->hwpwm >= PCA9685_MAXCHAN)
+                       reg = PCA9685_ALL_LED_OFF_H;
+               else
+                       reg = LED_N_OFF_H(pwm->hwpwm);
+
+               regmap_write(pca->regmap, reg, 0x0);
+
+               /* Set the full ON bit */
                if (pwm->hwpwm >= PCA9685_MAXCHAN)
                        reg = PCA9685_ALL_LED_ON_H;
                else
@@ -95,7 +172,7 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                return 0;
        }
 
-       duty = 4096 * (unsigned long long)duty_ns;
+       duty = PCA9685_COUNTER_RANGE * (unsigned long long)duty_ns;
        duty = DIV_ROUND_UP_ULL(duty, period_ns);
 
        if (pwm->hwpwm >= PCA9685_MAXCHAN)
@@ -112,6 +189,14 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
        regmap_write(pca->regmap, reg, ((int)duty >> 8) & 0xf);
 
+       /* Clear the full ON bit, otherwise the set OFF time has no effect */
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_ON_H;
+       else
+               reg = LED_N_ON_H(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, 0);
+
        return 0;
 }
 
@@ -228,6 +313,8 @@ static int pca9685_pwm_probe(struct i2c_client *client,
                        ret);
                return ret;
        }
+       pca->duty_ns = 0;
+       pca->period_ns = PCA9685_DEFAULT_PERIOD;
 
        i2c_set_clientdata(client, pca);
 
@@ -285,7 +372,6 @@ MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
 static struct i2c_driver pca9685_i2c_driver = {
        .driver = {
                .name = "pca9685-pwm",
-               .owner = THIS_MODULE,
                .of_match_table = pca9685_dt_ids,
        },
        .probe = pca9685_pwm_probe,
index ee63f9e..075c1a7 100644 (file)
@@ -301,7 +301,7 @@ static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
        pwm->duty = duty;
 
        /* If the channel is disabled we're done. */
-       if (!test_bit(PWMF_ENABLED, &_pwm->flags))
+       if (!pwm_is_enabled(_pwm))
                return 0;
 
        if (duty_only && pwm->timer_on) {
index 9442df2..7d9cc90 100644 (file)
@@ -83,7 +83,7 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
                          PWM_CONTINUOUS;
        u32 val;
 
-       if (pwm->polarity == PWM_POLARITY_INVERSED)
+       if (pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED)
                enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
        else
                enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
index cabd7d8..d4de060 100644 (file)
@@ -112,7 +112,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
         * If the PWM channel is disabled, make sure to turn on the clock
         * before writing the register. Otherwise, keep it enabled.
         */
-       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (!pwm_is_enabled(pwm)) {
                err = clk_prepare_enable(pc->clk);
                if (err < 0)
                        return err;
@@ -124,7 +124,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        /*
         * If the PWM is not enabled, turn the clock off again to save power.
         */
-       if (!test_bit(PWMF_ENABLED, &pwm->flags))
+       if (!pwm_is_enabled(pwm))
                clk_disable_unprepare(pc->clk);
 
        return 0;
@@ -214,7 +214,7 @@ static int tegra_pwm_remove(struct platform_device *pdev)
        for (i = 0; i < NUM_PWM; i++) {
                struct pwm_device *pwm = &pc->chip.pwms[i];
 
-               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+               if (!pwm_is_enabled(pwm))
                        if (clk_prepare_enable(pc->clk) < 0)
                                continue;
 
index e557bef..616af76 100644 (file)
@@ -97,7 +97,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
        writew(reg_val, pc->mmio_base + ECCTL2);
 
-       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (!pwm_is_enabled(pwm)) {
                /* Update active registers if not running */
                writel(duty_cycles, pc->mmio_base + CAP2);
                writel(period_cycles, pc->mmio_base + CAP1);
@@ -111,7 +111,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                writel(period_cycles, pc->mmio_base + CAP3);
        }
 
-       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (!pwm_is_enabled(pwm)) {
                reg_val = readw(pc->mmio_base + ECCTL2);
                /* Disable APWM mode to put APWM output Low */
                reg_val &= ~ECCTL2_APWM_MODE;
@@ -179,7 +179,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (pwm_is_enabled(pwm)) {
                dev_warn(chip->dev, "Removing PWM device without disabling\n");
                pm_runtime_put_sync(chip->dev);
        }
@@ -306,7 +306,7 @@ static int ecap_pwm_suspend(struct device *dev)
        ecap_pwm_save_context(pc);
 
        /* Disable explicitly if PWM is running */
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
+       if (pwm_is_enabled(pwm))
                pm_runtime_put_sync(dev);
 
        return 0;
@@ -318,7 +318,7 @@ static int ecap_pwm_resume(struct device *dev)
        struct pwm_device *pwm = pc->chip.pwms;
 
        /* Enable explicitly if PWM was running */
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
+       if (pwm_is_enabled(pwm))
                pm_runtime_get_sync(dev);
 
        ecap_pwm_restore_context(pc);
index 694b3cf..6a41e66 100644 (file)
@@ -407,7 +407,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 
-       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+       if (pwm_is_enabled(pwm)) {
                dev_warn(chip->dev, "Removing PWM device without disabling\n");
                pm_runtime_put_sync(chip->dev);
        }
@@ -565,7 +565,7 @@ static int ehrpwm_pwm_suspend(struct device *dev)
        for (i = 0; i < pc->chip.npwm; i++) {
                struct pwm_device *pwm = &pc->chip.pwms[i];
 
-               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+               if (!pwm_is_enabled(pwm))
                        continue;
 
                /* Disable explicitly if PWM is running */
@@ -582,7 +582,7 @@ static int ehrpwm_pwm_resume(struct device *dev)
        for (i = 0; i < pc->chip.npwm; i++) {
                struct pwm_device *pwm = &pc->chip.pwms[i];
 
-               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+               if (!pwm_is_enabled(pwm))
                        continue;
 
                /* Enable explicitly if PWM was running */
index 4bd0c63..c472772 100644 (file)
@@ -46,7 +46,7 @@ static ssize_t pwm_period_show(struct device *child,
 {
        const struct pwm_device *pwm = child_to_pwm_device(child);
 
-       return sprintf(buf, "%u\n", pwm->period);
+       return sprintf(buf, "%u\n", pwm_get_period(pwm));
 }
 
 static ssize_t pwm_period_store(struct device *child,
@@ -61,7 +61,7 @@ static ssize_t pwm_period_store(struct device *child,
        if (ret)
                return ret;
 
-       ret = pwm_config(pwm, pwm->duty_cycle, val);
+       ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val);
 
        return ret ? : size;
 }
@@ -72,7 +72,7 @@ static ssize_t pwm_duty_cycle_show(struct device *child,
 {
        const struct pwm_device *pwm = child_to_pwm_device(child);
 
-       return sprintf(buf, "%u\n", pwm->duty_cycle);
+       return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
 }
 
 static ssize_t pwm_duty_cycle_store(struct device *child,
@@ -87,7 +87,7 @@ static ssize_t pwm_duty_cycle_store(struct device *child,
        if (ret)
                return ret;
 
-       ret = pwm_config(pwm, val, pwm->period);
+       ret = pwm_config(pwm, val, pwm_get_period(pwm));
 
        return ret ? : size;
 }
@@ -97,7 +97,7 @@ static ssize_t pwm_enable_show(struct device *child,
                               char *buf)
 {
        const struct pwm_device *pwm = child_to_pwm_device(child);
-       int enabled = test_bit(PWMF_ENABLED, &pwm->flags);
+       int enabled = pwm_is_enabled(pwm);
 
        return sprintf(buf, "%d\n", enabled);
 }
@@ -133,8 +133,19 @@ static ssize_t pwm_polarity_show(struct device *child,
                                 char *buf)
 {
        const struct pwm_device *pwm = child_to_pwm_device(child);
+       const char *polarity = "unknown";
 
-       return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
+       switch (pwm_get_polarity(pwm)) {
+       case PWM_POLARITY_NORMAL:
+               polarity = "normal";
+               break;
+
+       case PWM_POLARITY_INVERSED:
+               polarity = "inversed";
+               break;
+       }
+
+       return sprintf(buf, "%s\n", polarity);
 }
 
 static ssize_t pwm_polarity_store(struct device *child,
@@ -301,9 +312,9 @@ static struct attribute *pwm_chip_attrs[] = {
 ATTRIBUTE_GROUPS(pwm_chip);
 
 static struct class pwm_class = {
-       .name           = "pwm",
-       .owner          = THIS_MODULE,
-       .dev_groups     = pwm_chip_groups,
+       .name = "pwm",
+       .owner = THIS_MODULE,
+       .dev_groups = pwm_chip_groups,
 };
 
 static int pwmchip_sysfs_match(struct device *parent, const void *data)
index 36262d0..d681f68 100644 (file)
@@ -79,26 +79,43 @@ enum {
        PWMF_EXPORTED = 1 << 2,
 };
 
+/**
+ * struct pwm_device - PWM channel object
+ * @label: name of the PWM device
+ * @flags: flags associated with the PWM device
+ * @hwpwm: per-chip relative index of the PWM device
+ * @pwm: global index of the PWM device
+ * @chip: PWM chip providing this PWM device
+ * @chip_data: chip-private data associated with the PWM device
+ * @period: period of the PWM signal (in nanoseconds)
+ * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
+ * @polarity: polarity of the PWM signal
+ */
 struct pwm_device {
-       const char              *label;
-       unsigned long           flags;
-       unsigned int            hwpwm;
-       unsigned int            pwm;
-       struct pwm_chip         *chip;
-       void                    *chip_data;
-
-       unsigned int            period;         /* in nanoseconds */
-       unsigned int            duty_cycle;     /* in nanoseconds */
-       enum pwm_polarity       polarity;
+       const char *label;
+       unsigned long flags;
+       unsigned int hwpwm;
+       unsigned int pwm;
+       struct pwm_chip *chip;
+       void *chip_data;
+
+       unsigned int period;
+       unsigned int duty_cycle;
+       enum pwm_polarity polarity;
 };
 
+static inline bool pwm_is_enabled(const struct pwm_device *pwm)
+{
+       return test_bit(PWMF_ENABLED, &pwm->flags);
+}
+
 static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
 {
        if (pwm)
                pwm->period = period;
 }
 
-static inline unsigned int pwm_get_period(struct pwm_device *pwm)
+static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
 {
        return pwm ? pwm->period : 0;
 }
@@ -109,7 +126,7 @@ static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
                pwm->duty_cycle = duty;
 }
 
-static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
+static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
 {
        return pwm ? pwm->duty_cycle : 0;
 }
@@ -119,6 +136,11 @@ static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
  */
 int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
 
+static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
+{
+       return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
+}
+
 /**
  * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
@@ -131,25 +153,18 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
  * @owner: helps prevent removal of modules exporting active PWMs
  */
 struct pwm_ops {
-       int                     (*request)(struct pwm_chip *chip,
-                                          struct pwm_device *pwm);
-       void                    (*free)(struct pwm_chip *chip,
-                                       struct pwm_device *pwm);
-       int                     (*config)(struct pwm_chip *chip,
-                                         struct pwm_device *pwm,
-                                         int duty_ns, int period_ns);
-       int                     (*set_polarity)(struct pwm_chip *chip,
-                                         struct pwm_device *pwm,
-                                         enum pwm_polarity polarity);
-       int                     (*enable)(struct pwm_chip *chip,
-                                         struct pwm_device *pwm);
-       void                    (*disable)(struct pwm_chip *chip,
-                                          struct pwm_device *pwm);
+       int (*request)(struct pwm_chip *chip, struct pwm_device *pwm);
+       void (*free)(struct pwm_chip *chip, struct pwm_device *pwm);
+       int (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
+                     int duty_ns, int period_ns);
+       int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm,
+                           enum pwm_polarity polarity);
+       int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
+       void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
 #ifdef CONFIG_DEBUG_FS
-       void                    (*dbg_show)(struct pwm_chip *chip,
-                                           struct seq_file *s);
+       void (*dbg_show)(struct pwm_chip *chip, struct seq_file *s);
 #endif
-       struct module           *owner;
+       struct module *owner;
 };
 
 /**
@@ -160,22 +175,24 @@ struct pwm_ops {
  * @base: number of first PWM controlled by this chip
  * @npwm: number of PWMs controlled by this chip
  * @pwms: array of PWM devices allocated by the framework
+ * @of_xlate: request a PWM device given a device tree PWM specifier
+ * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
  * @can_sleep: must be true if the .config(), .enable() or .disable()
  *             operations may sleep
  */
 struct pwm_chip {
-       struct device           *dev;
-       struct list_head        list;
-       const struct pwm_ops    *ops;
-       int                     base;
-       unsigned int            npwm;
-
-       struct pwm_device       *pwms;
-
-       struct pwm_device *     (*of_xlate)(struct pwm_chip *pc,
-                                           const struct of_phandle_args *args);
-       unsigned int            of_pwm_n_cells;
-       bool                    can_sleep;
+       struct device *dev;
+       struct list_head list;
+       const struct pwm_ops *ops;
+       int base;
+       unsigned int npwm;
+
+       struct pwm_device *pwms;
+
+       struct pwm_device * (*of_xlate)(struct pwm_chip *pc,
+                                       const struct of_phandle_args *args);
+       unsigned int of_pwm_n_cells;
+       bool can_sleep;
 };
 
 #if IS_ENABLED(CONFIG_PWM)