Commit 8d844b35 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

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

Pull pwm updates from Thierry Reding:
 "Various cleanups and fixes across the board"

* tag 'pwm/for-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (31 commits)
  pwm: lpc32xx: Remove handling of PWM channels
  pwm: atmel: Simplify using devm functions
  dt-bindings: pwm: brcm,kona-pwm: convert to YAML
  pwm: stmpe: Handle errors when disabling the signal
  pwm: stm32: Simplify using devm_pwmchip_add()
  pwm: stm32: Don't modify HW state in .remove() callback
  pwm: Fix order of freeing resources in pwmchip_remove()
  pwm: ntxec: Use device_set_of_node_from_dev()
  pwm: ntxec: Drop a write-only variable from driver data
  pwm: pxa: Don't reimplement of_device_get_match_data()
  pwm: lpc18xx-sct: Simplify using devm_clk_get_enabled()
  pwm: atmel-tcb: Don't track polarity in driver data
  pwm: atmel-tcb: Unroll atmel_tcb_pwm_set_polarity() into only caller
  pwm: atmel-tcb: Put per-channel data into driver data
  pwm: atmel-tcb: Fix resource freeing in error path and remove
  pwm: atmel-tcb: Harmonize resource allocation order
  pwm: Drop unused #include <linux/radix-tree.h>
  pwm: rz-mtu3: Fix build warning 'num_channel_ios' not described
  pwm: Remove outdated documentation for pwmchip_remove()
  pwm: atmel: Enable clk when pwm already enabled in bootloader
  ...
parents ff6e6ded 4aae44f6
Loading
Loading
Loading
Loading
+0 −21
Original line number Diff line number Diff line
Broadcom Kona PWM controller device tree bindings

This controller has 6 channels.

Required Properties :
- compatible: should contain "brcm,kona-pwm"
- reg: physical base address and length of the controller's registers
- clocks: phandle + clock specifier pair for the external clock
- #pwm-cells: Should be 3. See pwm.yaml in this directory for a
  description of the cells format.

Refer to clocks/clock-bindings.txt for generic clock consumer properties.

Example:

pwm: pwm@3e01a000 {
	compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm";
	reg = <0x3e01a000 0xc4>;
	clocks = <&pwm_clk>;
	#pwm-cells = <3>;
};
+51 −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/brcm,kona-pwm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Broadcom Kona family PWM controller

description:
  This controller has 6 channels.

maintainers:
  - Florian Fainelli <f.fainelli@gmail.com>

allOf:
  - $ref: pwm.yaml#

properties:
  compatible:
    items:
      - enum:
          - brcm,bcm11351-pwm
      - const: brcm,kona-pwm

  reg:
    maxItems: 1

  clocks:
    maxItems: 1

  '#pwm-cells':
    const: 3

required:
  - compatible
  - reg
  - clocks

unevaluatedProperties: false

examples:
  - |
    #include <dt-bindings/clock/bcm281xx.h>

    pwm@3e01a000 {
       compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm";
       reg = <0x3e01a000 0xcc>;
       clocks = <&slave_ccu BCM281XX_SLAVE_CCU_PWM>;
       #pwm-cells = <3>;
    };
...
+19 −22
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@

#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pwm.h>
#include <linux/radix-tree.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/err.h>
@@ -127,28 +127,28 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
}

