summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Wu <david.wu@rock-chips.com>2017-08-08 11:42:47 -0400
committerThierry Reding <thierry.reding@gmail.com>2017-08-18 11:44:34 -0400
commit3f9a363133eae0d01e77200af4ce9b58a4a9fc24 (patch)
tree6fb6401fdebe25b8be39c7e06ad3602438a9ad05
parent831b2790507b3aac3213e9f39c714d85b0220098 (diff)
pwm: rockchip: Add rk3328 support
The rk3328 SoC supports atomic update, we could lock the configuration of period and duty at first, after unlock is configured, the period and duty are effective at the same time. If the polarity, period and duty need to be configured together, the way for atomic update is "configure lock and old polarity" -> "configure period and duty" -> "configure unlock and new polarity". Signed-off-by: David Wu <david.wu@rock-chips.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r--drivers/pwm/pwm-rockchip.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index a3fcb404036d..4d99d468df09 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -29,6 +29,7 @@
29#define PWM_INACTIVE_POSITIVE (1 << 4) 29#define PWM_INACTIVE_POSITIVE (1 << 4)
30#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE) 30#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
31#define PWM_OUTPUT_LEFT (0 << 5) 31#define PWM_OUTPUT_LEFT (0 << 5)
32#define PWM_LOCK_EN (1 << 6)
32#define PWM_LP_DISABLE (0 << 8) 33#define PWM_LP_DISABLE (0 << 8)
33 34
34struct rockchip_pwm_chip { 35struct rockchip_pwm_chip {
@@ -50,6 +51,7 @@ struct rockchip_pwm_data {
50 struct rockchip_pwm_regs regs; 51 struct rockchip_pwm_regs regs;
51 unsigned int prescaler; 52 unsigned int prescaler;
52 bool supports_polarity; 53 bool supports_polarity;
54 bool supports_lock;
53 u32 enable_conf; 55 u32 enable_conf;
54}; 56};
55 57
@@ -121,10 +123,19 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
121 div = clk_rate * state->duty_cycle; 123 div = clk_rate * state->duty_cycle;
122 duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC); 124 duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC);
123 125
126 /*
127 * Lock the period and duty of previous configuration, then
128 * change the duty and period, that would not be effective.
129 */
130 ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
131 if (pc->data->supports_lock) {
132 ctrl |= PWM_LOCK_EN;
133 writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl);
134 }
135
124 writel(period, pc->base + pc->data->regs.period); 136 writel(period, pc->base + pc->data->regs.period);
125 writel(duty, pc->base + pc->data->regs.duty); 137 writel(duty, pc->base + pc->data->regs.duty);
126 138
127 ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
128 if (pc->data->supports_polarity) { 139 if (pc->data->supports_polarity) {
129 ctrl &= ~PWM_POLARITY_MASK; 140 ctrl &= ~PWM_POLARITY_MASK;
130 if (state->polarity == PWM_POLARITY_INVERSED) 141 if (state->polarity == PWM_POLARITY_INVERSED)
@@ -132,6 +143,15 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
132 else 143 else
133 ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; 144 ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
134 } 145 }
146
147 /*
148 * Unlock and set polarity at the same time,
149 * the configuration of duty, period and polarity
150 * would be effective together at next period.
151 */
152 if (pc->data->supports_lock)
153 ctrl &= ~PWM_LOCK_EN;
154
135 writel(ctrl, pc->base + pc->data->regs.ctrl); 155 writel(ctrl, pc->base + pc->data->regs.ctrl);
136} 156}
137 157
@@ -180,7 +200,8 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
180 pwm_get_state(pwm, &curstate); 200 pwm_get_state(pwm, &curstate);
181 enabled = curstate.enabled; 201 enabled = curstate.enabled;
182 202
183 if (state->polarity != curstate.polarity && enabled) { 203 if (state->polarity != curstate.polarity && enabled &&
204 !pc->data->supports_lock) {
184 ret = rockchip_pwm_enable(chip, pwm, false); 205 ret = rockchip_pwm_enable(chip, pwm, false);
185 if (ret) 206 if (ret)
186 goto out; 207 goto out;
@@ -221,6 +242,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
221 }, 242 },
222 .prescaler = 2, 243 .prescaler = 2,
223 .supports_polarity = false, 244 .supports_polarity = false,
245 .supports_lock = false,
224 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, 246 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
225}; 247};
226 248
@@ -233,6 +255,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
233 }, 255 },
234 .prescaler = 1, 256 .prescaler = 1,
235 .supports_polarity = true, 257 .supports_polarity = true,
258 .supports_lock = false,
236 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | 259 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
237 PWM_CONTINUOUS, 260 PWM_CONTINUOUS,
238}; 261};
@@ -246,6 +269,21 @@ static const struct rockchip_pwm_data pwm_data_vop = {
246 }, 269 },
247 .prescaler = 1, 270 .prescaler = 1,
248 .supports_polarity = true, 271 .supports_polarity = true,
272 .supports_lock = false,
273 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
274 PWM_CONTINUOUS,
275};
276
277static const struct rockchip_pwm_data pwm_data_v3 = {
278 .regs = {
279 .duty = 0x08,
280 .period = 0x04,
281 .cntr = 0x00,
282 .ctrl = 0x0c,
283 },
284 .prescaler = 1,
285 .supports_polarity = true,
286 .supports_lock = true,
249 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | 287 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
250 PWM_CONTINUOUS, 288 PWM_CONTINUOUS,
251}; 289};
@@ -254,6 +292,7 @@ static const struct of_device_id rockchip_pwm_dt_ids[] = {
254 { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1}, 292 { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
255 { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2}, 293 { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
256 { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop}, 294 { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
295 { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
257 { /* sentinel */ } 296 { /* sentinel */ }
258}; 297};
259MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids); 298MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);