1 diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
2 index c36f263..acc5dc1 100644
3 --- a/arch/arm/plat-mxc/pwm.c
4 +++ b/arch/arm/plat-mxc/pwm.c
6 #define MX1_PWMS 0x04 /* PWM Sample Register */
7 #define MX1_PWMP 0x08 /* PWM Period Register */
9 +#define MX1_PWMC_EN (1 << 4)
10 +#define MX1_PWMC_PRESCALER_MASK (0x7f << 8)
11 +#define MX1_PWMC_PRESCALER(x) ((x & 0x7f) << 8)
12 +#define MX1_PWMC_CLKSEL_MASK 0x3
13 +#define MX1_PWMC_CLKSEL(x) ((x & 0x3))
15 /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
17 @@ -54,25 +59,32 @@ struct pwm_device {
19 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
21 + unsigned long long c;
22 + unsigned long period_cycles, duty_cycles, prescale;
24 if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
27 - if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
28 - unsigned long long c;
29 - unsigned long period_cycles, duty_cycles, prescale;
31 + c = clk_get_rate(pwm->clk);
35 + if (cpu_is_mx1() || cpu_is_mx2())
38 - c = clk_get_rate(pwm->clk);
40 - do_div(c, 1000000000);
42 + do_div(c, 1000000000);
45 - prescale = period_cycles / 0x10000 + 1;
46 + prescale = period_cycles / 0x10000 + 1;
48 - period_cycles /= prescale;
49 - c = (unsigned long long)period_cycles * duty_ns;
50 - do_div(c, period_ns);
52 + period_cycles /= prescale;
53 + c = (unsigned long long)period_cycles * duty_ns;
54 + do_div(c, period_ns);
58 + if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
61 writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
62 writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
63 @@ -86,25 +98,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
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
76 - * This is good enough for programming the brightness of
77 - * the LCD backlight.
79 - * The real implementation would divide PERCLK[0] first by
80 - * both the prescaler (/1 .. /128) and then by CLKSEL
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;
89 + while (prescale >= 0x80 && clksel < 4) {
97 + ctrl = readl(pwm->mmio_base + MX1_PWMC);
98 + writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
100 + writel(duty_cycles, pwm->mmio_base + MX1_PWMS);
101 + writel(period_cycles, pwm->mmio_base + MX1_PWMP);
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);
111 @@ -116,6 +130,11 @@ EXPORT_SYMBOL(pwm_config);
112 int pwm_enable(struct pwm_device *pwm)
115 + if (cpu_is_mx1() || cpu_is_mx2()) {
117 + ctrl = readl(pwm->mmio_base + MX1_PWMC);
118 + writel(ctrl | MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
121 if (!pwm->clk_enabled) {
122 rc = clk_enable(pwm->clk);
123 @@ -128,7 +147,13 @@ EXPORT_SYMBOL(pwm_enable);
125 void pwm_disable(struct pwm_device *pwm)
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()) {
132 + ctrl = readl(pwm->mmio_base + MX1_PWMC);
133 + writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
136 if (pwm->clk_enabled) {
137 clk_disable(pwm->clk);