struct pwm_device *
of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args)
{
	struct pwm_device *pwm;

	if (pc->of_pwm_n_cells < 2)
	if (chip->of_pwm_n_cells < 2)
		return ERR_PTR(-EINVAL);

	/* flags in the third cell are optional */
	if (args->args_count < 2)
		return ERR_PTR(-EINVAL);

	if (args->args[0] >= pc->npwm)
	if (args->args[0] >= chip->npwm)
		return ERR_PTR(-EINVAL);

	pwm = pwm_request_from_chip(pc, args->args[0], NULL);
	pwm = pwm_request_from_chip(chip, args->args[0], NULL);
	if (IS_ERR(pwm))
		return pwm;

	pwm->args.period = args->args[1];
	pwm->args.polarity = PWM_POLARITY_NORMAL;

	if (pc->of_pwm_n_cells >= 3) {
	if (chip->of_pwm_n_cells >= 3) {
		if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
			pwm->args.polarity = PWM_POLARITY_INVERSED;
	}
@@ -158,18 +158,18 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);

struct pwm_device *
of_pwm_single_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
{
	struct pwm_device *pwm;

	if (pc->of_pwm_n_cells < 1)
	if (chip->of_pwm_n_cells < 1)
		return ERR_PTR(-EINVAL);

	/* validate that one cell is specified, optionally with flags */
	if (args->args_count != 1 && args->args_count != 2)
		return ERR_PTR(-EINVAL);

	pwm = pwm_request_from_chip(pc, 0, NULL);
	pwm = pwm_request_from_chip(chip, 0, NULL);
	if (IS_ERR(pwm))
		return pwm;

@@ -312,22 +312,19 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
 * pwmchip_remove() - remove a PWM chip
 * @chip: the PWM chip to remove
 *
 * Removes a PWM chip. This function may return busy if the PWM chip provides
 * a PWM device that is still requested.
 *
 * Returns: 0 on success or a negative error code on failure.
 * Removes a PWM chip.
 */
void pwmchip_remove(struct pwm_chip *chip)
{
	pwmchip_sysfs_unexport(chip);

	if (IS_ENABLED(CONFIG_OF))
		of_pwmchip_remove(chip);

	mutex_lock(&pwm_lock);

	list_del_init(&chip->list);

	if (IS_ENABLED(CONFIG_OF))
		of_pwmchip_remove(chip);

	free_pwms(chip);

	mutex_unlock(&pwm_lock);
@@ -692,7 +689,7 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
	struct pwm_device *pwm = NULL;
	struct of_phandle_args args;
	struct device_link *dl;
	struct pwm_chip *pc;
	struct pwm_chip *chip;
	int index = 0;
	int err;

@@ -709,16 +706,16 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
		return ERR_PTR(err);
	}

	pc = fwnode_to_pwmchip(of_fwnode_handle(args.np));
	if (IS_ERR(pc)) {
		if (PTR_ERR(pc) != -EPROBE_DEFER)
	chip = fwnode_to_pwmchip(of_fwnode_handle(args.np));
	if (IS_ERR(chip)) {
		if (PTR_ERR(chip) != -EPROBE_DEFER)
			pr_err("%s(): PWM chip not found\n", __func__);

		pwm = ERR_CAST(pc);
		pwm = ERR_CAST(chip);
		goto put;
	}

	pwm = pc->of_xlate(pc, &args);
	pwm = chip->of_xlate(chip, &args);
	if (IS_ERR(pwm))
		goto put;

+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
 * - When APPLE_PWM_CTRL is set to 0, the output is constant low
 */

#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
+34 −32
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/mfd/atmel-hlcdc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
@@ -38,11 +39,11 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
	return container_of(chip, struct atmel_hlcdc_pwm, chip);
}

static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
				 const struct pwm_state *state)
{
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
	struct atmel_hlcdc *hlcdc = atmel->hlcdc;
	unsigned int status;
	int ret;

@@ -54,7 +55,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
		u32 pwmcfg;
		int pres;

		if (!chip->errata || !chip->errata->slow_clk_erratum) {
		if (!atmel->errata || !atmel->errata->slow_clk_erratum) {
			clk_freq = clk_get_rate(new_clk);
			if (!clk_freq)
				return -EINVAL;
@@ -64,7 +65,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
		}

		/* Errata: cannot use slow clk on some IP revisions */
		if ((chip->errata && chip->errata->slow_clk_erratum) ||
		if ((atmel->errata && atmel->errata->slow_clk_erratum) ||
		    clk_period_ns > state->period) {
			new_clk = hlcdc->sys_clk;
			clk_freq = clk_get_rate(new_clk);
@@ -77,8 +78,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,

		for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) {
		/* Errata: cannot divide by 1 on some IP revisions */
			if (!pres && chip->errata &&
			    chip->errata->div1_clk_erratum)
			if (!pres && atmel->errata &&
			    atmel->errata->div1_clk_erratum)
				continue;

			if ((clk_period_ns << pres) >= state->period)
@@ -90,7 +91,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,

		pwmcfg = ATMEL_HLCDC_PWMPS(pres);

		if (new_clk != chip->cur_clk) {
		if (new_clk != atmel->cur_clk) {
			u32 gencfg = 0;
			int ret;

@@ -98,8 +99,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
			if (ret)
				return ret;

			clk_disable_unprepare(chip->cur_clk);
			chip->cur_clk = new_clk;
			clk_disable_unprepare(atmel->cur_clk);
			atmel->cur_clk = new_clk;

			if (new_clk == hlcdc->sys_clk)
				gencfg = ATMEL_HLCDC_CLKPWMSEL;
@@ -160,8 +161,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
		if (ret)
			return ret;

		clk_disable_unprepare(chip->cur_clk);
		chip->cur_clk = NULL;
		clk_disable_unprepare(atmel->cur_clk);
		atmel->cur_clk = NULL;
	}

	return 0;
@@ -183,31 +184,32 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_pwm_suspend(struct device *dev)
{
	struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev);
	struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);

	/* Keep the periph clock enabled if the PWM is still running. */
	if (pwm_is_enabled(&chip->chip.pwms[0]))
		clk_disable_unprepare(chip->hlcdc->periph_clk);
	if (pwm_is_enabled(&atmel->chip.pwms[0]))
		clk_disable_unprepare(atmel->hlcdc->periph_clk);

	return 0;
}

static int atmel_hlcdc_pwm_resume(struct device *dev)
{
	struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev);
	struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
	struct pwm_state state;
	int ret;

	pwm_get_state(&chip->chip.pwms[0], &state);
	pwm_get_state(&atmel->chip.pwms[0], &state);

	/* Re-enable the periph clock it was stopped during suspend. */
	if (!state.enabled) {
		ret = clk_prepare_enable(chip->hlcdc->periph_clk);
		ret = clk_prepare_enable(atmel->hlcdc->periph_clk);
		if (ret)
			return ret;
	}

	return atmel_hlcdc_pwm_apply(&chip->chip, &chip->chip.pwms[0], &state);
	return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0],
				     &state);
}
#endif

@@ -244,14 +246,14 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
{
	const struct of_device_id *match;
	struct device *dev = &pdev->dev;
	struct atmel_hlcdc_pwm *chip;
	struct atmel_hlcdc_pwm *atmel;
	struct atmel_hlcdc *hlcdc;
	int ret;

	hlcdc = dev_get_drvdata(dev->parent);

	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
	atmel = devm_kzalloc(dev, sizeof(*atmel), GFP_KERNEL);
	if (!atmel)
		return -ENOMEM;

	ret = clk_prepare_enable(hlcdc->periph_clk);
@@ -260,31 +262,31 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)

	match = of_match_node(atmel_hlcdc_dt_ids, dev->parent->of_node);
	if (match)
		chip->errata = match->data;
		atmel->errata = match->data;

	chip->hlcdc = hlcdc;
	chip->chip.ops = &atmel_hlcdc_pwm_ops;
	chip->chip.dev = dev;
	chip->chip.npwm = 1;
	atmel->hlcdc = hlcdc;
	atmel->chip.ops = &atmel_hlcdc_pwm_ops;
	atmel->chip.dev = dev;
	atmel->chip.npwm = 1;

	ret = pwmchip_add(&chip->chip);
	ret = pwmchip_add(&atmel->chip);
	if (ret) {
		clk_disable_unprepare(hlcdc->periph_clk);
		return ret;
	}

	platform_set_drvdata(pdev, chip);
	platform_set_drvdata(pdev, atmel);

	return 0;
}

static void atmel_hlcdc_pwm_remove(struct platform_device *pdev)
{
	struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev);
	struct atmel_hlcdc_pwm *atmel = platform_get_drvdata(pdev);

	pwmchip_remove(&chip->chip);
	pwmchip_remove(&atmel->chip);

	clk_disable_unprepare(chip->hlcdc->periph_clk);
	clk_disable_unprepare(atmel->hlcdc->periph_clk);
}

static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = {
Loading