pwm: i.MX: factor out SoC specific functions
authorSascha Hauer <s.hauer@pengutronix.de>
Tue, 3 Jul 2012 15:28:14 +0000 (17:28 +0200)
committerThierry Reding <thierry.reding@avionic-design.de>
Wed, 12 Sep 2012 12:25:04 +0000 (14:25 +0200)
To cleanup the code and to make it easier to support different
SoCs.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
drivers/pwm/pwm-imx.c

index 2a0b35333972836e0793fbe7a9f2e2c2de50e2af..8b7f01e0a100f5eef7a8e9aabaf924b29c19f57c 100644 (file)
@@ -46,81 +46,96 @@ struct imx_chip {
        void __iomem    *mmio_base;
 
        struct pwm_chip chip;
+
+       int (*config)(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns);
 };
 
 #define to_imx_chip(chip)      container_of(chip, struct imx_chip, chip)
 
-static int imx_pwm_config(struct pwm_chip *chip,
+static int imx_pwm_config_v1(struct pwm_chip *chip,
                struct pwm_device *pwm, int duty_ns, int period_ns)
 {
        struct imx_chip *imx = to_imx_chip(chip);
 
-       if (!(cpu_is_mx1() || cpu_is_mx21())) {
-               unsigned long long c;
-               unsigned long period_cycles, duty_cycles, prescale;
-               u32 cr;
-
-               c = clk_get_rate(imx->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;
-
-               /*
-                * according to imx pwm RM, the real period value should be
-                * PERIOD value in PWMPR plus 2.
-                */
-               if (period_cycles > 2)
-                       period_cycles -= 2;
-               else
-                       period_cycles = 0;
-
-               writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
-               writel(period_cycles, imx->mmio_base + MX3_PWMPR);
-
-               cr = MX3_PWMCR_PRESCALER(prescale) |
-                       MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
-                       MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
-
-               if (cpu_is_mx25())
-                       cr |= MX3_PWMCR_CLKSRC_IPG;
-               else
-                       cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
-
-               writel(cr, imx->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(imx->mmio_base + MX1_PWMP);
-               u32 p = max * duty_ns / period_ns;
-               writel(max - p, imx->mmio_base + MX1_PWMS);
-       } else {
-               BUG();
-       }
+       /*
+        * 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(imx->mmio_base + MX1_PWMP);
+       u32 p = max * duty_ns / period_ns;
+       writel(max - p, imx->mmio_base + MX1_PWMS);
+
+       return 0;
+}
+
+static int imx_pwm_config_v2(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, duty_cycles, prescale;
+       u32 cr;
+
+       c = clk_get_rate(imx->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;
+
+       /*
+        * according to imx pwm RM, the real period value should be
+        * PERIOD value in PWMPR plus 2.
+        */
+       if (period_cycles > 2)
+               period_cycles -= 2;
+       else
+               period_cycles = 0;
+
+       writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
+       writel(period_cycles, imx->mmio_base + MX3_PWMPR);
+
+       cr = MX3_PWMCR_PRESCALER(prescale) |
+               MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
+               MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
+
+       if (cpu_is_mx25())
+               cr |= MX3_PWMCR_CLKSRC_IPG;
+       else
+               cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
+
+       writel(cr, imx->mmio_base + MX3_PWMCR);
 
        return 0;
 }
 
+static int imx_pwm_config(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       struct imx_chip *imx = to_imx_chip(chip);
+
+       return imx->config(chip, pwm, duty_ns, period_ns);
+}
+
 static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct imx_chip *imx = to_imx_chip(chip);
@@ -187,6 +202,11 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev)
        if (imx->mmio_base == NULL)
                return -EADDRNOTAVAIL;
 
+       if (cpu_is_mx1() || cpu_is_mx21())
+               imx->config = imx_pwm_config_v1;
+       else
+               imx->config = imx_pwm_config_v2;
+
        ret = pwmchip_add(&imx->chip);
        if (ret < 0)
                return ret;