diff mbox series

[v5,12/14] iio: magnetometer: yas530: Add temperature calculation to "chip_info"

Message ID 2a93df6f99913e438dd2d394c074cf79544ab692.1659909060.git.jahau@rocketmail.com (mailing list archive)
State Superseded
Headers show
Series Add support for magnetometer Yamaha YAS537 | expand

Commit Message

Jakob Hauser Aug. 7, 2022, 11:06 p.m. UTC
Add temperature calculation to the "chip_info" structure to ease the handling
of different YAS variants.

Signed-off-by: Jakob Hauser <jahau@rocketmail.com>
---
 drivers/iio/magnetometer/yamaha-yas530.c | 140 ++++++++++++-----------
 1 file changed, 71 insertions(+), 69 deletions(-)

Comments

Andy Shevchenko Aug. 8, 2022, 11:36 a.m. UTC | #1
On Mon, Aug 8, 2022 at 1:07 AM Jakob Hauser <jahau@rocketmail.com> wrote:
>
> Add temperature calculation to the "chip_info" structure to ease the handling
> of different YAS variants.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> Signed-off-by: Jakob Hauser <jahau@rocketmail.com>
> ---
>  drivers/iio/magnetometer/yamaha-yas530.c | 140 ++++++++++++-----------
>  1 file changed, 71 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
> index 262a36c31616..780c7f4d1eff 100644
> --- a/drivers/iio/magnetometer/yamaha-yas530.c
> +++ b/drivers/iio/magnetometer/yamaha-yas530.c
> @@ -79,7 +79,6 @@
>  #define YAS530_DATA_BITS               12
>  #define YAS530_DATA_CENTER             BIT(YAS530_DATA_BITS - 1)
>  #define YAS530_DATA_OVERFLOW           (BIT(YAS530_DATA_BITS) - 1)
> -#define YAS530_20DEGREES               182 /* Counts starting at -62 °C */
>
>  #define YAS532_DEVICE_ID               0x02 /* YAS532/YAS533 (MS-3R/F) */
>  #define YAS532_VERSION_AB              0 /* YAS532/533 AB (MS-3R/F AB) */
> @@ -91,7 +90,6 @@
>  #define YAS532_DATA_BITS               13
>  #define YAS532_DATA_CENTER             BIT(YAS532_DATA_BITS - 1)
>  #define YAS532_DATA_OVERFLOW           (BIT(YAS532_DATA_BITS) - 1)
> -#define YAS532_20DEGREES               390 /* Counts starting at -50 °C */
>
>  /* Turn off device regulators etc after 5 seconds of inactivity */
>  #define YAS5XX_AUTOSUSPEND_DELAY_MS    5000
> @@ -119,6 +117,31 @@ static const int yas530_volatile_reg[] = {
>         YAS530_MEASURE,
>  };
>
> +/*
> + * t_ref_counts is the number of counts at reference temperature.
> + *
> + * The temperature value at YAS magnetometers is a number of counts. The
> + * values in t_ref_counts[] are the counts at the reference temperature
> + * of 20 °C.
> + *
> + * For YAS532/533, this value is known from the Android driver. For YAS530,
> + * it was approximately measured.
> + */
> +static const u16 t_ref_counts[] = { 182, 390, 390 };
> +
> +/*
> + * min_temp_celsius_x10 is the starting point of temperature counting
> + * in 1/10:s degrees Celsius.
> + *
> + * The array min_temp_celsius_x10[] contains the temperatures where the
> + * temperature value count is 0. The values are in 1/10:s degrees Celsius
> + * to ease the further temperature calculation.
> + *
> + * These temperatures are derived from the temperature resolutions given
> + * in the data sheets.
> + */
> +static const s16 min_temp_celsius_x10[] = { -620, -500, -500 };
> +
>  struct yas5xx_calibration {
>         /* Linearization calibration x, y1, y2 */
>         s32 r[3];
> @@ -143,6 +166,8 @@ struct yas5xx;
>   * @volatile_reg: device-specific volatile registers
>   * @volatile_reg_qty: quantity of device-specific volatile registers
>   * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE
> + * @t_ref: number of counts at reference temperature
> + * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius
>   */
>  struct yas5xx_chip_info {
>         unsigned int devid;
> @@ -151,6 +176,8 @@ struct yas5xx_chip_info {
>         const int *volatile_reg;
>         int volatile_reg_qty;
>         u32 scaling_val2;
> +       u16 t_ref;
> +       s16 min_temp_x10;
>  };
>
>  /**
> @@ -349,6 +376,20 @@ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
>                 (yas5xx->hard_offsets[axis] - c->r[axis]) * coef;
>  }
>
> +static s32 yas5xx_calc_temperature(struct yas5xx *yas5xx, u16 t)
> +{
> +       s32 to;
> +       u16 t_ref;
> +       int min_temp_x10, ref_temp_x10;
> +
> +       t_ref = yas5xx->chip_info->t_ref;
> +       min_temp_x10 = yas5xx->chip_info->min_temp_x10;
> +       ref_temp_x10 = 200;
> +
> +       to = (min_temp_x10 + ((ref_temp_x10 - min_temp_x10) * t / t_ref)) * 100;
> +       return to;
> +}
> +
>  /**
>   * yas530_get_measure() - Measure a sample of all axis and process
>   * @yas5xx: The device state
> @@ -363,7 +404,7 @@ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
>  static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
>  {
>         struct yas5xx_calibration *c = &yas5xx->calibration;
> -       u16 t_ref, t, x, y1, y2;
> +       u16 t_ref, t_comp, t, x, y1, y2;
>         /* These are signed x, signed y1 etc */
>         s32 sx, sy1, sy2, sy, sz;
>         int ret;
> @@ -378,47 +419,30 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
>         sy1 = yas530_linearize(yas5xx, y1, 1);
>         sy2 = yas530_linearize(yas5xx, y2, 2);
>
> -       /* Set the temperature reference value (unit: counts) */
> -       switch (yas5xx->chip_info->devid) {
> -       case YAS530_DEVICE_ID:
> -               t_ref = YAS530_20DEGREES;
> -               break;
> -       case YAS532_DEVICE_ID:
> -               t_ref = YAS532_20DEGREES;
> -               break;
> -       default:
> -               dev_err(yas5xx->dev, "unknown device type\n");
> -               return -EINVAL;
> -       }
> -
> -       /* Temperature compensation for x, y1, y2 respectively */
> +       /*
> +        * Set the temperature for compensation (unit: counts):
> +        * YAS532/YAS533 version AC uses the temperature deviation as a
> +        * multiplier. YAS530 and YAS532 version AB use solely the t value.
> +        */
> +       t_ref = yas5xx->chip_info->t_ref;
>         if (yas5xx->chip_info->devid == YAS532_DEVICE_ID &&
>             yas5xx->version == YAS532_VERSION_AC) {
> -               /*
> -                * YAS532 version AC uses the temperature deviation as a
> -                * multiplier.
> -                *
> -                *          Cx * (t - t_ref)
> -                * x' = x - ----------------
> -                *                100
> -                */
> -               sx = sx - (c->Cx * (t - t_ref)) / 100;
> -               sy1 = sy1 - (c->Cy1 * (t - t_ref)) / 100;
> -               sy2 = sy2 - (c->Cy2 * (t - t_ref)) / 100;
> +               t_comp = t - t_ref;
>         } else {
> -               /*
> -                * YAS530 and YAS532 version AB use solely the t value as a
> -                * multiplier.
> -                *
> -                *          Cx * t
> -                * x' = x - ------
> -                *           100
> -                */
> -               sx = sx - (c->Cx * t) / 100;
> -               sy1 = sy1 - (c->Cy1 * t) / 100;
> -               sy2 = sy2 - (c->Cy2 * t) / 100;
> +               t_comp = t;
>         }
>
> +       /*
> +        * Temperature compensation for x, y1, y2 respectively:
> +        *
> +        *          Cx * t_comp
> +        * x' = x - -----------
> +        *              100
> +        */
> +       sx = sx - (c->Cx * t_comp) / 100;
> +       sy1 = sy1 - (c->Cy1 * t_comp) / 100;
> +       sy2 = sy2 - (c->Cy2 * t_comp) / 100;
> +
>         /*
>          * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
>          * y and z.
> @@ -426,36 +450,8 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
>         sy = sy1 - sy2;
>         sz = -sy1 - sy2;
>
> -       /* Process temperature readout */
> -       switch (yas5xx->chip_info->devid) {
> -       case YAS530_DEVICE_ID:
> -               /*
> -                * Raw temperature value t is the number of counts starting
> -                * at -62 °C. Reference value t_ref is the number of counts
> -                * between -62 °C and 20 °C (82 °C range).
> -                *
> -                * Temperature in °C would be (82 / t_ref * t) - 62.
> -                *
> -                * Contrary to this, perform multiplication first and division
> -                * second due to calculating with integers.
> -                *
> -                * To get a nicer result, calculate with 1/10:s degrees Celsius
> -                * and finally multiply by 100 to return millidegrees Celsius.
> -                */
> -               *to = ((820 * t / t_ref) - 620) * 100;
> -               break;
> -       case YAS532_DEVICE_ID:
> -               /*
> -                * Actually same procedure for YAS532 but the starting point is
> -                * at -50 °C. Reference value t_ref is the number of counts
> -                * between -50 °C and 20 °C (70 °C range).
> -                */
> -               *to = ((700 * t / t_ref) - 500) * 100;
> -               break;
> -       default:
> -               dev_err(yas5xx->dev, "unknown device type\n");
> -               return -EINVAL;
> -       }
> +       /* Calculate temperature readout */
> +       *to = yas5xx_calc_temperature(yas5xx, t);
>
>         /*
>          * Calibrate [x,y,z] with some formulas like this:
> @@ -943,6 +939,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
>                 .volatile_reg = yas530_volatile_reg,
>                 .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
>                 .scaling_val2 = 100000000, /* picotesla to Gauss */
> +               .t_ref = t_ref_counts[yas530],
> +               .min_temp_x10 = min_temp_celsius_x10[yas530],
>         },
>         [yas532] = {
>                 .devid = YAS532_DEVICE_ID,
> @@ -951,6 +949,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
>                 .volatile_reg = yas530_volatile_reg,
>                 .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
>                 .scaling_val2 = 100000, /* nanotesla to Gauss */
> +               .t_ref = t_ref_counts[yas532],
> +               .min_temp_x10 = min_temp_celsius_x10[yas532],
>         },
>         [yas533] = {
>                 .devid = YAS532_DEVICE_ID,
> @@ -959,6 +959,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
>                 .volatile_reg = yas530_volatile_reg,
>                 .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
>                 .scaling_val2 = 100000, /* nanotesla to Gauss */
> +               .t_ref = t_ref_counts[yas533],
> +               .min_temp_x10 = min_temp_celsius_x10[yas533],
>         },
>  };
>
> --
> 2.35.1
>
Jakob Hauser Aug. 9, 2022, 11:36 p.m. UTC | #2
Hi Andy,

