brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 2510c10 Raw
550 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Freescale FlexTimer Module (FTM) PWM Driver4 *5 *  Copyright 2012-2013 Freescale Semiconductor, Inc.6 */7 8#include <linux/clk.h>9#include <linux/err.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/pm.h>17#include <linux/pwm.h>18#include <linux/regmap.h>19#include <linux/slab.h>20#include <linux/fsl/ftm.h>21 22#define FTM_SC_CLK(c)	(((c) + 1) << FTM_SC_CLK_MASK_SHIFT)23 24enum fsl_pwm_clk {25	FSL_PWM_CLK_SYS,26	FSL_PWM_CLK_FIX,27	FSL_PWM_CLK_EXT,28	FSL_PWM_CLK_CNTEN,29	FSL_PWM_CLK_MAX30};31 32struct fsl_ftm_soc {33	bool has_enable_bits;34};35 36struct fsl_pwm_periodcfg {37	enum fsl_pwm_clk clk_select;38	unsigned int clk_ps;39	unsigned int mod_period;40};41 42struct fsl_pwm_chip {43	struct mutex lock;44	struct regmap *regmap;45 46	/* This value is valid iff a pwm is running */47	struct fsl_pwm_periodcfg period;48 49	struct clk *ipg_clk;50	struct clk *clk[FSL_PWM_CLK_MAX];51 52	const struct fsl_ftm_soc *soc;53};54 55static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)56{57	return pwmchip_get_drvdata(chip);58}59 60static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)61{62	u32 val;63 64	regmap_read(fpc->regmap, FTM_FMS, &val);65	if (val & FTM_FMS_WPEN)66		regmap_set_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS);67}68 69static void ftm_set_write_protection(struct fsl_pwm_chip *fpc)70{71	regmap_set_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN);72}73 74static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a,75					const struct fsl_pwm_periodcfg *b)76{77	if (a->clk_select != b->clk_select)78		return false;79	if (a->clk_ps != b->clk_ps)80		return false;81	if (a->mod_period != b->mod_period)82		return false;83	return true;84}85 86static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)87{88	int ret;89	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);90 91	ret = clk_prepare_enable(fpc->ipg_clk);92	if (!ret && fpc->soc->has_enable_bits) {93		mutex_lock(&fpc->lock);94		regmap_set_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16));95		mutex_unlock(&fpc->lock);96	}97 98	return ret;99}100 101static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)102{103	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);104 105	if (fpc->soc->has_enable_bits) {106		mutex_lock(&fpc->lock);107		regmap_clear_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16));108		mutex_unlock(&fpc->lock);109	}110 111	clk_disable_unprepare(fpc->ipg_clk);112}113 114static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc,115					  unsigned int ticks)116{117	unsigned long rate;118	unsigned long long exval;119 120	rate = clk_get_rate(fpc->clk[fpc->period.clk_select]);121	exval = ticks;122	exval *= 1000000000UL;123	do_div(exval, rate >> fpc->period.clk_ps);124	return exval;125}126 127static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip *fpc,128					 unsigned int period_ns,129					 enum fsl_pwm_clk index,130					 struct fsl_pwm_periodcfg *periodcfg131					 )132{133	unsigned long long c;134	unsigned int ps;135 136	c = clk_get_rate(fpc->clk[index]);137	c = c * period_ns;138	do_div(c, 1000000000UL);139 140	if (c == 0)141		return false;142 143	for (ps = 0; ps < 8 ; ++ps, c >>= 1) {144		if (c <= 0x10000) {145			periodcfg->clk_select = index;146			periodcfg->clk_ps = ps;147			periodcfg->mod_period = c - 1;148			return true;149		}150	}151	return false;152}153 154static bool fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,155				     unsigned int period_ns,156				     struct fsl_pwm_periodcfg *periodcfg)157{158	enum fsl_pwm_clk m0, m1;159	unsigned long fix_rate, ext_rate;160	bool ret;161 162	ret = fsl_pwm_calculate_period_clk(fpc, period_ns, FSL_PWM_CLK_SYS,163					   periodcfg);164	if (ret)165		return true;166 167	fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);168	ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);169 170	if (fix_rate > ext_rate) {171		m0 = FSL_PWM_CLK_FIX;172		m1 = FSL_PWM_CLK_EXT;173	} else {174		m0 = FSL_PWM_CLK_EXT;175		m1 = FSL_PWM_CLK_FIX;176	}177 178	ret = fsl_pwm_calculate_period_clk(fpc, period_ns, m0, periodcfg);179	if (ret)180		return true;181 182	return fsl_pwm_calculate_period_clk(fpc, period_ns, m1, periodcfg);183}184 185static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,186					   unsigned int duty_ns)187{188	unsigned long long duty;189 190	unsigned int period = fpc->period.mod_period + 1;191	unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period);192 193	duty = (unsigned long long)duty_ns * period;194	do_div(duty, period_ns);195 196	return (unsigned int)duty;197}198 199static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip *fpc,200				       struct pwm_device *pwm)201{202	u32 val;203 204	regmap_read(fpc->regmap, FTM_OUTMASK, &val);205	if (~val & 0xFF)206		return true;207	else208		return false;209}210 211static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,212					 struct pwm_device *pwm)213{214	u32 val;215 216	regmap_read(fpc->regmap, FTM_OUTMASK, &val);217	if (~(val | BIT(pwm->hwpwm)) & 0xFF)218		return true;219	else220		return false;221}222 223static int fsl_pwm_apply_config(struct pwm_chip *chip,224				struct pwm_device *pwm,225				const struct pwm_state *newstate)226{227	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);228	unsigned int duty;229	u32 reg_polarity;230 231	struct fsl_pwm_periodcfg periodcfg;232	bool do_write_period = false;233 234	if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {235		dev_err(pwmchip_parent(chip), "failed to calculate new period\n");236		return -EINVAL;237	}238 239	if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm))240		do_write_period = true;241	/*242	 * The Freescale FTM controller supports only a single period for243	 * all PWM channels, therefore verify if the newly computed period244	 * is different than the current period being used. In such case245	 * we allow to change the period only if no other pwm is running.246	 */247	else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {248		if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {249			dev_err(pwmchip_parent(chip),250				"Cannot change period for PWM %u, disable other PWMs first\n",251				pwm->hwpwm);252			return -EBUSY;253		}254		if (fpc->period.clk_select != periodcfg.clk_select) {255			int ret;256			enum fsl_pwm_clk oldclk = fpc->period.clk_select;257			enum fsl_pwm_clk newclk = periodcfg.clk_select;258 259			ret = clk_prepare_enable(fpc->clk[newclk]);260			if (ret)261				return ret;262			clk_disable_unprepare(fpc->clk[oldclk]);263		}264		do_write_period = true;265	}266 267	ftm_clear_write_protection(fpc);268 269	if (do_write_period) {270		regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,271				   FTM_SC_CLK(periodcfg.clk_select));272		regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK,273				   periodcfg.clk_ps);274		regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period);275 276		fpc->period = periodcfg;277	}278 279	duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle);280 281	regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm),282		     FTM_CSC_MSB | FTM_CSC_ELSB);283	regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty);284 285	reg_polarity = 0;286	if (newstate->polarity == PWM_POLARITY_INVERSED)287		reg_polarity = BIT(pwm->hwpwm);288 289	regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity);290 291	ftm_set_write_protection(fpc);292 293	return 0;294}295 296static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,297			 const struct pwm_state *newstate)298{299	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);300	struct pwm_state *oldstate = &pwm->state;301	int ret = 0;302 303	/*304	 * oldstate to newstate : action305	 *306	 * disabled to disabled : ignore307	 * enabled to disabled : disable308	 * enabled to enabled : update settings309	 * disabled to enabled : update settings + enable310	 */311 312	mutex_lock(&fpc->lock);313 314	if (!newstate->enabled) {315		if (oldstate->enabled) {316			regmap_set_bits(fpc->regmap, FTM_OUTMASK,317					BIT(pwm->hwpwm));318			clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);319			clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);320		}321 322		goto end_mutex;323	}324 325	ret = fsl_pwm_apply_config(chip, pwm, newstate);326	if (ret)327		goto end_mutex;328 329	/* check if need to enable */330	if (!oldstate->enabled) {331		ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]);332		if (ret)333			goto end_mutex;334 335		ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);336		if (ret) {337			clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);338			goto end_mutex;339		}340 341		regmap_clear_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm));342	}343 344end_mutex:345	mutex_unlock(&fpc->lock);346	return ret;347}348 349static const struct pwm_ops fsl_pwm_ops = {350	.request = fsl_pwm_request,351	.free = fsl_pwm_free,352	.apply = fsl_pwm_apply,353};354 355static int fsl_pwm_init(struct fsl_pwm_chip *fpc)356{357	int ret;358 359	ret = clk_prepare_enable(fpc->ipg_clk);360	if (ret)361		return ret;362 363	regmap_write(fpc->regmap, FTM_CNTIN, 0x00);364	regmap_write(fpc->regmap, FTM_OUTINIT, 0x00);365	regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF);366 367	clk_disable_unprepare(fpc->ipg_clk);368 369	return 0;370}371 372static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg)373{374	switch (reg) {375	case FTM_FMS:376	case FTM_MODE:377	case FTM_CNT:378		return true;379	}380	return false;381}382 383static const struct regmap_config fsl_pwm_regmap_config = {384	.reg_bits = 32,385	.reg_stride = 4,386	.val_bits = 32,387 388	.max_register = FTM_PWMLOAD,389	.volatile_reg = fsl_pwm_volatile_reg,390	.cache_type = REGCACHE_FLAT,391};392 393static int fsl_pwm_probe(struct platform_device *pdev)394{395	struct pwm_chip *chip;396	struct fsl_pwm_chip *fpc;397	void __iomem *base;398	int ret;399 400	chip = devm_pwmchip_alloc(&pdev->dev, 8, sizeof(*fpc));401	if (IS_ERR(chip))402		return PTR_ERR(chip);403	fpc = to_fsl_chip(chip);404 405	mutex_init(&fpc->lock);406 407	fpc->soc = of_device_get_match_data(&pdev->dev);408 409	base = devm_platform_ioremap_resource(pdev, 0);410	if (IS_ERR(base))411		return PTR_ERR(base);412 413	fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "ftm_sys", base,414						&fsl_pwm_regmap_config);415	if (IS_ERR(fpc->regmap)) {416		dev_err(&pdev->dev, "regmap init failed\n");417		return PTR_ERR(fpc->regmap);418	}419 420	fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");421	if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {422		dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");423		return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);424	}425 426	fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(&pdev->dev, "ftm_fix");427	if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))428		return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);429 430	fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(&pdev->dev, "ftm_ext");431	if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))432		return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);433 434	fpc->clk[FSL_PWM_CLK_CNTEN] =435				devm_clk_get(&pdev->dev, "ftm_cnt_clk_en");436	if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))437		return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);438 439	/*440	 * ipg_clk is the interface clock for the IP. If not provided, use the441	 * ftm_sys clock as the default.442	 */443	fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");444	if (IS_ERR(fpc->ipg_clk))445		fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];446 447	chip->ops = &fsl_pwm_ops;448 449	ret = devm_pwmchip_add(&pdev->dev, chip);450	if (ret < 0) {451		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);452		return ret;453	}454 455	platform_set_drvdata(pdev, chip);456 457	return fsl_pwm_init(fpc);458}459 460#ifdef CONFIG_PM_SLEEP461static int fsl_pwm_suspend(struct device *dev)462{463	struct pwm_chip *chip = dev_get_drvdata(dev);464	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);465	int i;466 467	regcache_cache_only(fpc->regmap, true);468	regcache_mark_dirty(fpc->regmap);469 470	for (i = 0; i < chip->npwm; i++) {471		struct pwm_device *pwm = &chip->pwms[i];472 473		if (!test_bit(PWMF_REQUESTED, &pwm->flags))474			continue;475 476		clk_disable_unprepare(fpc->ipg_clk);477 478		if (!pwm_is_enabled(pwm))479			continue;480 481		clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);482		clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);483	}484 485	return 0;486}487 488static int fsl_pwm_resume(struct device *dev)489{490	struct pwm_chip *chip = dev_get_drvdata(dev);491	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);492	int i;493 494	for (i = 0; i < chip->npwm; i++) {495		struct pwm_device *pwm = &chip->pwms[i];496 497		if (!test_bit(PWMF_REQUESTED, &pwm->flags))498			continue;499 500		clk_prepare_enable(fpc->ipg_clk);501 502		if (!pwm_is_enabled(pwm))503			continue;504 505		clk_prepare_enable(fpc->clk[fpc->period.clk_select]);506		clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);507	}508 509	/* restore all registers from cache */510	regcache_cache_only(fpc->regmap, false);511	regcache_sync(fpc->regmap);512 513	return 0;514}515#endif516 517static const struct dev_pm_ops fsl_pwm_pm_ops = {518	SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume)519};520 521static const struct fsl_ftm_soc vf610_ftm_pwm = {522	.has_enable_bits = false,523};524 525static const struct fsl_ftm_soc imx8qm_ftm_pwm = {526	.has_enable_bits = true,527};528 529static const struct of_device_id fsl_pwm_dt_ids[] = {530	{ .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm },531	{ .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm },532	{ /* sentinel */ }533};534MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);535 536static struct platform_driver fsl_pwm_driver = {537	.driver = {538		.name = "fsl-ftm-pwm",539		.of_match_table = fsl_pwm_dt_ids,540		.pm = &fsl_pwm_pm_ops,541	},542	.probe = fsl_pwm_probe,543};544module_platform_driver(fsl_pwm_driver);545 546MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");547MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");548MODULE_ALIAS("platform:fsl-ftm-pwm");549MODULE_LICENSE("GPL");550