Commit 75bdc929 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'pwm/for-5.7-rc1' of...

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

Pull pwm updates from Thierry Reding:
 "There's quite a few changes this time around.

  Most of these are fixes and cleanups, but there's also new chip
  support for some drivers and a bit of rework"

* tag 'pwm/for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (33 commits)
  pwm: pca9685: Fix PWM/GPIO inter-operation
  pwm: Make pwm_apply_state_debug() static
  pwm: meson: Remove redundant assignment to variable fin_freq
  pwm: jz4740: Allow selection of PWM channels 0 and 1
  pwm: jz4740: Obtain regmap from parent node
  pwm: jz4740: Improve algorithm of clock calculation
  pwm: jz4740: Use clocks from TCU driver
  pwm: sun4i: Remove redundant needs_delay
  pwm: omap-dmtimer: Implement .apply callback
  pwm: omap-dmtimer: Do not disable PWM before changing period/duty_cycle
  pwm: omap-dmtimer: Fix PWM enabling sequence
  pwm: omap-dmtimer: Update description for PWM OMAP DM timer
  pwm: omap-dmtimer: Drop unused header file
  pwm: renesas-tpu: Drop confusing registered message
  pwm: renesas-tpu: Fix late Runtime PM enablement
  pwm: rcar: Fix late Runtime PM enablement
  dt-bindings: pwm: renesas-tpu: Document more R-Car Gen2 support
  pwm: meson: Fix confusing indentation
  pwm: pca9685: Use gpio core provided macro GPIO_LINE_DIRECTION_OUT
  pwm: pca9685: Replace CONFIG_PM with __maybe_unused
  ...
parents 6900433e 9cc5f232
Loading
Loading
Loading
Loading
+0 −23
Original line number Diff line number Diff line
* PWM controlled by ChromeOS EC

Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
(EC) and controlled via a host-command interface.

An EC PWM node should be only found as a sub-node of the EC node (see
Documentation/devicetree/bindings/mfd/cros-ec.txt).

Required properties:
- compatible: Must contain "google,cros-ec-pwm"
- #pwm-cells: Should be 1. The cell specifies the PWM index.

Example:
	cros-ec@0 {
		compatible = "google,cros-ec-spi";

		...

		cros_ec_pwm: ec-pwm {
			compatible = "google,cros-ec-pwm";
			#pwm-cells = <1>;
		};
	};
+40 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/pwm/google,cros-ec-pwm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: PWM controlled by ChromeOS EC

maintainers:
  - Thierry Reding <thierry.reding@gmail.com>
  - '"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>'

description: |
  Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
  (EC) and controlled via a host-command interface.
  An EC PWM node should be only found as a sub-node of the EC node (see
  Documentation/devicetree/bindings/mfd/cros-ec.txt).

properties:
  compatible:
    const: google,cros-ec-pwm
  "#pwm-cells":
    description: The cell specifies the PWM index.
    const: 1

required:
  - compatible
  - '#pwm-cells'

additionalProperties: false

examples:
  - |
    cros-ec@0 {
        compatible = "google,cros-ec-spi";
        cros_ec_pwm: ec-pwm {
            compatible = "google,cros-ec-pwm";
            #pwm-cells = <1>;
        };
    };
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ Required properties:
  - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132
  - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
  - "nvidia,tegra186-pwm": for Tegra186
  - "nvidia,tegra194-pwm": for Tegra194
- reg: physical base address and length of the controller's registers
- #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
  the cells format.
+36 −22
Original line number Diff line number Diff line
@@ -33,6 +33,15 @@ config PWM_SYSFS
	bool
	default y if SYSFS

config PWM_DEBUG
	bool "PWM lowlevel drivers additional checks and debug messages"
	depends on DEBUG_KERNEL
	help
	  This option enables some additional checks to help lowlevel driver
	  authors to get their callbacks implemented correctly.
	  It is expected to introduce some runtime overhead and diagnostic
	  output to the kernel log, so only enable while working on a driver.

config PWM_AB8500
	tristate "AB8500 PWM support"
	depends on AB8500_CORE && ARCH_U8500
@@ -44,7 +53,8 @@ config PWM_AB8500

