Commit e492250d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

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

Pull pwm updates from Thierry Reding:
 "This rather small set of changes includes some minor fixes and
  improvements.

  The AB8500 driver gained support for reading the initial hardware
  state and the Synopsys DesignWare driver received some work to prepare
  for device tree and platform support"

* tag 'pwm/for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: dwc: Use devm_pwmchip_add()
  pwm: dwc: Move memory allocation to own function
  pwm: dwc: Change &pci->dev to dev in probe
  dt-bindings: pwm: Document Synopsys DesignWare snps,pwm-dw-apb-timers-pwm2
  pwm: iqs620a: Replace one remaining instance of regmap_update_bits()
  pwm: ab8500: Implement .get_state()
  pwm: ab8500: Fix calculation of duty and period
  pwm: lp3943: Drop unused i2c include
  dt-bindings: pwm: mediatek: Convert pwm-mediatek to DT schema
  pwm: stm32-lp: fix the check on arr and cmp registers update
  pwm: Move pwm_capture() dummy to restore order
  pwm: sifive: Always let the first pwm_apply_state succeed
parents b07ce43d cf70d01a
Loading
Loading
Loading
Loading
+93 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pwm/mediatek,mt2712-pwm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: MediaTek PWM Controller

maintainers:
  - John Crispin <john@phrozen.org>

allOf:
  - $ref: pwm.yaml#

properties:
  compatible:
    oneOf:
      - enum:
          - mediatek,mt2712-pwm
          - mediatek,mt6795-pwm
          - mediatek,mt7622-pwm
          - mediatek,mt7623-pwm
          - mediatek,mt7628-pwm
          - mediatek,mt7629-pwm
          - mediatek,mt8183-pwm
          - mediatek,mt8365-pwm
          - mediatek,mt8516-pwm
      - items:
          - enum:
              - mediatek,mt8195-pwm
          - const: mediatek,mt8183-pwm

  reg:
    maxItems: 1

  "#pwm-cells":
    const: 2

  interrupts:
    maxItems: 1

  clocks:
    minItems: 2
    maxItems: 10

  clock-names:
    description:
      This controller needs two input clocks for its core and one
      clock for each PWM output.
    minItems: 2
    items:
      - const: top
      - const: main
      - const: pwm1
      - const: pwm2
      - const: pwm3
      - const: pwm4
      - const: pwm5
      - const: pwm6
      - const: pwm7
      - const: pwm8

required:
  - compatible
  - reg
  - "#pwm-cells"
  - clocks
  - clock-names

additionalProperties: false

examples:
  - |
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    #include <dt-bindings/clock/mt2712-clk.h>
    #include <dt-bindings/interrupt-controller/irq.h>

    pwm0: pwm@11006000 {
        compatible = "mediatek,mt2712-pwm";
        reg = <0x11006000 0x1000>;
        #pwm-cells = <2>;
        interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_LOW>;
        clocks = <&topckgen CLK_TOP_PWM_SEL>, <&pericfg CLK_PERI_PWM>,
                 <&pericfg CLK_PERI_PWM0>, <&pericfg CLK_PERI_PWM1>,
                 <&pericfg CLK_PERI_PWM2>, <&pericfg CLK_PERI_PWM3>,
                 <&pericfg CLK_PERI_PWM4>, <&pericfg CLK_PERI_PWM5>,
                 <&pericfg CLK_PERI_PWM6>, <&pericfg CLK_PERI_PWM7>;
        clock-names = "top", "main",
                      "pwm1", "pwm2",
                      "pwm3", "pwm4",
                      "pwm5", "pwm6",
                      "pwm7", "pwm8";
    };
+0 −52
Original line number Diff line number Diff line
MediaTek PWM controller

