Merge tag 'pwm/for-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Nov 2018 18:22:45 +0000 (11:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Nov 2018 18:22:45 +0000 (11:22 -0700)
Pull pwm updates from Thierry Reding:
 "This series contains a number of improvements to existing drivers,
  such as LPSS. Some drivers, such as renesas-tpu and rcar get support
  for more SoC generations. To round things off this fixes an issue with
  the sysfs interface"

* tag 'pwm/for-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: lpss: Only set update bit if we are actually changing the settings
  pwm: lpss: Force runtime-resume on suspend on Cherry Trail
  pwm: Enable TI ECAP driver for ARCH_K3
  dt-bindings: pwm: tiecap: Add TI AM654 SoC specific compatible
  dt-bindings: pwm: rcar: Add r8a774a1 support
  pwm: Send a uevent on the pwmchip device upon channel sysfs (un)export
  Revert "pwm: Set class for exported channels in sysfs"
  dt-bindings: pwm: renesas-tpu: Document r8a7744 support
  dt-bindings: pwm: rcar: Add r8a7744 support
  dt-bindings: pwm: renesas: tpu: Document R8A779{7|8}0 bindings
  dt-bindings: pwm: renesas: pwm-rcar: Document R8A779{7|8}0 bindings
  dt-bindings: pwm: renesas: tpu: Fix "compatible" prop description
  pwm: Use SPDX identifier for Renesas drivers
  pwm: lpss: Add get_state callback
  pwm: lpss: Release runtime-pm reference from the driver's remove callback
  pwm: lpss: Check PWM powerstate after resume on Cherry Trail devices
  pwm: lpss: Move struct pwm_lpss_chip definition to the header file
  pwm: lpss: Add ACPI HID for second PWM controller on Cherry Trail devices
  ACPI / PM: Export acpi_device_get_power() for use by modular build drivers
  pwm: tegra: Remove gratuituous blank line

12 files changed:
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
drivers/acpi/device_pm.c
drivers/pwm/Kconfig
drivers/pwm/pwm-lpss-platform.c
drivers/pwm/pwm-lpss.c
drivers/pwm/pwm-lpss.h
drivers/pwm/pwm-rcar.c
drivers/pwm/pwm-renesas-tpu.c
drivers/pwm/pwm-tegra.c
drivers/pwm/sysfs.c

index 06a363d9ccef9069124ae813bfb449d8cab182c7..b9a1d7402128b95437341b1e2d16d516fddfa114 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
   for da850  - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
   for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
   for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
+  for am654  - compatible = "ti,am654-ecap", "ti,am3352-ecap";
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The PWM channel index ranges from 0 to 4. The only third
   cell flag supported by this binding is PWM_POLARITY_INVERTED.
index e1ef6afbe3a74a89d9040b9d6642cd2c22aa2a0c..7f31fe7e209348ceb04a471e08be0f60b4fff65d 100644 (file)
@@ -3,7 +3,9 @@
 Required Properties:
 - compatible: should be "renesas,pwm-rcar" and one of the following.
  - "renesas,pwm-r8a7743": for RZ/G1M
+ - "renesas,pwm-r8a7744": for RZ/G1N
  - "renesas,pwm-r8a7745": for RZ/G1E
+ - "renesas,pwm-r8a774a1": for RZ/G2M
  - "renesas,pwm-r8a7778": for R-Car M1A
  - "renesas,pwm-r8a7779": for R-Car H1
  - "renesas,pwm-r8a7790": for R-Car H2
@@ -12,6 +14,8 @@ Required Properties:
  - "renesas,pwm-r8a7795": for R-Car H3
  - "renesas,pwm-r8a7796": for R-Car M3-W
  - "renesas,pwm-r8a77965": for R-Car M3-N
+ - "renesas,pwm-r8a77970": for R-Car V3M
+ - "renesas,pwm-r8a77980": for R-Car V3H
  - "renesas,pwm-r8a77990": for R-Car E3
  - "renesas,pwm-r8a77995": for R-Car D3
 - reg: base address and length of the registers block for the PWM.
index d53a16715da6ac33dea19a4a66ad38310feacc95..848a92b53d810eeb055544cbb037a38a54e05371 100644 (file)
@@ -2,13 +2,19 @@
 
 Required Properties:
 
-  - compatible: should be one of the following.
+  - compatible: must contain one or more of the following:
     - "renesas,tpu-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible PWM controller.
     - "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller.
     - "renesas,tpu-r8a7743": for R8A7743 (RZ/G1M) compatible PWM controller.
+    - "renesas,tpu-r8a7744": for R8A7744 (RZ/G1N) compatible PWM controller.
     - "renesas,tpu-r8a7745": for R8A7745 (RZ/G1E) compatible PWM controller.
     - "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller.