config PWM_ATMEL
	tristate "Atmel PWM support"
	depends on ARCH_AT91 && OF
	depends on OF
	depends on ARCH_AT91 || COMPILE_TEST
	help
	  Generic PWM framework driver for Atmel SoC.

@@ -100,7 +110,7 @@ config PWM_BCM_KONA

config PWM_BCM2835
	tristate "BCM2835 PWM support"
	depends on ARCH_BCM2835 || ARCH_BRCMSTB
	depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
	help
	  PWM framework driver for BCM2835 controller (Raspberry Pi)

@@ -109,7 +119,7 @@ config PWM_BCM2835

config PWM_BERLIN
	tristate "Marvell Berlin PWM support"
	depends on ARCH_BERLIN
	depends on ARCH_BERLIN || COMPILE_TEST
	help
	  PWM framework driver for Marvell Berlin SoCs.

@@ -118,7 +128,7 @@ config PWM_BERLIN

config PWM_BRCMSTB
	tristate "Broadcom STB PWM support"
	depends on ARCH_BRCMSTB || BMIPS_GENERIC
	depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
	help
	  Generic PWM framework driver for the Broadcom Set-top-Box
	  SoCs (BCM7xxx).
@@ -152,7 +162,7 @@ config PWM_CROS_EC

config PWM_EP93XX
	tristate "Cirrus Logic EP93xx PWM support"
	depends on ARCH_EP93XX
	depends on ARCH_EP93XX || COMPILE_TEST
	help
	  Generic PWM framework driver for Cirrus Logic EP93xx.

@@ -195,7 +205,7 @@ config PWM_IMG

config PWM_IMX1
	tristate "i.MX1 PWM support"
	depends on ARCH_MXC
	depends on ARCH_MXC || COMPILE_TEST
	help
	  Generic PWM framework driver for i.MX1 and i.MX21

@@ -204,7 +214,7 @@ config PWM_IMX1

config PWM_IMX27
	tristate "i.MX27 PWM support"
	depends on ARCH_MXC
	depends on ARCH_MXC || COMPILE_TEST
	help
	  Generic PWM framework driver for i.MX27 and later i.MX SoCs.

@@ -225,6 +235,8 @@ config PWM_IMX_TPM
config PWM_JZ4740
	tristate "Ingenic JZ47xx PWM support"
	depends on MACH_INGENIC
	depends on COMMON_CLK
	select MFD_SYSCON
	help
	  Generic PWM framework driver for Ingenic JZ47xx based
	  machines.
@@ -244,7 +256,7 @@ config PWM_LP3943

config PWM_LPC18XX_SCT
	tristate "LPC18xx/43xx PWM/SCT support"
	depends on ARCH_LPC18XX
	depends on ARCH_LPC18XX || COMPILE_TEST
	help
	  Generic PWM framework driver for NXP LPC18xx PWM/SCT which
	  supports 16 channels.
@@ -256,7 +268,7 @@ config PWM_LPC18XX_SCT

config PWM_LPC32XX
	tristate "LPC32XX PWM support"
	depends on ARCH_LPC32XX
	depends on ARCH_LPC32XX || COMPILE_TEST
	help
	  Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two
	  PWM controllers.
@@ -289,7 +301,8 @@ config PWM_LPSS_PLATFORM

config PWM_MESON
	tristate "Amlogic Meson PWM driver"
	depends on ARCH_MESON
	depends on ARCH_MESON || COMPILE_TEST
	depends on COMMON_CLK
	help
	  The platform driver for Amlogic Meson PWM controller.

@@ -318,7 +331,8 @@ config PWM_MEDIATEK

config PWM_MXS
	tristate "Freescale MXS PWM support"
	depends on ARCH_MXS && OF
	depends on OF
	depends on ARCH_MXS || COMPILE_TEST
	select STMP_DEVICE
	help
	  Generic PWM framework driver for Freescale MXS.
@@ -357,7 +371,7 @@ config PWM_PUV3

config PWM_PXA
	tristate "PXA PWM support"
	depends on ARCH_PXA
	depends on ARCH_PXA || COMPILE_TEST
	help
	  Generic PWM framework driver for PXA.

@@ -388,14 +402,14 @@ config PWM_RENESAS_TPU

