From 6a4e4bff9699ee1d77e51242a2982411cff6c280 Mon Sep 17 00:00:00 2001 From: Tim Kryger Date: Fri, 25 Apr 2014 11:31:12 -0700 Subject: pwm: kona: Introduce Kona PWM controller support Add support for the six-channel Kona PWM controller found on Broadcom mobile SoCs like bcm281xx. Signed-off-by: Tim Kryger Reviewed-by: Alex Elder Reviewed-by: Markus Mayer Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-bcm-kona.c | 318 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 drivers/pwm/pwm-bcm-kona.c (limited to 'drivers/pwm') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 5b34ff2..4ad7b89 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -62,6 +62,15 @@ config PWM_ATMEL_TCB To compile this driver as a module, choose M here: the module will be called pwm-atmel-tcb. +config PWM_BCM_KONA + tristate "Kona PWM support" + depends on ARCH_BCM_MOBILE + help + Generic PWM framework driver for Broadcom Kona PWM block. + + To compile this driver as a module, choose M here: the module + will be called pwm-bcm-kona. + config PWM_BFIN tristate "Blackfin PWM support" depends on BFIN_GPTIMERS diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index e57d2c3..5c86a19 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o +obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c new file mode 100644 index 0000000..02bc048 --- /dev/null +++ b/drivers/pwm/pwm-bcm-kona.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The Kona PWM has some unusual characteristics. Here are the main points. + * + * 1) There is no disable bit and the hardware docs advise programming a zero + * duty to achieve output equivalent to that of a normal disable operation. + * + * 2) Changes to prescale, duty, period, and polarity do not take effect until + * a subsequent rising edge of the trigger bit. + * + * 3) If the smooth bit and trigger bit are both low, the output is a constant + * high signal. Otherwise, the earlier waveform continues to be output. + * + * 4) If the smooth bit is set on the rising edge of the trigger bit, output + * will transition to the new settings on a period boundary (which could be + * seconds away). If the smooth bit is clear, new settings will be applied + * as soon as possible (the hardware always has a 400ns delay). + * + * 5) When the external clock that feeds the PWM is disabled, output is pegged + * high or low depending on its state at that exact instant. + */ + +#define PWM_CONTROL_OFFSET (0x00000000) +#define PWM_CONTROL_SMOOTH_SHIFT(chan) (24 + (chan)) +#define PWM_CONTROL_TYPE_SHIFT(chan) (16 + (chan)) +#define PWM_CONTROL_POLARITY_SHIFT(chan) (8 + (chan)) +#define PWM_CONTROL_TRIGGER_SHIFT(chan) (chan) + +#define PRESCALE_OFFSET (0x00000004) +#define PRESCALE_SHIFT(chan) ((chan) << 2) +#define PRESCALE_MASK(chan) (0x7 << PRESCALE_SHIFT(chan)) +#define PRESCALE_MIN (0x00000000) +#define PRESCALE_MAX (0x00000007) + +#define PERIOD_COUNT_OFFSET(chan) (0x00000008 + ((chan) << 3)) +#define PERIOD_COUNT_MIN (0x00000002) +#define PERIOD_COUNT_MAX (0x00ffffff) + +#define DUTY_CYCLE_HIGH_OFFSET(chan) (0x0000000c + ((chan) << 3)) +#define DUTY_CYCLE_HIGH_MIN (0x00000000) +#define DUTY_CYCLE_HIGH_MAX (0x00ffffff) + +struct kona_pwmc { + struct pwm_chip chip; + void __iomem *base; + struct clk *clk; +}; + +static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip) +{ + return container_of(_chip, struct kona_pwmc, chip); +} + +static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan) +{ + unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET); + + /* Clear trigger bit but set smooth bit to maintain old output */ + value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan); + value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan)); + writel(value, kp->base + PWM_CONTROL_OFFSET); + + /* Set trigger bit and clear smooth bit to apply new settings */ + value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan)); + value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan); + writel(value, kp->base + PWM_CONTROL_OFFSET); +} + +static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + u64 val, div, rate; + unsigned long prescale = PRESCALE_MIN, pc, dc; + unsigned int value, chan = pwm->hwpwm; + + /* + * Find period count, duty count and prescale to suit duty_ns and + * period_ns. This is done according to formulas described below: + * + * period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE + * + * PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1)) + * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1)) + */ + + rate = clk_get_rate(kp->clk); + + while (1) { + div = 1000000000; + div *= 1 + prescale; + val = rate * period_ns; + pc = div64_u64(val, div); + val = rate * duty_ns; + dc = div64_u64(val, div); + + /* If duty_ns or period_ns are not achievable then return */ + if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN) + return -EINVAL; + + /* If pc and dc are in bounds, the calculation is done */ + if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX) + break; + + /* Otherwise, increase prescale and recalculate pc and dc */ + if (++prescale > PRESCALE_MAX) + return -EINVAL; + } + + /* If the PWM channel is enabled, write the settings to the HW */ + if (test_bit(PWMF_ENABLED, &pwm->flags)) { + value = readl(kp->base + PRESCALE_OFFSET); + value &= ~PRESCALE_MASK(chan); + value |= prescale << PRESCALE_SHIFT(chan); + writel(value, kp->base + PRESCALE_OFFSET); + + writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan)); + + writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); + + kona_pwmc_apply_settings(kp, chan); + } + + return 0; +} + +static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + unsigned int chan = pwm->hwpwm; + unsigned int value; + int ret; + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(chip->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + value = readl(kp->base + PWM_CONTROL_OFFSET); + + if (polarity == PWM_POLARITY_NORMAL) + value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan); + else + value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan)); + + writel(value, kp->base + PWM_CONTROL_OFFSET); + + kona_pwmc_apply_settings(kp, chan); + + /* Wait for waveform to settle before gating off the clock */ + ndelay(400); + + clk_disable_unprepare(kp->clk); + + return 0; +} + +static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + int ret; + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(chip->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period); + if (ret < 0) { + clk_disable_unprepare(kp->clk); + return ret; + } + + return 0; +} + +static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct kona_pwmc *kp = to_kona_pwmc(chip); + unsigned int chan = pwm->hwpwm; + + /* Simulate a disable by configuring for zero duty */ + writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); + kona_pwmc_apply_settings(kp, chan); + + /* Wait for waveform to settle before gating off the clock */ + ndelay(400); + + clk_disable_unprepare(kp->clk); +} + +static const struct pwm_ops kona_pwm_ops = { + .config = kona_pwmc_config, + .set_polarity = kona_pwmc_set_polarity, + .enable = kona_pwmc_enable, + .disable = kona_pwmc_disable, + .owner = THIS_MODULE, +}; + +static int kona_pwmc_probe(struct platform_device *pdev) +{ + struct kona_pwmc *kp; + struct resource *res; + unsigned int chan; + unsigned int value = 0; + int ret = 0; + + kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); + if (kp == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, kp); + + kp->chip.dev = &pdev->dev; + kp->chip.ops = &kona_pwm_ops; + kp->chip.base = -1; + kp->chip.npwm = 6; + kp->chip.of_xlate = of_pwm_xlate_with_flags; + kp->chip.of_pwm_n_cells = 3; + kp->chip.can_sleep = true; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kp->base)) + return PTR_ERR(kp->base); + + kp->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(kp->clk)) { + dev_err(&pdev->dev, "failed to get clock: %ld\n", + PTR_ERR(kp->clk)); + return PTR_ERR(kp->clk); + } + + ret = clk_prepare_enable(kp->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + /* Set smooth mode, push/pull, and normal polarity for all channels */ + for (chan = 0; chan < kp->chip.npwm; chan++) { + value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan)); + value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan)); + value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan)); + } + + writel(value, kp->base + PWM_CONTROL_OFFSET); + + clk_disable_unprepare(kp->clk); + + ret = pwmchip_add(&kp->chip); + if (ret < 0) + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + + return ret; +} + +static int kona_pwmc_remove(struct platform_device *pdev) +{ + struct kona_pwmc *kp = platform_get_drvdata(pdev); + unsigned int chan; + + for (chan = 0; chan < kp->chip.npwm; chan++) + if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags)) + clk_disable_unprepare(kp->clk); + + return pwmchip_remove(&kp->chip); +} + +static const struct of_device_id bcm_kona_pwmc_dt[] = { + { .compatible = "brcm,kona-pwm" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm_kona_pwmc_dt); + +static struct platform_driver kona_pwmc_driver = { + .driver = { + .name = "bcm-kona-pwm", + .of_match_table = bcm_kona_pwmc_dt, + }, + .probe = kona_pwmc_probe, + .remove = kona_pwmc_remove, +}; +module_platform_driver(kona_pwmc_driver); + +MODULE_AUTHOR("Broadcom Corporation "); +MODULE_AUTHOR("Tim Kryger "); +MODULE_DESCRIPTION("Broadcom Kona PWM driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From a2fc1db61a651cd9b9dce2622562eadcc9e1e15c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:39:26 +0900 Subject: pwm: ab8500: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ab8500.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index 1d07a6f..9d53e8e 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -101,10 +101,8 @@ static int ab8500_pwm_probe(struct platform_device *pdev) * device which is required for ab8500 read and write */ ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); - if (ab8500 == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (ab8500 == NULL) return -ENOMEM; - } ab8500->chip.dev = &pdev->dev; ab8500->chip.ops = &ab8500_pwm_ops; -- cgit v1.1 From 1cbec749bf5a7d9259ce0650e2287cf95e65225d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:39:49 +0900 Subject: pwm: i.MX: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index cc47733..d797c7b 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -241,10 +241,8 @@ static int imx_pwm_probe(struct platform_device *pdev) return -ENODEV; imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); - if (imx == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (imx == NULL) return -ENOMEM; - } imx->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(imx->clk_per)) { -- cgit v1.1 From d93fc78f47f93a25a9f99fea613616901331d213 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:40:08 +0900 Subject: pwm: pxa: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index cd356d8..0b312ec 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -179,10 +179,8 @@ static int pwm_probe(struct platform_device *pdev) return -EINVAL; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (pwm == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (pwm == NULL) return -ENOMEM; - } pwm->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pwm->clk)) -- cgit v1.1 From 6c5059ccce2b66c9ca73f9c826b8e26d883fcf32 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:40:29 +0900 Subject: pwm: renesas-tpu: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-renesas-tpu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index aff6ba9..cc13ff4 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -405,10 +405,8 @@ static int tpu_probe(struct platform_device *pdev) int ret; tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL); - if (tpu == NULL) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + if (tpu == NULL) return -ENOMEM; - } spin_lock_init(&tpu->lock); tpu->pdev = pdev; -- cgit v1.1 From 9321fe9dbe1e32c2f24ba4b1fa92547016cd1174 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:40:49 +0900 Subject: pwm: spear: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-spear.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 8ad26b8..b4f6d0d 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -179,10 +179,8 @@ static int spear_pwm_probe(struct platform_device *pdev) u32 val; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); -- cgit v1.1 From 474b69025d60a8c45ecd32f9ae422c7c1a86853e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:41:10 +0900 Subject: pwm: tegra: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tegra.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 74298c5..61d86b9 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -173,10 +173,8 @@ static int tegra_pwm_probe(struct platform_device *pdev) int ret; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pwm) return -ENOMEM; - } pwm->dev = &pdev->dev; -- cgit v1.1 From c10d50631f29a1f09a0f3286e988877bd76733e3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:41:27 +0900 Subject: pwm: pwm-tiecap: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiecap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 032092c..74efbe7 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -209,10 +209,8 @@ static int ecap_pwm_probe(struct platform_device *pdev) u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { -- cgit v1.1 From 5e34895392ef10a1302ad5b88aa9a88fa731bc9b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:41:48 +0900 Subject: pwm: tiehrpwm: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index aee4471..3a31c08 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -440,10 +440,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!pc) return -ENOMEM; - } clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(clk)) { -- cgit v1.1 From b9f87404dde26769429b470e1d4854a3c380cf26 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 23 Apr 2014 18:42:10 +0900 Subject: pwm: vt8500: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Thierry Reding --- drivers/pwm/pwm-vt8500.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 323125a..652e6b5 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -211,10 +211,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev) } chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (chip == NULL) return -ENOMEM; - } chip->chip.dev = &pdev->dev; chip->chip.ops = &vt8500_pwm_ops; -- cgit v1.1 From 093e00bb3f82f3c67e2d1682e316fc012bcd0d92 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 18 Apr 2014 19:17:40 +0800 Subject: pwm: lpss: Add support for PCI devices Not all systems enumerate the PWM devices via ACPI. They can also be exposed via the PCI interface. Signed-off-by: Alan Cox Signed-off-by: Chew, Chiau Ee Reviewed-by: Mika Westerberg Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 161 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 31 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 449e372..c718ad1 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -6,6 +6,7 @@ * Author: Chew Kean Ho * Author: Chang Rebecca Swee Fun * Author: Chew Chiau Ee + * Author: Alan Cox * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +20,9 @@ #include #include #include +#include + +static int pci_drv, plat_drv; /* So we know which drivers registered */ #define PWM 0x00000000 #define PWM_ENABLE BIT(31) @@ -34,6 +38,16 @@ struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; struct clk *clk; + unsigned long clk_rate; +}; + +struct pwm_lpss_boardinfo { + unsigned long clk_rate; +}; + +/* BayTrail */ +static const struct pwm_lpss_boardinfo byt_info = { + 25000000 }; static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) @@ -55,7 +69,7 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, /* The equation is: base_unit = ((freq / c) * 65536) + correction */ base_unit = freq * 65536; - c = clk_get_rate(lpwm->clk); + c = lpwm->clk_rate; if (!c) return -EINVAL; @@ -113,52 +127,48 @@ static const struct pwm_ops pwm_lpss_ops = { .owner = THIS_MODULE, }; -static const struct acpi_device_id pwm_lpss_acpi_match[] = { - { "80860F09", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); - -static int pwm_lpss_probe(struct platform_device *pdev) +static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, + struct resource *r, + struct pwm_lpss_boardinfo *info) { struct pwm_lpss_chip *lpwm; - struct resource *r; int ret; - lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL); + lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); if (!lpwm) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + return ERR_PTR(-ENOMEM); - lpwm->regs = devm_ioremap_resource(&pdev->dev, r); + lpwm->regs = devm_ioremap_resource(dev, r); if (IS_ERR(lpwm->regs)) - return PTR_ERR(lpwm->regs); - - lpwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(lpwm->clk)) { - dev_err(&pdev->dev, "failed to get PWM clock\n"); - return PTR_ERR(lpwm->clk); + return lpwm->regs; + + if (info) { + lpwm->clk_rate = info->clk_rate; + } else { + lpwm->clk = devm_clk_get(dev, NULL); + if (IS_ERR(lpwm->clk)) { + dev_err(dev, "failed to get PWM clock\n"); + return ERR_CAST(lpwm->clk); + } + lpwm->clk_rate = clk_get_rate(lpwm->clk); } - lpwm->chip.dev = &pdev->dev; + lpwm->chip.dev = dev; lpwm->chip.ops = &pwm_lpss_ops; lpwm->chip.base = -1; lpwm->chip.npwm = 1; ret = pwmchip_add(&lpwm->chip); if (ret) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - return ret; + dev_err(dev, "failed to add PWM chip: %d\n", ret); + return ERR_PTR(ret); } - platform_set_drvdata(pdev, lpwm); - return 0; + return lpwm; } -static int pwm_lpss_remove(struct platform_device *pdev) +static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { - struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); u32 ctrl; ctrl = readl(lpwm->regs + PWM); @@ -167,15 +177,104 @@ static int pwm_lpss_remove(struct platform_device *pdev) return pwmchip_remove(&lpwm->chip); } -static struct platform_driver pwm_lpss_driver = { +static int pwm_lpss_probe_pci(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + const struct pwm_lpss_boardinfo *info; + struct pwm_lpss_chip *lpwm; + int err; + + err = pci_enable_device(pdev); + if (err < 0) + return err; + + info = (struct pwm_lpss_boardinfo *)id->driver_data; + lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); + if (IS_ERR(lpwm)) + return PTR_ERR(lpwm); + + pci_set_drvdata(pdev, lpwm); + return 0; +} + +static void pwm_lpss_remove_pci(struct pci_dev *pdev) +{ + struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); + + pwm_lpss_remove(lpwm); + pci_disable_device(pdev); +} + +static struct pci_device_id pwm_lpss_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&byt_info}, + { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&byt_info}, + { }, +}; +MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); + +static struct pci_driver pwm_lpss_driver_pci = { + .name = "pwm-lpss", + .id_table = pwm_lpss_pci_ids, + .probe = pwm_lpss_probe_pci, + .remove = pwm_lpss_remove_pci, +}; + +static int pwm_lpss_probe_platform(struct platform_device *pdev) +{ + struct pwm_lpss_chip *lpwm; + struct resource *r; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + lpwm = pwm_lpss_probe(&pdev->dev, r, NULL); + if (IS_ERR(lpwm)) + return PTR_ERR(lpwm); + + platform_set_drvdata(pdev, lpwm); + return 0; +} + +static int pwm_lpss_remove_platform(struct platform_device *pdev) +{ + struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); + + return pwm_lpss_remove(lpwm); +} + +static const struct acpi_device_id pwm_lpss_acpi_match[] = { + { "80860F09", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); + +static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, }, - .probe = pwm_lpss_probe, - .remove = pwm_lpss_remove, + .probe = pwm_lpss_probe_platform, + .remove = pwm_lpss_remove_platform, }; -module_platform_driver(pwm_lpss_driver); + +static int __init pwm_init(void) +{ + pci_drv = pci_register_driver(&pwm_lpss_driver_pci); + plat_drv = platform_driver_register(&pwm_lpss_driver_platform); + if (pci_drv && plat_drv) + return pci_drv; + + return 0; +} +module_init(pwm_init); + +static void __exit pwm_exit(void) +{ + if (!pci_drv) + pci_unregister_driver(&pwm_lpss_driver_pci); + if (!plat_drv) + platform_driver_unregister(&pwm_lpss_driver_platform); +} +module_exit(pwm_exit); MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg "); -- cgit v1.1 From 5b1e8e0653760ade53c0c7caaa9278c57361cb8b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 5 May 2014 23:29:00 +0200 Subject: pwm: spear: fix check on pwmchip_add() return value pwmchip_add() returns zero on success and a negative value on error, so the condition of the check must be inverted. Signed-off-by: Beniamino Galvani Acked-by: Viresh Kumar Signed-off-by: Thierry Reding --- drivers/pwm/pwm-spear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index b4f6d0d..cffa1e3 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -220,7 +220,7 @@ static int spear_pwm_probe(struct platform_device *pdev) } ret = pwmchip_add(&pc->chip); - if (!ret) { + if (ret < 0) { clk_unprepare(pc->clk); dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); } -- cgit v1.1 From 89c0339e0aa097384b3efed894b23820814c21d3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 7 May 2014 10:27:57 +0200 Subject: pwm: lpss: Fix const qualifier and sparse warnings Fixes the following warnings reported by the 0-DAY kernel build testing backend: drivers/pwm/pwm-lpss.c: In function 'pwm_lpss_probe_pci': >> drivers/pwm/pwm-lpss.c:192:2: warning: passing argument 3 of 'pwm_lpss_probe' discards 'const' qualifier from pointer target type [enabled by default] lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); ^ drivers/pwm/pwm-lpss.c:130:30: note: expected 'struct pwm_lpss_boardinfo *' but argument is of type 'const struct pwm_lpss_boardinfo *' static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, ^ >> drivers/pwm/pwm-lpss.c:143:28: sparse: incorrect type in return expression (different address spaces) drivers/pwm/pwm-lpss.c:143:28: expected struct pwm_lpss_chip * drivers/pwm/pwm-lpss.c:143:28: got void [noderef] *regs >> drivers/pwm/pwm-lpss.c:192:63: sparse: incorrect type in argument 3 (different modifiers) drivers/pwm/pwm-lpss.c:192:63: expected struct pwm_lpss_boardinfo *info drivers/pwm/pwm-lpss.c:192:63: got struct pwm_lpss_boardinfo const *[assigned] info drivers/pwm/pwm-lpss.c: In function 'pwm_lpss_probe_pci': drivers/pwm/pwm-lpss.c:192:2: warning: passing argument 3 of 'pwm_lpss_probe' discards 'const' qualifier from pointer target type [enabled by default] lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); ^ drivers/pwm/pwm-lpss.c:130:30: note: expected 'struct pwm_lpss_boardinfo *' but argument is of type 'const struct pwm_lpss_boardinfo *' static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, ^ Reported-by: kbuild test robot Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index c718ad1..44ce6c6 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -129,7 +129,7 @@ static const struct pwm_ops pwm_lpss_ops = { static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, - struct pwm_lpss_boardinfo *info) + const struct pwm_lpss_boardinfo *info) { struct pwm_lpss_chip *lpwm; int ret; @@ -140,7 +140,7 @@ static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, lpwm->regs = devm_ioremap_resource(dev, r); if (IS_ERR(lpwm->regs)) - return lpwm->regs; + return ERR_CAST(lpwm->regs); if (info) { lpwm->clk_rate = info->clk_rate; -- cgit v1.1 From 9c88669c2cfc91158f157b5584103ff7e5b6bedb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 9 Apr 2014 17:21:26 +0800 Subject: pwm: twl: Really disable twl6030 PWMs Current twl6030_pwm_disable() implementation writes TWL6030_TOGGLE3_REG twice, the second write sets TWL6030_PWMXEN bits so the PWM clock does not disable. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Thierry Reding --- drivers/pwm/pwm-twl.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index b99a50e..04f7672 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -265,14 +265,6 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); if (ret < 0) { - dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label); - goto out; - } - - val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); - if (ret < 0) { dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); goto out; } -- cgit v1.1 From 3796ce1d4d4b330a75005c5eda105603ce9d4071 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 19 May 2014 22:42:32 +0200 Subject: pwm: add period and polarity to struct pwm_lookup Add period and polarity members to struct pwm_lookup so that platforms using the lookup table can be treated the same way as those using the device tree. Signed-off-by: Alexandre Belloni Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index a804713..4b66bf0 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -661,10 +661,16 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) } } + mutex_unlock(&pwm_lookup_lock); + if (chip) pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, p->period); + pwm_set_polarity(pwm, p->polarity); - mutex_unlock(&pwm_lookup_lock); return pwm; } -- cgit v1.1 From dc671157139918eaf61f73db1bd6dd02960b66e2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 19 May 2014 22:42:34 +0200 Subject: pwm: renesas-tpu: remove unused struct tpu_pwm_platform_data The struct is not used anymore and the polarity initialization will be done using the PWM lookup table (or device tree). Signed-off-by: Alexandre Belloni Acked-by: Laurent Pinchart Acked-by: Simon Horman Signed-off-by: Thierry Reding --- drivers/pwm/pwm-renesas-tpu.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index cc13ff4..3b71b42 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -21,13 +21,14 @@ #include #include #include -#include #include #include #include #include #include +#define TPU_CHANNEL_MAX 4 + #define TPU_TSTR 0x00 /* Timer start register (shared) */ #define TPU_TCRn 0x00 /* Timer control register */ @@ -87,7 +88,6 @@ struct tpu_pwm_device { struct tpu_device { struct platform_device *pdev; - enum pwm_polarity polarities[TPU_CHANNEL_MAX]; struct pwm_chip chip; spinlock_t lock; @@ -229,7 +229,7 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm) pwm->tpu = tpu; pwm->channel = _pwm->hwpwm; - pwm->polarity = tpu->polarities[pwm->channel]; + pwm->polarity = PWM_POLARITY_NORMAL; pwm->prescaler = 0; pwm->period = 0; pwm->duty = 0; @@ -388,16 +388,6 @@ static const struct pwm_ops tpu_pwm_ops = { * Probe and remove */ -static void tpu_parse_pdata(struct tpu_device *tpu) -{ - struct tpu_pwm_platform_data *pdata = tpu->pdev->dev.platform_data; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(tpu->polarities); ++i) - tpu->polarities[i] = pdata ? pdata->channels[i].polarity - : PWM_POLARITY_NORMAL; -} - static int tpu_probe(struct platform_device *pdev) { struct tpu_device *tpu; @@ -411,9 +401,6 @@ static int tpu_probe(struct platform_device *pdev) spin_lock_init(&tpu->lock); tpu->pdev = pdev; - /* Initialize device configuration from platform data. */ - tpu_parse_pdata(tpu); - /* Map memory, get clock and pin control. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); tpu->base = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.1 From af5935ec125ef85823ea43fbcfdd3c15b532d199 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 2 Apr 2014 13:56:21 +0200 Subject: pwm: tiehrpwm: don't build PM related functions when not needed Fixes following warnings on AM335X with no PM_SLEEP drivers/pwm/pwm-tiehrpwm.c:534:13: warning: 'ehrpwm_pwm_save_context' defined but not used [-Wunused-function] drivers/pwm/pwm-tiehrpwm.c:548:13: warning: 'ehrpwm_pwm_restore_context' defined but not used [-Wunused-function] Signed-off-by: Wolfram Sang Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 3a31c08..f5e371d 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -529,6 +529,7 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev) return pwmchip_remove(&pc->chip); } +#ifdef CONFIG_PM_SLEEP static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc) { pm_runtime_get_sync(pc->chip.dev); @@ -555,7 +556,6 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc) ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl); } -#ifdef CONFIG_PM_SLEEP static int ehrpwm_pwm_suspend(struct device *dev) { struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev); -- cgit v1.1 From 3ea57ea6691241ccdf58d9735f85e49b6174990c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 2 Apr 2014 13:56:22 +0200 Subject: pwm: tiehrpwm: inline accessor functions These elementary functions should be inlined for fastest access. Also fixes this warning as a side-effect (when no PM_SLEEP is selected): drivers/pwm/pwm-tiehrpwm.c:141:12: warning: 'ehrpwm_read' defined but not used [-Wunused-function] Signed-off-by: Wolfram Sang Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index f5e371d..cb75133 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -138,12 +138,12 @@ static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct ehrpwm_pwm_chip, chip); } -static u16 ehrpwm_read(void __iomem *base, int offset) +static inline u16 ehrpwm_read(void __iomem *base, int offset) { return readw(base + offset); } -static void ehrpwm_write(void __iomem *base, int offset, unsigned int val) +static inline void ehrpwm_write(void __iomem *base, int offset, unsigned int val) { writew(val & 0xFFFF, base + offset); } -- cgit v1.1 From bd9c1b60050e2b7ef6507d8eaa5279afc043e06e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 8 Apr 2014 19:29:57 +0800 Subject: pwm: mxs: set pwm_chip can_sleep flag The .config() calls clk_get_rate() which might sleep, so we need to set pwm_chip can_sleep flag. Otherwise, we see the following warning when using PWM driven heartbeat led. WARNING: CPU: 0 PID: 0 at kernel/locking/mutex.c:856 mutex_trylock+0x184/0x1a4() DEBUG_LOCKS_WARN_ON(in_interrupt()) Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.14.0-rc5 #18 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x6c/0x8c) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (mutex_trylock+0x184/0x1a4) [] (mutex_trylock) from [] (clk_prepare_lock+0xc/0xec) [] (clk_prepare_lock) from [] (clk_get_rate+0xc/0x68) [] (clk_get_rate) from [] (mxs_pwm_config+0x20/0x198) [] (mxs_pwm_config) from [] (pwm_config+0x60/0x70) [] (pwm_config) from [] (__led_pwm_set+0x1c/0x3c) [] (__led_pwm_set) from [] (led_heartbeat_function+0x70/0x110) [] (led_heartbeat_function) from [] (call_timer_fn+0x7c/0x164) [] (call_timer_fn) from [] (run_timer_softirq+0x1f0/0x260) [] (run_timer_softirq) from [] (__do_softirq+0xc4/0x2f0) [] (__do_softirq) from [] (irq_exit+0xa4/0x10c) [] (irq_exit) from [] (handle_IRQ+0x34/0x84) [] (handle_IRQ) from [] (__irq_svc+0x44/0x54) [] (__irq_svc) from [] (arch_cpu_idle+0x40/0x48) [] (arch_cpu_idle) from [] (cpu_startup_entry+0x70/0x198) [] (cpu_startup_entry) from [] (start_kernel+0x2a8/0x2f8) Reported-by: Stefan Wahren Signed-off-by: Shawn Guo Acked-by: Alexandre Belloni Tested-by: Stefan Wahren Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mxs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 9475bc7..4f1bb4e 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -147,6 +147,7 @@ static int mxs_pwm_probe(struct platform_device *pdev) mxs->chip.dev = &pdev->dev; mxs->chip.ops = &mxs_pwm_ops; mxs->chip.base = -1; + mxs->chip.can_sleep = true; ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); if (ret < 0) { dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret); -- cgit v1.1 From cf3a384b3484200f45d185b2e3c7b71fd4511ea7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 9 Apr 2014 20:26:09 +0200 Subject: pwm: atmel: set pwm_chip can_sleep flag atmel_pwm_config() calls clk_get_rate() which might sleep, so we need to set pwm_chip can_sleep flag. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 0adc952..6e700a5 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -357,6 +357,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.base = -1; atmel_pwm->chip.npwm = 4; + atmel_pwm->chip.can_sleep = true; atmel_pwm->config = data->config; ret = pwmchip_add(&atmel_pwm->chip); -- cgit v1.1 From 00afb429fc447e9adc30828949ea85e654411562 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 16 Apr 2014 00:38:10 +0800 Subject: pwm: lp3943: Set pwm_chip can_sleep flag Read/write through I2C can sleep, thus set pwm_chip can_sleep flag. Signed-off-by: Axel Lin Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lp3943.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index a40b9c3..2c39b0e 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -278,6 +278,7 @@ static int lp3943_pwm_probe(struct platform_device *pdev) lp3943_pwm->chip.dev = &pdev->dev; lp3943_pwm->chip.ops = &lp3943_pwm_ops; lp3943_pwm->chip.npwm = LP3943_NUM_PWMS; + lp3943_pwm->chip.can_sleep = true; platform_set_drvdata(pdev, lp3943_pwm); -- cgit v1.1 From 3bdf878102110c916dd6a9fb0df9ecfde93a3c83 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Mon, 12 May 2014 20:26:21 +0530 Subject: pwm: samsung: do not set manual update bit in pwm_samsung_config pwm_samsung_config() sets the manual update bit via a call to the pwm_samsung_enable() function even when the channel is already running. This causes noticable flicker on display if we try to change the backlight brightness from minimum to maximum, continuously. So, we remove the call to pwm_samsung_enable() from pwm_samsung_config to avoid the flicker and this change doesn't harm normal working since the pwm-backlight driver already calls pwm_samsung_enable() where needed. Signed-off-by: Ajay Kumar Reviewed-by: Tomasz Figa Signed-off-by: Thierry Reding --- drivers/pwm/pwm-samsung.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index d66529a..ba6b650 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -335,9 +335,6 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm)); writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm)); - if (test_bit(PWMF_ENABLED, &pwm->flags)) - pwm_samsung_enable(chip, pwm); - chan->period_ns = period_ns; chan->tin_ns = tin_ns; chan->duty_ns = duty_ns; -- cgit v1.1 From 54b02347d71802a010ceace3dd25ed3774ba8a1e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 9 Apr 2014 21:19:54 +0800 Subject: pwm: ab8500: Fix wrong value shift for disable/enable PWM Current code only works when pdev->id is 1. Fix it by passing correct bit values to abx500_mask_and_set_register_interruptible(). Having DISABLE_PWM/ENABLE_PWM does not make the code more readable because the bit values depend on pdev->id. Thus drop the DISABLE_PWM and ENABLE_PWM defines. This patch also removes an unnecessary return in ab8500_pwm_disable(). Signed-off-by: Axel Lin Acked-by: Linus Walleij Acked-by: Alexandre BOURDIOL Acked-by: Philippe Begnic Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ab8500.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index 9d53e8e..4c07a84 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -20,10 +20,6 @@ #define AB8500_PWM_OUT_CTRL2_REG 0x61 #define AB8500_PWM_OUT_CTRL7_REG 0x66 -/* backlight driver constants */ -#define ENABLE_PWM 1 -#define DISABLE_PWM 0 - struct ab8500_pwm_chip { struct pwm_chip chip; }; @@ -64,7 +60,7 @@ static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) ret = abx500_mask_and_set_register_interruptible(chip->dev, AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, - 1 << (chip->base - 1), ENABLE_PWM); + 1 << (chip->base - 1), 1 << (chip->base - 1)); if (ret < 0) dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", pwm->label, ret); @@ -77,11 +73,10 @@ static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ret = abx500_mask_and_set_register_interruptible(chip->dev, AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, - 1 << (chip->base - 1), DISABLE_PWM); + 1 << (chip->base - 1), 0); if (ret < 0) dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", pwm->label, ret); - return; } static const struct pwm_ops ab8500_pwm_ops = { -- cgit v1.1 From 39fd3f99aba3f7683fc9b62e916e4c886a1cb6b0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 22 May 2014 08:05:20 +0800 Subject: pwm: fsl-ftm: set pwm_chip can_sleep flag The implementation of .config(), .enable() and .disable() operations in this driver may sleep, thus set pwm_chip can_sleep flag. Signed-off-by: Axel Lin Acked-by: Xiubo Li Signed-off-by: Thierry Reding --- drivers/pwm/pwm-fsl-ftm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pwm') diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 420169e..a18bc8f 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -454,6 +454,7 @@ static int fsl_pwm_probe(struct platform_device *pdev) fpc->chip.of_pwm_n_cells = 3; fpc->chip.base = -1; fpc->chip.npwm = 8; + fpc->chip.can_sleep = true; ret = pwmchip_add(&fpc->chip); if (ret < 0) { -- cgit v1.1