File Index
Files and directories
Sign in
FILE

stm32-lptimer-cnt.c

File preview with syntax highlighting.

linux-6.19.14/drivers/counter/stm32-lptimer-cnt.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * STM32 Low-Power Timer Encoder and Counter driver
  4 *
  5 * Copyright (C) STMicroelectronics 2017
  6 *
  7 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
  8 *
  9 * Inspired by 104-quad-8 and stm32-timer-trigger drivers.
 10 *
 11 */
 12
 13#include <linux/bitfield.h>
 14#include <linux/counter.h>
 15#include <linux/mfd/stm32-lptimer.h>
 16#include <linux/mod_devicetable.h>
 17#include <linux/module.h>
 18#include <linux/pinctrl/consumer.h>
 19#include <linux/platform_device.h>
 20#include <linux/types.h>
 21
 22struct stm32_lptim_cnt {
 23	struct device *dev;
 24	struct regmap *regmap;
 25	struct clk *clk;
 26	u32 ceiling;
 27	u32 polarity;
 28	u32 quadrature_mode;
 29	bool enabled;
 30};
 31
 32static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
 33{
 34	u32 val;
 35	int ret;
 36
 37	ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val);
 38	if (ret)
 39		return ret;
 40
 41	return FIELD_GET(STM32_LPTIM_ENABLE, val);
 42}
 43
 44static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
 45					int enable)
 46{
 47	int ret;
 48	u32 val;
 49
 50	val = FIELD_PREP(STM32_LPTIM_ENABLE, enable);
 51	ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val);
 52	if (ret)
 53		return ret;
 54
 55	if (!enable) {
 56		clk_disable(priv->clk);
 57		priv->enabled = false;
 58		return 0;
 59	}
 60
 61	ret = clk_enable(priv->clk);
 62	if (ret)
 63		goto disable_cnt;
 64
 65	/* LP timer must be enabled before writing CMP & ARR */
 66	ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->ceiling);
 67	if (ret)
 68		goto disable_clk;
 69
 70	ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0);
 71	if (ret)
 72		goto disable_clk;
 73
 74	/* ensure CMP & ARR registers are properly written */
 75	ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,
 76				       (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
 77				       100, 1000);
 78	if (ret)
 79		goto disable_clk;
 80
 81	ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,
 82			   STM32_LPTIM_CMPOKCF_ARROKCF);
 83	if (ret)
 84		goto disable_clk;
 85
 86	priv->enabled = true;
 87
 88	/* Start LP timer in continuous mode */
 89	return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
 90				  STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT);
 91
 92disable_clk:
 93	clk_disable(priv->clk);
 94disable_cnt:
 95	regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
 96
 97	return ret;
 98}
 99