config PWM_ROCKCHIP
	tristate "Rockchip PWM support"
	depends on ARCH_ROCKCHIP
	depends on ARCH_ROCKCHIP || COMPILE_TEST
	help
	  Generic PWM framework driver for the PWM controller found on
	  Rockchip SoCs.

config PWM_SAMSUNG
	tristate "Samsung PWM support"
	depends on PLAT_SAMSUNG || ARCH_EXYNOS
	depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
	help
	  Generic PWM framework driver for Samsung.

@@ -415,7 +429,7 @@ config PWM_SIFIVE

config PWM_SPEAR
	tristate "STMicroelectronics SPEAr PWM support"
	depends on PLAT_SPEAR
	depends on PLAT_SPEAR || COMPILE_TEST
	depends on OF
	help
	  Generic PWM framework driver for the PWM controller on ST
@@ -437,7 +451,7 @@ config PWM_SPRD

config PWM_STI
	tristate "STiH4xx PWM support"
	depends on ARCH_STI
	depends on ARCH_STI || COMPILE_TEST
	depends on OF
	help
	  Generic PWM framework driver for STiH4xx SoCs.
@@ -447,7 +461,7 @@ config PWM_STI

config PWM_STM32
	tristate "STMicroelectronics STM32 PWM"
	depends on MFD_STM32_TIMERS
	depends on MFD_STM32_TIMERS || COMPILE_TEST
	help
	  Generic PWM framework driver for STM32 SoCs.

@@ -483,7 +497,7 @@ config PWM_SUN4I

config PWM_TEGRA
	tristate "NVIDIA Tegra PWM support"
	depends on ARCH_TEGRA
	depends on ARCH_TEGRA || COMPILE_TEST
	help
	  Generic PWM framework driver for the PWFM controller found on NVIDIA
	  Tegra SoCs.
@@ -493,7 +507,7 @@ config PWM_TEGRA

config PWM_TIECAP
	tristate "ECAP PWM support"
	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
	help
	  PWM driver support for the ECAP APWM controller found on TI SOCs

@@ -502,7 +516,7 @@ config PWM_TIECAP

config PWM_TIEHRPWM
	tristate "EHRPWM PWM support"
	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3
	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 || COMPILE_TEST
	help
	  PWM driver support for the EHRPWM controller found on TI SOCs

@@ -529,7 +543,7 @@ config PWM_TWL_LED

config PWM_VT8500
	tristate "vt8500 PWM support"
	depends on ARCH_VT8500
	depends on ARCH_VT8500 || COMPILE_TEST
	help
	  Generic PWM framework driver for vt8500.

@@ -538,7 +552,7 @@ config PWM_VT8500

config PWM_ZX
	tristate "ZTE ZX PWM support"
	depends on ARCH_ZX
	depends on ARCH_ZX || COMPILE_TEST
	help
	  Generic PWM framework driver for ZTE ZX family SoCs.

+128 −7
Original line number Diff line number Diff line
@@ -120,6 +120,9 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
	if (pwm->chip->ops->get_state) {
		pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state);
		trace_pwm_get(pwm, &pwm->state);

		if (IS_ENABLED(PWM_DEBUG))
			pwm->last = pwm->state;
	}

	set_bit(PWMF_REQUESTED, &pwm->flags);
@@ -232,17 +235,28 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
}
EXPORT_SYMBOL_GPL(pwm_get_chip_data);

static bool pwm_ops_check(const struct pwm_ops *ops)
static bool pwm_ops_check(const struct pwm_chip *chip)
{

	const struct pwm_ops *ops = chip->ops;

	/* driver supports legacy, non-atomic operation */
	if (ops->config && ops->enable && ops->disable)
		return true;
	if (ops->config && ops->enable && ops->disable) {
		if (IS_ENABLED(CONFIG_PWM_DEBUG))
			dev_warn(chip->dev,
				 "Driver needs updating to atomic API\n");

	/* driver supports atomic operation */
	if (ops->apply)
		return true;
	}

	if (!ops->apply)
		return false;

	if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
		dev_warn(chip->dev,
			 "Please implement the .get_state() callback\n");

	return true;
}

