From 8c0216f377406c7613b67bd18755889026284192 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 4 Jan 2017 09:40:54 +0100 Subject: pwm: Remove .can_sleep from struct pwm_chip All PWM devices have been marked as "might sleep" since v4.5, there is no longer a need to differentiate on a per-chip basis. Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index d600fd5cd4ba..1223187ad354 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -304,7 +304,6 @@ static int imx_pwm_probe(struct platform_device *pdev) imx->chip.dev = &pdev->dev; imx->chip.base = -1; imx->chip.npwm = 1; - imx->chip.can_sleep = true; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); -- cgit From b2ec9efc1f4fb1dc13a599db88019d5472deef9b Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 10 Jan 2017 23:42:06 +0530 Subject: pwm: constify pwm_ops structures Declare pwm_ops structures as const as they are only stored in the ops field of a pwm_chip structure. This field is of type const struct pwm_ops *, so pwm_ops structures having this property can be declared as const. Done using Coccinelle: @r1 disable optional_qualifier@ identifier i; position p; @@ static struct pwm_ops i@p={...}; @ok1@ identifier r1.i; position p; struct pxa_pwm_chip pwm; struct bfin_pwm_chip bwm; struct vt8500_chip vp; struct imx_chip icp; @@ ( pwm.chip.ops=&i@p | bwm.chip.ops=&i@p | vp.chip.ops=&i@p | icp.chip.ops=&i@p ) @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct pwm_ops i; File size details: text data bss dec hex filename 1646 328 0 1974 7b6 drivers/pwm/pwm-imx.o 1742 224 0 1966 7ae drivers/pwm/pwm-imx.o 1941 296 0 2237 8bd drivers/pwm/pwm-pxa.o 2037 192 0 2229 8b5 drivers/pwm/pwm-pxa.o 1946 296 0 2242 8c2 drivers/pwm/pwm-vt8500.o 2050 192 0 2242 8c2 drivers/pwm/pwm-vt8500.o The drivers/pwm/pwm-bfin.o file did not compile. Signed-off-by: Bhumika Goyal Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bfin.c | 2 +- drivers/pwm/pwm-imx.c | 2 +- drivers/pwm/pwm-pxa.c | 2 +- drivers/pwm/pwm-vt8500.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c index 7631ef194de7..d2ed0a2a18e8 100644 --- a/drivers/pwm/pwm-bfin.c +++ b/drivers/pwm/pwm-bfin.c @@ -103,7 +103,7 @@ static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) disable_gptimer(priv->pin); } -static struct pwm_ops bfin_pwm_ops = { +static const struct pwm_ops bfin_pwm_ops = { .request = bfin_pwm_request, .free = bfin_pwm_free, .config = bfin_pwm_config, diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index d600fd5cd4ba..177fb81c916d 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -240,7 +240,7 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(imx->clk_per); } -static struct pwm_ops imx_pwm_ops = { +static const struct pwm_ops imx_pwm_ops = { .enable = imx_pwm_enable, .disable = imx_pwm_disable, .config = imx_pwm_config, diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 58b709f29130..4143a46684d2 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -118,7 +118,7 @@ static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(pc->clk); } -static struct pwm_ops pxa_pwm_ops = { +static const struct pwm_ops pxa_pwm_ops = { .config = pxa_pwm_config, .enable = pxa_pwm_enable, .disable = pxa_pwm_disable, diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index cdb58fd4619d..8141a4984126 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -184,7 +184,7 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip, return 0; } -static struct pwm_ops vt8500_pwm_ops = { +static const struct pwm_ops vt8500_pwm_ops = { .enable = vt8500_pwm_enable, .disable = vt8500_pwm_disable, .config = vt8500_pwm_config, -- cgit From 9fb27fac39f47632aa32ffd787b4de1dbd0b8655 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 29 Jan 2017 22:54:06 +0100 Subject: pwm: imx: Remove ipg clock and enable per clock when required The use of the ipg clock was introduced with commit 7b27c160c681 ("pwm: i.MX: fix clock lookup"). In the commit message it was claimed that the ipg clock is enabled for register accesses. This is true for the ->config() callback, but not for the ->set_enable() callback. Given that the ipg clock is not consistently enabled for all register accesses we can assume that either it is not required at all or that the current code does not work. Remove the ipg clock code for now so that it's no longer in the way of refactoring the driver. On the other hand, the i.MX 7 IP requires the peripheral clock to be enabled before accessing its registers. Since ->config() can be called when the PWM is disabled (in which case, the peripheral clock is also disabled), we need to surround the imx->config() with clk_prepare_enable(per_clk)/clk_disable_unprepare(per_clk) calls. Note that the driver was working fine for the i.MX 7 IP so far because the ipg and peripheral clock use the same hardware clock gate, which guaranteed peripheral clock activation even when ->config() was called when the PWM was disabled. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon Cc: Philipp Zabel Reviewed-by: Stefan Agner Tested-by: Stefan Agner Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 177fb81c916d..bb64122a74be 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -49,7 +49,6 @@ struct imx_chip { struct clk *clk_per; - struct clk *clk_ipg; void __iomem *mmio_base; @@ -206,13 +205,13 @@ static int imx_pwm_config(struct pwm_chip *chip, struct imx_chip *imx = to_imx_chip(chip); int ret; - ret = clk_prepare_enable(imx->clk_ipg); + ret = clk_prepare_enable(imx->clk_per); if (ret) return ret; ret = imx->config(chip, pwm, duty_ns, period_ns); - clk_disable_unprepare(imx->clk_ipg); + clk_disable_unprepare(imx->clk_per); return ret; } @@ -293,13 +292,6 @@ static int imx_pwm_probe(struct platform_device *pdev) return PTR_ERR(imx->clk_per); } - 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; imx->chip.base = -1; -- cgit From 0038922954236a6af424e2604ece88404dfbc41c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:07 +0100 Subject: pwm: imx: Add separate set of PWM ops for v1 and v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch provides separate set of PWM operations utilized by i.MX's v1 and v2 of the PWM hardware. Signed-off-by: Lothar Waßmann Signed-off-by: Bhuvanchandra DV Signed-off-by: Lukasz Majewski Acked-by: Shawn Guo Reviewed-by: Sascha Hauer Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index bb64122a74be..c405cb777808 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -239,7 +239,14 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(imx->clk_per); } -static const struct pwm_ops imx_pwm_ops = { +static const struct pwm_ops imx_pwm_ops_v1 = { + .enable = imx_pwm_enable, + .disable = imx_pwm_disable, + .config = imx_pwm_config, + .owner = THIS_MODULE, +}; + +static const struct pwm_ops imx_pwm_ops_v2 = { .enable = imx_pwm_enable, .disable = imx_pwm_disable, .config = imx_pwm_config, @@ -250,16 +257,19 @@ 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); + const struct pwm_ops *ops; }; static struct imx_pwm_data imx_pwm_data_v1 = { .config = imx_pwm_config_v1, .set_enable = imx_pwm_set_enable_v1, + .ops = &imx_pwm_ops_v1, }; static struct imx_pwm_data imx_pwm_data_v2 = { .config = imx_pwm_config_v2, .set_enable = imx_pwm_set_enable_v2, + .ops = &imx_pwm_ops_v2, }; static const struct of_device_id imx_pwm_dt_ids[] = { @@ -281,6 +291,8 @@ static int imx_pwm_probe(struct platform_device *pdev) if (!of_id) return -ENODEV; + data = of_id->data; + imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); if (imx == NULL) return -ENOMEM; @@ -292,7 +304,7 @@ static int imx_pwm_probe(struct platform_device *pdev) return PTR_ERR(imx->clk_per); } - imx->chip.ops = &imx_pwm_ops; + imx->chip.ops = data->ops; imx->chip.dev = &pdev->dev; imx->chip.base = -1; imx->chip.npwm = 1; @@ -303,7 +315,6 @@ static int imx_pwm_probe(struct platform_device *pdev) if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); - data = of_id->data; imx->config = data->config; imx->set_enable = data->set_enable; -- cgit From b3c088fe0297d7580bef5d5830fa5fc69ae8443c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:08 +0100 Subject: pwm: imx: Rewrite v1 code to facilitate switch to atomic PWM The code has been rewritten to remove "generic" calls to imx_pwm_{enable|disable|config}. Such approach would facilitate switch to atomic PWM (a.k.a ->apply()) implementation. Suggested-by: Stefan Agner Suggested-by: Boris Brezillon Reviewed-by: Stefan Agner Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index c405cb777808..5c712104066a 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -90,19 +90,33 @@ 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) +static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm) { struct imx_chip *imx = to_imx_chip(chip); u32 val; + int ret; + + ret = clk_prepare_enable(imx->clk_per); + if (ret < 0) + return ret; val = readl(imx->mmio_base + MX1_PWMC); + val |= MX1_PWMC_EN; + writel(val, imx->mmio_base + MX1_PWMC); - if (enable) - val |= MX1_PWMC_EN; - else - val &= ~MX1_PWMC_EN; + return 0; +} + +static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct imx_chip *imx = to_imx_chip(chip); + u32 val; + val = readl(imx->mmio_base + MX1_PWMC); + val &= ~MX1_PWMC_EN; writel(val, imx->mmio_base + MX1_PWMC); + + clk_disable_unprepare(imx->clk_per); } static int imx_pwm_config_v2(struct pwm_chip *chip, @@ -240,9 +254,9 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) } static const struct pwm_ops imx_pwm_ops_v1 = { - .enable = imx_pwm_enable, - .disable = imx_pwm_disable, - .config = imx_pwm_config, + .enable = imx_pwm_enable_v1, + .disable = imx_pwm_disable_v1, + .config = imx_pwm_config_v1, .owner = THIS_MODULE, }; @@ -261,8 +275,6 @@ struct imx_pwm_data { }; static struct imx_pwm_data imx_pwm_data_v1 = { - .config = imx_pwm_config_v1, - .set_enable = imx_pwm_set_enable_v1, .ops = &imx_pwm_ops_v1, }; -- cgit From 970247a486751c79903c7d853198d0106805c641 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:09 +0100 Subject: pwm: imx: Move PWMv2 software reset code to a separate function The software reset code has been extracted from imx_pwm_config_v2 function and moved to new one - imx_pwm_sw_reset(). This change reduces the overall size of imx_pwm_config_v2() and prepares it for atomic PWM operation. Suggested-by: Stefan Agner Suggested-by: Boris Brezillon Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 5c712104066a..c944f15f574c 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -119,6 +119,25 @@ static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(imx->clk_per); } +static void imx_pwm_sw_reset(struct pwm_chip *chip) +{ + struct imx_chip *imx = to_imx_chip(chip); + struct device *dev = chip->dev; + int wait_count = 0; + u32 cr; + + writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); + do { + usleep_range(200, 1000); + cr = readl(imx->mmio_base + MX3_PWMCR); + } while ((cr & MX3_PWMCR_SWR) && + (wait_count++ < MX3_PWM_SWR_LOOP)); + + if (cr & MX3_PWMCR_SWR) + dev_warn(dev, "software reset timeout\n"); +} + + static int imx_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -128,7 +147,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, unsigned long period_cycles, duty_cycles, prescale; unsigned int period_ms; bool enable = pwm_is_enabled(pwm); - int wait_count = 0, fifoav; + int fifoav; u32 cr, sr; /* @@ -151,15 +170,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, dev_warn(dev, "there is no free FIFO slot\n"); } } else { - writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); - do { - usleep_range(200, 1000); - cr = readl(imx->mmio_base + MX3_PWMCR); - } while ((cr & MX3_PWMCR_SWR) && - (wait_count++ < MX3_PWM_SWR_LOOP)); - - if (cr & MX3_PWMCR_SWR) - dev_warn(dev, "software reset timeout\n"); + imx_pwm_sw_reset(chip); } c = clk_get_rate(imx->clk_per); -- cgit From 73b1ff1f3e5ccc22b31fa44c98460ef05393181c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:10 +0100 Subject: pwm: imx: Move PWMv2 wait for fifo slot code to a separate function The code, which waits for fifo slot, has been extracted from imx_pwm_config_v2 function and moved to new one - imx_pwm_wait_fifo_slot(). This change reduces the overall size of imx_pwm_config_v2() and prepares it for atomic PWM operation. Suggested-by: Stefan Agner Suggested-by: Boris Brezillon Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index c944f15f574c..d557279446ed 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -137,18 +137,36 @@ static void imx_pwm_sw_reset(struct pwm_chip *chip) dev_warn(dev, "software reset timeout\n"); } +static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip, + struct pwm_device *pwm) +{ + struct imx_chip *imx = to_imx_chip(chip); + struct device *dev = chip->dev; + unsigned int period_ms; + int fifoav; + u32 sr; + + sr = readl(imx->mmio_base + MX3_PWMSR); + fifoav = sr & MX3_PWMSR_FIFOAV_MASK; + if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { + period_ms = DIV_ROUND_UP(pwm_get_period(pwm), + NSEC_PER_MSEC); + msleep(period_ms); + + sr = readl(imx->mmio_base + MX3_PWMSR); + if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) + dev_warn(dev, "there is no free FIFO slot\n"); + } +} 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); - struct device *dev = chip->dev; unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; - unsigned int period_ms; bool enable = pwm_is_enabled(pwm); - int fifoav; - u32 cr, sr; + u32 cr; /* * i.MX PWMv2 has a 4-word sample FIFO. @@ -157,21 +175,10 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, * wait for a full PWM cycle to get a relinquished FIFO slot * when the controller is enabled and the FIFO is fully loaded. */ - if (enable) { - sr = readl(imx->mmio_base + MX3_PWMSR); - fifoav = sr & MX3_PWMSR_FIFOAV_MASK; - if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { - period_ms = DIV_ROUND_UP(pwm_get_period(pwm), - NSEC_PER_MSEC); - msleep(period_ms); - - sr = readl(imx->mmio_base + MX3_PWMSR); - if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) - dev_warn(dev, "there is no free FIFO slot\n"); - } - } else { + if (enable) + imx_pwm_wait_fifo_slot(chip, pwm); + else imx_pwm_sw_reset(chip); - } c = clk_get_rate(imx->clk_per); c = c * period_ns; -- cgit From 0ca1a11a1d816c8fb0bb29b985666cef912958c1 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:11 +0100 Subject: pwm: imx: Provide atomic PWM support for i.MX PWMv2 This commit provides apply() callback implementation for i.MX's PWMv2. Suggested-by: Stefan Agner Suggested-by: Boris Brezillon Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index d557279446ed..34f3031d5c40 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -248,6 +248,72 @@ static int imx_pwm_config(struct pwm_chip *chip, return ret; } +static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + unsigned long period_cycles, duty_cycles, prescale; + struct imx_chip *imx = to_imx_chip(chip); + struct pwm_state cstate; + unsigned long long c; + int ret; + + pwm_get_state(pwm, &cstate); + + if (state->enabled) { + c = clk_get_rate(imx->clk_per); + c *= state->period; + + do_div(c, 1000000000); + period_cycles = c; + + prescale = period_cycles / 0x10000 + 1; + + period_cycles /= prescale; + c = (unsigned long long)period_cycles * state->duty_cycle; + do_div(c, state->period); + 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; + + /* + * Wait for a free FIFO slot if the PWM is already enabled, and + * flush the FIFO if the PWM was disabled and is about to be + * enabled. + */ + if (cstate.enabled) { + imx_pwm_wait_fifo_slot(chip, pwm); + } else { + ret = clk_prepare_enable(imx->clk_per); + if (ret) + return ret; + + imx_pwm_sw_reset(chip); + } + + writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); + writel(period_cycles, imx->mmio_base + MX3_PWMPR); + + writel(MX3_PWMCR_PRESCALER(prescale) | + MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | + MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | + MX3_PWMCR_EN, + imx->mmio_base + MX3_PWMCR); + } else if (cstate.enabled) { + writel(0, imx->mmio_base + MX3_PWMCR); + + clk_disable_unprepare(imx->clk_per); + } + + return 0; +} + static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct imx_chip *imx = to_imx_chip(chip); @@ -279,6 +345,7 @@ static const struct pwm_ops imx_pwm_ops_v1 = { }; static const struct pwm_ops imx_pwm_ops_v2 = { + .apply = imx_pwm_apply_v2, .enable = imx_pwm_enable, .disable = imx_pwm_disable, .config = imx_pwm_config, -- cgit From 871985b154ada5a0edaf1aa22d6a1de115b0213d Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:12 +0100 Subject: pwm: imx: Remove redundant i.MX PWMv2 code The code providing functionality surpassed by the atomic PWM is not needed anymore and hence can be removed. Suggested-by: Stefan Agner Suggested-by: Boris Brezillon Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 127 -------------------------------------------------- 1 file changed, 127 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 34f3031d5c40..0a81c028cb11 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -53,10 +53,6 @@ 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); - void (*set_enable)(struct pwm_chip *chip, bool enable); }; #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) @@ -159,95 +155,6 @@ static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip, } } -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; - bool enable = pwm_is_enabled(pwm); - u32 cr; - - /* - * i.MX PWMv2 has a 4-word sample FIFO. - * In order to avoid FIFO overflow issue, we do software reset - * to clear all sample FIFO if the controller is disabled or - * wait for a full PWM cycle to get a relinquished FIFO slot - * when the controller is enabled and the FIFO is fully loaded. - */ - if (enable) - imx_pwm_wait_fifo_slot(chip, pwm); - else - imx_pwm_sw_reset(chip); - - c = clk_get_rate(imx->clk_per); - 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_CLKSRC_IPG_HIGH; - - if (enable) - cr |= MX3_PWMCR_EN; - - writel(cr, imx->mmio_base + MX3_PWMCR); - - 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) -{ - struct imx_chip *imx = to_imx_chip(chip); - int ret; - - ret = clk_prepare_enable(imx->clk_per); - if (ret) - return ret; - - ret = imx->config(chip, pwm, duty_ns, period_ns); - - clk_disable_unprepare(imx->clk_per); - - return ret; -} - static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { @@ -314,29 +221,6 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } -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_per); - if (ret) - return ret; - - imx->set_enable(chip, true); - - return 0; -} - -static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct imx_chip *imx = to_imx_chip(chip); - - imx->set_enable(chip, false); - - clk_disable_unprepare(imx->clk_per); -} - static const struct pwm_ops imx_pwm_ops_v1 = { .enable = imx_pwm_enable_v1, .disable = imx_pwm_disable_v1, @@ -346,16 +230,10 @@ static const struct pwm_ops imx_pwm_ops_v1 = { static const struct pwm_ops imx_pwm_ops_v2 = { .apply = imx_pwm_apply_v2, - .enable = imx_pwm_enable, - .disable = imx_pwm_disable, - .config = imx_pwm_config, .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); const struct pwm_ops *ops; }; @@ -364,8 +242,6 @@ static struct imx_pwm_data imx_pwm_data_v1 = { }; static struct imx_pwm_data imx_pwm_data_v2 = { - .config = imx_pwm_config_v2, - .set_enable = imx_pwm_set_enable_v2, .ops = &imx_pwm_ops_v2, }; @@ -412,9 +288,6 @@ static int imx_pwm_probe(struct platform_device *pdev) if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); - imx->config = data->config; - imx->set_enable = data->set_enable; - ret = pwmchip_add(&imx->chip); if (ret < 0) return ret; -- cgit From 326ed314fefebb259563926c8c6110a009562e07 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Sun, 29 Jan 2017 22:54:15 +0100 Subject: pwm: imx: Add polarity inversion support to i.MX's PWMv2 With this patch the polarity settings for i.MX's PWMv2 is now supported on top of atomic PWM setting Signed-off-by: Bhuvanchandra DV Signed-off-by: Lukasz Majewski Reviewed-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/pwm/pwm-imx.c') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 0a81c028cb11..957099e82ed3 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -38,6 +38,7 @@ #define MX3_PWMCR_DOZEEN (1 << 24) #define MX3_PWMCR_WAITEN (1 << 23) #define MX3_PWMCR_DBGEN (1 << 22) +#define MX3_PWMCR_POUTC (1 << 18) #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) #define MX3_PWMCR_CLKSRC_IPG (1 << 16) #define MX3_PWMCR_SWR (1 << 3) @@ -163,6 +164,7 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state cstate; unsigned long long c; int ret; + u32 cr; pwm_get_state(pwm, &cstate); @@ -207,11 +209,15 @@ static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm, writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); writel(period_cycles, imx->mmio_base + MX3_PWMPR); - writel(MX3_PWMCR_PRESCALER(prescale) | - MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | - MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | - MX3_PWMCR_EN, - imx->mmio_base + MX3_PWMCR); + cr = MX3_PWMCR_PRESCALER(prescale) | + MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | + MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH | + MX3_PWMCR_EN; + + if (state->polarity == PWM_POLARITY_INVERSED) + cr |= MX3_PWMCR_POUTC; + + writel(cr, imx->mmio_base + MX3_PWMCR); } else if (cstate.enabled) { writel(0, imx->mmio_base + MX3_PWMCR); @@ -234,6 +240,7 @@ static const struct pwm_ops imx_pwm_ops_v2 = { }; struct imx_pwm_data { + bool polarity_supported; const struct pwm_ops *ops; }; @@ -242,6 +249,7 @@ static struct imx_pwm_data imx_pwm_data_v1 = { }; static struct imx_pwm_data imx_pwm_data_v2 = { + .polarity_supported = true, .ops = &imx_pwm_ops_v2, }; @@ -283,6 +291,12 @@ static int imx_pwm_probe(struct platform_device *pdev) imx->chip.npwm = 1; imx->chip.can_sleep = true; + if (data->polarity_supported) { + dev_dbg(&pdev->dev, "PWM supports output inversion\n"); + imx->chip.of_xlate = of_pwm_xlate_with_flags; + imx->chip.of_pwm_n_cells = 3; + } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(imx->mmio_base)) -- cgit