-    - "renesas,tpu": for generic R-Car and RZ/G1 TPU PWM controller.
+    - "renesas,tpu-r8a77970": for R8A77970 (R-Car V3M) compatible PWM
+                             controller.
+    - "renesas,tpu-r8a77980": for R8A77980 (R-Car V3H) compatible PWM
+                             controller.
+    - "renesas,tpu": for the generic TPU PWM controller; this is a fallback for
+                    the entries listed above.
 
   - reg: Base address and length of each memory resource used by the PWM
     controller hardware module.
index a7c2673ffd36e8a8287a40182fae189e6b71688e..824ae985ad93bebacbb70010e2e2c632a3d143a8 100644 (file)
@@ -126,6 +126,7 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
 
        return 0;
 }
+EXPORT_SYMBOL(acpi_device_get_power);
 
 static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
 {
index 504d252716f2e10db4914c8de651dff05106b82c..27e5dd47a01f9564fdff4c172be76b9694223e7e 100644 (file)
@@ -447,10 +447,9 @@ config PWM_TEGRA
 
 config  PWM_TIECAP
        tristate "ECAP PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
        help
-         PWM driver support for the ECAP APWM controller found on AM33XX
-         TI SOC
+         PWM driver support for the ECAP APWM controller found on TI SOCs
 
          To compile this driver as a module, choose M here: the module
          will be called pwm-tiecap.
index 5561b9e190f84a63513ff3b86ecbeef7461404e8..757230e1f575e618199d03be157f0b1bf864d243 100644 (file)
@@ -30,6 +30,7 @@ static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
        .clk_rate = 19200000,
        .npwm = 1,
        .base_unit_bits = 16,
+       .other_devices_aml_touches_pwm_regs = true,
 };
 
 /* Broxton */
@@ -60,6 +61,7 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, lpwm);
 
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
@@ -74,13 +76,29 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev)
        return pwm_lpss_remove(lpwm);
 }
 
-static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops,
-                        pwm_lpss_suspend,
-                        pwm_lpss_resume);
+static int pwm_lpss_prepare(struct device *dev)
+{
+       struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
+
+       /*
+        * If other device's AML code touches the PWM regs on suspend/resume
+        * force runtime-resume the PWM controller to allow this.
+        */
+       if (lpwm->info->other_devices_aml_touches_pwm_regs)
+               return 0; /* Force runtime-resume */
+
+       return 1; /* If runtime-suspended leave as is */
+}
+
+static const struct dev_pm_ops pwm_lpss_platform_pm_ops = {
+       .prepare = pwm_lpss_prepare,
+       SET_SYSTEM_SLEEP_PM_OPS(pwm_lpss_suspend, pwm_lpss_resume)
+};
 
 static const struct acpi_device_id pwm_lpss_acpi_match[] = {
        { "80860F09", (unsigned long)&pwm_lpss_byt_info },
        { "80862288", (unsigned long)&pwm_lpss_bsw_info },
+       { "80862289", (unsigned long)&pwm_lpss_bsw_info },
        { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
        { },
 };
index 4721a264bac2580cf8d21ee54396e0b494f1c9dc..2ac3a2aa9e53f5cab594fccdb042c1d77bcafa87 100644 (file)
 /* Size of each PWM register space if multiple */
 #define PWM_SIZE                       0x400
 
-#define MAX_PWMS                       4
-
-struct pwm_lpss_chip {
-       struct pwm_chip chip;
-       void __iomem *regs;
-       const struct pwm_lpss_boardinfo *info;
-       u32 saved_ctrl[MAX_PWMS];
-};
-
 static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
 {
        return container_of(chip, struct pwm_lpss_chip, chip);
@@ -97,7 +88,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
        unsigned long long on_time_div;
        unsigned long c = lpwm->info->clk_rate, base_unit_range;
        unsigned long long base_unit, freq = NSEC_PER_SEC;
-       u32 ctrl;
+       u32 orig_ctrl, ctrl;
 
        do_div(freq, period_ns);
 
@@ -114,13 +105,17 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
        do_div(on_time_div, period_ns);
        on_time_div = 255ULL - on_time_div;
 
-       ctrl = pwm_lpss_read(pwm);
+       orig_ctrl = ctrl = pwm_lpss_read(pwm);
        ctrl &= ~PWM_ON_TIME_DIV_MASK;
        ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
        base_unit &= base_unit_range;
        ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
        ctrl |= on_time_div;
-       pwm_lpss_write(pwm, ctrl);
+
+       if (orig_ctrl != ctrl) {
+               pwm_lpss_write(pwm, ctrl);
+               pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
+       }
 }
 
 static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
@@ -144,7 +139,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                                return ret;
                        }
                        pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
-                       pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
                        pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
                        ret = pwm_lpss_wait_for_update(pwm);
                        if (ret) {
@@ -157,7 +151,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                        if (ret)
                                return ret;
                        pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
-                       pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
                        return pwm_lpss_wait_for_update(pwm);
                }
        } else if (pwm_is_enabled(pwm)) {
@@ -168,8 +161,42 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        return 0;
 }
 
