summaryrefslogtreecommitdiff
path: root/drivers/pwm/pwm-fsl-ftm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-17 10:10:51 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-17 10:10:51 -0800
commit0b4954c46943e8f15b9379eed4f133c874a0bc66 (patch)
tree544ee140acdb104ba21a19452cc8eb231b05744f /drivers/pwm/pwm-fsl-ftm.c
parentd797da41b2aceed5daa8cd2eee92cd74b2a0c652 (diff)
parent39e046f2c1dd0742976d7ee6e464744cf2122f41 (diff)
Merge tag 'pwm/for-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding: "There are two new drivers, one for the BCM2835 (Raspberry Pi) and one used in conjunction with the LCD controller on various Atmel SoCs. The Samsung PWM driver can now be built for 64-bit ARM (Exynos7). A couple of fixes have been applied to the FTM PWM driver and system sleep support was added" * tag 'pwm/for-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: pwm: atmel-hlcdc: add at91sam9x5 and sama5d3 errata handling pwm: ftm: Add Power Management support for FTM PWM pwm: ftm: Add regmap rbtree type cache support pwm: ftm: Correctly track usage count pwm: samsung: Allow Samsung PWM driver to be enabled on Exynos7 pwm: add DT bindings documentation for atmel-hlcdc-pwm driver pwm: add support for atmel-hlcdc-pwm device pwm: Add BCM2835 PWM driver
Diffstat (limited to 'drivers/pwm/pwm-fsl-ftm.c')
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index 0f2cc7ef7784..f9dfc8b6407a 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -299,7 +300,7 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
{
int ret;
- if (fpc->use_count != 0)
+ if (fpc->use_count++ != 0)
return 0;
/* select counter clock source */
@@ -316,8 +317,6 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
return ret;
}
- fpc->use_count++;
-
return 0;
}
@@ -399,12 +398,23 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
return 0;
}
+static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FTM_CNT:
+ return true;
+ }
+ return false;
+}
+
static const struct regmap_config fsl_pwm_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = FTM_PWMLOAD,
+ .volatile_reg = fsl_pwm_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
};
static int fsl_pwm_probe(struct platform_device *pdev)
@@ -427,7 +437,7 @@ static int fsl_pwm_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
+ fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "ftm_sys", base,
&fsl_pwm_regmap_config);
if (IS_ERR(fpc->regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
@@ -478,6 +488,51 @@ static int fsl_pwm_remove(struct platform_device *pdev)
return pwmchip_remove(&fpc->chip);
}
+#ifdef CONFIG_PM_SLEEP
+static int fsl_pwm_suspend(struct device *dev)
+{
+ struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
+ u32 val;
+
+ regcache_cache_only(fpc->regmap, true);
+ regcache_mark_dirty(fpc->regmap);
+
+ /* read from cache */
+ regmap_read(fpc->regmap, FTM_OUTMASK, &val);
+ if ((val & 0xFF) != 0xFF) {
+ clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
+ clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
+ clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+ }
+
+ return 0;
+}
+
+static int fsl_pwm_resume(struct device *dev)
+{
+ struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
+ u32 val;
+
+ /* read from cache */
+ regmap_read(fpc->regmap, FTM_OUTMASK, &val);
+ if ((val & 0xFF) != 0xFF) {
+ clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+ clk_prepare_enable(fpc->clk[fpc->cnt_select]);
+ clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
+ }
+
+ /* restore all registers from cache */
+ regcache_cache_only(fpc->regmap, false);
+ regcache_sync(fpc->regmap);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops fsl_pwm_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume)
+};
+
static const struct of_device_id fsl_pwm_dt_ids[] = {
{ .compatible = "fsl,vf610-ftm-pwm", },
{ /* sentinel */ }
@@ -488,6 +543,7 @@ static struct platform_driver fsl_pwm_driver = {
.driver = {
.name = "fsl-ftm-pwm",
.of_match_table = fsl_pwm_dt_ids,
+ .pm = &fsl_pwm_pm_ops,
},
.probe = fsl_pwm_probe,
.remove = fsl_pwm_remove,