100static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)
101{
102	u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE |
103		   STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC;
104	u32 val;
105
106	/* Setup LP timer encoder/counter and polarity, without prescaler */
107	if (priv->quadrature_mode)
108		val = enable ? STM32_LPTIM_ENC : 0;
109	else
110		val = enable ? STM32_LPTIM_COUNTMODE : 0;
111	val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0);
112
113	return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val);
114}
115
116/*
117 * In non-quadrature mode, device counts up on active edge.
118 * In quadrature mode, encoder counting scenarios are as follows:
119 * +---------+----------+--------------------+--------------------+
120 * | Active  | Level on |      IN1 signal    |     IN2 signal     |
121 * | edge    | opposite +----------+---------+----------+---------+
122 * |         | signal   |  Rising  | Falling |  Rising  | Falling |
123 * +---------+----------+----------+---------+----------+---------+
124 * | Rising  | High ->  |   Down   |    -    |   Up     |    -    |
125 * | edge    | Low  ->  |   Up     |    -    |   Down   |    -    |
126 * +---------+----------+----------+---------+----------+---------+
127 * | Falling | High ->  |    -     |   Up    |    -     |   Down  |
128 * | edge    | Low  ->  |    -     |   Down  |    -     |   Up    |
129 * +---------+----------+----------+---------+----------+---------+
130 * | Both    | High ->  |   Down   |   Up    |   Up     |   Down  |
131 * | edges   | Low  ->  |   Up     |   Down  |   Down   |   Up    |
132 * +---------+----------+----------+---------+----------+---------+
133 */
134static const enum counter_function stm32_lptim_cnt_functions[] = {
135	COUNTER_FUNCTION_INCREASE,
136	COUNTER_FUNCTION_QUADRATURE_X4,
137};
138
139static const enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
140	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
141	COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
142	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
143	COUNTER_SYNAPSE_ACTION_NONE,
144};
145
146static int stm32_lptim_cnt_read(struct counter_device *counter,
147				struct counter_count *count, u64 *val)
148{
149	struct stm32_lptim_cnt *const priv = counter_priv(counter);
150	u32 cnt;
151	int ret;
152
153	ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &cnt);
154	if (ret)
155		return ret;
156
157	*val = cnt;
158
159	return 0;
160}
161
162static int stm32_lptim_cnt_function_read(struct counter_device *counter,
163					 struct counter_count *count,
164					 enum counter_function *function)
165{
166	struct stm32_lptim_cnt *const priv = counter_priv(counter);
167
168	if (!priv->quadrature_mode) {
169		*function = COUNTER_FUNCTION_INCREASE;
170		return 0;
171	}
172
173	if (priv->polarity == STM32_LPTIM_CKPOL_BOTH_EDGES) {
174		*function = COUNTER_FUNCTION_QUADRATURE_X4;
175		return 0;
176	}
177
178	return -EINVAL;
179}
180
181static int stm32_lptim_cnt_function_write(struct counter_device *counter,
182					  struct counter_count *count,
183					  enum counter_function function)
184{
185	struct stm32_lptim_cnt *const priv = counter_priv(counter);
186
187	if (stm32_lptim_is_enabled(priv))
188		return -EBUSY;
189
190	switch (function) {
191	case COUNTER_FUNCTION_INCREASE:
192		priv->quadrature_mode = 0;
193		return 0;
194	case COUNTER_FUNCTION_QUADRATURE_X4:
195		priv->quadrature_mode = 1;
196		priv->polarity = STM32_LPTIM_CKPOL_BOTH_EDGES;
197		return 0;
198	default:
199		/* should never reach this path */
200		return -EINVAL;
201	}
202}
203
204static int stm32_lptim_cnt_enable_read(struct counter_device *counter,
205				       struct counter_count *count,
206				       u8 *enable)
207{
208	struct stm32_lptim_cnt *const priv = counter_priv(counter);
209	int ret;
210
211	ret = stm32_lptim_is_enabled(priv);
212	if (ret < 0)
213		return ret;
214
215	*enable = ret;
216
217	return 0;
218}
219
220static int stm32_lptim_cnt_enable_write(struct counter_device *counter,
221					struct counter_count *count,
222					u8 enable)
223{
224	struct stm32_lptim_cnt *const priv = counter_priv(counter);
225	int ret;
226
227	/* Check nobody uses the timer, or already disabled/enabled */
228	ret = stm32_lptim_is_enabled(priv);
229	if ((ret < 0) || (!ret && !enable))
230		return ret;
231	if (enable && ret)
232		return -EBUSY;
233
234	ret = stm32_lptim_setup(priv, enable);
235	if (ret)
236		return ret;
237
238	ret = stm32_lptim_set_enable_state(priv, enable);
239	if (ret)
240		return ret;
241
242	return 0;
243}
244
245static int stm32_lptim_cnt_ceiling_read(struct counter_device *counter,
246					struct counter_count *count,
247					u64 *ceiling)
248{
249	struct stm32_lptim_cnt *const priv = counter_priv(counter);
250
251	*ceiling = priv->ceiling;
252
253	return 0;
254}
255
256static int stm32_lptim_cnt_ceiling_write(struct counter_device *counter,
257					 struct counter_count *count,
258					 u64 ceiling)
259{
260	struct stm32_lptim_cnt *const priv = counter_priv(counter);
261
262	if (stm32_lptim_is_enabled(priv))
263		return -EBUSY;
264
265	if (ceiling > STM32_LPTIM_MAX_ARR)
266		return -ERANGE;
267
268	priv->ceiling = ceiling;
269
270	return 0;
271}
272
273static struct counter_comp stm32_lptim_cnt_ext[] = {
274	COUNTER_COMP_ENABLE(stm32_lptim_cnt_enable_read,
275			    stm32_lptim_cnt_enable_write),
276	COUNTER_COMP_CEILING(stm32_lptim_cnt_ceiling_read,
277			     stm32_lptim_cnt_ceiling_write),
278};
279
280static int stm32_lptim_cnt_action_read(struct counter_device *counter,
281				       struct counter_count *count,
282				       struct counter_synapse *synapse,
283				       enum counter_synapse_action *action)
284{
285	struct stm32_lptim_cnt *const priv = counter_priv(counter);
286	enum counter_function function;
287	int err;
288
289	err = stm32_lptim_cnt_function_read(counter, count, &function);
290	if (err)
291		return err;
292
293	switch (function) {
294	case COUNTER_FUNCTION_INCREASE:
295		/* LP Timer acts as up-counter on input 1 */
296		if (synapse->signal->id != count->synapses[0].signal->id) {
297			*action = COUNTER_SYNAPSE_ACTION_NONE;
298			return 0;
299		}
300
301		switch (priv->polarity) {
302		case STM32_LPTIM_CKPOL_RISING_EDGE:
303			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
304			return 0;
305		case STM32_LPTIM_CKPOL_FALLING_EDGE:
306			*action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
307			return 0;
308		case STM32_LPTIM_CKPOL_BOTH_EDGES:
309			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
310			return 0;
311		default:
312			/* should never reach this path */
313			return -EINVAL;
314		}
315	case COUNTER_FUNCTION_QUADRATURE_X4:
316		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
317		return 0;
318	default:
319		/* should never reach this path */
320		return -EINVAL;
321	}
322}
323
324static int stm32_lptim_cnt_action_write(struct counter_device *counter,
325					struct counter_count *count,
326					struct counter_synapse *synapse,
327					enum counter_synapse_action action)
328{
329	struct stm32_lptim_cnt *const priv = counter_priv(counter);
330	enum counter_function function;
331	int err;
332
333	if (stm32_lptim_is_enabled(priv))
334		return -EBUSY;
335
336	err = stm32_lptim_cnt_function_read(counter, count, &function);
337	if (err)
338		return err;
339
340	/* only set polarity when in counter mode (on input 1) */
341	if (function != COUNTER_FUNCTION_INCREASE
342	    || synapse->signal->id != count->synapses[0].signal->id)
343		return -EINVAL;
344
345	switch (action) {
346	case COUNTER_SYNAPSE_ACTION_RISING_EDGE:
347		priv->polarity = STM32_LPTIM_CKPOL_RISING_EDGE;
348		return 0;
349	case COUNTER_SYNAPSE_ACTION_FALLING_EDGE:
350		priv->polarity = STM32_LPTIM_CKPOL_FALLING_EDGE;
351		return 0;
352	case COUNTER_SYNAPSE_ACTION_BOTH_EDGES:
353		priv->polarity = STM32_LPTIM_CKPOL_BOTH_EDGES;
354		return 0;
355	default:
356		return -EINVAL;
357	}
358}
359
360static const struct counter_ops stm32_lptim_cnt_ops = {
361	.count_read = stm32_lptim_cnt_read,
362	.function_read = stm32_lptim_cnt_function_read,
363	.function_write = stm32_lptim_cnt_function_write,
364	.action_read = stm32_lptim_cnt_action_read,
365	.action_write = stm32_lptim_cnt_action_write,
366};
367
368static struct counter_signal stm32_lptim_cnt_signals[] = {
369	{
370		.id = 0,
371		.name = "Channel 1 Quadrature A"
372	},
373	{
374		.id = 1,
375		.name = "Channel 1 Quadrature B"
376	}
377};
378
379static struct counter_synapse stm32_lptim_cnt_synapses[] = {
380	{
381		.actions_list = stm32_lptim_cnt_synapse_actions,
382		.num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions),
383		.signal = &stm32_lptim_cnt_signals[0]
384	},
385	{
386		.actions_list = stm32_lptim_cnt_synapse_actions,
387		.num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions),
388		.signal = &stm32_lptim_cnt_signals[1]
389	}
390};
391
392/* LP timer with encoder */
393static struct counter_count stm32_lptim_enc_counts = {
394	.id = 0,
395	.name = "LPTimer Count",
396	.functions_list = stm32_lptim_cnt_functions,
397	.num_functions = ARRAY_SIZE(stm32_lptim_cnt_functions),
398	.synapses = stm32_lptim_cnt_synapses,
399	.num_synapses = ARRAY_SIZE(stm32_lptim_cnt_synapses),
400	.ext = stm32_lptim_cnt_ext,
401	.num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext)
402};
403
404/* LP timer without encoder (counter only) */
405static struct counter_count stm32_lptim_in1_counts = {
406	.id = 0,
407	.name = "LPTimer Count",
408	.functions_list = stm32_lptim_cnt_functions,
409	.num_functions = 1,
410	.synapses = stm32_lptim_cnt_synapses,
411	.num_synapses = 1,
412	.ext = stm32_lptim_cnt_ext,
413	.num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext)
414};
415
416static int stm32_lptim_cnt_probe(struct platform_device *pdev)
417{
418	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
419	struct counter_device *counter;
420	struct stm32_lptim_cnt *priv;
421	int ret;
422
423	if (IS_ERR_OR_NULL(ddata))
424		return -EINVAL;
425
426	counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
427	if (!counter)
428		return -ENOMEM;
429	priv = counter_priv(counter);
430
431	priv->dev = &pdev->dev;
432	priv->regmap = ddata->regmap;
433	priv->clk = ddata->clk;
434	priv->ceiling = STM32_LPTIM_MAX_ARR;
435
436	/* Initialize Counter device */
437	counter->name = dev_name(&pdev->dev);
438	counter->parent = &pdev->dev;
439	counter->ops = &stm32_lptim_cnt_ops;
440	if (ddata->has_encoder) {
441		counter->counts = &stm32_lptim_enc_counts;
442		counter->num_signals = ARRAY_SIZE(stm32_lptim_cnt_signals);
443	} else {
444		counter->counts = &stm32_lptim_in1_counts;
445		counter->num_signals = 1;
446	}
447	counter->num_counts = 1;
448	counter->signals = stm32_lptim_cnt_signals;
449
450	platform_set_drvdata(pdev, priv);
451
452	ret = devm_counter_add(&pdev->dev, counter);
453	if (ret < 0)
454		return dev_err_probe(&pdev->dev, ret, "Failed to add counter\n");
455
456	return 0;
457}
458
459#ifdef CONFIG_PM_SLEEP
460static int stm32_lptim_cnt_suspend(struct device *dev)
461{
462	struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
463	int ret;
464
465	/* Only take care of enabled counter: don't disturb other MFD child */
466	if (priv->enabled) {
467		ret = stm32_lptim_setup(priv, 0);
468		if (ret)
469			return ret;
470
471		ret = stm32_lptim_set_enable_state(priv, 0);
472		if (ret)
473			return ret;
474
475		/* Force enable state for later resume */
476		priv->enabled = true;
477	}
478
479	return pinctrl_pm_select_sleep_state(dev);
480}
481
482static int stm32_lptim_cnt_resume(struct device *dev)
483{
484	struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
485	int ret;
486
487	ret = pinctrl_pm_select_default_state(dev);
488	if (ret)
489		return ret;
490
491	if (priv->enabled) {
492		priv->enabled = false;
493		ret = stm32_lptim_setup(priv, 1);
494		if (ret)
495			return ret;
496
497		ret = stm32_lptim_set_enable_state(priv, 1);
498		if (ret)
499			return ret;
500	}
501
502	return 0;
503}
504#endif
505
506static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
507			 stm32_lptim_cnt_resume);
508
509static const struct of_device_id stm32_lptim_cnt_of_match[] = {
510	{ .compatible = "st,stm32-lptimer-counter", },
511	{},
512};
513MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match);
514
515static struct platform_driver stm32_lptim_cnt_driver = {
516	.probe = stm32_lptim_cnt_probe,
517	.driver = {
518		.name = "stm32-lptimer-counter",
519		.of_match_table = stm32_lptim_cnt_of_match,
520		.pm = &stm32_lptim_cnt_pm_ops,
521	},
522};
523module_platform_driver(stm32_lptim_cnt_driver);
524
525MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
526MODULE_ALIAS("platform:stm32-lptimer-counter");
527MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");
528MODULE_LICENSE("GPL v2");
529MODULE_IMPORT_NS("COUNTER");
~/ Read-only file preview.