On 08.08.22 13:36, Andy Shevchenko wrote:
> On Mon, Aug 8, 2022 at 1:07 AM Jakob Hauser <jahau@rocketmail.com> wrote:
>>
>> Add temperature calculation to the "chip_info" structure to ease the handling
>> of different YAS variants.
> 
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

...

Due to C11 standard 6.6.7 considering array calls not as constant
expression (discussion on patch 9), the temperature values need to be
moved directly into the chip_info table as well.

I would move the comments in a reduced way into the kernel doc. It would
look like this:

/**
 * struct yas5xx_chip_info - device-specific data and function pointers
   ...
 * @t_ref: number of counts at reference temperature 20 °C
 * @min_temp_x10: starting point of temperature counting in 1/10:s
 * degrees Celsius
   ...
 *
 * The "t_ref" value for YAS532/533 is known from the Android driver.
 * For YAS530 it was approximately measured.
 *
 * The temperatures "min_temp_x10" are derived from the temperature
 * resolutions given in the data sheets.
 */
struct yas5xx_chip_info {
        ...
        u16 t_ref;
        s16 min_temp_x10;
        ...
};

static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
        [yas530] = {
                ...
                .t_ref = 182, /* counts */
                .min_temp_x10 = -620, /* 1/10:s degrees Celsius */
                ...
        },
        [yas532] = {
                ...
                .t_ref = 390, /* counts */
                .min_temp_x10 = -500, /* 1/10:s degrees Celsius */
                ...
        },
        [yas533] = {
                ...
                .t_ref = 390, /* counts */
                .min_temp_x10 = -500, /* 1/10:s degrees Celsius */
                ...
        },
};

As this is quite some change on that patch, I'd skip your "Reviewed-by:"
tag and you would need to review it again in v6.

Kind regards,
Jakob
diff mbox series

Patch

diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index 262a36c31616..780c7f4d1eff 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -79,7 +79,6 @@ 
 #define YAS530_DATA_BITS		12
 #define YAS530_DATA_CENTER		BIT(YAS530_DATA_BITS - 1)
 #define YAS530_DATA_OVERFLOW		(BIT(YAS530_DATA_BITS) - 1)
-#define YAS530_20DEGREES		182 /* Counts starting at -62 °C */
 
 #define YAS532_DEVICE_ID		0x02 /* YAS532/YAS533 (MS-3R/F) */
 #define YAS532_VERSION_AB		0 /* YAS532/533 AB (MS-3R/F AB) */
@@ -91,7 +90,6 @@ 
 #define YAS532_DATA_BITS		13
 #define YAS532_DATA_CENTER		BIT(YAS532_DATA_BITS - 1)
 #define YAS532_DATA_OVERFLOW		(BIT(YAS532_DATA_BITS) - 1)
-#define YAS532_20DEGREES		390 /* Counts starting at -50 °C */
 
 /* Turn off device regulators etc after 5 seconds of inactivity */
 #define YAS5XX_AUTOSUSPEND_DELAY_MS	5000
@@ -119,6 +117,31 @@  static const int yas530_volatile_reg[] = {
 	YAS530_MEASURE,
 };
 
+/*
+ * t_ref_counts is the number of counts at reference temperature.
+ *
+ * The temperature value at YAS magnetometers is a number of counts. The
+ * values in t_ref_counts[] are the counts at the reference temperature
+ * of 20 °C.
+ *
+ * For YAS532/533, this value is known from the Android driver. For YAS530,
+ * it was approximately measured.
+ */
+static const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/*
+ * min_temp_celsius_x10 is the starting point of temperature counting
+ * in 1/10:s degrees Celsius.
+ *
+ * The array min_temp_celsius_x10[] contains the temperatures where the
+ * temperature value count is 0. The values are in 1/10:s degrees Celsius
+ * to ease the further temperature calculation.
+ *
+ * These temperatures are derived from the temperature resolutions given
+ * in the data sheets.
+ */
+static const s16 min_temp_celsius_x10[] = { -620, -500, -500 };
+
 struct yas5xx_calibration {
 	/* Linearization calibration x, y1, y2 */
 	s32 r[3];
@@ -143,6 +166,8 @@  struct yas5xx;
  * @volatile_reg: device-specific volatile registers
  * @volatile_reg_qty: quantity of device-specific volatile registers
  * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE
+ * @t_ref: number of counts at reference temperature
+ * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius
  */
 struct yas5xx_chip_info {
 	unsigned int devid;
@@ -151,6 +176,8 @@  struct yas5xx_chip_info {
 	const int *volatile_reg;
 	int volatile_reg_qty;
 	u32 scaling_val2;
+	u16 t_ref;
+	s16 min_temp_x10;
 };
 
 /**
@@ -349,6 +376,20 @@  static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 		(yas5xx->hard_offsets[axis] - c->r[axis]) * coef;
 }
 
+static s32 yas5xx_calc_temperature(struct yas5xx *yas5xx, u16 t)
+{
+	s32 to;
+	u16 t_ref;
+	int min_temp_x10, ref_temp_x10;
+
+	t_ref = yas5xx->chip_info->t_ref;
+	min_temp_x10 = yas5xx->chip_info->min_temp_x10;
+	ref_temp_x10 = 200;
+
+	to = (min_temp_x10 + ((ref_temp_x10 - min_temp_x10) * t / t_ref)) * 100;
+	return to;
+}
+
 /**
  * yas530_get_measure() - Measure a sample of all axis and process
  * @yas5xx: The device state
@@ -363,7 +404,7 @@  static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
 {
 	struct yas5xx_calibration *c = &yas5xx->calibration;
-	u16 t_ref, t, x, y1, y2;
+	u16 t_ref, t_comp, t, x, y1, y2;
 	/* These are signed x, signed y1 etc */
 	s32 sx, sy1, sy2, sy, sz;
 	int ret;
@@ -378,47 +419,30 @@  static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 	sy1 = yas530_linearize(yas5xx, y1, 1);
 	sy2 = yas530_linearize(yas5xx, y2, 2);
 
-	/* Set the temperature reference value (unit: counts) */
-	switch (yas5xx->chip_info->devid) {
-	case YAS530_DEVICE_ID:
-		t_ref = YAS530_20DEGREES;
-		break;
-	case YAS532_DEVICE_ID:
-		t_ref = YAS532_20DEGREES;
-		break;
-	default:
-		dev_err(yas5xx->dev, "unknown device type\n");
-		return -EINVAL;
-	}
-
-	/* Temperature compensation for x, y1, y2 respectively */
+	/*
+	 * Set the temperature for compensation (unit: counts):
+	 * YAS532/YAS533 version AC uses the temperature deviation as a
+	 * multiplier. YAS530 and YAS532 version AB use solely the t value.
+	 */
+	t_ref = yas5xx->chip_info->t_ref;
 	if (yas5xx->chip_info->devid == YAS532_DEVICE_ID &&
 	    yas5xx->version == YAS532_VERSION_AC) {
-		/*
-		 * YAS532 version AC uses the temperature deviation as a
-		 * multiplier.
-		 *
-		 *          Cx * (t - t_ref)
-		 * x' = x - ----------------
-		 *                100
-		 */
-		sx = sx - (c->Cx * (t - t_ref)) / 100;
-		sy1 = sy1 - (c->Cy1 * (t - t_ref)) / 100;
-		sy2 = sy2 - (c->Cy2 * (t - t_ref)) / 100;
+		t_comp = t - t_ref;
 	} else {
-		/*
-		 * YAS530 and YAS532 version AB use solely the t value as a
-		 * multiplier.
-		 *
-		 *          Cx * t
-		 * x' = x - ------
-		 *           100
-		 */
-		sx = sx - (c->Cx * t) / 100;
-		sy1 = sy1 - (c->Cy1 * t) / 100;
-		sy2 = sy2 - (c->Cy2 * t) / 100;
+		t_comp = t;
 	}
 
+	/*
+	 * Temperature compensation for x, y1, y2 respectively:
+	 *
+	 *          Cx * t_comp
+	 * x' = x - -----------
+	 *              100
+	 */
+	sx = sx - (c->Cx * t_comp) / 100;
+	sy1 = sy1 - (c->Cy1 * t_comp) / 100;
+	sy2 = sy2 - (c->Cy2 * t_comp) / 100;
+
 	/*
 	 * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
 	 * y and z.
@@ -426,36 +450,8 @@  static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 	sy = sy1 - sy2;
 	sz = -sy1 - sy2;
 
-	/* Process temperature readout */
-	switch (yas5xx->chip_info->devid) {
-	case YAS530_DEVICE_ID:
-		/*
-		 * Raw temperature value t is the number of counts starting
-		 * at -62 °C. Reference value t_ref is the number of counts
-		 * between -62 °C and 20 °C (82 °C range).
-		 *
-		 * Temperature in °C would be (82 / t_ref * t) - 62.
-		 *
-		 * Contrary to this, perform multiplication first and division
-		 * second due to calculating with integers.
-		 *
-		 * To get a nicer result, calculate with 1/10:s degrees Celsius
-		 * and finally multiply by 100 to return millidegrees Celsius.
-		 */
-		*to = ((820 * t / t_ref) - 620) * 100;
-		break;
-	case YAS532_DEVICE_ID:
-		/*
-		 * Actually same procedure for YAS532 but the starting point is
-		 * at -50 °C. Reference value t_ref is the number of counts
-		 * between -50 °C and 20 °C (70 °C range).
-		 */
-		*to = ((700 * t / t_ref) - 500) * 100;
-		break;
-	default:
-		dev_err(yas5xx->dev, "unknown device type\n");
-		return -EINVAL;
-	}
+	/* Calculate temperature readout */
+	*to = yas5xx_calc_temperature(yas5xx, t);
 
 	/*
 	 * Calibrate [x,y,z] with some formulas like this:
@@ -943,6 +939,8 @@  static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
 		.volatile_reg = yas530_volatile_reg,
 		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
 		.scaling_val2 = 100000000, /* picotesla to Gauss */
+		.t_ref = t_ref_counts[yas530],
+		.min_temp_x10 = min_temp_celsius_x10[yas530],
 	},
 	[yas532] = {
 		.devid = YAS532_DEVICE_ID,
@@ -951,6 +949,8 @@  static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
 		.volatile_reg = yas530_volatile_reg,
 		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
 		.scaling_val2 = 100000, /* nanotesla to Gauss */
+		.t_ref = t_ref_counts[yas532],
+		.min_temp_x10 = min_temp_celsius_x10[yas532],
 	},
 	[yas533] = {
 		.devid = YAS532_DEVICE_ID,
@@ -959,6 +959,8 @@  static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
 		.volatile_reg = yas530_volatile_reg,
 		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
 		.scaling_val2 = 100000, /* nanotesla to Gauss */
+		.t_ref = t_ref_counts[yas533],
+		.min_temp_x10 = min_temp_celsius_x10[yas533],
 	},
 };