Required properties:
 - compatible: should be "mediatek,<name>-pwm":
   - "mediatek,mt2712-pwm": found on mt2712 SoC.
   - "mediatek,mt6795-pwm": found on mt6795 SoC.
   - "mediatek,mt7622-pwm": found on mt7622 SoC.
   - "mediatek,mt7623-pwm": found on mt7623 SoC.
   - "mediatek,mt7628-pwm": found on mt7628 SoC.
   - "mediatek,mt7629-pwm": found on mt7629 SoC.
   - "mediatek,mt8183-pwm": found on mt8183 SoC.
   - "mediatek,mt8195-pwm", "mediatek,mt8183-pwm": found on mt8195 SoC.
   - "mediatek,mt8365-pwm": found on mt8365 SoC.
   - "mediatek,mt8516-pwm": found on mt8516 SoC.
 - reg: physical base address and length of the controller's registers.
 - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of
   the cell format.
 - clocks: phandle and clock specifier of the PWM reference clock.
 - clock-names: must contain the following, except for MT7628 which
                has no clocks
   - "top": the top clock generator
   - "main": clock used by the PWM core
   - "pwm1-3": the three per PWM clocks for mt8365
   - "pwm1-8": the eight per PWM clocks for mt2712
   - "pwm1-6": the six per PWM clocks for mt7622
   - "pwm1-5": the five per PWM clocks for mt7623
   - "pwm1"  : the PWM1 clock for mt7629
 - pinctrl-names: Must contain a "default" entry.
 - pinctrl-0: One property must exist for each entry in pinctrl-names.
   See pinctrl/pinctrl-bindings.txt for details of the property values.

Optional properties:
- assigned-clocks: Reference to the PWM clock entries.
- assigned-clock-parents: The phandle of the parent clock of PWM clock.

Example:
	pwm0: pwm@11006000 {
		compatible = "mediatek,mt7623-pwm";
		reg = <0 0x11006000 0 0x1000>;
		#pwm-cells = <2>;
		clocks = <&topckgen CLK_TOP_PWM_SEL>,
			 <&pericfg CLK_PERI_PWM>,
			 <&pericfg CLK_PERI_PWM1>,
			 <&pericfg CLK_PERI_PWM2>,
			 <&pericfg CLK_PERI_PWM3>,
			 <&pericfg CLK_PERI_PWM4>,
			 <&pericfg CLK_PERI_PWM5>;
		clock-names = "top", "main", "pwm1", "pwm2",
			      "pwm3", "pwm4", "pwm5";
		pinctrl-names = "default";
		pinctrl-0 = <&pwm0_pins>;
	};
+68 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2022 SiFive, Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/pwm/snps,dw-apb-timers-pwm2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Synopsys DW-APB timers PWM controller

maintainers:
  - Ben Dooks <ben.dooks@sifive.com>

description:
  This describes the DesignWare APB timers module when used in the PWM
  mode. The IP core can be generated with various options which can
  control the functionality, the number of PWMs available and other
  internal controls the designer requires.

  The IP block has a version register so this can be used for detection
  instead of having to encode the IP version number in the device tree
  comaptible.

allOf:
  - $ref: pwm.yaml#

properties:
  compatible:
    const: snps,dw-apb-timers-pwm2

  reg:
    maxItems: 1

  "#pwm-cells":
    const: 3

  clocks:
    items:
      - description: Interface bus clock
      - description: PWM reference clock

  clock-names:
    items:
      - const: bus
      - const: timer

  snps,pwm-number:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: The number of PWM channels configured for this instance
    enum: [1, 2, 3, 4, 5, 6, 7, 8]

required:
  - compatible
  - reg
  - "#pwm-cells"
  - clocks
  - clock-names

additionalProperties: false

examples:
  - |
    pwm: pwm@180000 {
      compatible = "snps,dw-apb-timers-pwm2";
      reg = <0x180000 0x200>;
      #pwm-cells = <3>;
      clocks = <&bus>, <&timer>;
      clock-names = "bus", "timer";
    };
+103 −9
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 * Copyright (C) ST-Ericsson SA 2010
 *
 * Author: Arun R Murthy <arun.murthy@stericsson.com>
 * Datasheet: https://web.archive.org/web/20130614115108/http://www.stericsson.com/developers/CD00291561_UM1031_AB8500_user_manual-rev5_CTDS_public.pdf
 */
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -20,6 +21,8 @@
#define AB8500_PWM_OUT_CTRL2_REG	0x61
#define AB8500_PWM_OUT_CTRL7_REG	0x66

#define AB8500_PWM_CLKRATE 9600000

