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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAlvcT08ZHHRoaWVycnku
 cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zoRZ4D/9JewpxTGItNlmgRbrKU2vG
 IN5B13z/bEUQo3DS0bsqPqso6kma++Y2JJSs6/qABcjvvigAl9/HTzsP1ooJngmg
 3VfEXG6r7q6dA+ckqtIyti/VQ57mLmbSGjp8Y5BfA57hfrbTcKEWSjt5JynJodcR
 byOAMazpA+T28Vh4b1ickdztQ92vxe8NrHLHWXzWTePbSuFCeTQ+RjYaKQk3VPsk
 kIajkvR2cufxiTY/pBoqJrheNt3W2QY36Lzx8UbVK3vftzFBsBzwepzvO2RAk/D2
 lvdGMhOPlDkk8KNaKftbtYct43pAzNfgxjfvRTJP5/+1Sr50FJtQDHYDKEm1qOsn
 Z2BZ0rCuAYlu6XITSjYaEfyyrrTpd+Gl7WhSUYnu1Esbv33xD530ALU5MzaU0YD/
 yuJCqi5ddojJ2/3uOssDuA3cYdoZnQCzODKWWnH8JjGKas9s8KdbPp+7r9Inb8OX
 uVZM4L3k1ZtAyo/JgtwTK+/fog1ulDI1+L3oNgdFNzCS5Kv67AsZyA9SczI8itwn
 qdP0ZhQi5ZfmcuadynNy5qAtsZQk9w/i/fij/Rd/PoQOAzRymQJExeVDaDSd50qd
 A0jlw3Tw/WDY3YQpnW/555YH4z480smHAvO9tDZFINMD26gy3x+GaFAlUZKLLggp
 Oc39LyR4I6Z6rpPHCf1A0Q==
 =AECG
 -----END PGP SIGNATURE-----

Merge tag 'pwm/for-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

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
This commit is contained in:
Linus Torvalds 2018-11-02 11:22:45 -07:00
Родитель 0b21f21ae0 2153bbc12f
Коммит fcc37f76a9
12 изменённых файлов: 110 добавлений и 38 удалений

Просмотреть файл

@ -7,6 +7,7 @@ Required properties:
for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap"; for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
for 66ak2g - compatible = "ti,k2g-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 - #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 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. cell flag supported by this binding is PWM_POLARITY_INVERTED.

Просмотреть файл

@ -3,7 +3,9 @@
Required Properties: Required Properties:
- compatible: should be "renesas,pwm-rcar" and one of the following. - compatible: should be "renesas,pwm-rcar" and one of the following.
- "renesas,pwm-r8a7743": for RZ/G1M - "renesas,pwm-r8a7743": for RZ/G1M
- "renesas,pwm-r8a7744": for RZ/G1N
- "renesas,pwm-r8a7745": for RZ/G1E - "renesas,pwm-r8a7745": for RZ/G1E
- "renesas,pwm-r8a774a1": for RZ/G2M
- "renesas,pwm-r8a7778": for R-Car M1A - "renesas,pwm-r8a7778": for R-Car M1A
- "renesas,pwm-r8a7779": for R-Car H1 - "renesas,pwm-r8a7779": for R-Car H1
- "renesas,pwm-r8a7790": for R-Car H2 - "renesas,pwm-r8a7790": for R-Car H2
@ -12,6 +14,8 @@ Required Properties:
- "renesas,pwm-r8a7795": for R-Car H3 - "renesas,pwm-r8a7795": for R-Car H3
- "renesas,pwm-r8a7796": for R-Car M3-W - "renesas,pwm-r8a7796": for R-Car M3-W
- "renesas,pwm-r8a77965": for R-Car M3-N - "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-r8a77990": for R-Car E3
- "renesas,pwm-r8a77995": for R-Car D3 - "renesas,pwm-r8a77995": for R-Car D3
- reg: base address and length of the registers block for the PWM. - reg: base address and length of the registers block for the PWM.

Просмотреть файл

@ -2,13 +2,19 @@
Required Properties: 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-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible PWM controller.
- "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) 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-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-r8a7745": for R8A7745 (RZ/G1E) compatible PWM controller.
- "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) 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 - reg: Base address and length of each memory resource used by the PWM
controller hardware module. controller hardware module.

Просмотреть файл

