Root/target/linux/imx21/patches/040-pwm.patch

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

Archive Download this file



interactive