Skip to content

Commit

Permalink
Merge tag 'pwm/for-4.20-rc1' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/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
  • Loading branch information
Linus Torvalds committed Nov 2, 2018
2 parents 0b21f21 + 2153bbc commit fcc37f7
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 38 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
10 changes: 8 additions & 2 deletions Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
5 changes: 2 additions & 3 deletions drivers/pwm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
24 changes: 21 additions & 3 deletions drivers/pwm/pwm-lpss-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand All @@ -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 },
{ },
};
Expand Down
61 changes: 47 additions & 14 deletions drivers/pwm/pwm-lpss.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@
/* 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);
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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)) {
Expand All @@ -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,
};

Expand Down Expand Up @@ -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);
Expand Down
14 changes: 13 additions & 1 deletion drivers/pwm/pwm-lpss.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,25 @@
#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,
Expand Down
5 changes: 1 addition & 4 deletions drivers/pwm/pwm-rcar.c
Original file line number Diff line number Diff line change
@@ -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>
Expand Down
10 changes: 1 addition & 9 deletions drivers/pwm/pwm-renesas-tpu.c
Original file line number Diff line number Diff line change
@@ -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>
Expand Down
1 change: 0 additions & 1 deletion drivers/pwm/pwm-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
12 changes: 11 additions & 1 deletion drivers/pwm/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand Down

0 comments on commit fcc37f7

Please sign in to comment.