[PATCH] iio: accel: bma400: Refactor generic interrupt configuration

Akshay Jindal posted 1 patch 1 week, 6 days ago
There is a newer version of this series
drivers/iio/accel/bma400.h      |  71 +++++++++++++++---
drivers/iio/accel/bma400_core.c | 128 ++++++++++++++++----------------
2 files changed, 125 insertions(+), 74 deletions(-)
[PATCH] iio: accel: bma400: Refactor generic interrupt configuration
Posted by Akshay Jindal 1 week, 6 days ago
Refactor the generic interrupt configuration logic to improve readability
and reduce repetitive code. Replace hard-coded register values with macros
and enums, making it clearer what configuration is written to hardware.

Introduce a const struct to map event direction to the corresponding
generic interrupt. This removes the need for switch statements in multiple
callbacks, including activity event setup, read_event_value, and
write_event_value, while still performing the selection at runtime.

This change has no functional impact but simplifies the code and makes it
easier to maintain and extend in future updates.

Signed-off-by: Akshay Jindal <akshayaj.lkd@gmail.com>
---
 drivers/iio/accel/bma400.h      |  71 +++++++++++++++---
 drivers/iio/accel/bma400_core.c | 128 ++++++++++++++++----------------
 2 files changed, 125 insertions(+), 74 deletions(-)

diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
index 932358b45f17..ab7d1d139b66 100644
--- a/drivers/iio/accel/bma400.h
+++ b/drivers/iio/accel/bma400.h
@@ -68,7 +68,19 @@
 #define BMA400_CMD_REG              0x7e
 
 /* Interrupt registers */
-#define BMA400_INT_CONFIG0_REG	    0x1f
+#define BMA400_INT_CONFIG0_REG			0x1f
+#define BMA400_INT_CONFIG0_ORTN_CHG_MASK	BIT(1)
+#define BMA400_INT_CONFIG0_GEN1_MASK		BIT(2)
+#define BMA400_INT_CONFIG0_GEN2_MASK		BIT(3)
+#define BMA400_INT_CONFIG0_FIFO_FULL_MASK	BIT(5)
+#define BMA400_INT_CONFIG0_FIFO_WTRMRK_MASK	BIT(6)
+#define BMA400_INT_CONFIG0_DRDY_MASK		BIT(7)
+
+enum generic_intr {
+	GEN1_INTR,
+	GEN2_INTR
+};
+
 #define BMA400_INT_CONFIG1_REG	    0x20
 #define BMA400_INT1_MAP_REG	    0x21
 #define BMA400_INT_IO_CTRL_REG	    0x24
@@ -96,15 +108,53 @@
 #define BMA400_ACC_ODR_MIN_HZ       12
 
 /* Generic interrupts register */
-#define BMA400_GEN1INT_CONFIG0      0x3f
-#define BMA400_GEN2INT_CONFIG0      0x4A
-#define BMA400_GEN_CONFIG1_OFF      0x01
-#define BMA400_GEN_CONFIG2_OFF      0x02
-#define BMA400_GEN_CONFIG3_OFF      0x03
-#define BMA400_GEN_CONFIG31_OFF     0x04
-#define BMA400_INT_GEN1_MSK         BIT(2)
-#define BMA400_INT_GEN2_MSK         BIT(3)
-#define BMA400_GEN_HYST_MSK         GENMASK(1, 0)
+#define BMA400_GENINT_CONFIG_REG_BASE	0x3f
+#define BMA400_NUM_GENINT_CONFIG_REGS	11
+#define BMA400_GENINT_CONFIG_REG(gen_intr, config_idx)	\
+	(BMA400_GENINT_CONFIG_REG_BASE +		\
+	(gen_intr) * BMA400_NUM_GENINT_CONFIG_REGS +	\
+	(config_idx))
+
+/* Generic Interrupt Config0 register */
+#define BMA400_GENINT_CONFIG0_HYST_MASK			GENMASK(1, 0)
+#define BMA400_GENINT_CONFIG0_REF_UPD_MODE_MASK		GENMASK(3, 2)
+#define BMA400_GENINT_CONFIG0_DATA_SRC_MASK		BIT(4)
+#define BMA400_GENINT_CONFIG0_X_EN_MASK			BIT(5)
+#define BMA400_GENINT_CONFIG0_Y_EN_MASK			BIT(6)
+#define BMA400_GENINT_CONFIG0_Z_EN_MASK			BIT(7)
+
+enum bma400_hysteresis_config {
+	NO_HYSTERESIS,
+	HYSTERESIS_24MG,
+	HYSTERESIS_48MG,
+	HYSTERESIS_96MG
+};
+
+enum bma400_accel_data_src {
+	ACCEL_FILT1,
+	ACCEL_FILT2
+};
+
+enum bma400_ref_updt_mode {
+	BMA400_REF_MANUAL_UPDT_MODE,
+	BMA400_REF_ONETIME_UPDT_MODE,
+	BMA400_REF_EVERYTIME_UPDT_MODE,
+	BMA400_REF_EVERYTIME_LP_UPDT_MODE
+};
+
+/* Generic Interrupt Config1 register */
+#define BMA400_GENINT_CONFIG1_AXES_COMB_MASK		BIT(0)
+#define BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK		BIT(1)
+
+enum bma400_genintr_acceleval_axescomb {
+	BMA400_EVAL_X_OR_Y_OR_Z,
+	BMA400_EVAL_X_AND_Y_AND_Z,
+};
+
+enum bma400_detect_criterion {
+	BMA400_DETECT_INACTIVITY,
+	BMA400_DETECT_ACTIVITY,
+};
 
 /* TAP config registers */
 #define BMA400_TAP_CONFIG           0x57
