summaryrefslogtreecommitdiff
path: root/drivers/pwm/pwm-rcar.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-13 15:46:21 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-13 15:46:21 -0700
commitdaf3ef6e965d1d51d6ec604a8fc9919b75d5ec3c (patch)
tree643eeb6adc04a5e0a038d1a1dcbb2f6c8169c47e /drivers/pwm/pwm-rcar.c
parent41531f58a6513b86f8f379117eca82502022b4a9 (diff)
parent6873842235d678a245a378669f35e145df2441b9 (diff)
Merge tag 'pwm/for-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding: "This set of changes adds support for more generations of the RCar controller as well as runtime PM support. The JZ4740 driver gains support for device tree and can now be used on all Ingenic SoCs. Rounding things off is a random assortment of fixes and cleanups all across the board" * tag 'pwm/for-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (29 commits) pwm: rcar: Add suspend/resume support pwm: rcar: Use PM Runtime to control module clock dt-bindings: pwm: rcar: Add bindings for R-Car M3N support pwm: rcar: Fix a condition to prevent mismatch value setting to duty pwm: sysfs: Use put_device() instead of kfree() dt-bindings: pwm: sunxi: Add new compatible strings pwm: sun4i: Simplify controller mapping pwm: sun4i: Drop unused .has_rdy member pwm: sun4i: Properly check current state pwm: Remove depends on AVR32 pwm: stm32: LPTimer: Use 3 cells ->of_xlate() dt-bindings: pwm-stm32-lp: Add #pwm-cells pwm: stm32: Protect common prescaler for all channels pwm: stm32: Remove unused struct device pwm: mediatek: Improve precision in rate calculation pwm: mediatek: Remove redundant MODULE_ALIAS entries pwm: mediatek: Fix up PWM4 and PWM5 malfunction on MT7623 pwm: jz4740: Enable for all Ingenic SoCs pwm: jz4740: Add support for devicetree pwm: jz4740: Implement ->set_polarity() ...
Diffstat (limited to 'drivers/pwm/pwm-rcar.c')
-rw-r--r--drivers/pwm/pwm-rcar.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 1c85ecc9e7ac..91d11f2e2fef 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -134,16 +134,12 @@ static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
-
- return clk_prepare_enable(rp->clk);
+ return pm_runtime_get_sync(chip->dev);
}
static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
-
- clk_disable_unprepare(rp->clk);
+ pm_runtime_put(chip->dev);
}
static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -156,8 +152,12 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (div < 0)
return div;
- /* Let the core driver set pwm->period if disabled and duty_ns == 0 */
- if (!pwm_is_enabled(pwm) && !duty_ns)
+ /*
+ * Let the core driver set pwm->period if disabled and duty_ns == 0.
+ * But, this driver should prevent to set the new duty_ns if current
+ * duty_cycle is not set
+ */
+ if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
return 0;
rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
@@ -258,11 +258,53 @@ static const struct of_device_id rcar_pwm_of_table[] = {
};
MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
+#ifdef CONFIG_PM_SLEEP
+static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+ struct pwm_chip *chip = &rcar_pwm->chip;
+
+ return &chip->pwms[0];
+}
+
+static int rcar_pwm_suspend(struct device *dev)
+{
+ struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
+
+ if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+ return 0;
+
+ pm_runtime_put(dev);
+
+ return 0;
+}
+
+static int rcar_pwm_resume(struct device *dev)
+{
+ struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
+
+ if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+ return 0;
+
+ pm_runtime_get_sync(dev);
+
+ rcar_pwm_config(pwm->chip, pwm, pwm->state.duty_cycle,
+ pwm->state.period);
+ if (pwm_is_enabled(pwm))
+ rcar_pwm_enable(pwm->chip, pwm);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops, rcar_pwm_suspend, rcar_pwm_resume);
+
static struct platform_driver rcar_pwm_driver = {
.probe = rcar_pwm_probe,
.remove = rcar_pwm_remove,
.driver = {
.name = "pwm-rcar",
+ .pm = &rcar_pwm_pm_ops,
.of_match_table = of_match_ptr(rcar_pwm_of_table),
}
};