@@ -46,6 +46,20 @@
#define BIT_CH(bit, chan) ((bit) << ((chan) * PWMCH_OFFSET))
+#define SUN4I_MAX_PWM_CHANNELS 2
+
+/* regmap fields */
+enum {
+ /* Used bit fields in control register */
+ FIELD_PRESCALER = 0,
+ FIELD_POLARITY,
+ FIELD_CLK_GATING,
+ FIELD_READY,
+
+ /* Keep last */
+ NUM_FIELDS,
+};
+
static const u32 prescaler_table[] = {
120,
180,
@@ -75,6 +89,7 @@ struct sun4i_pwm_chip {
struct pwm_chip chip;
struct clk *clk;
struct regmap *regmap;
+ struct regmap_field *fields[SUN4I_MAX_PWM_CHANNELS][NUM_FIELDS];
spinlock_t ctrl_lock;
const struct sun4i_pwm_data *data;
};
@@ -88,6 +103,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ struct regmap_field **chan_fields = sun4i_pwm->fields[pwm->hwpwm];
u32 prd, dty, val, clk_gate;
u64 clk_rate, div = 0;
unsigned int prescaler = 0;
@@ -140,38 +156,36 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
}
spin_lock(&sun4i_pwm->ctrl_lock);
- err = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
- if (err) {
- dev_err(chip->dev, "failed to read from CTL register\n");
- goto err_cleanup;
- }
- if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
- spin_unlock(&sun4i_pwm->ctrl_lock);
- clk_disable_unprepare(sun4i_pwm->clk);
- return -EBUSY;
- }
-
- clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
- if (clk_gate) {
- val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
- err = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
+ if (sun4i_pwm->data->has_rdy) {
+ err = regmap_field_read(chan_fields[FIELD_READY], &val);
if (err) {
- dev_err(chip->dev, "failed to write to CTL register\n");
+ dev_err(chip->dev, "failed to read ready bit\n");
+ goto err_cleanup;
+ }
+ if (val) {
+ err = -EBUSY;
goto err_cleanup;
}
}
- err = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
+ err = regmap_field_read(chan_fields[FIELD_CLK_GATING], &clk_gate);
if (err) {
- dev_err(chip->dev, "failed to read from CTL register\n");
+ dev_err(chip->dev, "failed to read clock_gating bit\n");
goto err_cleanup;
}
- val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
- val |= BIT_CH(prescaler, pwm->hwpwm);
- err = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
+ if (clk_gate) {
+ err = regmap_field_write(chan_fields[FIELD_CLK_GATING], 0);
+ if (err) {
+ dev_err(chip->dev,
+ "failed to write to clock_gating bit\n");
+ goto err_cleanup;
+ }
+ }
+
+ err = regmap_field_write(chan_fields[FIELD_PRESCALER], prescaler);
if (err) {
- dev_err(chip->dev, "failed to write to CTL register\n");
+ dev_err(chip->dev, "failed to write to prescaler field\n");
goto err_cleanup;
}
@@ -183,16 +197,10 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
}
if (clk_gate) {
- err = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
+ err = regmap_field_write(chan_fields[FIELD_CLK_GATING], 1);
if (err) {
dev_err(chip->dev,
- "failed to read from CTL register\n");
- goto err_cleanup;
- }
- val |= clk_gate;
- err = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
- if (err) {
- dev_err(chip->dev, "failed to write to CTL register\n");
+ "failed to write to clock_gating bit\n");
goto err_cleanup;
}
}
@@ -208,7 +216,7 @@ static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
enum pwm_polarity polarity)
{
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
- u32 val;
+ struct regmap_field **chan_fields = sun4i_pwm->fields[pwm->hwpwm];
int ret;
ret = clk_prepare_enable(sun4i_pwm->clk);
@@ -218,27 +226,14 @@ static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
}
spin_lock(&sun4i_pwm->ctrl_lock);
- ret = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
- if (ret) {
- dev_err(chip->dev,
- "failed to read from CTL register\n");
- goto err_cleanup;
- }
-
- if (polarity != PWM_POLARITY_NORMAL)
- val &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
- else
- val |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
-
- ret = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
- if (ret) {
- dev_err(chip->dev, "failed to write to CTL register\n");
- goto err_cleanup;
- }
+ ret = regmap_field_write(chan_fields[FIELD_POLARITY],
+ polarity == PWM_POLARITY_NORMAL);
+ if (ret)
+ dev_err(chip->dev, "failed to write to polarity bit\n");
-err_cleanup:
spin_unlock(&sun4i_pwm->ctrl_lock);
- clk_disable_unprepare(sun4i_pwm->clk);
+ if (ret)
+ clk_disable_unprepare(sun4i_pwm->clk);
return ret;
}
@@ -246,7 +241,7 @@ static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
- u32 val;
+ u32 mask;
int ret;
ret = clk_prepare_enable(sun4i_pwm->clk);
@@ -255,54 +250,33 @@ static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
return ret;
}
+ mask = BIT_CH(PWM_EN, pwm->hwpwm);
+ mask |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+
spin_lock(&sun4i_pwm->ctrl_lock);
- ret = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
- if (ret) {
- dev_err(chip->dev,
- "failed to read from CTL register\n");
- goto err_cleanup;
- }
- val |= BIT_CH(PWM_EN, pwm->hwpwm);
- val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
- ret = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
- if (ret) {
+ ret = regmap_update_bits(sun4i_pwm->regmap, PWM_CTRL_REG, mask, mask);
+ if (ret)
dev_err(chip->dev, "failed to write to CTL register\n");
- goto err_cleanup;
- }
-
spin_unlock(&sun4i_pwm->ctrl_lock);
- return ret;
-err_cleanup:
- spin_unlock(&sun4i_pwm->ctrl_lock);
if (ret)
clk_disable_unprepare(sun4i_pwm->clk);
-
return ret;
}
static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
- u32 val;
+ u32 mask;
int err;
+ mask = BIT_CH(PWM_EN, pwm->hwpwm);
+ mask |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+
spin_lock(&sun4i_pwm->ctrl_lock);
- err = regmap_read(sun4i_pwm->regmap, PWM_CTRL_REG, &val);
- if (err) {
- dev_err(chip->dev,
- "failed to read from CTL register\n");
- goto err_cleanup;
- }
- val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
- val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
- err = regmap_write(sun4i_pwm->regmap, PWM_CTRL_REG, val);
- if (err) {
+ err = regmap_update_bits(sun4i_pwm->regmap, PWM_CTRL_REG, mask, 0);
+ if (err)
dev_err(chip->dev, "failed to write to CTL register\n");
- goto err_cleanup;
- }
-
-err_cleanup:
spin_unlock(&sun4i_pwm->ctrl_lock);
clk_disable_unprepare(sun4i_pwm->clk);
@@ -316,6 +290,22 @@ static const struct pwm_ops sun4i_pwm_ops = {
.owner = THIS_MODULE,
};
+static const struct reg_field
+sun4i_pwm_regfields[SUN4I_MAX_PWM_CHANNELS][NUM_FIELDS] = {
+ {
+ [FIELD_PRESCALER] = REG_FIELD(PWM_CTRL_REG, 0, 3),
+ [FIELD_POLARITY] = REG_FIELD(PWM_CTRL_REG, 5, 5),
+ [FIELD_CLK_GATING] = REG_FIELD(PWM_CTRL_REG, 6, 6),
+ [FIELD_READY] = REG_FIELD(PWM_CTRL_REG, 28, 28),
+ },
+ {
+ [FIELD_PRESCALER] = REG_FIELD(PWM_CTRL_REG, 15, 18),
+ [FIELD_POLARITY] = REG_FIELD(PWM_CTRL_REG, 20, 20),
+ [FIELD_CLK_GATING] = REG_FIELD(PWM_CTRL_REG, 21, 21),
+ [FIELD_READY] = REG_FIELD(PWM_CTRL_REG, 29, 29),
+ },
+};
+
static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
.has_prescaler_bypass = false,
.has_rdy = false,
@@ -374,6 +364,28 @@ static const struct regmap_config sunxi_pwm_regmap_config = {
.reg_stride = 4,
};
+static int sun4i_alloc_reg_fields(struct device *dev,
+ struct sun4i_pwm_chip *pwm, int chan)
+{
+ int i, err;
+
+ if (chan >= SUN4I_MAX_PWM_CHANNELS)
+ return -EINVAL;
+ for (i = 0; i < NUM_FIELDS; i++) {
+ pwm->fields[chan][i] =
+ devm_regmap_field_alloc(dev, pwm->regmap,
+ sun4i_pwm_regfields[chan][i]);
+ if (IS_ERR(pwm->fields[chan][i])) {
+ dev_err(dev, "regmap field allocation failed\n");
+ err = PTR_ERR(pwm->fields[chan][i]);
+ pwm->fields[chan][i] = NULL;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int sun4i_pwm_probe(struct platform_device *pdev)
{
struct sun4i_pwm_chip *pwm;
@@ -428,15 +440,22 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
goto clk_error;
}
- ret = regmap_read(pwm->regmap, PWM_CTRL_REG, &val);
- if (ret) {
- dev_err(&pdev->dev, "failed to read from CTL register\n");
- goto read_error;
+ for (i = 0; i < pwm->chip.npwm; i++) {
+ ret = sun4i_alloc_reg_fields(&pdev->dev, pwm, i);
+ if (ret)
+ goto read_error;
}
- for (i = 0; i < pwm->chip.npwm; i++)
- if (!(val & BIT_CH(PWM_ACT_STATE, i)))
+
+ for (i = 0; i < pwm->chip.npwm; i++) {
+ ret = regmap_field_read(pwm->fields[i][FIELD_POLARITY], &val);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read polarity bit\n");
+ goto read_error;
+ }
+ if (val)
pwm_set_polarity(&pwm->chip.pwms[i],
PWM_POLARITY_INVERSED);
+ }
clk_disable_unprepare(pwm->clk);
return 0;