1
0
Fork 0

pwm: Changes for v5.6-rc1

This set of changes are mostly cleanups and minor improvements with some
 new chip support for some drivers.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAl46zmoZHHRoaWVycnku
 cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zodGZEACQyt5Es8RbSMws6qmsZXSU
 XgVi1vCq3Mz51t2DMXp3PCe4Kb7MMTIn8nsFhQ6Q7z888ZCYC6auRTZ5kLNUZvwe
 guBqUR2+y2RkG0d9fWvf8xan2FqKuh33axX4YljNYI7lj79tyhQvHIC/B4DFes9y
 FnpvtDsFdVIFJmnDjgynWO5FhGbf7DdO6Mhmj99lQN3yMiUQ6RGmoXXrKoadcbNt
 vWGr5UqFY72PdVvMQFIA7U3ZeM5n8ocVI6TmvqHhX1ozLyB113yWXZr1hLH4LXzz
 f14NHygpo/GhB8ch3elxBZcXWPmPyn9tHxd2tYnlQ8whEY5RSD3C/bmVFMruhOLC
 LkcAmJ4mbk4tOVEoHB23vTcV5oxcVobDqIOj0W9n1pKWsx6Y3J31rIIg2BCPwSB2
 o/xtFWafuvX9E90EVVM0H0mZSsxydZLXWOr17wzb1xlVulCpJCzvnhwJ8JXB6a0z
 9/az3nGpOa6QB17IkR+sRkjVAnUFJ0CLHURIv+O7O+DBHVuykojdjpACzZcyy7kl
 4ZrHhhCKwEbC4gjmtaJTgmQ0L/WGYfOBQKQmBKaQEJWXPUHsyJ4DFJjrIF4INqOe
 mS9BRvC0nRJ6g3ulOR95sVszMVrXKFUaMN6XqzyWzWPibdDk+1QR4EqU1QZQ/PgR
 46RWEV02tG6SK65UzLqZxA==
 =x0aH
 -----END PGP SIGNATURE-----

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
  ...
alistair/sensors
Linus Torvalds 2020-02-05 18:11:51 +00:00
commit 4c7d00ccf4
13 changed files with 535 additions and 195 deletions

View File

@ -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>;
};

View File

@ -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
@ -490,7 +491,7 @@ config PWM_TEGRA
To compile this driver as a module, choose M here: the module
will be called pwm-tegra.
config PWM_TIECAP
config PWM_TIECAP
tristate "ECAP PWM support"
depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
help
@ -499,7 +500,7 @@ config PWM_TIECAP
To compile this driver as a module, choose M here: the module
will be called pwm-tiecap.
config PWM_TIEHRPWM
config PWM_TIEHRPWM
tristate "EHRPWM PWM support"
depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3
help

View File