+/* This function gets called once from pwmchip_add to get the initial state */
+static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+                              struct pwm_state *state)
+{
+       struct pwm_lpss_chip *lpwm = to_lpwm(chip);
+       unsigned long base_unit_range;
+       unsigned long long base_unit, freq, on_time_div;
+       u32 ctrl;
+
+       base_unit_range = BIT(lpwm->info->base_unit_bits);
+
+       ctrl = pwm_lpss_read(pwm);
+       on_time_div = 255 - (ctrl & PWM_ON_TIME_DIV_MASK);
+       base_unit = (ctrl >> PWM_BASE_UNIT_SHIFT) & (base_unit_range - 1);
+
+       freq = base_unit * lpwm->info->clk_rate;
+       do_div(freq, base_unit_range);
+       if (freq == 0)
+               state->period = NSEC_PER_SEC;
+       else
+               state->period = NSEC_PER_SEC / (unsigned long)freq;
+
+       on_time_div *= state->period;
+       do_div(on_time_div, 255);
+       state->duty_cycle = on_time_div;
+
+       state->polarity = PWM_POLARITY_NORMAL;
+       state->enabled = !!(ctrl & PWM_ENABLE);
+
+       if (state->enabled)
+               pm_runtime_get(chip->dev);
+}
+
 static const struct pwm_ops pwm_lpss_ops = {
        .apply = pwm_lpss_apply,
+       .get_state = pwm_lpss_get_state,
        .owner = THIS_MODULE,
 };
 
@@ -214,6 +241,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
 
 int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
 {
+       int i;
+
+       for (i = 0; i < lpwm->info->npwm; i++) {
+               if (pwm_is_enabled(&lpwm->chip.pwms[i]))
+                       pm_runtime_put(lpwm->chip.dev);
+       }
        return pwmchip_remove(&lpwm->chip);
 }
 EXPORT_SYMBOL_GPL(pwm_lpss_remove);
index 7a4238ad1fcb1f25390032019170759c6666ae83..3236be835bd9c948b929cd066ae74feaff2eed73 100644 (file)
 #include <linux/device.h>
 #include <linux/pwm.h>
 
-struct pwm_lpss_chip;
+#define MAX_PWMS                       4
+
+struct pwm_lpss_chip {
+       struct pwm_chip chip;
+       void __iomem *regs;
+       const struct pwm_lpss_boardinfo *info;
+       u32 saved_ctrl[MAX_PWMS];
+};
 
 struct pwm_lpss_boardinfo {
        unsigned long clk_rate;
        unsigned int npwm;
        unsigned long base_unit_bits;
        bool bypass;
+       /*
+        * On some devices the _PS0/_PS3 AML code of the GPU (GFX0) device
+        * messes with the PWM0 controllers state,
+        */
+       bool other_devices_aml_touches_pwm_regs;
 };
 
 struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
index 748f614d53755daabdd9f1529d7ba9cd602cb611..a41812fc6f95733a2568eb0d6b5c7f44fe5a1741 100644 (file)
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * R-Car PWM Timer driver
  *
  * Copyright (C) 2015 Renesas Electronics Corporation
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/clk.h>
index 29267d12fb4c9d3cf9283c38b114b00430704b09..4a855a21b782dea30c8b6e555a76132a3e306deb 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * R-Mobile TPU PWM driver
  *
  * Copyright (C) 2012 Renesas Solutions Corp.
- *
- * 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
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/clk.h>
index f8ebbece57b71ad5f03501304b8144b1341cbe7f..48c4595a0ffcecb815bf641a7ca7ae34f77475cd 100644 (file)
@@ -300,7 +300,6 @@ static const struct of_device_id tegra_pwm_of_match[] = {
        { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
        { }
 };
-
 MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
 
 static const struct dev_pm_ops tegra_pwm_pm_ops = {
index 7c71cdb8a9d8f92102b5875d120b83a3364fb6d0..ceb233dd604840bd2370dbe3c0446a751f22fe6d 100644 (file)
@@ -249,6 +249,7 @@ static void pwm_export_release(struct device *child)
 static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
 {
        struct pwm_export *export;
+       char *pwm_prop[2];
        int ret;
 
        if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
@@ -263,7 +264,6 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
        export->pwm = pwm;
        mutex_init(&export->lock);
 
-       export->child.class = parent->class;
        export->child.release = pwm_export_release;
        export->child.parent = parent;
        export->child.devt = MKDEV(0, 0);
@@ -277,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
                export = NULL;
                return ret;
        }
+       pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm);
+       pwm_prop[1] = NULL;
+       kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
+       kfree(pwm_prop[0]);
 
        return 0;
 }
@@ -289,6 +293,7 @@ static int pwm_unexport_match(struct device *child, void *data)
 static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
 {
        struct device *child;
+       char *pwm_prop[2];
 
        if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
                return -ENODEV;
@@ -297,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
        if (!child)
                return -ENODEV;
 
+       pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm);
+       pwm_prop[1] = NULL;
+       kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
+       kfree(pwm_prop[0]);
+
        /* for device_find_child() */
        put_device(child);
        device_unregister(child);