Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/counter/stm32-lptimer-cnt.c
26278 views
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 <[email protected]>
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
22
struct 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
32
static 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
44
static 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
92
disable_clk:
93
clk_disable(priv->clk);
94
disable_cnt:
95
regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
96
97
return ret;
98
}
99
100
static 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
*/
134
static const enum counter_function stm32_lptim_cnt_functions[] = {
135
COUNTER_FUNCTION_INCREASE,
136
COUNTER_FUNCTION_QUADRATURE_X4,
137
};
138
139
static 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
146
static 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
162
static 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
181
static 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
204
static 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
220
static 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
245
static 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
256
static 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
273
static 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
280
static 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
324
static 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
360
static 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
368
static 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
379
static 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 */
393
static 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) */
405
static 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
416
static 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
460
static 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
482
static 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
506
static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
507
stm32_lptim_cnt_resume);
508
509
static const struct of_device_id stm32_lptim_cnt_of_match[] = {
510
{ .compatible = "st,stm32-lptimer-counter", },
511
{},
512
};
513
MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match);
514
515
static 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
};
523
module_platform_driver(stm32_lptim_cnt_driver);
524
525
MODULE_AUTHOR("Fabrice Gasnier <[email protected]>");
526
MODULE_ALIAS("platform:stm32-lptimer-counter");
527
MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");
528
MODULE_LICENSE("GPL v2");
529
MODULE_IMPORT_NS("COUNTER");
530
531