linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Refactor 104-quad-8 to match device operations
@ 2023-03-18 14:59 William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 1/4] counter: 104-quad-8: Utilize bitfield access macros William Breathitt Gray
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-18 14:59 UTC (permalink / raw)
  To: linux-iio
  Cc: Johannes Berg, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel, William Breathitt Gray

The 104-quad-8 driver was initially introduced to the IIO subsystem
where it didn't quite fit with the existing paradigm [0]; these
differences eventually led to the creation of the Counter subsystem[1].
As a result of its awkward beginnings, the design of the 104-quad-8
driver was structured around maintaining abstract state buffers that
would eventually be converted to match the actual device registers
states on-the-fly as needed.

The original design approach for the 104-quad-8 driver was neither
efficient nor easy to troubleshoot, but it did allow us to focus on
implementing and supporting necessary APIs for the nascent Counter
subsystem. Now that development for the 104-quad-8 driver has shifted
to maintenance, it is a good time to refactor and clean up the code to
match closer to what is actually happening on the device. This patchset
is an attempt to rectify the situation as such.

The primary change is a transition from maintaining individual
configuration states independently, to storing buffers of the device
register configurations. To that end, the bitfield API is leveraged to
access and retrieve field states. Modifying bitfields is a common code
pattern so a FIELD_MODIFY macro is introduced to facililate such.
Finally some helper functions are introduced to abstract the handling of
the PR, FLAG, and PSC registers.

Modifying a buffer state in-place is a common pattern, so should we also
consider adding a field_replace() function similar to bitmap_replace()?

[0] https://lore.kernel.org/r/b43e2942b763b87afc85bfa9fe36e5695cba4c44.1475079578.git.vilhelm.gray@gmail.com/
[1] https://lore.kernel.org/r/cover.1554184734.git.vilhelm.gray@gmail.com/

William Breathitt Gray (4):
  counter: 104-quad-8: Utilize bitfield access macros
  bitfield: Introduce the FIELD_MODIFY() macro
  counter: 104-quad-8: Refactor to buffer states for CMR, IOR, and IDR
  counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and
    PSC

 drivers/counter/104-quad-8.c | 526 ++++++++++++++++++-----------------
 include/linux/bitfield.h     |  18 +-
 2 files changed, 283 insertions(+), 261 deletions(-)


base-commit: 00f4bc5184c19cb33f468f1ea409d70d19f8f502
-- 
2.39.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/4] counter: 104-quad-8: Utilize bitfield access macros
  2023-03-18 14:59 [PATCH 0/4] Refactor 104-quad-8 to match device operations William Breathitt Gray
