Commit 4c7d00cc authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

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

Pull pwm updates from Thierry Reding:
 "Mostly cleanups and minor improvements with some new chip support for
  some drivers"

* tag 'pwm/for-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (37 commits)
  pwm: Remove set but not set variable 'pwm'
  pwm: sun4i: Initialize variables before use
  pwm: stm32: Remove automatic output enable
  pwm: sun4i: Narrow scope of local variable
  pwm: bcm2835: Allow building for ARCH_BRCMSTB
  pwm: imx27: Eliminate error message for defer probe
  pwm: sun4i: Fix inconsistent IS_ERR and PTR_ERR
  pwm: sun4i: Move pwm_calculate() out of spin_lock()
  pwm: omap-dmtimer: Allow compiling with COMPILE_TEST
  pwm: omap-dmtimer: put_device() after of_find_device_by_node()
  pwm: omap-dmtimer: Simplify error handling
  pwm: omap-dmtimer: Remove PWM chip in .remove before making it unfunctional
  pwm: Implement tracing for .get_state() and .apply_state()
  pwm: rcar: Document inability to set duty_cycle = 0
  pwm: rcar: Drop useless call to pwm_get_state()
  pwm: Fix minor Kconfig whitespace issues
  pwm: atmel: Implement .get_state()
  pwm: atmel: Use register accessors for channels
  pwm: atmel: Document known weaknesses of both hardware and software
  pwm: atmel: Replace loop in prescale calculation by ad-hoc calculation
  ...
parents 18ea671b 9871abff
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ Freescale MXS PWM controller
Required properties:
- compatible: should be "fsl,imx23-pwm"
- 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
- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
  the cells format.
- fsl,pwm-number: the number of PWM devices

@@ -12,6 +12,6 @@ Example:
pwm: pwm@80064000 {
	compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
	reg = <0x80064000 0x2000>;
	#pwm-cells = <2>;
	#pwm-cells = <3>;
	fsl,pwm-number = <8>;
};
+5 −4
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ config PWM_BCM_KONA

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

@@ -328,7 +328,8 @@ config PWM_MXS

config PWM_OMAP_DMTIMER
	tristate "OMAP Dual-Mode Timer PWM support"
	depends on OF && ARCH_OMAP && OMAP_DM_TIMER
	depends on OF
	depends on OMAP_DM_TIMER || COMPILE_TEST
	help
	  Generic PWM framework driver for OMAP Dual-Mode Timer PWM output

+10 −3
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@

#include <dt-bindings/pwm/pwm.h>

#define CREATE_TRACE_POINTS
#include <trace/events/pwm.h>

#define MAX_PWMS 1024

static DEFINE_MUTEX(pwm_lookup_lock);
@@ -114,6 +117,11 @@ 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);
	}

	set_bit(PWMF_REQUESTED, &pwm->flags);
	pwm->label = label;

@@ -283,9 +291,6 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
		pwm->hwpwm = i;
		pwm->state.polarity = polarity;

		if (chip->ops->get_state)
			chip->ops->get_state(chip, pwm, &pwm->state);

		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
	}

@@ -472,6 +477,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
		if (err)
			return err;

		trace_pwm_apply(pwm, state);

		pwm->state = *state;
	} else {
		/*
+74 −13
Original line number Diff line number Diff line
@@ -4,6 +4,19 @@
 *
 * Copyright (C) 2013 Atmel Corporation
 *		 Bo Shen <voice.shen@atmel.com>
 *
 * Links to reference manuals for the supported PWM chips can be found in
 * Documentation/arm/microchip.rst.
 *
 * Limitations:
 * - Periods start with the inactive level.
 * - Hardware has to be stopped in general to update settings.
 *
 * Software bugs/possible improvements:
 * - When atmel_pwm_apply() is called with state->enabled=false a change in
 *   state->polarity isn't honored.
 * - Instead of sleeping to wait for a completed period, the interrupt
 *   functionality could be used.
 */

#include <linux/clk.h>
@@ -47,6 +60,8 @@
#define PWMV2_CPRD		0x0C
#define PWMV2_CPRDUPD		0x10

#define PWM_MAX_PRES		10

struct atmel_pwm_registers {
	u8 period;
	u8 period_upd;
@@ -55,8 +70,7 @@ struct atmel_pwm_registers {
};

struct atmel_pwm_config {
	u32 max_period;
	u32 max_pres;
	u32 period_bits;
};

struct atmel_pwm_data {
@@ -97,7 +111,7 @@ static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip,
{
	unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;

	return readl_relaxed(chip->base + base + offset);
	return atmel_pwm_readl(chip, base + offset);
}

static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
@@ -106,7 +120,7 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
{
	unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;

	writel_relaxed(val, chip->base + base + offset);
	atmel_pwm_writel(chip, base + offset, val);
}

static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
@@ -115,17 +129,27 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
{
	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
	unsigned long long cycles = state->period;
	int shift;

	/* Calculate the period cycles and prescale value */
	cycles *= clk_get_rate(atmel_pwm->clk);
	do_div(cycles, NSEC_PER_SEC);

	for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
		(*pres)++;
	/*
	 * The register for the period length is cfg.period_bits bits wide.
	 * So for each bit the number of clock cycles is wider divide the input
	 * clock frequency by two using pres and shift cprd accordingly.
	 */
	shift = fls(cycles) - atmel_pwm->data->cfg.period_bits;

	if (*pres > atmel_pwm->data->cfg.max_pres) {
	if (shift > PWM_MAX_PRES) {
		dev_err(chip->dev, "pres exceeds the maximum value\n");
		return -EINVAL;
	} else if (shift > 0) {
		*pres = shift;
		cycles >>= *pres;
	} else {
		*pres = 0;
	}

	*cprd = cycles;
@@ -271,8 +295,48 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
	return 0;
}

static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
				struct pwm_state *state)
{
	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
	u32 sr, cmr;

	sr = atmel_pwm_readl(atmel_pwm, PWM_SR);
	cmr = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);

	if (sr & (1 << pwm->hwpwm)) {
		unsigned long rate = clk_get_rate(atmel_pwm->clk);
		u32 cdty, cprd, pres;
		u64 tmp;

		pres = cmr & PWM_CMR_CPRE_MSK;

		cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
					  atmel_pwm->data->regs.period);
		tmp = (u64)cprd * NSEC_PER_SEC;
		tmp <<= pres;
		state->period = DIV64_U64_ROUND_UP(tmp, rate);

		cdty = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
					  atmel_pwm->data->regs.duty);
		tmp = (u64)cdty * NSEC_PER_SEC;
		tmp <<= pres;
		state->duty_cycle = DIV64_U64_ROUND_UP(tmp, rate);

		state->enabled = true;
	} else {
		state->enabled = false;
	}

	if (cmr & PWM_CMR_CPOL)
		state->polarity = PWM_POLARITY_INVERSED;
	else
		state->polarity = PWM_POLARITY_NORMAL;
}

