summaryrefslogtreecommitdiff
path: root/drivers/pwm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/Kconfig22
-rw-r--r--drivers/pwm/Makefile2
-rw-r--r--drivers/pwm/core.c70
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c1
-rw-r--r--drivers/pwm/pwm-atmel.c1
-rw-r--r--drivers/pwm/pwm-bcm-kona.c1
-rw-r--r--drivers/pwm/pwm-berlin.c1
-rw-r--r--drivers/pwm/pwm-bfin.c2
-rw-r--r--drivers/pwm/pwm-brcmstb.c1
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c1
-rw-r--r--drivers/pwm/pwm-hibvt.c271
-rw-r--r--drivers/pwm/pwm-imx.c272
-rw-r--r--drivers/pwm/pwm-lp3943.c1
-rw-r--r--drivers/pwm/pwm-lpss-pci.c22
-rw-r--r--drivers/pwm/pwm-lpss-platform.c21
-rw-r--r--drivers/pwm/pwm-lpss.c132
-rw-r--r--drivers/pwm/pwm-lpss.h4
-rw-r--r--drivers/pwm/pwm-meson.c1
-rw-r--r--drivers/pwm/pwm-mxs.c2
-rw-r--r--drivers/pwm/pwm-pca9685.c176
-rw-r--r--drivers/pwm/pwm-pxa.c2
-rw-r--r--drivers/pwm/pwm-sti.c1
-rw-r--r--drivers/pwm/pwm-stm32.c397
-rw-r--r--drivers/pwm/pwm-sun4i.c1
-rw-r--r--drivers/pwm/pwm-twl-led.c1
-rw-r--r--drivers/pwm/pwm-twl.c1
-rw-r--r--drivers/pwm/pwm-vt8500.c2
27 files changed, 1133 insertions, 276 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf0128899c09..42e37c20b361 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -76,7 +76,9 @@ config PWM_ATMEL_TCB
config PWM_BCM_IPROC
tristate "iProc PWM support"
- depends on ARCH_BCM_IPROC
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
+ depends on COMMON_CLK
+ default ARCH_BCM_IPROC
help
Generic PWM framework driver for Broadcom iProc PWM block. This
block is used in Broadcom iProc SoC's.
@@ -175,6 +177,15 @@ config PWM_FSL_FTM
To compile this driver as a module, choose M here: the module
will be called pwm-fsl-ftm.
+config PWM_HIBVT
+ tristate "HiSilicon BVT PWM support"
+ depends on ARCH_HISI || COMPILE_TEST
+ help
+ Generic PWM framework driver for HiSilicon BVT SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-hibvt.
+
config PWM_IMG
tristate "Imagination Technologies PWM driver"
depends on HAS_IOMEM
@@ -388,6 +399,15 @@ config PWM_STI
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
+config PWM_STM32
+ tristate "STMicroelectronics STM32 PWM"
+ depends on MFD_STM32_TIMERS || COMPILE_TEST
+ help
+ Generic PWM framework driver for STM32 SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-stm32.
+
config PWM_STMPE
bool "STMPE expander PWM export"
depends on MFD_STMPE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54efcc2..346a83b00f28 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o
obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
+obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o
obj-$(CONFIG_PWM_IMG) += pwm-img.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
+obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 172ef8245811..a0860b30bd93 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -137,9 +137,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
{
struct pwm_device *pwm;
+ /* check, whether the driver supports a third cell for flags */
if (pc->of_pwm_n_cells < 3)
return ERR_PTR(-EINVAL);
+ /* flags in the third cell are optional */
+ if (args->args_count < 2)
+ return ERR_PTR(-EINVAL);
+
if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL);
@@ -148,11 +153,10 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
return pwm;
pwm->args.period = args->args[1];
+ pwm->args.polarity = PWM_POLARITY_NORMAL;
- if (args->args[2] & PWM_POLARITY_INVERTED)
+ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
pwm->args.polarity = PWM_POLARITY_INVERSED;
- else
- pwm->args.polarity = PWM_POLARITY_NORMAL;
return pwm;
}
@@ -163,9 +167,14 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
{
struct pwm_device *pwm;
+ /* sanity check driver support */
if (pc->of_pwm_n_cells < 2)
return ERR_PTR(-EINVAL);
+ /* all cells are required */
+ if (args->args_count != pc->of_pwm_n_cells)
+ return ERR_PTR(-EINVAL);
+
if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL);
@@ -663,24 +672,17 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
&args);
if (err) {
- pr_debug("%s(): can't parse \"pwms\" property\n", __func__);
+ pr_err("%s(): can't parse \"pwms\" property\n", __func__);
return ERR_PTR(err);
}
pc = of_node_to_pwmchip(args.np);
if (IS_ERR(pc)) {
- pr_debug("%s(): PWM chip not found\n", __func__);
+ pr_err("%s(): PWM chip not found\n", __func__);
pwm = ERR_CAST(pc);
goto put;
}
- if (args.args_count != pc->of_pwm_n_cells) {
- pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
- args.np->full_name);
- pwm = ERR_PTR(-EINVAL);
- goto put;
- }
-
pwm = pc->of_xlate(pc, &args);
if (IS_ERR(pwm))
goto put;
@@ -757,12 +759,13 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
*/
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
{
- struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
const char *dev_id = dev ? dev_name(dev) : NULL;
- struct pwm_chip *chip = NULL;
+ struct pwm_device *pwm;
+ struct pwm_chip *chip;
unsigned int best = 0;
struct pwm_lookup *p, *chosen = NULL;
unsigned int match;
+ int err;
/* look up via DT first */
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
@@ -817,24 +820,35 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
}
}
- if (!chosen) {
- pwm = ERR_PTR(-ENODEV);
- goto out;
- }
+ mutex_unlock(&pwm_lookup_lock);
+
+ if (!chosen)
+ return ERR_PTR(-ENODEV);
chip = pwmchip_find_by_name(chosen->provider);
+
+ /*
+ * If the lookup entry specifies a module, load the module and retry
+ * the PWM chip lookup. This can be used to work around driver load
+ * ordering issues if driver's can't be made to properly support the
+ * deferred probe mechanism.
+ */
+ if (!chip && chosen->module) {
+ err = request_module(chosen->module);
+ if (err == 0)
+ chip = pwmchip_find_by_name(chosen->provider);
+ }
+
if (!chip)
- goto out;
+ return ERR_PTR(-EPROBE_DEFER);
pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id);
if (IS_ERR(pwm))
- goto out;
+ return pwm;
pwm->args.period = chosen->period;
pwm->args.polarity = chosen->polarity;
-out:
- mutex_unlock(&pwm_lookup_lock);
return pwm;
}
EXPORT_SYMBOL_GPL(pwm_get);
@@ -960,18 +974,6 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
}
EXPORT_SYMBOL_GPL(devm_pwm_put);
-/**
- * pwm_can_sleep() - report whether PWM access will sleep
- * @pwm: PWM device
- *
- * Returns: True if accessing the PWM can sleep, false otherwise.
- */
-bool pwm_can_sleep(struct pwm_device *pwm)
-{
- return true;
-}
-EXPORT_SYMBOL_GPL(pwm_can_sleep);
-
#ifdef CONFIG_DEBUG_FS
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
{
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 14fc011faa32..999187277ea5 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -270,7 +270,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
chip->chip.npwm = 1;
chip->chip.of_xlate = of_pwm_xlate_with_flags;
chip->chip.of_pwm_n_cells = 3;
- chip->chip.can_sleep = 1;
ret = pwmchip_add_with_polarity(&chip->chip, PWM_POLARITY_INVERSED);
if (ret) {
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index e6b8b1b7e6ba..67a7023be5c2 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -385,7 +385,6 @@ 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;
atmel_pwm->updated_pwms = 0;
mutex_init(&atmel_pwm->isr_lock);
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index c63418322023..09a95aeb3a70 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -276,7 +276,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
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);
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index 01339c152ab0..771859aca4be 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -206,7 +206,6 @@ static int berlin_pwm_probe(struct platform_device *pdev)
pwm->chip.ops = &berlin_pwm_ops;
pwm->chip.base = -1;
pwm->chip.npwm = 4;
- pwm->chip.can_sleep = true;
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
pwm->chip.of_pwm_n_cells = 3;
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-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index 5d5adee16886..8063cffa1c96 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -270,7 +270,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
p->chip.ops = &brcmstb_pwm_ops;
p->chip.base = -1;
p->chip.npwm = 2;
- p->chip.can_sleep = true;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
p->base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index fad968eb75f6..557b4ea16796 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -446,7 +446,6 @@ 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-hibvt.c b/drivers/pwm/pwm-hibvt.c
new file mode 100644
index 000000000000..d0e8f8542626
--- /dev/null
+++ b/drivers/pwm/pwm-hibvt.c
@@ -0,0 +1,271 @@
+/*
+ * PWM Controller Driver for HiSilicon BVT SoCs
+ *
+ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/reset.h>
+
+#define PWM_CFG0_ADDR(x) (((x) * 0x20) + 0x0)
+#define PWM_CFG1_ADDR(x) (((x) * 0x20) + 0x4)
+#define PWM_CFG2_ADDR(x) (((x) * 0x20) + 0x8)
+#define PWM_CTRL_ADDR(x) (((x) * 0x20) + 0xC)
+
+#define PWM_ENABLE_SHIFT 0
+#define PWM_ENABLE_MASK BIT(0)
+
+#define PWM_POLARITY_SHIFT 1
+#define PWM_POLARITY_MASK BIT(1)
+
+#define PWM_KEEP_SHIFT 2
+#define PWM_KEEP_MASK BIT(2)
+
+#define PWM_PERIOD_MASK GENMASK(31, 0)
+#define PWM_DUTY_MASK GENMASK(31, 0)
+
+struct hibvt_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+ struct reset_control *rstc;
+};
+
+struct hibvt_pwm_soc {
+ u32 num_pwms;
+};
+
+static const struct hibvt_pwm_soc pwm_soc[2] = {
+ { .num_pwms = 4 },
+ { .num_pwms = 8 },
+};
+
+static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct hibvt_pwm_chip, chip);
+}
+
+static void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
+ u32 mask, u32 data)
+{
+ void __iomem *address = base + offset;
+ u32 value;
+
+ value = readl(address);
+ value &= ~mask;
+ value |= (data & mask);
+ writel(value, address);
+}
+
+static void hibvt_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
+
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
+ PWM_ENABLE_MASK, 0x1);
+}
+
+static void hibvt_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
+
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
+ PWM_ENABLE_MASK, 0x0);
+}
+
+static void hibvt_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_cycle_ns, int period_ns)
+{
+ struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
+ u32 freq, period, duty;
+
+ freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
+
+ period = div_u64(freq * period_ns, 1000);
+ duty = div_u64(period * duty_cycle_ns, period_ns);
+
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG0_ADDR(pwm->hwpwm),
+ PWM_PERIOD_MASK, period);
+
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG1_ADDR(pwm->hwpwm),
+ PWM_DUTY_MASK, duty);
+}
+
+static void hibvt_pwm_set_polarity(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
+
+ if (polarity == PWM_POLARITY_INVERSED)
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
+ PWM_POLARITY_MASK, (0x1 << PWM_POLARITY_SHIFT));
+ else
+ hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm),
+ PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT));
+}
+
+static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
+ void __iomem *base;
+ u32 freq, value;
+
+ freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000);
+ base = hi_pwm_chip->base;
+
+ value = readl(base + PWM_CFG0_ADDR(pwm->hwpwm));
+ state->period = div_u64(value * 1000, freq);
+
+ value = readl(base + PWM_CFG1_ADDR(pwm->hwpwm));
+ state->duty_cycle = div_u64(value * 1000, freq);
+
+ value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm));
+ state->enabled = (PWM_ENABLE_MASK & value);
+}
+
+static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ if (state->polarity != pwm->state.polarity)
+ hibvt_pwm_set_polarity(chip, pwm, state->polarity);
+
+ if (state->period != pwm->state.period ||
+ state->duty_cycle != pwm->state.duty_cycle)
+ hibvt_pwm_config(chip, pwm, state->duty_cycle, state->period);
+
+ if (state->enabled != pwm->state.enabled) {
+ if (state->enabled)
+ hibvt_pwm_enable(chip, pwm);
+ else
+ hibvt_pwm_disable(chip, pwm);
+ }
+
+ return 0;
+}
+
+static struct pwm_ops hibvt_pwm_ops = {
+ .get_state = hibvt_pwm_get_state,
+ .apply = hibvt_pwm_apply,
+
+ .owner = THIS_MODULE,
+};
+
+static int hibvt_pwm_probe(struct platform_device *pdev)
+{
+ const struct hibvt_pwm_soc *soc =
+ of_device_get_match_data(&pdev->dev);
+ struct hibvt_pwm_chip *pwm_chip;
+ struct resource *res;
+ int ret;
+ int i;
+
+ pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
+ if (pwm_chip == NULL)
+ return -ENOMEM;
+
+ pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm_chip->clk)) {
+ dev_err(&pdev->dev, "getting clock failed with %ld\n",
+ PTR_ERR(pwm_chip->clk));
+ return PTR_ERR(pwm_chip->clk);
+ }
+
+ pwm_chip->chip.ops = &hibvt_pwm_ops;
+ pwm_chip->chip.dev = &pdev->dev;
+ pwm_chip->chip.base = -1;
+ pwm_chip->chip.npwm = soc->num_pwms;
+ pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
+ pwm_chip->chip.of_pwm_n_cells = 3;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm_chip->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm_chip->base))
+ return PTR_ERR(pwm_chip->base);
+
+ ret = clk_prepare_enable(pwm_chip->clk);
+ if (ret < 0)
+ return ret;
+
+ pwm_chip->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm_chip->rstc)) {
+ clk_disable_unprepare(pwm_chip->clk);
+ return PTR_ERR(pwm_chip->rstc);
+ }
+
+ reset_control_assert(pwm_chip->rstc);
+ msleep(30);
+ reset_control_deassert(pwm_chip->rstc);
+
+ ret = pwmchip_add(&pwm_chip->chip);
+ if (ret < 0) {
+ clk_disable_unprepare(pwm_chip->clk);
+ return ret;
+ }
+
+ for (i = 0; i < pwm_chip->chip.npwm; i++) {
+ hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
+ PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
+ }
+
+ platform_set_drvdata(pdev, pwm_chip);
+
+ return 0;
+}
+
+static int hibvt_pwm_remove(struct platform_device *pdev)
+{
+ struct hibvt_pwm_chip *pwm_chip;
+
+ pwm_chip = platform_get_drvdata(pdev);
+
+ reset_control_assert(pwm_chip->rstc);
+ msleep(30);
+ reset_control_deassert(pwm_chip->rstc);
+
+ clk_disable_unprepare(pwm_chip->clk);
+
+ return pwmchip_remove(&pwm_chip->chip);
+}
+
+static const struct of_device_id hibvt_pwm_of_match[] = {
+ { .compatible = "hisilicon,hi3516cv300-pwm", .data = &pwm_soc[0] },
+ { .compatible = "hisilicon,hi3519v100-pwm", .data = &pwm_soc[1] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hibvt_pwm_of_match);
+
+static struct platform_driver hibvt_pwm_driver = {
+ .driver = {
+ .name = "hibvt-pwm",
+ .of_match_table = hibvt_pwm_of_match,
+ },
+ .probe = hibvt_pwm_probe,
+ .remove = hibvt_pwm_remove,
+};
+module_platform_driver(hibvt_pwm_driver);
+
+MODULE_AUTHOR("Jian Yuan");
+MODULE_DESCRIPTION("HiSilicon BVT SoCs PWM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index d600fd5cd4ba..2ba5c3a398ff 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)
@@ -49,15 +50,10 @@
struct imx_chip {
struct clk *clk_per;
- struct clk *clk_ipg;
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)
@@ -91,176 +87,170 @@ 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;
- val = readl(imx->mmio_base + MX1_PWMC);
-
- if (enable)
- val |= MX1_PWMC_EN;
- else
- val &= ~MX1_PWMC_EN;
+ 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);
-}
-
-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 wait_count = 0, fifoav;
- u32 cr, sr;
-
- /*
- * 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) {
- 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 {
- 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");
- }
-
- 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)
+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 + MX3_PWMCR);
-
- if (enable)
- val |= MX3_PWMCR_EN;
- else
- val &= ~MX3_PWMCR_EN;
+ val = readl(imx->mmio_base + MX1_PWMC);
+ val &= ~MX1_PWMC_EN;
+ writel(val, imx->mmio_base + MX1_PWMC);
- writel(val, imx->mmio_base + MX3_PWMCR);
+ clk_disable_unprepare(imx->clk_per);
}
-static int imx_pwm_config(struct pwm_chip *chip,
- struct pwm_device *pwm, int duty_ns, int period_ns)
+static void imx_pwm_sw_reset(struct pwm_chip *chip)
{
struct imx_chip *imx = to_imx_chip(chip);
- int ret;
-
- ret = clk_prepare_enable(imx->clk_ipg);
- if (ret)
- return ret;
+ 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");
+}
- ret = imx->config(chip, pwm, duty_ns, period_ns);
+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;
- clk_disable_unprepare(imx->clk_ipg);
+ 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);
- return ret;
+ 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_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+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;
+ u32 cr;
+
+ 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);
+ }
- ret = clk_prepare_enable(imx->clk_per);
- if (ret)
- return ret;
+ writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
+ writel(period_cycles, imx->mmio_base + MX3_PWMPR);
- imx->set_enable(chip, true);
+ cr = MX3_PWMCR_PRESCALER(prescale) |
+ MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
+ MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH |
+ MX3_PWMCR_EN;
- return 0;
-}
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ cr |= MX3_PWMCR_POUTC;
-static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct imx_chip *imx = to_imx_chip(chip);
+ writel(cr, imx->mmio_base + MX3_PWMCR);
+ } else if (cstate.enabled) {
+ writel(0, imx->mmio_base + MX3_PWMCR);
- imx->set_enable(chip, false);
+ clk_disable_unprepare(imx->clk_per);
+ }
- clk_disable_unprepare(imx->clk_per);
+ return 0;
}
-static struct pwm_ops imx_pwm_ops = {
- .enable = imx_pwm_enable,
- .disable = imx_pwm_disable,
- .config = imx_pwm_config,
+static const struct pwm_ops imx_pwm_ops_v1 = {
+ .enable = imx_pwm_enable_v1,
+ .disable = imx_pwm_disable_v1,
+ .config = imx_pwm_config_v1,
+ .owner = THIS_MODULE,
+};
+
+static const struct pwm_ops imx_pwm_ops_v2 = {
+ .apply = imx_pwm_apply_v2,
.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);
+ bool polarity_supported;
+ 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,
+ .polarity_supported = true,
+ .ops = &imx_pwm_ops_v2,
};
static const struct of_device_id imx_pwm_dt_ids[] = {
@@ -282,6 +272,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;
@@ -293,28 +285,22 @@ 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.ops = data->ops;
imx->chip.dev = &pdev->dev;
imx->chip.base = -1;
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))
return PTR_ERR(imx->mmio_base);
- data = of_id->data;
- imx->config = data->config;
- imx->set_enable = data->set_enable;
-
ret = pwmchip_add(&imx->chip);
if (ret < 0)
return ret;
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 872ea76a4f19..52584e9962ed 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -278,7 +278,6 @@ 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-pci.c b/drivers/pwm/pwm-lpss-pci.c
index 3622f093490e..053088b9b66e 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -17,6 +17,27 @@
#include "pwm-lpss.h"
+/* BayTrail */
+static const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
+ .clk_rate = 25000000,
+ .npwm = 1,
+ .base_unit_bits = 16,
+};
+
+/* Braswell */
+static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
+ .clk_rate = 19200000,
+ .npwm = 1,
+ .base_unit_bits = 16,
+};
+
+/* Broxton */
+static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
+ .clk_rate = 19200000,
+ .npwm = 4,
+ .base_unit_bits = 22,
+};
+
static int pwm_lpss_probe_pci(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -80,6 +101,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
+ { PCI_VDEVICE(INTEL, 0x31c8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info},
{ },
};
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 54433fc6d1a4..b22b6fdadb9a 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -18,6 +18,27 @@
#include "pwm-lpss.h"
+/* BayTrail */
+static const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
+ .clk_rate = 25000000,
+ .npwm = 1,
+ .base_unit_bits = 16,
+};
+
+/* Braswell */
+static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
+ .clk_rate = 19200000,
+ .npwm = 1,
+ .base_unit_bits = 16,
+};
+
+/* Broxton */
+static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
+ .clk_rate = 19200000,
+ .npwm = 4,
+ .base_unit_bits = 22,
+};
+
static int pwm_lpss_probe_platform(struct platform_device *pdev)
{
const struct pwm_lpss_boardinfo *info;
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 72c0bce5a75c..689d2c1cbead 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@@ -37,30 +38,6 @@ struct pwm_lpss_chip {
const struct pwm_lpss_boardinfo *info;
};
-/* BayTrail */
-const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
- .clk_rate = 25000000,
- .npwm = 1,
- .base_unit_bits = 16,
-};
-EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
-
-/* Braswell */
-const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
- .clk_rate = 19200000,
- .npwm = 1,
- .base_unit_bits = 16,
-};
-EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
-
-/* Broxton */
-const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
- .clk_rate = 19200000,
- .npwm = 4,
- .base_unit_bits = 22,
-};
-EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
-
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
{
return container_of(chip, struct pwm_lpss_chip, chip);
@@ -80,17 +57,42 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
}
-static void pwm_lpss_update(struct pwm_device *pwm)
+static int pwm_lpss_update(struct pwm_device *pwm)
{
+ struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
+ const void __iomem *addr = lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM;
+ const unsigned int ms = 500 * USEC_PER_MSEC;
+ u32 val;
+ int err;
+
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
- /* Give it some time to propagate */
- usleep_range(10, 50);
+
+ /*
+ * PWM Configuration register has SW_UPDATE bit that is set when a new
+ * configuration is written to the register. The bit is automatically
+ * cleared at the start of the next output cycle by the IP block.
+ *
+ * If one writes a new configuration to the register while it still has
+ * the bit enabled, PWM may freeze. That is, while one can still write
+ * to the register, it won't have an effect. Thus, we try to sleep long
+ * enough that the bit gets cleared and make sure the bit is not
+ * enabled while we update the configuration.
+ */
+ err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms);
+ if (err)
+ dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n");
+
+ return err;
}
-static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
+{
+ return (pwm_lpss_read(pwm) & PWM_SW_UPDATE) ? -EBUSY : 0;
+}
+
+static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
{
- struct pwm_lpss_chip *lpwm = to_lpwm(chip);
unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC;
@@ -102,62 +104,62 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
* The equation is:
* base_unit = round(base_unit_range * freq / c)
*/
- base_unit_range = BIT(lpwm->info->base_unit_bits);
+ base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
freq *= base_unit_range;
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
- if (duty_ns <= 0)
- duty_ns = 1;
on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns);
on_time_div = 255ULL - on_time_div;
- pm_runtime_get_sync(chip->dev);
-
ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
- ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
- base_unit &= (base_unit_range - 1);
+ ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
+ base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
pwm_lpss_write(pwm, ctrl);
-
- /*
- * If the PWM is already enabled we need to notify the hardware
- * about the change by setting PWM_SW_UPDATE.
- */
- if (pwm_is_enabled(pwm))
- pwm_lpss_update(pwm);
-
- pm_runtime_put(chip->dev);
-
- return 0;
}
-static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
{
- pm_runtime_get_sync(chip->dev);
+ struct pwm_lpss_chip *lpwm = to_lpwm(chip);
+ int ret;
- /*
- * Hardware must first see PWM_SW_UPDATE before the PWM can be
- * enabled.
- */
- pwm_lpss_update(pwm);
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
- return 0;
-}
+ if (state->enabled) {
+ if (!pwm_is_enabled(pwm)) {
+ pm_runtime_get_sync(chip->dev);
+ ret = pwm_lpss_is_updating(pwm);
+ if (ret) {
+ pm_runtime_put(chip->dev);
+ return ret;
+ }
+ pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
+ ret = pwm_lpss_update(pwm);
+ if (ret) {
+ pm_runtime_put(chip->dev);
+ return ret;
+ }
+ pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
+ } else {
+ ret = pwm_lpss_is_updating(pwm);
+ if (ret)
+ return ret;
+ pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
+ return pwm_lpss_update(pwm);
+ }
+ } else if (pwm_is_enabled(pwm)) {
+ pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
+ pm_runtime_put(chip->dev);
+ }
-static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
- pm_runtime_put(chip->dev);
+ return 0;
}
static const struct pwm_ops pwm_lpss_ops = {
- .config = pwm_lpss_config,
- .enable = pwm_lpss_enable,
- .disable = pwm_lpss_disable,
+ .apply = pwm_lpss_apply,
.owner = THIS_MODULE,
};
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index 04766e0d41aa..c94cd7c2695d 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -24,10 +24,6 @@ struct pwm_lpss_boardinfo {
unsigned long base_unit_bits;
};
-extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;
-extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info;
-extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info;
-
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 9d5bd7d5c610..045ef9fa6fe3 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -524,7 +524,6 @@ static struct platform_driver meson_pwm_driver = {
};
module_platform_driver(meson_pwm_driver);
-MODULE_ALIAS("platform:meson-pwm");
MODULE_DESCRIPTION("Amlogic Meson PWM Generator driver");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 9a596324ebef..a6017ad9926c 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -151,7 +151,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-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 117fccf7934a..0cfb3571a732 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -20,8 +20,10 @@
*/
#include <linux/acpi.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
@@ -65,7 +67,6 @@
#define PCA9685_MAXCHAN 0x10
#define LED_FULL (1 << 4)
-#define MODE1_RESTART (1 << 7)
#define MODE1_SLEEP (1 << 4)
#define MODE2_INVRT (1 << 4)
#define MODE2_OUTDRV (1 << 2)
@@ -81,6 +82,10 @@ struct pca9685 {
int active_cnt;
int duty_ns;
int period_ns;
+#if IS_ENABLED(CONFIG_GPIOLIB)
+ struct mutex lock;
+ struct gpio_chip gpio;
+#endif
};
static inline struct pca9685 *to_pca(struct pwm_chip *chip)
@@ -88,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
}
+#if IS_ENABLED(CONFIG_GPIOLIB)
+static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+{
+ struct pca9685 *pca = gpiochip_get_data(gpio);
+ struct pwm_device *pwm;
+
+ mutex_lock(&pca->lock);
+
+ pwm = &pca->chip.pwms[offset];
+
+ if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
+ mutex_unlock(&pca->lock);
+ return -EBUSY;
+ }
+
+ pwm_set_chip_data(pwm, (void *)1);
+
+ mutex_unlock(&pca->lock);
+ return 0;
+}
+
+static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
+{
+ struct pca9685 *pca = gpiochip_get_data(gpio);
+ struct pwm_device *pwm;
+
+ mutex_lock(&pca->lock);
+ pwm = &pca->chip.pwms[offset];
+ pwm_set_chip_data(pwm, NULL);
+ mutex_unlock(&pca->lock);
+}
+
+static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
+{
+ bool is_gpio = false;
+
+ mutex_lock(&pca->lock);
+
+ if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+ unsigned int i;
+
+ /*
+ * Check if any of the GPIOs are requested and in that case
+ * prevent using the "all LEDs" channel.
+ */
+ for (i = 0; i < pca->gpio.ngpio; i++)
+ if (gpiochip_is_requested(&pca->gpio, i)) {
+ is_gpio = true;
+ break;
+ }
+ } else if (pwm_get_chip_data(pwm)) {
+ is_gpio = true;
+ }
+
+ mutex_unlock(&pca->lock);
+ return is_gpio;
+}
+
+static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
+{
+ struct pca9685 *pca = gpiochip_get_data(gpio);
+ struct pwm_device *pwm = &pca->chip.pwms[offset];
+ unsigned int value;
+
+ regmap_read(pca->regmap, LED_N_ON_H(pwm->hwpwm), &value);
+
+ return value & LED_FULL;
+}
+
+static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
+ int value)
+{
+ struct pca9685 *pca = gpiochip_get_data(gpio);
+ struct pwm_device *pwm = &pca->chip.pwms[offset];
+ unsigned int on = value ? LED_FULL : 0;
+
+ /* Clear both OFF registers */
+ regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm), 0);
+ regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm), 0);
+
+ /* Set the full ON bit */
+ regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on);
+}
+
+static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ /* Always out */
+ return 0;
+}
+
+static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio,
+ unsigned int offset)
+{
+ return -EINVAL;
+}
+
+static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
+ unsigned int offset, int value)
+{
+ pca9685_pwm_gpio_set(gpio, offset, value);
+
+ return 0;
+}
+
+/*
+ * The PCA9685 has a bit for turning the PWM output full off or on. Some
+ * boards like Intel Galileo actually uses these as normal GPIOs so we
+ * expose a GPIO chip here which can exclusively take over the underlying
+ * PWM channel.
+ */
+static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
+{
+ struct device *dev = pca->chip.dev;
+
+ mutex_init(&pca->lock);
+
+ pca->gpio.label = dev_name(dev);
+ pca->gpio.parent = dev;
+ pca->gpio.request = pca9685_pwm_gpio_request;
+ pca->gpio.free = pca9685_pwm_gpio_free;
+ pca->gpio.get_direction = pca9685_pwm_gpio_get_direction;
+ pca->gpio.direction_input = pca9685_pwm_gpio_direction_input;
+ pca->gpio.direction_output = pca9685_pwm_gpio_direction_output;
+ pca->gpio.get = pca9685_pwm_gpio_get;
+ pca->gpio.set = pca9685_pwm_gpio_set;
+ pca->gpio.base = -1;
+ pca->gpio.ngpio = PCA9685_MAXCHAN;
+ pca->gpio.can_sleep = true;
+
+ return devm_gpiochip_add_data(dev, &pca->gpio, pca);
+}
+#else
+static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
+ struct pwm_device *pwm)
+{
+ return false;
+}
+
+static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
+{
+ return 0;
+}
+#endif
+
static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
@@ -117,16 +267,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
udelay(500);
pca->period_ns = period_ns;
-
- /*
- * If the duty cycle did not change, restart PWM with
- * the same duty cycle to period ratio and return.
- */
- if (duty_ns == pca->duty_ns) {
- regmap_update_bits(pca->regmap, PCA9685_MODE1,
- MODE1_RESTART, 0x1);
- return 0;
- }
} else {
dev_err(chip->dev,
"prescaler not set: period out of bounds!\n");
@@ -264,6 +404,9 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct pca9685 *pca = to_pca(chip);
+ if (pca9685_pwm_is_gpio(pca, pwm))
+ return -EBUSY;
+
if (pca->active_cnt++ == 0)
return regmap_update_bits(pca->regmap, PCA9685_MODE1,
MODE1_SLEEP, 0x0);
@@ -343,9 +486,16 @@ static int pca9685_pwm_probe(struct i2c_client *client,
pca->chip.dev = &client->dev;
pca->chip.base = -1;
- pca->chip.can_sleep = true;
- return pwmchip_add(&pca->chip);
+ ret = pwmchip_add(&pca->chip);
+ if (ret < 0)
+ return ret;
+
+ ret = pca9685_pwm_gpio_probe(pca);
+ if (ret < 0)
+ pwmchip_remove(&pca->chip);
+
+ return ret;
}
static int pca9685_pwm_remove(struct i2c_client *client)
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-sti.c b/drivers/pwm/pwm-sti.c
index dd82dc840af9..2b7c31c9d1ab 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -635,7 +635,6 @@ skip_cpt:
pc->chip.ops = &sti_pwm_ops;
pc->chip.base = -1;
pc->chip.npwm = pc->cdata->pwm_num_devs;
- pc->chip.can_sleep = true;
ret = pwmchip_add(&pc->chip);
if (ret < 0) {
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 000000000000..6139512aab7b
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Gerald Baeza <gerald.baeza@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ * pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/mfd/stm32-timers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define CCMR_CHANNEL_SHIFT 8
+#define CCMR_CHANNEL_MASK 0xFF
+#define MAX_BREAKINPUT 2
+
+struct stm32_pwm {
+ struct pwm_chip chip;
+ struct device *dev;
+ struct clk *clk;
+ struct regmap *regmap;
+ u32 max_arr;
+ bool have_complementary_output;
+};
+
+struct stm32_breakinput {
+ u32 index;
+ u32 level;
+ u32 filter;
+};
+
+static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
+{
+ return container_of(chip, struct stm32_pwm, chip);
+}
+
+static u32 active_channels(struct stm32_pwm *dev)
+{
+ u32 ccer;
+
+ regmap_read(dev->regmap, TIM_CCER, &ccer);
+
+ return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
+{
+ switch (ch) {
+ case 0:
+ return regmap_write(dev->regmap, TIM_CCR1, value);
+ case 1:
+ return regmap_write(dev->regmap, TIM_CCR2, value);
+ case 2:
+ return regmap_write(dev->regmap, TIM_CCR3, value);
+ case 3:
+ return regmap_write(dev->regmap, TIM_CCR4, value);
+ }
+ return -EINVAL;
+}
+
+static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
+ int duty_ns, int period_ns)
+{
+ unsigned long long prd, div, dty;
+ unsigned int prescaler = 0;
+ u32 ccmr, mask, shift;
+
+ /* Period and prescaler values depends on clock rate */
+ div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
+
+ do_div(div, NSEC_PER_SEC);
+ prd = div;
+
+ while (div > priv->max_arr) {
+ prescaler++;
+ div = prd;
+ do_div(div, prescaler + 1);
+ }
+
+ prd = div;
+
+ if (prescaler > MAX_TIM_PSC)
+ return -EINVAL;
+
+ /*
+ * All channels share the same prescaler and counter so when two
+ * channels are active at the same time we can't change them
+ */
+ if (active_channels(priv) & ~(1 << ch * 4)) {
+ u32 psc, arr;
+
+ regmap_read(priv->regmap, TIM_PSC, &psc);
+ regmap_read(priv->regmap, TIM_ARR, &arr);
+
+ if ((psc != prescaler) || (arr != prd - 1))
+ return -EBUSY;
+ }
+
+ regmap_write(priv->regmap, TIM_PSC, prescaler);
+ regmap_write(priv->regmap, TIM_ARR, prd - 1);
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+ /* Calculate the duty cycles */
+ dty = prd * duty_ns;
+ do_div(dty, period_ns);
+
+ write_ccrx(priv, ch, dty);
+
+ /* Configure output mode */
+ shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
+ ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+ mask = CCMR_CHANNEL_MASK << shift;
+
+ if (ch < 2)
+ regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr);
+ else
+ regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
+
+ regmap_update_bits(priv->regmap, TIM_BDTR,
+ TIM_BDTR_MOE | TIM_BDTR_AOE,
+ TIM_BDTR_MOE | TIM_BDTR_AOE);
+
+ return 0;
+}
+
+static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
+ enum pwm_polarity polarity)
+{
+ u32 mask;
+
+ mask = TIM_CCER_CC1P << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NP << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask,
+ polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+ return 0;
+}
+
+static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
+{
+ u32 mask;
+ int ret;
+
+ ret = clk_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ /* Enable channel */
+ mask = TIM_CCER_CC1E << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NE << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask, mask);
+
+ /* Make sure that registers are updated */
+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+ /* Enable controller */
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+ return 0;
+}
+
+static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
+{
+ u32 mask;
+
+ /* Disable channel */
+ mask = TIM_CCER_CC1E << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NE << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask, 0);
+
+ /* When all channels are disabled, we can disable the controller */
+ if (!active_channels(priv))
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+ clk_disable(priv->clk);
+}
+
+static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ bool enabled;
+ struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
+ int ret;
+
+ enabled = pwm->state.enabled;
+
+ if (enabled && !state->enabled) {
+ stm32_pwm_disable(priv, pwm->hwpwm);
+ return 0;
+ }
+
+ if (state->polarity != pwm->state.polarity)
+ stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
+
+ ret = stm32_pwm_config(priv, pwm->hwpwm,
+ state->duty_cycle, state->period);
+ if (ret)
+ return ret;
+
+ if (!enabled && state->enabled)
+ ret = stm32_pwm_enable(priv, pwm->hwpwm);
+
+ return ret;
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+ .owner = THIS_MODULE,
+ .apply = stm32_pwm_apply,
+};
+
+static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
+ int index, int level, int filter)
+{
+ u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E;
+ int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT;
+ u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF
+ : TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F;
+ u32 bdtr = bke;
+
+ /*
+ * The both bits could be set since only one will be wrote
+ * due to mask value.
+ */
+ if (level)
+ bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P;
+
+ bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift;
+
+ regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr);
+
+ regmap_read(priv->regmap, TIM_BDTR, &bdtr);
+
+ return (bdtr & bke) ? 0 : -EINVAL;
+}
+
+static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
+ struct device_node *np)
+{
+ struct stm32_breakinput breakinput[MAX_BREAKINPUT];
+ int nb, ret, i, array_size;
+
+ nb = of_property_count_elems_of_size(np, "st,breakinput",
+ sizeof(struct stm32_breakinput));
+
+ /*
+ * Because "st,breakinput" parameter is optional do not make probe
+ * failed if it doesn't exist.
+ */
+ if (nb <= 0)
+ return 0;
+
+ if (nb > MAX_BREAKINPUT)
+ return -EINVAL;
+
+ array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32);
+ ret = of_property_read_u32_array(np, "st,breakinput",
+ (u32 *)breakinput, array_size);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nb && !ret; i++) {
+ ret = stm32_pwm_set_breakinput(priv,
+ breakinput[i].index,
+ breakinput[i].level,
+ breakinput[i].filter);
+ }
+
+ return ret;
+}
+
+static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
+{
+ u32 ccer;
+
+ /*
+ * If complementary bit doesn't exist writing 1 will have no
+ * effect so we can detect it.
+ */
+ regmap_update_bits(priv->regmap,
+ TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE);
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0);
+
+ priv->have_complementary_output = (ccer != 0);
+}
+
+static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
+{
+ u32 ccer;
+ int npwm = 0;
+
+ /*
+ * If channels enable bits don't exist writing 1 will have no
+ * effect so we can detect and count them.
+ */
+ regmap_update_bits(priv->regmap,
+ TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE);
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0);
+
+ if (ccer & TIM_CCER_CC1E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC2E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC3E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC4E)
+ npwm++;
+
+ return npwm;
+}
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
+ struct stm32_pwm *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = ddata->regmap;
+ priv->clk = ddata->clk;
+ priv->max_arr = ddata->max_arr;
+
+ if (!priv->regmap || !priv->clk)
+ return -EINVAL;
+
+ ret = stm32_pwm_apply_breakinputs(priv, np);
+ if (ret)
+ return ret;
+
+ stm32_pwm_detect_complementary(priv);
+
+ priv->chip.base = -1;
+ priv->chip.dev = dev;
+ priv->chip.ops = &stm32pwm_ops;
+ priv->chip.npwm = stm32_pwm_detect_channels(priv);
+
+ ret = pwmchip_add(&priv->chip);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+ struct stm32_pwm *priv = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < priv->chip.npwm; i++)
+ pwm_disable(&priv->chip.pwms[i]);
+
+ pwmchip_remove(&priv->chip);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+ { .compatible = "st,stm32-pwm", },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static struct platform_driver stm32_pwm_driver = {
+ .probe = stm32_pwm_probe,
+ .remove = stm32_pwm_remove,
+ .driver = {
+ .name = "stm32-pwm",
+ .of_match_table = stm32_pwm_of_match,
+ },
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:stm32-pwm");
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index b0803f6c64d9..1284ffa05921 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -340,7 +340,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
pwm->chip.ops = &sun4i_pwm_ops;
pwm->chip.base = -1;
pwm->chip.npwm = pwm->data->npwm;
- pwm->chip.can_sleep = true;
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
pwm->chip.of_pwm_n_cells = 3;
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index b964470025c5..21eff991d0e3 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -303,7 +303,6 @@ static int twl_pwmled_probe(struct platform_device *pdev)
twl->chip.dev = &pdev->dev;
twl->chip.base = -1;
- twl->chip.can_sleep = true;
mutex_init(&twl->mutex);
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index 7a993b056638..9de617b76680 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -323,7 +323,6 @@ static int twl_pwm_probe(struct platform_device *pdev)
twl->chip.dev = &pdev->dev;
twl->chip.base = -1;
twl->chip.npwm = 2;
- twl->chip.can_sleep = true;
mutex_init(&twl->mutex);
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,