xref: /openbmc/linux/drivers/counter/104-quad-8.c (revision 3216e551)
1f1d8a071SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0
2f1d8a071SWilliam Breathitt Gray /*
3f1d8a071SWilliam Breathitt Gray  * Counter driver for the ACCES 104-QUAD-8
4f1d8a071SWilliam Breathitt Gray  * Copyright (C) 2016 William Breathitt Gray
5f1d8a071SWilliam Breathitt Gray  *
6f1d8a071SWilliam Breathitt Gray  * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
7f1d8a071SWilliam Breathitt Gray  */
8f1d8a071SWilliam Breathitt Gray #include <linux/bitops.h>
9f1d8a071SWilliam Breathitt Gray #include <linux/counter.h>
10f1d8a071SWilliam Breathitt Gray #include <linux/device.h>
11f1d8a071SWilliam Breathitt Gray #include <linux/errno.h>
12f1d8a071SWilliam Breathitt Gray #include <linux/io.h>
13f1d8a071SWilliam Breathitt Gray #include <linux/ioport.h>
147aa2ba0dSWilliam Breathitt Gray #include <linux/interrupt.h>
15f1d8a071SWilliam Breathitt Gray #include <linux/isa.h>
16f1d8a071SWilliam Breathitt Gray #include <linux/kernel.h>
17c95cc0d9SWilliam Breathitt Gray #include <linux/list.h>
18f1d8a071SWilliam Breathitt Gray #include <linux/module.h>
19f1d8a071SWilliam Breathitt Gray #include <linux/moduleparam.h>
20f1d8a071SWilliam Breathitt Gray #include <linux/types.h>
2109db4678SWilliam Breathitt Gray #include <linux/spinlock.h>
22f1d8a071SWilliam Breathitt Gray 
23f1d8a071SWilliam Breathitt Gray #define QUAD8_EXTENT 32
24f1d8a071SWilliam Breathitt Gray 
25f1d8a071SWilliam Breathitt Gray static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
26f1d8a071SWilliam Breathitt Gray static unsigned int num_quad8;
27af383bb1SWilliam Breathitt Gray module_param_hw_array(base, uint, ioport, &num_quad8, 0);
28f1d8a071SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
29f1d8a071SWilliam Breathitt Gray 
307aa2ba0dSWilliam Breathitt Gray static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
317aa2ba0dSWilliam Breathitt Gray module_param_hw_array(irq, uint, irq, NULL, 0);
327aa2ba0dSWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
337aa2ba0dSWilliam Breathitt Gray 
34f1d8a071SWilliam Breathitt Gray #define QUAD8_NUM_COUNTERS 8
35f1d8a071SWilliam Breathitt Gray 
36f1d8a071SWilliam Breathitt Gray /**
37daae1ee5SWilliam Breathitt Gray  * struct channel_reg - channel register structure
38daae1ee5SWilliam Breathitt Gray  * @data:	Count data
39daae1ee5SWilliam Breathitt Gray  * @control:	Channel flags and control
40daae1ee5SWilliam Breathitt Gray  */
41daae1ee5SWilliam Breathitt Gray struct channel_reg {
42daae1ee5SWilliam Breathitt Gray 	u8 data;
43daae1ee5SWilliam Breathitt Gray 	u8 control;
44daae1ee5SWilliam Breathitt Gray };
45daae1ee5SWilliam Breathitt Gray 
46daae1ee5SWilliam Breathitt Gray /**
47daae1ee5SWilliam Breathitt Gray  * struct quad8_reg - device register structure
48daae1ee5SWilliam Breathitt Gray  * @channel:		quadrature counter data and control
49daae1ee5SWilliam Breathitt Gray  * @interrupt_status:	channel interrupt status
50daae1ee5SWilliam Breathitt Gray  * @channel_oper:	enable/reset counters and interrupt functions
51daae1ee5SWilliam Breathitt Gray  * @index_interrupt:	enable channel interrupts
52daae1ee5SWilliam Breathitt Gray  * @reserved:		reserved for Factory Use
53daae1ee5SWilliam Breathitt Gray  * @index_input_levels:	index signal logical input level
54daae1ee5SWilliam Breathitt Gray  * @cable_status:	differential encoder cable status
55daae1ee5SWilliam Breathitt Gray  */
56daae1ee5SWilliam Breathitt Gray struct quad8_reg {
57daae1ee5SWilliam Breathitt Gray 	struct channel_reg channel[QUAD8_NUM_COUNTERS];
58daae1ee5SWilliam Breathitt Gray 	u8 interrupt_status;
59daae1ee5SWilliam Breathitt Gray 	u8 channel_oper;
60daae1ee5SWilliam Breathitt Gray 	u8 index_interrupt;
61daae1ee5SWilliam Breathitt Gray 	u8 reserved[3];
62daae1ee5SWilliam Breathitt Gray 	u8 index_input_levels;
63daae1ee5SWilliam Breathitt Gray 	u8 cable_status;
64daae1ee5SWilliam Breathitt Gray };
65daae1ee5SWilliam Breathitt Gray 
66daae1ee5SWilliam Breathitt Gray /**
67e357e81fSWilliam Breathitt Gray  * struct quad8 - device private data structure
6894a853ecSWilliam Breathitt Gray  * @lock:		lock to prevent clobbering device states during R/W ops
69f1d8a071SWilliam Breathitt Gray  * @counter:		instance of the counter_device
70954ab5ccSWilliam Breathitt Gray  * @fck_prescaler:	array of filter clock prescaler configurations
71f1d8a071SWilliam Breathitt Gray  * @preset:		array of preset values
72f1d8a071SWilliam Breathitt Gray  * @count_mode:		array of count mode configurations
73f1d8a071SWilliam Breathitt Gray  * @quadrature_mode:	array of quadrature mode configurations
74f1d8a071SWilliam Breathitt Gray  * @quadrature_scale:	array of quadrature mode scale configurations
75f1d8a071SWilliam Breathitt Gray  * @ab_enable:		array of A and B inputs enable configurations
76f1d8a071SWilliam Breathitt Gray  * @preset_enable:	array of set_to_preset_on_index attribute configurations
777aa2ba0dSWilliam Breathitt Gray  * @irq_trigger:	array of current IRQ trigger function configurations
78f1d8a071SWilliam Breathitt Gray  * @synchronous_mode:	array of index function synchronous mode configurations
79f1d8a071SWilliam Breathitt Gray  * @index_polarity:	array of index function polarity configurations
80954ab5ccSWilliam Breathitt Gray  * @cable_fault_enable:	differential encoder cable status enable configurations
81daae1ee5SWilliam Breathitt Gray  * @reg:		I/O address offset for the device registers
82f1d8a071SWilliam Breathitt Gray  */
83e357e81fSWilliam Breathitt Gray struct quad8 {
8409db4678SWilliam Breathitt Gray 	spinlock_t lock;
85de65d055SWilliam Breathitt Gray 	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
86f1d8a071SWilliam Breathitt Gray 	unsigned int preset[QUAD8_NUM_COUNTERS];
87f1d8a071SWilliam Breathitt Gray 	unsigned int count_mode[QUAD8_NUM_COUNTERS];
88f1d8a071SWilliam Breathitt Gray 	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
89f1d8a071SWilliam Breathitt Gray 	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
90f1d8a071SWilliam Breathitt Gray 	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
91f1d8a071SWilliam Breathitt Gray 	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
927aa2ba0dSWilliam Breathitt Gray 	unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
93f1d8a071SWilliam Breathitt Gray 	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
94f1d8a071SWilliam Breathitt Gray 	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
95954ab5ccSWilliam Breathitt Gray 	unsigned int cable_fault_enable;
96daae1ee5SWilliam Breathitt Gray 	struct quad8_reg __iomem *reg;
97f1d8a071SWilliam Breathitt Gray };
98f1d8a071SWilliam Breathitt Gray 
99f1d8a071SWilliam Breathitt Gray /* Borrow Toggle flip-flop */
100f1d8a071SWilliam Breathitt Gray #define QUAD8_FLAG_BT BIT(0)
101f1d8a071SWilliam Breathitt Gray /* Carry Toggle flip-flop */
102f1d8a071SWilliam Breathitt Gray #define QUAD8_FLAG_CT BIT(1)
103f1d8a071SWilliam Breathitt Gray /* Error flag */
104f1d8a071SWilliam Breathitt Gray #define QUAD8_FLAG_E BIT(4)
105f1d8a071SWilliam Breathitt Gray /* Up/Down flag */
106f1d8a071SWilliam Breathitt Gray #define QUAD8_FLAG_UD BIT(5)
107f1d8a071SWilliam Breathitt Gray /* Reset and Load Signal Decoders */
108f1d8a071SWilliam Breathitt Gray #define QUAD8_CTR_RLD 0x00
109f1d8a071SWilliam Breathitt Gray /* Counter Mode Register */
110f1d8a071SWilliam Breathitt Gray #define QUAD8_CTR_CMR 0x20
111f1d8a071SWilliam Breathitt Gray /* Input / Output Control Register */
112f1d8a071SWilliam Breathitt Gray #define QUAD8_CTR_IOR 0x40
113f1d8a071SWilliam Breathitt Gray /* Index Control Register */
114f1d8a071SWilliam Breathitt Gray #define QUAD8_CTR_IDR 0x60
115f1d8a071SWilliam Breathitt Gray /* Reset Byte Pointer (three byte data pointer) */
116f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_RESET_BP 0x01
117f1d8a071SWilliam Breathitt Gray /* Reset Counter */
118f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_RESET_CNTR 0x02
119f1d8a071SWilliam Breathitt Gray /* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
120f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_RESET_FLAGS 0x04
121f1d8a071SWilliam Breathitt Gray /* Reset Error flag */
122f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_RESET_E 0x06
123f1d8a071SWilliam Breathitt Gray /* Preset Register to Counter */
124f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_PRESET_CNTR 0x08
125f1d8a071SWilliam Breathitt Gray /* Transfer Counter to Output Latch */
126f1d8a071SWilliam Breathitt Gray #define QUAD8_RLD_CNTR_OUT 0x10
127de65d055SWilliam Breathitt Gray /* Transfer Preset Register LSB to FCK Prescaler */
128de65d055SWilliam Breathitt Gray #define QUAD8_RLD_PRESET_PSC 0x18
129f1d8a071SWilliam Breathitt Gray #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
1307aa2ba0dSWilliam Breathitt Gray #define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
131f1d8a071SWilliam Breathitt Gray #define QUAD8_CMR_QUADRATURE_X1 0x08
132f1d8a071SWilliam Breathitt Gray #define QUAD8_CMR_QUADRATURE_X2 0x10
133f1d8a071SWilliam Breathitt Gray #define QUAD8_CMR_QUADRATURE_X4 0x18
134f1d8a071SWilliam Breathitt Gray 
135f1d8a071SWilliam Breathitt Gray static int quad8_signal_read(struct counter_device *counter,
136493b938aSWilliam Breathitt Gray 			     struct counter_signal *signal,
137493b938aSWilliam Breathitt Gray 			     enum counter_signal_level *level)
138f1d8a071SWilliam Breathitt Gray {
139aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
140f1d8a071SWilliam Breathitt Gray 	unsigned int state;
141f1d8a071SWilliam Breathitt Gray 
142f1d8a071SWilliam Breathitt Gray 	/* Only Index signal levels can be read */
143f1d8a071SWilliam Breathitt Gray 	if (signal->id < 16)
144f1d8a071SWilliam Breathitt Gray 		return -EINVAL;
145f1d8a071SWilliam Breathitt Gray 
146daae1ee5SWilliam Breathitt Gray 	state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16);
147f1d8a071SWilliam Breathitt Gray 
148493b938aSWilliam Breathitt Gray 	*level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
149f1d8a071SWilliam Breathitt Gray 
150f1d8a071SWilliam Breathitt Gray 	return 0;
151f1d8a071SWilliam Breathitt Gray }
152f1d8a071SWilliam Breathitt Gray 
153f1d8a071SWilliam Breathitt Gray static int quad8_count_read(struct counter_device *counter,
154aaec1a0fSWilliam Breathitt Gray 			    struct counter_count *count, u64 *val)
155f1d8a071SWilliam Breathitt Gray {
156aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
157daae1ee5SWilliam Breathitt Gray 	struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
158f1d8a071SWilliam Breathitt Gray 	unsigned int flags;
159f1d8a071SWilliam Breathitt Gray 	unsigned int borrow;
160f1d8a071SWilliam Breathitt Gray 	unsigned int carry;
16109db4678SWilliam Breathitt Gray 	unsigned long irqflags;
162f1d8a071SWilliam Breathitt Gray 	int i;
163f1d8a071SWilliam Breathitt Gray 
164daae1ee5SWilliam Breathitt Gray 	flags = ioread8(&chan->control);
165f1d8a071SWilliam Breathitt Gray 	borrow = flags & QUAD8_FLAG_BT;
166f1d8a071SWilliam Breathitt Gray 	carry = !!(flags & QUAD8_FLAG_CT);
167f1d8a071SWilliam Breathitt Gray 
168f1d8a071SWilliam Breathitt Gray 	/* Borrow XOR Carry effectively doubles count range */
169d49e6ee2SWilliam Breathitt Gray 	*val = (unsigned long)(borrow ^ carry) << 24;
170f1d8a071SWilliam Breathitt Gray 
17109db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
172fc069262SSyed Nayyar Waris 
173f1d8a071SWilliam Breathitt Gray 	/* Reset Byte Pointer; transfer Counter to Output Latch */
174b6e9cdedSWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
175daae1ee5SWilliam Breathitt Gray 		 &chan->control);
176f1d8a071SWilliam Breathitt Gray 
177f1d8a071SWilliam Breathitt Gray 	for (i = 0; i < 3; i++)
178daae1ee5SWilliam Breathitt Gray 		*val |= (unsigned long)ioread8(&chan->data) << (8 * i);
179f1d8a071SWilliam Breathitt Gray 
18009db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
181fc069262SSyed Nayyar Waris 
182f1d8a071SWilliam Breathitt Gray 	return 0;
183f1d8a071SWilliam Breathitt Gray }
184f1d8a071SWilliam Breathitt Gray 
185f1d8a071SWilliam Breathitt Gray static int quad8_count_write(struct counter_device *counter,
186aaec1a0fSWilliam Breathitt Gray 			     struct counter_count *count, u64 val)
187f1d8a071SWilliam Breathitt Gray {
188aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
189daae1ee5SWilliam Breathitt Gray 	struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
19009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
191f1d8a071SWilliam Breathitt Gray 	int i;
192f1d8a071SWilliam Breathitt Gray 
193f1d8a071SWilliam Breathitt Gray 	/* Only 24-bit values are supported */
194d49e6ee2SWilliam Breathitt Gray 	if (val > 0xFFFFFF)
195e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
196f1d8a071SWilliam Breathitt Gray 
19709db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
198fc069262SSyed Nayyar Waris 
199f1d8a071SWilliam Breathitt Gray 	/* Reset Byte Pointer */
200daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
201f1d8a071SWilliam Breathitt Gray 
202f1d8a071SWilliam Breathitt Gray 	/* Counter can only be set via Preset Register */
203f1d8a071SWilliam Breathitt Gray 	for (i = 0; i < 3; i++)
204daae1ee5SWilliam Breathitt Gray 		iowrite8(val >> (8 * i), &chan->data);
205f1d8a071SWilliam Breathitt Gray 
206f1d8a071SWilliam Breathitt Gray 	/* Transfer Preset Register to Counter */
207daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control);
208f1d8a071SWilliam Breathitt Gray 
209f1d8a071SWilliam Breathitt Gray 	/* Reset Byte Pointer */
210daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
211f1d8a071SWilliam Breathitt Gray 
212f1d8a071SWilliam Breathitt Gray 	/* Set Preset Register back to original value */
213d49e6ee2SWilliam Breathitt Gray 	val = priv->preset[count->id];
214f1d8a071SWilliam Breathitt Gray 	for (i = 0; i < 3; i++)
215daae1ee5SWilliam Breathitt Gray 		iowrite8(val >> (8 * i), &chan->data);
216f1d8a071SWilliam Breathitt Gray 
217f1d8a071SWilliam Breathitt Gray 	/* Reset Borrow, Carry, Compare, and Sign flags */
218daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
219f1d8a071SWilliam Breathitt Gray 	/* Reset Error flag */
220daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
221f1d8a071SWilliam Breathitt Gray 
22209db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
223fc069262SSyed Nayyar Waris 
224f1d8a071SWilliam Breathitt Gray 	return 0;
225f1d8a071SWilliam Breathitt Gray }
226f1d8a071SWilliam Breathitt Gray 
227394a0150SWilliam Breathitt Gray static const enum counter_function quad8_count_functions_list[] = {
228aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_PULSE_DIRECTION,
229aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X1_A,
230aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X2_A,
231aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X4,
232f1d8a071SWilliam Breathitt Gray };
233f1d8a071SWilliam Breathitt Gray 
234aaec1a0fSWilliam Breathitt Gray static int quad8_function_read(struct counter_device *counter,
235aaec1a0fSWilliam Breathitt Gray 			       struct counter_count *count,
236aaec1a0fSWilliam Breathitt Gray 			       enum counter_function *function)
237f1d8a071SWilliam Breathitt Gray {
238aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
239f1d8a071SWilliam Breathitt Gray 	const int id = count->id;
24009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
241f1d8a071SWilliam Breathitt Gray 
24209db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
243fc069262SSyed Nayyar Waris 
244fc069262SSyed Nayyar Waris 	if (priv->quadrature_mode[id])
245fc069262SSyed Nayyar Waris 		switch (priv->quadrature_scale[id]) {
246f1d8a071SWilliam Breathitt Gray 		case 0:
247aaec1a0fSWilliam Breathitt Gray 			*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
248f1d8a071SWilliam Breathitt Gray 			break;
249f1d8a071SWilliam Breathitt Gray 		case 1:
250aaec1a0fSWilliam Breathitt Gray 			*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
251f1d8a071SWilliam Breathitt Gray 			break;
252f1d8a071SWilliam Breathitt Gray 		case 2:
253aaec1a0fSWilliam Breathitt Gray 			*function = COUNTER_FUNCTION_QUADRATURE_X4;
254f1d8a071SWilliam Breathitt Gray 			break;
255f1d8a071SWilliam Breathitt Gray 		}
256f1d8a071SWilliam Breathitt Gray 	else
257aaec1a0fSWilliam Breathitt Gray 		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
258f1d8a071SWilliam Breathitt Gray 
25909db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
260fc069262SSyed Nayyar Waris 
261f1d8a071SWilliam Breathitt Gray 	return 0;
262f1d8a071SWilliam Breathitt Gray }
263f1d8a071SWilliam Breathitt Gray 
264aaec1a0fSWilliam Breathitt Gray static int quad8_function_write(struct counter_device *counter,
265aaec1a0fSWilliam Breathitt Gray 				struct counter_count *count,
266aaec1a0fSWilliam Breathitt Gray 				enum counter_function function)
267f1d8a071SWilliam Breathitt Gray {
268aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
269f1d8a071SWilliam Breathitt Gray 	const int id = count->id;
270f1d8a071SWilliam Breathitt Gray 	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
271f1d8a071SWilliam Breathitt Gray 	unsigned int *const scale = priv->quadrature_scale + id;
272f1d8a071SWilliam Breathitt Gray 	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
273daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[id].control;
27409db4678SWilliam Breathitt Gray 	unsigned long irqflags;
275fc069262SSyed Nayyar Waris 	unsigned int mode_cfg;
276fc069262SSyed Nayyar Waris 	unsigned int idr_cfg;
277fc069262SSyed Nayyar Waris 
27809db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
279fc069262SSyed Nayyar Waris 
280fc069262SSyed Nayyar Waris 	mode_cfg = priv->count_mode[id] << 1;
281fc069262SSyed Nayyar Waris 	idr_cfg = priv->index_polarity[id] << 1;
282f1d8a071SWilliam Breathitt Gray 
283aaec1a0fSWilliam Breathitt Gray 	if (function == COUNTER_FUNCTION_PULSE_DIRECTION) {
284f1d8a071SWilliam Breathitt Gray 		*quadrature_mode = 0;
285f1d8a071SWilliam Breathitt Gray 
286f1d8a071SWilliam Breathitt Gray 		/* Quadrature scaling only available in quadrature mode */
287f1d8a071SWilliam Breathitt Gray 		*scale = 0;
288f1d8a071SWilliam Breathitt Gray 
289f1d8a071SWilliam Breathitt Gray 		/* Synchronous function not supported in non-quadrature mode */
290f1d8a071SWilliam Breathitt Gray 		if (*synchronous_mode) {
291f1d8a071SWilliam Breathitt Gray 			*synchronous_mode = 0;
292f1d8a071SWilliam Breathitt Gray 			/* Disable synchronous function mode */
293daae1ee5SWilliam Breathitt Gray 			iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
294f1d8a071SWilliam Breathitt Gray 		}
295f1d8a071SWilliam Breathitt Gray 	} else {
296f1d8a071SWilliam Breathitt Gray 		*quadrature_mode = 1;
297f1d8a071SWilliam Breathitt Gray 
298f1d8a071SWilliam Breathitt Gray 		switch (function) {
299aaec1a0fSWilliam Breathitt Gray 		case COUNTER_FUNCTION_QUADRATURE_X1_A:
300f1d8a071SWilliam Breathitt Gray 			*scale = 0;
301f1d8a071SWilliam Breathitt Gray 			mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
302f1d8a071SWilliam Breathitt Gray 			break;
303aaec1a0fSWilliam Breathitt Gray 		case COUNTER_FUNCTION_QUADRATURE_X2_A:
304f1d8a071SWilliam Breathitt Gray 			*scale = 1;
305f1d8a071SWilliam Breathitt Gray 			mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
306f1d8a071SWilliam Breathitt Gray 			break;
307aaec1a0fSWilliam Breathitt Gray 		case COUNTER_FUNCTION_QUADRATURE_X4:
308f1d8a071SWilliam Breathitt Gray 			*scale = 2;
309f1d8a071SWilliam Breathitt Gray 			mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
310f1d8a071SWilliam Breathitt Gray 			break;
311b11eed15SWilliam Breathitt Gray 		default:
312b11eed15SWilliam Breathitt Gray 			/* should never reach this path */
31309db4678SWilliam Breathitt Gray 			spin_unlock_irqrestore(&priv->lock, irqflags);
314b11eed15SWilliam Breathitt Gray 			return -EINVAL;
315f1d8a071SWilliam Breathitt Gray 		}
316f1d8a071SWilliam Breathitt Gray 	}
317f1d8a071SWilliam Breathitt Gray 
318f1d8a071SWilliam Breathitt Gray 	/* Load mode configuration to Counter Mode Register */
319daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
320f1d8a071SWilliam Breathitt Gray 
32109db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
322fc069262SSyed Nayyar Waris 
323f1d8a071SWilliam Breathitt Gray 	return 0;
324f1d8a071SWilliam Breathitt Gray }
325f1d8a071SWilliam Breathitt Gray 
326aaec1a0fSWilliam Breathitt Gray static int quad8_direction_read(struct counter_device *counter,
327aaec1a0fSWilliam Breathitt Gray 				struct counter_count *count,
328aaec1a0fSWilliam Breathitt Gray 				enum counter_count_direction *direction)
329f1d8a071SWilliam Breathitt Gray {
330aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
331f1d8a071SWilliam Breathitt Gray 	unsigned int ud_flag;
332daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
333f1d8a071SWilliam Breathitt Gray 
334f1d8a071SWilliam Breathitt Gray 	/* U/D flag: nonzero = up, zero = down */
335b6e9cdedSWilliam Breathitt Gray 	ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD;
336f1d8a071SWilliam Breathitt Gray 
337f1d8a071SWilliam Breathitt Gray 	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
338f1d8a071SWilliam Breathitt Gray 		COUNTER_COUNT_DIRECTION_BACKWARD;
339aaec1a0fSWilliam Breathitt Gray 
340aaec1a0fSWilliam Breathitt Gray 	return 0;
341f1d8a071SWilliam Breathitt Gray }
342f1d8a071SWilliam Breathitt Gray 
3436a9eb0e3SWilliam Breathitt Gray static const enum counter_synapse_action quad8_index_actions_list[] = {
344aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_NONE,
345aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
346f1d8a071SWilliam Breathitt Gray };
347f1d8a071SWilliam Breathitt Gray 
3486a9eb0e3SWilliam Breathitt Gray static const enum counter_synapse_action quad8_synapse_actions_list[] = {
349aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_NONE,
350aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
351aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
352aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
353f1d8a071SWilliam Breathitt Gray };
354f1d8a071SWilliam Breathitt Gray 
355aaec1a0fSWilliam Breathitt Gray static int quad8_action_read(struct counter_device *counter,
356aaec1a0fSWilliam Breathitt Gray 			     struct counter_count *count,
357aaec1a0fSWilliam Breathitt Gray 			     struct counter_synapse *synapse,
358aaec1a0fSWilliam Breathitt Gray 			     enum counter_synapse_action *action)
359f1d8a071SWilliam Breathitt Gray {
360aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
361f1d8a071SWilliam Breathitt Gray 	int err;
362aaec1a0fSWilliam Breathitt Gray 	enum counter_function function;
363f1d8a071SWilliam Breathitt Gray 	const size_t signal_a_id = count->synapses[0].signal->id;
364f1d8a071SWilliam Breathitt Gray 	enum counter_count_direction direction;
365f1d8a071SWilliam Breathitt Gray 
366f1d8a071SWilliam Breathitt Gray 	/* Handle Index signals */
367f1d8a071SWilliam Breathitt Gray 	if (synapse->signal->id >= 16) {
368f1d8a071SWilliam Breathitt Gray 		if (priv->preset_enable[count->id])
369aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
370f1d8a071SWilliam Breathitt Gray 		else
371aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_NONE;
372f1d8a071SWilliam Breathitt Gray 
373f1d8a071SWilliam Breathitt Gray 		return 0;
374f1d8a071SWilliam Breathitt Gray 	}
375f1d8a071SWilliam Breathitt Gray 
376aaec1a0fSWilliam Breathitt Gray 	err = quad8_function_read(counter, count, &function);
377f1d8a071SWilliam Breathitt Gray 	if (err)
378f1d8a071SWilliam Breathitt Gray 		return err;
379f1d8a071SWilliam Breathitt Gray 
380f1d8a071SWilliam Breathitt Gray 	/* Default action mode */
381aaec1a0fSWilliam Breathitt Gray 	*action = COUNTER_SYNAPSE_ACTION_NONE;
382f1d8a071SWilliam Breathitt Gray 
383f1d8a071SWilliam Breathitt Gray 	/* Determine action mode based on current count function mode */
384f1d8a071SWilliam Breathitt Gray 	switch (function) {
385aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_PULSE_DIRECTION:
386f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id)
387aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
388b11eed15SWilliam Breathitt Gray 		return 0;
389aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X1_A:
390f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id) {
391aaec1a0fSWilliam Breathitt Gray 			err = quad8_direction_read(counter, count, &direction);
392aaec1a0fSWilliam Breathitt Gray 			if (err)
393aaec1a0fSWilliam Breathitt Gray 				return err;
394f1d8a071SWilliam Breathitt Gray 
395f1d8a071SWilliam Breathitt Gray 			if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
396aaec1a0fSWilliam Breathitt Gray 				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
397f1d8a071SWilliam Breathitt Gray 			else
398aaec1a0fSWilliam Breathitt Gray 				*action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
399f1d8a071SWilliam Breathitt Gray 		}
400b11eed15SWilliam Breathitt Gray 		return 0;
401aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X2_A:
402f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id)
403aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
404b11eed15SWilliam Breathitt Gray 		return 0;
405aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X4:
406aaec1a0fSWilliam Breathitt Gray 		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
407f1d8a071SWilliam Breathitt Gray 		return 0;
408b11eed15SWilliam Breathitt Gray 	default:
409b11eed15SWilliam Breathitt Gray 		/* should never reach this path */
410b11eed15SWilliam Breathitt Gray 		return -EINVAL;
411b11eed15SWilliam Breathitt Gray 	}
412f1d8a071SWilliam Breathitt Gray }
413f1d8a071SWilliam Breathitt Gray 
4147aa2ba0dSWilliam Breathitt Gray enum {
4157aa2ba0dSWilliam Breathitt Gray 	QUAD8_EVENT_CARRY = 0,
4167aa2ba0dSWilliam Breathitt Gray 	QUAD8_EVENT_COMPARE = 1,
4177aa2ba0dSWilliam Breathitt Gray 	QUAD8_EVENT_CARRY_BORROW = 2,
4187aa2ba0dSWilliam Breathitt Gray 	QUAD8_EVENT_INDEX = 3,
4197aa2ba0dSWilliam Breathitt Gray };
4207aa2ba0dSWilliam Breathitt Gray 
4217aa2ba0dSWilliam Breathitt Gray static int quad8_events_configure(struct counter_device *counter)
4227aa2ba0dSWilliam Breathitt Gray {
423aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
4247aa2ba0dSWilliam Breathitt Gray 	unsigned long irq_enabled = 0;
4257aa2ba0dSWilliam Breathitt Gray 	unsigned long irqflags;
426c95cc0d9SWilliam Breathitt Gray 	struct counter_event_node *event_node;
427c95cc0d9SWilliam Breathitt Gray 	unsigned int next_irq_trigger;
4287aa2ba0dSWilliam Breathitt Gray 	unsigned long ior_cfg;
4297aa2ba0dSWilliam Breathitt Gray 
4307aa2ba0dSWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
4317aa2ba0dSWilliam Breathitt Gray 
432c95cc0d9SWilliam Breathitt Gray 	list_for_each_entry(event_node, &counter->events_list, l) {
433c95cc0d9SWilliam Breathitt Gray 		switch (event_node->event) {
434c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_OVERFLOW:
435c95cc0d9SWilliam Breathitt Gray 			next_irq_trigger = QUAD8_EVENT_CARRY;
436c95cc0d9SWilliam Breathitt Gray 			break;
437c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_THRESHOLD:
438c95cc0d9SWilliam Breathitt Gray 			next_irq_trigger = QUAD8_EVENT_COMPARE;
439c95cc0d9SWilliam Breathitt Gray 			break;
440c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
441c95cc0d9SWilliam Breathitt Gray 			next_irq_trigger = QUAD8_EVENT_CARRY_BORROW;
442c95cc0d9SWilliam Breathitt Gray 			break;
443c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_INDEX:
444c95cc0d9SWilliam Breathitt Gray 			next_irq_trigger = QUAD8_EVENT_INDEX;
445c95cc0d9SWilliam Breathitt Gray 			break;
446c95cc0d9SWilliam Breathitt Gray 		default:
447c95cc0d9SWilliam Breathitt Gray 			/* should never reach this path */
448c95cc0d9SWilliam Breathitt Gray 			spin_unlock_irqrestore(&priv->lock, irqflags);
449c95cc0d9SWilliam Breathitt Gray 			return -EINVAL;
4507aa2ba0dSWilliam Breathitt Gray 		}
4517aa2ba0dSWilliam Breathitt Gray 
452c95cc0d9SWilliam Breathitt Gray 		/* Skip configuration if it is the same as previously set */
453c95cc0d9SWilliam Breathitt Gray 		if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
454c95cc0d9SWilliam Breathitt Gray 			continue;
455c95cc0d9SWilliam Breathitt Gray 
456c95cc0d9SWilliam Breathitt Gray 		/* Save new IRQ function configuration */
457c95cc0d9SWilliam Breathitt Gray 		priv->irq_trigger[event_node->channel] = next_irq_trigger;
458c95cc0d9SWilliam Breathitt Gray 
459c95cc0d9SWilliam Breathitt Gray 		/* Load configuration to I/O Control Register */
460c95cc0d9SWilliam Breathitt Gray 		ior_cfg = priv->ab_enable[event_node->channel] |
461c95cc0d9SWilliam Breathitt Gray 			  priv->preset_enable[event_node->channel] << 1 |
462c95cc0d9SWilliam Breathitt Gray 			  priv->irq_trigger[event_node->channel] << 3;
463daae1ee5SWilliam Breathitt Gray 		iowrite8(QUAD8_CTR_IOR | ior_cfg,
464daae1ee5SWilliam Breathitt Gray 			 &priv->reg->channel[event_node->channel].control);
4657aa2ba0dSWilliam Breathitt Gray 
4667aa2ba0dSWilliam Breathitt Gray 		/* Enable IRQ line */
467c95cc0d9SWilliam Breathitt Gray 		irq_enabled |= BIT(event_node->channel);
4687aa2ba0dSWilliam Breathitt Gray 	}
4697aa2ba0dSWilliam Breathitt Gray 
470daae1ee5SWilliam Breathitt Gray 	iowrite8(irq_enabled, &priv->reg->index_interrupt);
4717aa2ba0dSWilliam Breathitt Gray 
4727aa2ba0dSWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
4737aa2ba0dSWilliam Breathitt Gray 
4747aa2ba0dSWilliam Breathitt Gray 	return 0;
4757aa2ba0dSWilliam Breathitt Gray }
4767aa2ba0dSWilliam Breathitt Gray 
4777aa2ba0dSWilliam Breathitt Gray static int quad8_watch_validate(struct counter_device *counter,
4787aa2ba0dSWilliam Breathitt Gray 				const struct counter_watch *watch)
4797aa2ba0dSWilliam Breathitt Gray {
480c95cc0d9SWilliam Breathitt Gray 	struct counter_event_node *event_node;
4817aa2ba0dSWilliam Breathitt Gray 
4827aa2ba0dSWilliam Breathitt Gray 	if (watch->channel > QUAD8_NUM_COUNTERS - 1)
4837aa2ba0dSWilliam Breathitt Gray 		return -EINVAL;
4847aa2ba0dSWilliam Breathitt Gray 
4857aa2ba0dSWilliam Breathitt Gray 	switch (watch->event) {
4867aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_OVERFLOW:
4877aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_THRESHOLD:
4887aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
4897aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_INDEX:
490c95cc0d9SWilliam Breathitt Gray 		list_for_each_entry(event_node, &counter->next_events_list, l)
491c95cc0d9SWilliam Breathitt Gray 			if (watch->channel == event_node->channel &&
492c95cc0d9SWilliam Breathitt Gray 				watch->event != event_node->event)
4937aa2ba0dSWilliam Breathitt Gray 				return -EINVAL;
4947aa2ba0dSWilliam Breathitt Gray 		return 0;
4957aa2ba0dSWilliam Breathitt Gray 	default:
4967aa2ba0dSWilliam Breathitt Gray 		return -EINVAL;
4977aa2ba0dSWilliam Breathitt Gray 	}
4987aa2ba0dSWilliam Breathitt Gray }
4997aa2ba0dSWilliam Breathitt Gray 
50017aa207eSYueHaibing static const struct counter_ops quad8_ops = {
501f1d8a071SWilliam Breathitt Gray 	.signal_read = quad8_signal_read,
502f1d8a071SWilliam Breathitt Gray 	.count_read = quad8_count_read,
503f1d8a071SWilliam Breathitt Gray 	.count_write = quad8_count_write,
504aaec1a0fSWilliam Breathitt Gray 	.function_read = quad8_function_read,
505aaec1a0fSWilliam Breathitt Gray 	.function_write = quad8_function_write,
5067aa2ba0dSWilliam Breathitt Gray 	.action_read = quad8_action_read,
5077aa2ba0dSWilliam Breathitt Gray 	.events_configure = quad8_events_configure,
5087aa2ba0dSWilliam Breathitt Gray 	.watch_validate = quad8_watch_validate,
509f1d8a071SWilliam Breathitt Gray };
510f1d8a071SWilliam Breathitt Gray 
511e357e81fSWilliam Breathitt Gray static const char *const quad8_index_polarity_modes[] = {
512e357e81fSWilliam Breathitt Gray 	"negative",
513e357e81fSWilliam Breathitt Gray 	"positive"
514e357e81fSWilliam Breathitt Gray };
515e357e81fSWilliam Breathitt Gray 
516f1d8a071SWilliam Breathitt Gray static int quad8_index_polarity_get(struct counter_device *counter,
517aaec1a0fSWilliam Breathitt Gray 				    struct counter_signal *signal,
518aaec1a0fSWilliam Breathitt Gray 				    u32 *index_polarity)
519f1d8a071SWilliam Breathitt Gray {
520aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
521f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
522f1d8a071SWilliam Breathitt Gray 
523f1d8a071SWilliam Breathitt Gray 	*index_polarity = priv->index_polarity[channel_id];
524f1d8a071SWilliam Breathitt Gray 
525f1d8a071SWilliam Breathitt Gray 	return 0;
526f1d8a071SWilliam Breathitt Gray }
527f1d8a071SWilliam Breathitt Gray 
528f1d8a071SWilliam Breathitt Gray static int quad8_index_polarity_set(struct counter_device *counter,
529aaec1a0fSWilliam Breathitt Gray 				    struct counter_signal *signal,
530aaec1a0fSWilliam Breathitt Gray 				    u32 index_polarity)
531f1d8a071SWilliam Breathitt Gray {
532aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
533f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
534daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
53509db4678SWilliam Breathitt Gray 	unsigned long irqflags;
536fc069262SSyed Nayyar Waris 	unsigned int idr_cfg = index_polarity << 1;
537fc069262SSyed Nayyar Waris 
53809db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
539fc069262SSyed Nayyar Waris 
540fc069262SSyed Nayyar Waris 	idr_cfg |= priv->synchronous_mode[channel_id];
541f1d8a071SWilliam Breathitt Gray 
542f1d8a071SWilliam Breathitt Gray 	priv->index_polarity[channel_id] = index_polarity;
543f1d8a071SWilliam Breathitt Gray 
544f1d8a071SWilliam Breathitt Gray 	/* Load Index Control configuration to Index Control Register */
545daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
546f1d8a071SWilliam Breathitt Gray 
54709db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
548fc069262SSyed Nayyar Waris 
549f1d8a071SWilliam Breathitt Gray 	return 0;
550f1d8a071SWilliam Breathitt Gray }
551f1d8a071SWilliam Breathitt Gray 
552e357e81fSWilliam Breathitt Gray static const char *const quad8_synchronous_modes[] = {
553e357e81fSWilliam Breathitt Gray 	"non-synchronous",
554e357e81fSWilliam Breathitt Gray 	"synchronous"
555e357e81fSWilliam Breathitt Gray };
556e357e81fSWilliam Breathitt Gray 
557f1d8a071SWilliam Breathitt Gray static int quad8_synchronous_mode_get(struct counter_device *counter,
558aaec1a0fSWilliam Breathitt Gray 				      struct counter_signal *signal,
559aaec1a0fSWilliam Breathitt Gray 				      u32 *synchronous_mode)
560f1d8a071SWilliam Breathitt Gray {
561aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
562f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
563f1d8a071SWilliam Breathitt Gray 
564f1d8a071SWilliam Breathitt Gray 	*synchronous_mode = priv->synchronous_mode[channel_id];
565f1d8a071SWilliam Breathitt Gray 
566f1d8a071SWilliam Breathitt Gray 	return 0;
567f1d8a071SWilliam Breathitt Gray }
568f1d8a071SWilliam Breathitt Gray 
569f1d8a071SWilliam Breathitt Gray static int quad8_synchronous_mode_set(struct counter_device *counter,
570aaec1a0fSWilliam Breathitt Gray 				      struct counter_signal *signal,
571aaec1a0fSWilliam Breathitt Gray 				      u32 synchronous_mode)
572f1d8a071SWilliam Breathitt Gray {
573aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
574f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
575daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
57609db4678SWilliam Breathitt Gray 	unsigned long irqflags;
577fc069262SSyed Nayyar Waris 	unsigned int idr_cfg = synchronous_mode;
578fc069262SSyed Nayyar Waris 
57909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
580fc069262SSyed Nayyar Waris 
581fc069262SSyed Nayyar Waris 	idr_cfg |= priv->index_polarity[channel_id] << 1;
582f1d8a071SWilliam Breathitt Gray 
583f1d8a071SWilliam Breathitt Gray 	/* Index function must be non-synchronous in non-quadrature mode */
584fc069262SSyed Nayyar Waris 	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
58509db4678SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
586f1d8a071SWilliam Breathitt Gray 		return -EINVAL;
587fc069262SSyed Nayyar Waris 	}
588f1d8a071SWilliam Breathitt Gray 
589f1d8a071SWilliam Breathitt Gray 	priv->synchronous_mode[channel_id] = synchronous_mode;
590f1d8a071SWilliam Breathitt Gray 
591f1d8a071SWilliam Breathitt Gray 	/* Load Index Control configuration to Index Control Register */
592daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
593f1d8a071SWilliam Breathitt Gray 
59409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
595fc069262SSyed Nayyar Waris 
596f1d8a071SWilliam Breathitt Gray 	return 0;
597f1d8a071SWilliam Breathitt Gray }
598f1d8a071SWilliam Breathitt Gray 
599aaec1a0fSWilliam Breathitt Gray static int quad8_count_floor_read(struct counter_device *counter,
600aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count, u64 *floor)
601f1d8a071SWilliam Breathitt Gray {
602f1d8a071SWilliam Breathitt Gray 	/* Only a floor of 0 is supported */
603aaec1a0fSWilliam Breathitt Gray 	*floor = 0;
604aaec1a0fSWilliam Breathitt Gray 
605aaec1a0fSWilliam Breathitt Gray 	return 0;
606f1d8a071SWilliam Breathitt Gray }
607f1d8a071SWilliam Breathitt Gray 
608aaec1a0fSWilliam Breathitt Gray static int quad8_count_mode_read(struct counter_device *counter,
609aaec1a0fSWilliam Breathitt Gray 				 struct counter_count *count,
610aaec1a0fSWilliam Breathitt Gray 				 enum counter_count_mode *cnt_mode)
611f1d8a071SWilliam Breathitt Gray {
612aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
613f1d8a071SWilliam Breathitt Gray 
614f1d8a071SWilliam Breathitt Gray 	/* Map 104-QUAD-8 count mode to Generic Counter count mode */
615f1d8a071SWilliam Breathitt Gray 	switch (priv->count_mode[count->id]) {
616f1d8a071SWilliam Breathitt Gray 	case 0:
617f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
618f1d8a071SWilliam Breathitt Gray 		break;
619f1d8a071SWilliam Breathitt Gray 	case 1:
620f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
621f1d8a071SWilliam Breathitt Gray 		break;
622f1d8a071SWilliam Breathitt Gray 	case 2:
623f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
624f1d8a071SWilliam Breathitt Gray 		break;
625f1d8a071SWilliam Breathitt Gray 	case 3:
626f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
627f1d8a071SWilliam Breathitt Gray 		break;
628f1d8a071SWilliam Breathitt Gray 	}
629f1d8a071SWilliam Breathitt Gray 
630f1d8a071SWilliam Breathitt Gray 	return 0;
631f1d8a071SWilliam Breathitt Gray }
632f1d8a071SWilliam Breathitt Gray 
633aaec1a0fSWilliam Breathitt Gray static int quad8_count_mode_write(struct counter_device *counter,
634aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count,
635aaec1a0fSWilliam Breathitt Gray 				  enum counter_count_mode cnt_mode)
636f1d8a071SWilliam Breathitt Gray {
637aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
638aaec1a0fSWilliam Breathitt Gray 	unsigned int count_mode;
639f1d8a071SWilliam Breathitt Gray 	unsigned int mode_cfg;
640daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
64109db4678SWilliam Breathitt Gray 	unsigned long irqflags;
642f1d8a071SWilliam Breathitt Gray 
643f1d8a071SWilliam Breathitt Gray 	/* Map Generic Counter count mode to 104-QUAD-8 count mode */
644f1d8a071SWilliam Breathitt Gray 	switch (cnt_mode) {
645f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_NORMAL:
646aaec1a0fSWilliam Breathitt Gray 		count_mode = 0;
647f1d8a071SWilliam Breathitt Gray 		break;
648f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_RANGE_LIMIT:
649aaec1a0fSWilliam Breathitt Gray 		count_mode = 1;
650f1d8a071SWilliam Breathitt Gray 		break;
651f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_NON_RECYCLE:
652aaec1a0fSWilliam Breathitt Gray 		count_mode = 2;
653f1d8a071SWilliam Breathitt Gray 		break;
654f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_MODULO_N:
655aaec1a0fSWilliam Breathitt Gray 		count_mode = 3;
656f1d8a071SWilliam Breathitt Gray 		break;
657b11eed15SWilliam Breathitt Gray 	default:
658b11eed15SWilliam Breathitt Gray 		/* should never reach this path */
659b11eed15SWilliam Breathitt Gray 		return -EINVAL;
660f1d8a071SWilliam Breathitt Gray 	}
661f1d8a071SWilliam Breathitt Gray 
66209db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
663fc069262SSyed Nayyar Waris 
664aaec1a0fSWilliam Breathitt Gray 	priv->count_mode[count->id] = count_mode;
665f1d8a071SWilliam Breathitt Gray 
666f1d8a071SWilliam Breathitt Gray 	/* Set count mode configuration value */
667aaec1a0fSWilliam Breathitt Gray 	mode_cfg = count_mode << 1;
668f1d8a071SWilliam Breathitt Gray 
669f1d8a071SWilliam Breathitt Gray 	/* Add quadrature mode configuration */
670f1d8a071SWilliam Breathitt Gray 	if (priv->quadrature_mode[count->id])
671f1d8a071SWilliam Breathitt Gray 		mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
672f1d8a071SWilliam Breathitt Gray 
673f1d8a071SWilliam Breathitt Gray 	/* Load mode configuration to Counter Mode Register */
674daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
675f1d8a071SWilliam Breathitt Gray 
67609db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
677fc069262SSyed Nayyar Waris 
678f1d8a071SWilliam Breathitt Gray 	return 0;
679f1d8a071SWilliam Breathitt Gray }
680f1d8a071SWilliam Breathitt Gray 
681aaec1a0fSWilliam Breathitt Gray static int quad8_count_enable_read(struct counter_device *counter,
682aaec1a0fSWilliam Breathitt Gray 				   struct counter_count *count, u8 *enable)
683f1d8a071SWilliam Breathitt Gray {
684aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
685f1d8a071SWilliam Breathitt Gray 
686aaec1a0fSWilliam Breathitt Gray 	*enable = priv->ab_enable[count->id];
687aaec1a0fSWilliam Breathitt Gray 
688aaec1a0fSWilliam Breathitt Gray 	return 0;
689f1d8a071SWilliam Breathitt Gray }
690f1d8a071SWilliam Breathitt Gray 
691aaec1a0fSWilliam Breathitt Gray static int quad8_count_enable_write(struct counter_device *counter,
692aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u8 enable)
693f1d8a071SWilliam Breathitt Gray {
694aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
695daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
69609db4678SWilliam Breathitt Gray 	unsigned long irqflags;
697f1d8a071SWilliam Breathitt Gray 	unsigned int ior_cfg;
698f1d8a071SWilliam Breathitt Gray 
69909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
700fc069262SSyed Nayyar Waris 
701aaec1a0fSWilliam Breathitt Gray 	priv->ab_enable[count->id] = enable;
702f1d8a071SWilliam Breathitt Gray 
7037aa2ba0dSWilliam Breathitt Gray 	ior_cfg = enable | priv->preset_enable[count->id] << 1 |
7047aa2ba0dSWilliam Breathitt Gray 		  priv->irq_trigger[count->id] << 3;
705f1d8a071SWilliam Breathitt Gray 
706f1d8a071SWilliam Breathitt Gray 	/* Load I/O control configuration */
707daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
708f1d8a071SWilliam Breathitt Gray 
70909db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
710fc069262SSyed Nayyar Waris 
711aaec1a0fSWilliam Breathitt Gray 	return 0;
712f1d8a071SWilliam Breathitt Gray }
713f1d8a071SWilliam Breathitt Gray 
714e357e81fSWilliam Breathitt Gray static const char *const quad8_noise_error_states[] = {
715e357e81fSWilliam Breathitt Gray 	"No excessive noise is present at the count inputs",
716e357e81fSWilliam Breathitt Gray 	"Excessive noise is present at the count inputs"
717e357e81fSWilliam Breathitt Gray };
718e357e81fSWilliam Breathitt Gray 
719f1d8a071SWilliam Breathitt Gray static int quad8_error_noise_get(struct counter_device *counter,
720aaec1a0fSWilliam Breathitt Gray 				 struct counter_count *count, u32 *noise_error)
721f1d8a071SWilliam Breathitt Gray {
722aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
723daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
724f1d8a071SWilliam Breathitt Gray 
725daae1ee5SWilliam Breathitt Gray 	*noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E);
726f1d8a071SWilliam Breathitt Gray 
727f1d8a071SWilliam Breathitt Gray 	return 0;
728f1d8a071SWilliam Breathitt Gray }
729f1d8a071SWilliam Breathitt Gray 
730aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_read(struct counter_device *counter,
731aaec1a0fSWilliam Breathitt Gray 				   struct counter_count *count, u64 *preset)
732f1d8a071SWilliam Breathitt Gray {
733aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
734f1d8a071SWilliam Breathitt Gray 
735aaec1a0fSWilliam Breathitt Gray 	*preset = priv->preset[count->id];
736aaec1a0fSWilliam Breathitt Gray 
737aaec1a0fSWilliam Breathitt Gray 	return 0;
738f1d8a071SWilliam Breathitt Gray }
739f1d8a071SWilliam Breathitt Gray 
740e612b600SWilliam Breathitt Gray static void quad8_preset_register_set(struct quad8 *const priv, const int id,
741e612b600SWilliam Breathitt Gray 				      const unsigned int preset)
742fc069262SSyed Nayyar Waris {
743daae1ee5SWilliam Breathitt Gray 	struct channel_reg __iomem *const chan = priv->reg->channel + id;
744fc069262SSyed Nayyar Waris 	int i;
745fc069262SSyed Nayyar Waris 
746e357e81fSWilliam Breathitt Gray 	priv->preset[id] = preset;
747fc069262SSyed Nayyar Waris 
748fc069262SSyed Nayyar Waris 	/* Reset Byte Pointer */
749daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
750fc069262SSyed Nayyar Waris 
751fc069262SSyed Nayyar Waris 	/* Set Preset Register */
752fc069262SSyed Nayyar Waris 	for (i = 0; i < 3; i++)
753daae1ee5SWilliam Breathitt Gray 		iowrite8(preset >> (8 * i), &chan->data);
754fc069262SSyed Nayyar Waris }
755fc069262SSyed Nayyar Waris 
756aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_write(struct counter_device *counter,
757aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u64 preset)
758f1d8a071SWilliam Breathitt Gray {
759aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
76009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
761f1d8a071SWilliam Breathitt Gray 
762f1d8a071SWilliam Breathitt Gray 	/* Only 24-bit values are supported */
763f1d8a071SWilliam Breathitt Gray 	if (preset > 0xFFFFFF)
764e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
765f1d8a071SWilliam Breathitt Gray 
76609db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
767f1d8a071SWilliam Breathitt Gray 
768fc069262SSyed Nayyar Waris 	quad8_preset_register_set(priv, count->id, preset);
769f1d8a071SWilliam Breathitt Gray 
77009db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
771f1d8a071SWilliam Breathitt Gray 
772aaec1a0fSWilliam Breathitt Gray 	return 0;
773f1d8a071SWilliam Breathitt Gray }
774f1d8a071SWilliam Breathitt Gray 
775aaec1a0fSWilliam Breathitt Gray static int quad8_count_ceiling_read(struct counter_device *counter,
776aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u64 *ceiling)
777f1d8a071SWilliam Breathitt Gray {
778aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
77909db4678SWilliam Breathitt Gray 	unsigned long irqflags;
780fc069262SSyed Nayyar Waris 
78109db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
782f1d8a071SWilliam Breathitt Gray 
783f1d8a071SWilliam Breathitt Gray 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
784f1d8a071SWilliam Breathitt Gray 	switch (priv->count_mode[count->id]) {
785f1d8a071SWilliam Breathitt Gray 	case 1:
786f1d8a071SWilliam Breathitt Gray 	case 3:
787aaec1a0fSWilliam Breathitt Gray 		*ceiling = priv->preset[count->id];
788aaec1a0fSWilliam Breathitt Gray 		break;
789aaec1a0fSWilliam Breathitt Gray 	default:
790f1d8a071SWilliam Breathitt Gray 		/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
791aaec1a0fSWilliam Breathitt Gray 		*ceiling = 0x1FFFFFF;
792aaec1a0fSWilliam Breathitt Gray 		break;
793f1d8a071SWilliam Breathitt Gray 	}
794f1d8a071SWilliam Breathitt Gray 
79509db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
796aaec1a0fSWilliam Breathitt Gray 
797aaec1a0fSWilliam Breathitt Gray 	return 0;
798aaec1a0fSWilliam Breathitt Gray }
799aaec1a0fSWilliam Breathitt Gray 
800aaec1a0fSWilliam Breathitt Gray static int quad8_count_ceiling_write(struct counter_device *counter,
801aaec1a0fSWilliam Breathitt Gray 				     struct counter_count *count, u64 ceiling)
802f1d8a071SWilliam Breathitt Gray {
803aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
80409db4678SWilliam Breathitt Gray 	unsigned long irqflags;
805fc069262SSyed Nayyar Waris 
806fc069262SSyed Nayyar Waris 	/* Only 24-bit values are supported */
807fc069262SSyed Nayyar Waris 	if (ceiling > 0xFFFFFF)
808e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
809fc069262SSyed Nayyar Waris 
81009db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
811f1d8a071SWilliam Breathitt Gray 
812f1d8a071SWilliam Breathitt Gray 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
813f1d8a071SWilliam Breathitt Gray 	switch (priv->count_mode[count->id]) {
814f1d8a071SWilliam Breathitt Gray 	case 1:
815f1d8a071SWilliam Breathitt Gray 	case 3:
816fc069262SSyed Nayyar Waris 		quad8_preset_register_set(priv, count->id, ceiling);
81709db4678SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
818aaec1a0fSWilliam Breathitt Gray 		return 0;
819f1d8a071SWilliam Breathitt Gray 	}
820f1d8a071SWilliam Breathitt Gray 
82109db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
822fc069262SSyed Nayyar Waris 
823728246e8SWilliam Breathitt Gray 	return -EINVAL;
824f1d8a071SWilliam Breathitt Gray }
825f1d8a071SWilliam Breathitt Gray 
826aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_enable_read(struct counter_device *counter,
827aaec1a0fSWilliam Breathitt Gray 					  struct counter_count *count,
828aaec1a0fSWilliam Breathitt Gray 					  u8 *preset_enable)
829f1d8a071SWilliam Breathitt Gray {
830aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
831f1d8a071SWilliam Breathitt Gray 
832aaec1a0fSWilliam Breathitt Gray 	*preset_enable = !priv->preset_enable[count->id];
833aaec1a0fSWilliam Breathitt Gray 
834aaec1a0fSWilliam Breathitt Gray 	return 0;
835f1d8a071SWilliam Breathitt Gray }
836f1d8a071SWilliam Breathitt Gray 
837aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_enable_write(struct counter_device *counter,
838aaec1a0fSWilliam Breathitt Gray 					   struct counter_count *count,
839aaec1a0fSWilliam Breathitt Gray 					   u8 preset_enable)
840f1d8a071SWilliam Breathitt Gray {
841aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
842daae1ee5SWilliam Breathitt Gray 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
84309db4678SWilliam Breathitt Gray 	unsigned long irqflags;
844f1d8a071SWilliam Breathitt Gray 	unsigned int ior_cfg;
845f1d8a071SWilliam Breathitt Gray 
846f1d8a071SWilliam Breathitt Gray 	/* Preset enable is active low in Input/Output Control register */
847f1d8a071SWilliam Breathitt Gray 	preset_enable = !preset_enable;
848f1d8a071SWilliam Breathitt Gray 
84909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
850fc069262SSyed Nayyar Waris 
851f1d8a071SWilliam Breathitt Gray 	priv->preset_enable[count->id] = preset_enable;
852f1d8a071SWilliam Breathitt Gray 
8537aa2ba0dSWilliam Breathitt Gray 	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
8547aa2ba0dSWilliam Breathitt Gray 		  priv->irq_trigger[count->id] << 3;
855f1d8a071SWilliam Breathitt Gray 
856f1d8a071SWilliam Breathitt Gray 	/* Load I/O control configuration to Input / Output Control Register */
857daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
858f1d8a071SWilliam Breathitt Gray 
85909db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
860fc069262SSyed Nayyar Waris 
861aaec1a0fSWilliam Breathitt Gray 	return 0;
862f1d8a071SWilliam Breathitt Gray }
863f1d8a071SWilliam Breathitt Gray 
864aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_read(struct counter_device *counter,
865954ab5ccSWilliam Breathitt Gray 					 struct counter_signal *signal,
866aaec1a0fSWilliam Breathitt Gray 					 u8 *cable_fault)
867954ab5ccSWilliam Breathitt Gray {
868aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
869954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
87009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
871708d9893SSyed Nayyar Waris 	bool disabled;
872954ab5ccSWilliam Breathitt Gray 	unsigned int status;
873954ab5ccSWilliam Breathitt Gray 
87409db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
875708d9893SSyed Nayyar Waris 
876708d9893SSyed Nayyar Waris 	disabled = !(priv->cable_fault_enable & BIT(channel_id));
877708d9893SSyed Nayyar Waris 
878708d9893SSyed Nayyar Waris 	if (disabled) {
87909db4678SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
880954ab5ccSWilliam Breathitt Gray 		return -EINVAL;
881708d9893SSyed Nayyar Waris 	}
882954ab5ccSWilliam Breathitt Gray 
883954ab5ccSWilliam Breathitt Gray 	/* Logic 0 = cable fault */
884daae1ee5SWilliam Breathitt Gray 	status = ioread8(&priv->reg->cable_status);
885954ab5ccSWilliam Breathitt Gray 
88609db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
887708d9893SSyed Nayyar Waris 
888954ab5ccSWilliam Breathitt Gray 	/* Mask respective channel and invert logic */
889aaec1a0fSWilliam Breathitt Gray 	*cable_fault = !(status & BIT(channel_id));
890954ab5ccSWilliam Breathitt Gray 
891aaec1a0fSWilliam Breathitt Gray 	return 0;
892954ab5ccSWilliam Breathitt Gray }
893954ab5ccSWilliam Breathitt Gray 
894aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_enable_read(struct counter_device *counter,
895aaec1a0fSWilliam Breathitt Gray 						struct counter_signal *signal,
896aaec1a0fSWilliam Breathitt Gray 						u8 *enable)
897954ab5ccSWilliam Breathitt Gray {
898aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
899954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
900954ab5ccSWilliam Breathitt Gray 
901aaec1a0fSWilliam Breathitt Gray 	*enable = !!(priv->cable_fault_enable & BIT(channel_id));
902aaec1a0fSWilliam Breathitt Gray 
903aaec1a0fSWilliam Breathitt Gray 	return 0;
904954ab5ccSWilliam Breathitt Gray }
905954ab5ccSWilliam Breathitt Gray 
906aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
907aaec1a0fSWilliam Breathitt Gray 						 struct counter_signal *signal,
908aaec1a0fSWilliam Breathitt Gray 						 u8 enable)
909954ab5ccSWilliam Breathitt Gray {
910aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
911954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
91209db4678SWilliam Breathitt Gray 	unsigned long irqflags;
913954ab5ccSWilliam Breathitt Gray 	unsigned int cable_fault_enable;
914954ab5ccSWilliam Breathitt Gray 
91509db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
916708d9893SSyed Nayyar Waris 
917954ab5ccSWilliam Breathitt Gray 	if (enable)
918954ab5ccSWilliam Breathitt Gray 		priv->cable_fault_enable |= BIT(channel_id);
919954ab5ccSWilliam Breathitt Gray 	else
920954ab5ccSWilliam Breathitt Gray 		priv->cable_fault_enable &= ~BIT(channel_id);
921954ab5ccSWilliam Breathitt Gray 
922954ab5ccSWilliam Breathitt Gray 	/* Enable is active low in Differential Encoder Cable Status register */
923954ab5ccSWilliam Breathitt Gray 	cable_fault_enable = ~priv->cable_fault_enable;
924954ab5ccSWilliam Breathitt Gray 
925daae1ee5SWilliam Breathitt Gray 	iowrite8(cable_fault_enable, &priv->reg->cable_status);
926954ab5ccSWilliam Breathitt Gray 
92709db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
928708d9893SSyed Nayyar Waris 
929aaec1a0fSWilliam Breathitt Gray 	return 0;
930954ab5ccSWilliam Breathitt Gray }
931954ab5ccSWilliam Breathitt Gray 
932aaec1a0fSWilliam Breathitt Gray static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
933aaec1a0fSWilliam Breathitt Gray 					   struct counter_signal *signal,
934aaec1a0fSWilliam Breathitt Gray 					   u8 *prescaler)
935de65d055SWilliam Breathitt Gray {
936aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
937de65d055SWilliam Breathitt Gray 
938aaec1a0fSWilliam Breathitt Gray 	*prescaler = priv->fck_prescaler[signal->id / 2];
939aaec1a0fSWilliam Breathitt Gray 
940aaec1a0fSWilliam Breathitt Gray 	return 0;
941de65d055SWilliam Breathitt Gray }
942de65d055SWilliam Breathitt Gray 
943aaec1a0fSWilliam Breathitt Gray static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
944aaec1a0fSWilliam Breathitt Gray 					    struct counter_signal *signal,
945aaec1a0fSWilliam Breathitt Gray 					    u8 prescaler)
946de65d055SWilliam Breathitt Gray {
947aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
948de65d055SWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
949daae1ee5SWilliam Breathitt Gray 	struct channel_reg __iomem *const chan = priv->reg->channel + channel_id;
95009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
951de65d055SWilliam Breathitt Gray 
95209db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
953d5ed76adSSyed Nayyar Waris 
954de65d055SWilliam Breathitt Gray 	priv->fck_prescaler[channel_id] = prescaler;
955de65d055SWilliam Breathitt Gray 
956de65d055SWilliam Breathitt Gray 	/* Reset Byte Pointer */
957daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
958de65d055SWilliam Breathitt Gray 
959de65d055SWilliam Breathitt Gray 	/* Set filter clock factor */
960daae1ee5SWilliam Breathitt Gray 	iowrite8(prescaler, &chan->data);
961b6e9cdedSWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
962daae1ee5SWilliam Breathitt Gray 		 &chan->control);
963de65d055SWilliam Breathitt Gray 
96409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
965d5ed76adSSyed Nayyar Waris 
966aaec1a0fSWilliam Breathitt Gray 	return 0;
967de65d055SWilliam Breathitt Gray }
968de65d055SWilliam Breathitt Gray 
969aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_signal_ext[] = {
970aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_BOOL("cable_fault", quad8_signal_cable_fault_read,
971aaec1a0fSWilliam Breathitt Gray 				 NULL),
972aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_BOOL("cable_fault_enable",
973aaec1a0fSWilliam Breathitt Gray 				 quad8_signal_cable_fault_enable_read,
974aaec1a0fSWilliam Breathitt Gray 				 quad8_signal_cable_fault_enable_write),
975aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_U8("filter_clock_prescaler",
976aaec1a0fSWilliam Breathitt Gray 			       quad8_signal_fck_prescaler_read,
977aaec1a0fSWilliam Breathitt Gray 			       quad8_signal_fck_prescaler_write)
978de65d055SWilliam Breathitt Gray };
979de65d055SWilliam Breathitt Gray 
980aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
981aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
982aaec1a0fSWilliam Breathitt Gray 
983aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_index_ext[] = {
984aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get,
985aaec1a0fSWilliam Breathitt Gray 				 quad8_index_polarity_set,
986aaec1a0fSWilliam Breathitt Gray 				 quad8_index_pol_enum),
987aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get,
988aaec1a0fSWilliam Breathitt Gray 				 quad8_synchronous_mode_set,
989aaec1a0fSWilliam Breathitt Gray 				 quad8_synch_mode_enum),
990f1d8a071SWilliam Breathitt Gray };
991f1d8a071SWilliam Breathitt Gray 
992f1d8a071SWilliam Breathitt Gray #define QUAD8_QUAD_SIGNAL(_id, _name) {		\
993f1d8a071SWilliam Breathitt Gray 	.id = (_id),				\
994de65d055SWilliam Breathitt Gray 	.name = (_name),			\
995de65d055SWilliam Breathitt Gray 	.ext = quad8_signal_ext,		\
996de65d055SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_signal_ext)	\
997f1d8a071SWilliam Breathitt Gray }
998f1d8a071SWilliam Breathitt Gray 
999f1d8a071SWilliam Breathitt Gray #define	QUAD8_INDEX_SIGNAL(_id, _name) {	\
1000f1d8a071SWilliam Breathitt Gray 	.id = (_id),				\
1001f1d8a071SWilliam Breathitt Gray 	.name = (_name),			\
1002f1d8a071SWilliam Breathitt Gray 	.ext = quad8_index_ext,			\
1003f1d8a071SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_index_ext)	\
1004f1d8a071SWilliam Breathitt Gray }
1005f1d8a071SWilliam Breathitt Gray 
1006f1d8a071SWilliam Breathitt Gray static struct counter_signal quad8_signals[] = {
1007f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1008f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1009f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1010f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1011f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1012f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1013f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1014f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1015f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1016f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1017f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1018f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1019f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1020f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1021f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1022f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1023f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1024f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1025f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1026f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1027f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1028f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1029f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1030f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1031f1d8a071SWilliam Breathitt Gray };
1032f1d8a071SWilliam Breathitt Gray 
1033f1d8a071SWilliam Breathitt Gray #define QUAD8_COUNT_SYNAPSES(_id) {					\
1034f1d8a071SWilliam Breathitt Gray 	{								\
1035f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_synapse_actions_list,		\
1036f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1037f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id)			\
1038f1d8a071SWilliam Breathitt Gray 	},								\
1039f1d8a071SWilliam Breathitt Gray 	{								\
1040f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_synapse_actions_list,		\
1041f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1042f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id) + 1			\
1043f1d8a071SWilliam Breathitt Gray 	},								\
1044f1d8a071SWilliam Breathitt Gray 	{								\
1045f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_index_actions_list,		\
1046f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_index_actions_list),	\
1047f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id) + 16		\
1048f1d8a071SWilliam Breathitt Gray 	}								\
1049f1d8a071SWilliam Breathitt Gray }
1050f1d8a071SWilliam Breathitt Gray 
1051f1d8a071SWilliam Breathitt Gray static struct counter_synapse quad8_count_synapses[][3] = {
1052f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1053f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1054f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1055f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1056f1d8a071SWilliam Breathitt Gray };
1057f1d8a071SWilliam Breathitt Gray 
1058aaec1a0fSWilliam Breathitt Gray static const enum counter_count_mode quad8_cnt_modes[] = {
1059aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_NORMAL,
1060aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_RANGE_LIMIT,
1061aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_NON_RECYCLE,
1062aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_MODULO_N,
1063aaec1a0fSWilliam Breathitt Gray };
1064aaec1a0fSWilliam Breathitt Gray 
1065aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_AVAILABLE(quad8_count_mode_available, quad8_cnt_modes);
1066aaec1a0fSWilliam Breathitt Gray 
1067aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_error_noise_enum, quad8_noise_error_states);
1068aaec1a0fSWilliam Breathitt Gray 
1069aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_count_ext[] = {
1070aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_CEILING(quad8_count_ceiling_read,
1071aaec1a0fSWilliam Breathitt Gray 			     quad8_count_ceiling_write),
1072aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_FLOOR(quad8_count_floor_read, NULL),
1073aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_MODE(quad8_count_mode_read, quad8_count_mode_write,
1074aaec1a0fSWilliam Breathitt Gray 				quad8_count_mode_available),
1075aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_DIRECTION(quad8_direction_read),
1076aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_ENABLE(quad8_count_enable_read, quad8_count_enable_write),
1077aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_ENUM("error_noise", quad8_error_noise_get, NULL,
1078aaec1a0fSWilliam Breathitt Gray 				quad8_error_noise_enum),
1079aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_PRESET(quad8_count_preset_read, quad8_count_preset_write),
1080aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_PRESET_ENABLE(quad8_count_preset_enable_read,
1081aaec1a0fSWilliam Breathitt Gray 				   quad8_count_preset_enable_write),
1082f1d8a071SWilliam Breathitt Gray };
1083f1d8a071SWilliam Breathitt Gray 
1084f1d8a071SWilliam Breathitt Gray #define QUAD8_COUNT(_id, _cntname) {					\
1085f1d8a071SWilliam Breathitt Gray 	.id = (_id),							\
1086f1d8a071SWilliam Breathitt Gray 	.name = (_cntname),						\
1087f1d8a071SWilliam Breathitt Gray 	.functions_list = quad8_count_functions_list,			\
1088f1d8a071SWilliam Breathitt Gray 	.num_functions = ARRAY_SIZE(quad8_count_functions_list),	\
1089f1d8a071SWilliam Breathitt Gray 	.synapses = quad8_count_synapses[(_id)],			\
1090f1d8a071SWilliam Breathitt Gray 	.num_synapses =	2,						\
1091f1d8a071SWilliam Breathitt Gray 	.ext = quad8_count_ext,						\
1092f1d8a071SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_count_ext)				\
1093f1d8a071SWilliam Breathitt Gray }
1094f1d8a071SWilliam Breathitt Gray 
1095f1d8a071SWilliam Breathitt Gray static struct counter_count quad8_counts[] = {
1096f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(0, "Channel 1 Count"),
1097f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(1, "Channel 2 Count"),
1098f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(2, "Channel 3 Count"),
1099f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(3, "Channel 4 Count"),
1100f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(4, "Channel 5 Count"),
1101f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(5, "Channel 6 Count"),
1102f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(6, "Channel 7 Count"),
1103f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(7, "Channel 8 Count")
1104f1d8a071SWilliam Breathitt Gray };
1105f1d8a071SWilliam Breathitt Gray 
11067aa2ba0dSWilliam Breathitt Gray static irqreturn_t quad8_irq_handler(int irq, void *private)
11077aa2ba0dSWilliam Breathitt Gray {
11089e884bb1SUwe Kleine-König 	struct counter_device *counter = private;
11099e884bb1SUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
11107aa2ba0dSWilliam Breathitt Gray 	unsigned long irq_status;
11117aa2ba0dSWilliam Breathitt Gray 	unsigned long channel;
11127aa2ba0dSWilliam Breathitt Gray 	u8 event;
11137aa2ba0dSWilliam Breathitt Gray 
1114daae1ee5SWilliam Breathitt Gray 	irq_status = ioread8(&priv->reg->interrupt_status);
11157aa2ba0dSWilliam Breathitt Gray 	if (!irq_status)
11167aa2ba0dSWilliam Breathitt Gray 		return IRQ_NONE;
11177aa2ba0dSWilliam Breathitt Gray 
11187aa2ba0dSWilliam Breathitt Gray 	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
11197aa2ba0dSWilliam Breathitt Gray 		switch (priv->irq_trigger[channel]) {
11207aa2ba0dSWilliam Breathitt Gray 		case QUAD8_EVENT_CARRY:
11217aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_OVERFLOW;
11227aa2ba0dSWilliam Breathitt Gray 				break;
11237aa2ba0dSWilliam Breathitt Gray 		case QUAD8_EVENT_COMPARE:
11247aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_THRESHOLD;
11257aa2ba0dSWilliam Breathitt Gray 				break;
11267aa2ba0dSWilliam Breathitt Gray 		case QUAD8_EVENT_CARRY_BORROW:
11277aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
11287aa2ba0dSWilliam Breathitt Gray 				break;
11297aa2ba0dSWilliam Breathitt Gray 		case QUAD8_EVENT_INDEX:
11307aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_INDEX;
11317aa2ba0dSWilliam Breathitt Gray 				break;
11327aa2ba0dSWilliam Breathitt Gray 		default:
11337aa2ba0dSWilliam Breathitt Gray 			/* should never reach this path */
11347aa2ba0dSWilliam Breathitt Gray 			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
11357aa2ba0dSWilliam Breathitt Gray 				  priv->irq_trigger[channel], channel);
11367aa2ba0dSWilliam Breathitt Gray 			continue;
11377aa2ba0dSWilliam Breathitt Gray 		}
11387aa2ba0dSWilliam Breathitt Gray 
11399e884bb1SUwe Kleine-König 		counter_push_event(counter, event, channel);
11407aa2ba0dSWilliam Breathitt Gray 	}
11417aa2ba0dSWilliam Breathitt Gray 
11427aa2ba0dSWilliam Breathitt Gray 	/* Clear pending interrupts on device */
1143daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
11447aa2ba0dSWilliam Breathitt Gray 
11457aa2ba0dSWilliam Breathitt Gray 	return IRQ_HANDLED;
11467aa2ba0dSWilliam Breathitt Gray }
11477aa2ba0dSWilliam Breathitt Gray 
1148daae1ee5SWilliam Breathitt Gray static void quad8_init_counter(struct channel_reg __iomem *const chan)
1149b6e9cdedSWilliam Breathitt Gray {
1150b6e9cdedSWilliam Breathitt Gray 	unsigned long i;
1151b6e9cdedSWilliam Breathitt Gray 
1152b6e9cdedSWilliam Breathitt Gray 	/* Reset Byte Pointer */
1153daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
1154b6e9cdedSWilliam Breathitt Gray 	/* Reset filter clock factor */
1155daae1ee5SWilliam Breathitt Gray 	iowrite8(0, &chan->data);
1156b6e9cdedSWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
1157daae1ee5SWilliam Breathitt Gray 		 &chan->control);
1158b6e9cdedSWilliam Breathitt Gray 	/* Reset Byte Pointer */
1159daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
1160b6e9cdedSWilliam Breathitt Gray 	/* Reset Preset Register */
1161b6e9cdedSWilliam Breathitt Gray 	for (i = 0; i < 3; i++)
1162daae1ee5SWilliam Breathitt Gray 		iowrite8(0x00, &chan->data);
1163b6e9cdedSWilliam Breathitt Gray 	/* Reset Borrow, Carry, Compare, and Sign flags */
1164daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
1165b6e9cdedSWilliam Breathitt Gray 	/* Reset Error flag */
1166daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
1167b6e9cdedSWilliam Breathitt Gray 	/* Binary encoding; Normal count; non-quadrature mode */
1168daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_CMR, &chan->control);
1169b6e9cdedSWilliam Breathitt Gray 	/* Disable A and B inputs; preset on index; FLG1 as Carry */
1170daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IOR, &chan->control);
1171b6e9cdedSWilliam Breathitt Gray 	/* Disable index function; negative index polarity */
1172daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CTR_IDR, &chan->control);
1173b6e9cdedSWilliam Breathitt Gray }
1174b6e9cdedSWilliam Breathitt Gray 
1175f1d8a071SWilliam Breathitt Gray static int quad8_probe(struct device *dev, unsigned int id)
1176f1d8a071SWilliam Breathitt Gray {
11779e884bb1SUwe Kleine-König 	struct counter_device *counter;
1178e357e81fSWilliam Breathitt Gray 	struct quad8 *priv;
1179b6e9cdedSWilliam Breathitt Gray 	unsigned long i;
11807aa2ba0dSWilliam Breathitt Gray 	int err;
1181f1d8a071SWilliam Breathitt Gray 
1182f1d8a071SWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
1183f1d8a071SWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1184f1d8a071SWilliam Breathitt Gray 			base[id], base[id] + QUAD8_EXTENT);
1185f1d8a071SWilliam Breathitt Gray 		return -EBUSY;
1186f1d8a071SWilliam Breathitt Gray 	}
1187f1d8a071SWilliam Breathitt Gray 
11889e884bb1SUwe Kleine-König 	counter = devm_counter_alloc(dev, sizeof(*priv));
11899e884bb1SUwe Kleine-König 	if (!counter)
1190f1d8a071SWilliam Breathitt Gray 		return -ENOMEM;
11919e884bb1SUwe Kleine-König 	priv = counter_priv(counter);
1192f1d8a071SWilliam Breathitt Gray 
1193daae1ee5SWilliam Breathitt Gray 	priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
1194daae1ee5SWilliam Breathitt Gray 	if (!priv->reg)
1195b6e9cdedSWilliam Breathitt Gray 		return -ENOMEM;
1196b6e9cdedSWilliam Breathitt Gray 
1197f1d8a071SWilliam Breathitt Gray 	/* Initialize Counter device and driver data */
11989e884bb1SUwe Kleine-König 	counter->name = dev_name(dev);
11999e884bb1SUwe Kleine-König 	counter->parent = dev;
12009e884bb1SUwe Kleine-König 	counter->ops = &quad8_ops;
12019e884bb1SUwe Kleine-König 	counter->counts = quad8_counts;
12029e884bb1SUwe Kleine-König 	counter->num_counts = ARRAY_SIZE(quad8_counts);
12039e884bb1SUwe Kleine-König 	counter->signals = quad8_signals;
12049e884bb1SUwe Kleine-König 	counter->num_signals = ARRAY_SIZE(quad8_signals);
1205f1d8a071SWilliam Breathitt Gray 
120609db4678SWilliam Breathitt Gray 	spin_lock_init(&priv->lock);
1207fc069262SSyed Nayyar Waris 
12087aa2ba0dSWilliam Breathitt Gray 	/* Reset Index/Interrupt Register */
1209daae1ee5SWilliam Breathitt Gray 	iowrite8(0x00, &priv->reg->index_interrupt);
1210f1d8a071SWilliam Breathitt Gray 	/* Reset all counters and disable interrupt function */
1211daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper);
1212f1d8a071SWilliam Breathitt Gray 	/* Set initial configuration for all counters */
1213b6e9cdedSWilliam Breathitt Gray 	for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
1214daae1ee5SWilliam Breathitt Gray 		quad8_init_counter(priv->reg->channel + i);
1215954ab5ccSWilliam Breathitt Gray 	/* Disable Differential Encoder Cable Status for all channels */
1216daae1ee5SWilliam Breathitt Gray 	iowrite8(0xFF, &priv->reg->cable_status);
12177aa2ba0dSWilliam Breathitt Gray 	/* Enable all counters and enable interrupt function */
1218daae1ee5SWilliam Breathitt Gray 	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
12197aa2ba0dSWilliam Breathitt Gray 
1220663d8fb0SWilliam Breathitt Gray 	err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
1221663d8fb0SWilliam Breathitt Gray 			       IRQF_SHARED, counter->name, counter);
12227aa2ba0dSWilliam Breathitt Gray 	if (err)
12237aa2ba0dSWilliam Breathitt Gray 		return err;
1224f1d8a071SWilliam Breathitt Gray 
12259e884bb1SUwe Kleine-König 	err = devm_counter_add(dev, counter);
12269e884bb1SUwe Kleine-König 	if (err < 0)
12279e884bb1SUwe Kleine-König 		return dev_err_probe(dev, err, "Failed to add counter\n");
12289e884bb1SUwe Kleine-König 
12299e884bb1SUwe Kleine-König 	return 0;
1230f1d8a071SWilliam Breathitt Gray }
1231f1d8a071SWilliam Breathitt Gray 
1232f1d8a071SWilliam Breathitt Gray static struct isa_driver quad8_driver = {
1233f1d8a071SWilliam Breathitt Gray 	.probe = quad8_probe,
1234f1d8a071SWilliam Breathitt Gray 	.driver = {
1235f1d8a071SWilliam Breathitt Gray 		.name = "104-quad-8"
1236f1d8a071SWilliam Breathitt Gray 	}
1237f1d8a071SWilliam Breathitt Gray };
1238f1d8a071SWilliam Breathitt Gray 
1239f1d8a071SWilliam Breathitt Gray module_isa_driver(quad8_driver, num_quad8);
1240f1d8a071SWilliam Breathitt Gray 
1241f1d8a071SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1242e357e81fSWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
1243f1d8a071SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
1244*3216e551SWilliam Breathitt Gray MODULE_IMPORT_NS(COUNTER);
1245