diff options
Diffstat (limited to 'drivers/pwm/pwm-fsl-ftm.c')
-rw-r--r-- | drivers/pwm/pwm-fsl-ftm.c | 57 |
1 files changed, 50 insertions, 7 deletions
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 557b4ea16796..883378d055c6 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pwm.h> @@ -75,6 +76,10 @@ enum fsl_pwm_clk { FSL_PWM_CLK_MAX }; +struct fsl_ftm_soc { + bool has_enable_bits; +}; + struct fsl_pwm_chip { struct pwm_chip chip; @@ -87,7 +92,10 @@ struct fsl_pwm_chip { int period_ns; + struct clk *ipg_clk; struct clk *clk[FSL_PWM_CLK_MAX]; + + const struct fsl_ftm_soc *soc; }; static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) @@ -97,16 +105,32 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { + int ret; struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); + if (!ret && fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + BIT(pwm->hwpwm + 16)); + mutex_unlock(&fpc->lock); + } + + return ret; } static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + if (fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + 0); + mutex_unlock(&fpc->lock); + } + + clk_disable_unprepare(fpc->ipg_clk); } static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc, @@ -363,7 +387,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) { int ret; - ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); if (ret) return ret; @@ -371,7 +395,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); return 0; } @@ -408,6 +432,7 @@ static int fsl_pwm_probe(struct platform_device *pdev) mutex_init(&fpc->lock); + fpc->soc = of_device_get_match_data(&pdev->dev); fpc->chip.dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -441,6 +466,15 @@ static int fsl_pwm_probe(struct platform_device *pdev) if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN])) return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]); + /* + * ipg_clk is the interface clock for the IP. If not provided, use the + * ftm_sys clock as the default. + */ + fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fpc->ipg_clk)) + fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS]; + + fpc->chip.ops = &fsl_pwm_ops; fpc->chip.of_xlate = of_pwm_xlate_with_flags; fpc->chip.of_pwm_n_cells = 3; @@ -480,7 +514,7 @@ static int fsl_pwm_suspend(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -503,7 +537,7 @@ static int fsl_pwm_resume(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + clk_prepare_enable(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -524,8 +558,17 @@ static const struct dev_pm_ops fsl_pwm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume) }; +static const struct fsl_ftm_soc vf610_ftm_pwm = { + .has_enable_bits = false, +}; + +static const struct fsl_ftm_soc imx8qm_ftm_pwm = { + .has_enable_bits = true, +}; + static const struct of_device_id fsl_pwm_dt_ids[] = { - { .compatible = "fsl,vf610-ftm-pwm", }, + { .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm }, + { .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids); |