struct ab8500_pwm_chip {
	struct pwm_chip chip;
	unsigned int hwid;
@@ -35,13 +38,60 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
	int ret;
	u8 reg;
	unsigned int higher_val, lower_val;
	u8 higher_val, lower_val;
	unsigned int duty_steps, div;
	struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);

	if (state->polarity != PWM_POLARITY_NORMAL)
		return -EINVAL;

	if (!state->enabled) {
	if (state->enabled) {
		/*
		 * A time quantum is
		 *   q = (32 - FreqPWMOutx[3:0]) / AB8500_PWM_CLKRATE
		 * The period is always 1024 q, duty_cycle is between 1q and 1024q.
		 *
		 * FreqPWMOutx[3:0] | output frequency | output frequency | 1024q = period
		 *                  | (from manual)    |   (1 / 1024q)    | = 1 / freq
		 * -----------------+------------------+------------------+--------------
		 *      b0000       |      293 Hz      |  292.968750 Hz   | 3413333.33 ns
		 *      b0001       |      302 Hz      |  302.419355 Hz   | 3306666.66 ns
		 *      b0010       |      312 Hz      |  312.500000 Hz   | 3200000    ns
		 *      b0011       |      323 Hz      |  323.275862 Hz   | 3093333.33 ns
		 *      b0100       |      334 Hz      |  334.821429 Hz   | 2986666.66 ns
		 *      b0101       |      347 Hz      |  347.222222 Hz   | 2880000    ns
		 *      b0110       |      360 Hz      |  360.576923 Hz   | 2773333.33 ns
		 *      b0111       |      375 Hz      |  375.000000 Hz   | 2666666.66 ns
		 *      b1000       |      390 Hz      |  390.625000 Hz   | 2560000    ns
		 *      b1001       |      407 Hz      |  407.608696 Hz   | 2453333.33 ns
		 *      b1010       |      426 Hz      |  426.136364 Hz   | 2346666.66 ns
		 *      b1011       |      446 Hz      |  446.428571 Hz   | 2240000    ns
		 *      b1100       |      468 Hz      |  468.750000 Hz   | 2133333.33 ns
		 *      b1101       |      493 Hz      |  493.421053 Hz   | 2026666.66 ns
		 *      b1110       |      520 Hz      |  520.833333 Hz   | 1920000    ns
		 *      b1111       |      551 Hz      |  551.470588 Hz   | 1813333.33 ns
		 *
		 *
		 * AB8500_PWM_CLKRATE is a multiple of 1024, so the division by
		 * 1024 can be done in this factor without loss of precision.
		 */
		div = min_t(u64, mul_u64_u64_div_u64(state->period,
						     AB8500_PWM_CLKRATE >> 10,
						     NSEC_PER_SEC), 32); /* 32 - FreqPWMOutx[3:0] */
		if (div <= 16)
			/* requested period < 3413333.33 */
			return -EINVAL;

		duty_steps = max_t(u64, mul_u64_u64_div_u64(state->duty_cycle,
							    AB8500_PWM_CLKRATE,
							    (u64)NSEC_PER_SEC * div), 1024);
	}

	/*
	 * The hardware doesn't support duty_steps = 0 explicitly, but emits low
	 * when disabled.
	 */
	if (!state->enabled || duty_steps == 0) {
		ret = abx500_mask_and_set_register_interruptible(chip->dev,
					AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
					1 << ab8500->hwid, 0);
@@ -53,28 +103,29 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
	}

	/*
	 * get the first 8 bits that are be written to
	 * The lower 8 bits of duty_steps is written to ...
	 * AB8500_PWM_OUT_CTRL1_REG[0:7]
	 */
	lower_val = state->duty_cycle & 0x00FF;
	lower_val = (duty_steps - 1) & 0x00ff;
	/*
	 * get bits [9:10] that are to be written to
	 * AB8500_PWM_OUT_CTRL2_REG[0:1]
	 * The two remaining high bits to
	 * AB8500_PWM_OUT_CTRL2_REG[0:1]; together with FreqPWMOutx.
	 */
	higher_val = ((state->duty_cycle & 0x0300) >> 8);
	higher_val = ((duty_steps - 1) & 0x0300) >> 8 | (32 - div) << 4;

	reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);

	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
			reg, (u8)lower_val);
			reg, lower_val);
	if (ret < 0)
		return ret;

	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
			(reg + 1), (u8)higher_val);
			(reg + 1), higher_val);
	if (ret < 0)
		return ret;

	/* enable */
	ret = abx500_mask_and_set_register_interruptible(chip->dev,
				AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
				1 << ab8500->hwid, 1 << ab8500->hwid);
