040-pwm.patch 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. --- a/arch/arm/plat-mxc/pwm.c
  2. +++ b/arch/arm/plat-mxc/pwm.c
  3. @@ -25,6 +25,11 @@
  4. #define MX1_PWMS 0x04 /* PWM Sample Register */
  5. #define MX1_PWMP 0x08 /* PWM Period Register */
  6. +#define MX1_PWMC_EN (1 << 4)
  7. +#define MX1_PWMC_PRESCALER_MASK (0x7f << 8)
  8. +#define MX1_PWMC_PRESCALER(x) ((x & 0x7f) << 8)
  9. +#define MX1_PWMC_CLKSEL_MASK 0x3
  10. +#define MX1_PWMC_CLKSEL(x) ((x & 0x3))
  11. /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
  12. @@ -54,26 +59,33 @@ struct pwm_device {
  13. int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
  14. {
  15. + unsigned long long c;
  16. + unsigned long period_cycles, duty_cycles, prescale;
  17. +
  18. if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
  19. return -EINVAL;
  20. + c = clk_get_rate(pwm->clk);
  21. +
  22. + c = c * period_ns;
  23. +
  24. + if (cpu_is_mx1() || cpu_is_mx2())
  25. + c >>= 1;
  26. +
  27. + do_div(c, 1000000000);
  28. + period_cycles = c;
  29. +
  30. + prescale = period_cycles / 0x10000 + 1;
  31. +
  32. + period_cycles /= prescale;
  33. + c = (unsigned long long)period_cycles * duty_ns;
  34. + do_div(c, period_ns);
  35. + duty_cycles = c;
  36. +
  37. +
  38. if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
  39. - unsigned long long c;
  40. - unsigned long period_cycles, duty_cycles, prescale;
  41. u32 cr;
  42. - c = clk_get_rate(pwm->clk);
  43. - c = c * period_ns;
  44. - do_div(c, 1000000000);
  45. - period_cycles = c;
  46. -
  47. - prescale = period_cycles / 0x10000 + 1;
  48. -
  49. - period_cycles /= prescale;
  50. - c = (unsigned long long)period_cycles * duty_ns;
  51. - do_div(c, period_ns);
  52. - duty_cycles = c;
  53. -
  54. writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
  55. writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
  56. @@ -86,25 +98,28 @@ int pwm_config(struct pwm_device *pwm, i
  57. writel(cr, pwm->mmio_base + MX3_PWMCR);
  58. } else if (cpu_is_mx1() || cpu_is_mx21()) {
  59. - /* The PWM subsystem allows for exact frequencies. However,
  60. - * I cannot connect a scope on my device to the PWM line and
  61. - * thus cannot provide the program the PWM controller
  62. - * exactly. Instead, I'm relying on the fact that the
  63. - * Bootloader (u-boot or WinCE+haret) has programmed the PWM
  64. - * function group already. So I'll just modify the PWM sample
  65. - * register to follow the ratio of duty_ns vs. period_ns
  66. - * accordingly.
  67. - *
  68. - * This is good enough for programming the brightness of
  69. - * the LCD backlight.
  70. - *
  71. - * The real implementation would divide PERCLK[0] first by
  72. - * both the prescaler (/1 .. /128) and then by CLKSEL
  73. - * (/2 .. /16).
  74. - */
  75. - u32 max = readl(pwm->mmio_base + MX1_PWMP);
  76. - u32 p = max * duty_ns / period_ns;
  77. - writel(max - p, pwm->mmio_base + MX1_PWMS);
  78. + unsigned long clksel = 0;
  79. + u32 ctrl;
  80. +
  81. + while (prescale >= 0x80 && clksel < 4) {
  82. + prescale >>= 1;
  83. + ++clksel;
  84. + }
  85. +
  86. + if (clksel > 3)
  87. + return -EINVAL;
  88. +
  89. + ctrl = readl(pwm->mmio_base + MX1_PWMC);
  90. + writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
  91. +
  92. + writel(duty_cycles, pwm->mmio_base + MX1_PWMS);
  93. + writel(period_cycles, pwm->mmio_base + MX1_PWMP);
  94. +
  95. + ctrl &= ~(MX1_PWMC_PRESCALER_MASK | MX1_PWMC_CLKSEL_MASK);
  96. + ctrl |= MX1_PWMC_PRESCALER(prescale);
  97. + ctrl |= MX1_PWMC_CLKSEL(clksel);
  98. + writel(ctrl, pwm->mmio_base + MX1_PWMC);
  99. +
  100. } else {
  101. BUG();
  102. }
  103. @@ -116,6 +131,11 @@ EXPORT_SYMBOL(pwm_config);
  104. int pwm_enable(struct pwm_device *pwm)
  105. {
  106. int rc = 0;
  107. + if (cpu_is_mx1() || cpu_is_mx2()) {
  108. + u32 ctrl;
  109. + ctrl = readl(pwm->mmio_base + MX1_PWMC);
  110. + writel(ctrl | MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
  111. + }
  112. if (!pwm->clk_enabled) {
  113. rc = clk_enable(pwm->clk);
  114. @@ -128,7 +148,13 @@ EXPORT_SYMBOL(pwm_enable);
  115. void pwm_disable(struct pwm_device *pwm)
  116. {
  117. - writel(0, pwm->mmio_base + MX3_PWMCR);
  118. + if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
  119. + writel(0, pwm->mmio_base + MX3_PWMCR);
  120. + } else if (cpu_is_mx1() || cpu_is_mx2()) {
  121. + u32 ctrl;
  122. + ctrl = readl(pwm->mmio_base + MX1_PWMC);
  123. + writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
  124. + }
  125. if (pwm->clk_enabled) {
  126. clk_disable(pwm->clk);