@ -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 {
/*

View File

@ -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,
},
};

View File

@ -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,8 +163,19 @@ 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 */
state->duty_cycle = ret;
/*
* 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;
}
static struct pwm_device *
@ -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,

View File

@ -85,6 +85,13 @@ struct pwm_imx27_chip {
struct clk *clk_per;
void __iomem *mmio_base;
struct pwm_chip chip;
/*
* The driver cannot read the current duty cycle from the hardware if
* the hardware is disabled. Cache the last programmed duty cycle
* value to return in that case.
*/
unsigned int duty_cycle;
};
#define to_pwm_imx27_chip(chip) container_of(chip, struct pwm_imx27_chip, chip)
@ -155,14 +162,17 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
tmp = NSEC_PER_SEC * (u64)(period + 2);
state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
/* PWMSAR can be read only if PWM is enabled */
if (state->enabled) {
/*
* PWMSAR can be read only if PWM is enabled. If the PWM is disabled,
* use the cached value.
*/
if (state->enabled)
val = readl(imx->mmio_base + MX3_PWMSAR);
tmp = NSEC_PER_SEC * (u64)(val);
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
} else {
state->duty_cycle = 0;
}
else
val = imx->duty_cycle;
tmp = NSEC_PER_SEC * (u64)(val);
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
if (!state->enabled)
pwm_imx27_clk_disable_unprepare(chip);
@ -220,63 +230,68 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
pwm_get_state(pwm, &cstate);
if (state->enabled) {
c = clk_get_rate(imx->clk_per);
c *= state->period;
c = clk_get_rate(imx->clk_per);
c *= state->period;
do_div(c, 1000000000);
period_cycles = c;
do_div(c, 1000000000);
period_cycles = c;
prescale = period_cycles / 0x10000 + 1;
prescale = period_cycles / 0x10000 + 1;
period_cycles /= prescale;
c = (unsigned long long)period_cycles * state->duty_cycle;
do_div(c, state->period);
duty_cycles = c;
period_cycles /= prescale;
c = (unsigned long long)period_cycles * state->duty_cycle;
do_div(c, state->period);
duty_cycles = c;
/*
* according to imx pwm RM, the real period value should be
* PERIOD value in PWMPR plus 2.
*/
if (period_cycles > 2)
period_cycles -= 2;
else
period_cycles = 0;
/*
* according to imx pwm RM, the real period value should be PERIOD
* value in PWMPR plus 2.
*/
if (period_cycles > 2)
period_cycles -= 2;
else
period_cycles = 0;
/*
* Wait for a free FIFO slot if the PWM is already enabled, and
* flush the FIFO if the PWM was disabled and is about to be
* enabled.
*/
if (cstate.enabled) {
pwm_imx27_wait_fifo_slot(chip, pwm);
} else {
ret = pwm_imx27_clk_prepare_enable(chip);
if (ret)
return ret;
/*
* Wait for a free FIFO slot if the PWM is already enabled, and flush
* the FIFO if the PWM was disabled and is about to be enabled.
*/
if (cstate.enabled) {
pwm_imx27_wait_fifo_slot(chip, pwm);
} else {
ret = pwm_imx27_clk_prepare_enable(chip);
if (ret)
return ret;
pwm_imx27_sw_reset(chip);
}
writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
writel(period_cycles, imx->mmio_base + MX3_PWMPR);
cr = MX3_PWMCR_PRESCALER_SET(prescale) |
MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
if (state->polarity == PWM_POLARITY_INVERSED)
cr |= FIELD_PREP(MX3_PWMCR_POUTC,
MX3_PWMCR_POUTC_INVERTED);
writel(cr, imx->mmio_base + MX3_PWMCR);
} else if (cstate.enabled) {
writel(0, imx->mmio_base + MX3_PWMCR);
pwm_imx27_clk_disable_unprepare(chip);
pwm_imx27_sw_reset(chip);
}
writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
writel(period_cycles, imx->mmio_base + MX3_PWMPR);
/*
* Store the duty cycle for future reference in cases where the
* MX3_PWMSAR register can't be read (i.e. when the PWM is disabled).
*/
imx->duty_cycle = duty_cycles;
cr = MX3_PWMCR_PRESCALER_SET(prescale) |
MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
MX3_PWMCR_DBGEN;
if (state->polarity == PWM_POLARITY_INVERSED)
cr |= FIELD_PREP(MX3_PWMCR_POUTC,
MX3_PWMCR_POUTC_INVERTED);
if (state->enabled)
cr |= MX3_PWMCR_EN;
writel(cr, imx->mmio_base + MX3_PWMCR);
if (!state->enabled && cstate.enabled)
pwm_imx27_clk_disable_unprepare(chip);
return 0;
}
@ -304,9 +319,13 @@ static int pwm_imx27_probe(struct platform_device *pdev)
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx->clk_ipg)) {
dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
PTR_ERR(imx->clk_ipg));
return PTR_ERR(imx->clk_ipg);
int ret = PTR_ERR(imx->clk_ipg);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"getting ipg clock failed with %d\n",
ret);
return ret;
}
imx->clk_per = devm_clk_get(&pdev->dev, "per");

View File

