summaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-rockchip.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-rockchip.c')
-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);