pwm-apple.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-License-Identifier: GPL-2.0 OR MIT
  2. /*
  3. * Driver for the Apple SoC PWM controller
  4. *
  5. * Copyright The Asahi Linux Contributors
  6. *
  7. * Limitations:
  8. * - The writes to cycle registers are shadowed until a write to
  9. * the control register.
  10. * - If both OFF_CYCLES and ON_CYCLES are set to 0, the output
  11. * is a constant off signal.
  12. * - When APPLE_PWM_CTRL is set to 0, the output is constant low
  13. */
  14. #include <linux/mod_devicetable.h>
  15. #include <linux/module.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/pwm.h>
  18. #include <linux/io.h>
  19. #include <linux/clk.h>
  20. #include <linux/math64.h>
  21. #define APPLE_PWM_CTRL 0x00
  22. #define APPLE_PWM_ON_CYCLES 0x1c
  23. #define APPLE_PWM_OFF_CYCLES 0x18
  24. #define APPLE_PWM_CTRL_ENABLE BIT(0)
  25. #define APPLE_PWM_CTRL_MODE BIT(2)
  26. #define APPLE_PWM_CTRL_UPDATE BIT(5)
  27. #define APPLE_PWM_CTRL_TRIGGER BIT(9)
  28. #define APPLE_PWM_CTRL_INVERT BIT(10)
  29. #define APPLE_PWM_CTRL_OUTPUT_ENABLE BIT(14)
  30. struct apple_pwm {
  31. void __iomem *base;
  32. u64 clkrate;
  33. };
  34. static inline struct apple_pwm *to_apple_pwm(struct pwm_chip *chip)
  35. {
  36. return pwmchip_get_drvdata(chip);
  37. }
  38. static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
  39. const struct pwm_state *state)
  40. {
  41. struct apple_pwm *fpwm;
  42. if (state->polarity == PWM_POLARITY_INVERSED)
  43. return -EINVAL;
  44. fpwm = to_apple_pwm(chip);
  45. if (state->enabled) {
  46. u64 on_cycles, off_cycles;
  47. on_cycles = mul_u64_u64_div_u64(fpwm->clkrate,
  48. state->duty_cycle, NSEC_PER_SEC);
  49. if (on_cycles > 0xFFFFFFFF)
  50. on_cycles = 0xFFFFFFFF;
  51. off_cycles = mul_u64_u64_div_u64(fpwm->clkrate,
  52. state->period, NSEC_PER_SEC) - on_cycles;
  53. if (off_cycles > 0xFFFFFFFF)
  54. off_cycles = 0xFFFFFFFF;
  55. writel(on_cycles, fpwm->base + APPLE_PWM_ON_CYCLES);
  56. writel(off_cycles, fpwm->base + APPLE_PWM_OFF_CYCLES);
  57. writel(APPLE_PWM_CTRL_ENABLE | APPLE_PWM_CTRL_OUTPUT_ENABLE | APPLE_PWM_CTRL_UPDATE,
  58. fpwm->base + APPLE_PWM_CTRL);
  59. } else {
  60. writel(0, fpwm->base + APPLE_PWM_CTRL);
  61. }
  62. return 0;
  63. }
  64. static int apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
  65. struct pwm_state *state)
  66. {
  67. struct apple_pwm *fpwm;
  68. u32 on_cycles, off_cycles, ctrl;
  69. fpwm = to_apple_pwm(chip);
  70. ctrl = readl(fpwm->base + APPLE_PWM_CTRL);
  71. on_cycles = readl(fpwm->base + APPLE_PWM_ON_CYCLES);
  72. off_cycles = readl(fpwm->base + APPLE_PWM_OFF_CYCLES);
  73. state->enabled = (ctrl & APPLE_PWM_CTRL_ENABLE) && (ctrl & APPLE_PWM_CTRL_OUTPUT_ENABLE);
  74. state->polarity = PWM_POLARITY_NORMAL;
  75. // on_cycles + off_cycles is 33 bits, NSEC_PER_SEC is 30, there is no overflow
  76. state->duty_cycle = DIV64_U64_ROUND_UP((u64)on_cycles * NSEC_PER_SEC, fpwm->clkrate);
  77. state->period = DIV64_U64_ROUND_UP(((u64)off_cycles + (u64)on_cycles) *
  78. NSEC_PER_SEC, fpwm->clkrate);
  79. return 0;
  80. }
  81. static const struct pwm_ops apple_pwm_ops = {
  82. .apply = apple_pwm_apply,
  83. .get_state = apple_pwm_get_state,
  84. };
  85. static int apple_pwm_probe(struct platform_device *pdev)
  86. {
  87. struct pwm_chip *chip;
  88. struct apple_pwm *fpwm;
  89. struct clk *clk;
  90. int ret;
  91. chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*fpwm));
  92. if (IS_ERR(chip))
  93. return PTR_ERR(chip);
  94. fpwm = to_apple_pwm(chip);
  95. fpwm->base = devm_platform_ioremap_resource(pdev, 0);
  96. if (IS_ERR(fpwm->base))
  97. return PTR_ERR(fpwm->base);
  98. clk = devm_clk_get_enabled(&pdev->dev, NULL);
  99. if (IS_ERR(clk))
  100. return dev_err_probe(&pdev->dev, PTR_ERR(clk), "unable to get the clock");
  101. /*
  102. * Uses the 24MHz system clock on all existing devices, can only
  103. * happen if the device tree is broken
  104. *
  105. * This check is done to prevent an overflow in .apply
  106. */
  107. fpwm->clkrate = clk_get_rate(clk);
  108. if (fpwm->clkrate > NSEC_PER_SEC)
  109. return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock out of range");
  110. chip->ops = &apple_pwm_ops;
  111. ret = devm_pwmchip_add(&pdev->dev, chip);
  112. if (ret < 0)
  113. return dev_err_probe(&pdev->dev, ret, "unable to add pwm chip");
  114. return 0;
  115. }
  116. static const struct of_device_id apple_pwm_of_match[] = {
  117. { .compatible = "apple,s5l-fpwm" },
  118. {}
  119. };
  120. MODULE_DEVICE_TABLE(of, apple_pwm_of_match);
  121. static struct platform_driver apple_pwm_driver = {
  122. .probe = apple_pwm_probe,
  123. .driver = {
  124. .name = "apple-pwm",
  125. .of_match_table = apple_pwm_of_match,
  126. },
  127. };
  128. module_platform_driver(apple_pwm_driver);
  129. MODULE_DESCRIPTION("Apple SoC PWM driver");
  130. MODULE_LICENSE("Dual MIT/GPL");