@ -25,12 +25,16 @@
#define PERIOD_PERIOD(p) ((p) & 0xffff)
#define PERIOD_PERIOD_MAX 0x10000
#define PERIOD_ACTIVE_HIGH (3 << 16)
#define PERIOD_ACTIVE_LOW (2 << 16)
#define PERIOD_INACTIVE_HIGH (3 << 18)
#define PERIOD_INACTIVE_LOW (2 << 18)
#define PERIOD_POLARITY_NORMAL (PERIOD_ACTIVE_HIGH | PERIOD_INACTIVE_LOW)
#define PERIOD_POLARITY_INVERSE (PERIOD_ACTIVE_LOW | PERIOD_INACTIVE_HIGH)
#define PERIOD_CDIV(div) (((div) & 0x7) << 20)
#define PERIOD_CDIV_MAX 8
static const unsigned int cdiv[PERIOD_CDIV_MAX] = {
1, 2, 4, 8, 16, 64, 256, 1024
static const u8 cdiv_shift[PERIOD_CDIV_MAX] = {
0, 1, 2, 3, 4, 6, 8, 10
};
struct mxs_pwm_chip {
@ -41,19 +45,34 @@ struct mxs_pwm_chip {
#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip)
static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
int ret, div = 0;
unsigned int period_cycles, duty_cycles;
unsigned long rate;
unsigned long long c;
unsigned int pol_bits;
/*
* If the PWM channel is disabled, make sure to turn on the
* clock before calling clk_get_rate() and writing to the
* registers. Otherwise, just keep it enabled.
*/
if (!pwm_is_enabled(pwm)) {
ret = clk_prepare_enable(mxs->clk);
if (ret)
return ret;
}
if (!state->enabled && pwm_is_enabled(pwm))
writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + CLR);
rate = clk_get_rate(mxs->clk);
while (1) {
c = rate / cdiv[div];
c = c * period_ns;
c = rate >> cdiv_shift[div];
c = c * state->period;
do_div(c, 1000000000);
if (c < PERIOD_PERIOD_MAX)
break;
@ -63,62 +82,40 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
}
period_cycles = c;
c *= duty_ns;
do_div(c, period_ns);
c *= state->duty_cycle;
do_div(c, state->period);
duty_cycles = c;
/*
* If the PWM channel is disabled, make sure to turn on the clock
* before writing the register. Otherwise, keep it enabled.
* The data sheet the says registers must be written to in
* this order (ACTIVEn, then PERIODn). Also, the new settings
* only take effect at the beginning of a new period, avoiding
* glitches.
*/
if (!pwm_is_enabled(pwm)) {
ret = clk_prepare_enable(mxs->clk);
if (ret)
return ret;
}
pol_bits = state->polarity == PWM_POLARITY_NORMAL ?
PERIOD_POLARITY_NORMAL : PERIOD_POLARITY_INVERSE;
writel(duty_cycles << 16,
mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20);
writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH |
PERIOD_INACTIVE_LOW | PERIOD_CDIV(div),
mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20);
mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20);
writel(PERIOD_PERIOD(period_cycles) | pol_bits | PERIOD_CDIV(div),
mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20);
/*
* If the PWM is not enabled, turn the clock off again to save power.
*/
if (!pwm_is_enabled(pwm))
if (state->enabled) {
if (!pwm_is_enabled(pwm)) {
/*
* The clock was enabled above. Just enable
* the channel in the control register.
*/
writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET);
}
} else {
clk_disable_unprepare(mxs->clk);
}
return 0;
}
static int mxs_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
int ret;
ret = clk_prepare_enable(mxs->clk);
if (ret)
return ret;
writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET);
return 0;
}
static void mxs_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + CLR);
clk_disable_unprepare(mxs->clk);
}
static const struct pwm_ops mxs_pwm_ops = {
.config = mxs_pwm_config,
.enable = mxs_pwm_enable,
.disable = mxs_pwm_disable,
.apply = mxs_pwm_apply,
.owner = THIS_MODULE,
};
@ -142,6 +139,8 @@ static int mxs_pwm_probe(struct platform_device *pdev)
mxs->chip.dev = &pdev->dev;
mxs->chip.ops = &mxs_pwm_ops;
mxs->chip.of_xlate = of_pwm_xlate_with_flags;
mxs->chip.of_pwm_n_cells = 3;
mxs->chip.base = -1;
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);

View File

