[PATCH v2 2/2] drivers: pwm: pwm-atmel: implement pwm dead-times

From: Claudiu Beznea
Date: Tue May 09 2017 - 04:29:57 EST


Implement PWM dead-times for atmel PWM controllers.
Since this driver is used by PWM controllers which
supports dead-times and PWM controllers which doesn't,
add specific input for dead-time register in atmel
register private data structure.

Signed-off-by: Claudiu Beznea <claudiu.beznea@xxxxxxxxxxxxx>
---
drivers/pwm/pwm-atmel.c | 61 +++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 530d7dc..dababa6 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -33,8 +33,9 @@

#define PWM_CMR 0x0
/* Bit field in CMR */
-#define PWM_CMR_CPOL (1 << 9)
-#define PWM_CMR_UPD_CDTY (1 << 10)
+#define PWM_CMR_CPOL BIT(9)
+#define PWM_CMR_UPD_CDTY BIT(10)
+#define PWM_CMR_DTE BIT(16)
#define PWM_CMR_CPRE_MSK 0xF

/* The following registers for PWM v1 */
@@ -47,6 +48,7 @@
#define PWMV2_CDTYUPD 0x08
#define PWMV2_CPRD 0x0C
#define PWMV2_CPRDUPD 0x10
+#define PWMV2_DT 0x18

/*
* Max value for duty and period
@@ -63,6 +65,7 @@ struct atmel_pwm_registers {
u8 period_upd;
u8 duty;
u8 duty_upd;
+ u8 dt;
};

struct atmel_pwm_chip {
@@ -161,6 +164,31 @@ static void atmel_pwm_update_cdty(struct pwm_chip *chip, struct pwm_device *pwm,
atmel_pwm->regs->duty_upd, cdty);
}

+static int atmel_pwm_calculate_deadtime(struct pwm_chip *chip,
+ struct pwm_state *state,
+ unsigned long cprd, unsigned long *dt)
+{
+ unsigned long long cycles;
+
+ if (state->deadtime_fe > state->duty_cycle ||
+ state->deadtime_re > state->period - state->duty_cycle)
+ return -EINVAL;
+
+ if (state->deadtime_fe) {
+ cycles = (unsigned long long)state->deadtime_fe * cprd;
+ do_div(cycles, state->period);
+ *dt = (cycles << 16);
+ }
+
+ if (state->deadtime_re) {
+ cycles = (unsigned long long)state->deadtime_re * cprd;
+ do_div(cycles, state->period);
+ *dt |= cycles;
+ }
+
+ return 0;
+}
+
static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip,
struct pwm_device *pwm,
unsigned long cprd, unsigned long cdty)
@@ -214,7 +242,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
struct pwm_state cstate;
- unsigned long cprd, cdty;
+ unsigned long cprd, cdty, dt = 0;
u32 pres, val;
int ret;

@@ -223,7 +251,9 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (state->enabled) {
if (cstate.enabled &&
cstate.polarity == state->polarity &&
- cstate.period == state->period) {
+ cstate.period == state->period &&
+ cstate.deadtime_re == state->deadtime_re &&
+ cstate.deadtime_fe == state->deadtime_fe) {
cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
atmel_pwm->regs->period);
atmel_pwm_calculate_cdty(state, cprd, &cdty);
@@ -239,6 +269,16 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}

+ if (atmel_pwm->regs->dt) {
+ ret = atmel_pwm_calculate_deadtime(chip, state, cprd,
+ &dt);
+ if (ret) {
+ dev_err(chip->dev,
+ "failed to calculate dead-time\n");
+ return ret;
+ }
+ }
+
atmel_pwm_calculate_cdty(state, cprd, &cdty);

if (cstate.enabled) {
@@ -258,8 +298,19 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
val &= ~PWM_CMR_CPOL;
else
val |= PWM_CMR_CPOL;
+
+ if (atmel_pwm->regs->dt) {
+ if (dt)
+ val |= PWM_CMR_DTE;
+ else
+ val &= ~PWM_CMR_DTE;
+ }
+
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty);
+ if (atmel_pwm->regs->dt)
+ atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm,
+ atmel_pwm->regs->dt, dt);
mutex_lock(&atmel_pwm->isr_lock);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm);
@@ -282,6 +333,7 @@ static const struct atmel_pwm_registers atmel_pwm_regs_v1 = {
.period_upd = PWMV1_CUPD,
.duty = PWMV1_CDTY,
.duty_upd = PWMV1_CUPD,
+ .dt = 0,
};

static const struct atmel_pwm_registers atmel_pwm_regs_v2 = {
@@ -289,6 +341,7 @@ static const struct atmel_pwm_registers atmel_pwm_regs_v2 = {
.period_upd = PWMV2_CPRDUPD,
.duty = PWMV2_CDTY,
.duty_upd = PWMV2_CDTYUPD,
+ .dt = PWMV2_DT,
};

static const struct platform_device_id atmel_pwm_devtypes[] = {
--
2.7.4