Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / counter / i8254.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel 8254 Programmable Interval Timer
4  * Copyright (C) William Breathitt Gray
5  */
6 #include <linux/bitfield.h>
7 #include <linux/bits.h>
8 #include <linux/counter.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/export.h>
12 #include <linux/i8254.h>
13 #include <linux/limits.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/regmap.h>
17
18 #include <asm/unaligned.h>
19
20 #define I8254_COUNTER_REG(_counter) (_counter)
21 #define I8254_CONTROL_REG 0x3
22
23 #define I8254_SC GENMASK(7, 6)
24 #define I8254_RW GENMASK(5, 4)
25 #define I8254_M GENMASK(3, 1)
26 #define I8254_CONTROL(_sc, _rw, _m) \
27         (u8_encode_bits(_sc, I8254_SC) | u8_encode_bits(_rw, I8254_RW) | \
28          u8_encode_bits(_m, I8254_M))
29
30 #define I8254_RW_TWO_BYTE 0x3
31 #define I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT 0
32 #define I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT 1
33 #define I8254_MODE_RATE_GENERATOR 2
34 #define I8254_MODE_SQUARE_WAVE_MODE 3
35 #define I8254_MODE_SOFTWARE_TRIGGERED_STROBE 4
36 #define I8254_MODE_HARDWARE_TRIGGERED_STROBE 5
37
38 #define I8254_COUNTER_LATCH(_counter) I8254_CONTROL(_counter, 0x0, 0x0)
39 #define I8254_PROGRAM_COUNTER(_counter, _mode) I8254_CONTROL(_counter, I8254_RW_TWO_BYTE, _mode)
40
41 #define I8254_NUM_COUNTERS 3
42
43 /**
44  * struct i8254 - I8254 device private data structure
45  * @lock:       synchronization lock to prevent I/O race conditions
46  * @preset:     array of Counter Register states
47  * @out_mode:   array of mode configuration states
48  * @map:        Regmap for the device
49  */
50 struct i8254 {
51         struct mutex lock;
52         u16 preset[I8254_NUM_COUNTERS];
53         u8 out_mode[I8254_NUM_COUNTERS];
54         struct regmap *map;
55 };
56
57 static int i8254_count_read(struct counter_device *const counter, struct counter_count *const count,
58                             u64 *const val)
59 {
60         struct i8254 *const priv = counter_priv(counter);
61         int ret;
62         u8 value[2];
63
64         mutex_lock(&priv->lock);
65
66         ret = regmap_write(priv->map, I8254_CONTROL_REG, I8254_COUNTER_LATCH(count->id));
67         if (ret) {
68                 mutex_unlock(&priv->lock);
69                 return ret;
70         }
71         ret = regmap_noinc_read(priv->map, I8254_COUNTER_REG(count->id), value, sizeof(value));
72         if (ret) {
73                 mutex_unlock(&priv->lock);
74                 return ret;
75         }
76
77         mutex_unlock(&priv->lock);
78
79         *val = get_unaligned_le16(value);
80
81         return ret;
82 }
83
84 static int i8254_function_read(struct counter_device *const counter,
85                                struct counter_count *const count,
86                                enum counter_function *const function)
87 {
88         *function = COUNTER_FUNCTION_DECREASE;
89         return 0;
90 }
91
92 #define I8254_SYNAPSES_PER_COUNT 2
93 #define I8254_SIGNAL_ID_CLK 0
94 #define I8254_SIGNAL_ID_GATE 1
95
96 static int i8254_action_read(struct counter_device *const counter,
97                              struct counter_count *const count,
98                              struct counter_synapse *const synapse,
99                              enum counter_synapse_action *const action)
100 {
101         struct i8254 *const priv = counter_priv(counter);
102
103         switch (synapse->signal->id % I8254_SYNAPSES_PER_COUNT) {
104         case I8254_SIGNAL_ID_CLK:
105                 *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
106                 return 0;
107         case I8254_SIGNAL_ID_GATE:
108                 switch (priv->out_mode[count->id]) {
109                 case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
110                 case I8254_MODE_RATE_GENERATOR:
111                 case I8254_MODE_SQUARE_WAVE_MODE:
112                 case I8254_MODE_HARDWARE_TRIGGERED_STROBE:
113                         *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
114                         return 0;
115                 default:
116                         *action = COUNTER_SYNAPSE_ACTION_NONE;
117                         return 0;
118                 }
119         default:
120                 /* should never reach this path */
121                 return -EINVAL;
122         }
123 }
124
125 static int i8254_count_ceiling_read(struct counter_device *const counter,
126                                     struct counter_count *const count, u64 *const ceiling)
127 {
128         struct i8254 *const priv = counter_priv(counter);
129
130         mutex_lock(&priv->lock);
131
132         switch (priv->out_mode[count->id]) {
133         case I8254_MODE_RATE_GENERATOR:
134                 /* Rate Generator decrements 0 by one and the counter "wraps around" */
135                 *ceiling = (priv->preset[count->id] == 0) ? U16_MAX : priv->preset[count->id];
136                 break;
137         case I8254_MODE_SQUARE_WAVE_MODE:
138                 if (priv->preset[count->id] % 2)
139                         *ceiling = priv->preset[count->id] - 1;
140                 else if (priv->preset[count->id] == 0)
141                         /* Square Wave Mode decrements 0 by two and the counter "wraps around" */
142                         *ceiling = U16_MAX - 1;
143                 else
144                         *ceiling = priv->preset[count->id];
145                 break;
146         default:
147                 *ceiling = U16_MAX;
148                 break;
149         }
150
151         mutex_unlock(&priv->lock);
152
153         return 0;
154 }
155
156 static int i8254_count_mode_read(struct counter_device *const counter,
157                                  struct counter_count *const count,
158                                  enum counter_count_mode *const count_mode)
159 {
160         const struct i8254 *const priv = counter_priv(counter);
161
162         switch (priv->out_mode[count->id]) {
163         case I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT:
164                 *count_mode = COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT;
165                 return 0;
166         case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
167                 *count_mode = COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT;
168                 return 0;
169         case I8254_MODE_RATE_GENERATOR:
170                 *count_mode = COUNTER_COUNT_MODE_RATE_GENERATOR;
171                 return 0;
172         case I8254_MODE_SQUARE_WAVE_MODE:
173                 *count_mode = COUNTER_COUNT_MODE_SQUARE_WAVE_MODE;
174                 return 0;
175         case I8254_MODE_SOFTWARE_TRIGGERED_STROBE:
176                 *count_mode = COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE;
177                 return 0;
178         case I8254_MODE_HARDWARE_TRIGGERED_STROBE:
179                 *count_mode = COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE;
180                 return 0;
181         default:
182                 /* should never reach this path */
183                 return -EINVAL;
184         }
185 }
186
187 static int i8254_count_mode_write(struct counter_device *const counter,
188                                   struct counter_count *const count,
189                                   const enum counter_count_mode count_mode)
190 {
191         struct i8254 *const priv = counter_priv(counter);
192         u8 out_mode;
193         int ret;
194
195         switch (count_mode) {
196         case COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT:
197                 out_mode = I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT;
198                 break;
199         case COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
200                 out_mode = I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT;
201                 break;
202         case COUNTER_COUNT_MODE_RATE_GENERATOR:
203                 out_mode = I8254_MODE_RATE_GENERATOR;
204                 break;
205         case COUNTER_COUNT_MODE_SQUARE_WAVE_MODE:
206                 out_mode = I8254_MODE_SQUARE_WAVE_MODE;
207                 break;
208         case COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE:
209                 out_mode = I8254_MODE_SOFTWARE_TRIGGERED_STROBE;
210                 break;
211         case COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE:
212                 out_mode = I8254_MODE_HARDWARE_TRIGGERED_STROBE;
213                 break;
214         default:
215                 /* should never reach this path */
216                 return -EINVAL;
217         }
218
219         mutex_lock(&priv->lock);
220
221         /* Counter Register is cleared when the counter is programmed */
222         priv->preset[count->id] = 0;
223         priv->out_mode[count->id] = out_mode;
224         ret = regmap_write(priv->map, I8254_CONTROL_REG,
225                            I8254_PROGRAM_COUNTER(count->id, out_mode));
226
227         mutex_unlock(&priv->lock);
228
229         return ret;
230 }
231
232 static int i8254_count_floor_read(struct counter_device *const counter,
233                                   struct counter_count *const count, u64 *const floor)
234 {
235         struct i8254 *const priv = counter_priv(counter);
236
237         mutex_lock(&priv->lock);
238
239         switch (priv->out_mode[count->id]) {
240         case I8254_MODE_RATE_GENERATOR:
241                 /* counter is always reloaded after 1, but 0 is a possible reload value */
242                 *floor = (priv->preset[count->id] == 0) ? 0 : 1;
243                 break;
244         case I8254_MODE_SQUARE_WAVE_MODE:
245                 /* counter is always reloaded after 2 for even preset values */
246                 *floor = (priv->preset[count->id] % 2 || priv->preset[count->id] == 0) ? 0 : 2;
247                 break;
248         default:
249                 *floor = 0;
250                 break;
251         }
252
253         mutex_unlock(&priv->lock);
254
255         return 0;
256 }
257
258 static int i8254_count_preset_read(struct counter_device *const counter,
259                                    struct counter_count *const count, u64 *const preset)
260 {
261         const struct i8254 *const priv = counter_priv(counter);
262
263         *preset = priv->preset[count->id];
264
265         return 0;
266 }
267
268 static int i8254_count_preset_write(struct counter_device *const counter,
269                                     struct counter_count *const count, const u64 preset)
270 {
271         struct i8254 *const priv = counter_priv(counter);
272         int ret;
273         u8 value[2];
274
275         if (preset > U16_MAX)
276                 return -ERANGE;
277
278         mutex_lock(&priv->lock);
279
280         if (priv->out_mode[count->id] == I8254_MODE_RATE_GENERATOR ||
281             priv->out_mode[count->id] == I8254_MODE_SQUARE_WAVE_MODE) {
282                 if (preset == 1) {
283                         mutex_unlock(&priv->lock);
284                         return -EINVAL;
285                 }
286         }
287
288         priv->preset[count->id] = preset;
289
290         put_unaligned_le16(preset, value);
291         ret = regmap_noinc_write(priv->map, I8254_COUNTER_REG(count->id), value, 2);
292
293         mutex_unlock(&priv->lock);
294
295         return ret;
296 }
297
298 static int i8254_init_hw(struct regmap *const map)
299 {
300         unsigned long i;
301         int ret;
302
303         for (i = 0; i < I8254_NUM_COUNTERS; i++) {
304                 /* Initialize each counter to Mode 0 */
305                 ret = regmap_write(map, I8254_CONTROL_REG,
306                                    I8254_PROGRAM_COUNTER(i, I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT));
307                 if (ret)
308                         return ret;
309         }
310
311         return 0;
312 }
313
314 static const struct counter_ops i8254_ops = {
315         .count_read = i8254_count_read,
316         .function_read = i8254_function_read,
317         .action_read = i8254_action_read,
318 };
319
320 #define I8254_SIGNAL(_id, _name) {              \
321         .id = (_id),                            \
322         .name = (_name),                        \
323 }
324
325 static struct counter_signal i8254_signals[] = {
326         I8254_SIGNAL(0, "CLK 0"), I8254_SIGNAL(1, "GATE 0"),
327         I8254_SIGNAL(2, "CLK 1"), I8254_SIGNAL(3, "GATE 1"),
328         I8254_SIGNAL(4, "CLK 2"), I8254_SIGNAL(5, "GATE 2"),
329 };
330
331 static const enum counter_synapse_action i8254_clk_actions[] = {
332         COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
333 };
334 static const enum counter_synapse_action i8254_gate_actions[] = {
335         COUNTER_SYNAPSE_ACTION_NONE,
336         COUNTER_SYNAPSE_ACTION_RISING_EDGE,
337 };
338
339 #define I8254_SYNAPSES_BASE(_id) ((_id) * I8254_SYNAPSES_PER_COUNT)
340 #define I8254_SYNAPSE_CLK(_id) {                                        \
341         .actions_list   = i8254_clk_actions,                            \
342         .num_actions    = ARRAY_SIZE(i8254_clk_actions),                \
343         .signal         = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 0], \
344 }
345 #define I8254_SYNAPSE_GATE(_id) {                                       \
346         .actions_list   = i8254_gate_actions,                           \
347         .num_actions    = ARRAY_SIZE(i8254_gate_actions),               \
348         .signal         = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 1], \
349 }
350
351 static struct counter_synapse i8254_synapses[] = {
352         I8254_SYNAPSE_CLK(0), I8254_SYNAPSE_GATE(0),
353         I8254_SYNAPSE_CLK(1), I8254_SYNAPSE_GATE(1),
354         I8254_SYNAPSE_CLK(2), I8254_SYNAPSE_GATE(2),
355 };
356
357 static const enum counter_function i8254_functions_list[] = {
358         COUNTER_FUNCTION_DECREASE,
359 };
360
361 static const enum counter_count_mode i8254_count_modes[] = {
362         COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT,
363         COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT,
364         COUNTER_COUNT_MODE_RATE_GENERATOR,
365         COUNTER_COUNT_MODE_SQUARE_WAVE_MODE,
366         COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE,
367         COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE,
368 };
369
370 static DEFINE_COUNTER_AVAILABLE(i8254_count_modes_available, i8254_count_modes);
371
372 static struct counter_comp i8254_count_ext[] = {
373         COUNTER_COMP_CEILING(i8254_count_ceiling_read, NULL),
374         COUNTER_COMP_COUNT_MODE(i8254_count_mode_read, i8254_count_mode_write,
375                                 i8254_count_modes_available),
376         COUNTER_COMP_FLOOR(i8254_count_floor_read, NULL),
377         COUNTER_COMP_PRESET(i8254_count_preset_read, i8254_count_preset_write),
378 };
379
380 #define I8254_COUNT(_id, _name) {                               \
381         .id = (_id),                                            \
382         .name = (_name),                                        \
383         .functions_list = i8254_functions_list,                 \
384         .num_functions = ARRAY_SIZE(i8254_functions_list),      \
385         .synapses = &i8254_synapses[I8254_SYNAPSES_BASE(_id)],  \
386         .num_synapses = I8254_SYNAPSES_PER_COUNT,               \
387         .ext = i8254_count_ext,                                 \
388         .num_ext = ARRAY_SIZE(i8254_count_ext)                  \
389 }
390
391 static struct counter_count i8254_counts[I8254_NUM_COUNTERS] = {
392         I8254_COUNT(0, "Counter 0"), I8254_COUNT(1, "Counter 1"), I8254_COUNT(2, "Counter 2"),
393 };
394
395 /**
396  * devm_i8254_regmap_register - Register an i8254 Counter device
397  * @dev: device that is registering this i8254 Counter device
398  * @config: configuration for i8254_regmap_config
399  *
400  * Registers an Intel 8254 Programmable Interval Timer Counter device. Returns 0 on success and
401  * negative error number on failure.
402  */
403 int devm_i8254_regmap_register(struct device *const dev,
404                                const struct i8254_regmap_config *const config)
405 {
406         struct counter_device *counter;
407         struct i8254 *priv;
408         int err;
409
410         if (!config->parent)
411                 return -EINVAL;
412
413         if (!config->map)
414                 return -EINVAL;
415
416         counter = devm_counter_alloc(dev, sizeof(*priv));
417         if (!counter)
418                 return -ENOMEM;
419         priv = counter_priv(counter);
420         priv->map = config->map;
421
422         counter->name = dev_name(config->parent);
423         counter->parent = config->parent;
424         counter->ops = &i8254_ops;
425         counter->counts = i8254_counts;
426         counter->num_counts = ARRAY_SIZE(i8254_counts);
427         counter->signals = i8254_signals;
428         counter->num_signals = ARRAY_SIZE(i8254_signals);
429
430         mutex_init(&priv->lock);
431
432         err = i8254_init_hw(priv->map);
433         if (err)
434                 return err;
435
436         err = devm_counter_add(dev, counter);
437         if (err < 0)
438                 return dev_err_probe(dev, err, "Failed to add counter\n");
439
440         return 0;
441 }
442 EXPORT_SYMBOL_NS_GPL(devm_i8254_regmap_register, I8254);
443
444 MODULE_AUTHOR("William Breathitt Gray");
445 MODULE_DESCRIPTION("Intel 8254 Programmable Interval Timer");
446 MODULE_LICENSE("GPL");
447 MODULE_IMPORT_NS(COUNTER);