@@ -119,6 +169,7 @@
 #define BMA400_TAP_QUIETDT_MSK      GENMASK(5, 4)
 #define BMA400_TAP_TIM_LIST_LEN     4
 
+
 /*
  * BMA400_SCALE_MIN macro value represents m/s^2 for 1 LSB before
  * converting to micro values for +-2g range.
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 85e23badf733..d59c26b8a57f 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -121,6 +121,29 @@ struct bma400_data {
 	__be16 duration;
 };
 
+struct bma400_genintr_info {
+	u8 genintr;
+	unsigned int intrmask;
+	enum iio_event_direction dir;
+	enum bma400_detect_criterion detect_mode;
+};
+
+/* Lookup struct for determining GEN1/GEN2 based on dir */
+static const struct bma400_genintr_info bma400_genintrs[] = {
+	[IIO_EV_DIR_RISING] = {
+		.genintr = GEN1_INTR,	/* 0 for GEN1 */
+		.intrmask = BMA400_INT_CONFIG0_GEN1_MASK,
+		.dir = IIO_EV_DIR_RISING,
+		.detect_mode = BMA400_DETECT_ACTIVITY,
+	},
+	[IIO_EV_DIR_FALLING] = {
+		.genintr = GEN2_INTR,	/* 1 for GEN2 */
+		.intrmask = BMA400_INT_CONFIG0_GEN2_MASK,
+		.dir = IIO_EV_DIR_FALLING,
+		.detect_mode = BMA400_DETECT_INACTIVITY,
+	}
+};
+
 static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -1114,10 +1137,10 @@ static int bma400_read_event_config(struct iio_dev *indio_dev,
 	case IIO_ACCEL:
 		switch (dir) {
 		case IIO_EV_DIR_RISING:
-			return FIELD_GET(BMA400_INT_GEN1_MSK,
+			return FIELD_GET(BMA400_INT_CONFIG0_GEN1_MASK,
 					 data->generic_event_en);
 		case IIO_EV_DIR_FALLING:
-			return FIELD_GET(BMA400_INT_GEN2_MSK,
+			return FIELD_GET(BMA400_INT_CONFIG0_GEN2_MASK,
 					 data->generic_event_en);
 		case IIO_EV_DIR_SINGLETAP:
 			return FIELD_GET(BMA400_S_TAP_MSK,
@@ -1159,59 +1182,50 @@ static int bma400_activity_event_en(struct bma400_data *data,
 				    enum iio_event_direction dir,
 				    int state)
 {
-	int ret, reg, msk, value;
-	int field_value = 0;
-
-	switch (dir) {
-	case IIO_EV_DIR_RISING:
-		reg = BMA400_GEN1INT_CONFIG0;
-		msk = BMA400_INT_GEN1_MSK;
-		value = 2;
-		set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
-			      FIELD_PREP(BMA400_INT_GEN1_MSK, state));
-		break;
-	case IIO_EV_DIR_FALLING:
-		reg = BMA400_GEN2INT_CONFIG0;
-		msk = BMA400_INT_GEN2_MSK;
-		value = 0;
-		set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
-			      FIELD_PREP(BMA400_INT_GEN2_MSK, state));
-		break;
-	default:
-		return -EINVAL;
-	}
+	int ret, regval;
+	u8 genintr = bma400_genintrs[dir].genintr;
+	u8 detect_criterion = bma400_genintrs[dir].detect_mode;
+	unsigned int intrmask = bma400_genintrs[dir].intrmask;
 
 	/* Enabling all axis for interrupt evaluation */
-	ret = regmap_write(data->regmap, reg, 0xF8);
+	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 0),
+			   BMA400_GENINT_CONFIG0_X_EN_MASK |
+			   BMA400_GENINT_CONFIG0_Y_EN_MASK |
+			   BMA400_GENINT_CONFIG0_Z_EN_MASK|
+			   BMA400_REF_EVERYTIME_UPDT_MODE);
 	if (ret)
 		return ret;
 
 	/* OR combination of all axis for interrupt evaluation */
-	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF, value);
+	regval = FIELD_PREP(BMA400_GENINT_CONFIG1_AXES_COMB_MASK, BMA400_EVAL_X_OR_Y_OR_Z) |
+		 FIELD_PREP(BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK, detect_criterion);
+	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 1), regval);
 	if (ret)
 		return ret;
 
 	/* Initial value to avoid interrupts while enabling*/
