From 19e73333236a6115617f8ffb4cc290bdb6f2865a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 3 Jul 2012 17:28:14 +0200 Subject: pwm: i.MX: factor out SoC specific functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To cleanup the code and to make it easier to support different SoCs. Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 146 ++++++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 63 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 2a0b3533397..8b7f01e0a10 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -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; -- cgit v1.2.3-70-g09d2 From 140827c148f2f3a95fdcec5310f6cd980139b383 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Aug 2012 09:12:01 +0200 Subject: pwm: i.MX: remove unnecessary if in pwm_[en|dis]able MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PWM core makes sure that pwm_enable/disable are called only once. Still keep the enabled state since we will need it in pwm_config. Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 8b7f01e0a10..5d426ffe6a3 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -42,7 +42,7 @@ struct imx_chip { struct clk *clk; - int clk_enabled; + int enabled; void __iomem *mmio_base; struct pwm_chip chip; @@ -139,14 +139,15 @@ static int imx_pwm_config(struct pwm_chip *chip, static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct imx_chip *imx = to_imx_chip(chip); - int rc = 0; + int ret; - if (!imx->clk_enabled) { - rc = clk_prepare_enable(imx->clk); - if (!rc) - imx->clk_enabled = 1; - } - return rc; + ret = clk_prepare_enable(imx->clk); + if (ret) + return ret; + + imx->enabled = 1; + + return 0; } static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) @@ -155,10 +156,8 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) writel(0, imx->mmio_base + MX3_PWMCR); - if (imx->clk_enabled) { - clk_disable_unprepare(imx->clk); - imx->clk_enabled = 0; - } + clk_disable_unprepare(imx->clk); + imx->enabled = 0; } static struct pwm_ops imx_pwm_ops = { @@ -190,8 +189,6 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) imx->chip.base = -1; imx->chip.npwm = 1; - imx->clk_enabled = 0; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "no memory resource defined\n"); -- cgit v1.2.3-70-g09d2 From 66ad6a613abeeeabc5217a0498fae63205e8ddb8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Aug 2012 11:39:25 +0200 Subject: pwm: i.MX: add functions to enable/disable pwm. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to enable/disable the PWM only by switching the clock on or off. Instead, use the dedicated register bits. These differ on different SoCs, so introduce a SoC specific function for this. Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 5d426ffe6a3..13d4d22f12c 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -25,6 +25,7 @@ #define MX1_PWMS 0x04 /* PWM Sample Register */ #define MX1_PWMP 0x08 /* PWM Period Register */ +#define MX1_PWMC_EN (1 << 4) /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ @@ -49,6 +50,7 @@ struct imx_chip { int (*config)(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns); + void (*set_enable)(struct pwm_chip *chip, bool enable); }; #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) @@ -82,6 +84,21 @@ static int imx_pwm_config_v1(struct pwm_chip *chip, return 0; } +static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) +{ + struct imx_chip *imx = to_imx_chip(chip); + u32 val; + + val = readl(imx->mmio_base + MX1_PWMC); + + if (enable) + val |= MX1_PWMC_EN; + else + val &= ~MX1_PWMC_EN; + + writel(val, imx->mmio_base + MX1_PWMC); +} + static int imx_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -116,7 +133,10 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | - MX3_PWMCR_DBGEN | MX3_PWMCR_EN; + MX3_PWMCR_DBGEN; + + if (imx->enabled) + cr |= MX3_PWMCR_EN; if (cpu_is_mx25()) cr |= MX3_PWMCR_CLKSRC_IPG; @@ -128,6 +148,21 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, return 0; } +static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) +{ + struct imx_chip *imx = to_imx_chip(chip); + u32 val; + + val = readl(imx->mmio_base + MX3_PWMCR); + + if (enable) + val |= MX3_PWMCR_EN; + else + val &= ~MX3_PWMCR_EN; + + writel(val, imx->mmio_base + MX3_PWMCR); +} + static int imx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -145,6 +180,8 @@ static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) if (ret) return ret; + imx->set_enable(chip, true); + imx->enabled = 1; return 0; @@ -154,7 +191,7 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct imx_chip *imx = to_imx_chip(chip); - writel(0, imx->mmio_base + MX3_PWMCR); + imx->set_enable(chip, false); clk_disable_unprepare(imx->clk); imx->enabled = 0; @@ -199,10 +236,13 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) if (imx->mmio_base == NULL) return -EADDRNOTAVAIL; - if (cpu_is_mx1() || cpu_is_mx21()) + if (cpu_is_mx1() || cpu_is_mx21()) { imx->config = imx_pwm_config_v1; - else + imx->set_enable = imx_pwm_set_enable_v1; + } else { imx->config = imx_pwm_config_v2; + imx->set_enable = imx_pwm_set_enable_v2; + } ret = pwmchip_add(&imx->chip); if (ret < 0) -- cgit v1.2.3-70-g09d2 From 208d038f4792b5ca0dc76deebbc0ae13b4f1a744 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Aug 2012 08:27:40 +0200 Subject: pwm: i.MX: Use module_platform_driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 13d4d22f12c..a1e799ee07d 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -271,17 +271,7 @@ static struct platform_driver imx_pwm_driver = { .remove = __devexit_p(imx_pwm_remove), }; -static int __init imx_pwm_init(void) -{ - return platform_driver_register(&imx_pwm_driver); -} -arch_initcall(imx_pwm_init); - -static void __exit imx_pwm_exit(void) -{ - platform_driver_unregister(&imx_pwm_driver); -} -module_exit(imx_pwm_exit); +module_platform_driver(imx_pwm_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sascha Hauer "); -- cgit v1.2.3-70-g09d2 From 479e2e301c626cc64fb27b6b1938655eaba8b036 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 25 Jun 2012 16:16:25 +0200 Subject: pwm: i.MX: add devicetree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time remove platform based support. No user for this driver has made it into mainline so far, so all we break is out of tree stuff. Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/imx-pwm.txt | 17 +++++++++ drivers/pwm/pwm-imx.c | 44 ++++++++++++++++++----- 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/imx-pwm.txt (limited to 'drivers/pwm/pwm-imx.c') diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt new file mode 100644 index 00000000000..9b9b18514b6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt @@ -0,0 +1,17 @@ +Freescale i.MX PWM controller + +Required properties: +- compatible: should be "fsl,-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the duty cycle in nanoseconds. +- interrupts: The interrupt for the pwm controller + +Example: + +pwm1: pwm@53fb4000 { + #pwm-cells = <2>; + compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; + reg = <0x53fb4000 0x4000>; + interrupts = <61>; +}; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index a1e799ee07d..0f6c436c063 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -16,9 +16,9 @@ #include #include #include +#include #include - /* i.MX1 and i.MX21 share the same PWM function block: */ #define MX1_PWMC 0x00 /* PWM Control Register */ @@ -204,12 +204,41 @@ static struct pwm_ops imx_pwm_ops = { .owner = THIS_MODULE, }; +struct imx_pwm_data { + int (*config)(struct pwm_chip *chip, + struct pwm_device *pwm, int duty_ns, int period_ns); + void (*set_enable)(struct pwm_chip *chip, bool enable); +}; + +static struct imx_pwm_data imx_pwm_data_v1 = { + .config = imx_pwm_config_v1, + .set_enable = imx_pwm_set_enable_v1, +}; + +static struct imx_pwm_data imx_pwm_data_v2 = { + .config = imx_pwm_config_v2, + .set_enable = imx_pwm_set_enable_v2, +}; + +static const struct of_device_id imx_pwm_dt_ids[] = { + { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, }, + { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); + static int __devinit imx_pwm_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(imx_pwm_dt_ids, &pdev->dev); + struct imx_pwm_data *data; struct imx_chip *imx; struct resource *r; int ret = 0; + if (!of_id) + return -ENODEV; + imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); if (imx == NULL) { dev_err(&pdev->dev, "failed to allocate memory\n"); @@ -236,13 +265,9 @@ 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; - imx->set_enable = imx_pwm_set_enable_v1; - } else { - imx->config = imx_pwm_config_v2; - imx->set_enable = imx_pwm_set_enable_v2; - } + data = of_id->data; + imx->config = data->config; + imx->set_enable = data->set_enable; ret = pwmchip_add(&imx->chip); if (ret < 0) @@ -265,7 +290,8 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev) static struct platform_driver imx_pwm_driver = { .driver = { - .name = "mxc_pwm", + .name = "imx-pwm", + .of_match_table = of_match_ptr(imx_pwm_dt_ids), }, .probe = imx_pwm_probe, .remove = __devexit_p(imx_pwm_remove), -- cgit v1.2.3-70-g09d2 From 8d1c24bfd20829f5943c76b85c4973db264dd666 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Aug 2012 12:03:29 +0200 Subject: pwm: i.MX: use per clock unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i.MX PWM module has two clocks: The ipg clock and the ipg highfreq (peripheral) clock. The ipg clock has to be enabled for this hardware to work. The actual PWM output can either be driven by the ipg clock or the ipg highfreq. The ipg highfreq has the advantage that it runs even when the SoC is in low power modes. Use the always running clock also on i.MX25. Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 0f6c436c063..852de6ce6e1 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -17,7 +17,6 @@ #include #include #include -#include /* i.MX1 and i.MX21 share the same PWM function block: */ @@ -133,16 +132,11 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | - MX3_PWMCR_DBGEN; + MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; if (imx->enabled) cr |= 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; -- cgit v1.2.3-70-g09d2 From 7b27c160c68152581c702b9f1fe362338d2a0cad Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 25 Jun 2012 16:15:20 +0200 Subject: pwm: i.MX: fix clock lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i.MX PWM core has two clocks: The ipg clock and the ipg highfreq (peripheral) clock. The ipg clock has to be enabled for this hardware to work. The actual PWM output can either be driven by the ipg clock or the ipg highfreq. The ipg highfreq has the advantage that it runs even when the SoC is in low power modes. This patch requests both clocks and enables the ipg clock for accessing registers and the peripheral clock to actually turn on the PWM. Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer Reviewed-by: Shawn Guo Reviewed-by: Benoît Thébaudeau Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 852de6ce6e1..8a5d3ae2946 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -40,7 +40,8 @@ #define MX3_PWMCR_EN (1 << 0) struct imx_chip { - struct clk *clk; + struct clk *clk_per; + struct clk *clk_ipg; int enabled; void __iomem *mmio_base; @@ -106,7 +107,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, unsigned long period_cycles, duty_cycles, prescale; u32 cr; - c = clk_get_rate(imx->clk); + c = clk_get_rate(imx->clk_per); c = c * period_ns; do_div(c, 1000000000); period_cycles = c; @@ -161,8 +162,17 @@ 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); + int ret; + + ret = clk_prepare_enable(imx->clk_ipg); + if (ret) + return ret; - return imx->config(chip, pwm, duty_ns, period_ns); + ret = imx->config(chip, pwm, duty_ns, period_ns); + + clk_disable_unprepare(imx->clk_ipg); + + return ret; } static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) @@ -170,7 +180,7 @@ static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct imx_chip *imx = to_imx_chip(chip); int ret; - ret = clk_prepare_enable(imx->clk); + ret = clk_prepare_enable(imx->clk_per); if (ret) return ret; @@ -187,7 +197,7 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) imx->set_enable(chip, false); - clk_disable_unprepare(imx->clk); + clk_disable_unprepare(imx->clk_per); imx->enabled = 0; } @@ -239,10 +249,19 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) return -ENOMEM; } - imx->clk = devm_clk_get(&pdev->dev, "pwm"); + imx->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(imx->clk_per)) { + dev_err(&pdev->dev, "getting per clock failed with %ld\n", + PTR_ERR(imx->clk_per)); + return PTR_ERR(imx->clk_per); + } - if (IS_ERR(imx->clk)) - return PTR_ERR(imx->clk); + imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imx->clk_ipg)) { + dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", + PTR_ERR(imx->clk_ipg)); + return PTR_ERR(imx->clk_ipg); + } imx->chip.ops = &imx_pwm_ops; imx->chip.dev = &pdev->dev; -- cgit v1.2.3-70-g09d2