diff options
Diffstat (limited to 'drivers/pwm/pwm-rockchip.c')
-rw-r--r-- | drivers/pwm/pwm-rockchip.c | 43 |
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 | ||
34 | struct rockchip_pwm_chip { | 35 | struct 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 | |||
277 | static 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 | }; |
259 | MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids); | 298 | MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids); |