-	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A);
+	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 2), 0x0A);
 	if (ret)
 		return ret;
 
 	/* Initial duration value to avoid interrupts while enabling*/
-	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF, 0x0F);
+	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 4), 0x0F);
 	if (ret)
 		return ret;
 
-	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk,
-				 field_value);
+	regval = FIELD_PREP(BMA400_INT_CONFIG0_GEN1_MASK, state);
+	if (genintr)
+		regval = FIELD_PREP(BMA400_INT_CONFIG0_GEN2_MASK, state);
+
+	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, intrmask, regval);
 	if (ret)
 		return ret;
 
-	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk,
-				 field_value);
+	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, intrmask, regval);
 	if (ret)
 		return ret;
 
-	set_mask_bits(&data->generic_event_en, msk, field_value);
+	set_mask_bits(&data->generic_event_en, intrmask, regval);
 	return 0;
 }
 
@@ -1336,18 +1350,6 @@ static int bma400_write_event_config(struct iio_dev *indio_dev,
 	}
 }
 
-static int get_gen_config_reg(enum iio_event_direction dir)
-{
-	switch (dir) {
-	case IIO_EV_DIR_FALLING:
-		return BMA400_GEN2INT_CONFIG0;
-	case IIO_EV_DIR_RISING:
-		return BMA400_GEN1INT_CONFIG0;
-	default:
-		return -EINVAL;
-	}
-}
-
 static int bma400_read_event_value(struct iio_dev *indio_dev,
 				   const struct iio_chan_spec *chan,
 				   enum iio_event_type type,
@@ -1356,22 +1358,20 @@ static int bma400_read_event_value(struct iio_dev *indio_dev,
 				   int *val, int *val2)
 {
 	struct bma400_data *data = iio_priv(indio_dev);
-	int ret, reg, reg_val, raw;
+	int ret, genintr, reg_val, raw;
 
 	if (chan->type != IIO_ACCEL)
 		return -EINVAL;
 
 	switch (type) {
 	case IIO_EV_TYPE_MAG:
-		reg = get_gen_config_reg(dir);
-		if (reg < 0)
-			return -EINVAL;
+		genintr = bma400_genintrs[dir].genintr;
 
 		*val2 = 0;
 		switch (info) {
 		case IIO_EV_INFO_VALUE:
 			ret = regmap_read(data->regmap,
-					  reg + BMA400_GEN_CONFIG2_OFF,
+					  BMA400_GENINT_CONFIG_REG(genintr, 2),
 					  val);
 			if (ret)
 				return ret;
@@ -1379,7 +1379,7 @@ static int bma400_read_event_value(struct iio_dev *indio_dev,
 		case IIO_EV_INFO_PERIOD:
 			mutex_lock(&data->mutex);
 			ret = regmap_bulk_read(data->regmap,
-					       reg + BMA400_GEN_CONFIG3_OFF,
+					       BMA400_GENINT_CONFIG_REG(genintr, 3),
 					       &data->duration,
 					       sizeof(data->duration));
 			if (ret) {
@@ -1390,10 +1390,12 @@ static int bma400_read_event_value(struct iio_dev *indio_dev,
 			mutex_unlock(&data->mutex);
 			return IIO_VAL_INT;
 		case IIO_EV_INFO_HYSTERESIS:
-			ret = regmap_read(data->regmap, reg, val);
+			ret = regmap_read(data->regmap,
+					  BMA400_GENINT_CONFIG_REG(genintr, 0),
+					  val);
 			if (ret)
 				return ret;
-			*val = FIELD_GET(BMA400_GEN_HYST_MSK, *val);
+			*val = FIELD_GET(BMA400_GENINT_CONFIG0_HYST_MASK, *val);
 			return IIO_VAL_INT;
 		default:
 			return -EINVAL;
@@ -1444,16 +1446,14 @@ static int bma400_write_event_value(struct iio_dev *indio_dev,
 				    int val, int val2)
 {
 	struct bma400_data *data = iio_priv(indio_dev);
-	int reg, ret, raw;
+	int genintr, ret, raw;
 
 	if (chan->type != IIO_ACCEL)
 		return -EINVAL;
 
 	switch (type) {
 	case IIO_EV_TYPE_MAG:
-		reg = get_gen_config_reg(dir);
-		if (reg < 0)
-			return -EINVAL;
+		genintr = bma400_genintrs[dir].genintr;
 
 		switch (info) {
 		case IIO_EV_INFO_VALUE:
@@ -1461,7 +1461,7 @@ static int bma400_write_event_value(struct iio_dev *indio_dev,
 				return -EINVAL;
 
 			return regmap_write(data->regmap,
-					    reg + BMA400_GEN_CONFIG2_OFF,
+					    BMA400_GENINT_CONFIG_REG(genintr, 2),
 					    val);
 		case IIO_EV_INFO_PERIOD:
 			if (val < 1 || val > 65535)
@@ -1470,7 +1470,7 @@ static int bma400_write_event_value(struct iio_dev *indio_dev,
 			mutex_lock(&data->mutex);
 			put_unaligned_be16(val, &data->duration);
 			ret = regmap_bulk_write(data->regmap,
-						reg + BMA400_GEN_CONFIG3_OFF,
+						BMA400_GENINT_CONFIG_REG(genintr, 3),
 						&data->duration,
 						sizeof(data->duration));
 			mutex_unlock(&data->mutex);
@@ -1479,10 +1479,10 @@ static int bma400_write_event_value(struct iio_dev *indio_dev,
 			if (val < 0 || val > 3)
 				return -EINVAL;
 
-			return regmap_update_bits(data->regmap, reg,
-						  BMA400_GEN_HYST_MSK,
-						  FIELD_PREP(BMA400_GEN_HYST_MSK,
-							     val));
+			return regmap_update_bits(data->regmap,
+						  BMA400_GENINT_CONFIG_REG(genintr, 0),
+						  BMA400_GENINT_CONFIG0_HYST_MASK,
+						  FIELD_PREP(BMA400_GENINT_CONFIG0_HYST_MASK, val));
 		default:
 			return -EINVAL;
 		}
@@ -1650,10 +1650,10 @@ static irqreturn_t bma400_interrupt(int irq, void *private)
 						  IIO_EV_DIR_DOUBLETAP),
 			       timestamp);
 
-	if (FIELD_GET(BMA400_INT_GEN1_MSK, le16_to_cpu(data->status)))
+	if (FIELD_GET(BMA400_INT_CONFIG0_GEN1_MASK, le16_to_cpu(data->status)))
 		ev_dir = IIO_EV_DIR_RISING;
 
-	if (FIELD_GET(BMA400_INT_GEN2_MSK, le16_to_cpu(data->status)))
+	if (FIELD_GET(BMA400_INT_CONFIG0_GEN2_MASK, le16_to_cpu(data->status)))
 		ev_dir = IIO_EV_DIR_FALLING;
 
 	if (ev_dir != IIO_EV_DIR_NONE) {
-- 
2.43.0
Re: [PATCH] iio: accel: bma400: Refactor generic interrupt configuration
Posted by Nuno Sá 1 week, 5 days ago
Hi,

Thanks for your patch.

On Fri, 2025-09-19 at 00:37 +0530, Akshay Jindal wrote:
> Refactor the generic interrupt configuration logic to improve readability
> and reduce repetitive code. Replace hard-coded register values with macros
> and enums, making it clearer what configuration is written to hardware.
> 
> Introduce a const struct to map event direction to the corresponding
> generic interrupt. This removes the need for switch statements in multiple
> callbacks, including activity event setup, read_event_value, and
> write_event_value, while still performing the selection at runtime.
> 
> This change has no functional impact but simplifies the code and makes it
> easier to maintain and extend in future updates.
> 
> Signed-off-by: Akshay Jindal <akshayaj.lkd@gmail.com>
> ---

You may be trying to refactor too much in one single patch. I would maybe think
about splitting this into 2/3 logical changes.

>  drivers/iio/accel/bma400.h      |  71 +++++++++++++++---
>  drivers/iio/accel/bma400_core.c | 128 ++++++++++++++++----------------
>  2 files changed, 125 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
> index 932358b45f17..ab7d1d139b66 100644
> --- a/drivers/iio/accel/bma400.h
> +++ b/drivers/iio/accel/bma400.h
> @@ -68,7 +68,19 @@
>  #define BMA400_CMD_REG              0x7e
>  
>  /* Interrupt registers */
> -#define BMA400_INT_CONFIG0_REG	    0x1f
> +#define BMA400_INT_CONFIG0_REG			0x1f
> +#define BMA400_INT_CONFIG0_ORTN_CHG_MASK	BIT(1)
> +#define BMA400_INT_CONFIG0_GEN1_MASK		BIT(2)
> +#define BMA400_INT_CONFIG0_GEN2_MASK		BIT(3)
> +#define BMA400_INT_CONFIG0_FIFO_FULL_MASK	BIT(5)
> +#define BMA400_INT_CONFIG0_FIFO_WTRMRK_MASK	BIT(6)
> +#define BMA400_INT_CONFIG0_DRDY_MASK		BIT(7)
> +
> +enum generic_intr {
> +	GEN1_INTR,
> +	GEN2_INTR
> +};
> +
>  #define BMA400_INT_CONFIG1_REG	    0x20
>  #define BMA400_INT1_MAP_REG	    0x21
>  #define BMA400_INT_IO_CTRL_REG	    0x24
> @@ -96,15 +108,53 @@
>  #define BMA400_ACC_ODR_MIN_HZ       12
>  
>  /* Generic interrupts register */
> -#define BMA400_GEN1INT_CONFIG0      0x3f
> -#define BMA400_GEN2INT_CONFIG0      0x4A
> -#define BMA400_GEN_CONFIG1_OFF      0x01
> -#define BMA400_GEN_CONFIG2_OFF      0x02
> -#define BMA400_GEN_CONFIG3_OFF      0x03
> -#define BMA400_GEN_CONFIG31_OFF     0x04
> -#define BMA400_INT_GEN1_MSK         BIT(2)
> -#define BMA400_INT_GEN2_MSK         BIT(3)
> -#define BMA400_GEN_HYST_MSK         GENMASK(1, 0)
> +#define BMA400_GENINT_CONFIG_REG_BASE	0x3f
> +#define BMA400_NUM_GENINT_CONFIG_REGS	11
> +#define BMA400_GENINT_CONFIG_REG(gen_intr, config_idx)	\
> +	(BMA400_GENINT_CONFIG_REG_BASE +		\
> +	(gen_intr) * BMA400_NUM_GENINT_CONFIG_REGS +	\
> +	(config_idx))

Not sure the above macro helps that much. More on this below...

> +
> +/* Generic Interrupt Config0 register */
> +#define BMA400_GENINT_CONFIG0_HYST_MASK			GENMASK(1, 0)
> +#define BMA400_GENINT_CONFIG0_REF_UPD_MODE_MASK		GENMASK(3, 2)
> +#define BMA400_GENINT_CONFIG0_DATA_SRC_MASK		BIT(4)
> +#define BMA400_GENINT_CONFIG0_X_EN_MASK			BIT(5)
> +#define BMA400_GENINT_CONFIG0_Y_EN_MASK			BIT(6)
> +#define BMA400_GENINT_CONFIG0_Z_EN_MASK			BIT(7)
> +
> +enum bma400_hysteresis_config {
> +	NO_HYSTERESIS,
> +	HYSTERESIS_24MG,
> +	HYSTERESIS_48MG,
> +	HYSTERESIS_96MG
> +};
> +
> +enum bma400_accel_data_src {
> +	ACCEL_FILT1,
> +	ACCEL_FILT2
> +};
> +
> +enum bma400_ref_updt_mode {
> +	BMA400_REF_MANUAL_UPDT_MODE,
> +	BMA400_REF_ONETIME_UPDT_MODE,
> +	BMA400_REF_EVERYTIME_UPDT_MODE,
> +	BMA400_REF_EVERYTIME_LP_UPDT_MODE
> +};
> +
> +/* Generic Interrupt Config1 register */
> +#define BMA400_GENINT_CONFIG1_AXES_COMB_MASK		BIT(0)
> +#define BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK		BIT(1)
> +
> +enum bma400_genintr_acceleval_axescomb {
> +	BMA400_EVAL_X_OR_Y_OR_Z,
> +	BMA400_EVAL_X_AND_Y_AND_Z,
> +};
> +
> +enum bma400_detect_criterion {
> +	BMA400_DETECT_INACTIVITY,
> +	BMA400_DETECT_ACTIVITY,
> +};
>  
>  /* TAP config registers */
>  #define BMA400_TAP_CONFIG           0x57
> @@ -119,6 +169,7 @@
>  #define BMA400_TAP_QUIETDT_MSK      GENMASK(5, 4)
>  #define BMA400_TAP_TIM_LIST_LEN     4
>  
> +
>  /*
>   * BMA400_SCALE_MIN macro value represents m/s^2 for 1 LSB before
>   * converting to micro values for +-2g range.
> diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
> index 85e23badf733..d59c26b8a57f 100644
> --- a/drivers/iio/accel/bma400_core.c
> +++ b/drivers/iio/accel/bma400_core.c
> @@ -121,6 +121,29 @@ struct bma400_data {
>  	__be16 duration;
>  };
>  
> +struct bma400_genintr_info {
> +	u8 genintr;
> +	unsigned int intrmask;
> +	enum iio_event_direction dir;
> +	enum bma400_detect_criterion detect_mode;
> +};
> +
> +/* Lookup struct for determining GEN1/GEN2 based on dir */
> +static const struct bma400_genintr_info bma400_genintrs[] = {
> +	[IIO_EV_DIR_RISING] = {
> +		.genintr = GEN1_INTR,	/* 0 for GEN1 */
> +		.intrmask = BMA400_INT_CONFIG0_GEN1_MASK,
> +		.dir = IIO_EV_DIR_RISING,
> +		.detect_mode = BMA400_DETECT_ACTIVITY,
> +	},
> +	[IIO_EV_DIR_FALLING] = {
> +		.genintr = GEN2_INTR,	/* 1 for GEN2 */
> +		.intrmask = BMA400_INT_CONFIG0_GEN2_MASK,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.detect_mode = BMA400_DETECT_INACTIVITY,
> +	}
> +};
> +
>  static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
>  {
>  	switch (reg) {
> @@ -1114,10 +1137,10 @@ static int bma400_read_event_config(struct iio_dev
> *indio_dev,
>  	case IIO_ACCEL:
>  		switch (dir) {
>  		case IIO_EV_DIR_RISING:
> -			return FIELD_GET(BMA400_INT_GEN1_MSK,
> +			return FIELD_GET(BMA400_INT_CONFIG0_GEN1_MASK,
>  					 data->generic_event_en);

Like the above is above renaming defines in a more logical name. Not going to
opinate whether this name is better or not but you could put that (and other
similar changes) in one patch.

>  		case IIO_EV_DIR_FALLING:
> -			return FIELD_GET(BMA400_INT_GEN2_MSK,
> +			return FIELD_GET(BMA400_INT_CONFIG0_GEN2_MASK,
>  					 data->generic_event_en);
>  		case IIO_EV_DIR_SINGLETAP:
>  			return FIELD_GET(BMA400_S_TAP_MSK,
> @@ -1159,59 +1182,50 @@ static int bma400_activity_event_en(struct bma400_data
> *data,
>  				    enum iio_event_direction dir,
>  				    int state)
>  {
> -	int ret, reg, msk, value;
> -	int field_value = 0;
> -
> -	switch (dir) {
> -	case IIO_EV_DIR_RISING:
> -		reg = BMA400_GEN1INT_CONFIG0;
> -		msk = BMA400_INT_GEN1_MSK;
> -		value = 2;
> -		set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
> -			      FIELD_PREP(BMA400_INT_GEN1_MSK, state));
> -		break;
> -	case IIO_EV_DIR_FALLING:
> -		reg = BMA400_GEN2INT_CONFIG0;
> -		msk = BMA400_INT_GEN2_MSK;
> -		value = 0;
> -		set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
> -			      FIELD_PREP(BMA400_INT_GEN2_MSK, state));
> -		break;
> -	default:
> -		return -EINVAL;
> -	}
> +	int ret, regval;
> +	u8 genintr = bma400_genintrs[dir].genintr;
> +	u8 detect_criterion = bma400_genintrs[dir].detect_mode;
> +	unsigned int intrmask = bma400_genintrs[dir].intrmask;
>  

Hmm, you should still have the switch case. Again, not sure the const struct
adds that much but I'm also fine with it. But I would do:

switch (dir) {
case IIO_EV_DIR_RISING:
case IIO_EV_DIR_FALLING:
	genintr = bma400_genintrs[dir].genintr;
	detect_criterion = bma400_genintrs[dir].detect_mode;
	intrmask = bma400_genintrs[dir].intrmask;
default:
	return -EINVAL;

>  	/* Enabling all axis for interrupt evaluation */
> -	ret = regmap_write(data->regmap, reg, 0xF8);
> +	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr,
> 0),
> +			   BMA400_GENINT_CONFIG0_X_EN_MASK |
> +			   BMA400_GENINT_CONFIG0_Y_EN_MASK |
> +			   BMA400_GENINT_CONFIG0_Z_EN_MASK|
> +			   BMA400_REF_EVERYTIME_UPDT_MODE);
>  	if (ret)
>  		return ret;
>  
>  	/* OR combination of all axis for interrupt evaluation */
> -	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF,
> value);
> +	regval = FIELD_PREP(BMA400_GENINT_CONFIG1_AXES_COMB_MASK,
> BMA400_EVAL_X_OR_Y_OR_Z) |
> +		 FIELD_PREP(BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK,
> detect_criterion);
> +	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr,
> 1), regval);
>  	if (ret)
>  		return ret;
>  
>  	/* Initial value to avoid interrupts while enabling*/
> -	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A);
> +	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr,
> 2), 0x0A);

I do not think readability is improved here. The former is way easier to read
IMO. Also, we still have the magic 0x0A.

>  	if (ret)
>  		return ret;
>  
>  	/* Initial duration value to avoid interrupts while enabling*/
> -	ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF,
> 0x0F);
> +	ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr,
> 4), 0x0F);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk,
> -				 field_value);
> +	regval = FIELD_PREP(BMA400_INT_CONFIG0_GEN1_MASK, state);
> +	if (genintr)
> +		regval = FIELD_PREP(BMA400_INT_CONFIG0_GEN2_MASK, state);
> +
> +	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, intrmask,
> regval);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk,
> -				 field_value);
> +	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG,
> intrmask, regval);
>  	if (ret)
>  		return ret;
>  
> -	set_mask_bits(&data->generic_event_en, msk, field_value);
> +	set_mask_bits(&data->generic_event_en, intrmask, regval);
>  	return 0;
>  }
>  
> @@ -1336,18 +1350,6 @@ static int bma400_write_event_config(struct iio_dev
> *indio_dev,
>  	}
>  }
>  
> -static int get_gen_config_reg(enum iio_event_direction dir)
> -{
> -	switch (dir) {
> -	case IIO_EV_DIR_FALLING:
> -		return BMA400_GEN2INT_CONFIG0;
> -	case IIO_EV_DIR_RISING:
> -		return BMA400_GEN1INT_CONFIG0;
> -	default:
> -		return -EINVAL;
> -	}
> -}
> -
>  static int bma400_read_event_value(struct iio_dev *indio_dev,
>  				   const struct iio_chan_spec *chan,
>  				   enum iio_event_type type,
> @@ -1356,22 +1358,20 @@ static int bma400_read_event_value(struct iio_dev
> *indio_dev,
>  				   int *val, int *val2)
>  {
>  	struct bma400_data *data = iio_priv(indio_dev);
> -	int ret, reg, reg_val, raw;
> +	int ret, genintr, reg_val, raw;
>  
>  	if (chan->type != IIO_ACCEL)
>  		return -EINVAL;
>  
>  	switch (type) {
>  	case IIO_EV_TYPE_MAG:
> -		reg = get_gen_config_reg(dir);
> -		if (reg < 0)
> -			return -EINVAL;
> +		genintr = bma400_genintrs[dir].genintr;

Again you should make sure dir is valid. You could keep get_gen_config_reg() and
do something similar with what I suggested above.

>  
>  		*val2 = 0;
>  		switch (info) {
>  		case IIO_EV_INFO_VALUE:
>  			ret = regmap_read(data->regmap,
> -					  reg + BMA400_GEN_CONFIG2_OFF,
> +					  BMA400_GENINT_CONFIG_REG(genintr,
> 2),
>  					  val);
>  			if (ret)
>  				return ret;
> @@ -1379,7 +1379,7 @@ static int bma400_read_event_value(struct iio_dev
> *indio_dev,
>  		case IIO_EV_INFO_PERIOD:
>  			mutex_lock(&data->mutex);
>  			ret = regmap_bulk_read(data->regmap,
> -					       reg + BMA400_GEN_CONFIG3_OFF,
> +					      
> BMA400_GENINT_CONFIG_REG(genintr, 3),
>  					       &data->duration,
>  					       sizeof(data->duration));
>  			if (ret) {
> @@ -1390,10 +1390,12 @@ static int bma400_read_event_value(struct iio_dev
> *indio_dev,
>  			mutex_unlock(&data->mutex);
>  			return IIO_VAL_INT;
>  		case IIO_EV_INFO_HYSTERESIS:
> -			ret = regmap_read(data->regmap, reg, val);
> +			ret = regmap_read(data->regmap,
> +					  BMA400_GENINT_CONFIG_REG(genintr,
> 0),
> +					  val);

One more case where I don't really think this macro is doing readability any
better.

- Nuno Sá
Re: [PATCH] iio: accel: bma400: Refactor generic interrupt configuration
Posted by Akshay Jindal 1 week, 3 days ago
Hi Nuno,
Thank you so much for your review. Please find follow-ups inline.

On Fri, Sep 19, 2025 at 5:34 PM Nuno Sá <noname.nuno@gmail.com> wrote:
>
> Hi,
>
> Thanks for your patch.
>
> On Fri, 2025-09-19 at 00:37 +0530, Akshay Jindal wrote:
> > Refactor the generic interrupt configuration logic to improve readability
> > and reduce repetitive code. Replace hard-coded register values with macros
> > and enums, making it clearer what configuration is written to hardware.
> >
> > Introduce a const struct to map event direction to the corresponding
> > generic interrupt. This removes the need for switch statements in multiple
> > callbacks, including activity event setup, read_event_value, and
> > write_event_value, while still performing the selection at runtime.
> >
> > This change has no functional impact but simplifies the code and makes it
> > easier to maintain and extend in future updates.
> >
> > Signed-off-by: Akshay Jindal <akshayaj.lkd@gmail.com>
> > ---
>
> You may be trying to refactor too much in one single patch. I would maybe think
> about splitting this into 2/3 logical changes.
>
> >  drivers/iio/accel/bma400.h      |  71 +++++++++++++++---
> >  drivers/iio/accel/bma400_core.c | 128 ++++++++++++++++----------------
> >  2 files changed, 125 insertions(+), 74 deletions(-)
> >
> > diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
> > index 932358b45f17..ab7d1d139b66 100644
> > --- a/drivers/iio/accel/bma400.h
> > +++ b/drivers/iio/accel/bma400.h
> > @@ -68,7 +68,19 @@
> >  #define BMA400_CMD_REG              0x7e
> >
> >  /* Interrupt registers */
> > -#define BMA400_INT_CONFIG0_REG           0x1f
> > +#define BMA400_INT_CONFIG0_REG                       0x1f
> > +#define BMA400_INT_CONFIG0_ORTN_CHG_MASK     BIT(1)
> > +#define BMA400_INT_CONFIG0_GEN1_MASK         BIT(2)
> > +#define BMA400_INT_CONFIG0_GEN2_MASK         BIT(3)
> > +#define BMA400_INT_CONFIG0_FIFO_FULL_MASK    BIT(5)
> > +#define BMA400_INT_CONFIG0_FIFO_WTRMRK_MASK  BIT(6)
> > +#define BMA400_INT_CONFIG0_DRDY_MASK         BIT(7)
> > +
> > +enum generic_intr {
> > +     GEN1_INTR,
> > +     GEN2_INTR
> > +};
> > +
> >  #define BMA400_INT_CONFIG1_REG           0x20
> >  #define BMA400_INT1_MAP_REG      0x21
> >  #define BMA400_INT_IO_CTRL_REG           0x24
> > @@ -96,15 +108,53 @@
> >  #define BMA400_ACC_ODR_MIN_HZ       12
> >
> >  /* Generic interrupts register */
> > -#define BMA400_GEN1INT_CONFIG0      0x3f
> > -#define BMA400_GEN2INT_CONFIG0      0x4A
> > -#define BMA400_GEN_CONFIG1_OFF      0x01
> > -#define BMA400_GEN_CONFIG2_OFF      0x02
> > -#define BMA400_GEN_CONFIG3_OFF      0x03
> > -#define BMA400_GEN_CONFIG31_OFF     0x04
> > -#define BMA400_INT_GEN1_MSK         BIT(2)
> > -#define BMA400_INT_GEN2_MSK         BIT(3)
> > -#define BMA400_GEN_HYST_MSK         GENMASK(1, 0)
> > +#define BMA400_GENINT_CONFIG_REG_BASE        0x3f
> > +#define BMA400_NUM_GENINT_CONFIG_REGS        11
> > +#define BMA400_GENINT_CONFIG_REG(gen_intr, config_idx)       \
> > +     (BMA400_GENINT_CONFIG_REG_BASE +                \
> > +     (gen_intr) * BMA400_NUM_GENINT_CONFIG_REGS +    \
> > +     (config_idx))
>
> Not sure the above macro helps that much. More on this below...
In my last patch regarding ltr390, I was given feedback towards
reducing the number of macro definitions. This may look little cryptic,
but it enables me to access GEN1(11) + GEN2 (11) registers with only
2 definitions. I see it as a reasonable tradeoff between readability and
code volume.

> >  static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
> >  {
> >       switch (reg) {
> > @@ -1114,10 +1137,10 @@ static int bma400_read_event_config(struct iio_dev
> > *indio_dev,
> >       case IIO_ACCEL:
> >               switch (dir) {
> >               case IIO_EV_DIR_RISING:
> > -                     return FIELD_GET(BMA400_INT_GEN1_MSK,
> > +                     return FIELD_GET(BMA400_INT_CONFIG0_GEN1_MASK,
> >                                        data->generic_event_en);
>
> Like the above is above renaming defines in a more logical name. Not going to
> opinate whether this name is better or not but you could put that (and other
> similar changes) in one patch.

Initially, I thought of doing this, but if you look at the diff in bma400.h,
only GEN1_MASK and GEN2_MASK have been renamed and re-placed closer
to their register definition macro. Rest all of them are either new
introductions
or have gone for good. Hence I felt it might be an overkill to create
a new patch
just for 2 reg bit renaming. At the same time, I feel new
introductions should be
clubbed with their usage. Ofcourse, all of them are not being used, but even if
the code is using 1 bit of a reg, then all of its fields should be defined.
Due to the above logic, I kept it in a single patch. Although happy to change if
you still feel otherwise.

>
> >               case IIO_EV_DIR_FALLING:
> > -                     return FIELD_GET(BMA400_INT_GEN2_MSK,
> > +                     return FIELD_GET(BMA400_INT_CONFIG0_GEN2_MASK,
> >                                        data->generic_event_en);
> >               case IIO_EV_DIR_SINGLETAP:
> >                       return FIELD_GET(BMA400_S_TAP_MSK,
> > @@ -1159,59 +1182,50 @@ static int bma400_activity_event_en(struct bma400_data
> > *data,
> >                                   enum iio_event_direction dir,
> >                                   int state)
> >  {
> > -     int ret, reg, msk, value;
> > -     int field_value = 0;
> > -
> > -     switch (dir) {
> > -     case IIO_EV_DIR_RISING:
> > -             reg = BMA400_GEN1INT_CONFIG0;
> > -             msk = BMA400_INT_GEN1_MSK;
> > -             value = 2;
> > -             set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
> > -                           FIELD_PREP(BMA400_INT_GEN1_MSK, state));
> > -             break;
> > -     case IIO_EV_DIR_FALLING:
> > -             reg = BMA400_GEN2INT_CONFIG0;
> > -             msk = BMA400_INT_GEN2_MSK;
> > -             value = 0;
> > -             set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
> > -                           FIELD_PREP(BMA400_INT_GEN2_MSK, state));
> > -             break;
> > -     default:
> > -             return -EINVAL;
> > -     }
> > +     int ret, regval;
> > +     u8 genintr = bma400_genintrs[dir].genintr;
> > +     u8 detect_criterion = bma400_genintrs[dir].detect_mode;
> > +     unsigned int intrmask = bma400_genintrs[dir].intrmask;
> >
>
> Hmm, you should still have the switch case. Again, not sure the const struct
> adds that much but I'm also fine with it. But I would do:
>
> switch (dir) {
> case IIO_EV_DIR_RISING:
> case IIO_EV_DIR_FALLING:
>         genintr = bma400_genintrs[dir].genintr;
>         detect_criterion = bma400_genintrs[dir].detect_mode;
>         intrmask = bma400_genintrs[dir].intrmask;
> default:
>         return -EINVAL;
>
Thank you for detailing it out. Yes this gives the best of both worlds.
Uses the centralized lookup struct as well as makes sure dir is sanitized.
Will wrap it up in a function and apply in the v2.

Thanks,
Akshay.