brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 9897312 Raw
262 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * STM32 Low-Power Timer PWM driver4 *5 * Copyright (C) STMicroelectronics 20176 *7 * Author: Gerald Baeza <gerald.baeza@st.com>8 *9 * Inspired by Gerald Baeza's pwm-stm32 driver10 */11 12#include <linux/bitfield.h>13#include <linux/mfd/stm32-lptimer.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/pinctrl/consumer.h>17#include <linux/platform_device.h>18#include <linux/pwm.h>19 20struct stm32_pwm_lp {21	struct clk *clk;22	struct regmap *regmap;23};24 25static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip)26{27	return pwmchip_get_drvdata(chip);28}29 30/* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */31#define STM32_LPTIM_MAX_PRESCALER	12832 33static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,34			      const struct pwm_state *state)35{36	struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip);37	unsigned long long prd, div, dty;38	struct pwm_state cstate;39	u32 val, mask, cfgr, presc = 0;40	bool reenable;41	int ret;42 43	pwm_get_state(pwm, &cstate);44	reenable = !cstate.enabled;45 46	if (!state->enabled) {47		if (cstate.enabled) {48			/* Disable LP timer */49			ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0);50			if (ret)51				return ret;52			/* disable clock to PWM counter */53			clk_disable(priv->clk);54		}55		return 0;56	}57 58	/* Calculate the period and prescaler value */59	div = (unsigned long long)clk_get_rate(priv->clk) * state->period;60	do_div(div, NSEC_PER_SEC);61	if (!div) {62		/* Clock is too slow to achieve requested period. */63		dev_dbg(pwmchip_parent(chip), "Can't reach %llu ns\n", state->period);64		return -EINVAL;65	}66 67	prd = div;68	while (div > STM32_LPTIM_MAX_ARR) {69		presc++;70		if ((1 << presc) > STM32_LPTIM_MAX_PRESCALER) {71			dev_err(pwmchip_parent(chip), "max prescaler exceeded\n");72			return -EINVAL;73		}74		div = prd >> presc;75	}76	prd = div;77 78	/* Calculate the duty cycle */79	dty = prd * state->duty_cycle;80	do_div(dty, state->period);81 82	if (!cstate.enabled) {83		/* enable clock to drive PWM counter */84		ret = clk_enable(priv->clk);85		if (ret)86			return ret;87	}88 89	ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr);90	if (ret)91		goto err;92 93	if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) ||94	    (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) {95		val = FIELD_PREP(STM32_LPTIM_PRESC, presc);96		val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity);97		mask = STM32_LPTIM_PRESC | STM32_LPTIM_WAVPOL;98 99		/* Must disable LP timer to modify CFGR */100		reenable = true;101		ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0);102		if (ret)103			goto err;104 105		ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask,106					 val);107		if (ret)108			goto err;109	}110 111	if (reenable) {112		/* Must (re)enable LP timer to modify CMP & ARR */113		ret = regmap_write(priv->regmap, STM32_LPTIM_CR,114				   STM32_LPTIM_ENABLE);115		if (ret)116			goto err;117	}118 119	ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, prd - 1);120	if (ret)121		goto err;122 123	ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, prd - (1 + dty));124	if (ret)125		goto err;126 127	/* ensure CMP & ARR registers are properly written */128	ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,129				       (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,130				       100, 1000);131	if (ret) {132		dev_err(pwmchip_parent(chip), "ARR/CMP registers write issue\n");133		goto err;134	}135	ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,136			   STM32_LPTIM_CMPOKCF_ARROKCF);137	if (ret)138		goto err;139 140	if (reenable) {141		/* Start LP timer in continuous mode */142		ret = regmap_set_bits(priv->regmap, STM32_LPTIM_CR,143				      STM32_LPTIM_CNTSTRT);144		if (ret) {145			regmap_write(priv->regmap, STM32_LPTIM_CR, 0);146			goto err;147		}148	}149 150	return 0;151err:152	if (!cstate.enabled)153		clk_disable(priv->clk);154 155	return ret;156}157 158static int stm32_pwm_lp_get_state(struct pwm_chip *chip,159				  struct pwm_device *pwm,160				  struct pwm_state *state)161{162	struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip);163	unsigned long rate = clk_get_rate(priv->clk);164	u32 val, presc, prd;165	u64 tmp;166 167	regmap_read(priv->regmap, STM32_LPTIM_CR, &val);168	state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val);169	/* Keep PWM counter clock refcount in sync with PWM initial state */170	if (state->enabled)171		clk_enable(priv->clk);172 173	regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val);174	presc = FIELD_GET(STM32_LPTIM_PRESC, val);175	state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val);176 177	regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd);178	tmp = prd + 1;179	tmp = (tmp << presc) * NSEC_PER_SEC;180	state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate);181 182	regmap_read(priv->regmap, STM32_LPTIM_CMP, &val);183	tmp = prd - val;184	tmp = (tmp << presc) * NSEC_PER_SEC;185	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate);186 187	return 0;188}189 190static const struct pwm_ops stm32_pwm_lp_ops = {191	.apply = stm32_pwm_lp_apply,192	.get_state = stm32_pwm_lp_get_state,193};194 195static int stm32_pwm_lp_probe(struct platform_device *pdev)196{197	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);198	struct stm32_pwm_lp *priv;199	struct pwm_chip *chip;200	int ret;201 202	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));203	if (IS_ERR(chip))204		return PTR_ERR(chip);205	priv = to_stm32_pwm_lp(chip);206 207	priv->regmap = ddata->regmap;208	priv->clk = ddata->clk;209	chip->ops = &stm32_pwm_lp_ops;210 211	ret = devm_pwmchip_add(&pdev->dev, chip);212	if (ret < 0)213		return ret;214 215	platform_set_drvdata(pdev, chip);216 217	return 0;218}219 220static int stm32_pwm_lp_suspend(struct device *dev)221{222	struct pwm_chip *chip = dev_get_drvdata(dev);223	struct pwm_state state;224 225	pwm_get_state(&chip->pwms[0], &state);226	if (state.enabled) {227		dev_err(dev, "The consumer didn't stop us (%s)\n",228			chip->pwms[0].label);229		return -EBUSY;230	}231 232	return pinctrl_pm_select_sleep_state(dev);233}234 235static int stm32_pwm_lp_resume(struct device *dev)236{237	return pinctrl_pm_select_default_state(dev);238}239 240static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,241				stm32_pwm_lp_resume);242 243static const struct of_device_id stm32_pwm_lp_of_match[] = {244	{ .compatible = "st,stm32-pwm-lp", },245	{},246};247MODULE_DEVICE_TABLE(of, stm32_pwm_lp_of_match);248 249static struct platform_driver stm32_pwm_lp_driver = {250	.probe	= stm32_pwm_lp_probe,251	.driver	= {252		.name = "stm32-pwm-lp",253		.of_match_table = stm32_pwm_lp_of_match,254		.pm = pm_ptr(&stm32_pwm_lp_pm_ops),255	},256};257module_platform_driver(stm32_pwm_lp_driver);258 259MODULE_ALIAS("platform:stm32-pwm-lp");260MODULE_DESCRIPTION("STMicroelectronics STM32 PWM LP driver");261MODULE_LICENSE("GPL v2");262