pwm-pxa.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * drivers/pwm/pwm-pxa.c
  4. *
  5. * simple driver for PWM (Pulse Width Modulator) controller
  6. *
  7. * 2008-02-13 initial version
  8. * eric miao <eric.miao@marvell.com>
  9. *
  10. * Links to reference manuals for some of the supported PWM chips can be found
  11. * in Documentation/arch/arm/marvell.rst.
  12. *
  13. * Limitations:
  14. * - When PWM is stopped, the current PWM period stops abruptly at the next
  15. * input clock (PWMCR_SD is set) and the output is driven to inactive.
  16. */
  17. #include <linux/mod_devicetable.h>
  18. #include <linux/module.h>
  19. #include <linux/kernel.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/slab.h>
  22. #include <linux/err.h>
  23. #include <linux/clk.h>
  24. #include <linux/io.h>
  25. #include <linux/pwm.h>
  26. #include <linux/of.h>
  27. #include <asm/div64.h>
  28. #define HAS_SECONDARY_PWM 0x10
  29. static const struct platform_device_id pwm_id_table[] = {
  30. /* PWM has_secondary_pwm? */
  31. { "pxa25x-pwm", 0 },
  32. { "pxa27x-pwm", HAS_SECONDARY_PWM },
  33. { "pxa168-pwm", 0 },
  34. { "pxa910-pwm", 0 },
  35. { },
  36. };
  37. MODULE_DEVICE_TABLE(platform, pwm_id_table);
  38. /* PWM registers and bits definitions */
  39. #define PWMCR (0x00)
  40. #define PWMDCR (0x04)
  41. #define PWMPCR (0x08)
  42. #define PWMCR_SD (1 << 6)
  43. #define PWMDCR_FD (1 << 10)
  44. struct pxa_pwm_chip {
  45. struct device *dev;
  46. struct clk *clk;
  47. void __iomem *mmio_base;
  48. };
  49. static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
  50. {
  51. return pwmchip_get_drvdata(chip);
  52. }
  53. /*
  54. * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
  55. * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
  56. */
  57. static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
  58. u64 duty_ns, u64 period_ns)
  59. {
  60. struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
  61. unsigned long long c;
  62. unsigned long period_cycles, prescale, pv, dc;
  63. unsigned long offset;
  64. offset = pwm->hwpwm ? 0x10 : 0;
  65. c = clk_get_rate(pc->clk);
  66. c = c * period_ns;
  67. do_div(c, 1000000000);
  68. period_cycles = c;
  69. if (period_cycles < 1)
  70. period_cycles = 1;
  71. prescale = (period_cycles - 1) / 1024;
  72. pv = period_cycles / (prescale + 1) - 1;
  73. if (prescale > 63)
  74. return -EINVAL;
  75. if (duty_ns == period_ns)
  76. dc = PWMDCR_FD;
  77. else
  78. dc = mul_u64_u64_div_u64(pv + 1, duty_ns, period_ns);
  79. writel(prescale | PWMCR_SD, pc->mmio_base + offset + PWMCR);
  80. writel(dc, pc->mmio_base + offset + PWMDCR);
  81. writel(pv, pc->mmio_base + offset + PWMPCR);
  82. return 0;
  83. }
  84. static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
  85. const struct pwm_state *state)
  86. {
  87. struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
  88. u64 duty_cycle;
  89. int err;
  90. if (state->polarity != PWM_POLARITY_NORMAL)
  91. return -EINVAL;
  92. err = clk_prepare_enable(pc->clk);
  93. if (err)
  94. return err;
  95. duty_cycle = state->enabled ? state->duty_cycle : 0;
  96. err = pxa_pwm_config(chip, pwm, duty_cycle, state->period);
  97. if (err) {
  98. clk_disable_unprepare(pc->clk);
  99. return err;
  100. }
  101. if (state->enabled && !pwm->state.enabled)
  102. return 0;
  103. clk_disable_unprepare(pc->clk);
  104. if (!state->enabled && pwm->state.enabled)
  105. clk_disable_unprepare(pc->clk);
  106. return 0;
  107. }
  108. static const struct pwm_ops pxa_pwm_ops = {
  109. .apply = pxa_pwm_apply,
  110. };
  111. #ifdef CONFIG_OF
  112. /*
  113. * Device tree users must create one device instance for each PWM channel.
  114. * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
  115. * code that this is a single channel pxa25x-pwm. Currently all devices are
  116. * supported identically.
  117. */
  118. static const struct of_device_id pwm_of_match[] = {
  119. { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]},
  120. { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]},
  121. { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]},
  122. { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]},
  123. { }
  124. };
  125. MODULE_DEVICE_TABLE(of, pwm_of_match);
  126. #else
  127. #define pwm_of_match NULL
  128. #endif
  129. static int pwm_probe(struct platform_device *pdev)
  130. {
  131. const struct platform_device_id *id = platform_get_device_id(pdev);
  132. struct pwm_chip *chip;
  133. struct pxa_pwm_chip *pc;
  134. int ret = 0;
  135. if (IS_ENABLED(CONFIG_OF) && id == NULL)
  136. id = of_device_get_match_data(&pdev->dev);
  137. if (id == NULL)
  138. return -EINVAL;
  139. chip = devm_pwmchip_alloc(&pdev->dev,
  140. (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1,
  141. sizeof(*pc));
  142. if (IS_ERR(chip))
  143. return PTR_ERR(chip);
  144. pc = to_pxa_pwm_chip(chip);
  145. pc->clk = devm_clk_get(&pdev->dev, NULL);
  146. if (IS_ERR(pc->clk))
  147. return PTR_ERR(pc->clk);
  148. chip->ops = &pxa_pwm_ops;
  149. if (IS_ENABLED(CONFIG_OF))
  150. chip->of_xlate = of_pwm_single_xlate;
  151. pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
  152. if (IS_ERR(pc->mmio_base))
  153. return PTR_ERR(pc->mmio_base);
  154. ret = devm_pwmchip_add(&pdev->dev, chip);
  155. if (ret < 0) {
  156. dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
  157. return ret;
  158. }
  159. return 0;
  160. }
  161. static struct platform_driver pwm_driver = {
  162. .driver = {
  163. .name = "pxa25x-pwm",
  164. .of_match_table = pwm_of_match,
  165. },
  166. .probe = pwm_probe,
  167. .id_table = pwm_id_table,
  168. };
  169. module_platform_driver(pwm_driver);
  170. MODULE_DESCRIPTION("PXA Pulse Width Modulator driver");
  171. MODULE_LICENSE("GPL v2");