pwm-sifive.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2020 SiFive, Inc
  4. * For SiFive's PWM IP block documentation please refer Chapter 14 of
  5. * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
  6. *
  7. * Limitations:
  8. * - When changing both duty cycle and period, we cannot prevent in
  9. * software that the output might produce a period with mixed
  10. * settings (new period length and old duty cycle).
  11. * - The hardware cannot generate a 100% duty cycle.
  12. * - The hardware generates only inverted output.
  13. */
  14. #include <common.h>
  15. #include <clk.h>
  16. #include <div64.h>
  17. #include <dm.h>
  18. #include <pwm.h>
  19. #include <regmap.h>
  20. #include <linux/io.h>
  21. #include <linux/log2.h>
  22. #include <linux/bitfield.h>
  23. /* PWMCFG fields */
  24. #define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0)
  25. #define PWM_SIFIVE_PWMCFG_STICKY BIT(8)
  26. #define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9)
  27. #define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10)
  28. #define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12)
  29. #define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13)
  30. #define PWM_SIFIVE_PWMCFG_CENTER BIT(16)
  31. #define PWM_SIFIVE_PWMCFG_GANG BIT(24)
  32. #define PWM_SIFIVE_PWMCFG_IP BIT(28)
  33. /* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
  34. #define PWM_SIFIVE_SIZE_PWMCMP 4
  35. #define PWM_SIFIVE_CMPWIDTH 16
  36. DECLARE_GLOBAL_DATA_PTR;
  37. struct pwm_sifive_regs {
  38. unsigned long cfg;
  39. unsigned long cnt;
  40. unsigned long pwms;
  41. unsigned long cmp0;
  42. };
  43. struct pwm_sifive_data {
  44. struct pwm_sifive_regs regs;
  45. };
  46. struct pwm_sifive_priv {
  47. void __iomem *base;
  48. ulong freq;
  49. const struct pwm_sifive_data *data;
  50. };
  51. static int pwm_sifive_set_config(struct udevice *dev, uint channel,
  52. uint period_ns, uint duty_ns)
  53. {
  54. struct pwm_sifive_priv *priv = dev_get_priv(dev);
  55. const struct pwm_sifive_regs *regs = &priv->data->regs;
  56. unsigned long scale_pow;
  57. unsigned long long num;
  58. u32 scale, val = 0, frac;
  59. debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
  60. /*
  61. * The PWM unit is used with pwmzerocmp=0, so the only way to modify the
  62. * period length is using pwmscale which provides the number of bits the
  63. * counter is shifted before being feed to the comparators. A period
  64. * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
  65. * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
  66. */
  67. scale_pow = lldiv((uint64_t)priv->freq * period_ns, 1000000000);
  68. scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
  69. val |= FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
  70. /*
  71. * The problem of output producing mixed setting as mentioned at top,
  72. * occurs here. To minimize the window for this problem, we are
  73. * calculating the register values first and then writing them
  74. * consecutively
  75. */
  76. num = (u64)duty_ns * (1U << PWM_SIFIVE_CMPWIDTH);
  77. frac = DIV_ROUND_CLOSEST_ULL(num, period_ns);
  78. frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
  79. writel(val, priv->base + regs->cfg);
  80. writel(frac, priv->base + regs->cmp0 + channel *
  81. PWM_SIFIVE_SIZE_PWMCMP);
  82. return 0;
  83. }
  84. static int pwm_sifive_set_enable(struct udevice *dev, uint channel, bool enable)
  85. {
  86. struct pwm_sifive_priv *priv = dev_get_priv(dev);
  87. const struct pwm_sifive_regs *regs = &priv->data->regs;
  88. u32 val;
  89. debug("%s: Enable '%s'\n", __func__, dev->name);
  90. if (enable) {
  91. val = readl(priv->base + regs->cfg);
  92. val |= PWM_SIFIVE_PWMCFG_EN_ALWAYS;
  93. writel(val, priv->base + regs->cfg);
  94. } else {
  95. writel(0, priv->base + regs->cmp0 + channel *
  96. PWM_SIFIVE_SIZE_PWMCMP);
  97. }
  98. return 0;
  99. }
  100. static int pwm_sifive_ofdata_to_platdata(struct udevice *dev)
  101. {
  102. struct pwm_sifive_priv *priv = dev_get_priv(dev);
  103. priv->base = dev_read_addr_ptr(dev);
  104. return 0;
  105. }
  106. static int pwm_sifive_probe(struct udevice *dev)
  107. {
  108. struct pwm_sifive_priv *priv = dev_get_priv(dev);
  109. struct clk clk;
  110. int ret = 0;
  111. ret = clk_get_by_index(dev, 0, &clk);
  112. if (ret < 0) {
  113. debug("%s get clock fail!\n", __func__);
  114. return -EINVAL;
  115. }
  116. priv->freq = clk_get_rate(&clk);
  117. priv->data = (struct pwm_sifive_data *)dev_get_driver_data(dev);
  118. return 0;
  119. }
  120. static const struct pwm_ops pwm_sifive_ops = {
  121. .set_config = pwm_sifive_set_config,
  122. .set_enable = pwm_sifive_set_enable,
  123. };
  124. static const struct pwm_sifive_data pwm_data = {
  125. .regs = {
  126. .cfg = 0x00,
  127. .cnt = 0x08,
  128. .pwms = 0x10,
  129. .cmp0 = 0x20,
  130. },
  131. };
  132. static const struct udevice_id pwm_sifive_ids[] = {
  133. { .compatible = "sifive,pwm0", .data = (ulong)&pwm_data},
  134. { }
  135. };
  136. U_BOOT_DRIVER(pwm_sifive) = {
  137. .name = "pwm_sifive",
  138. .id = UCLASS_PWM,
  139. .of_match = pwm_sifive_ids,
  140. .ops = &pwm_sifive_ops,
  141. .ofdata_to_platdata = pwm_sifive_ofdata_to_platdata,
  142. .probe = pwm_sifive_probe,
  143. .priv_auto_alloc_size = sizeof(struct pwm_sifive_priv),
  144. };