@ 2023-03-18 14:59 ` William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro William Breathitt Gray
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-18 14:59 UTC (permalink / raw)
  To: linux-iio
  Cc: Johannes Berg, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel, William Breathitt Gray

The 104-QUAD-8 features several registers with various bitfields.
Utilize bitfield access macros such as FIELD_PREP to make the code
easier to read and the intent clearer.

Suggested-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/counter/104-quad-8.c | 267 +++++++++++++++++++++++------------
 1 file changed, 176 insertions(+), 91 deletions(-)

diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index d9cb937665cf..be7b04b52d85 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -5,7 +5,8 @@
  *
  * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
  */
-#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
 #include <linux/counter.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -98,36 +99,110 @@ struct quad8 {
 };
 
 /* Error flag */
-#define QUAD8_FLAG_E BIT(4)
+#define FLAG_E BIT(4)
 /* Up/Down flag */
-#define QUAD8_FLAG_UD BIT(5)
+#define FLAG_UD BIT(5)
+
+#define REGISTER_SELECTION GENMASK(6, 5)
+
 /* Reset and Load Signal Decoders */
-#define QUAD8_CTR_RLD 0x00
+#define SELECT_RLD FIELD_PREP(REGISTER_SELECTION, 0x0)
 /* Counter Mode Register */
-#define QUAD8_CTR_CMR 0x20
+#define SELECT_CMR FIELD_PREP(REGISTER_SELECTION, 0x1)
 /* Input / Output Control Register */
-#define QUAD8_CTR_IOR 0x40
+#define SELECT_IOR FIELD_PREP(REGISTER_SELECTION, 0x2)
 /* Index Control Register */
-#define QUAD8_CTR_IDR 0x60
+#define SELECT_IDR FIELD_PREP(REGISTER_SELECTION, 0x3)
+
+/*
+ * Reset and Load Signal Decoders
+ */
+#define RESETS GENMASK(2, 1)
+#define LOADS GENMASK(4, 3)
 /* Reset Byte Pointer (three byte data pointer) */
-#define QUAD8_RLD_RESET_BP 0x01
-/* Reset Counter */
-#define QUAD8_RLD_RESET_CNTR 0x02
-/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
-#define QUAD8_RLD_RESET_FLAGS 0x04
+#define RESET_BP BIT(0)
+/* Reset Borrow Toggle, Carry toggle, Compare toggle, Sign, and Index flags */
+#define RESET_BT_CT_CPT_S_IDX FIELD_PREP(RESETS, 0x2)
 /* Reset Error flag */
-#define QUAD8_RLD_RESET_E 0x06
+#define RESET_E FIELD_PREP(RESETS, 0x3)
 /* Preset Register to Counter */
-#define QUAD8_RLD_PRESET_CNTR 0x08
+#define TRANSFER_PR_TO_CNTR FIELD_PREP(LOADS, 0x1)
 /* Transfer Counter to Output Latch */
-#define QUAD8_RLD_CNTR_OUT 0x10
+#define TRANSFER_CNTR_TO_OL FIELD_PREP(LOADS, 0x2)
 /* Transfer Preset Register LSB to FCK Prescaler */
-#define QUAD8_RLD_PRESET_PSC 0x18
-#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
-#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
-#define QUAD8_CMR_QUADRATURE_X1 0x08
-#define QUAD8_CMR_QUADRATURE_X2 0x10
-#define QUAD8_CMR_QUADRATURE_X4 0x18
+#define TRANSFER_PR0_TO_PSC FIELD_PREP(LOADS, 0x3)
+
+/*
+ * Counter Mode Registers
+ */
+#define COUNT_ENCODING BIT(0)
+#define COUNT_MODE GENMASK(2, 1)
+#define QUADRATURE_MODE GENMASK(4, 3)
+/* Binary count */
+#define BINARY FIELD_PREP(COUNT_ENCODING, 0x0)
+/* Normal count */
+#define NORMAL_COUNT 0x0
+#define CMR_NORMAL_COUNT FIELD_PREP(COUNT_MODE, NORMAL_COUNT)
+/* Range Limit */
+#define RANGE_LIMIT 0x1
+/* Non-recycle count */
+#define NON_RECYCLE_COUNT 0x2
+/* Modulo-N */
+#define MODULO_N 0x3
+/* Non-quadrature */
+#define NON_QUADRATURE FIELD_PREP(QUADRATURE_MODE, 0x0)
+/* Quadrature X1 */
+#define QUADRATURE_X1 FIELD_PREP(QUADRATURE_MODE, 0x1)
+/* Quadrature X2 */
+#define QUADRATURE_X2 FIELD_PREP(QUADRATURE_MODE, 0x2)
+/* Quadrature X4 */
+#define QUADRATURE_X4 FIELD_PREP(QUADRATURE_MODE, 0x3)
+
+/*
+ * Input/Output Control Register
+ */
+#define AB_GATE BIT(0)
+#define LOAD_PIN BIT(1)
+#define FLG_PINS GENMASK(4, 3)
+/* Disable inputs A and B */
+#define DISABLE_AB FIELD_PREP(AB_GATE, 0x0)
+/* Load Counter input */
+#define LOAD_CNTR FIELD_PREP(LOAD_PIN, 0x0)
+/* FLG1 = CARRY(active low); FLG2 = BORROW(active low) */
+#define FLG1_CARRY_FLG2_BORROW 0x0
+#define IOR_FLG1_CARRY_FLG2_BORROW FIELD_PREP(FLG_PINS, FLG1_CARRY_FLG2_BORROW)
+/* FLG1 = COMPARE(active low); FLG2 = BORROW(active low) */
+#define FLG1_COMPARE_FLG2_BORROW 0x1
+/* FLG1 = Carry(active low)/Borrow(active low); FLG2 = U/D(active low) flag */
+#define FLG1_CARRYBORROW_FLG2_UD 0x2
+/* FLG1 = INDX (low pulse at INDEX pin active level); FLG2 = E flag */
+#define FLG1_INDX_FLG2_E 0x3
+
+/*
+ * INDEX CONTROL REGISTERS
+ */
+#define INDEX_MODE BIT(0)
+#define INDEX_POLARITY BIT(1)
+/* Disable Index mode */
+#define DISABLE_INDEX_MODE FIELD_PREP(INDEX_MODE, 0x0)
+/* Negative Index Polarity */
+#define NEGATIVE_INDEX_POLARITY FIELD_PREP(INDEX_POLARITY, 0x0)
+
+/*
+ * Channel Operation Register
+ */
+#define COUNTERS_OPERATION BIT(0)
+#define INTERRUPT_FUNCTION BIT(2)
+/* Enable all Counters */
+#define ENABLE_COUNTERS FIELD_PREP(COUNTERS_OPERATION, 0x0)
+/* Reset all Counters */
+#define RESET_COUNTERS FIELD_PREP(COUNTERS_OPERATION, 0x1)
+/* Disable the interrupt function */
+#define DISABLE_INTERRUPT_FUNCTION FIELD_PREP(INTERRUPT_FUNCTION, 0x0)
+/* Enable the interrupt function */
+#define ENABLE_INTERRUPT_FUNCTION FIELD_PREP(INTERRUPT_FUNCTION, 0x1)
+/* Any write to the Channel Operation register clears any pending interrupts */
+#define CLEAR_PENDING_INTERRUPTS (ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION)
 
 /* Each Counter is 24 bits wide */
 #define LS7267_CNTR_MAX GENMASK(23, 0)
@@ -163,8 +238,7 @@ static int quad8_count_read(struct counter_device *counter,
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	/* Reset Byte Pointer; transfer Counter to Output Latch */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
-		 &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP | TRANSFER_CNTR_TO_OL, &chan->control);
 
 	for (i = 0; i < 3; i++)
 		*val |= (unsigned long)ioread8(&chan->data) << (8 * i);
@@ -188,17 +262,17 @@ static int quad8_count_write(struct counter_device *counter,
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 
 	/* Counter can only be set via Preset Register */
 	for (i = 0; i < 3; i++)
 		iowrite8(val >> (8 * i), &chan->data);
 
 	/* Transfer Preset Register to Counter */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control);
+	iowrite8(SELECT_RLD | TRANSFER_PR_TO_CNTR, &chan->control);
 
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 
 	/* Set Preset Register back to original value */
 	val = priv->preset[count->id];
@@ -206,9 +280,9 @@ static int quad8_count_write(struct counter_device *counter,
 		iowrite8(val >> (8 * i), &chan->data);
 
 	/* Reset Borrow, Carry, Compare, and Sign flags */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
 	/* Reset Error flag */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
+	iowrite8(SELECT_RLD | RESET_E, &chan->control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -279,8 +353,8 @@ static int quad8_function_write(struct counter_device *counter,
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	mode_cfg = priv->count_mode[id] << 1;
-	idr_cfg = priv->index_polarity[id] << 1;
+	mode_cfg = FIELD_PREP(COUNT_MODE, priv->count_mode[id]);
+	idr_cfg = FIELD_PREP(INDEX_POLARITY, priv->index_polarity[id]);
 
 	if (function == COUNTER_FUNCTION_PULSE_DIRECTION) {
 		*quadrature_mode = 0;
@@ -288,11 +362,14 @@ static int quad8_function_write(struct counter_device *counter,
 		/* Quadrature scaling only available in quadrature mode */
 		*scale = 0;
 
+		mode_cfg |= NON_QUADRATURE;
+
 		/* Synchronous function not supported in non-quadrature mode */
 		if (*synchronous_mode) {
-			*synchronous_mode = 0;
 			/* Disable synchronous function mode */
-			iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+			*synchronous_mode = 0;
+			idr_cfg |= FIELD_PREP(INDEX_MODE, *synchronous_mode);
+			iowrite8(SELECT_IDR | idr_cfg, control);
 		}
 	} else {
 		*quadrature_mode = 1;
@@ -300,15 +377,15 @@ static int quad8_function_write(struct counter_device *counter,
 		switch (function) {
 		case COUNTER_FUNCTION_QUADRATURE_X1_A:
 			*scale = 0;
-			mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
+			mode_cfg |= QUADRATURE_X1;
 			break;
 		case COUNTER_FUNCTION_QUADRATURE_X2_A:
 			*scale = 1;
-			mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
+			mode_cfg |= QUADRATURE_X2;
 			break;
 		case COUNTER_FUNCTION_QUADRATURE_X4:
 			*scale = 2;
-			mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
+			mode_cfg |= QUADRATURE_X4;
 			break;
 		default:
 			/* should never reach this path */
@@ -318,7 +395,7 @@ static int quad8_function_write(struct counter_device *counter,
 	}
 
 	/* Load mode configuration to Counter Mode Register */
-	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+	iowrite8(SELECT_CMR | mode_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -332,9 +409,11 @@ static int quad8_direction_read(struct counter_device *counter,
 	const struct quad8 *const priv = counter_priv(counter);
 	unsigned int ud_flag;
 	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
+	unsigned long flag;
 
+	flag = ioread8(flag_addr);
 	/* U/D flag: nonzero = up, zero = down */
-	ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD;
+	ud_flag = FIELD_GET(FLAG_UD, flag);
 
 	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
 		COUNTER_COUNT_DIRECTION_BACKWARD;
@@ -423,10 +502,10 @@ static int quad8_action_read(struct counter_device *counter,
 }
 
 enum {
-	QUAD8_EVENT_CARRY = 0,
-	QUAD8_EVENT_COMPARE = 1,
-	QUAD8_EVENT_CARRY_BORROW = 2,
-	QUAD8_EVENT_INDEX = 3,
+	QUAD8_EVENT_CARRY = FLG1_CARRY_FLG2_BORROW,
+	QUAD8_EVENT_COMPARE = FLG1_COMPARE_FLG2_BORROW,
+	QUAD8_EVENT_CARRY_BORROW = FLG1_CARRYBORROW_FLG2_UD,
+	QUAD8_EVENT_INDEX = FLG1_INDX_FLG2_E,
 };
 
 static int quad8_events_configure(struct counter_device *counter)
@@ -471,10 +550,13 @@ static int quad8_events_configure(struct counter_device *counter)
 		priv->irq_trigger[event_node->channel] = next_irq_trigger;
 
 		/* Load configuration to I/O Control Register */
-		ior_cfg = priv->ab_enable[event_node->channel] |
-			  priv->preset_enable[event_node->channel] << 1 |
-			  priv->irq_trigger[event_node->channel] << 3;
-		iowrite8(QUAD8_CTR_IOR | ior_cfg,
+		ior_cfg = FIELD_PREP(AB_GATE,
+				     priv->ab_enable[event_node->channel]) |
+			  FIELD_PREP(LOAD_PIN,
+				     priv->preset_enable[event_node->channel]) |
+			  FIELD_PREP(FLG_PINS,
+				     priv->irq_trigger[event_node->channel]);
+		iowrite8(SELECT_IOR | ior_cfg,
 			 &priv->reg->channel[event_node->channel].control);
 	}
 
@@ -544,16 +626,16 @@ static int quad8_index_polarity_set(struct counter_device *counter,
 	const size_t channel_id = signal->id - 16;
 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
 	unsigned long irqflags;
-	unsigned int idr_cfg = index_polarity << 1;
+	unsigned int idr_cfg = FIELD_PREP(INDEX_POLARITY, index_polarity);
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	idr_cfg |= priv->synchronous_mode[channel_id];
+	idr_cfg |= FIELD_PREP(INDEX_MODE, priv->synchronous_mode[channel_id]);
 
 	priv->index_polarity[channel_id] = index_polarity;
 
 	/* Load Index Control configuration to Index Control Register */
-	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+	iowrite8(SELECT_IDR | idr_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -611,11 +693,11 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
 	const size_t channel_id = signal->id - 16;
 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
 	unsigned long irqflags;
-	unsigned int idr_cfg = synchronous_mode;
+	unsigned int idr_cfg = FIELD_PREP(INDEX_MODE, synchronous_mode);
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	idr_cfg |= priv->index_polarity[channel_id] << 1;
+	idr_cfg |= FIELD_PREP(INDEX_POLARITY, priv->index_polarity[channel_id]);
 
 	/* Index function must be non-synchronous in non-quadrature mode */
 	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
@@ -626,7 +708,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
 	priv->synchronous_mode[channel_id] = synchronous_mode;
 
 	/* Load Index Control configuration to Index Control Register */
-	iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+	iowrite8(SELECT_IDR | idr_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -648,18 +730,17 @@ static int quad8_count_mode_read(struct counter_device *counter,
 {
 	const struct quad8 *const priv = counter_priv(counter);
 
-	/* Map 104-QUAD-8 count mode to Generic Counter count mode */
 	switch (priv->count_mode[count->id]) {
-	case 0:
+	case NORMAL_COUNT:
 		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
 		break;
-	case 1:
+	case RANGE_LIMIT:
 		*cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
 		break;
-	case 2:
+	case NON_RECYCLE_COUNT:
 		*cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
 		break;
-	case 3:
+	case MODULO_N:
 		*cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
 		break;
 	}
@@ -677,19 +758,18 @@ static int quad8_count_mode_write(struct counter_device *counter,
 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
 	unsigned long irqflags;
 
-	/* Map Generic Counter count mode to 104-QUAD-8 count mode */
 	switch (cnt_mode) {
 	case COUNTER_COUNT_MODE_NORMAL:
-		count_mode = 0;
+		count_mode = NORMAL_COUNT;
 		break;
 	case COUNTER_COUNT_MODE_RANGE_LIMIT:
-		count_mode = 1;
+		count_mode = RANGE_LIMIT;
 		break;
 	case COUNTER_COUNT_MODE_NON_RECYCLE:
-		count_mode = 2;
+		count_mode = NON_RECYCLE_COUNT;
 		break;
 	case COUNTER_COUNT_MODE_MODULO_N:
-		count_mode = 3;
+		count_mode = MODULO_N;
 		break;
 	default:
 		/* should never reach this path */
@@ -701,14 +781,17 @@ static int quad8_count_mode_write(struct counter_device *counter,
 	priv->count_mode[count->id] = count_mode;
 
 	/* Set count mode configuration value */
-	mode_cfg = count_mode << 1;
+	mode_cfg = FIELD_PREP(COUNT_MODE, count_mode);
 
 	/* Add quadrature mode configuration */
 	if (priv->quadrature_mode[count->id])
-		mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
+		mode_cfg |= FIELD_PREP(QUADRATURE_MODE,
+				       priv->quadrature_scale[count->id] + 1);
+	else
+		mode_cfg |= NON_QUADRATURE;
 
 	/* Load mode configuration to Counter Mode Register */
-	iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+	iowrite8(SELECT_CMR | mode_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -737,11 +820,12 @@ static int quad8_count_enable_write(struct counter_device *counter,
 
 	priv->ab_enable[count->id] = enable;
 
-	ior_cfg = enable | priv->preset_enable[count->id] << 1 |
-		  priv->irq_trigger[count->id] << 3;
+	ior_cfg = FIELD_PREP(AB_GATE, enable) |
+		  FIELD_PREP(LOAD_PIN, priv->preset_enable[count->id]) |
+		  FIELD_PREP(FLG_PINS, priv->irq_trigger[count->id]);
 
 	/* Load I/O control configuration */
-	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+	iowrite8(SELECT_IOR | ior_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -758,8 +842,10 @@ static int quad8_error_noise_get(struct counter_device *counter,
 {
 	const struct quad8 *const priv = counter_priv(counter);
 	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
+	unsigned long flag;
 
-	*noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E);
+	flag = ioread8(flag_addr);
+	*noise_error = FIELD_GET(FLAG_E, flag);
 
 	return 0;
 }
@@ -783,7 +869,7 @@ static void quad8_preset_register_set(struct quad8 *const priv, const int id,
 	priv->preset[id] = preset;
 
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 
 	/* Set Preset Register */
 	for (i = 0; i < 3; i++)
@@ -818,8 +904,8 @@ static int quad8_count_ceiling_read(struct counter_device *counter,
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 	switch (priv->count_mode[count->id]) {
-	case 1:
-	case 3:
+	case RANGE_LIMIT:
+	case MODULO_N:
 		*ceiling = priv->preset[count->id];
 		break;
 	default:
@@ -845,8 +931,8 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 	switch (priv->count_mode[count->id]) {
-	case 1:
-	case 3:
+	case RANGE_LIMIT:
+	case MODULO_N:
 		quad8_preset_register_set(priv, count->id, ceiling);
 		spin_unlock_irqrestore(&priv->lock, irqflags);
 		return 0;
@@ -884,11 +970,12 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
 
 	priv->preset_enable[count->id] = preset_enable;
 
-	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
-		  priv->irq_trigger[count->id] << 3;
+	ior_cfg = FIELD_PREP(AB_GATE, priv->ab_enable[count->id]) |
+		  FIELD_PREP(LOAD_PIN, preset_enable) |
+		  FIELD_PREP(FLG_PINS, priv->irq_trigger[count->id]);
 
 	/* Load I/O control configuration to Input / Output Control Register */
-	iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+	iowrite8(SELECT_IOR | ior_cfg, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -988,12 +1075,11 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
 	priv->fck_prescaler[channel_id] = prescaler;
 
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 
 	/* Set filter clock factor */
 	iowrite8(prescaler, &chan->data);
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
-		 &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP | TRANSFER_PR0_TO_PSC, &chan->control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -1183,7 +1269,7 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 	}
 
 	/* Clear pending interrupts on device */
-	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+	iowrite8(CLEAR_PENDING_INTERRUPTS, &priv->reg->channel_oper);
 
 	return IRQ_HANDLED;
 }
@@ -1193,26 +1279,25 @@ static void quad8_init_counter(struct channel_reg __iomem *const chan)
 	unsigned long i;
 
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 	/* Reset filter clock factor */
 	iowrite8(0, &chan->data);
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
-		 &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP | TRANSFER_PR0_TO_PSC, &chan->control);
 	/* Reset Byte Pointer */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
 	/* Reset Preset Register */
 	for (i = 0; i < 3; i++)
 		iowrite8(0x00, &chan->data);
 	/* Reset Borrow, Carry, Compare, and Sign flags */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
+	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
 	/* Reset Error flag */
-	iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
+	iowrite8(SELECT_RLD | RESET_E, &chan->control);
 	/* Binary encoding; Normal count; non-quadrature mode */
-	iowrite8(QUAD8_CTR_CMR, &chan->control);
+	iowrite8(SELECT_CMR | BINARY | CMR_NORMAL_COUNT | NON_QUADRATURE, &chan->control);
 	/* Disable A and B inputs; preset on index; FLG1 as Carry */
-	iowrite8(QUAD8_CTR_IOR, &chan->control);
+	iowrite8(SELECT_IOR | DISABLE_AB | LOAD_CNTR | IOR_FLG1_CARRY_FLG2_BORROW, &chan->control);
 	/* Disable index function; negative index polarity */
-	iowrite8(QUAD8_CTR_IDR, &chan->control);
+	iowrite8(SELECT_IDR | DISABLE_INDEX_MODE | NEGATIVE_INDEX_POLARITY, &chan->control);
 }
 
 static int quad8_probe(struct device *dev, unsigned int id)
@@ -1251,14 +1336,14 @@ static int quad8_probe(struct device *dev, unsigned int id)
 	/* Reset Index/Interrupt Register */
 	iowrite8(0x00, &priv->reg->index_interrupt);
 	/* Reset all counters and disable interrupt function */
-	iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper);
+	iowrite8(RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION, &priv->reg->channel_oper);
 	/* Set initial configuration for all counters */
 	for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
 		quad8_init_counter(priv->reg->channel + i);
 	/* Disable Differential Encoder Cable Status for all channels */
 	iowrite8(0xFF, &priv->reg->cable_status);
 	/* Enable all counters and enable interrupt function */
-	iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+	iowrite8(ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION, &priv->reg->channel_oper);
 
 	err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
 			       IRQF_SHARED, counter->name, counter);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro
  2023-03-18 14:59 [PATCH 0/4] Refactor 104-quad-8 to match device operations William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 1/4] counter: 104-quad-8: Utilize bitfield access macros William Breathitt Gray
@ 2023-03-18 14:59 ` William Breathitt Gray
  2023-03-20  8:50   ` Johannes Berg
  2023-03-18 14:59 ` [PATCH 3/4] counter: 104-quad-8: Refactor to buffer states for CMR, IOR, and IDR William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC William Breathitt Gray
  3 siblings, 1 reply; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-18 14:59 UTC (permalink / raw)
  To: linux-iio
  Cc: Johannes Berg, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel, William Breathitt Gray