@ -256,7 +256,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
if (!timer_pdev) {
dev_err(&pdev->dev, "Unable to find Timer pdev\n");
ret = -ENODEV;
goto put;
goto err_find_timer_pdev;
}
timer_pdata = dev_get_platdata(&timer_pdev->dev);
@ -264,7 +264,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev,
"dmtimer pdata structure NULL, deferring probe\n");
ret = -EPROBE_DEFER;
goto put;
goto err_platdata;
}
pdata = timer_pdata->timer_ops;
@ -283,30 +283,25 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
!pdata->write_counter) {
dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
ret = -EINVAL;
goto put;
goto err_platdata;
}
if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
ret = -ENODEV;
goto put;
goto err_timer_property;
}
dm_timer = pdata->request_by_node(timer);
if (!dm_timer) {
ret = -EPROBE_DEFER;
goto put;
goto err_request_timer;
}
put:
of_node_put(timer);
if (ret < 0)
return ret;
omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
pdata->free(dm_timer);
return -ENOMEM;
ret = -ENOMEM;
goto err_alloc_omap;
}
omap->pdata = pdata;
@ -339,27 +334,56 @@ put:
ret = pwmchip_add(&omap->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register PWM\n");
omap->pdata->free(omap->dm_timer);
return ret;
goto err_pwmchip_add;
}
of_node_put(timer);
platform_set_drvdata(pdev, omap);
return 0;
err_pwmchip_add:
/*
* *omap is allocated using devm_kzalloc,
* so no free necessary here
*/
err_alloc_omap:
pdata->free(dm_timer);
err_request_timer:
err_timer_property:
err_platdata:
put_device(&timer_pdev->dev);
err_find_timer_pdev:
of_node_put(timer);
return ret;
}
static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
{
struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
int ret;
ret = pwmchip_remove(&omap->chip);
if (ret)
return ret;
if (pm_runtime_active(&omap->dm_timer_pdev->dev))
omap->pdata->stop(omap->dm_timer);
omap->pdata->free(omap->dm_timer);
put_device(&omap->dm_timer_pdev->dev);
mutex_destroy(&omap->mutex);
return pwmchip_remove(&omap->chip);
return 0;
}
static const struct of_device_id pwm_omap_dmtimer_of_match[] = {

View File

@ -159,13 +159,9 @@ static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
{
struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm;
pca9685_pwm_gpio_set(gpio, offset, 0);
pm_runtime_put(pca->chip.dev);
mutex_lock(&pca->lock);
pwm = &pca->chip.pwms[offset];
mutex_unlock(&pca->lock);
}
static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,

View File

@ -3,6 +3,9 @@
* R-Car PWM Timer driver
*
* Copyright (C) 2015 Renesas Electronics Corporation
*
* Limitations:
* - The hardware cannot generate a 0% duty cycle.
*/
#include <linux/clk.h>
@ -161,11 +164,9 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
struct pwm_state cur_state;
int div, ret;
/* This HW/driver only supports normal polarity */
pwm_get_state(pwm, &cur_state);
if (state->polarity != PWM_POLARITY_NORMAL)
return -ENOTSUPP;

View File

@ -377,9 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
else
regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
regmap_update_bits(priv->regmap, TIM_BDTR,
TIM_BDTR_MOE | TIM_BDTR_AOE,
TIM_BDTR_MOE | TIM_BDTR_AOE);
regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE);
return 0;
}

View File

