Commit 19e73333 authored by Sascha Hauer's avatar Sascha Hauer Committed by Thierry Reding

pwm: i.MX: factor out SoC specific functions

To cleanup the code and to make it easier to support different
SoCs.
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: default avatarShawn Guo <shawn.guo@linaro.org>
Reviewed-by: default avatarBenoît Thébaudeau <benoit.thebaudeau@advansee.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@avionic-design.de>
parent daa5629b
...@@ -46,81 +46,96 @@ struct imx_chip { ...@@ -46,81 +46,96 @@ struct imx_chip {
void __iomem *mmio_base; void __iomem *mmio_base;
struct pwm_chip chip; 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) #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 pwm_device *pwm, int duty_ns, int period_ns)
{ {
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
if (!(cpu_is_mx1() || cpu_is_mx21())) { /*
unsigned long long c; * The PWM subsystem allows for exact frequencies. However,
unsigned long period_cycles, duty_cycles, prescale; * I cannot connect a scope on my device to the PWM line and
u32 cr; * thus cannot provide the program the PWM controller
* exactly. Instead, I'm relying on the fact that the
c = clk_get_rate(imx->clk); * Bootloader (u-boot or WinCE+haret) has programmed the PWM
c = c * period_ns; * function group already. So I'll just modify the PWM sample
do_div(c, 1000000000); * register to follow the ratio of duty_ns vs. period_ns
period_cycles = c; * accordingly.
*
prescale = period_cycles / 0x10000 + 1; * This is good enough for programming the brightness of
* the LCD backlight.
period_cycles /= prescale; *
c = (unsigned long long)period_cycles * duty_ns; * The real implementation would divide PERCLK[0] first by
do_div(c, period_ns); * both the prescaler (/1 .. /128) and then by CLKSEL
duty_cycles = c; * (/2 .. /16).
*/
/* u32 max = readl(imx->mmio_base + MX1_PWMP);
* according to imx pwm RM, the real period value should be u32 p = max * duty_ns / period_ns;
* PERIOD value in PWMPR plus 2. writel(max - p, imx->mmio_base + MX1_PWMS);
*/
if (period_cycles > 2) return 0;
period_cycles -= 2; }
else
period_cycles = 0; static int imx_pwm_config_v2(struct pwm_chip *chip,
struct pwm_device *pwm, int duty_ns, int period_ns)
writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); {
writel(period_cycles, imx->mmio_base + MX3_PWMPR); struct imx_chip *imx = to_imx_chip(chip);
unsigned long long c;
cr = MX3_PWMCR_PRESCALER(prescale) | unsigned long period_cycles, duty_cycles, prescale;
MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | u32 cr;
MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
c = clk_get_rate(imx->clk);
if (cpu_is_mx25()) c = c * period_ns;
cr |= MX3_PWMCR_CLKSRC_IPG; do_div(c, 1000000000);
else period_cycles = c;
cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
prescale = period_cycles / 0x10000 + 1;
writel(cr, imx->mmio_base + MX3_PWMCR);
} else if (cpu_is_mx1() || cpu_is_mx21()) { period_cycles /= prescale;
/* The PWM subsystem allows for exact frequencies. However, c = (unsigned long long)period_cycles * duty_ns;
* I cannot connect a scope on my device to the PWM line and do_div(c, period_ns);
* thus cannot provide the program the PWM controller duty_cycles = c;
* 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 * according to imx pwm RM, the real period value should be
* register to follow the ratio of duty_ns vs. period_ns * PERIOD value in PWMPR plus 2.
* accordingly. */
* if (period_cycles > 2)
* This is good enough for programming the brightness of period_cycles -= 2;
* the LCD backlight. else
* period_cycles = 0;
* The real implementation would divide PERCLK[0] first by
* both the prescaler (/1 .. /128) and then by CLKSEL writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
* (/2 .. /16). writel(period_cycles, imx->mmio_base + MX3_PWMPR);
*/
u32 max = readl(imx->mmio_base + MX1_PWMP); cr = MX3_PWMCR_PRESCALER(prescale) |
u32 p = max * duty_ns / period_ns; MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
writel(max - p, imx->mmio_base + MX1_PWMS); MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
} else {
BUG(); 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; 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) static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{ {
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
...@@ -187,6 +202,11 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) ...@@ -187,6 +202,11 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev)
if (imx->mmio_base == NULL) if (imx->mmio_base == NULL)
return -EADDRNOTAVAIL; 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); ret = pwmchip_add(&imx->chip);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment