diff mbox series

[3/5] iio: adis: Add adis_update_bits() APIs

Message ID 20200225124152.270914-4-nuno.sa@analog.com (mailing list archive)
State New, archived
Headers show
Series Support ADIS16475 and similar IMUs | expand

Commit Message

Nuno Sa Feb. 25, 2020, 12:41 p.m. UTC
This patch adds a `regmap_update_bits()` like API to the ADIS library.
It provides locked and unlocked variant.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/imu/adis.c       | 26 +++++++++++++++
 include/linux/iio/imu/adis.h | 61 ++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

Comments

Jonathan Cameron March 3, 2020, 8:48 p.m. UTC | #1
On Tue, 25 Feb 2020 13:41:50 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> This patch adds a `regmap_update_bits()` like API to the ADIS library.
> It provides locked and unlocked variant.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Mostly fine, but I wonder if we can avoid the need to have comments
on handling of 1 and 8 byte values by explicitly avoiding them happening.

Thanks,

Jonathan

> ---
>  drivers/iio/imu/adis.c       | 26 +++++++++++++++
>  include/linux/iio/imu/adis.h | 61 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 87 insertions(+)
> 
> diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
> index a8afd01de4f3..fa0ee35d96f0 100644
> --- a/drivers/iio/imu/adis.c
> +++ b/drivers/iio/imu/adis.c
> @@ -223,6 +223,32 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(__adis_read_reg);
> +/**
> + * __adis_update_bits_base() - ADIS Update bits function - Unlocked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + * @size: Size of the register to update
> + *
> + * Updates the desired bits of @reg in accordance with @mask and @val.
> + */
> +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
> +			    const u32 val, u8 size)
> +{
> +	int ret;
> +	u32 __val;
> +
> +	ret = __adis_read_reg(adis, reg, &__val, size);
> +	if (ret)
> +		return ret;
> +
> +	__val &= ~mask;
> +	__val |= val & mask;
> +
> +	return __adis_write_reg(adis, reg, __val, size);
> +}
> +EXPORT_SYMBOL_GPL(__adis_update_bits_base);
>  
>  #ifdef CONFIG_DEBUG_FS
>  
> diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
> index b4c35d137e2a..07073f698718 100644
> --- a/include/linux/iio/imu/adis.h
> +++ b/include/linux/iio/imu/adis.h
> @@ -303,6 +303,67 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
>  	return ret;
>  }
>  
> +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
> +			    const u32 val, u8 size);
> +/**
> + * adis_update_bits_base() - ADIS Update bits function - Locked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + * @size: Size of the register to update
> + *
> + * Updates the desired bits of @reg in accordance with @mask and @val.
> + */
> +static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
> +					const u32 mask, const u32 val, u8 size)
> +{
> +	int ret;
> +
> +	mutex_lock(&adis->state_lock);
> +	ret = __adis_update_bits_base(adis, reg, mask, val, size);
> +	mutex_unlock(&adis->state_lock);
> +	return ret;
> +}
> +
> +/**
> + * adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + *
> + * This macro evaluates the sizeof of @val at compile time and calls
> + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
> + * @val can lead to undesired behavior if the register to update is 16bit. Also
> + * note that a 64bit value will be treated as an integer. In the same way,
> + * a char is seen as a short.

Are these 'edge' conditions desirable?  If not can we use the compile
time checking tricks to trigger a build failure if they occur?
BUILD_BUG_ON(sizeof(val) == 1) etc.

> + */
> +#define adis_update_bits(adis, reg, mask, val) ({			\
> +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> +		adis_update_bits_base(adis, reg, mask, val, 4),         \
> +		adis_update_bits_base(adis, reg, mask, val, 2));	\
> +})
> +
> +/**
> + * adis_update_bits() - Wrapper macro for adis_update_bits_base
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + *
> + * This macro evaluates the sizeof of @val at compile time and calls
> + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
> + * @val can lead to undesired behavior if the register to update is 16bit. Also
> + * note that a 64bit value will be treated as an integer. In the same way,
> + * a char is seen as a short.
> + */
> +#define __adis_update_bits(adis, reg, mask, val) ({			\
> +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> +		__adis_update_bits_base(adis, reg, mask, val, 4),	\
> +		__adis_update_bits_base(adis, reg, mask, val, 2));	\
> +})
> +
>  int adis_enable_irq(struct adis *adis, bool enable);
>  int __adis_check_status(struct adis *adis);
>  int __adis_initial_startup(struct adis *adis);
Nuno Sa March 4, 2020, 5:32 p.m. UTC | #2
On Tue, 2020-03-03 at 20:48 +0000, Jonathan Cameron wrote:
> On Tue, 25 Feb 2020 13:41:50 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > This patch adds a `regmap_update_bits()` like API to the ADIS
> > library.
> > It provides locked and unlocked variant.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> Mostly fine, but I wonder if we can avoid the need to have comments
> on handling of 1 and 8 byte values by explicitly avoiding them
> happening.
> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  drivers/iio/imu/adis.c       | 26 +++++++++++++++
> >  include/linux/iio/imu/adis.h | 61
> > ++++++++++++++++++++++++++++++++++++
> >  2 files changed, 87 insertions(+)
> > 
> > diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
> > index a8afd01de4f3..fa0ee35d96f0 100644
> > --- a/drivers/iio/imu/adis.c
> > +++ b/drivers/iio/imu/adis.c
> > @@ -223,6 +223,32 @@ int __adis_read_reg(struct adis *adis,
> > unsigned int reg,
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL_GPL(__adis_read_reg);
> > +/**
> > + * __adis_update_bits_base() - ADIS Update bits function -
> > Unlocked version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + * @size: Size of the register to update
> > + *
> > + * Updates the desired bits of @reg in accordance with @mask and
> > @val.
> > + */
> > +int __adis_update_bits_base(struct adis *adis, unsigned int reg,
> > const u32 mask,
> > +			    const u32 val, u8 size)
> > +{
> > +	int ret;
> > +	u32 __val;
> > +
> > +	ret = __adis_read_reg(adis, reg, &__val, size);
> > +	if (ret)
> > +		return ret;
> > +
> > +	__val &= ~mask;
> > +	__val |= val & mask;
> > +
> > +	return __adis_write_reg(adis, reg, __val, size);
> > +}
> > +EXPORT_SYMBOL_GPL(__adis_update_bits_base);
> >  
> >  #ifdef CONFIG_DEBUG_FS
> >  
> > diff --git a/include/linux/iio/imu/adis.h
> > b/include/linux/iio/imu/adis.h
> > index b4c35d137e2a..07073f698718 100644
> > --- a/include/linux/iio/imu/adis.h
> > +++ b/include/linux/iio/imu/adis.h
> > @@ -303,6 +303,67 @@ static inline int adis_read_reg_32(struct adis
> > *adis, unsigned int reg,
> >  	return ret;
> >  }
> >  
> > +int __adis_update_bits_base(struct adis *adis, unsigned int reg,
> > const u32 mask,
> > +			    const u32 val, u8 size);
> > +/**
> > + * adis_update_bits_base() - ADIS Update bits function - Locked
> > version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + * @size: Size of the register to update
> > + *
> > + * Updates the desired bits of @reg in accordance with @mask and
> > @val.
> > + */
> > +static inline int adis_update_bits_base(struct adis *adis,
> > unsigned int reg,
> > +					const u32 mask, const u32 val,
> > u8 size)
> > +{
> > +	int ret;
> > +
> > +	mutex_lock(&adis->state_lock);
> > +	ret = __adis_update_bits_base(adis, reg, mask, val, size);
> > +	mutex_unlock(&adis->state_lock);
> > +	return ret;
> > +}
> > +
> > +/**
> > + * adis_update_bits() - Wrapper macro for adis_update_bits_base -
> > Locked version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + *
> > + * This macro evaluates the sizeof of @val at compile time and
> > calls
> > + * adis_update_bits_base() accordingly. Be aware that using
> > MACROS/DEFINES for
> > + * @val can lead to undesired behavior if the register to update
> > is 16bit. Also
> > + * note that a 64bit value will be treated as an integer. In the
> > same way,
> > + * a char is seen as a short.
> 
> Are these 'edge' conditions desirable?  If not can we use the compile
> time checking tricks to trigger a build failure if they occur?
> BUILD_BUG_ON(sizeof(val) == 1) etc.

So, I guess there's no arm in the 'edge' conditions if users know what
they are doing :). But I have no problems in making/forcing the right
types by adding the compile time checks...

Will add it in v2

- Nuno Sá
> > + */
> > +#define adis_update_bits(adis, reg, mask, val) ({			
> > \
> > +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> > +		adis_update_bits_base(adis, reg, mask, val,
> > 4),         \
> > +		adis_update_bits_base(adis, reg, mask, val, 2));	\
> > +})
> > +
> > +/**
> > + * adis_update_bits() - Wrapper macro for adis_update_bits_base
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + *
> > + * This macro evaluates the sizeof of @val at compile time and
> > calls
> > + * adis_update_bits_base() accordingly. Be aware that using
> > MACROS/DEFINES for
> > + * @val can lead to undesired behavior if the register to update
> > is 16bit. Also
> > + * note that a 64bit value will be treated as an integer. In the
> > same way,
> > + * a char is seen as a short.
> > + */
> > +#define __adis_update_bits(adis, reg, mask, val) ({		
> > 	\
> > +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> > +		__adis_update_bits_base(adis, reg, mask, val, 4),	\
> > +		__adis_update_bits_base(adis, reg, mask, val, 2));	\
> > +})
> > +
> >  int adis_enable_irq(struct adis *adis, bool enable);
> >  int __adis_check_status(struct adis *adis);
> >  int __adis_initial_startup(struct adis *adis);
diff mbox series

Patch

diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index a8afd01de4f3..fa0ee35d96f0 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -223,6 +223,32 @@  int __adis_read_reg(struct adis *adis, unsigned int reg,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(__adis_read_reg);
+/**
+ * __adis_update_bits_base() - ADIS Update bits function - Unlocked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ * @size: Size of the register to update
+ *
+ * Updates the desired bits of @reg in accordance with @mask and @val.
+ */
+int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
+			    const u32 val, u8 size)
+{
+	int ret;
+	u32 __val;
+
+	ret = __adis_read_reg(adis, reg, &__val, size);
+	if (ret)
+		return ret;
+
+	__val &= ~mask;
+	__val |= val & mask;
+
+	return __adis_write_reg(adis, reg, __val, size);
+}
+EXPORT_SYMBOL_GPL(__adis_update_bits_base);
 
 #ifdef CONFIG_DEBUG_FS
 
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index b4c35d137e2a..07073f698718 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -303,6 +303,67 @@  static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
 	return ret;
 }
 
+int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
+			    const u32 val, u8 size);
+/**
+ * adis_update_bits_base() - ADIS Update bits function - Locked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ * @size: Size of the register to update
+ *
+ * Updates the desired bits of @reg in accordance with @mask and @val.
+ */
+static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
+					const u32 mask, const u32 val, u8 size)
+{
+	int ret;
+
+	mutex_lock(&adis->state_lock);
+	ret = __adis_update_bits_base(adis, reg, mask, val, size);
+	mutex_unlock(&adis->state_lock);
+	return ret;
+}
+
+/**
+ * adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ *
+ * This macro evaluates the sizeof of @val at compile time and calls
+ * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
+ * @val can lead to undesired behavior if the register to update is 16bit. Also
+ * note that a 64bit value will be treated as an integer. In the same way,
+ * a char is seen as a short.
+ */
+#define adis_update_bits(adis, reg, mask, val) ({			\
+	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
+		adis_update_bits_base(adis, reg, mask, val, 4),         \
+		adis_update_bits_base(adis, reg, mask, val, 2));	\
+})
+
+/**
+ * adis_update_bits() - Wrapper macro for adis_update_bits_base
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ *
+ * This macro evaluates the sizeof of @val at compile time and calls
+ * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
+ * @val can lead to undesired behavior if the register to update is 16bit. Also
+ * note that a 64bit value will be treated as an integer. In the same way,
+ * a char is seen as a short.
+ */
+#define __adis_update_bits(adis, reg, mask, val) ({			\
+	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
+		__adis_update_bits_base(adis, reg, mask, val, 4),	\
+		__adis_update_bits_base(adis, reg, mask, val, 2));	\
+})
+
 int adis_enable_irq(struct adis *adis, bool enable);
 int __adis_check_status(struct adis *adis);
 int __adis_initial_startup(struct adis *adis);