static const struct pwm_ops atmel_pwm_ops = {
	.apply = atmel_pwm_apply,
	.get_state = atmel_pwm_get_state,
	.owner = THIS_MODULE,
};

@@ -285,8 +349,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
	},
	.cfg = {
		/* 16 bits to keep period and duty. */
		.max_period	= 0xffff,
		.max_pres	= 10,
		.period_bits	= 16,
	},
};

@@ -299,8 +362,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
	},
	.cfg = {
		/* 16 bits to keep period and duty. */
		.max_period	= 0xffff,
		.max_pres	= 10,
		.period_bits	= 16,
	},
};

@@ -313,8 +375,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
	},
	.cfg = {
		/* 32 bits to keep period and duty. */
		.max_period	= 0xffffffff,
		.max_pres	= 10,
		.period_bits	= 32,
	},
};

+54 −4
Original line number Diff line number Diff line
@@ -25,11 +25,39 @@ struct cros_ec_pwm_device {
	struct pwm_chip chip;
};

/**
 * struct cros_ec_pwm - per-PWM driver data
 * @duty_cycle: cached duty cycle
 */
struct cros_ec_pwm {
	u16 duty_cycle;
};

static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *c)
{
	return container_of(c, struct cros_ec_pwm_device, chip);
}

static int cros_ec_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct cros_ec_pwm *channel;

	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
	if (!channel)
		return -ENOMEM;

	pwm_set_chip_data(pwm, channel);

	return 0;
}

static void cros_ec_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);

	kfree(channel);
}

static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
{
	struct {
@@ -96,7 +124,9 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			     const struct pwm_state *state)
{
	struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
	int duty_cycle;
	struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
	u16 duty_cycle;
	int ret;

	/* The EC won't let us change the period */
	if (state->period != EC_PWM_MAX_DUTY)
@@ -108,13 +138,20 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
	 */
	duty_cycle = state->enabled ? state->duty_cycle : 0;

	return cros_ec_pwm_set_duty(ec_pwm->ec, pwm->hwpwm, duty_cycle);
	ret = cros_ec_pwm_set_duty(ec_pwm->ec, pwm->hwpwm, duty_cycle);
	if (ret < 0)
		return ret;

	channel->duty_cycle = state->duty_cycle;

	return 0;
}

static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
				  struct pwm_state *state)
{
	struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
	struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
	int ret;

	ret = cros_ec_pwm_get_duty(ec_pwm->ec, pwm->hwpwm);
@@ -126,7 +163,18 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
	state->enabled = (ret > 0);
	state->period = EC_PWM_MAX_DUTY;

	/* Note that "disabled" and "duty cycle == 0" are treated the same */
	/*
	 * Note that "disabled" and "duty cycle == 0" are treated the same. If
	 * the cached duty cycle is not zero, used the cached duty cycle. This
	 * ensures that the configured duty cycle is kept across a disable and
	 * enable operation and avoids potentially confusing consumers.
	 *
	 * For the case of the initial hardware readout, channel->duty_cycle
	 * will be 0 and the actual duty cycle read from the EC is used.
	 */
	if (ret == 0 && channel->duty_cycle > 0)
		state->duty_cycle = channel->duty_cycle;
	else
		state->duty_cycle = ret;
}

@@ -149,6 +197,8 @@ cros_ec_pwm_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
}

static const struct pwm_ops cros_ec_pwm_ops = {
	.request = cros_ec_pwm_request,
	.free = cros_ec_pwm_free,
	.get_state	= cros_ec_pwm_get_state,
	.apply		= cros_ec_pwm_apply,
	.owner		= THIS_MODULE,
Loading