@ -126,6 +126,7 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
return 0; return 0;
} }
EXPORT_SYMBOL(acpi_device_get_power);
static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state) static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
{ {

Просмотреть файл

@ -447,10 +447,9 @@ config PWM_TEGRA
config PWM_TIECAP config PWM_TIECAP
tristate "ECAP PWM support" 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 help
PWM driver support for the ECAP APWM controller found on AM33XX PWM driver support for the ECAP APWM controller found on TI SOCs
TI SOC
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called pwm-tiecap. will be called pwm-tiecap.

Просмотреть файл

@ -30,6 +30,7 @@ static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
.clk_rate = 19200000, .clk_rate = 19200000,
.npwm = 1, .npwm = 1,
.base_unit_bits = 16, .base_unit_bits = 16,
.other_devices_aml_touches_pwm_regs = true,
}; };
/* Broxton */ /* Broxton */
@ -60,6 +61,7 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
platform_set_drvdata(pdev, lpwm); platform_set_drvdata(pdev, lpwm);
dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&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); return pwm_lpss_remove(lpwm);
} }
static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops, static int pwm_lpss_prepare(struct device *dev)
pwm_lpss_suspend, {
pwm_lpss_resume); 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[] = { static const struct acpi_device_id pwm_lpss_acpi_match[] = {
{ "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80860F09", (unsigned long)&pwm_lpss_byt_info },
{ "80862288", (unsigned long)&pwm_lpss_bsw_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info },
{ "80862289", (unsigned long)&pwm_lpss_bsw_info },
{ "80865AC8", (unsigned long)&pwm_lpss_bxt_info }, { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
{ }, { },
}; };

Просмотреть файл

@ -32,15 +32,6 @@
/* Size of each PWM register space if multiple */ /* Size of each PWM register space if multiple */
#define PWM_SIZE 0x400 #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) static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
{ {
return container_of(chip, struct pwm_lpss_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 long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range; unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC; unsigned long long base_unit, freq = NSEC_PER_SEC;
u32 ctrl; u32 orig_ctrl, ctrl;
do_div(freq, period_ns); 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); do_div(on_time_div, period_ns);
on_time_div = 255ULL - on_time_div; 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 &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT); ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
base_unit &= base_unit_range; base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div; 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) 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; return ret;
} }
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); 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); pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm); ret = pwm_lpss_wait_for_update(pwm);
if (ret) { if (ret) {
@ -157,7 +151,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret) if (ret)
return ret; return ret;
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); 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); return pwm_lpss_wait_for_update(pwm);
} }
} else if (pwm_is_enabled(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; 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 = { static const struct pwm_ops pwm_lpss_ops = {
.apply = pwm_lpss_apply, .apply = pwm_lpss_apply,
.get_state = pwm_lpss_get_state,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
@ -214,6 +241,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 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); return pwmchip_remove(&lpwm->chip);
} }
EXPORT_SYMBOL_GPL(pwm_lpss_remove); EXPORT_SYMBOL_GPL(pwm_lpss_remove);

Просмотреть файл

@ -16,13 +16,25 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/pwm.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 { struct pwm_lpss_boardinfo {
unsigned long clk_rate; unsigned long clk_rate;
unsigned int npwm; unsigned int npwm;
unsigned long base_unit_bits; unsigned long base_unit_bits;
bool bypass; 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, struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,

Просмотреть файл

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* R-Car PWM Timer driver * R-Car PWM Timer driver
* *
* Copyright (C) 2015 Renesas Electronics Corporation * 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> #include <linux/clk.h>

Просмотреть файл

@ -1,16 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* R-Mobile TPU PWM driver * R-Mobile TPU PWM driver
* *
* Copyright (C) 2012 Renesas Solutions Corp. * 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> #include <linux/clk.h>

Просмотреть файл

@ -300,7 +300,6 @@ static const struct of_device_id tegra_pwm_of_match[] = {
{ .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc }, { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
static const struct dev_pm_ops tegra_pwm_pm_ops = { static const struct dev_pm_ops tegra_pwm_pm_ops = {

Просмотреть файл

@ -249,6 +249,7 @@ static void pwm_export_release(struct device *child)
static int pwm_export_child(struct device *parent, struct pwm_device *pwm) static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
{ {
struct pwm_export *export; struct pwm_export *export;
char *pwm_prop[2];
int ret; int ret;
if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) 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; export->pwm = pwm;
mutex_init(&export->lock); mutex_init(&export->lock);
export->child.class = parent->class;
export->child.release = pwm_export_release; export->child.release = pwm_export_release;
export->child.parent = parent; export->child.parent = parent;
export->child.devt = MKDEV(0, 0); export->child.devt = MKDEV(0, 0);
@ -277,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
export = NULL; export = NULL;
return ret; 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; 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) static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
{ {
struct device *child; struct device *child;
char *pwm_prop[2];
if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
return -ENODEV; return -ENODEV;
@ -297,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
if (!child) if (!child)
return -ENODEV; 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() */ /* for device_find_child() */
put_device(child); put_device(child);
device_unregister(child); device_unregister(child);