summaryrefslogtreecommitdiff
path: root/drivers/pwm
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2014-08-06 23:36:12 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-08-06 23:36:12 -0700
commit5e2aa2ed08e2e280121dc7cf5609c87d464f12ef (patch)
treeca7d7b1480285e3b617fecc5b41f0ce150a82c32 /drivers/pwm
parentf62d14a8072b9756db36ba394e2b267470a40240 (diff)
parentfc8104bc5a3f6f49d79f45f2706f79f77a9fb2ae (diff)
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.17.
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/Kconfig9
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/core.c8
-rw-r--r--drivers/pwm/pwm-ab8500.c13
-rw-r--r--drivers/pwm/pwm-atmel.c1
-rw-r--r--drivers/pwm/pwm-bcm-kona.c318
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c1
-rw-r--r--drivers/pwm/pwm-imx.c4
-rw-r--r--drivers/pwm/pwm-lp3943.c1
-rw-r--r--drivers/pwm/pwm-lpss.c161
-rw-r--r--drivers/pwm/pwm-mxs.c1
-rw-r--r--drivers/pwm/pwm-pxa.c4
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c23
-rw-r--r--drivers/pwm/pwm-samsung.c3
-rw-r--r--drivers/pwm/pwm-spear.c6
-rw-r--r--drivers/pwm/pwm-tegra.c4
-rw-r--r--drivers/pwm/pwm-tiecap.c4
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c10
-rw-r--r--drivers/pwm/pwm-twl.c8
-rw-r--r--drivers/pwm/pwm-vt8500.c4
20 files changed, 487 insertions, 97 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 5b34ff29ea38..4ad7b89a4cb4 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 e57d2c38a794..5c86a19d5d39 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/core.c b/drivers/pwm/core.c
index a80471399c20..4b66bf09ee55 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;
}
diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
index 1d07a6f99375..4c07a8420b37 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 = {
@@ -101,10 +96,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;
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 0adc952cc4ef..6e700a541ca3 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);
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
new file mode 100644
index 000000000000..02bc048892a9
--- /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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/*
+ * 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 <bcm-kernel-feedback-list@broadcom.com>");
+MODULE_AUTHOR("Tim Kryger <tkryger@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Kona PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index 420169e96b5f..a18bc8fea385 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) {
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index cc4773344874..d797c7b84c3f 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)) {
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index a40b9c34e9ff..2c39b0e50fa4 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);
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 449e372050a0..44ce6c6103ae 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -6,6 +6,7 @@
* Author: Chew Kean Ho <kean.ho.chew@intel.com>
* Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
* Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
+ * Author: Alan Cox <alan@linux.intel.com>
*
* 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 <linux/module.h>
#include <linux/pwm.h>
#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+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,
+ const 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 ERR_CAST(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 <mika.westerberg@linux.intel.com>");
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 9475bc7a6f97..4f1bb4e0a426 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);
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index cd356d870244..0b312ec420b6 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))
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index aff6ba9b49e7..3b71b42e89d5 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -21,13 +21,14 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/platform_data/pwm-renesas-tpu.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#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;
@@ -405,17 +395,12 @@ 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;
- /* 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);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index d66529a995a1..ba6b650cf8dc 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;
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index cb2d4f0f9711..6fd93e6a4122 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);
@@ -222,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);
}
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 74298c561c4e..61d86b9498ca 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;
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 032092c7a6ae..74efbe7f20c3 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)) {
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index aee4471424d1..cb75133085a8 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);
}
@@ -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)) {
@@ -531,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);
@@ -557,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);
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index b99a50e626a6..04f76725d591 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;
}
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 323125abf3f4..652e6b5b859b 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;