@ -3,6 +3,10 @@
* Driver for Allwinner sun4i Pulse Width Modulation Controller
*
* Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com>
*
* Limitations:
* - When outputing the source clock directly, the PWM logic will be bypassed
* and the currently running period is not guaranteed to be completed
*/
#include <linux/bitops.h>
@ -16,6 +20,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/time.h>
@ -72,12 +77,15 @@ static const u32 prescaler_table[] = {
struct sun4i_pwm_data {
bool has_prescaler_bypass;
bool has_direct_mod_clk_output;
unsigned int npwm;
};
struct sun4i_pwm_chip {
struct pwm_chip chip;
struct clk *bus_clk;
struct clk *clk;
struct reset_control *rst;
void __iomem *base;
spinlock_t ctrl_lock;
const struct sun4i_pwm_data *data;
@ -115,6 +123,20 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
/*
* PWM chapter in H6 manual has a diagram which explains that if bypass
* bit is set, no other setting has any meaning. Even more, experiment
* proved that also enable bit is ignored in this case.
*/
if ((val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) &&
sun4i_pwm->data->has_direct_mod_clk_output) {
state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
state->polarity = PWM_POLARITY_NORMAL;
state->enabled = true;
return;
}
if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) &&
sun4i_pwm->data->has_prescaler_bypass)
prescaler = 1;
@ -146,13 +168,24 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
const struct pwm_state *state,
u32 *dty, u32 *prd, unsigned int *prsclr)
u32 *dty, u32 *prd, unsigned int *prsclr,
bool *bypass)
{
u64 clk_rate, div = 0;
unsigned int pval, prescaler = 0;
unsigned int prescaler = 0;
clk_rate = clk_get_rate(sun4i_pwm->clk);
*bypass = sun4i_pwm->data->has_direct_mod_clk_output &&
state->enabled &&
(state->period * clk_rate >= NSEC_PER_SEC) &&
(state->period * clk_rate < 2 * NSEC_PER_SEC) &&
(state->duty_cycle * clk_rate * 2 >= NSEC_PER_SEC);
/* Skip calculation of other parameters if we bypass them */
if (*bypass)
return 0;
if (sun4i_pwm->data->has_prescaler_bypass) {
/* First, test without any prescaler when available */
prescaler = PWM_PRESCAL_MASK;
@ -170,9 +203,11 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
if (prescaler == 0) {
/* Go up from the first divider */
for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
if (!prescaler_table[prescaler])
unsigned int pval = prescaler_table[prescaler];
if (!pval)
continue;
pval = prescaler_table[prescaler];
div = clk_rate;
do_div(div, pval);
div = div * state->period;
@ -199,10 +234,11 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
struct pwm_state cstate;
u32 ctrl;
u32 ctrl, duty = 0, period = 0, val;
int ret;
unsigned int delay_us;
unsigned int delay_us, prescaler = 0;
unsigned long now;
bool bypass;
pwm_get_state(pwm, &cstate);
@ -214,46 +250,52 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
}
}
ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler,
&bypass);
if (ret) {
dev_err(chip->dev, "period exceeds the maximum value\n");
if (!cstate.enabled)
clk_disable_unprepare(sun4i_pwm->clk);
return ret;
}
spin_lock(&sun4i_pwm->ctrl_lock);
ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
if ((cstate.period != state->period) ||
(cstate.duty_cycle != state->duty_cycle)) {
u32 period, duty, val;
unsigned int prescaler;
ret = sun4i_pwm_calculate(sun4i_pwm, state,
&duty, &period, &prescaler);
if (ret) {
dev_err(chip->dev, "period exceeds the maximum value\n");
spin_unlock(&sun4i_pwm->ctrl_lock);
if (!cstate.enabled)
clk_disable_unprepare(sun4i_pwm->clk);
return ret;
}
if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) {
/* Prescaler changed, the clock has to be gated */
ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
if (sun4i_pwm->data->has_direct_mod_clk_output) {
if (bypass) {
ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm);
/* We can skip other parameter */
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
ctrl |= BIT_CH(prescaler, pwm->hwpwm);
spin_unlock(&sun4i_pwm->ctrl_lock);
return 0;
}
val = (duty & PWM_DTY_MASK) | PWM_PRD(period);
sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
usecs_to_jiffies(cstate.period / 1000 + 1);
sun4i_pwm->needs_delay[pwm->hwpwm] = true;
ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm);
}
if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) {
/* Prescaler changed, the clock has to be gated */
ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
ctrl |= BIT_CH(prescaler, pwm->hwpwm);
}
val = (duty & PWM_DTY_MASK) | PWM_PRD(period);
sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
usecs_to_jiffies(cstate.period / 1000 + 1);
sun4i_pwm->needs_delay[pwm->hwpwm] = true;
if (state->polarity != PWM_POLARITY_NORMAL)
ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
else
ctrl |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
if (state->enabled) {
ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
} else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
@ -319,6 +361,12 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = {
.npwm = 1,
};
static const struct sun4i_pwm_data sun50i_h6_pwm_data = {
.has_prescaler_bypass = true,
.has_direct_mod_clk_output = true,
.npwm = 2,
};
static const struct of_device_id sun4i_pwm_dt_ids[] = {
{
.compatible = "allwinner,sun4i-a10-pwm",
@ -335,6 +383,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = {
}, {
.compatible = "allwinner,sun8i-h3-pwm",
.data = &sun4i_pwm_single_bypass,
}, {
.compatible = "allwinner,sun50i-h6-pwm",
.data = &sun50i_h6_pwm_data,
}, {
/* sentinel */
},
@ -360,9 +411,69 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->base))
return PTR_ERR(pwm->base);
pwm->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pwm->clk))
/*
* All hardware variants need a source clock that is divided and
* then feeds the counter that defines the output wave form. In the
* device tree this clock is either unnamed or called "mod".
* Some variants (e.g. H6) need another clock to access the
* hardware registers; this is called "bus".
* So we request "mod" first (and ignore the corner case that a
* parent provides a "mod" clock while the right one would be the
* unnamed one of the PWM device) and if this is not found we fall
* back to the first clock of the PWM.
*/
pwm->clk = devm_clk_get_optional(&pdev->dev, "mod");
if (IS_ERR(pwm->clk)) {
if (PTR_ERR(pwm->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "get mod clock failed %pe\n",
pwm->clk);
return PTR_ERR(pwm->clk);
}
if (!pwm->clk) {
pwm->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pwm->clk)) {
if (PTR_ERR(pwm->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "get unnamed clock failed %pe\n",
pwm->clk);
return PTR_ERR(pwm->clk);
}
}
pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus");
if (IS_ERR(pwm->bus_clk)) {
if (PTR_ERR(pwm->bus_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "get bus clock failed %pe\n",
pwm->bus_clk);
return PTR_ERR(pwm->bus_clk);
}
pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
if (IS_ERR(pwm->rst)) {
if (PTR_ERR(pwm->rst) != -EPROBE_DEFER)
dev_err(&pdev->dev, "get reset failed %pe\n",
pwm->rst);
return PTR_ERR(pwm->rst);
}
/* Deassert reset */
ret = reset_control_deassert(pwm->rst);
if (ret) {
dev_err(&pdev->dev, "cannot deassert reset control: %pe\n",
ERR_PTR(ret));
return ret;
}
/*
* We're keeping the bus clock on for the sake of simplicity.
* Actually it only needs to be on for hardware register accesses.
*/
ret = clk_prepare_enable(pwm->bus_clk);
if (ret) {
dev_err(&pdev->dev, "cannot prepare and enable bus_clk %pe\n",
ERR_PTR(ret));
goto err_bus;
}
pwm->chip.dev = &pdev->dev;
pwm->chip.ops = &sun4i_pwm_ops;
@ -376,19 +487,34 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
ret = pwmchip_add(&pwm->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
return ret;
goto err_pwm_add;
}
platform_set_drvdata(pdev, pwm);
return 0;
err_pwm_add:
clk_disable_unprepare(pwm->bus_clk);
err_bus:
reset_control_assert(pwm->rst);
return ret;
}
static int sun4i_pwm_remove(struct platform_device *pdev)
{
struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev);
int ret;
return pwmchip_remove(&pwm->chip);
ret = pwmchip_remove(&pwm->chip);
if (ret)
return ret;
clk_disable_unprepare(pwm->bus_clk);
reset_control_assert(pwm->rst);
return 0;
}
static struct platform_driver sun4i_pwm_driver = {

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM pwm
#if !defined(_TRACE_PWM_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_PWM_H
#include <linux/pwm.h>
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS(pwm,
TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state),
TP_ARGS(pwm, state),
TP_STRUCT__entry(
__field(struct pwm_device *, pwm)
__field(u64, period)
__field(u64, duty_cycle)
__field(enum pwm_polarity, polarity)
__field(bool, enabled)
),
TP_fast_assign(
__entry->pwm = pwm;
__entry->period = state->period;
__entry->duty_cycle = state->duty_cycle;
__entry->polarity = state->polarity;
__entry->enabled = state->enabled;
),
TP_printk("%p: period=%llu duty_cycle=%llu polarity=%d enabled=%d",
__entry->pwm, __entry->period, __entry->duty_cycle,
__entry->polarity, __entry->enabled)
);
DEFINE_EVENT(pwm, pwm_apply,
TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state),
TP_ARGS(pwm, state)
);
DEFINE_EVENT(pwm, pwm_get,
TP_PROTO(struct pwm_device *pwm, const struct pwm_state *state),
TP_ARGS(pwm, state)
);
#endif /* _TRACE_PWM_H */
/* This part must be outside protection */
#include <trace/define_trace.h>