It is a common code pattern to modify a bitfield by masking the field
and performing a bitwise OR with the respective FIELD_PREP. Wrap such a
task into a macro by introducing FIELD_MODIFY() which modifies the field
specified by a mask from a bitfield by putting a val in the field.

Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 include/linux/bitfield.h | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index ebfa12f69501..b06a98f0a87f 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -38,8 +38,7 @@
  *	  FIELD_PREP(REG_FIELD_D, 0x40);
  *
  * Modify:
- *  reg &= ~REG_FIELD_C;
- *  reg |= FIELD_PREP(REG_FIELD_C, c);
+ *  reg = FIELD_MODIFY(REG_FIELD_C, reg, c);
  */
 
 #define __bf_shf(x) (__builtin_ffsll(x) - 1)
@@ -155,6 +154,21 @@
 		(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask));	\
 	})
 
+/**
+ * FIELD_MODIFY() - modify a bitfield element
+ * @_mask: shifted mask defining the field's length and position
+ * @_reg:  value of entire bitfield
+ * @_val:  value to put in the field
+ *
+ * FIELD_MODIFY() modifies the field specified by @_mask from the
+ * bitfield passed in as @_reg by putting @val in the field.
+ */
+#define FIELD_MODIFY(_mask, _reg, _val)						\
+	({									\
+		__BF_FIELD_CHECK(_mask, _reg, _val, "FIELD_MODIFY: ");		\
+		(typeof(_mask))(((_reg) & ~(_mask)) | FIELD_PREP(_mask, _val));	\
+	})
+
 extern void __compiletime_error("value doesn't fit into mask")
 __field_overflow(void);
 extern void __compiletime_error("bad bitfield mask")
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/4] counter: 104-quad-8: Refactor to buffer states for CMR, IOR, and IDR
  2023-03-18 14:59 [PATCH 0/4] Refactor 104-quad-8 to match device operations William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 1/4] counter: 104-quad-8: Utilize bitfield access macros William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro William Breathitt Gray
@ 2023-03-18 14:59 ` William Breathitt Gray
  2023-03-18 14:59 ` [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC William Breathitt Gray
  3 siblings, 0 replies; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-18 14:59 UTC (permalink / raw)
  To: linux-iio
  Cc: Johannes Berg, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel, William Breathitt Gray

The 104-quad-8 driver buffers the device configuration states
separately, however each device has only three control registers: CMR,
IOR, and IDR. Refactoring to buffer the states of these control
registers rather than each configuration separately results in more
succinct code that more closely matches what is happening on the device.

Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/counter/104-quad-8.c | 290 ++++++++++++++---------------------
 1 file changed, 113 insertions(+), 177 deletions(-)

diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index be7b04b52d85..796f02fc53b8 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -68,32 +68,21 @@ struct quad8_reg {
 /**
  * struct quad8 - device private data structure
  * @lock:		lock to prevent clobbering device states during R/W ops
- * @counter:		instance of the counter_device
+ * @cmr:		array of Counter Mode Register states
+ * @ior:		array of Input / Output Control Register states
+ * @idr:		array of Index Control Register states
  * @fck_prescaler:	array of filter clock prescaler configurations
  * @preset:		array of preset values
- * @count_mode:		array of count mode configurations
- * @quadrature_mode:	array of quadrature mode configurations
- * @quadrature_scale:	array of quadrature mode scale configurations
- * @ab_enable:		array of A and B inputs enable configurations
- * @preset_enable:	array of set_to_preset_on_index attribute configurations
- * @irq_trigger:	array of current IRQ trigger function configurations
- * @synchronous_mode:	array of index function synchronous mode configurations
- * @index_polarity:	array of index function polarity configurations
  * @cable_fault_enable:	differential encoder cable status enable configurations
  * @reg:		I/O address offset for the device registers
  */
 struct quad8 {
 	spinlock_t lock;
+	unsigned long cmr[QUAD8_NUM_COUNTERS];
+	unsigned long ior[QUAD8_NUM_COUNTERS];
+	unsigned long idr[QUAD8_NUM_COUNTERS];
 	unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
 	unsigned int preset[QUAD8_NUM_COUNTERS];
-	unsigned int count_mode[QUAD8_NUM_COUNTERS];
-	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
-	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
-	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
-	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
-	unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
-	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
-	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
 	unsigned int cable_fault_enable;
 	struct quad8_reg __iomem *reg;
 };
@@ -102,6 +91,8 @@ struct quad8 {
 #define FLAG_E BIT(4)
 /* Up/Down flag */
 #define FLAG_UD BIT(5)
+/* Counting up */
+#define UP 0x1
 
 #define REGISTER_SELECTION GENMASK(6, 5)
 
@@ -142,7 +133,6 @@ struct quad8 {
 #define BINARY FIELD_PREP(COUNT_ENCODING, 0x0)
 /* Normal count */
 #define NORMAL_COUNT 0x0
-#define CMR_NORMAL_COUNT FIELD_PREP(COUNT_MODE, NORMAL_COUNT)
 /* Range Limit */
 #define RANGE_LIMIT 0x1
 /* Non-recycle count */
@@ -150,13 +140,13 @@ struct quad8 {
 /* Modulo-N */
 #define MODULO_N 0x3
 /* Non-quadrature */
-#define NON_QUADRATURE FIELD_PREP(QUADRATURE_MODE, 0x0)
+#define NON_QUADRATURE 0x0
 /* Quadrature X1 */
-#define QUADRATURE_X1 FIELD_PREP(QUADRATURE_MODE, 0x1)
+#define QUADRATURE_X1 0x1
 /* Quadrature X2 */
-#define QUADRATURE_X2 FIELD_PREP(QUADRATURE_MODE, 0x2)
+#define QUADRATURE_X2 0x2
 /* Quadrature X4 */
-#define QUADRATURE_X4 FIELD_PREP(QUADRATURE_MODE, 0x3)
+#define QUADRATURE_X4 0x3
 
 /*
  * Input/Output Control Register
@@ -167,10 +157,9 @@ struct quad8 {
 /* Disable inputs A and B */
 #define DISABLE_AB FIELD_PREP(AB_GATE, 0x0)
 /* Load Counter input */
-#define LOAD_CNTR FIELD_PREP(LOAD_PIN, 0x0)
+#define LOAD_CNTR 0x0
 /* FLG1 = CARRY(active low); FLG2 = BORROW(active low) */
 #define FLG1_CARRY_FLG2_BORROW 0x0
-#define IOR_FLG1_CARRY_FLG2_BORROW FIELD_PREP(FLG_PINS, FLG1_CARRY_FLG2_BORROW)
 /* FLG1 = COMPARE(active low); FLG2 = BORROW(active low) */
 #define FLG1_COMPARE_FLG2_BORROW 0x1
 /* FLG1 = Carry(active low)/Borrow(active low); FLG2 = U/D(active low) flag */
@@ -184,9 +173,13 @@ struct quad8 {
 #define INDEX_MODE BIT(0)
 #define INDEX_POLARITY BIT(1)
 /* Disable Index mode */
-#define DISABLE_INDEX_MODE FIELD_PREP(INDEX_MODE, 0x0)
+#define DISABLE_INDEX_MODE 0x0
+/* Enable Index mode */
+#define ENABLE_INDEX_MODE 0x1
 /* Negative Index Polarity */
-#define NEGATIVE_INDEX_POLARITY FIELD_PREP(INDEX_POLARITY, 0x0)
+#define NEGATIVE_INDEX_POLARITY 0x0
+/* Positive Index Polarity */
+#define POSITIVE_INDEX_POLARITY 0x1
 
 /*
  * Channel Operation Register
@@ -299,19 +292,17 @@ static const enum counter_function quad8_count_functions_list[] = {
 static int quad8_function_get(const struct quad8 *const priv, const size_t id,
 			      enum counter_function *const function)
 {
-	if (!priv->quadrature_mode[id]) {
+	switch (FIELD_GET(QUADRATURE_MODE, priv->cmr[id])) {
+	case NON_QUADRATURE:
 		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
 		return 0;
-	}
-
-	switch (priv->quadrature_scale[id]) {
-	case 0:
+	case QUADRATURE_X1:
 		*function = COUNTER_FUNCTION_QUADRATURE_X1_A;
 		return 0;
-	case 1:
+	case QUADRATURE_X2:
 		*function = COUNTER_FUNCTION_QUADRATURE_X2_A;
 		return 0;
-	case 2:
+	case QUADRATURE_X4:
 		*function = COUNTER_FUNCTION_QUADRATURE_X4;
 		return 0;
 	default:
@@ -343,59 +334,42 @@ static int quad8_function_write(struct counter_device *counter,
 {
 	struct quad8 *const priv = counter_priv(counter);
 	const int id = count->id;
-	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
-	unsigned int *const scale = priv->quadrature_scale + id;
-	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
 	u8 __iomem *const control = &priv->reg->channel[id].control;
+	unsigned long *const idr = &priv->idr[id];
+	unsigned long *const cmr = &priv->cmr[id];
 	unsigned long irqflags;
 	unsigned int mode_cfg;
-	unsigned int idr_cfg;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	mode_cfg = FIELD_PREP(COUNT_MODE, priv->count_mode[id]);
-	idr_cfg = FIELD_PREP(INDEX_POLARITY, priv->index_polarity[id]);
-
-	if (function == COUNTER_FUNCTION_PULSE_DIRECTION) {
-		*quadrature_mode = 0;
-
-		/* Quadrature scaling only available in quadrature mode */
-		*scale = 0;
-
-		mode_cfg |= NON_QUADRATURE;
+	switch (function) {
+	case COUNTER_FUNCTION_PULSE_DIRECTION:
+		mode_cfg = NON_QUADRATURE;
 
 		/* Synchronous function not supported in non-quadrature mode */
-		if (*synchronous_mode) {
+		if (FIELD_GET(INDEX_MODE, *idr) == ENABLE_INDEX_MODE) {
 			/* Disable synchronous function mode */
-			*synchronous_mode = 0;
-			idr_cfg |= FIELD_PREP(INDEX_MODE, *synchronous_mode);
-			iowrite8(SELECT_IDR | idr_cfg, control);
-		}
-	} else {
-		*quadrature_mode = 1;
-
-		switch (function) {
-		case COUNTER_FUNCTION_QUADRATURE_X1_A:
-			*scale = 0;
-			mode_cfg |= QUADRATURE_X1;
-			break;
-		case COUNTER_FUNCTION_QUADRATURE_X2_A:
-			*scale = 1;
-			mode_cfg |= QUADRATURE_X2;
-			break;
-		case COUNTER_FUNCTION_QUADRATURE_X4:
-			*scale = 2;
-			mode_cfg |= QUADRATURE_X4;
-			break;
-		default:
-			/* should never reach this path */
-			spin_unlock_irqrestore(&priv->lock, irqflags);
-			return -EINVAL;
+			*idr = FIELD_MODIFY(INDEX_MODE, *idr, DISABLE_INDEX_MODE);
+			iowrite8(*idr, control);
 		}
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X1_A:
+		mode_cfg = QUADRATURE_X1;
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X2_A:
+		mode_cfg = QUADRATURE_X2;
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X4:
+		mode_cfg = QUADRATURE_X4;
+		break;
+	default:
+		/* should never reach this path */
+		spin_unlock_irqrestore(&priv->lock, irqflags);
+		return -EINVAL;
 	}
 
-	/* Load mode configuration to Counter Mode Register */
-	iowrite8(SELECT_CMR | mode_cfg, control);
+	*cmr = FIELD_MODIFY(QUADRATURE_MODE, *cmr, mode_cfg);
+	iowrite8(*cmr, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -407,15 +381,11 @@ static int quad8_direction_read(struct counter_device *counter,
 				enum counter_count_direction *direction)
 {
 	const struct quad8 *const priv = counter_priv(counter);
-	unsigned int ud_flag;
 	u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
 	unsigned long flag;
 
 	flag = ioread8(flag_addr);
-	/* U/D flag: nonzero = up, zero = down */
-	ud_flag = FIELD_GET(FLAG_UD, flag);
-
-	*direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
+	*direction = (FIELD_GET(FLAG_UD, flag) == UP) ? COUNTER_COUNT_DIRECTION_FORWARD :
 		COUNTER_COUNT_DIRECTION_BACKWARD;
 
 	return 0;
@@ -447,7 +417,7 @@ static int quad8_action_read(struct counter_device *counter,
 
 	/* Handle Index signals */
 	if (synapse->signal->id >= 16) {
-		if (!priv->preset_enable[count->id])
+		if (FIELD_GET(LOAD_PIN, priv->ior[count->id]) == LOAD_CNTR)
 			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
 		else
 			*action = COUNTER_SYNAPSE_ACTION_NONE;
@@ -501,37 +471,30 @@ static int quad8_action_read(struct counter_device *counter,
 	}
 }
 
-enum {
-	QUAD8_EVENT_CARRY = FLG1_CARRY_FLG2_BORROW,
-	QUAD8_EVENT_COMPARE = FLG1_COMPARE_FLG2_BORROW,
-	QUAD8_EVENT_CARRY_BORROW = FLG1_CARRYBORROW_FLG2_UD,
-	QUAD8_EVENT_INDEX = FLG1_INDX_FLG2_E,
-};
-
 static int quad8_events_configure(struct counter_device *counter)
 {
 	struct quad8 *const priv = counter_priv(counter);
 	unsigned long irq_enabled = 0;
 	unsigned long irqflags;
 	struct counter_event_node *event_node;
-	unsigned int next_irq_trigger;
-	unsigned long ior_cfg;
+	unsigned long flg_pins;
+	unsigned long *ior;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	list_for_each_entry(event_node, &counter->events_list, l) {
 		switch (event_node->event) {
 		case COUNTER_EVENT_OVERFLOW:
-			next_irq_trigger = QUAD8_EVENT_CARRY;
+			flg_pins = FLG1_CARRY_FLG2_BORROW;
 			break;
 		case COUNTER_EVENT_THRESHOLD:
-			next_irq_trigger = QUAD8_EVENT_COMPARE;
+			flg_pins = FLG1_COMPARE_FLG2_BORROW;
 			break;
 		case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
-			next_irq_trigger = QUAD8_EVENT_CARRY_BORROW;
+			flg_pins = FLG1_CARRYBORROW_FLG2_UD;
 			break;
 		case COUNTER_EVENT_INDEX:
-			next_irq_trigger = QUAD8_EVENT_INDEX;
+			flg_pins = FLG1_INDX_FLG2_E;
 			break;
 		default:
 			/* should never reach this path */
@@ -542,22 +505,15 @@ static int quad8_events_configure(struct counter_device *counter)
 		/* Enable IRQ line */
 		irq_enabled |= BIT(event_node->channel);
 
+		ior = &priv->ior[event_node->channel];
+
 		/* Skip configuration if it is the same as previously set */
-		if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
+		if (flg_pins == FIELD_GET(FLG_PINS, *ior))
 			continue;
 
 		/* Save new IRQ function configuration */
-		priv->irq_trigger[event_node->channel] = next_irq_trigger;
-
-		/* Load configuration to I/O Control Register */
-		ior_cfg = FIELD_PREP(AB_GATE,
-				     priv->ab_enable[event_node->channel]) |
-			  FIELD_PREP(LOAD_PIN,
-				     priv->preset_enable[event_node->channel]) |
-			  FIELD_PREP(FLG_PINS,
-				     priv->irq_trigger[event_node->channel]);
-		iowrite8(SELECT_IOR | ior_cfg,
-			 &priv->reg->channel[event_node->channel].control);
+		*ior = FIELD_MODIFY(FLG_PINS, *ior, flg_pins);
+		iowrite8(*ior, &priv->reg->channel[event_node->channel].control);
 	}
 
 	iowrite8(irq_enabled, &priv->reg->index_interrupt);
@@ -613,7 +569,7 @@ static int quad8_index_polarity_get(struct counter_device *counter,
 	const struct quad8 *const priv = counter_priv(counter);
 	const size_t channel_id = signal->id - 16;
 
-	*index_polarity = priv->index_polarity[channel_id];
+	*index_polarity = FIELD_GET(INDEX_POLARITY, priv->idr[channel_id]);
 
 	return 0;
 }
@@ -625,17 +581,13 @@ static int quad8_index_polarity_set(struct counter_device *counter,
 	struct quad8 *const priv = counter_priv(counter);
 	const size_t channel_id = signal->id - 16;
 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
+	unsigned long *const idr = &priv->idr[channel_id];
 	unsigned long irqflags;
-	unsigned int idr_cfg = FIELD_PREP(INDEX_POLARITY, index_polarity);
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	idr_cfg |= FIELD_PREP(INDEX_MODE, priv->synchronous_mode[channel_id]);
-
-	priv->index_polarity[channel_id] = index_polarity;
-
-	/* Load Index Control configuration to Index Control Register */
-	iowrite8(SELECT_IDR | idr_cfg, control);
+	*idr = FIELD_MODIFY(INDEX_POLARITY, *idr, index_polarity);
+	iowrite8(*idr, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -653,8 +605,8 @@ static int quad8_polarity_read(struct counter_device *counter,
 	if (err)
 		return err;
 
-	*polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
-		COUNTER_SIGNAL_POLARITY_NEGATIVE;
+	*polarity = (index_polarity == POSITIVE_INDEX_POLARITY) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
+								  COUNTER_SIGNAL_POLARITY_NEGATIVE;
 
 	return 0;
 }
@@ -663,7 +615,8 @@ static int quad8_polarity_write(struct counter_device *counter,
 				struct counter_signal *signal,
 				enum counter_signal_polarity polarity)
 {
-	const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0;
+	const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ?
+			POSITIVE_INDEX_POLARITY : NEGATIVE_INDEX_POLARITY;
 
 	return quad8_index_polarity_set(counter, signal, pol);
 }
@@ -680,7 +633,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter,
 	const struct quad8 *const priv = counter_priv(counter);
 	const size_t channel_id = signal->id - 16;
 
-	*synchronous_mode = priv->synchronous_mode[channel_id];
+	*synchronous_mode = FIELD_GET(INDEX_MODE, priv->idr[channel_id]);
 
 	return 0;
 }
@@ -692,23 +645,19 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
 	struct quad8 *const priv = counter_priv(counter);
 	const size_t channel_id = signal->id - 16;
 	u8 __iomem *const control = &priv->reg->channel[channel_id].control;
+	unsigned long *const idr = &priv->idr[channel_id];
 	unsigned long irqflags;
-	unsigned int idr_cfg = FIELD_PREP(INDEX_MODE, synchronous_mode);
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	idr_cfg |= FIELD_PREP(INDEX_POLARITY, priv->index_polarity[channel_id]);
-
 	/* Index function must be non-synchronous in non-quadrature mode */
-	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
+	if (synchronous_mode && FIELD_GET(QUADRATURE_MODE, *idr) == NON_QUADRATURE) {
 		spin_unlock_irqrestore(&priv->lock, irqflags);
 		return -EINVAL;
 	}
 
-	priv->synchronous_mode[channel_id] = synchronous_mode;
-
-	/* Load Index Control configuration to Index Control Register */
-	iowrite8(SELECT_IDR | idr_cfg, control);
+	*idr = FIELD_MODIFY(INDEX_MODE, *idr, synchronous_mode);
+	iowrite8(*idr, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -730,7 +679,7 @@ static int quad8_count_mode_read(struct counter_device *counter,
 {
 	const struct quad8 *const priv = counter_priv(counter);
 
-	switch (priv->count_mode[count->id]) {
+	switch (FIELD_GET(COUNT_MODE, priv->cmr[count->id])) {
 	case NORMAL_COUNT:
 		*cnt_mode = COUNTER_COUNT_MODE_NORMAL;
 		break;
@@ -754,8 +703,8 @@ static int quad8_count_mode_write(struct counter_device *counter,
 {
 	struct quad8 *const priv = counter_priv(counter);
 	unsigned int count_mode;
-	unsigned int mode_cfg;
 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
+	unsigned long *const cmr = &priv->cmr[count->id];
 	unsigned long irqflags;
 
 	switch (cnt_mode) {
@@ -778,20 +727,8 @@ static int quad8_count_mode_write(struct counter_device *counter,
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	priv->count_mode[count->id] = count_mode;
-
-	/* Set count mode configuration value */
-	mode_cfg = FIELD_PREP(COUNT_MODE, count_mode);
-
-	/* Add quadrature mode configuration */
-	if (priv->quadrature_mode[count->id])
-		mode_cfg |= FIELD_PREP(QUADRATURE_MODE,
-				       priv->quadrature_scale[count->id] + 1);
-	else
-		mode_cfg |= NON_QUADRATURE;
-
-	/* Load mode configuration to Counter Mode Register */
-	iowrite8(SELECT_CMR | mode_cfg, control);
+	*cmr = FIELD_MODIFY(COUNT_MODE, *cmr, count_mode);
+	iowrite8(*cmr, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -803,7 +740,7 @@ static int quad8_count_enable_read(struct counter_device *counter,
 {
 	const struct quad8 *const priv = counter_priv(counter);
 
-	*enable = priv->ab_enable[count->id];
+	*enable = FIELD_GET(AB_GATE, priv->ior[count->id]);
 
 	return 0;
 }
@@ -813,19 +750,13 @@ static int quad8_count_enable_write(struct counter_device *counter,
 {
 	struct quad8 *const priv = counter_priv(counter);
 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
+	unsigned long *const ior = &priv->ior[count->id];
 	unsigned long irqflags;
-	unsigned int ior_cfg;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	priv->ab_enable[count->id] = enable;
-
-	ior_cfg = FIELD_PREP(AB_GATE, enable) |
-		  FIELD_PREP(LOAD_PIN, priv->preset_enable[count->id]) |
-		  FIELD_PREP(FLG_PINS, priv->irq_trigger[count->id]);
-
-	/* Load I/O control configuration */
-	iowrite8(SELECT_IOR | ior_cfg, control);
+	*ior = FIELD_MODIFY(AB_GATE, *ior, enable);
+	iowrite8(*ior, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -903,7 +834,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
-	switch (priv->count_mode[count->id]) {
+	switch (FIELD_GET(COUNT_MODE, priv->cmr[count->id])) {
 	case RANGE_LIMIT:
 	case MODULO_N:
 		*ceiling = priv->preset[count->id];
@@ -930,7 +861,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
-	switch (priv->count_mode[count->id]) {
+	switch (FIELD_GET(COUNT_MODE, priv->cmr[count->id])) {
 	case RANGE_LIMIT:
 	case MODULO_N:
 		quad8_preset_register_set(priv, count->id, ceiling);
@@ -949,7 +880,8 @@ static int quad8_count_preset_enable_read(struct counter_device *counter,
 {
 	const struct quad8 *const priv = counter_priv(counter);
 
-	*preset_enable = !priv->preset_enable[count->id];
+	/* Preset enable is active low in Input/Output Control register */
+	*preset_enable = !FIELD_GET(LOAD_PIN, priv->ior[count->id]);
 
 	return 0;
 }
@@ -960,22 +892,14 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
 {
 	struct quad8 *const priv = counter_priv(counter);
 	u8 __iomem *const control = &priv->reg->channel[count->id].control;
+	unsigned long *const ior = &priv->ior[count->id];
 	unsigned long irqflags;
-	unsigned int ior_cfg;
-
-	/* Preset enable is active low in Input/Output Control register */
-	preset_enable = !preset_enable;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	priv->preset_enable[count->id] = preset_enable;
-
-	ior_cfg = FIELD_PREP(AB_GATE, priv->ab_enable[count->id]) |
-		  FIELD_PREP(LOAD_PIN, preset_enable) |
-		  FIELD_PREP(FLG_PINS, priv->irq_trigger[count->id]);
-
-	/* Load I/O control configuration to Input / Output Control Register */
-	iowrite8(SELECT_IOR | ior_cfg, control);
+	/* Preset enable is active low in Input/Output Control register */
+	*ior = FIELD_MODIFY(LOAD_PIN, *ior, !preset_enable);
+	iowrite8(*ior, control);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -1238,6 +1162,7 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 	struct quad8 *const priv = counter_priv(counter);
 	unsigned long irq_status;
 	unsigned long channel;
+	unsigned int flg_pins;
 	u8 event;
 
 	irq_status = ioread8(&priv->reg->interrupt_status);
@@ -1245,23 +1170,24 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 		return IRQ_NONE;
 
 	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
-		switch (priv->irq_trigger[channel]) {
-		case QUAD8_EVENT_CARRY:
+		flg_pins = FIELD_GET(FLG_PINS, priv->ior[channel]);
+		switch (flg_pins) {
+		case FLG1_CARRY_FLG2_BORROW:
 			event = COUNTER_EVENT_OVERFLOW;
 				break;
-		case QUAD8_EVENT_COMPARE:
+		case FLG1_COMPARE_FLG2_BORROW:
 			event = COUNTER_EVENT_THRESHOLD;
 				break;
-		case QUAD8_EVENT_CARRY_BORROW:
+		case FLG1_CARRYBORROW_FLG2_UD:
 			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
 				break;
-		case QUAD8_EVENT_INDEX:
+		case FLG1_INDX_FLG2_E:
 			event = COUNTER_EVENT_INDEX;
 				break;
 		default:
 			/* should never reach this path */
 			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
-				  priv->irq_trigger[channel], channel);
+				  flg_pins, channel);
 			continue;
 		}
 
@@ -1274,8 +1200,9 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 	return IRQ_HANDLED;
 }
 
-static void quad8_init_counter(struct channel_reg __iomem *const chan)
+static void quad8_init_counter(struct quad8 *const priv, const size_t channel)
 {
+	struct channel_reg __iomem *const chan = priv->reg->channel + channel;
 	unsigned long i;
 
 	/* Reset Byte Pointer */
@@ -1292,12 +1219,21 @@ static void quad8_init_counter(struct channel_reg __iomem *const chan)
 	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
 	/* Reset Error flag */
 	iowrite8(SELECT_RLD | RESET_E, &chan->control);
+
 	/* Binary encoding; Normal count; non-quadrature mode */
-	iowrite8(SELECT_CMR | BINARY | CMR_NORMAL_COUNT | NON_QUADRATURE, &chan->control);
+	priv->cmr[channel] = SELECT_CMR | BINARY | FIELD_PREP(COUNT_MODE, NORMAL_COUNT) |
+			     FIELD_PREP(QUADRATURE_MODE, NON_QUADRATURE);
+	iowrite8(priv->cmr[channel], &chan->control);
+
 	/* Disable A and B inputs; preset on index; FLG1 as Carry */
-	iowrite8(SELECT_IOR | DISABLE_AB | LOAD_CNTR | IOR_FLG1_CARRY_FLG2_BORROW, &chan->control);
+	priv->ior[channel] = SELECT_IOR | DISABLE_AB | FIELD_PREP(LOAD_PIN, LOAD_CNTR) |
+			     FIELD_PREP(FLG_PINS, FLG1_CARRY_FLG2_BORROW);
+	iowrite8(priv->ior[channel], &chan->control);
+
 	/* Disable index function; negative index polarity */
-	iowrite8(SELECT_IDR | DISABLE_INDEX_MODE | NEGATIVE_INDEX_POLARITY, &chan->control);
+	priv->idr[channel] = SELECT_IDR | FIELD_PREP(INDEX_MODE, DISABLE_INDEX_MODE) |
+			     FIELD_PREP(INDEX_POLARITY, NEGATIVE_INDEX_POLARITY);
+	iowrite8(priv->idr[channel], &chan->control);
 }
 
 static int quad8_probe(struct device *dev, unsigned int id)
@@ -1339,7 +1275,7 @@ static int quad8_probe(struct device *dev, unsigned int id)
 	iowrite8(RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION, &priv->reg->channel_oper);
 	/* Set initial configuration for all counters */
 	for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
-		quad8_init_counter(priv->reg->channel + i);
+		quad8_init_counter(priv, i);
 	/* Disable Differential Encoder Cable Status for all channels */
 	iowrite8(0xFF, &priv->reg->cable_status);
 	/* Enable all counters and enable interrupt function */
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-18 14:59 [PATCH 0/4] Refactor 104-quad-8 to match device operations William Breathitt Gray
                   ` (2 preceding siblings ...)
  2023-03-18 14:59 ` [PATCH 3/4] counter: 104-quad-8: Refactor to buffer states for CMR, IOR, and IDR William Breathitt Gray
@ 2023-03-18 14:59 ` William Breathitt Gray
  2023-03-20 12:28   ` Andy Shevchenko
  3 siblings, 1 reply; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-18 14:59 UTC (permalink / raw)
  To: linux-iio
  Cc: Johannes Berg, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel, William Breathitt Gray

The Preset Register (PR), Flag Register (FLAG), and Filter Clock
Prescaler (PSC) have common usage patterns. Wrap up such usage into
dedicated functions to improve code clarity.

Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/counter/104-quad-8.c | 103 +++++++++++++++--------------------
 1 file changed, 45 insertions(+), 58 deletions(-)

diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 796f02fc53b8..27ec905ebe85 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -241,41 +241,49 @@ static int quad8_count_read(struct counter_device *counter,
 	return 0;
 }
 
+static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
+				      const unsigned long preset)
+{
+	struct channel_reg __iomem *const chan = priv->reg->channel + id;
+	int i;
+
+	/* Reset Byte Pointer */
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
+
+	/* Set Preset Register */
+	for (i = 0; i < 3; i++)
+		iowrite8(preset >> (8 * i), &chan->data);
+}
+
+static void quad8_flag_register_reset(struct quad8 *const priv, const size_t id)
+{
+	struct channel_reg __iomem *const chan = priv->reg->channel + id;
+
+	/* Reset Borrow, Carry, Compare, and Sign flags */
+	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
+	/* Reset Error flag */
+	iowrite8(SELECT_RLD | RESET_E, &chan->control);
+}
+
 static int quad8_count_write(struct counter_device *counter,
 			     struct counter_count *count, u64 val)
 {
 	struct quad8 *const priv = counter_priv(counter);
 	struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
 	unsigned long irqflags;
-	int i;
 
 	if (val > LS7267_CNTR_MAX)
 		return -ERANGE;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-
 	/* Counter can only be set via Preset Register */
-	for (i = 0; i < 3; i++)
-		iowrite8(val >> (8 * i), &chan->data);
-
+	quad8_preset_register_set(priv, count->id, val);
 	/* Transfer Preset Register to Counter */
 	iowrite8(SELECT_RLD | TRANSFER_PR_TO_CNTR, &chan->control);
-
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-
+	quad8_flag_register_reset(priv, count->id);
 	/* Set Preset Register back to original value */
-	val = priv->preset[count->id];
-	for (i = 0; i < 3; i++)
-		iowrite8(val >> (8 * i), &chan->data);
-
-	/* Reset Borrow, Carry, Compare, and Sign flags */
-	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
-	/* Reset Error flag */
-	iowrite8(SELECT_RLD | RESET_E, &chan->control);
+	quad8_preset_register_set(priv, count->id, priv->preset[count->id]);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -791,22 +799,6 @@ static int quad8_count_preset_read(struct counter_device *counter,
 	return 0;
 }
 
-static void quad8_preset_register_set(struct quad8 *const priv, const int id,
-				      const unsigned int preset)
-{
-	struct channel_reg __iomem *const chan = priv->reg->channel + id;
-	int i;
-
-	priv->preset[id] = preset;
-
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-
-	/* Set Preset Register */
-	for (i = 0; i < 3; i++)
-		iowrite8(preset >> (8 * i), &chan->data);
-}
-
 static int quad8_count_preset_write(struct counter_device *counter,
 				    struct counter_count *count, u64 preset)
 {
@@ -818,6 +810,7 @@ static int quad8_count_preset_write(struct counter_device *counter,
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
+	priv->preset[count->id] = preset;
 	quad8_preset_register_set(priv, count->id, preset);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
@@ -864,6 +857,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
 	switch (FIELD_GET(COUNT_MODE, priv->cmr[count->id])) {
 	case RANGE_LIMIT:
 	case MODULO_N:
+		priv->preset[count->id] = ceiling;
 		quad8_preset_register_set(priv, count->id, ceiling);
 		spin_unlock_irqrestore(&priv->lock, irqflags);
 		return 0;
@@ -985,25 +979,30 @@ static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
 	return 0;
 }
 
+static void quad8_filter_clock_prescaler_set(struct quad8 *const priv, const size_t id,
+					     const u8 prescaler)
+{
+	struct channel_reg __iomem *const chan = priv->reg->channel + id;
+
+	/* Reset Byte Pointer */
+	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
+	/* Reset filter clock factor */
+	iowrite8(prescaler, &chan->data);
+	iowrite8(SELECT_RLD | TRANSFER_PR0_TO_PSC, &chan->control);
+}
+
 static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
 					    struct counter_signal *signal,
 					    u8 prescaler)
 {
 	struct quad8 *const priv = counter_priv(counter);
 	const size_t channel_id = signal->id / 2;
-	struct channel_reg __iomem *const chan = priv->reg->channel + channel_id;
 	unsigned long irqflags;
 
 	spin_lock_irqsave(&priv->lock, irqflags);
 
 	priv->fck_prescaler[channel_id] = prescaler;
-
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-
-	/* Set filter clock factor */
-	iowrite8(prescaler, &chan->data);
-	iowrite8(SELECT_RLD | RESET_BP | TRANSFER_PR0_TO_PSC, &chan->control);
+	quad8_filter_clock_prescaler_set(priv, channel_id, prescaler);
 
 	spin_unlock_irqrestore(&priv->lock, irqflags);
 
@@ -1203,22 +1202,10 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 static void quad8_init_counter(struct quad8 *const priv, const size_t channel)
 {
 	struct channel_reg __iomem *const chan = priv->reg->channel + channel;
-	unsigned long i;
 
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-	/* Reset filter clock factor */
-	iowrite8(0, &chan->data);
-	iowrite8(SELECT_RLD | RESET_BP | TRANSFER_PR0_TO_PSC, &chan->control);
-	/* Reset Byte Pointer */
-	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
-	/* Reset Preset Register */
-	for (i = 0; i < 3; i++)
-		iowrite8(0x00, &chan->data);
-	/* Reset Borrow, Carry, Compare, and Sign flags */
-	iowrite8(SELECT_RLD | RESET_BT_CT_CPT_S_IDX, &chan->control);
-	/* Reset Error flag */
-	iowrite8(SELECT_RLD | RESET_E, &chan->control);
+	quad8_filter_clock_prescaler_set(priv, channel, 0);
+	quad8_preset_register_set(priv, channel, 0);
+	quad8_flag_register_reset(priv, channel);
 
 	/* Binary encoding; Normal count; non-quadrature mode */
 	priv->cmr[channel] = SELECT_CMR | BINARY | FIELD_PREP(COUNT_MODE, NORMAL_COUNT) |
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro
  2023-03-18 14:59 ` [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro William Breathitt Gray
@ 2023-03-20  8:50   ` Johannes Berg
  2023-03-20 12:22     ` Andy Shevchenko
  2023-03-20 15:03     ` William Breathitt Gray
  0 siblings, 2 replies; 13+ messages in thread
From: Johannes Berg @ 2023-03-20  8:50 UTC (permalink / raw)
  To: William Breathitt Gray, linux-iio
  Cc: Jonathan Cameron, Andy Shevchenko, Andrew Morton, linux-kernel

On Sat, 2023-03-18 at 14:59 +0000, William Breathitt Gray wrote:
> It is a common code pattern to modify a bitfield by masking the field
> and performing a bitwise OR with the respective FIELD_PREP. Wrap such a
> task into a macro by introducing FIELD_MODIFY() which modifies the field
> specified by a mask from a bitfield by putting a val in the field.

So I have no objection to adding this and you using FIELD_* macros, but
just wanted to say that personally I've come to prefer the typed
versions declared later in the fiel, and there we have
<type>_replace_bits() already.

Hmm. And now that I mentioned that, maybe that means FIELD_REPLACE()
would be nicer as a name?

johannes


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro
  2023-03-20  8:50   ` Johannes Berg
@ 2023-03-20 12:22     ` Andy Shevchenko
  2023-03-20 15:03     ` William Breathitt Gray
  1 sibling, 0 replies; 13+ messages in thread
From: Andy Shevchenko @ 2023-03-20 12:22 UTC (permalink / raw)
  To: Johannes Berg
  Cc: William Breathitt Gray, linux-iio, Jonathan Cameron,
	Andrew Morton, linux-kernel

On Mon, Mar 20, 2023 at 09:50:35AM +0100, Johannes Berg wrote:
> On Sat, 2023-03-18 at 14:59 +0000, William Breathitt Gray wrote:
> > It is a common code pattern to modify a bitfield by masking the field
> > and performing a bitwise OR with the respective FIELD_PREP. Wrap such a
> > task into a macro by introducing FIELD_MODIFY() which modifies the field
> > specified by a mask from a bitfield by putting a val in the field.
> 
> So I have no objection to adding this and you using FIELD_* macros, but
> just wanted to say that personally I've come to prefer the typed
> versions declared later in the fiel, and there we have
> <type>_replace_bits() already.
> 
> Hmm. And now that I mentioned that, maybe that means FIELD_REPLACE()
> would be nicer as a name?

+1 here with the similar thoughts.

One thing I hate about macros like above mentioned is that Elixir or similar
code browsing tools can't find. In net there are specific #if 0 ... #endif
sections for mitigating that.

Shouldn't we add the similar into bitfield.h?

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-18 14:59 ` [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC William Breathitt Gray
@ 2023-03-20 12:28   ` Andy Shevchenko
  2023-03-20 15:31     ` William Breathitt Gray
  0 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2023-03-20 12:28 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: linux-iio, Johannes Berg, Jonathan Cameron, Andrew Morton, linux-kernel

On Sat, Mar 18, 2023 at 10:59:51AM -0400, William Breathitt Gray wrote:
> The Preset Register (PR), Flag Register (FLAG), and Filter Clock
> Prescaler (PSC) have common usage patterns. Wrap up such usage into
> dedicated functions to improve code clarity.

...

> +static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
> +				      const unsigned long preset)
> +{
> +	struct channel_reg __iomem *const chan = priv->reg->channel + id;
> +	int i;
> +
> +	/* Reset Byte Pointer */
> +	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
> +
> +	/* Set Preset Register */
> +	for (i = 0; i < 3; i++)
> +		iowrite8(preset >> (8 * i), &chan->data);
> +}

May we add generic __iowrite8_copy() / __ioread8_copy() instead?

It seems that even current __ioread32_copy() and __iowrite32_copy() has to
be amended to support IO.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro
  2023-03-20  8:50   ` Johannes Berg
  2023-03-20 12:22     ` Andy Shevchenko
@ 2023-03-20 15:03     ` William Breathitt Gray
  1 sibling, 0 replies; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-20 15:03 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-iio, Jonathan Cameron, Andy Shevchenko, Andrew Morton,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1075 bytes --]

On Mon, Mar 20, 2023 at 09:50:35AM +0100, Johannes Berg wrote:
> On Sat, 2023-03-18 at 14:59 +0000, William Breathitt Gray wrote:
> > It is a common code pattern to modify a bitfield by masking the field
> > and performing a bitwise OR with the respective FIELD_PREP. Wrap such a
> > task into a macro by introducing FIELD_MODIFY() which modifies the field
> > specified by a mask from a bitfield by putting a val in the field.
> 
> So I have no objection to adding this and you using FIELD_* macros, but
> just wanted to say that personally I've come to prefer the typed
> versions declared later in the fiel, and there we have
> <type>_replace_bits() already.
> 
> Hmm. And now that I mentioned that, maybe that means FIELD_REPLACE()
> would be nicer as a name?
> 
> johannes

Perhaps I can convert all of these FIELD_GET(), FIELD_MODIFY(), and
FIELD_GET() to the equivalent of u8_get_bits(), u8p_replace_bits(), and
u8_encode_bits(). If that works, then I'll just drop the FIELD_MODIFY()
patch in the v2 patchset submission.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-20 12:28   ` Andy Shevchenko
@ 2023-03-20 15:31     ` William Breathitt Gray
  2023-03-20 15:36       ` Andy Shevchenko
  0 siblings, 1 reply; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-20 15:31 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-iio, Johannes Berg, Jonathan Cameron, Andrew Morton, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1369 bytes --]

On Mon, Mar 20, 2023 at 02:28:31PM +0200, Andy Shevchenko wrote:
> On Sat, Mar 18, 2023 at 10:59:51AM -0400, William Breathitt Gray wrote:
> > The Preset Register (PR), Flag Register (FLAG), and Filter Clock
> > Prescaler (PSC) have common usage patterns. Wrap up such usage into
> > dedicated functions to improve code clarity.
> 
> ...
> 
> > +static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
> > +				      const unsigned long preset)
> > +{
> > +	struct channel_reg __iomem *const chan = priv->reg->channel + id;
> > +	int i;
> > +
> > +	/* Reset Byte Pointer */
> > +	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
> > +
> > +	/* Set Preset Register */
> > +	for (i = 0; i < 3; i++)
> > +		iowrite8(preset >> (8 * i), &chan->data);
> > +}
> 
> May we add generic __iowrite8_copy() / __ioread8_copy() instead?
> 
> It seems that even current __ioread32_copy() and __iowrite32_copy() has to
> be amended to support IO.
> 
> -- 
> With Best Regards,
> Andy Shevchenko

Sure, I would use __iowrite8_copy() / __ioread8_copy() for these
situations if it were available.

Is something equivalent available for the regmap API? I'm planning to
migrate this driver to the regmap API soon after this patch series is
merged, so the *_copy() calls would need to migrated as well.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-20 15:31     ` William Breathitt Gray
@ 2023-03-20 15:36       ` Andy Shevchenko
  2023-03-20 15:53         ` William Breathitt Gray
  0 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2023-03-20 15:36 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: linux-iio, Johannes Berg, Jonathan Cameron, Andrew Morton, linux-kernel

On Mon, Mar 20, 2023 at 11:31:07AM -0400, William Breathitt Gray wrote:
> On Mon, Mar 20, 2023 at 02:28:31PM +0200, Andy Shevchenko wrote:
> > On Sat, Mar 18, 2023 at 10:59:51AM -0400, William Breathitt Gray wrote:
> > > The Preset Register (PR), Flag Register (FLAG), and Filter Clock
> > > Prescaler (PSC) have common usage patterns. Wrap up such usage into
> > > dedicated functions to improve code clarity.

...

> > > +static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
> > > +				      const unsigned long preset)
> > > +{
> > > +	struct channel_reg __iomem *const chan = priv->reg->channel + id;
> > > +	int i;
> > > +
> > > +	/* Reset Byte Pointer */
> > > +	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
> > > +
> > > +	/* Set Preset Register */
> > > +	for (i = 0; i < 3; i++)
> > > +		iowrite8(preset >> (8 * i), &chan->data);
> > > +}
> > 
> > May we add generic __iowrite8_copy() / __ioread8_copy() instead?
> > 
> > It seems that even current __ioread32_copy() and __iowrite32_copy() has to
> > be amended to support IO.

> Sure, I would use __iowrite8_copy() / __ioread8_copy() for these
> situations if it were available.

If needed, you may always introduce ones.

> Is something equivalent available for the regmap API? I'm planning to
> migrate this driver to the regmap API soon after this patch series is
> merged, so the *_copy() calls would need to migrated as well.

Yes. It's regmap bulk operations.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-20 15:36       ` Andy Shevchenko
@ 2023-03-20 15:53         ` William Breathitt Gray
  2023-03-20 16:54           ` Andy Shevchenko
  0 siblings, 1 reply; 13+ messages in thread
From: William Breathitt Gray @ 2023-03-20 15:53 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-iio, Johannes Berg, Jonathan Cameron, Andrew Morton, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2378 bytes --]

On Mon, Mar 20, 2023 at 05:36:17PM +0200, Andy Shevchenko wrote:
> On Mon, Mar 20, 2023 at 11:31:07AM -0400, William Breathitt Gray wrote:
> > On Mon, Mar 20, 2023 at 02:28:31PM +0200, Andy Shevchenko wrote:
> > > On Sat, Mar 18, 2023 at 10:59:51AM -0400, William Breathitt Gray wrote:
> > > > The Preset Register (PR), Flag Register (FLAG), and Filter Clock
> > > > Prescaler (PSC) have common usage patterns. Wrap up such usage into
> > > > dedicated functions to improve code clarity.
> 
> ...
> 
> > > > +static void quad8_preset_register_set(struct quad8 *const priv, const size_t id,
> > > > +				      const unsigned long preset)
> > > > +{
> > > > +	struct channel_reg __iomem *const chan = priv->reg->channel + id;
> > > > +	int i;
> > > > +
> > > > +	/* Reset Byte Pointer */
> > > > +	iowrite8(SELECT_RLD | RESET_BP, &chan->control);
> > > > +
> > > > +	/* Set Preset Register */
> > > > +	for (i = 0; i < 3; i++)
> > > > +		iowrite8(preset >> (8 * i), &chan->data);
> > > > +}
> > > 
> > > May we add generic __iowrite8_copy() / __ioread8_copy() instead?
> > > 
> > > It seems that even current __ioread32_copy() and __iowrite32_copy() has to
> > > be amended to support IO.
> 
> > Sure, I would use __iowrite8_copy() / __ioread8_copy() for these
> > situations if it were available.
> 
> If needed, you may always introduce ones.
> 
> > Is something equivalent available for the regmap API? I'm planning to
> > migrate this driver to the regmap API soon after this patch series is
> > merged, so the *_copy() calls would need to migrated as well.
> 
> Yes. It's regmap bulk operations.
> 
> -- 
> With Best Regards,
> Andy Shevchenko

After reading through the implementation for these functions I realized
they are actually doing something different than what's happening here.
The 104-QUAD-8 device exposes the 24-bit register by consecutive 8-bit
I/O operations on the same address; however, the iomap_copy and regmap
bulk functions operate on different addresses.

I'm not sure if there really is a way to make the 104-QUAD-8 operation
more generic for other drivers because it configures the current byte
pointer through a separate register from the data register (all of this
feel rather device specific), so I suspect keeping this function local
to 104-quad-8 is best for now.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC
  2023-03-20 15:53         ` William Breathitt Gray
@ 2023-03-20 16:54           ` Andy Shevchenko
  0 siblings, 0 replies; 13+ messages in thread
From: Andy Shevchenko @ 2023-03-20 16:54 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: linux-iio, Johannes Berg, Jonathan Cameron, Andrew Morton, linux-kernel

On Mon, Mar 20, 2023 at 11:53:36AM -0400, William Breathitt Gray wrote:
> On Mon, Mar 20, 2023 at 05:36:17PM +0200, Andy Shevchenko wrote:

...

> After reading through the implementation for these functions I realized
> they are actually doing something different than what's happening here.
> The 104-QUAD-8 device exposes the 24-bit register by consecutive 8-bit
> I/O operations on the same address; however, the iomap_copy and regmap
> bulk functions operate on different addresses.

Ah, than we have ioreadXX_rep()/iowriteXX_rep() for that.

> I'm not sure if there really is a way to make the 104-QUAD-8 operation
> more generic for other drivers because it configures the current byte
> pointer through a separate register from the data register (all of this
> feel rather device specific), so I suspect keeping this function local
> to 104-quad-8 is best for now.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-03-20 17:07 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-18 14:59 [PATCH 0/4] Refactor 104-quad-8 to match device operations William Breathitt Gray
2023-03-18 14:59 ` [PATCH 1/4] counter: 104-quad-8: Utilize bitfield access macros William Breathitt Gray
2023-03-18 14:59 ` [PATCH 2/4] bitfield: Introduce the FIELD_MODIFY() macro William Breathitt Gray
2023-03-20  8:50   ` Johannes Berg
2023-03-20 12:22     ` Andy Shevchenko
2023-03-20 15:03     ` William Breathitt Gray
2023-03-18 14:59 ` [PATCH 3/4] counter: 104-quad-8: Refactor to buffer states for CMR, IOR, and IDR William Breathitt Gray
2023-03-18 14:59 ` [PATCH 4/4] counter: 104-quad-8: Utilize helper functions to handle PR, FLAG and PSC William Breathitt Gray
2023-03-20 12:28   ` Andy Shevchenko
2023-03-20 15:31     ` William Breathitt Gray
2023-03-20 15:36       ` Andy Shevchenko
2023-03-20 15:53         ` William Breathitt Gray
2023-03-20 16:54           ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).