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