xref: /openbmc/linux/drivers/counter/104-quad-8.c (revision 98ffe025)
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  */
8398abaabSWilliam Breathitt Gray #include <linux/bitfield.h>
9398abaabSWilliam Breathitt Gray #include <linux/bits.h>
10f1d8a071SWilliam Breathitt Gray #include <linux/counter.h>
11f1d8a071SWilliam Breathitt Gray #include <linux/device.h>
12*98ffe025SWilliam Breathitt Gray #include <linux/err.h>
13f1d8a071SWilliam Breathitt Gray #include <linux/io.h>
14f1d8a071SWilliam Breathitt Gray #include <linux/ioport.h>
157aa2ba0dSWilliam Breathitt Gray #include <linux/interrupt.h>
16f1d8a071SWilliam Breathitt Gray #include <linux/isa.h>
17f1d8a071SWilliam Breathitt Gray #include <linux/kernel.h>
18c95cc0d9SWilliam Breathitt Gray #include <linux/list.h>
19f1d8a071SWilliam Breathitt Gray #include <linux/module.h>
20f1d8a071SWilliam Breathitt Gray #include <linux/moduleparam.h>
21*98ffe025SWilliam Breathitt Gray #include <linux/regmap.h>
2209db4678SWilliam Breathitt Gray #include <linux/spinlock.h>
23*98ffe025SWilliam Breathitt Gray #include <linux/types.h>
24f1d8a071SWilliam Breathitt Gray 
25142c8622SWilliam Breathitt Gray #include <asm/unaligned.h>
26142c8622SWilliam Breathitt Gray 
27f1d8a071SWilliam Breathitt Gray #define QUAD8_EXTENT 32
28f1d8a071SWilliam Breathitt Gray 
29f1d8a071SWilliam Breathitt Gray static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
30f1d8a071SWilliam Breathitt Gray static unsigned int num_quad8;
31af383bb1SWilliam Breathitt Gray module_param_hw_array(base, uint, ioport, &num_quad8, 0);
32f1d8a071SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
33f1d8a071SWilliam Breathitt Gray 
347aa2ba0dSWilliam Breathitt Gray static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
350c83a280SWilliam Breathitt Gray static unsigned int num_irq;
360c83a280SWilliam Breathitt Gray module_param_hw_array(irq, uint, irq, &num_irq, 0);
377aa2ba0dSWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
387aa2ba0dSWilliam Breathitt Gray 
39f1d8a071SWilliam Breathitt Gray #define QUAD8_NUM_COUNTERS 8
40f1d8a071SWilliam Breathitt Gray 
41*98ffe025SWilliam Breathitt Gray #define QUAD8_DATA(_channel) ((_channel) * 2)
42*98ffe025SWilliam Breathitt Gray #define QUAD8_CONTROL(_channel) (QUAD8_DATA(_channel) + 1)
43*98ffe025SWilliam Breathitt Gray #define QUAD8_INTERRUPT_STATUS 0x10
44*98ffe025SWilliam Breathitt Gray #define QUAD8_CHANNEL_OPERATION 0x11
45*98ffe025SWilliam Breathitt Gray #define QUAD8_INDEX_INTERRUPT 0x12
46*98ffe025SWilliam Breathitt Gray #define QUAD8_INDEX_INPUT_LEVELS 0x16
47*98ffe025SWilliam Breathitt Gray #define QUAD8_CABLE_STATUS 0x17
48daae1ee5SWilliam Breathitt Gray 
49daae1ee5SWilliam Breathitt Gray /**
50e357e81fSWilliam Breathitt Gray  * struct quad8 - device private data structure
5194a853ecSWilliam Breathitt Gray  * @lock:		lock to prevent clobbering device states during R/W ops
524d8df168SWilliam Breathitt Gray  * @cmr:		array of Counter Mode Register states
534d8df168SWilliam Breathitt Gray  * @ior:		array of Input / Output Control Register states
544d8df168SWilliam Breathitt Gray  * @idr:		array of Index Control Register states
55954ab5ccSWilliam Breathitt Gray  * @fck_prescaler:	array of filter clock prescaler configurations
56f1d8a071SWilliam Breathitt Gray  * @preset:		array of preset values
57954ab5ccSWilliam Breathitt Gray  * @cable_fault_enable:	differential encoder cable status enable configurations
58*98ffe025SWilliam Breathitt Gray  * @map:		regmap for the device
59f1d8a071SWilliam Breathitt Gray  */
60e357e81fSWilliam Breathitt Gray struct quad8 {
6109db4678SWilliam Breathitt Gray 	spinlock_t lock;
624d8df168SWilliam Breathitt Gray 	u8 cmr[QUAD8_NUM_COUNTERS];
634d8df168SWilliam Breathitt Gray 	u8 ior[QUAD8_NUM_COUNTERS];
644d8df168SWilliam Breathitt Gray 	u8 idr[QUAD8_NUM_COUNTERS];
65de65d055SWilliam Breathitt Gray 	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
66f1d8a071SWilliam Breathitt Gray 	unsigned int preset[QUAD8_NUM_COUNTERS];
67954ab5ccSWilliam Breathitt Gray 	unsigned int cable_fault_enable;
68*98ffe025SWilliam Breathitt Gray 	struct regmap *map;
69*98ffe025SWilliam Breathitt Gray };
70*98ffe025SWilliam Breathitt Gray 
71*98ffe025SWilliam Breathitt Gray static const struct regmap_range quad8_wr_ranges[] = {
72*98ffe025SWilliam Breathitt Gray 	regmap_reg_range(0x0, 0xF), regmap_reg_range(0x11, 0x12), regmap_reg_range(0x17, 0x17),
73*98ffe025SWilliam Breathitt Gray };
74*98ffe025SWilliam Breathitt Gray static const struct regmap_range quad8_rd_ranges[] = {
75*98ffe025SWilliam Breathitt Gray 	regmap_reg_range(0x0, 0x12), regmap_reg_range(0x16, 0x18),
76*98ffe025SWilliam Breathitt Gray };
77*98ffe025SWilliam Breathitt Gray static const struct regmap_access_table quad8_wr_table = {
78*98ffe025SWilliam Breathitt Gray 	.yes_ranges = quad8_wr_ranges,
79*98ffe025SWilliam Breathitt Gray 	.n_yes_ranges = ARRAY_SIZE(quad8_wr_ranges),
80*98ffe025SWilliam Breathitt Gray };
81*98ffe025SWilliam Breathitt Gray static const struct regmap_access_table quad8_rd_table = {
82*98ffe025SWilliam Breathitt Gray 	.yes_ranges = quad8_rd_ranges,
83*98ffe025SWilliam Breathitt Gray 	.n_yes_ranges = ARRAY_SIZE(quad8_rd_ranges),
84*98ffe025SWilliam Breathitt Gray };
85*98ffe025SWilliam Breathitt Gray static const struct regmap_config quad8_regmap_config = {
86*98ffe025SWilliam Breathitt Gray 	.reg_bits = 8,
87*98ffe025SWilliam Breathitt Gray 	.reg_stride = 1,
88*98ffe025SWilliam Breathitt Gray 	.val_bits = 8,
89*98ffe025SWilliam Breathitt Gray 	.io_port = true,
90*98ffe025SWilliam Breathitt Gray 	.wr_table = &quad8_wr_table,
91*98ffe025SWilliam Breathitt Gray 	.rd_table = &quad8_rd_table,
92f1d8a071SWilliam Breathitt Gray };
93f1d8a071SWilliam Breathitt Gray 
94f1d8a071SWilliam Breathitt Gray /* Error flag */
95398abaabSWilliam Breathitt Gray #define FLAG_E BIT(4)
96f1d8a071SWilliam Breathitt Gray /* Up/Down flag */
97398abaabSWilliam Breathitt Gray #define FLAG_UD BIT(5)
984d8df168SWilliam Breathitt Gray /* Counting up */
994d8df168SWilliam Breathitt Gray #define UP 0x1
100398abaabSWilliam Breathitt Gray 
101398abaabSWilliam Breathitt Gray #define REGISTER_SELECTION GENMASK(6, 5)
102398abaabSWilliam Breathitt Gray 
103f1d8a071SWilliam Breathitt Gray /* Reset and Load Signal Decoders */
104398abaabSWilliam Breathitt Gray #define SELECT_RLD u8_encode_bits(0x0, REGISTER_SELECTION)
105f1d8a071SWilliam Breathitt Gray /* Counter Mode Register */
106398abaabSWilliam Breathitt Gray #define SELECT_CMR u8_encode_bits(0x1, REGISTER_SELECTION)
107f1d8a071SWilliam Breathitt Gray /* Input / Output Control Register */
108398abaabSWilliam Breathitt Gray #define SELECT_IOR u8_encode_bits(0x2, REGISTER_SELECTION)
109f1d8a071SWilliam Breathitt Gray /* Index Control Register */
110398abaabSWilliam Breathitt Gray #define SELECT_IDR u8_encode_bits(0x3, REGISTER_SELECTION)
111398abaabSWilliam Breathitt Gray 
112398abaabSWilliam Breathitt Gray /*
113398abaabSWilliam Breathitt Gray  * Reset and Load Signal Decoders
114398abaabSWilliam Breathitt Gray  */
115398abaabSWilliam Breathitt Gray #define RESETS GENMASK(2, 1)
116398abaabSWilliam Breathitt Gray #define LOADS GENMASK(4, 3)
117f1d8a071SWilliam Breathitt Gray /* Reset Byte Pointer (three byte data pointer) */
118398abaabSWilliam Breathitt Gray #define RESET_BP BIT(0)
119398abaabSWilliam Breathitt Gray /* Reset Borrow Toggle, Carry toggle, Compare toggle, Sign, and Index flags */
120398abaabSWilliam Breathitt Gray #define RESET_BT_CT_CPT_S_IDX u8_encode_bits(0x2, RESETS)
121f1d8a071SWilliam Breathitt Gray /* Reset Error flag */
122398abaabSWilliam Breathitt Gray #define RESET_E u8_encode_bits(0x3, RESETS)
123f1d8a071SWilliam Breathitt Gray /* Preset Register to Counter */
124398abaabSWilliam Breathitt Gray #define TRANSFER_PR_TO_CNTR u8_encode_bits(0x1, LOADS)
125f1d8a071SWilliam Breathitt Gray /* Transfer Counter to Output Latch */
126398abaabSWilliam Breathitt Gray #define TRANSFER_CNTR_TO_OL u8_encode_bits(0x2, LOADS)
127de65d055SWilliam Breathitt Gray /* Transfer Preset Register LSB to FCK Prescaler */
128398abaabSWilliam Breathitt Gray #define TRANSFER_PR0_TO_PSC u8_encode_bits(0x3, LOADS)
129398abaabSWilliam Breathitt Gray 
130398abaabSWilliam Breathitt Gray /*
131398abaabSWilliam Breathitt Gray  * Counter Mode Registers
132398abaabSWilliam Breathitt Gray  */
133398abaabSWilliam Breathitt Gray #define COUNT_ENCODING BIT(0)
134398abaabSWilliam Breathitt Gray #define COUNT_MODE GENMASK(2, 1)
135398abaabSWilliam Breathitt Gray #define QUADRATURE_MODE GENMASK(4, 3)
136398abaabSWilliam Breathitt Gray /* Binary count */
137398abaabSWilliam Breathitt Gray #define BINARY u8_encode_bits(0x0, COUNT_ENCODING)
138398abaabSWilliam Breathitt Gray /* Normal count */
139398abaabSWilliam Breathitt Gray #define NORMAL_COUNT 0x0
140398abaabSWilliam Breathitt Gray /* Range Limit */
141398abaabSWilliam Breathitt Gray #define RANGE_LIMIT 0x1
142398abaabSWilliam Breathitt Gray /* Non-recycle count */
143398abaabSWilliam Breathitt Gray #define NON_RECYCLE_COUNT 0x2
144398abaabSWilliam Breathitt Gray /* Modulo-N */
145398abaabSWilliam Breathitt Gray #define MODULO_N 0x3
146398abaabSWilliam Breathitt Gray /* Non-quadrature */
147398abaabSWilliam Breathitt Gray #define NON_QUADRATURE 0x0
148398abaabSWilliam Breathitt Gray /* Quadrature X1 */
149398abaabSWilliam Breathitt Gray #define QUADRATURE_X1 0x1
150398abaabSWilliam Breathitt Gray /* Quadrature X2 */
151398abaabSWilliam Breathitt Gray #define QUADRATURE_X2 0x2
152398abaabSWilliam Breathitt Gray /* Quadrature X4 */
153398abaabSWilliam Breathitt Gray #define QUADRATURE_X4 0x3
154398abaabSWilliam Breathitt Gray 
155398abaabSWilliam Breathitt Gray /*
156398abaabSWilliam Breathitt Gray  * Input/Output Control Register
157398abaabSWilliam Breathitt Gray  */
158398abaabSWilliam Breathitt Gray #define AB_GATE BIT(0)
159398abaabSWilliam Breathitt Gray #define LOAD_PIN BIT(1)
160398abaabSWilliam Breathitt Gray #define FLG_PINS GENMASK(4, 3)
161398abaabSWilliam Breathitt Gray /* Disable inputs A and B */
162398abaabSWilliam Breathitt Gray #define DISABLE_AB u8_encode_bits(0x0, AB_GATE)
163398abaabSWilliam Breathitt Gray /* Load Counter input */
164398abaabSWilliam Breathitt Gray #define LOAD_CNTR 0x0
165398abaabSWilliam Breathitt Gray /* FLG1 = CARRY(active low); FLG2 = BORROW(active low) */
166398abaabSWilliam Breathitt Gray #define FLG1_CARRY_FLG2_BORROW 0x0
167398abaabSWilliam Breathitt Gray /* FLG1 = COMPARE(active low); FLG2 = BORROW(active low) */
168398abaabSWilliam Breathitt Gray #define FLG1_COMPARE_FLG2_BORROW 0x1
169398abaabSWilliam Breathitt Gray /* FLG1 = Carry(active low)/Borrow(active low); FLG2 = U/D(active low) flag */
170398abaabSWilliam Breathitt Gray #define FLG1_CARRYBORROW_FLG2_UD 0x2
171398abaabSWilliam Breathitt Gray /* FLG1 = INDX (low pulse at INDEX pin active level); FLG2 = E flag */
172398abaabSWilliam Breathitt Gray #define FLG1_INDX_FLG2_E 0x3
173398abaabSWilliam Breathitt Gray 
174398abaabSWilliam Breathitt Gray /*
175398abaabSWilliam Breathitt Gray  * INDEX CONTROL REGISTERS
176398abaabSWilliam Breathitt Gray  */
177398abaabSWilliam Breathitt Gray #define INDEX_MODE BIT(0)
178398abaabSWilliam Breathitt Gray #define INDEX_POLARITY BIT(1)
179398abaabSWilliam Breathitt Gray /* Disable Index mode */
180398abaabSWilliam Breathitt Gray #define DISABLE_INDEX_MODE 0x0
1814d8df168SWilliam Breathitt Gray /* Enable Index mode */
1824d8df168SWilliam Breathitt Gray #define ENABLE_INDEX_MODE 0x1
183398abaabSWilliam Breathitt Gray /* Negative Index Polarity */
184398abaabSWilliam Breathitt Gray #define NEGATIVE_INDEX_POLARITY 0x0
1854d8df168SWilliam Breathitt Gray /* Positive Index Polarity */
1864d8df168SWilliam Breathitt Gray #define POSITIVE_INDEX_POLARITY 0x1
187398abaabSWilliam Breathitt Gray 
188398abaabSWilliam Breathitt Gray /*
189398abaabSWilliam Breathitt Gray  * Channel Operation Register
190398abaabSWilliam Breathitt Gray  */
191398abaabSWilliam Breathitt Gray #define COUNTERS_OPERATION BIT(0)
192398abaabSWilliam Breathitt Gray #define INTERRUPT_FUNCTION BIT(2)
193398abaabSWilliam Breathitt Gray /* Enable all Counters */
194398abaabSWilliam Breathitt Gray #define ENABLE_COUNTERS u8_encode_bits(0x0, COUNTERS_OPERATION)
195398abaabSWilliam Breathitt Gray /* Reset all Counters */
196398abaabSWilliam Breathitt Gray #define RESET_COUNTERS u8_encode_bits(0x1, COUNTERS_OPERATION)
197398abaabSWilliam Breathitt Gray /* Disable the interrupt function */
198398abaabSWilliam Breathitt Gray #define DISABLE_INTERRUPT_FUNCTION u8_encode_bits(0x0, INTERRUPT_FUNCTION)
199398abaabSWilliam Breathitt Gray /* Enable the interrupt function */
200398abaabSWilliam Breathitt Gray #define ENABLE_INTERRUPT_FUNCTION u8_encode_bits(0x1, INTERRUPT_FUNCTION)
201398abaabSWilliam Breathitt Gray /* Any write to the Channel Operation register clears any pending interrupts */
202398abaabSWilliam Breathitt Gray #define CLEAR_PENDING_INTERRUPTS (ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION)
203f1d8a071SWilliam Breathitt Gray 
2044aa3b75cSWilliam Breathitt Gray /* Each Counter is 24 bits wide */
2054aa3b75cSWilliam Breathitt Gray #define LS7267_CNTR_MAX GENMASK(23, 0)
2064aa3b75cSWilliam Breathitt Gray 
quad8_control_register_update(struct regmap * const map,u8 * const buf,const size_t channel,const u8 val,const u8 field)207*98ffe025SWilliam Breathitt Gray static __always_inline int quad8_control_register_update(struct regmap *const map, u8 *const buf,
2084d8df168SWilliam Breathitt Gray 							 const size_t channel, const u8 val,
2094d8df168SWilliam Breathitt Gray 							 const u8 field)
2104d8df168SWilliam Breathitt Gray {
2114d8df168SWilliam Breathitt Gray 	u8p_replace_bits(&buf[channel], val, field);
212*98ffe025SWilliam Breathitt Gray 	return regmap_write(map, QUAD8_CONTROL(channel), buf[channel]);
2134d8df168SWilliam Breathitt Gray }
2144d8df168SWilliam Breathitt Gray 
quad8_signal_read(struct counter_device * counter,struct counter_signal * signal,enum counter_signal_level * level)215f1d8a071SWilliam Breathitt Gray static int quad8_signal_read(struct counter_device *counter,
216493b938aSWilliam Breathitt Gray 			     struct counter_signal *signal,
217493b938aSWilliam Breathitt Gray 			     enum counter_signal_level *level)
218f1d8a071SWilliam Breathitt Gray {
219aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
220*98ffe025SWilliam Breathitt Gray 	int ret;
221f1d8a071SWilliam Breathitt Gray 
222f1d8a071SWilliam Breathitt Gray 	/* Only Index signal levels can be read */
223f1d8a071SWilliam Breathitt Gray 	if (signal->id < 16)
224f1d8a071SWilliam Breathitt Gray 		return -EINVAL;
225f1d8a071SWilliam Breathitt Gray 
226*98ffe025SWilliam Breathitt Gray 	ret = regmap_test_bits(priv->map, QUAD8_INDEX_INPUT_LEVELS, BIT(signal->id - 16));
227*98ffe025SWilliam Breathitt Gray 	if (ret < 0)
228*98ffe025SWilliam Breathitt Gray 		return ret;
229f1d8a071SWilliam Breathitt Gray 
230*98ffe025SWilliam Breathitt Gray 	*level = (ret) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
231f1d8a071SWilliam Breathitt Gray 
232f1d8a071SWilliam Breathitt Gray 	return 0;
233f1d8a071SWilliam Breathitt Gray }
234f1d8a071SWilliam Breathitt Gray 
quad8_count_read(struct counter_device * counter,struct counter_count * count,u64 * val)235f1d8a071SWilliam Breathitt Gray static int quad8_count_read(struct counter_device *counter,
236aaec1a0fSWilliam Breathitt Gray 			    struct counter_count *count, u64 *val)
237f1d8a071SWilliam Breathitt Gray {
238aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
23909db4678SWilliam Breathitt Gray 	unsigned long irqflags;
240142c8622SWilliam Breathitt Gray 	u8 value[3];
241*98ffe025SWilliam Breathitt Gray 	int ret;
242f1d8a071SWilliam Breathitt Gray 
24309db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
244fc069262SSyed Nayyar Waris 
245*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(count->id),
246*98ffe025SWilliam Breathitt Gray 			   SELECT_RLD | RESET_BP | TRANSFER_CNTR_TO_OL);
247*98ffe025SWilliam Breathitt Gray 	if (ret)
248*98ffe025SWilliam Breathitt Gray 		goto exit_unlock;
249*98ffe025SWilliam Breathitt Gray 	ret = regmap_noinc_read(priv->map, QUAD8_DATA(count->id), value, sizeof(value));
250f1d8a071SWilliam Breathitt Gray 
251*98ffe025SWilliam Breathitt Gray exit_unlock:
25209db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
253fc069262SSyed Nayyar Waris 
254142c8622SWilliam Breathitt Gray 	*val = get_unaligned_le24(value);
255142c8622SWilliam Breathitt Gray 
256*98ffe025SWilliam Breathitt Gray 	return ret;
257f1d8a071SWilliam Breathitt Gray }
258f1d8a071SWilliam Breathitt Gray 
quad8_preset_register_set(struct quad8 * const priv,const size_t id,const unsigned long preset)259*98ffe025SWilliam Breathitt Gray static int quad8_preset_register_set(struct quad8 *const priv, const size_t id,
260142c8622SWilliam Breathitt Gray 				     const unsigned long preset)
261142c8622SWilliam Breathitt Gray {
262142c8622SWilliam Breathitt Gray 	u8 value[3];
263*98ffe025SWilliam Breathitt Gray 	int ret;
264142c8622SWilliam Breathitt Gray 
265142c8622SWilliam Breathitt Gray 	put_unaligned_le24(preset, value);
266142c8622SWilliam Breathitt Gray 
267*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
268*98ffe025SWilliam Breathitt Gray 	if (ret)
269*98ffe025SWilliam Breathitt Gray 		return ret;
270*98ffe025SWilliam Breathitt Gray 	return regmap_noinc_write(priv->map, QUAD8_DATA(id), value, sizeof(value));
271142c8622SWilliam Breathitt Gray }
272142c8622SWilliam Breathitt Gray 
quad8_flag_register_reset(struct quad8 * const priv,const size_t id)273*98ffe025SWilliam Breathitt Gray static int quad8_flag_register_reset(struct quad8 *const priv, const size_t id)
274142c8622SWilliam Breathitt Gray {
275*98ffe025SWilliam Breathitt Gray 	int ret;
276142c8622SWilliam Breathitt Gray 
277*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BT_CT_CPT_S_IDX);
278*98ffe025SWilliam Breathitt Gray 	if (ret)
279*98ffe025SWilliam Breathitt Gray 		return ret;
280*98ffe025SWilliam Breathitt Gray 	return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_E);
281142c8622SWilliam Breathitt Gray }
282142c8622SWilliam Breathitt Gray 
quad8_count_write(struct counter_device * counter,struct counter_count * count,u64 val)283f1d8a071SWilliam Breathitt Gray static int quad8_count_write(struct counter_device *counter,
284aaec1a0fSWilliam Breathitt Gray 			     struct counter_count *count, u64 val)
285f1d8a071SWilliam Breathitt Gray {
286aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
28709db4678SWilliam Breathitt Gray 	unsigned long irqflags;
288*98ffe025SWilliam Breathitt Gray 	int ret;
289f1d8a071SWilliam Breathitt Gray 
2904aa3b75cSWilliam Breathitt Gray 	if (val > LS7267_CNTR_MAX)
291e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
292f1d8a071SWilliam Breathitt Gray 
29309db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
294fc069262SSyed Nayyar Waris 
295f1d8a071SWilliam Breathitt Gray 	/* Counter can only be set via Preset Register */
296*98ffe025SWilliam Breathitt Gray 	ret = quad8_preset_register_set(priv, count->id, val);
297*98ffe025SWilliam Breathitt Gray 	if (ret)
298*98ffe025SWilliam Breathitt Gray 		goto exit_unlock;
299*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(count->id), SELECT_RLD | TRANSFER_PR_TO_CNTR);
300*98ffe025SWilliam Breathitt Gray 	if (ret)
301*98ffe025SWilliam Breathitt Gray 		goto exit_unlock;
302f1d8a071SWilliam Breathitt Gray 
303*98ffe025SWilliam Breathitt Gray 	ret = quad8_flag_register_reset(priv, count->id);
304*98ffe025SWilliam Breathitt Gray 	if (ret)
305*98ffe025SWilliam Breathitt Gray 		goto exit_unlock;
306f1d8a071SWilliam Breathitt Gray 
307f1d8a071SWilliam Breathitt Gray 	/* Set Preset Register back to original value */
308*98ffe025SWilliam Breathitt Gray 	ret = quad8_preset_register_set(priv, count->id, priv->preset[count->id]);
309f1d8a071SWilliam Breathitt Gray 
310*98ffe025SWilliam Breathitt Gray exit_unlock:
31109db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
312fc069262SSyed Nayyar Waris 
313*98ffe025SWilliam Breathitt Gray 	return ret;
314f1d8a071SWilliam Breathitt Gray }
315f1d8a071SWilliam Breathitt Gray 
316394a0150SWilliam Breathitt Gray static const enum counter_function quad8_count_functions_list[] = {
317aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_PULSE_DIRECTION,
318aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X1_A,
319aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X2_A,
320aaec1a0fSWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X4,
321f1d8a071SWilliam Breathitt Gray };
322f1d8a071SWilliam Breathitt Gray 
quad8_function_get(const struct quad8 * const priv,const size_t id,enum counter_function * const function)323d501d378SWilliam Breathitt Gray static int quad8_function_get(const struct quad8 *const priv, const size_t id,
324d501d378SWilliam Breathitt Gray 			      enum counter_function *const function)
325d501d378SWilliam Breathitt Gray {
3264d8df168SWilliam Breathitt Gray 	switch (u8_get_bits(priv->cmr[id], QUADRATURE_MODE)) {
3274d8df168SWilliam Breathitt Gray 	case NON_QUADRATURE:
328d501d378SWilliam Breathitt Gray 		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
329d501d378SWilliam Breathitt Gray 		return 0;
3304d8df168SWilliam Breathitt Gray 	case QUADRATURE_X1:
331d501d378SWilliam Breathitt Gray 		*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
332d501d378SWilliam Breathitt Gray 		return 0;
3334d8df168SWilliam Breathitt Gray 	case QUADRATURE_X2:
334d501d378SWilliam Breathitt Gray 		*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
335d501d378SWilliam Breathitt Gray 		return 0;
3364d8df168SWilliam Breathitt Gray 	case QUADRATURE_X4:
337d501d378SWilliam Breathitt Gray 		*function = COUNTER_FUNCTION_QUADRATURE_X4;
338d501d378SWilliam Breathitt Gray 		return 0;
339d501d378SWilliam Breathitt Gray 	default:
340d501d378SWilliam Breathitt Gray 		/* should never reach this path */
341d501d378SWilliam Breathitt Gray 		return -EINVAL;
342d501d378SWilliam Breathitt Gray 	}
343d501d378SWilliam Breathitt Gray }
344d501d378SWilliam Breathitt Gray 
quad8_function_read(struct counter_device * counter,struct counter_count * count,enum counter_function * function)345aaec1a0fSWilliam Breathitt Gray static int quad8_function_read(struct counter_device *counter,
346aaec1a0fSWilliam Breathitt Gray 			       struct counter_count *count,
347aaec1a0fSWilliam Breathitt Gray 			       enum counter_function *function)
348f1d8a071SWilliam Breathitt Gray {
349aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
35009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
351d501d378SWilliam Breathitt Gray 	int retval;
352f1d8a071SWilliam Breathitt Gray 
35309db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
354fc069262SSyed Nayyar Waris 
355d501d378SWilliam Breathitt Gray 	retval = quad8_function_get(priv, count->id, function);
356f1d8a071SWilliam Breathitt Gray 
35709db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
358fc069262SSyed Nayyar Waris 
359d501d378SWilliam Breathitt Gray 	return retval;
360f1d8a071SWilliam Breathitt Gray }
361f1d8a071SWilliam Breathitt Gray 
quad8_function_write(struct counter_device * counter,struct counter_count * count,enum counter_function function)362aaec1a0fSWilliam Breathitt Gray static int quad8_function_write(struct counter_device *counter,
363aaec1a0fSWilliam Breathitt Gray 				struct counter_count *count,
364aaec1a0fSWilliam Breathitt Gray 				enum counter_function function)
365f1d8a071SWilliam Breathitt Gray {
366aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
367f1d8a071SWilliam Breathitt Gray 	const int id = count->id;
36809db4678SWilliam Breathitt Gray 	unsigned long irqflags;
369fc069262SSyed Nayyar Waris 	unsigned int mode_cfg;
3704d8df168SWilliam Breathitt Gray 	bool synchronous_mode;
371*98ffe025SWilliam Breathitt Gray 	int ret;
372f1d8a071SWilliam Breathitt Gray 
373f1d8a071SWilliam Breathitt Gray 	switch (function) {
3744d8df168SWilliam Breathitt Gray 	case COUNTER_FUNCTION_PULSE_DIRECTION:
3754d8df168SWilliam Breathitt Gray 		mode_cfg = NON_QUADRATURE;
3764d8df168SWilliam Breathitt Gray 		break;
377aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X1_A:
3784d8df168SWilliam Breathitt Gray 		mode_cfg = QUADRATURE_X1;
379f1d8a071SWilliam Breathitt Gray 		break;
380aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X2_A:
3814d8df168SWilliam Breathitt Gray 		mode_cfg = QUADRATURE_X2;
382f1d8a071SWilliam Breathitt Gray 		break;
383aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X4:
3844d8df168SWilliam Breathitt Gray 		mode_cfg = QUADRATURE_X4;
385f1d8a071SWilliam Breathitt Gray 		break;
386b11eed15SWilliam Breathitt Gray 	default:
387b11eed15SWilliam Breathitt Gray 		/* should never reach this path */
388b11eed15SWilliam Breathitt Gray 		return -EINVAL;
389f1d8a071SWilliam Breathitt Gray 	}
390f1d8a071SWilliam Breathitt Gray 
3914d8df168SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
3924d8df168SWilliam Breathitt Gray 
3934d8df168SWilliam Breathitt Gray 	/* Synchronous function not supported in non-quadrature mode */
3944d8df168SWilliam Breathitt Gray 	synchronous_mode = u8_get_bits(priv->idr[id], INDEX_MODE) == ENABLE_INDEX_MODE;
395*98ffe025SWilliam Breathitt Gray 	if (synchronous_mode && mode_cfg == NON_QUADRATURE) {
396*98ffe025SWilliam Breathitt Gray 		ret = quad8_control_register_update(priv->map, priv->idr, id, DISABLE_INDEX_MODE,
397*98ffe025SWilliam Breathitt Gray 						    INDEX_MODE);
398*98ffe025SWilliam Breathitt Gray 		if (ret)
399*98ffe025SWilliam Breathitt Gray 			goto exit_unlock;
400*98ffe025SWilliam Breathitt Gray 	}
4014d8df168SWilliam Breathitt Gray 
402*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->cmr, id, mode_cfg, QUADRATURE_MODE);
403f1d8a071SWilliam Breathitt Gray 
404*98ffe025SWilliam Breathitt Gray exit_unlock:
40509db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
406fc069262SSyed Nayyar Waris 
407*98ffe025SWilliam Breathitt Gray 	return ret;
408f1d8a071SWilliam Breathitt Gray }
409f1d8a071SWilliam Breathitt Gray 
quad8_direction_read(struct counter_device * counter,struct counter_count * count,enum counter_count_direction * direction)410aaec1a0fSWilliam Breathitt Gray static int quad8_direction_read(struct counter_device *counter,
411aaec1a0fSWilliam Breathitt Gray 				struct counter_count *count,
412aaec1a0fSWilliam Breathitt Gray 				enum counter_count_direction *direction)
413f1d8a071SWilliam Breathitt Gray {
414aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
415*98ffe025SWilliam Breathitt Gray 	unsigned int flag;
416*98ffe025SWilliam Breathitt Gray 	int ret;
417f1d8a071SWilliam Breathitt Gray 
418*98ffe025SWilliam Breathitt Gray 	ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
419*98ffe025SWilliam Breathitt Gray 	if (ret)
420*98ffe025SWilliam Breathitt Gray 		return ret;
4214d8df168SWilliam Breathitt Gray 	*direction = (u8_get_bits(flag, FLAG_UD) == UP) ? COUNTER_COUNT_DIRECTION_FORWARD :
422f1d8a071SWilliam Breathitt Gray 		COUNTER_COUNT_DIRECTION_BACKWARD;
423aaec1a0fSWilliam Breathitt Gray 
424aaec1a0fSWilliam Breathitt Gray 	return 0;
425f1d8a071SWilliam Breathitt Gray }
426f1d8a071SWilliam Breathitt Gray 
4276a9eb0e3SWilliam Breathitt Gray static const enum counter_synapse_action quad8_index_actions_list[] = {
428aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_NONE,
429aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
430f1d8a071SWilliam Breathitt Gray };
431f1d8a071SWilliam Breathitt Gray 
4326a9eb0e3SWilliam Breathitt Gray static const enum counter_synapse_action quad8_synapse_actions_list[] = {
433aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_NONE,
434aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
435aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
436aaec1a0fSWilliam Breathitt Gray 	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
437f1d8a071SWilliam Breathitt Gray };
438f1d8a071SWilliam Breathitt Gray 
quad8_action_read(struct counter_device * counter,struct counter_count * count,struct counter_synapse * synapse,enum counter_synapse_action * action)439aaec1a0fSWilliam Breathitt Gray static int quad8_action_read(struct counter_device *counter,
440aaec1a0fSWilliam Breathitt Gray 			     struct counter_count *count,
441aaec1a0fSWilliam Breathitt Gray 			     struct counter_synapse *synapse,
442aaec1a0fSWilliam Breathitt Gray 			     enum counter_synapse_action *action)
443f1d8a071SWilliam Breathitt Gray {
444aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
445d501d378SWilliam Breathitt Gray 	unsigned long irqflags;
446f1d8a071SWilliam Breathitt Gray 	int err;
447aaec1a0fSWilliam Breathitt Gray 	enum counter_function function;
448f1d8a071SWilliam Breathitt Gray 	const size_t signal_a_id = count->synapses[0].signal->id;
449f1d8a071SWilliam Breathitt Gray 	enum counter_count_direction direction;
450f1d8a071SWilliam Breathitt Gray 
4514d8df168SWilliam Breathitt Gray 	/* Default action mode */
452aaec1a0fSWilliam Breathitt Gray 	*action = COUNTER_SYNAPSE_ACTION_NONE;
453f1d8a071SWilliam Breathitt Gray 
4544d8df168SWilliam Breathitt Gray 	/* Handle Index signals */
4554d8df168SWilliam Breathitt Gray 	if (synapse->signal->id >= 16) {
4564d8df168SWilliam Breathitt Gray 		if (u8_get_bits(priv->ior[count->id], LOAD_PIN) == LOAD_CNTR)
4574d8df168SWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
458f1d8a071SWilliam Breathitt Gray 		return 0;
459f1d8a071SWilliam Breathitt Gray 	}
460f1d8a071SWilliam Breathitt Gray 
461d501d378SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
462d501d378SWilliam Breathitt Gray 
463d501d378SWilliam Breathitt Gray 	/* Get Count function and direction atomically */
464d501d378SWilliam Breathitt Gray 	err = quad8_function_get(priv, count->id, &function);
465d501d378SWilliam Breathitt Gray 	if (err) {
466d501d378SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
467f1d8a071SWilliam Breathitt Gray 		return err;
468d501d378SWilliam Breathitt Gray 	}
469d501d378SWilliam Breathitt Gray 	err = quad8_direction_read(counter, count, &direction);
470d501d378SWilliam Breathitt Gray 	if (err) {
471d501d378SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
472d501d378SWilliam Breathitt Gray 		return err;
473d501d378SWilliam Breathitt Gray 	}
474d501d378SWilliam Breathitt Gray 
475d501d378SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
476f1d8a071SWilliam Breathitt Gray 
477f1d8a071SWilliam Breathitt Gray 	/* Determine action mode based on current count function mode */
478f1d8a071SWilliam Breathitt Gray 	switch (function) {
479aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_PULSE_DIRECTION:
480f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id)
481aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
482b11eed15SWilliam Breathitt Gray 		return 0;
483aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X1_A:
484f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id) {
485f1d8a071SWilliam Breathitt Gray 			if (direction == COUNTER_COUNT_DIRECTION_FORWARD)
486aaec1a0fSWilliam Breathitt Gray 				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
487f1d8a071SWilliam Breathitt Gray 			else
488aaec1a0fSWilliam Breathitt Gray 				*action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
489f1d8a071SWilliam Breathitt Gray 		}
490b11eed15SWilliam Breathitt Gray 		return 0;
491aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X2_A:
492f1d8a071SWilliam Breathitt Gray 		if (synapse->signal->id == signal_a_id)
493aaec1a0fSWilliam Breathitt Gray 			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
494b11eed15SWilliam Breathitt Gray 		return 0;
495aaec1a0fSWilliam Breathitt Gray 	case COUNTER_FUNCTION_QUADRATURE_X4:
496aaec1a0fSWilliam Breathitt Gray 		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
497f1d8a071SWilliam Breathitt Gray 		return 0;
498b11eed15SWilliam Breathitt Gray 	default:
499b11eed15SWilliam Breathitt Gray 		/* should never reach this path */
500b11eed15SWilliam Breathitt Gray 		return -EINVAL;
501b11eed15SWilliam Breathitt Gray 	}
502f1d8a071SWilliam Breathitt Gray }
503f1d8a071SWilliam Breathitt Gray 
quad8_events_configure(struct counter_device * counter)5047aa2ba0dSWilliam Breathitt Gray static int quad8_events_configure(struct counter_device *counter)
5057aa2ba0dSWilliam Breathitt Gray {
506aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
5077aa2ba0dSWilliam Breathitt Gray 	unsigned long irq_enabled = 0;
5087aa2ba0dSWilliam Breathitt Gray 	unsigned long irqflags;
509c95cc0d9SWilliam Breathitt Gray 	struct counter_event_node *event_node;
5104d8df168SWilliam Breathitt Gray 	u8 flg_pins;
511*98ffe025SWilliam Breathitt Gray 	int ret;
5127aa2ba0dSWilliam Breathitt Gray 
5137aa2ba0dSWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
5147aa2ba0dSWilliam Breathitt Gray 
515c95cc0d9SWilliam Breathitt Gray 	list_for_each_entry(event_node, &counter->events_list, l) {
516c95cc0d9SWilliam Breathitt Gray 		switch (event_node->event) {
517c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_OVERFLOW:
5184d8df168SWilliam Breathitt Gray 			flg_pins = FLG1_CARRY_FLG2_BORROW;
519c95cc0d9SWilliam Breathitt Gray 			break;
520c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_THRESHOLD:
5214d8df168SWilliam Breathitt Gray 			flg_pins = FLG1_COMPARE_FLG2_BORROW;
522c95cc0d9SWilliam Breathitt Gray 			break;
523c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
5244d8df168SWilliam Breathitt Gray 			flg_pins = FLG1_CARRYBORROW_FLG2_UD;
525c95cc0d9SWilliam Breathitt Gray 			break;
526c95cc0d9SWilliam Breathitt Gray 		case COUNTER_EVENT_INDEX:
5274d8df168SWilliam Breathitt Gray 			flg_pins = FLG1_INDX_FLG2_E;
528c95cc0d9SWilliam Breathitt Gray 			break;
529c95cc0d9SWilliam Breathitt Gray 		default:
530c95cc0d9SWilliam Breathitt Gray 			/* should never reach this path */
531*98ffe025SWilliam Breathitt Gray 			ret = -EINVAL;
532*98ffe025SWilliam Breathitt Gray 			goto exit_unlock;
5337aa2ba0dSWilliam Breathitt Gray 		}
5347aa2ba0dSWilliam Breathitt Gray 
5352bc54aaaSWilliam Breathitt Gray 		/* Enable IRQ line */
5362bc54aaaSWilliam Breathitt Gray 		irq_enabled |= BIT(event_node->channel);
5372bc54aaaSWilliam Breathitt Gray 
538c95cc0d9SWilliam Breathitt Gray 		/* Skip configuration if it is the same as previously set */
5394d8df168SWilliam Breathitt Gray 		if (flg_pins == u8_get_bits(priv->ior[event_node->channel], FLG_PINS))
540c95cc0d9SWilliam Breathitt Gray 			continue;
541c95cc0d9SWilliam Breathitt Gray 
542c95cc0d9SWilliam Breathitt Gray 		/* Save new IRQ function configuration */
543*98ffe025SWilliam Breathitt Gray 		ret = quad8_control_register_update(priv->map, priv->ior, event_node->channel,
544*98ffe025SWilliam Breathitt Gray 						    flg_pins, FLG_PINS);
545*98ffe025SWilliam Breathitt Gray 		if (ret)
546*98ffe025SWilliam Breathitt Gray 			goto exit_unlock;
5477aa2ba0dSWilliam Breathitt Gray 	}
5487aa2ba0dSWilliam Breathitt Gray 
549*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, irq_enabled);
5507aa2ba0dSWilliam Breathitt Gray 
551*98ffe025SWilliam Breathitt Gray exit_unlock:
5527aa2ba0dSWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
5537aa2ba0dSWilliam Breathitt Gray 
554*98ffe025SWilliam Breathitt Gray 	return ret;
5557aa2ba0dSWilliam Breathitt Gray }
5567aa2ba0dSWilliam Breathitt Gray 
quad8_watch_validate(struct counter_device * counter,const struct counter_watch * watch)5577aa2ba0dSWilliam Breathitt Gray static int quad8_watch_validate(struct counter_device *counter,
5587aa2ba0dSWilliam Breathitt Gray 				const struct counter_watch *watch)
5597aa2ba0dSWilliam Breathitt Gray {
560c95cc0d9SWilliam Breathitt Gray 	struct counter_event_node *event_node;
5617aa2ba0dSWilliam Breathitt Gray 
5627aa2ba0dSWilliam Breathitt Gray 	if (watch->channel > QUAD8_NUM_COUNTERS - 1)
5637aa2ba0dSWilliam Breathitt Gray 		return -EINVAL;
5647aa2ba0dSWilliam Breathitt Gray 
5657aa2ba0dSWilliam Breathitt Gray 	switch (watch->event) {
5667aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_OVERFLOW:
5677aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_THRESHOLD:
5687aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
5697aa2ba0dSWilliam Breathitt Gray 	case COUNTER_EVENT_INDEX:
570c95cc0d9SWilliam Breathitt Gray 		list_for_each_entry(event_node, &counter->next_events_list, l)
571c95cc0d9SWilliam Breathitt Gray 			if (watch->channel == event_node->channel &&
572c95cc0d9SWilliam Breathitt Gray 				watch->event != event_node->event)
5737aa2ba0dSWilliam Breathitt Gray 				return -EINVAL;
5747aa2ba0dSWilliam Breathitt Gray 		return 0;
5757aa2ba0dSWilliam Breathitt Gray 	default:
5767aa2ba0dSWilliam Breathitt Gray 		return -EINVAL;
5777aa2ba0dSWilliam Breathitt Gray 	}
5787aa2ba0dSWilliam Breathitt Gray }
5797aa2ba0dSWilliam Breathitt Gray 
58017aa207eSYueHaibing static const struct counter_ops quad8_ops = {
581f1d8a071SWilliam Breathitt Gray 	.signal_read = quad8_signal_read,
582f1d8a071SWilliam Breathitt Gray 	.count_read = quad8_count_read,
583f1d8a071SWilliam Breathitt Gray 	.count_write = quad8_count_write,
584aaec1a0fSWilliam Breathitt Gray 	.function_read = quad8_function_read,
585aaec1a0fSWilliam Breathitt Gray 	.function_write = quad8_function_write,
5867aa2ba0dSWilliam Breathitt Gray 	.action_read = quad8_action_read,
5877aa2ba0dSWilliam Breathitt Gray 	.events_configure = quad8_events_configure,
5887aa2ba0dSWilliam Breathitt Gray 	.watch_validate = quad8_watch_validate,
589f1d8a071SWilliam Breathitt Gray };
590f1d8a071SWilliam Breathitt Gray 
591e357e81fSWilliam Breathitt Gray static const char *const quad8_index_polarity_modes[] = {
592e357e81fSWilliam Breathitt Gray 	"negative",
593e357e81fSWilliam Breathitt Gray 	"positive"
594e357e81fSWilliam Breathitt Gray };
595e357e81fSWilliam Breathitt Gray 
quad8_index_polarity_get(struct counter_device * counter,struct counter_signal * signal,u32 * index_polarity)596f1d8a071SWilliam Breathitt Gray static int quad8_index_polarity_get(struct counter_device *counter,
597aaec1a0fSWilliam Breathitt Gray 				    struct counter_signal *signal,
598aaec1a0fSWilliam Breathitt Gray 				    u32 *index_polarity)
599f1d8a071SWilliam Breathitt Gray {
600aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
601f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
602f1d8a071SWilliam Breathitt Gray 
6034d8df168SWilliam Breathitt Gray 	*index_polarity = u8_get_bits(priv->idr[channel_id], INDEX_POLARITY);
604f1d8a071SWilliam Breathitt Gray 
605f1d8a071SWilliam Breathitt Gray 	return 0;
606f1d8a071SWilliam Breathitt Gray }
607f1d8a071SWilliam Breathitt Gray 
quad8_index_polarity_set(struct counter_device * counter,struct counter_signal * signal,u32 index_polarity)608f1d8a071SWilliam Breathitt Gray static int quad8_index_polarity_set(struct counter_device *counter,
609aaec1a0fSWilliam Breathitt Gray 				    struct counter_signal *signal,
610aaec1a0fSWilliam Breathitt Gray 				    u32 index_polarity)
611f1d8a071SWilliam Breathitt Gray {
612aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
613f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
61409db4678SWilliam Breathitt Gray 	unsigned long irqflags;
615*98ffe025SWilliam Breathitt Gray 	int ret;
616fc069262SSyed Nayyar Waris 
61709db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
618fc069262SSyed Nayyar Waris 
619*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->idr, channel_id, index_polarity,
620*98ffe025SWilliam Breathitt Gray 					    INDEX_POLARITY);
621f1d8a071SWilliam Breathitt Gray 
62209db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
623fc069262SSyed Nayyar Waris 
624*98ffe025SWilliam Breathitt Gray 	return ret;
625f1d8a071SWilliam Breathitt Gray }
626f1d8a071SWilliam Breathitt Gray 
quad8_polarity_read(struct counter_device * counter,struct counter_signal * signal,enum counter_signal_polarity * polarity)6279830288aSWilliam Breathitt Gray static int quad8_polarity_read(struct counter_device *counter,
6289830288aSWilliam Breathitt Gray 			       struct counter_signal *signal,
6299830288aSWilliam Breathitt Gray 			       enum counter_signal_polarity *polarity)
6309830288aSWilliam Breathitt Gray {
6319830288aSWilliam Breathitt Gray 	int err;
6329830288aSWilliam Breathitt Gray 	u32 index_polarity;
6339830288aSWilliam Breathitt Gray 
6349830288aSWilliam Breathitt Gray 	err = quad8_index_polarity_get(counter, signal, &index_polarity);
6359830288aSWilliam Breathitt Gray 	if (err)
6369830288aSWilliam Breathitt Gray 		return err;
6379830288aSWilliam Breathitt Gray 
6384d8df168SWilliam Breathitt Gray 	*polarity = (index_polarity == POSITIVE_INDEX_POLARITY) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
6399830288aSWilliam Breathitt Gray 		COUNTER_SIGNAL_POLARITY_NEGATIVE;
6409830288aSWilliam Breathitt Gray 
6419830288aSWilliam Breathitt Gray 	return 0;
6429830288aSWilliam Breathitt Gray }
6439830288aSWilliam Breathitt Gray 
quad8_polarity_write(struct counter_device * counter,struct counter_signal * signal,enum counter_signal_polarity polarity)6449830288aSWilliam Breathitt Gray static int quad8_polarity_write(struct counter_device *counter,
6459830288aSWilliam Breathitt Gray 				struct counter_signal *signal,
6469830288aSWilliam Breathitt Gray 				enum counter_signal_polarity polarity)
6479830288aSWilliam Breathitt Gray {
6484d8df168SWilliam Breathitt Gray 	const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? POSITIVE_INDEX_POLARITY :
6494d8df168SWilliam Breathitt Gray 									 NEGATIVE_INDEX_POLARITY;
6509830288aSWilliam Breathitt Gray 
6519830288aSWilliam Breathitt Gray 	return quad8_index_polarity_set(counter, signal, pol);
6529830288aSWilliam Breathitt Gray }
6539830288aSWilliam Breathitt Gray 
654e357e81fSWilliam Breathitt Gray static const char *const quad8_synchronous_modes[] = {
655e357e81fSWilliam Breathitt Gray 	"non-synchronous",
656e357e81fSWilliam Breathitt Gray 	"synchronous"
657e357e81fSWilliam Breathitt Gray };
658e357e81fSWilliam Breathitt Gray 
quad8_synchronous_mode_get(struct counter_device * counter,struct counter_signal * signal,u32 * synchronous_mode)659f1d8a071SWilliam Breathitt Gray static int quad8_synchronous_mode_get(struct counter_device *counter,
660aaec1a0fSWilliam Breathitt Gray 				      struct counter_signal *signal,
661aaec1a0fSWilliam Breathitt Gray 				      u32 *synchronous_mode)
662f1d8a071SWilliam Breathitt Gray {
663aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
664f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
665f1d8a071SWilliam Breathitt Gray 
6664d8df168SWilliam Breathitt Gray 	*synchronous_mode = u8_get_bits(priv->idr[channel_id], INDEX_MODE);
667f1d8a071SWilliam Breathitt Gray 
668f1d8a071SWilliam Breathitt Gray 	return 0;
669f1d8a071SWilliam Breathitt Gray }
670f1d8a071SWilliam Breathitt Gray 
quad8_synchronous_mode_set(struct counter_device * counter,struct counter_signal * signal,u32 synchronous_mode)671f1d8a071SWilliam Breathitt Gray static int quad8_synchronous_mode_set(struct counter_device *counter,
672aaec1a0fSWilliam Breathitt Gray 				      struct counter_signal *signal,
673aaec1a0fSWilliam Breathitt Gray 				      u32 synchronous_mode)
674f1d8a071SWilliam Breathitt Gray {
675aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
676f1d8a071SWilliam Breathitt Gray 	const size_t channel_id = signal->id - 16;
6774d8df168SWilliam Breathitt Gray 	u8 quadrature_mode;
67809db4678SWilliam Breathitt Gray 	unsigned long irqflags;
679*98ffe025SWilliam Breathitt Gray 	int ret;
680fc069262SSyed Nayyar Waris 
68109db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
682fc069262SSyed Nayyar Waris 
683f1d8a071SWilliam Breathitt Gray 	/* Index function must be non-synchronous in non-quadrature mode */
6844d8df168SWilliam Breathitt Gray 	quadrature_mode = u8_get_bits(priv->idr[channel_id], QUADRATURE_MODE);
6854d8df168SWilliam Breathitt Gray 	if (synchronous_mode && quadrature_mode == NON_QUADRATURE) {
686*98ffe025SWilliam Breathitt Gray 		ret = -EINVAL;
687*98ffe025SWilliam Breathitt Gray 		goto exit_unlock;
688fc069262SSyed Nayyar Waris 	}
689f1d8a071SWilliam Breathitt Gray 
690*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->idr, channel_id, synchronous_mode,
691*98ffe025SWilliam Breathitt Gray 					    INDEX_MODE);
692f1d8a071SWilliam Breathitt Gray 
693*98ffe025SWilliam Breathitt Gray exit_unlock:
69409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
695fc069262SSyed Nayyar Waris 
696*98ffe025SWilliam Breathitt Gray 	return ret;
697f1d8a071SWilliam Breathitt Gray }
698f1d8a071SWilliam Breathitt Gray 
quad8_count_floor_read(struct counter_device * counter,struct counter_count * count,u64 * floor)699aaec1a0fSWilliam Breathitt Gray static int quad8_count_floor_read(struct counter_device *counter,
700aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count, u64 *floor)
701f1d8a071SWilliam Breathitt Gray {
702f1d8a071SWilliam Breathitt Gray 	/* Only a floor of 0 is supported */
703aaec1a0fSWilliam Breathitt Gray 	*floor = 0;
704aaec1a0fSWilliam Breathitt Gray 
705aaec1a0fSWilliam Breathitt Gray 	return 0;
706f1d8a071SWilliam Breathitt Gray }
707f1d8a071SWilliam Breathitt Gray 
quad8_count_mode_read(struct counter_device * counter,struct counter_count * count,enum counter_count_mode * cnt_mode)708aaec1a0fSWilliam Breathitt Gray static int quad8_count_mode_read(struct counter_device *counter,
709aaec1a0fSWilliam Breathitt Gray 				 struct counter_count *count,
710aaec1a0fSWilliam Breathitt Gray 				 enum counter_count_mode *cnt_mode)
711f1d8a071SWilliam Breathitt Gray {
712aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
713f1d8a071SWilliam Breathitt Gray 
7144d8df168SWilliam Breathitt Gray 	switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
715398abaabSWilliam Breathitt Gray 	case NORMAL_COUNT:
716f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
717f1d8a071SWilliam Breathitt Gray 		break;
718398abaabSWilliam Breathitt Gray 	case RANGE_LIMIT:
719f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
720f1d8a071SWilliam Breathitt Gray 		break;
721398abaabSWilliam Breathitt Gray 	case NON_RECYCLE_COUNT:
722f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
723f1d8a071SWilliam Breathitt Gray 		break;
724398abaabSWilliam Breathitt Gray 	case MODULO_N:
725f1d8a071SWilliam Breathitt Gray 		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
726f1d8a071SWilliam Breathitt Gray 		break;
727f1d8a071SWilliam Breathitt Gray 	}
728f1d8a071SWilliam Breathitt Gray 
729f1d8a071SWilliam Breathitt Gray 	return 0;
730f1d8a071SWilliam Breathitt Gray }
731f1d8a071SWilliam Breathitt Gray 
quad8_count_mode_write(struct counter_device * counter,struct counter_count * count,enum counter_count_mode cnt_mode)732aaec1a0fSWilliam Breathitt Gray static int quad8_count_mode_write(struct counter_device *counter,
733aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count,
734aaec1a0fSWilliam Breathitt Gray 				  enum counter_count_mode cnt_mode)
735f1d8a071SWilliam Breathitt Gray {
736aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
737aaec1a0fSWilliam Breathitt Gray 	unsigned int count_mode;
73809db4678SWilliam Breathitt Gray 	unsigned long irqflags;
739*98ffe025SWilliam Breathitt Gray 	int ret;
740f1d8a071SWilliam Breathitt Gray 
741f1d8a071SWilliam Breathitt Gray 	switch (cnt_mode) {
742f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_NORMAL:
743398abaabSWilliam Breathitt Gray 		count_mode = NORMAL_COUNT;
744f1d8a071SWilliam Breathitt Gray 		break;
745f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_RANGE_LIMIT:
746398abaabSWilliam Breathitt Gray 		count_mode = RANGE_LIMIT;
747f1d8a071SWilliam Breathitt Gray 		break;
748f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_NON_RECYCLE:
749398abaabSWilliam Breathitt Gray 		count_mode = NON_RECYCLE_COUNT;
750f1d8a071SWilliam Breathitt Gray 		break;
751f1d8a071SWilliam Breathitt Gray 	case COUNTER_COUNT_MODE_MODULO_N:
752398abaabSWilliam Breathitt Gray 		count_mode = MODULO_N;
753f1d8a071SWilliam Breathitt Gray 		break;
754b11eed15SWilliam Breathitt Gray 	default:
755b11eed15SWilliam Breathitt Gray 		/* should never reach this path */
756b11eed15SWilliam Breathitt Gray 		return -EINVAL;
757f1d8a071SWilliam Breathitt Gray 	}
758f1d8a071SWilliam Breathitt Gray 
75909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
760fc069262SSyed Nayyar Waris 
761*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->cmr, count->id, count_mode,
762*98ffe025SWilliam Breathitt Gray 					    COUNT_MODE);
763f1d8a071SWilliam Breathitt Gray 
76409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
765fc069262SSyed Nayyar Waris 
766*98ffe025SWilliam Breathitt Gray 	return ret;
767f1d8a071SWilliam Breathitt Gray }
768f1d8a071SWilliam Breathitt Gray 
quad8_count_enable_read(struct counter_device * counter,struct counter_count * count,u8 * enable)769aaec1a0fSWilliam Breathitt Gray static int quad8_count_enable_read(struct counter_device *counter,
770aaec1a0fSWilliam Breathitt Gray 				   struct counter_count *count, u8 *enable)
771f1d8a071SWilliam Breathitt Gray {
772aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
773f1d8a071SWilliam Breathitt Gray 
7744d8df168SWilliam Breathitt Gray 	*enable = u8_get_bits(priv->ior[count->id], AB_GATE);
775aaec1a0fSWilliam Breathitt Gray 
776aaec1a0fSWilliam Breathitt Gray 	return 0;
777f1d8a071SWilliam Breathitt Gray }
778f1d8a071SWilliam Breathitt Gray 
quad8_count_enable_write(struct counter_device * counter,struct counter_count * count,u8 enable)779aaec1a0fSWilliam Breathitt Gray static int quad8_count_enable_write(struct counter_device *counter,
780aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u8 enable)
781f1d8a071SWilliam Breathitt Gray {
782aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
78309db4678SWilliam Breathitt Gray 	unsigned long irqflags;
784*98ffe025SWilliam Breathitt Gray 	int ret;
785f1d8a071SWilliam Breathitt Gray 
78609db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
787fc069262SSyed Nayyar Waris 
788*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->ior, count->id, enable, AB_GATE);
789f1d8a071SWilliam Breathitt Gray 
79009db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
791fc069262SSyed Nayyar Waris 
792*98ffe025SWilliam Breathitt Gray 	return ret;
793f1d8a071SWilliam Breathitt Gray }
794f1d8a071SWilliam Breathitt Gray 
795e357e81fSWilliam Breathitt Gray static const char *const quad8_noise_error_states[] = {
796e357e81fSWilliam Breathitt Gray 	"No excessive noise is present at the count inputs",
797e357e81fSWilliam Breathitt Gray 	"Excessive noise is present at the count inputs"
798e357e81fSWilliam Breathitt Gray };
799e357e81fSWilliam Breathitt Gray 
quad8_error_noise_get(struct counter_device * counter,struct counter_count * count,u32 * noise_error)800f1d8a071SWilliam Breathitt Gray static int quad8_error_noise_get(struct counter_device *counter,
801aaec1a0fSWilliam Breathitt Gray 				 struct counter_count *count, u32 *noise_error)
802f1d8a071SWilliam Breathitt Gray {
803aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
804*98ffe025SWilliam Breathitt Gray 	unsigned int flag;
805*98ffe025SWilliam Breathitt Gray 	int ret;
806f1d8a071SWilliam Breathitt Gray 
807*98ffe025SWilliam Breathitt Gray 	ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
808*98ffe025SWilliam Breathitt Gray 	if (ret)
809*98ffe025SWilliam Breathitt Gray 		return ret;
810398abaabSWilliam Breathitt Gray 	*noise_error = u8_get_bits(flag, FLAG_E);
811f1d8a071SWilliam Breathitt Gray 
812f1d8a071SWilliam Breathitt Gray 	return 0;
813f1d8a071SWilliam Breathitt Gray }
814f1d8a071SWilliam Breathitt Gray 
quad8_count_preset_read(struct counter_device * counter,struct counter_count * count,u64 * preset)815aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_read(struct counter_device *counter,
816aaec1a0fSWilliam Breathitt Gray 				   struct counter_count *count, u64 *preset)
817f1d8a071SWilliam Breathitt Gray {
818aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
819f1d8a071SWilliam Breathitt Gray 
820aaec1a0fSWilliam Breathitt Gray 	*preset = priv->preset[count->id];
821aaec1a0fSWilliam Breathitt Gray 
822aaec1a0fSWilliam Breathitt Gray 	return 0;
823f1d8a071SWilliam Breathitt Gray }
824f1d8a071SWilliam Breathitt Gray 
quad8_count_preset_write(struct counter_device * counter,struct counter_count * count,u64 preset)825aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_write(struct counter_device *counter,
826aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u64 preset)
827f1d8a071SWilliam Breathitt Gray {
828aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
82909db4678SWilliam Breathitt Gray 	unsigned long irqflags;
830*98ffe025SWilliam Breathitt Gray 	int ret;
831f1d8a071SWilliam Breathitt Gray 
8324aa3b75cSWilliam Breathitt Gray 	if (preset > LS7267_CNTR_MAX)
833e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
834f1d8a071SWilliam Breathitt Gray 
83509db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
836f1d8a071SWilliam Breathitt Gray 
837142c8622SWilliam Breathitt Gray 	priv->preset[count->id] = preset;
838*98ffe025SWilliam Breathitt Gray 	ret = quad8_preset_register_set(priv, count->id, preset);
839f1d8a071SWilliam Breathitt Gray 
84009db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
841f1d8a071SWilliam Breathitt Gray 
842*98ffe025SWilliam Breathitt Gray 	return ret;
843f1d8a071SWilliam Breathitt Gray }
844f1d8a071SWilliam Breathitt Gray 
quad8_count_ceiling_read(struct counter_device * counter,struct counter_count * count,u64 * ceiling)845aaec1a0fSWilliam Breathitt Gray static int quad8_count_ceiling_read(struct counter_device *counter,
846aaec1a0fSWilliam Breathitt Gray 				    struct counter_count *count, u64 *ceiling)
847f1d8a071SWilliam Breathitt Gray {
848aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
84909db4678SWilliam Breathitt Gray 	unsigned long irqflags;
850fc069262SSyed Nayyar Waris 
85109db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
852f1d8a071SWilliam Breathitt Gray 
853f1d8a071SWilliam Breathitt Gray 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
8544d8df168SWilliam Breathitt Gray 	switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
855398abaabSWilliam Breathitt Gray 	case RANGE_LIMIT:
856398abaabSWilliam Breathitt Gray 	case MODULO_N:
857aaec1a0fSWilliam Breathitt Gray 		*ceiling = priv->preset[count->id];
858aaec1a0fSWilliam Breathitt Gray 		break;
859aaec1a0fSWilliam Breathitt Gray 	default:
8604aa3b75cSWilliam Breathitt Gray 		*ceiling = LS7267_CNTR_MAX;
861aaec1a0fSWilliam Breathitt Gray 		break;
862f1d8a071SWilliam Breathitt Gray 	}
863f1d8a071SWilliam Breathitt Gray 
86409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
865aaec1a0fSWilliam Breathitt Gray 
866aaec1a0fSWilliam Breathitt Gray 	return 0;
867aaec1a0fSWilliam Breathitt Gray }
868aaec1a0fSWilliam Breathitt Gray 
quad8_count_ceiling_write(struct counter_device * counter,struct counter_count * count,u64 ceiling)869aaec1a0fSWilliam Breathitt Gray static int quad8_count_ceiling_write(struct counter_device *counter,
870aaec1a0fSWilliam Breathitt Gray 				     struct counter_count *count, u64 ceiling)
871f1d8a071SWilliam Breathitt Gray {
872aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
87309db4678SWilliam Breathitt Gray 	unsigned long irqflags;
874*98ffe025SWilliam Breathitt Gray 	int ret;
875fc069262SSyed Nayyar Waris 
8764aa3b75cSWilliam Breathitt Gray 	if (ceiling > LS7267_CNTR_MAX)
877e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
878fc069262SSyed Nayyar Waris 
87909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
880f1d8a071SWilliam Breathitt Gray 
881f1d8a071SWilliam Breathitt Gray 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
8824d8df168SWilliam Breathitt Gray 	switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
883398abaabSWilliam Breathitt Gray 	case RANGE_LIMIT:
884398abaabSWilliam Breathitt Gray 	case MODULO_N:
885142c8622SWilliam Breathitt Gray 		priv->preset[count->id] = ceiling;
886*98ffe025SWilliam Breathitt Gray 		ret = quad8_preset_register_set(priv, count->id, ceiling);
887*98ffe025SWilliam Breathitt Gray 		break;
888*98ffe025SWilliam Breathitt Gray 	default:
889*98ffe025SWilliam Breathitt Gray 		ret = -EINVAL;
890*98ffe025SWilliam Breathitt Gray 		break;
891f1d8a071SWilliam Breathitt Gray 	}
892f1d8a071SWilliam Breathitt Gray 
89309db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
894fc069262SSyed Nayyar Waris 
895*98ffe025SWilliam Breathitt Gray 	return ret;
896f1d8a071SWilliam Breathitt Gray }
897f1d8a071SWilliam Breathitt Gray 
quad8_count_preset_enable_read(struct counter_device * counter,struct counter_count * count,u8 * preset_enable)898aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_enable_read(struct counter_device *counter,
899aaec1a0fSWilliam Breathitt Gray 					  struct counter_count *count,
900aaec1a0fSWilliam Breathitt Gray 					  u8 *preset_enable)
901f1d8a071SWilliam Breathitt Gray {
902aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
903f1d8a071SWilliam Breathitt Gray 
9044d8df168SWilliam Breathitt Gray 	/* Preset enable is active low in Input/Output Control register */
9054d8df168SWilliam Breathitt Gray 	*preset_enable = !u8_get_bits(priv->ior[count->id], LOAD_PIN);
906aaec1a0fSWilliam Breathitt Gray 
907aaec1a0fSWilliam Breathitt Gray 	return 0;
908f1d8a071SWilliam Breathitt Gray }
909f1d8a071SWilliam Breathitt Gray 
quad8_count_preset_enable_write(struct counter_device * counter,struct counter_count * count,u8 preset_enable)910aaec1a0fSWilliam Breathitt Gray static int quad8_count_preset_enable_write(struct counter_device *counter,
911aaec1a0fSWilliam Breathitt Gray 					   struct counter_count *count,
912aaec1a0fSWilliam Breathitt Gray 					   u8 preset_enable)
913f1d8a071SWilliam Breathitt Gray {
914aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
91509db4678SWilliam Breathitt Gray 	unsigned long irqflags;
916*98ffe025SWilliam Breathitt Gray 	int ret;
917f1d8a071SWilliam Breathitt Gray 
91809db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
919fc069262SSyed Nayyar Waris 
9204d8df168SWilliam Breathitt Gray 	/* Preset enable is active low in Input/Output Control register */
921*98ffe025SWilliam Breathitt Gray 	ret = quad8_control_register_update(priv->map, priv->ior, count->id, !preset_enable,
922*98ffe025SWilliam Breathitt Gray 					    LOAD_PIN);
923f1d8a071SWilliam Breathitt Gray 
92409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
925fc069262SSyed Nayyar Waris 
926*98ffe025SWilliam Breathitt Gray 	return ret;
927f1d8a071SWilliam Breathitt Gray }
928f1d8a071SWilliam Breathitt Gray 
quad8_signal_cable_fault_read(struct counter_device * counter,struct counter_signal * signal,u8 * cable_fault)929aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_read(struct counter_device *counter,
930954ab5ccSWilliam Breathitt Gray 					 struct counter_signal *signal,
931aaec1a0fSWilliam Breathitt Gray 					 u8 *cable_fault)
932954ab5ccSWilliam Breathitt Gray {
933aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
934954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
93509db4678SWilliam Breathitt Gray 	unsigned long irqflags;
936708d9893SSyed Nayyar Waris 	bool disabled;
937*98ffe025SWilliam Breathitt Gray 	int ret;
938954ab5ccSWilliam Breathitt Gray 
93909db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
940708d9893SSyed Nayyar Waris 
941708d9893SSyed Nayyar Waris 	disabled = !(priv->cable_fault_enable & BIT(channel_id));
942708d9893SSyed Nayyar Waris 
943708d9893SSyed Nayyar Waris 	if (disabled) {
94409db4678SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
945954ab5ccSWilliam Breathitt Gray 		return -EINVAL;
946708d9893SSyed Nayyar Waris 	}
947954ab5ccSWilliam Breathitt Gray 
948*98ffe025SWilliam Breathitt Gray 	ret = regmap_test_bits(priv->map, QUAD8_CABLE_STATUS, BIT(channel_id));
949*98ffe025SWilliam Breathitt Gray 	if (ret < 0) {
950*98ffe025SWilliam Breathitt Gray 		spin_unlock_irqrestore(&priv->lock, irqflags);
951*98ffe025SWilliam Breathitt Gray 		return ret;
952*98ffe025SWilliam Breathitt Gray 	}
953954ab5ccSWilliam Breathitt Gray 
95409db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
955708d9893SSyed Nayyar Waris 
956*98ffe025SWilliam Breathitt Gray 	/* Logic 0 = cable fault */
957*98ffe025SWilliam Breathitt Gray 	*cable_fault = !ret;
958954ab5ccSWilliam Breathitt Gray 
959aaec1a0fSWilliam Breathitt Gray 	return 0;
960954ab5ccSWilliam Breathitt Gray }
961954ab5ccSWilliam Breathitt Gray 
quad8_signal_cable_fault_enable_read(struct counter_device * counter,struct counter_signal * signal,u8 * enable)962aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_enable_read(struct counter_device *counter,
963aaec1a0fSWilliam Breathitt Gray 						struct counter_signal *signal,
964aaec1a0fSWilliam Breathitt Gray 						u8 *enable)
965954ab5ccSWilliam Breathitt Gray {
966aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
967954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
968954ab5ccSWilliam Breathitt Gray 
969aaec1a0fSWilliam Breathitt Gray 	*enable = !!(priv->cable_fault_enable & BIT(channel_id));
970aaec1a0fSWilliam Breathitt Gray 
971aaec1a0fSWilliam Breathitt Gray 	return 0;
972954ab5ccSWilliam Breathitt Gray }
973954ab5ccSWilliam Breathitt Gray 
quad8_signal_cable_fault_enable_write(struct counter_device * counter,struct counter_signal * signal,u8 enable)974aaec1a0fSWilliam Breathitt Gray static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
975aaec1a0fSWilliam Breathitt Gray 						 struct counter_signal *signal,
976aaec1a0fSWilliam Breathitt Gray 						 u8 enable)
977954ab5ccSWilliam Breathitt Gray {
978aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
979954ab5ccSWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
98009db4678SWilliam Breathitt Gray 	unsigned long irqflags;
981954ab5ccSWilliam Breathitt Gray 	unsigned int cable_fault_enable;
982*98ffe025SWilliam Breathitt Gray 	int ret;
983954ab5ccSWilliam Breathitt Gray 
98409db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
985708d9893SSyed Nayyar Waris 
986954ab5ccSWilliam Breathitt Gray 	if (enable)
987954ab5ccSWilliam Breathitt Gray 		priv->cable_fault_enable |= BIT(channel_id);
988954ab5ccSWilliam Breathitt Gray 	else
989954ab5ccSWilliam Breathitt Gray 		priv->cable_fault_enable &= ~BIT(channel_id);
990954ab5ccSWilliam Breathitt Gray 
991954ab5ccSWilliam Breathitt Gray 	/* Enable is active low in Differential Encoder Cable Status register */
992954ab5ccSWilliam Breathitt Gray 	cable_fault_enable = ~priv->cable_fault_enable;
993954ab5ccSWilliam Breathitt Gray 
994*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, cable_fault_enable);
995954ab5ccSWilliam Breathitt Gray 
99609db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
997708d9893SSyed Nayyar Waris 
998*98ffe025SWilliam Breathitt Gray 	return ret;
999954ab5ccSWilliam Breathitt Gray }
1000954ab5ccSWilliam Breathitt Gray 
quad8_signal_fck_prescaler_read(struct counter_device * counter,struct counter_signal * signal,u8 * prescaler)1001aaec1a0fSWilliam Breathitt Gray static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
1002aaec1a0fSWilliam Breathitt Gray 					   struct counter_signal *signal,
1003aaec1a0fSWilliam Breathitt Gray 					   u8 *prescaler)
1004de65d055SWilliam Breathitt Gray {
1005aea8334bSUwe Kleine-König 	const struct quad8 *const priv = counter_priv(counter);
1006de65d055SWilliam Breathitt Gray 
1007aaec1a0fSWilliam Breathitt Gray 	*prescaler = priv->fck_prescaler[signal->id / 2];
1008aaec1a0fSWilliam Breathitt Gray 
1009aaec1a0fSWilliam Breathitt Gray 	return 0;
1010de65d055SWilliam Breathitt Gray }
1011de65d055SWilliam Breathitt Gray 
quad8_filter_clock_prescaler_set(struct quad8 * const priv,const size_t id,const u8 prescaler)1012*98ffe025SWilliam Breathitt Gray static int quad8_filter_clock_prescaler_set(struct quad8 *const priv, const size_t id,
1013142c8622SWilliam Breathitt Gray 					    const u8 prescaler)
1014142c8622SWilliam Breathitt Gray {
1015*98ffe025SWilliam Breathitt Gray 	int ret;
1016142c8622SWilliam Breathitt Gray 
1017*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
1018*98ffe025SWilliam Breathitt Gray 	if (ret)
1019*98ffe025SWilliam Breathitt Gray 		return ret;
1020*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_DATA(id), prescaler);
1021*98ffe025SWilliam Breathitt Gray 	if (ret)
1022*98ffe025SWilliam Breathitt Gray 		return ret;
1023*98ffe025SWilliam Breathitt Gray 	return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | TRANSFER_PR0_TO_PSC);
1024142c8622SWilliam Breathitt Gray }
1025142c8622SWilliam Breathitt Gray 
quad8_signal_fck_prescaler_write(struct counter_device * counter,struct counter_signal * signal,u8 prescaler)1026aaec1a0fSWilliam Breathitt Gray static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
1027aaec1a0fSWilliam Breathitt Gray 					    struct counter_signal *signal,
1028aaec1a0fSWilliam Breathitt Gray 					    u8 prescaler)
1029de65d055SWilliam Breathitt Gray {
1030aea8334bSUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
1031de65d055SWilliam Breathitt Gray 	const size_t channel_id = signal->id / 2;
103209db4678SWilliam Breathitt Gray 	unsigned long irqflags;
1033*98ffe025SWilliam Breathitt Gray 	int ret;
1034de65d055SWilliam Breathitt Gray 
103509db4678SWilliam Breathitt Gray 	spin_lock_irqsave(&priv->lock, irqflags);
1036d5ed76adSSyed Nayyar Waris 
1037de65d055SWilliam Breathitt Gray 	priv->fck_prescaler[channel_id] = prescaler;
1038*98ffe025SWilliam Breathitt Gray 	ret = quad8_filter_clock_prescaler_set(priv, channel_id, prescaler);
1039de65d055SWilliam Breathitt Gray 
104009db4678SWilliam Breathitt Gray 	spin_unlock_irqrestore(&priv->lock, irqflags);
1041d5ed76adSSyed Nayyar Waris 
1042*98ffe025SWilliam Breathitt Gray 	return ret;
1043de65d055SWilliam Breathitt Gray }
1044de65d055SWilliam Breathitt Gray 
1045aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_signal_ext[] = {
1046aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_BOOL("cable_fault", quad8_signal_cable_fault_read,
1047aaec1a0fSWilliam Breathitt Gray 				 NULL),
1048aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_BOOL("cable_fault_enable",
1049aaec1a0fSWilliam Breathitt Gray 				 quad8_signal_cable_fault_enable_read,
1050aaec1a0fSWilliam Breathitt Gray 				 quad8_signal_cable_fault_enable_write),
1051aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_U8("filter_clock_prescaler",
1052aaec1a0fSWilliam Breathitt Gray 			       quad8_signal_fck_prescaler_read,
1053aaec1a0fSWilliam Breathitt Gray 			       quad8_signal_fck_prescaler_write)
1054de65d055SWilliam Breathitt Gray };
1055de65d055SWilliam Breathitt Gray 
10569830288aSWilliam Breathitt Gray static const enum counter_signal_polarity quad8_polarities[] = {
10579830288aSWilliam Breathitt Gray 	COUNTER_SIGNAL_POLARITY_POSITIVE,
10589830288aSWilliam Breathitt Gray 	COUNTER_SIGNAL_POLARITY_NEGATIVE,
10599830288aSWilliam Breathitt Gray };
10609830288aSWilliam Breathitt Gray 
10619830288aSWilliam Breathitt Gray static DEFINE_COUNTER_AVAILABLE(quad8_polarity_available, quad8_polarities);
10629830288aSWilliam Breathitt Gray 
1063aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
1064aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
1065aaec1a0fSWilliam Breathitt Gray 
1066aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_index_ext[] = {
1067aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get,
1068aaec1a0fSWilliam Breathitt Gray 				 quad8_index_polarity_set,
1069aaec1a0fSWilliam Breathitt Gray 				 quad8_index_pol_enum),
10709830288aSWilliam Breathitt Gray 	COUNTER_COMP_POLARITY(quad8_polarity_read, quad8_polarity_write,
10719830288aSWilliam Breathitt Gray 			      quad8_polarity_available),
1072aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get,
1073aaec1a0fSWilliam Breathitt Gray 				 quad8_synchronous_mode_set,
1074aaec1a0fSWilliam Breathitt Gray 				 quad8_synch_mode_enum),
1075f1d8a071SWilliam Breathitt Gray };
1076f1d8a071SWilliam Breathitt Gray 
1077f1d8a071SWilliam Breathitt Gray #define QUAD8_QUAD_SIGNAL(_id, _name) {		\
1078f1d8a071SWilliam Breathitt Gray 	.id = (_id),				\
1079de65d055SWilliam Breathitt Gray 	.name = (_name),			\
1080de65d055SWilliam Breathitt Gray 	.ext = quad8_signal_ext,		\
1081de65d055SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_signal_ext)	\
1082f1d8a071SWilliam Breathitt Gray }
1083f1d8a071SWilliam Breathitt Gray 
1084f1d8a071SWilliam Breathitt Gray #define	QUAD8_INDEX_SIGNAL(_id, _name) {	\
1085f1d8a071SWilliam Breathitt Gray 	.id = (_id),				\
1086f1d8a071SWilliam Breathitt Gray 	.name = (_name),			\
1087f1d8a071SWilliam Breathitt Gray 	.ext = quad8_index_ext,			\
1088f1d8a071SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_index_ext)	\
1089f1d8a071SWilliam Breathitt Gray }
1090f1d8a071SWilliam Breathitt Gray 
1091f1d8a071SWilliam Breathitt Gray static struct counter_signal quad8_signals[] = {
1092f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1093f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1094f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1095f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1096f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1097f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1098f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1099f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1100f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1101f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1102f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1103f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1104f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1105f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1106f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1107f1d8a071SWilliam Breathitt Gray 	QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1108f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1109f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1110f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1111f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1112f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1113f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1114f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1115f1d8a071SWilliam Breathitt Gray 	QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1116f1d8a071SWilliam Breathitt Gray };
1117f1d8a071SWilliam Breathitt Gray 
1118f1d8a071SWilliam Breathitt Gray #define QUAD8_COUNT_SYNAPSES(_id) {					\
1119f1d8a071SWilliam Breathitt Gray 	{								\
1120f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_synapse_actions_list,		\
1121f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1122f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id)			\
1123f1d8a071SWilliam Breathitt Gray 	},								\
1124f1d8a071SWilliam Breathitt Gray 	{								\
1125f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_synapse_actions_list,		\
1126f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_synapse_actions_list),	\
1127f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id) + 1			\
1128f1d8a071SWilliam Breathitt Gray 	},								\
1129f1d8a071SWilliam Breathitt Gray 	{								\
1130f1d8a071SWilliam Breathitt Gray 		.actions_list = quad8_index_actions_list,		\
1131f1d8a071SWilliam Breathitt Gray 		.num_actions = ARRAY_SIZE(quad8_index_actions_list),	\
1132f1d8a071SWilliam Breathitt Gray 		.signal = quad8_signals + 2 * (_id) + 16		\
1133f1d8a071SWilliam Breathitt Gray 	}								\
1134f1d8a071SWilliam Breathitt Gray }
1135f1d8a071SWilliam Breathitt Gray 
1136f1d8a071SWilliam Breathitt Gray static struct counter_synapse quad8_count_synapses[][3] = {
1137f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1138f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1139f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1140f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1141f1d8a071SWilliam Breathitt Gray };
1142f1d8a071SWilliam Breathitt Gray 
1143aaec1a0fSWilliam Breathitt Gray static const enum counter_count_mode quad8_cnt_modes[] = {
1144aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_NORMAL,
1145aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_RANGE_LIMIT,
1146aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_NON_RECYCLE,
1147aaec1a0fSWilliam Breathitt Gray 	COUNTER_COUNT_MODE_MODULO_N,
1148aaec1a0fSWilliam Breathitt Gray };
1149aaec1a0fSWilliam Breathitt Gray 
1150aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_AVAILABLE(quad8_count_mode_available, quad8_cnt_modes);
1151aaec1a0fSWilliam Breathitt Gray 
1152aaec1a0fSWilliam Breathitt Gray static DEFINE_COUNTER_ENUM(quad8_error_noise_enum, quad8_noise_error_states);
1153aaec1a0fSWilliam Breathitt Gray 
1154aaec1a0fSWilliam Breathitt Gray static struct counter_comp quad8_count_ext[] = {
1155aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_CEILING(quad8_count_ceiling_read,
1156aaec1a0fSWilliam Breathitt Gray 			     quad8_count_ceiling_write),
1157aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_FLOOR(quad8_count_floor_read, NULL),
1158aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_MODE(quad8_count_mode_read, quad8_count_mode_write,
1159aaec1a0fSWilliam Breathitt Gray 				quad8_count_mode_available),
1160aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_DIRECTION(quad8_direction_read),
1161aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_ENABLE(quad8_count_enable_read, quad8_count_enable_write),
1162aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_ENUM("error_noise", quad8_error_noise_get, NULL,
1163aaec1a0fSWilliam Breathitt Gray 				quad8_error_noise_enum),
1164aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_PRESET(quad8_count_preset_read, quad8_count_preset_write),
1165aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_PRESET_ENABLE(quad8_count_preset_enable_read,
1166aaec1a0fSWilliam Breathitt Gray 				   quad8_count_preset_enable_write),
1167f1d8a071SWilliam Breathitt Gray };
1168f1d8a071SWilliam Breathitt Gray 
1169f1d8a071SWilliam Breathitt Gray #define QUAD8_COUNT(_id, _cntname) {					\
1170f1d8a071SWilliam Breathitt Gray 	.id = (_id),							\
1171f1d8a071SWilliam Breathitt Gray 	.name = (_cntname),						\
1172f1d8a071SWilliam Breathitt Gray 	.functions_list = quad8_count_functions_list,			\
1173f1d8a071SWilliam Breathitt Gray 	.num_functions = ARRAY_SIZE(quad8_count_functions_list),	\
1174f1d8a071SWilliam Breathitt Gray 	.synapses = quad8_count_synapses[(_id)],			\
1175f1d8a071SWilliam Breathitt Gray 	.num_synapses =	2,						\
1176f1d8a071SWilliam Breathitt Gray 	.ext = quad8_count_ext,						\
1177f1d8a071SWilliam Breathitt Gray 	.num_ext = ARRAY_SIZE(quad8_count_ext)				\
1178f1d8a071SWilliam Breathitt Gray }
1179f1d8a071SWilliam Breathitt Gray 
1180f1d8a071SWilliam Breathitt Gray static struct counter_count quad8_counts[] = {
1181f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(0, "Channel 1 Count"),
1182f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(1, "Channel 2 Count"),
1183f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(2, "Channel 3 Count"),
1184f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(3, "Channel 4 Count"),
1185f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(4, "Channel 5 Count"),
1186f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(5, "Channel 6 Count"),
1187f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(6, "Channel 7 Count"),
1188f1d8a071SWilliam Breathitt Gray 	QUAD8_COUNT(7, "Channel 8 Count")
1189f1d8a071SWilliam Breathitt Gray };
1190f1d8a071SWilliam Breathitt Gray 
quad8_irq_handler(int irq,void * private)11917aa2ba0dSWilliam Breathitt Gray static irqreturn_t quad8_irq_handler(int irq, void *private)
11927aa2ba0dSWilliam Breathitt Gray {
11939e884bb1SUwe Kleine-König 	struct counter_device *counter = private;
11949e884bb1SUwe Kleine-König 	struct quad8 *const priv = counter_priv(counter);
1195*98ffe025SWilliam Breathitt Gray 	unsigned int status;
11967aa2ba0dSWilliam Breathitt Gray 	unsigned long irq_status;
11977aa2ba0dSWilliam Breathitt Gray 	unsigned long channel;
11984d8df168SWilliam Breathitt Gray 	unsigned int flg_pins;
11997aa2ba0dSWilliam Breathitt Gray 	u8 event;
1200*98ffe025SWilliam Breathitt Gray 	int ret;
12017aa2ba0dSWilliam Breathitt Gray 
1202*98ffe025SWilliam Breathitt Gray 	ret = regmap_read(priv->map, QUAD8_INTERRUPT_STATUS, &status);
1203*98ffe025SWilliam Breathitt Gray 	if (ret)
1204*98ffe025SWilliam Breathitt Gray 		return ret;
1205*98ffe025SWilliam Breathitt Gray 	if (!status)
12067aa2ba0dSWilliam Breathitt Gray 		return IRQ_NONE;
12077aa2ba0dSWilliam Breathitt Gray 
1208*98ffe025SWilliam Breathitt Gray 	irq_status = status;
12097aa2ba0dSWilliam Breathitt Gray 	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
12104d8df168SWilliam Breathitt Gray 		flg_pins = u8_get_bits(priv->ior[channel], FLG_PINS);
12114d8df168SWilliam Breathitt Gray 		switch (flg_pins) {
12124d8df168SWilliam Breathitt Gray 		case FLG1_CARRY_FLG2_BORROW:
12137aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_OVERFLOW;
12147aa2ba0dSWilliam Breathitt Gray 				break;
12154d8df168SWilliam Breathitt Gray 		case FLG1_COMPARE_FLG2_BORROW:
12167aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_THRESHOLD;
12177aa2ba0dSWilliam Breathitt Gray 				break;
12184d8df168SWilliam Breathitt Gray 		case FLG1_CARRYBORROW_FLG2_UD:
12197aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
12207aa2ba0dSWilliam Breathitt Gray 				break;
12214d8df168SWilliam Breathitt Gray 		case FLG1_INDX_FLG2_E:
12227aa2ba0dSWilliam Breathitt Gray 			event = COUNTER_EVENT_INDEX;
12237aa2ba0dSWilliam Breathitt Gray 				break;
12247aa2ba0dSWilliam Breathitt Gray 		default:
12257aa2ba0dSWilliam Breathitt Gray 			/* should never reach this path */
12267aa2ba0dSWilliam Breathitt Gray 			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
12274d8df168SWilliam Breathitt Gray 				  flg_pins, channel);
12287aa2ba0dSWilliam Breathitt Gray 			continue;
12297aa2ba0dSWilliam Breathitt Gray 		}
12307aa2ba0dSWilliam Breathitt Gray 
12319e884bb1SUwe Kleine-König 		counter_push_event(counter, event, channel);
12327aa2ba0dSWilliam Breathitt Gray 	}
12337aa2ba0dSWilliam Breathitt Gray 
1234*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION, CLEAR_PENDING_INTERRUPTS);
1235*98ffe025SWilliam Breathitt Gray 	if (ret)
1236*98ffe025SWilliam Breathitt Gray 		return ret;
12377aa2ba0dSWilliam Breathitt Gray 
12387aa2ba0dSWilliam Breathitt Gray 	return IRQ_HANDLED;
12397aa2ba0dSWilliam Breathitt Gray }
12407aa2ba0dSWilliam Breathitt Gray 
quad8_init_counter(struct quad8 * const priv,const size_t channel)1241*98ffe025SWilliam Breathitt Gray static int quad8_init_counter(struct quad8 *const priv, const size_t channel)
1242b6e9cdedSWilliam Breathitt Gray {
1243*98ffe025SWilliam Breathitt Gray 	int ret;
1244b6e9cdedSWilliam Breathitt Gray 
1245*98ffe025SWilliam Breathitt Gray 	ret = quad8_filter_clock_prescaler_set(priv, channel, 0);
1246*98ffe025SWilliam Breathitt Gray 	if (ret)
1247*98ffe025SWilliam Breathitt Gray 		return ret;
1248*98ffe025SWilliam Breathitt Gray 	ret = quad8_preset_register_set(priv, channel, 0);
1249*98ffe025SWilliam Breathitt Gray 	if (ret)
1250*98ffe025SWilliam Breathitt Gray 		return ret;
1251*98ffe025SWilliam Breathitt Gray 	ret = quad8_flag_register_reset(priv, channel);
1252*98ffe025SWilliam Breathitt Gray 	if (ret)
1253*98ffe025SWilliam Breathitt Gray 		return ret;
12544d8df168SWilliam Breathitt Gray 
1255b6e9cdedSWilliam Breathitt Gray 	/* Binary encoding; Normal count; non-quadrature mode */
12564d8df168SWilliam Breathitt Gray 	priv->cmr[channel] = SELECT_CMR | BINARY | u8_encode_bits(NORMAL_COUNT, COUNT_MODE) |
12574d8df168SWilliam Breathitt Gray 			     u8_encode_bits(NON_QUADRATURE, QUADRATURE_MODE);
1258*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->cmr[channel]);
1259*98ffe025SWilliam Breathitt Gray 	if (ret)
1260*98ffe025SWilliam Breathitt Gray 		return ret;
12614d8df168SWilliam Breathitt Gray 
1262b6e9cdedSWilliam Breathitt Gray 	/* Disable A and B inputs; preset on index; FLG1 as Carry */
12634d8df168SWilliam Breathitt Gray 	priv->ior[channel] = SELECT_IOR | DISABLE_AB | u8_encode_bits(LOAD_CNTR, LOAD_PIN) |
12644d8df168SWilliam Breathitt Gray 			     u8_encode_bits(FLG1_CARRY_FLG2_BORROW, FLG_PINS);
1265*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->ior[channel]);
1266*98ffe025SWilliam Breathitt Gray 	if (ret)
1267*98ffe025SWilliam Breathitt Gray 		return ret;
12684d8df168SWilliam Breathitt Gray 
1269b6e9cdedSWilliam Breathitt Gray 	/* Disable index function; negative index polarity */
12704d8df168SWilliam Breathitt Gray 	priv->idr[channel] = SELECT_IDR | u8_encode_bits(DISABLE_INDEX_MODE, INDEX_MODE) |
12714d8df168SWilliam Breathitt Gray 			     u8_encode_bits(NEGATIVE_INDEX_POLARITY, INDEX_POLARITY);
1272*98ffe025SWilliam Breathitt Gray 	return regmap_write(priv->map, QUAD8_CONTROL(channel), priv->idr[channel]);
1273b6e9cdedSWilliam Breathitt Gray }
1274b6e9cdedSWilliam Breathitt Gray 
quad8_probe(struct device * dev,unsigned int id)1275f1d8a071SWilliam Breathitt Gray static int quad8_probe(struct device *dev, unsigned int id)
1276f1d8a071SWilliam Breathitt Gray {
12779e884bb1SUwe Kleine-König 	struct counter_device *counter;
1278e357e81fSWilliam Breathitt Gray 	struct quad8 *priv;
1279*98ffe025SWilliam Breathitt Gray 	void __iomem *regs;
1280b6e9cdedSWilliam Breathitt Gray 	unsigned long i;
1281*98ffe025SWilliam Breathitt Gray 	int ret;
1282f1d8a071SWilliam Breathitt Gray 
1283f1d8a071SWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
1284f1d8a071SWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1285f1d8a071SWilliam Breathitt Gray 			base[id], base[id] + QUAD8_EXTENT);
1286f1d8a071SWilliam Breathitt Gray 		return -EBUSY;
1287f1d8a071SWilliam Breathitt Gray 	}
1288f1d8a071SWilliam Breathitt Gray 
12899e884bb1SUwe Kleine-König 	counter = devm_counter_alloc(dev, sizeof(*priv));
12909e884bb1SUwe Kleine-König 	if (!counter)
1291f1d8a071SWilliam Breathitt Gray 		return -ENOMEM;
12929e884bb1SUwe Kleine-König 	priv = counter_priv(counter);
1293f1d8a071SWilliam Breathitt Gray 
1294*98ffe025SWilliam Breathitt Gray 	regs = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
1295*98ffe025SWilliam Breathitt Gray 	if (!regs)
1296b6e9cdedSWilliam Breathitt Gray 		return -ENOMEM;
1297b6e9cdedSWilliam Breathitt Gray 
1298*98ffe025SWilliam Breathitt Gray 	priv->map = devm_regmap_init_mmio(dev, regs, &quad8_regmap_config);
1299*98ffe025SWilliam Breathitt Gray 	if (IS_ERR(priv->map))
1300*98ffe025SWilliam Breathitt Gray 		return dev_err_probe(dev, PTR_ERR(priv->map),
1301*98ffe025SWilliam Breathitt Gray 				     "Unable to initialize register map\n");
1302*98ffe025SWilliam Breathitt Gray 
1303f1d8a071SWilliam Breathitt Gray 	/* Initialize Counter device and driver data */
13049e884bb1SUwe Kleine-König 	counter->name = dev_name(dev);
13059e884bb1SUwe Kleine-König 	counter->parent = dev;
13069e884bb1SUwe Kleine-König 	counter->ops = &quad8_ops;
13079e884bb1SUwe Kleine-König 	counter->counts = quad8_counts;
13089e884bb1SUwe Kleine-König 	counter->num_counts = ARRAY_SIZE(quad8_counts);
13099e884bb1SUwe Kleine-König 	counter->signals = quad8_signals;
13109e884bb1SUwe Kleine-König 	counter->num_signals = ARRAY_SIZE(quad8_signals);
1311f1d8a071SWilliam Breathitt Gray 
131209db4678SWilliam Breathitt Gray 	spin_lock_init(&priv->lock);
1313fc069262SSyed Nayyar Waris 
13147aa2ba0dSWilliam Breathitt Gray 	/* Reset Index/Interrupt Register */
1315*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, 0x00);
1316*98ffe025SWilliam Breathitt Gray 	if (ret)
1317*98ffe025SWilliam Breathitt Gray 		return ret;
1318f1d8a071SWilliam Breathitt Gray 	/* Reset all counters and disable interrupt function */
1319*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
1320*98ffe025SWilliam Breathitt Gray 			   RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION);
1321*98ffe025SWilliam Breathitt Gray 	if (ret)
1322*98ffe025SWilliam Breathitt Gray 		return ret;
1323f1d8a071SWilliam Breathitt Gray 	/* Set initial configuration for all counters */
1324*98ffe025SWilliam Breathitt Gray 	for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
1325*98ffe025SWilliam Breathitt Gray 		ret = quad8_init_counter(priv, i);
1326*98ffe025SWilliam Breathitt Gray 		if (ret)
1327*98ffe025SWilliam Breathitt Gray 			return ret;
1328*98ffe025SWilliam Breathitt Gray 	}
1329954ab5ccSWilliam Breathitt Gray 	/* Disable Differential Encoder Cable Status for all channels */
1330*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, GENMASK(7, 0));
1331*98ffe025SWilliam Breathitt Gray 	if (ret)
1332*98ffe025SWilliam Breathitt Gray 		return ret;
13337aa2ba0dSWilliam Breathitt Gray 	/* Enable all counters and enable interrupt function */
1334*98ffe025SWilliam Breathitt Gray 	ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
1335*98ffe025SWilliam Breathitt Gray 			   ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION);
1336*98ffe025SWilliam Breathitt Gray 	if (ret)
1337*98ffe025SWilliam Breathitt Gray 		return ret;
13387aa2ba0dSWilliam Breathitt Gray 
1339*98ffe025SWilliam Breathitt Gray 	ret = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
1340663d8fb0SWilliam Breathitt Gray 			       IRQF_SHARED, counter->name, counter);
1341*98ffe025SWilliam Breathitt Gray 	if (ret)
1342*98ffe025SWilliam Breathitt Gray 		return ret;
1343f1d8a071SWilliam Breathitt Gray 
1344*98ffe025SWilliam Breathitt Gray 	ret = devm_counter_add(dev, counter);
1345*98ffe025SWilliam Breathitt Gray 	if (ret < 0)
1346*98ffe025SWilliam Breathitt Gray 		return dev_err_probe(dev, ret, "Failed to add counter\n");
13479e884bb1SUwe Kleine-König 
13489e884bb1SUwe Kleine-König 	return 0;
1349f1d8a071SWilliam Breathitt Gray }
1350f1d8a071SWilliam Breathitt Gray 
1351f1d8a071SWilliam Breathitt Gray static struct isa_driver quad8_driver = {
1352f1d8a071SWilliam Breathitt Gray 	.probe = quad8_probe,
1353f1d8a071SWilliam Breathitt Gray 	.driver = {
1354f1d8a071SWilliam Breathitt Gray 		.name = "104-quad-8"
1355f1d8a071SWilliam Breathitt Gray 	}
1356f1d8a071SWilliam Breathitt Gray };
1357f1d8a071SWilliam Breathitt Gray 
13580c83a280SWilliam Breathitt Gray module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq);
1359f1d8a071SWilliam Breathitt Gray 
1360f1d8a071SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1361e357e81fSWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
1362f1d8a071SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
13633216e551SWilliam Breathitt Gray MODULE_IMPORT_NS(COUNTER);
1364