pwm: sti: Fix PWM prescaler handling

This patch fixes the pwm driver to write the complete 8 bits of
the prescaler value to the PWM Control register.

Signed-off-by: Ajit Pal Singh <ajitpal.singh@st.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
Ajit Pal Singh 2014-07-14 15:33:29 +01:00 committed by Thierry Reding
parent acad00d3d6
commit bf9cc80b6c

View File

@ -25,10 +25,13 @@
#define STI_DS_REG(ch) (4 * (ch)) /* Channel's Duty Cycle register */ #define STI_DS_REG(ch) (4 * (ch)) /* Channel's Duty Cycle register */
#define STI_PWMCR 0x50 /* Control/Config register */ #define STI_PWMCR 0x50 /* Control/Config register */
#define STI_INTEN 0x54 /* Interrupt Enable/Disable register */ #define STI_INTEN 0x54 /* Interrupt Enable/Disable register */
#define PWM_PRESCALE_LOW_MASK 0x0f
#define PWM_PRESCALE_HIGH_MASK 0xf0
/* Regfield IDs */ /* Regfield IDs */
enum { enum {
PWMCLK_PRESCALE, PWMCLK_PRESCALE_LOW,
PWMCLK_PRESCALE_HIGH,
PWM_EN, PWM_EN,
PWM_INT_EN, PWM_INT_EN,
@ -49,7 +52,8 @@ struct sti_pwm_chip {
unsigned long clk_rate; unsigned long clk_rate;
struct regmap *regmap; struct regmap *regmap;
struct sti_pwm_compat_data *cdata; struct sti_pwm_compat_data *cdata;
struct regmap_field *prescale; struct regmap_field *prescale_low;
struct regmap_field *prescale_high;
struct regmap_field *pwm_en; struct regmap_field *pwm_en;
struct regmap_field *pwm_int_en; struct regmap_field *pwm_int_en;
unsigned long *pwm_periods; unsigned long *pwm_periods;
@ -58,7 +62,8 @@ struct sti_pwm_chip {
}; };
static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = { static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
[PWMCLK_PRESCALE] = REG_FIELD(STI_PWMCR, 0, 3), [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWMCR, 0, 3),
[PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWMCR, 11, 14),
[PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9), [PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9),
[PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0), [PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0),
}; };
@ -109,10 +114,10 @@ static int sti_pwm_cmp_periods(const void *key, const void *elt)
* For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles.
* The only way to change the period (apart from changing the PWM input clock) * The only way to change the period (apart from changing the PWM input clock)
* is to change the PWM clock prescaler. * is to change the PWM clock prescaler.
* The prescaler is of 4 bits, so only 16 prescaler values and hence only * The prescaler is of 8 bits, so 256 prescaler values and hence
* 16 possible period values are supported (for a particular clock rate). * 256 possible period values are supported (for a particular clock rate).
* The requested period will be applied only if it matches one of these * The requested period will be applied only if it matches one of these
* 16 values. * 256 values.
*/ */
static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) int duty_ns, int period_ns)
@ -154,7 +159,13 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret) if (ret)
return ret; return ret;
ret = regmap_field_write(pc->prescale, prescale); ret = regmap_field_write(pc->prescale_low,
prescale & PWM_PRESCALE_LOW_MASK);
if (ret)
goto clk_dis;
ret = regmap_field_write(pc->prescale_high,
(prescale & PWM_PRESCALE_HIGH_MASK) >> 4);
if (ret) if (ret)
goto clk_dis; goto clk_dis;
@ -222,10 +233,15 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
reg_fields = cdata->reg_fields; reg_fields = cdata->reg_fields;
pc->prescale = devm_regmap_field_alloc(dev, pc->regmap, pc->prescale_low = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWMCLK_PRESCALE]); reg_fields[PWMCLK_PRESCALE_LOW]);
if (IS_ERR(pc->prescale)) if (IS_ERR(pc->prescale_low))
return PTR_ERR(pc->prescale); return PTR_ERR(pc->prescale_low);
pc->prescale_high = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWMCLK_PRESCALE_HIGH]);
if (IS_ERR(pc->prescale_high))
return PTR_ERR(pc->prescale_high);
pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap, pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWM_EN]); reg_fields[PWM_EN]);