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

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
...@@ -3,7 +3,7 @@ Freescale MXS PWM controller ...@@ -3,7 +3,7 @@ Freescale MXS PWM controller
Required properties: Required properties:
- compatible: should be "fsl,imx23-pwm" - compatible: should be "fsl,imx23-pwm"
- reg: physical base address and length of the controller's registers - 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. the cells format.
- fsl,pwm-number: the number of PWM devices - fsl,pwm-number: the number of PWM devices
...@@ -12,6 +12,6 @@ Example: ...@@ -12,6 +12,6 @@ Example:
pwm: pwm@80064000 { pwm: pwm@80064000 {
compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
reg = <0x80064000 0x2000>; reg = <0x80064000 0x2000>;
#pwm-cells = <2>; #pwm-cells = <3>;
fsl,pwm-number = <8>; fsl,pwm-number = <8>;
}; };
...@@ -100,7 +100,7 @@ config PWM_BCM_KONA ...@@ -100,7 +100,7 @@ config PWM_BCM_KONA
config PWM_BCM2835 config PWM_BCM2835
tristate "BCM2835 PWM support" tristate "BCM2835 PWM support"
depends on ARCH_BCM2835 depends on ARCH_BCM2835 || ARCH_BRCMSTB
help help
PWM framework driver for BCM2835 controller (Raspberry Pi) PWM framework driver for BCM2835 controller (Raspberry Pi)
...@@ -328,7 +328,8 @@ config PWM_MXS ...@@ -328,7 +328,8 @@ config PWM_MXS
config PWM_OMAP_DMTIMER config PWM_OMAP_DMTIMER
tristate "OMAP Dual-Mode Timer PWM support" 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 help
Generic PWM framework driver for OMAP Dual-Mode Timer PWM output Generic PWM framework driver for OMAP Dual-Mode Timer PWM output
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <dt-bindings/pwm/pwm.h> #include <dt-bindings/pwm/pwm.h>
#define CREATE_TRACE_POINTS
#include <trace/events/pwm.h>
#define MAX_PWMS 1024 #define MAX_PWMS 1024
static DEFINE_MUTEX(pwm_lookup_lock); static DEFINE_MUTEX(pwm_lookup_lock);
...@@ -114,6 +117,11 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) ...@@ -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); set_bit(PWMF_REQUESTED, &pwm->flags);
pwm->label = label; pwm->label = label;
...@@ -283,9 +291,6 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, ...@@ -283,9 +291,6 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
pwm->hwpwm = i; pwm->hwpwm = i;
pwm->state.polarity = polarity; 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); 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) ...@@ -472,6 +477,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
if (err) if (err)
return err; return err;
trace_pwm_apply(pwm, state);
pwm->state = *state; pwm->state = *state;
} else { } else {
/* /*
......
...@@ -4,6 +4,19 @@ ...@@ -4,6 +4,19 @@
* *
* Copyright (C) 2013 Atmel Corporation * Copyright (C) 2013 Atmel Corporation
* Bo Shen <voice.shen@atmel.com> * 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> #include <linux/clk.h>
...@@ -47,6 +60,8 @@ ...@@ -47,6 +60,8 @@
#define PWMV2_CPRD 0x0C #define PWMV2_CPRD 0x0C
#define PWMV2_CPRDUPD 0x10 #define PWMV2_CPRDUPD 0x10
#define PWM_MAX_PRES 10
struct atmel_pwm_registers { struct atmel_pwm_registers {
u8 period; u8 period;
u8 period_upd; u8 period_upd;
...@@ -55,8 +70,7 @@ struct atmel_pwm_registers { ...@@ -55,8 +70,7 @@ struct atmel_pwm_registers {
}; };
struct atmel_pwm_config { struct atmel_pwm_config {
u32 max_period; u32 period_bits;
u32 max_pres;
}; };
struct atmel_pwm_data { struct atmel_pwm_data {
...@@ -97,7 +111,7 @@ static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, ...@@ -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; 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, 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, ...@@ -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; 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, 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, ...@@ -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); struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
unsigned long long cycles = state->period; unsigned long long cycles = state->period;
int shift;
/* Calculate the period cycles and prescale value */ /* Calculate the period cycles and prescale value */
cycles *= clk_get_rate(atmel_pwm->clk); cycles *= clk_get_rate(atmel_pwm->clk);
do_div(cycles, NSEC_PER_SEC); 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"); dev_err(chip->dev, "pres exceeds the maximum value\n");
return -EINVAL; return -EINVAL;
} else if (shift > 0) {
*pres = shift;
cycles >>= *pres;
} else {
*pres = 0;
} }
*cprd = cycles; *cprd = cycles;
...@@ -271,8 +295,48 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -271,8 +295,48 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0; 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 = { static const struct pwm_ops atmel_pwm_ops = {
.apply = atmel_pwm_apply, .apply = atmel_pwm_apply,
.get_state = atmel_pwm_get_state,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -285,8 +349,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = { ...@@ -285,8 +349,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
}, },
.cfg = { .cfg = {
/* 16 bits to keep period and duty. */ /* 16 bits to keep period and duty. */
.max_period = 0xffff, .period_bits = 16,
.max_pres = 10,
}, },
}; };
...@@ -299,8 +362,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = { ...@@ -299,8 +362,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
}, },
.cfg = { .cfg = {
/* 16 bits to keep period and duty. */ /* 16 bits to keep period and duty. */
.max_period = 0xffff, .period_bits = 16,
.max_pres = 10,
}, },
}; };
...@@ -313,8 +375,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = { ...@@ -313,8 +375,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
}, },
.cfg = { .cfg = {
/* 32 bits to keep period and duty. */ /* 32 bits to keep period and duty. */
.max_period = 0xffffffff, .period_bits = 32,
.max_pres = 10,
}, },
}; };
......
...@@ -25,11 +25,39 @@ struct cros_ec_pwm_device { ...@@ -25,11 +25,39 @@ struct cros_ec_pwm_device {
struct pwm_chip chip; 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) 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); 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) static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
{ {
struct { struct {
...@@ -96,7 +124,9 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -96,7 +124,9 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state) const struct pwm_state *state)
{ {
struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); 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 */ /* The EC won't let us change the period */
if (state->period != EC_PWM_MAX_DUTY) 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, ...@@ -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; 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, static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state) struct pwm_state *state)
{ {
struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); 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; int ret;
ret = cros_ec_pwm_get_duty(ec_pwm->ec, pwm->hwpwm); 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, ...@@ -126,7 +163,18 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->enabled = (ret > 0); state->enabled = (ret > 0);
state->period = EC_PWM_MAX_DUTY; 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; state->duty_cycle = ret;
} }
...@@ -149,6 +197,8 @@ cros_ec_pwm_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) ...@@ -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 = { 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, .get_state = cros_ec_pwm_get_state,
.apply = cros_ec_pwm_apply, .apply = cros_ec_pwm_apply,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -85,6 +85,13 @@ struct pwm_imx27_chip { ...@@ -85,6 +85,13 @@ struct pwm_imx27_chip {
struct clk *clk_per; struct clk *clk_per;
void __iomem *mmio_base; void __iomem *mmio_base;
struct pwm_chip chip; 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) #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, ...@@ -155,14 +162,17 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
tmp = NSEC_PER_SEC * (u64)(period + 2); tmp = NSEC_PER_SEC * (u64)(period + 2);
state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); 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); val = readl(imx->mmio_base + MX3_PWMSAR);
else
val = imx->duty_cycle;
tmp = NSEC_PER_SEC * (u64)(val); tmp = NSEC_PER_SEC * (u64)(val);
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
} else {
state->duty_cycle = 0;
}
if (!state->enabled) if (!state->enabled)
pwm_imx27_clk_disable_unprepare(chip); pwm_imx27_clk_disable_unprepare(chip);
...@@ -220,7 +230,6 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -220,7 +230,6 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
pwm_get_state(pwm, &cstate); pwm_get_state(pwm, &cstate);
if (state->enabled) {
c = clk_get_rate(imx->clk_per); c = clk_get_rate(imx->clk_per);
c *= state->period; c *= state->period;
...@@ -235,8 +244,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -235,8 +244,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
duty_cycles = c; duty_cycles = c;
/* /*
* according to imx pwm RM, the real period value should be * according to imx pwm RM, the real period value should be PERIOD
* PERIOD value in PWMPR plus 2. * value in PWMPR plus 2.
*/ */
if (period_cycles > 2) if (period_cycles > 2)
period_cycles -= 2; period_cycles -= 2;
...@@ -244,9 +253,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -244,9 +253,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
period_cycles = 0; period_cycles = 0;
/* /*
* Wait for a free FIFO slot if the PWM is already enabled, and * Wait for a free FIFO slot if the PWM is already enabled, and flush
* flush the FIFO if the PWM was disabled and is about to be * the FIFO if the PWM was disabled and is about to be enabled.
* enabled.
*/ */
if (cstate.enabled) { if (cstate.enabled) {
pwm_imx27_wait_fifo_slot(chip, pwm); pwm_imx27_wait_fifo_slot(chip, pwm);
...@@ -261,21 +269,28 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -261,21 +269,28 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
writel(period_cycles, imx->mmio_base + MX3_PWMPR); 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) | cr = MX3_PWMCR_PRESCALER_SET(prescale) |
MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN | MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEN | MX3_PWMCR_WAITEN |
FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) | FIELD_PREP(MX3_PWMCR_CLKSRC, MX3_PWMCR_CLKSRC_IPG_HIGH) |
MX3_PWMCR_DBGEN | MX3_PWMCR_EN; MX3_PWMCR_DBGEN;
if (state->polarity == PWM_POLARITY_INVERSED) if (state->polarity == PWM_POLARITY_INVERSED)
cr |= FIELD_PREP(MX3_PWMCR_POUTC, cr |= FIELD_PREP(MX3_PWMCR_POUTC,
MX3_PWMCR_POUTC_INVERTED); MX3_PWMCR_POUTC_INVERTED);
if (state->enabled)
cr |= MX3_PWMCR_EN;
writel(cr, imx->mmio_base + MX3_PWMCR); writel(cr, imx->mmio_base + MX3_PWMCR);
} else if (cstate.enabled) {
writel(0, imx->mmio_base + MX3_PWMCR);
if (!state->enabled && cstate.enabled)
pwm_imx27_clk_disable_unprepare(chip); pwm_imx27_clk_disable_unprepare(chip);
}
return 0; return 0;
} }
...@@ -304,9 +319,13 @@ static int pwm_imx27_probe(struct platform_device *pdev) ...@@ -304,9 +319,13 @@ static int pwm_imx27_probe(struct platform_device *pdev)
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx->clk_ipg)) { if (IS_ERR(imx->clk_ipg)) {
dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", int ret = PTR_ERR(imx->clk_ipg);
PTR_ERR(imx->clk_ipg));
return 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"); imx->clk_per = devm_clk_get(&pdev->dev, "per");
......
...@@ -25,12 +25,16 @@ ...@@ -25,12 +25,16 @@
#define PERIOD_PERIOD(p) ((p) & 0xffff) #define PERIOD_PERIOD(p) ((p) & 0xffff)
#define PERIOD_PERIOD_MAX 0x10000 #define PERIOD_PERIOD_MAX 0x10000
#define PERIOD_ACTIVE_HIGH (3 << 16) #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_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(div) (((div) & 0x7) << 20)
#define PERIOD_CDIV_MAX 8 #define PERIOD_CDIV_MAX 8
static const unsigned int cdiv[PERIOD_CDIV_MAX] = { static const u8 cdiv_shift[PERIOD_CDIV_MAX] = {
1, 2, 4, 8, 16, 64, 256, 1024 0, 1, 2, 3, 4, 6, 8, 10
}; };
struct mxs_pwm_chip { struct mxs_pwm_chip {
...@@ -41,19 +45,34 @@ 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) #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, static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) const struct pwm_state *state)
{ {
struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
int ret, div = 0; int ret, div = 0;
unsigned int period_cycles, duty_cycles; unsigned int period_cycles, duty_cycles;
unsigned long rate; unsigned long rate;
unsigned long long c; 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); rate = clk_get_rate(mxs->clk);
while (1) { while (1) {
c = rate / cdiv[div]; c = rate >> cdiv_shift[div];
c = c * period_ns; c = c * state->period;
do_div(c, 1000000000); do_div(c, 1000000000);
if (c < PERIOD_PERIOD_MAX) if (c < PERIOD_PERIOD_MAX)
break; break;
...@@ -63,62 +82,40 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -63,62 +82,40 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
} }
period_cycles = c; period_cycles = c;
c *= duty_ns; c *= state->duty_cycle;
do_div(c, period_ns); do_div(c, state->period);
duty_cycles = c; duty_cycles = c;
/* /*
* If the PWM channel is disabled, make sure to turn on the clock * The data sheet the says registers must be written to in
* before writing the register. Otherwise, keep it enabled. * 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, writel(duty_cycles << 16,
mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20); mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20);
writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH | writel(PERIOD_PERIOD(period_cycles) | pol_bits | PERIOD_CDIV(div),
PERIOD_INACTIVE_LOW | PERIOD_CDIV(div),
mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20); mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20);
if (state->enabled) {
if (!pwm_is_enabled(pwm)) {
/* /*
* If the PWM is not enabled, turn the clock off again to save power. * The clock was enabled above. Just enable
* the channel in the control register.
*/ */
if (!pwm_is_enabled(pwm))
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); writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET);
}
return 0; } else {
}
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); clk_disable_unprepare(mxs->clk);
}
return 0;
} }
static const struct pwm_ops mxs_pwm_ops = { static const struct pwm_ops mxs_pwm_ops = {
.config = mxs_pwm_config, .apply = mxs_pwm_apply,
.enable = mxs_pwm_enable,
.disable = mxs_pwm_disable,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -142,6 +139,8 @@ static int mxs_pwm_probe(struct platform_device *pdev) ...@@ -142,6 +139,8 @@ static int mxs_pwm_probe(struct platform_device *pdev)
mxs->chip.dev = &pdev->dev; mxs->chip.dev = &pdev->dev;
mxs->chip.ops = &mxs_pwm_ops; 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; mxs->chip.base = -1;
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
......
...@@ -256,7 +256,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -256,7 +256,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
if (!timer_pdev) { if (!timer_pdev) {
dev_err(&pdev->dev, "Unable to find Timer pdev\n"); dev_err(&pdev->dev, "Unable to find Timer pdev\n");
ret = -ENODEV; ret = -ENODEV;
goto put; goto err_find_timer_pdev;
} }
timer_pdata = dev_get_platdata(&timer_pdev->dev); timer_pdata = dev_get_platdata(&timer_pdev->dev);
...@@ -264,7 +264,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -264,7 +264,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
"dmtimer pdata structure NULL, deferring probe\n"); "dmtimer pdata structure NULL, deferring probe\n");
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto put; goto err_platdata;
} }
pdata = timer_pdata->timer_ops; pdata = timer_pdata->timer_ops;
...@@ -283,30 +283,25 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -283,30 +283,25 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
!pdata->write_counter) { !pdata->write_counter) {
dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n"); dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
ret = -EINVAL; ret = -EINVAL;
goto put; goto err_platdata;
} }
if (!of_get_property(timer, "ti,timer-pwm", NULL)) { if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n"); dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
ret = -ENODEV; ret = -ENODEV;
goto put; goto err_timer_property;
} }
dm_timer = pdata->request_by_node(timer); dm_timer = pdata->request_by_node(timer);
if (!dm_timer) { if (!dm_timer) {
ret = -EPROBE_DEFER; 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); omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
if (!omap) { if (!omap) {
pdata->free(dm_timer); ret = -ENOMEM;
return -ENOMEM; goto err_alloc_omap;
} }
omap->pdata = pdata; omap->pdata = pdata;
...@@ -339,27 +334,56 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -339,27 +334,56 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
ret = pwmchip_add(&omap->chip); ret = pwmchip_add(&omap->chip);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to register PWM\n"); dev_err(&pdev->dev, "failed to register PWM\n");
omap->pdata->free(omap->dm_timer); goto err_pwmchip_add;
return ret;
} }
of_node_put(timer);
platform_set_drvdata(pdev, omap); platform_set_drvdata(pdev, omap);
return 0; 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) static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
{ {
struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(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)) if (pm_runtime_active(&omap->dm_timer_pdev->dev))
omap->pdata->stop(omap->dm_timer); omap->pdata->stop(omap->dm_timer);
omap->pdata->free(omap->dm_timer); omap->pdata->free(omap->dm_timer);
put_device(&omap->dm_timer_pdev->dev);
mutex_destroy(&omap->mutex); mutex_destroy(&omap->mutex);
return pwmchip_remove(&omap->chip); return 0;
} }
static const struct of_device_id pwm_omap_dmtimer_of_match[] = { static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
......
...@@ -159,13 +159,9 @@ static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset, ...@@ -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) static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
{ {
struct pca9685 *pca = gpiochip_get_data(gpio); struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm;
pca9685_pwm_gpio_set(gpio, offset, 0); pca9685_pwm_gpio_set(gpio, offset, 0);
pm_runtime_put(pca->chip.dev); 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, static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
* R-Car PWM Timer driver * R-Car PWM Timer driver
* *
* Copyright (C) 2015 Renesas Electronics Corporation * Copyright (C) 2015 Renesas Electronics Corporation
*
* Limitations:
* - The hardware cannot generate a 0% duty cycle.
*/ */
#include <linux/clk.h> #include <linux/clk.h>
...@@ -161,11 +164,9 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -161,11 +164,9 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state) const struct pwm_state *state)
{ {
struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
struct pwm_state cur_state;
int div, ret; int div, ret;
/* This HW/driver only supports normal polarity */ /* This HW/driver only supports normal polarity */
pwm_get_state(pwm, &cur_state);
if (state->polarity != PWM_POLARITY_NORMAL) if (state->polarity != PWM_POLARITY_NORMAL)
return -ENOTSUPP; return -ENOTSUPP;
......
...@@ -377,9 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch, ...@@ -377,9 +377,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
else else
regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
regmap_update_bits(priv->regmap, TIM_BDTR, regmap_update_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE, TIM_BDTR_MOE);
TIM_BDTR_MOE | TIM_BDTR_AOE,
TIM_BDTR_MOE | TIM_BDTR_AOE);
return 0; return 0;
} }
......
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
* Driver for Allwinner sun4i Pulse Width Modulation Controller * Driver for Allwinner sun4i Pulse Width Modulation Controller
* *
* Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com> * 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> #include <linux/bitops.h>
...@@ -16,6 +20,7 @@ ...@@ -16,6 +20,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pwm.h> #include <linux/pwm.h>
#include <linux/reset.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/time.h> #include <linux/time.h>
...@@ -72,12 +77,15 @@ static const u32 prescaler_table[] = { ...@@ -72,12 +77,15 @@ static const u32 prescaler_table[] = {
struct sun4i_pwm_data { struct sun4i_pwm_data {
bool has_prescaler_bypass; bool has_prescaler_bypass;
bool has_direct_mod_clk_output;
unsigned int npwm; unsigned int npwm;
}; };
struct sun4i_pwm_chip { struct sun4i_pwm_chip {
struct pwm_chip chip; struct pwm_chip chip;
struct clk *bus_clk;
struct clk *clk; struct clk *clk;
struct reset_control *rst;
void __iomem *base; void __iomem *base;
spinlock_t ctrl_lock; spinlock_t ctrl_lock;
const struct sun4i_pwm_data *data; const struct sun4i_pwm_data *data;
...@@ -115,6 +123,20 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, ...@@ -115,6 +123,20 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip,
val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); 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) && if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) &&
sun4i_pwm->data->has_prescaler_bypass) sun4i_pwm->data->has_prescaler_bypass)
prescaler = 1; prescaler = 1;
...@@ -146,13 +168,24 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, ...@@ -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, static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
const struct pwm_state *state, 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; u64 clk_rate, div = 0;
unsigned int pval, prescaler = 0; unsigned int prescaler = 0;
clk_rate = clk_get_rate(sun4i_pwm->clk); 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) { if (sun4i_pwm->data->has_prescaler_bypass) {
/* First, test without any prescaler when available */ /* First, test without any prescaler when available */
prescaler = PWM_PRESCAL_MASK; prescaler = PWM_PRESCAL_MASK;
...@@ -170,9 +203,11 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, ...@@ -170,9 +203,11 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
if (prescaler == 0) { if (prescaler == 0) {
/* Go up from the first divider */ /* Go up from the first divider */
for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) { for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
if (!prescaler_table[prescaler]) unsigned int pval = prescaler_table[prescaler];
if (!pval)
continue; continue;
pval = prescaler_table[prescaler];
div = clk_rate; div = clk_rate;
do_div(div, pval); do_div(div, pval);
div = div * state->period; div = div * state->period;
...@@ -199,10 +234,11 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -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 sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
struct pwm_state cstate; struct pwm_state cstate;
u32 ctrl; u32 ctrl, duty = 0, period = 0, val;
int ret; int ret;
unsigned int delay_us; unsigned int delay_us, prescaler = 0;
unsigned long now; unsigned long now;
bool bypass;
pwm_get_state(pwm, &cstate); pwm_get_state(pwm, &cstate);
...@@ -214,24 +250,30 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -214,24 +250,30 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
} }
} }
spin_lock(&sun4i_pwm->ctrl_lock); ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler,
ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); &bypass);
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) { if (ret) {
dev_err(chip->dev, "period exceeds the maximum value\n"); dev_err(chip->dev, "period exceeds the maximum value\n");
spin_unlock(&sun4i_pwm->ctrl_lock);
if (!cstate.enabled) if (!cstate.enabled)
clk_disable_unprepare(sun4i_pwm->clk); clk_disable_unprepare(sun4i_pwm->clk);
return ret; return ret;
} }
spin_lock(&sun4i_pwm->ctrl_lock);
ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
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);
spin_unlock(&sun4i_pwm->ctrl_lock);
return 0;
}
ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm);
}
if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) {
/* Prescaler changed, the clock has to be gated */ /* Prescaler changed, the clock has to be gated */
ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
...@@ -246,7 +288,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -246,7 +288,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
sun4i_pwm->next_period[pwm->hwpwm] = jiffies + sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
usecs_to_jiffies(cstate.period / 1000 + 1); usecs_to_jiffies(cstate.period / 1000 + 1);
sun4i_pwm->needs_delay[pwm->hwpwm] = true; sun4i_pwm->needs_delay[pwm->hwpwm] = true;
}
if (state->polarity != PWM_POLARITY_NORMAL) if (state->polarity != PWM_POLARITY_NORMAL)
ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm); ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
...@@ -254,6 +295,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -254,6 +295,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
ctrl |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm); ctrl |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
if (state->enabled) { if (state->enabled) {
ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
} else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) { } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
...@@ -319,6 +361,12 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = { ...@@ -319,6 +361,12 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = {
.npwm = 1, .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[] = { static const struct of_device_id sun4i_pwm_dt_ids[] = {
{ {
.compatible = "allwinner,sun4i-a10-pwm", .compatible = "allwinner,sun4i-a10-pwm",
...@@ -335,6 +383,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { ...@@ -335,6 +383,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = {
}, { }, {
.compatible = "allwinner,sun8i-h3-pwm", .compatible = "allwinner,sun8i-h3-pwm",
.data = &sun4i_pwm_single_bypass, .data = &sun4i_pwm_single_bypass,
}, {
.compatible = "allwinner,sun50i-h6-pwm",
.data = &sun50i_h6_pwm_data,
}, { }, {
/* sentinel */ /* sentinel */
}, },
...@@ -360,9 +411,69 @@ static int sun4i_pwm_probe(struct platform_device *pdev) ...@@ -360,9 +411,69 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->base)) if (IS_ERR(pwm->base))
return PTR_ERR(pwm->base); return PTR_ERR(pwm->base);
/*
* 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); pwm->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pwm->clk)) 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); 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.dev = &pdev->dev;
pwm->chip.ops = &sun4i_pwm_ops; pwm->chip.ops = &sun4i_pwm_ops;
...@@ -376,19 +487,34 @@ static int sun4i_pwm_probe(struct platform_device *pdev) ...@@ -376,19 +487,34 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
ret = pwmchip_add(&pwm->chip); ret = pwmchip_add(&pwm->chip);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
return ret; goto err_pwm_add;
} }
platform_set_drvdata(pdev, pwm); platform_set_drvdata(pdev, pwm);
return 0; 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) static int sun4i_pwm_remove(struct platform_device *pdev)
{ {
struct sun4i_pwm_chip *pwm = platform_get_drvdata(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 = { static struct platform_driver sun4i_pwm_driver = {
......
/* 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>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment