aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-meson.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-10 12:57:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-10 12:57:15 -0400
commitcece6460c24386d15503ad4e07f740a88f3c8403 (patch)
tree1937ac45f2fb146e0347131ec56a15dd84fd9d4c /drivers/pwm/pwm-meson.c
parent15500c0a506e256976a81c858e33844bb0781e02 (diff)
parentf41efceb46e697a750e93c19e4579dc50697effe (diff)
Merge tag 'pwm/for-5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding: "Nothing out of the ordinary this cycle. The bulk of this is a collection of fixes for existing drivers and some cleanups. There's one new driver for i.MX SoCs and addition of support for some new variants to existing drivers" * tag 'pwm/for-5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: pwm: meson: Add clock source configuration for Meson G12A dt-bindings: pwm: Update bindings for the Meson G12A Family pwm: samsung: Don't uses devm_*() functions in ->request() pwm: Clear chip_data in pwm_put() pwm: Add i.MX TPM PWM driver support dt-bindings: pwm: Add i.MX TPM PWM binding pwm: imx27: Use devm_platform_ioremap_resource() to simplify code pwm: meson: Use the spin-lock only to protect register modifications pwm: meson: Don't disable PWM when setting duty repeatedly pwm: meson: Consider 128 a valid pre-divider pwm: sysfs: fix typo "its" -> "it's" pwm: tiehrpwm: Enable compilation for ARCH_K3 dt-bindings: pwm: tiehrpwm: Add TI AM654 SoC specific compatible pwm: tiehrpwm: Update shadow register for disabling PWMs pwm: img: Turn final 'else if' into 'else' in img_pwm_config pwm: Fix deadlock warning when removing PWM device
Diffstat (limited to 'drivers/pwm/pwm-meson.c')
-rw-r--r--drivers/pwm/pwm-meson.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 4ae5d774443e..fb5a369b1a8d 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -111,6 +111,10 @@ struct meson_pwm {
111 const struct meson_pwm_data *data; 111 const struct meson_pwm_data *data;
112 void __iomem *base; 112 void __iomem *base;
113 u8 inverter_mask; 113 u8 inverter_mask;
114 /*
115 * Protects register (write) access to the REG_MISC_AB register
116 * that is shared between the two PWMs.
117 */
114 spinlock_t lock; 118 spinlock_t lock;
115}; 119};
116 120
@@ -184,7 +188,7 @@ static int meson_pwm_calc(struct meson_pwm *meson,
184 do_div(fin_ps, fin_freq); 188 do_div(fin_ps, fin_freq);
185 189
186 /* Calc pre_div with the period */ 190 /* Calc pre_div with the period */
187 for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { 191 for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) {
188 cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, 192 cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
189 fin_ps * (pre_div + 1)); 193 fin_ps * (pre_div + 1));
190 dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", 194 dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n",
@@ -193,7 +197,7 @@ static int meson_pwm_calc(struct meson_pwm *meson,
193 break; 197 break;
194 } 198 }
195 199
196 if (pre_div == MISC_CLK_DIV_MASK) { 200 if (pre_div > MISC_CLK_DIV_MASK) {
197 dev_err(meson->chip.dev, "unable to get period pre_div\n"); 201 dev_err(meson->chip.dev, "unable to get period pre_div\n");
198 return -EINVAL; 202 return -EINVAL;
199 } 203 }
@@ -235,6 +239,7 @@ static void meson_pwm_enable(struct meson_pwm *meson,
235{ 239{
236 u32 value, clk_shift, clk_enable, enable; 240 u32 value, clk_shift, clk_enable, enable;
237 unsigned int offset; 241 unsigned int offset;
242 unsigned long flags;
238 243
239 switch (id) { 244 switch (id) {
240 case 0: 245 case 0:
@@ -255,6 +260,8 @@ static void meson_pwm_enable(struct meson_pwm *meson,
255 return; 260 return;
256 } 261 }
257 262
263 spin_lock_irqsave(&meson->lock, flags);
264
258 value = readl(meson->base + REG_MISC_AB); 265 value = readl(meson->base + REG_MISC_AB);
259 value &= ~(MISC_CLK_DIV_MASK << clk_shift); 266 value &= ~(MISC_CLK_DIV_MASK << clk_shift);
260 value |= channel->pre_div << clk_shift; 267 value |= channel->pre_div << clk_shift;
@@ -267,11 +274,14 @@ static void meson_pwm_enable(struct meson_pwm *meson,
267 value = readl(meson->base + REG_MISC_AB); 274 value = readl(meson->base + REG_MISC_AB);
268 value |= enable; 275 value |= enable;
269 writel(value, meson->base + REG_MISC_AB); 276 writel(value, meson->base + REG_MISC_AB);
277
278 spin_unlock_irqrestore(&meson->lock, flags);
270} 279}
271 280
272static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) 281static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id)
273{ 282{
274 u32 value, enable; 283 u32 value, enable;
284 unsigned long flags;
275 285
276 switch (id) { 286 switch (id) {
277 case 0: 287 case 0:
@@ -286,9 +296,13 @@ static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id)
286 return; 296 return;
287 } 297 }
288 298
299 spin_lock_irqsave(&meson->lock, flags);
300
289 value = readl(meson->base + REG_MISC_AB); 301 value = readl(meson->base + REG_MISC_AB);
290 value &= ~enable; 302 value &= ~enable;
291 writel(value, meson->base + REG_MISC_AB); 303 writel(value, meson->base + REG_MISC_AB);
304
305 spin_unlock_irqrestore(&meson->lock, flags);
292} 306}
293 307
294static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 308static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -296,29 +310,21 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
296{ 310{
297 struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); 311 struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
298 struct meson_pwm *meson = to_meson_pwm(chip); 312 struct meson_pwm *meson = to_meson_pwm(chip);
299 unsigned long flags;
300 int err = 0; 313 int err = 0;
301 314
302 if (!state) 315 if (!state)
303 return -EINVAL; 316 return -EINVAL;
304 317
305 spin_lock_irqsave(&meson->lock, flags);
306
307 if (!state->enabled) { 318 if (!state->enabled) {
308 meson_pwm_disable(meson, pwm->hwpwm); 319 meson_pwm_disable(meson, pwm->hwpwm);
309 channel->state.enabled = false; 320 channel->state.enabled = false;
310 321
311 goto unlock; 322 return 0;
312 } 323 }
313 324
314 if (state->period != channel->state.period || 325 if (state->period != channel->state.period ||
315 state->duty_cycle != channel->state.duty_cycle || 326 state->duty_cycle != channel->state.duty_cycle ||
316 state->polarity != channel->state.polarity) { 327 state->polarity != channel->state.polarity) {
317 if (channel->state.enabled) {
318 meson_pwm_disable(meson, pwm->hwpwm);
319 channel->state.enabled = false;
320 }
321
322 if (state->polarity != channel->state.polarity) { 328 if (state->polarity != channel->state.polarity) {
323 if (state->polarity == PWM_POLARITY_NORMAL) 329 if (state->polarity == PWM_POLARITY_NORMAL)
324 meson->inverter_mask |= BIT(pwm->hwpwm); 330 meson->inverter_mask |= BIT(pwm->hwpwm);
@@ -329,7 +335,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
329 err = meson_pwm_calc(meson, channel, pwm->hwpwm, 335 err = meson_pwm_calc(meson, channel, pwm->hwpwm,
330 state->duty_cycle, state->period); 336 state->duty_cycle, state->period);
331 if (err < 0) 337 if (err < 0)
332 goto unlock; 338 return err;
333 339
334 channel->state.polarity = state->polarity; 340 channel->state.polarity = state->polarity;
335 channel->state.period = state->period; 341 channel->state.period = state->period;
@@ -341,9 +347,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
341 channel->state.enabled = true; 347 channel->state.enabled = true;
342 } 348 }
343 349
344unlock: 350 return 0;
345 spin_unlock_irqrestore(&meson->lock, flags);
346 return err;
347} 351}
348 352
349static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 353static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -429,6 +433,24 @@ static const struct meson_pwm_data pwm_axg_ao_data = {
429 .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names), 433 .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names),
430}; 434};
431 435
436static const char * const pwm_g12a_ao_cd_parent_names[] = {
437 "aoclk81", "xtal",
438};
439
440static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
441 .parent_names = pwm_g12a_ao_cd_parent_names,
442 .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names),
443};
444
445static const char * const pwm_g12a_ee_parent_names[] = {
446 "xtal", "hdmi_pll", "fclk_div4", "fclk_div3"
447};
448
449static const struct meson_pwm_data pwm_g12a_ee_data = {
450 .parent_names = pwm_g12a_ee_parent_names,
451 .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_names),
452};
453
432static const struct of_device_id meson_pwm_matches[] = { 454static const struct of_device_id meson_pwm_matches[] = {
433 { 455 {
434 .compatible = "amlogic,meson8b-pwm", 456 .compatible = "amlogic,meson8b-pwm",
@@ -450,6 +472,18 @@ static const struct of_device_id meson_pwm_matches[] = {
450 .compatible = "amlogic,meson-axg-ao-pwm", 472 .compatible = "amlogic,meson-axg-ao-pwm",
451 .data = &pwm_axg_ao_data 473 .data = &pwm_axg_ao_data
452 }, 474 },
475 {
476 .compatible = "amlogic,meson-g12a-ee-pwm",
477 .data = &pwm_g12a_ee_data
478 },
479 {
480 .compatible = "amlogic,meson-g12a-ao-pwm-ab",
481 .data = &pwm_axg_ao_data
482 },
483 {
484 .compatible = "amlogic,meson-g12a-ao-pwm-cd",
485 .data = &pwm_g12a_ao_cd_data
486 },
453 {}, 487 {},
454}; 488};
455MODULE_DEVICE_TABLE(of, meson_pwm_matches); 489MODULE_DEVICE_TABLE(of, meson_pwm_matches);