4be3c3e48c
SVN-Revision: 21082
137 lines
3.8 KiB
Diff
137 lines
3.8 KiB
Diff
--- a/arch/arm/plat-mxc/pwm.c
|
|
+++ b/arch/arm/plat-mxc/pwm.c
|
|
@@ -25,6 +25,11 @@
|
|
#define MX1_PWMS 0x04 /* PWM Sample Register */
|
|
#define MX1_PWMP 0x08 /* PWM Period Register */
|
|
|
|
+#define MX1_PWMC_EN (1 << 4)
|
|
+#define MX1_PWMC_PRESCALER_MASK (0x7f << 8)
|
|
+#define MX1_PWMC_PRESCALER(x) ((x & 0x7f) << 8)
|
|
+#define MX1_PWMC_CLKSEL_MASK 0x3
|
|
+#define MX1_PWMC_CLKSEL(x) ((x & 0x3))
|
|
|
|
/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
|
|
|
|
@@ -54,26 +59,33 @@ struct pwm_device {
|
|
|
|
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
|
|
{
|
|
+ unsigned long long c;
|
|
+ unsigned long period_cycles, duty_cycles, prescale;
|
|
+
|
|
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
|
|
return -EINVAL;
|
|
|
|
+ c = clk_get_rate(pwm->clk);
|
|
+
|
|
+ c = c * period_ns;
|
|
+
|
|
+ if (cpu_is_mx1() || cpu_is_mx2())
|
|
+ c >>= 1;
|
|
+
|
|
+ do_div(c, 1000000000);
|
|
+ period_cycles = c;
|
|
+
|
|
+ prescale = period_cycles / 0x10000 + 1;
|
|
+
|
|
+ period_cycles /= prescale;
|
|
+ c = (unsigned long long)period_cycles * duty_ns;
|
|
+ do_div(c, period_ns);
|
|
+ duty_cycles = c;
|
|
+
|
|
+
|
|
if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
|
|
- unsigned long long c;
|
|
- unsigned long period_cycles, duty_cycles, prescale;
|
|
u32 cr;
|
|
|
|
- c = clk_get_rate(pwm->clk);
|
|
- c = c * period_ns;
|
|
- do_div(c, 1000000000);
|
|
- period_cycles = c;
|
|
-
|
|
- prescale = period_cycles / 0x10000 + 1;
|
|
-
|
|
- period_cycles /= prescale;
|
|
- c = (unsigned long long)period_cycles * duty_ns;
|
|
- do_div(c, period_ns);
|
|
- duty_cycles = c;
|
|
-
|
|
writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
|
|
writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
|
|
|
|
@@ -86,25 +98,28 @@ int pwm_config(struct pwm_device *pwm, i
|
|
|
|
writel(cr, pwm->mmio_base + MX3_PWMCR);
|
|
} else if (cpu_is_mx1() || cpu_is_mx21()) {
|
|
- /* The PWM subsystem allows for exact frequencies. However,
|
|
- * I cannot connect a scope on my device to the PWM line and
|
|
- * thus cannot provide the program the PWM controller
|
|
- * exactly. Instead, I'm relying on the fact that the
|
|
- * Bootloader (u-boot or WinCE+haret) has programmed the PWM
|
|
- * function group already. So I'll just modify the PWM sample
|
|
- * register to follow the ratio of duty_ns vs. period_ns
|
|
- * accordingly.
|
|
- *
|
|
- * This is good enough for programming the brightness of
|
|
- * the LCD backlight.
|
|
- *
|
|
- * The real implementation would divide PERCLK[0] first by
|
|
- * both the prescaler (/1 .. /128) and then by CLKSEL
|
|
- * (/2 .. /16).
|
|
- */
|
|
- u32 max = readl(pwm->mmio_base + MX1_PWMP);
|
|
- u32 p = max * duty_ns / period_ns;
|
|
- writel(max - p, pwm->mmio_base + MX1_PWMS);
|
|
+ unsigned long clksel = 0;
|
|
+ u32 ctrl;
|
|
+
|
|
+ while (prescale >= 0x80 && clksel < 4) {
|
|
+ prescale >>= 1;
|
|
+ ++clksel;
|
|
+ }
|
|
+
|
|
+ if (clksel > 3)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ctrl = readl(pwm->mmio_base + MX1_PWMC);
|
|
+ writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
|
|
+
|
|
+ writel(duty_cycles, pwm->mmio_base + MX1_PWMS);
|
|
+ writel(period_cycles, pwm->mmio_base + MX1_PWMP);
|
|
+
|
|
+ ctrl &= ~(MX1_PWMC_PRESCALER_MASK | MX1_PWMC_CLKSEL_MASK);
|
|
+ ctrl |= MX1_PWMC_PRESCALER(prescale);
|
|
+ ctrl |= MX1_PWMC_CLKSEL(clksel);
|
|
+ writel(ctrl, pwm->mmio_base + MX1_PWMC);
|
|
+
|
|
} else {
|
|
BUG();
|
|
}
|
|
@@ -116,6 +131,11 @@ EXPORT_SYMBOL(pwm_config);
|
|
int pwm_enable(struct pwm_device *pwm)
|
|
{
|
|
int rc = 0;
|
|
+ if (cpu_is_mx1() || cpu_is_mx2()) {
|
|
+ u32 ctrl;
|
|
+ ctrl = readl(pwm->mmio_base + MX1_PWMC);
|
|
+ writel(ctrl | MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
|
|
+ }
|
|
|
|
if (!pwm->clk_enabled) {
|
|
rc = clk_enable(pwm->clk);
|
|
@@ -128,7 +148,13 @@ EXPORT_SYMBOL(pwm_enable);
|
|
|
|
void pwm_disable(struct pwm_device *pwm)
|
|
{
|
|
- writel(0, pwm->mmio_base + MX3_PWMCR);
|
|
+ if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
|
|
+ writel(0, pwm->mmio_base + MX3_PWMCR);
|
|
+ } else if (cpu_is_mx1() || cpu_is_mx2()) {
|
|
+ u32 ctrl;
|
|
+ ctrl = readl(pwm->mmio_base + MX1_PWMC);
|
|
+ writel(ctrl & ~MX1_PWMC_EN, pwm->mmio_base + MX1_PWMC);
|
|
+ }
|
|
|
|
if (pwm->clk_enabled) {
|
|
clk_disable(pwm->clk);
|