diff options
Diffstat (limited to 'drivers/pwm/pwm-tiehrpwm.c')
-rw-r--r-- | drivers/pwm/pwm-tiehrpwm.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 9ffd389d0c8b..72a6dd40c9ec 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
26 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
27 | #include <linux/pm_runtime.h> | 27 | #include <linux/pm_runtime.h> |
28 | #include <linux/of_device.h> | ||
29 | #include <linux/pinctrl/consumer.h> | ||
30 | |||
31 | #include "pwm-tipwmss.h" | ||
28 | 32 | ||
29 | /* EHRPWM registers and bits definitions */ | 33 | /* EHRPWM registers and bits definitions */ |
30 | 34 | ||
@@ -115,6 +119,7 @@ struct ehrpwm_pwm_chip { | |||
115 | void __iomem *mmio_base; | 119 | void __iomem *mmio_base; |
116 | unsigned long period_cycles[NUM_PWM_CHANNEL]; | 120 | unsigned long period_cycles[NUM_PWM_CHANNEL]; |
117 | enum pwm_polarity polarity[NUM_PWM_CHANNEL]; | 121 | enum pwm_polarity polarity[NUM_PWM_CHANNEL]; |
122 | struct clk *tbclk; | ||
118 | }; | 123 | }; |
119 | 124 | ||
120 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 125 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) |
@@ -335,6 +340,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
335 | /* Channels polarity can be configured from action qualifier module */ | 340 | /* Channels polarity can be configured from action qualifier module */ |
336 | configure_polarity(pc, pwm->hwpwm); | 341 | configure_polarity(pc, pwm->hwpwm); |
337 | 342 | ||
343 | /* Enable TBCLK before enabling PWM device */ | ||
344 | clk_enable(pc->tbclk); | ||
345 | |||
338 | /* Enable time counter for free_run */ | 346 | /* Enable time counter for free_run */ |
339 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); | 347 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); |
340 | return 0; | 348 | return 0; |
@@ -363,6 +371,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
363 | 371 | ||
364 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); | 372 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); |
365 | 373 | ||
374 | /* Disabling TBCLK on PWM disable */ | ||
375 | clk_disable(pc->tbclk); | ||
376 | |||
366 | /* Stop Time base counter */ | 377 | /* Stop Time base counter */ |
367 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); | 378 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); |
368 | 379 | ||
@@ -392,12 +403,24 @@ static const struct pwm_ops ehrpwm_pwm_ops = { | |||
392 | .owner = THIS_MODULE, | 403 | .owner = THIS_MODULE, |
393 | }; | 404 | }; |
394 | 405 | ||
406 | static const struct of_device_id ehrpwm_of_match[] = { | ||
407 | { .compatible = "ti,am33xx-ehrpwm" }, | ||
408 | {}, | ||
409 | }; | ||
410 | MODULE_DEVICE_TABLE(of, ehrpwm_of_match); | ||
411 | |||
395 | static int ehrpwm_pwm_probe(struct platform_device *pdev) | 412 | static int ehrpwm_pwm_probe(struct platform_device *pdev) |
396 | { | 413 | { |
397 | int ret; | 414 | int ret; |
398 | struct resource *r; | 415 | struct resource *r; |
399 | struct clk *clk; | 416 | struct clk *clk; |
400 | struct ehrpwm_pwm_chip *pc; | 417 | struct ehrpwm_pwm_chip *pc; |
418 | u16 status; | ||
419 | struct pinctrl *pinctrl; | ||
420 | |||
421 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
422 | if (IS_ERR(pinctrl)) | ||
423 | dev_warn(&pdev->dev, "unable to select pin group\n"); | ||
401 | 424 | ||
402 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); | 425 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); |
403 | if (!pc) { | 426 | if (!pc) { |
@@ -419,6 +442,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) | |||
419 | 442 | ||
420 | pc->chip.dev = &pdev->dev; | 443 | pc->chip.dev = &pdev->dev; |
421 | pc->chip.ops = &ehrpwm_pwm_ops; | 444 | pc->chip.ops = &ehrpwm_pwm_ops; |
445 | pc->chip.of_xlate = of_pwm_xlate_with_flags; | ||
446 | pc->chip.of_pwm_n_cells = 3; | ||
422 | pc->chip.base = -1; | 447 | pc->chip.base = -1; |
423 | pc->chip.npwm = NUM_PWM_CHANNEL; | 448 | pc->chip.npwm = NUM_PWM_CHANNEL; |
424 | 449 | ||
@@ -432,6 +457,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) | |||
432 | if (!pc->mmio_base) | 457 | if (!pc->mmio_base) |
433 | return -EADDRNOTAVAIL; | 458 | return -EADDRNOTAVAIL; |
434 | 459 | ||
460 | /* Acquire tbclk for Time Base EHRPWM submodule */ | ||
461 | pc->tbclk = devm_clk_get(&pdev->dev, "tbclk"); | ||
462 | if (IS_ERR(pc->tbclk)) { | ||
463 | dev_err(&pdev->dev, "Failed to get tbclk\n"); | ||
464 | return PTR_ERR(pc->tbclk); | ||
465 | } | ||
466 | |||
435 | ret = pwmchip_add(&pc->chip); | 467 | ret = pwmchip_add(&pc->chip); |
436 | if (ret < 0) { | 468 | if (ret < 0) { |
437 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | 469 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); |
@@ -439,14 +471,40 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) | |||
439 | } | 471 | } |
440 | 472 | ||
441 | pm_runtime_enable(&pdev->dev); | 473 | pm_runtime_enable(&pdev->dev); |
474 | pm_runtime_get_sync(&pdev->dev); | ||
475 | |||
476 | status = pwmss_submodule_state_change(pdev->dev.parent, | ||
477 | PWMSS_EPWMCLK_EN); | ||
478 | if (!(status & PWMSS_EPWMCLK_EN_ACK)) { | ||
479 | dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); | ||
480 | ret = -EINVAL; | ||
481 | goto pwmss_clk_failure; | ||
482 | } | ||
483 | |||
484 | pm_runtime_put_sync(&pdev->dev); | ||
485 | |||
442 | platform_set_drvdata(pdev, pc); | 486 | platform_set_drvdata(pdev, pc); |
443 | return 0; | 487 | return 0; |
488 | |||
489 | pwmss_clk_failure: | ||
490 | pm_runtime_put_sync(&pdev->dev); | ||
491 | pm_runtime_disable(&pdev->dev); | ||
492 | pwmchip_remove(&pc->chip); | ||
493 | return ret; | ||
444 | } | 494 | } |
445 | 495 | ||
446 | static int ehrpwm_pwm_remove(struct platform_device *pdev) | 496 | static int ehrpwm_pwm_remove(struct platform_device *pdev) |
447 | { | 497 | { |
448 | struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); | 498 | struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); |
449 | 499 | ||
500 | pm_runtime_get_sync(&pdev->dev); | ||
501 | /* | ||
502 | * Due to hardware misbehaviour, acknowledge of the stop_req | ||
503 | * is missing. Hence checking of the status bit skipped. | ||
504 | */ | ||
505 | pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ); | ||
506 | pm_runtime_put_sync(&pdev->dev); | ||
507 | |||
450 | pm_runtime_put_sync(&pdev->dev); | 508 | pm_runtime_put_sync(&pdev->dev); |
451 | pm_runtime_disable(&pdev->dev); | 509 | pm_runtime_disable(&pdev->dev); |
452 | return pwmchip_remove(&pc->chip); | 510 | return pwmchip_remove(&pc->chip); |
@@ -454,7 +512,9 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev) | |||
454 | 512 | ||
455 | static struct platform_driver ehrpwm_pwm_driver = { | 513 | static struct platform_driver ehrpwm_pwm_driver = { |
456 | .driver = { | 514 | .driver = { |
457 | .name = "ehrpwm", | 515 | .name = "ehrpwm", |
516 | .owner = THIS_MODULE, | ||
517 | .of_match_table = ehrpwm_of_match, | ||
458 | }, | 518 | }, |
459 | .probe = ehrpwm_pwm_probe, | 519 | .probe = ehrpwm_pwm_probe, |
460 | .remove = ehrpwm_pwm_remove, | 520 | .remove = ehrpwm_pwm_remove, |