@@ -85,8 +136,51 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
	return ret;
}

static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
				struct pwm_state *state)
{
	u8 ctrl7, lower_val, higher_val;
	int ret;
	struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
	unsigned int div, duty_steps;

	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
						AB8500_PWM_OUT_CTRL7_REG,
						&ctrl7);
	if (ret)
		return ret;

	state->polarity = PWM_POLARITY_NORMAL;

	if (!(ctrl7 & 1 << ab8500->hwid)) {
		state->enabled = false;
		return 0;
	}

	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
						AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2),
						&lower_val);
	if (ret)
		return ret;

	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
						AB8500_PWM_OUT_CTRL2_REG + (ab8500->hwid * 2),
						&higher_val);
	if (ret)
		return ret;

	div = 32 - ((higher_val & 0xf0) >> 4);
	duty_steps = ((higher_val & 3) << 8 | lower_val) + 1;

	state->period = DIV64_U64_ROUND_UP((u64)div << 10, AB8500_PWM_CLKRATE);
	state->duty_cycle = DIV64_U64_ROUND_UP((u64)div * duty_steps, AB8500_PWM_CLKRATE);

	return 0;
}

static const struct pwm_ops ab8500_pwm_ops = {
	.apply = ab8500_pwm_apply,
	.get_state = ab8500_pwm_get_state,
	.owner = THIS_MODULE,
};

+21 −17
Original line number Diff line number Diff line
@@ -198,20 +198,35 @@ static const struct pwm_ops dwc_pwm_ops = {
	.owner = THIS_MODULE,
};

static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
{
	struct dwc_pwm *dwc;

	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
	if (!dwc)
		return NULL;

	dwc->chip.dev = dev;
	dwc->chip.ops = &dwc_pwm_ops;
	dwc->chip.npwm = DWC_TIMERS_TOTAL;

	dev_set_drvdata(dev, dwc);
	return dwc;
}

static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
	struct device *dev = &pci->dev;
	struct dwc_pwm *dwc;
	int ret;

	dwc = devm_kzalloc(&pci->dev, sizeof(*dwc), GFP_KERNEL);
	dwc = dwc_pwm_alloc(dev);
	if (!dwc)
		return -ENOMEM;

	ret = pcim_enable_device(pci);
	if (ret) {
		dev_err(&pci->dev,
			"Failed to enable device (%pe)\n", ERR_PTR(ret));
		dev_err(dev, "Failed to enable device (%pe)\n", ERR_PTR(ret));
		return ret;
	}

@@ -219,24 +234,17 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)

	ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
	if (ret) {
		dev_err(&pci->dev,
			"Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
		dev_err(dev, "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
		return ret;
	}

	dwc->base = pcim_iomap_table(pci)[0];
	if (!dwc->base) {
		dev_err(&pci->dev, "Base address missing\n");
		dev_err(dev, "Base address missing\n");
		return -ENOMEM;
	}

	pci_set_drvdata(pci, dwc);

	dwc->chip.dev = dev;
	dwc->chip.ops = &dwc_pwm_ops;
	dwc->chip.npwm = DWC_TIMERS_TOTAL;

	ret = pwmchip_add(&dwc->chip);
	ret = devm_pwmchip_add(dev, &dwc->chip);
	if (ret)
		return ret;

@@ -248,12 +256,8 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)

static void dwc_pwm_remove(struct pci_dev *pci)
{
	struct dwc_pwm *dwc = pci_get_drvdata(pci);

	pm_runtime_forbid(&pci->dev);
	pm_runtime_get_noresume(&pci->dev);

	pwmchip_remove(&dwc->chip);
}

#ifdef CONFIG_PM_SLEEP
Loading