/**
@@ -266,7 +280,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
		return -EINVAL;

	if (!pwm_ops_check(chip->ops))
	if (!pwm_ops_check(chip))
		return -EINVAL;

	mutex_lock(&pwm_lock);
@@ -450,6 +464,107 @@ void pwm_free(struct pwm_device *pwm)
}
EXPORT_SYMBOL_GPL(pwm_free);

static void pwm_apply_state_debug(struct pwm_device *pwm,
				  const struct pwm_state *state)
{
	struct pwm_state *last = &pwm->last;
	struct pwm_chip *chip = pwm->chip;
	struct pwm_state s1, s2;
	int err;

	if (!IS_ENABLED(CONFIG_PWM_DEBUG))
		return;

	/* No reasonable diagnosis possible without .get_state() */
	if (!chip->ops->get_state)
		return;

	/*
	 * *state was just applied. Read out the hardware state and do some
	 * checks.
	 */

	chip->ops->get_state(chip, pwm, &s1);
	trace_pwm_get(pwm, &s1);

	/*
	 * The lowlevel driver either ignored .polarity (which is a bug) or as
	 * best effort inverted .polarity and fixed .duty_cycle respectively.
	 * Undo this inversion and fixup for further tests.
	 */
	if (s1.enabled && s1.polarity != state->polarity) {
		s2.polarity = state->polarity;
		s2.duty_cycle = s1.period - s1.duty_cycle;
		s2.period = s1.period;
		s2.enabled = s1.enabled;
	} else {
		s2 = s1;
	}

	if (s2.polarity != state->polarity &&
	    state->duty_cycle < state->period)
		dev_warn(chip->dev, ".apply ignored .polarity\n");

	if (state->enabled &&
	    last->polarity == state->polarity &&
	    last->period > s2.period &&
	    last->period <= state->period)
		dev_warn(chip->dev,
			 ".apply didn't pick the best available period (requested: %u, applied: %u, possible: %u)\n",
			 state->period, s2.period, last->period);

	if (state->enabled && state->period < s2.period)
		dev_warn(chip->dev,
			 ".apply is supposed to round down period (requested: %u, applied: %u)\n",
			 state->period, s2.period);

	if (state->enabled &&
	    last->polarity == state->polarity &&
	    last->period == s2.period &&
	    last->duty_cycle > s2.duty_cycle &&
	    last->duty_cycle <= state->duty_cycle)
		dev_warn(chip->dev,
			 ".apply didn't pick the best available duty cycle (requested: %u/%u, applied: %u/%u, possible: %u/%u)\n",
			 state->duty_cycle, state->period,
			 s2.duty_cycle, s2.period,
			 last->duty_cycle, last->period);

	if (state->enabled && state->duty_cycle < s2.duty_cycle)
		dev_warn(chip->dev,
			 ".apply is supposed to round down duty_cycle (requested: %u/%u, applied: %u/%u)\n",
			 state->duty_cycle, state->period,
			 s2.duty_cycle, s2.period);

	if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
		dev_warn(chip->dev,
			 "requested disabled, but yielded enabled with duty > 0");

	/* reapply the state that the driver reported being configured. */
	err = chip->ops->apply(chip, pwm, &s1);
	if (err) {
		*last = s1;
		dev_err(chip->dev, "failed to reapply current setting\n");
		return;
	}

	trace_pwm_apply(pwm, &s1);

	chip->ops->get_state(chip, pwm, last);
	trace_pwm_get(pwm, last);

	/* reapplication of the current state should give an exact match */
	if (s1.enabled != last->enabled ||
	    s1.polarity != last->polarity ||
	    (s1.enabled && s1.period != last->period) ||
	    (s1.enabled && s1.duty_cycle != last->duty_cycle)) {
		dev_err(chip->dev,
			".apply is not idempotent (ena=%d pol=%d %u/%u) -> (ena=%d pol=%d %u/%u)\n",
			s1.enabled, s1.polarity, s1.duty_cycle, s1.period,
			last->enabled, last->polarity, last->duty_cycle,
			last->period);
	}
}

/**
 * pwm_apply_state() - atomically apply a new state to a PWM device
 * @pwm: PWM device
@@ -480,6 +595,12 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
		trace_pwm_apply(pwm, state);

		pwm->state = *state;

		/*
		 * only do this after pwm->state was applied as some
		 * implementations of .get_state depend on this
		 */
		pwm_apply_state_debug(pwm, state);
	} else {
		/*
		 * FIXME: restore the initial state in case of error.
Loading