Skip to contentSkip to conversation

Add support for magnetometer Yamaha YAS537

PATCH Superseded Jakob Hauser 4 participants 39 messages Jul 3, 2022 – Aug 3, 2022 1 message not in the archive IIO

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

v4 cover Add support for magnetometer Yamaha YAS537

This patchset adds YAS537 variant to the already existing driver for Yamaha YAS magnetometers.

Patch 1 is a fix on the current driver.
Patches 2-9 are cleanups and refactoring.
Patch 10 finally adds the YAS537 variant.

Patch 9 adds the "chip_info" approach. As this change is quite extensive, it might need some more discussion and refinement. Also the patchset as such. However, applying that patch late in the patchset allows a good traceability how the other changes were introduced.

By adding patch 9 (chip_info), some of the review comments on the last patchset became obsolete:
- Patch 8 v3: Comment "Can't return here, because you leave the PM counters imbalanced."
- Patch 8 v3: Comment on strncpy() vs. strscpy(),
- Patch 8 v3: "fall through" comment at function yas5xx_volatile_reg().
- Patch 8 v3: Empty line between "break" and "default" within switch statement of function yas5xx_probe().

Changes in v4:
- Rebased to torvalds/linux v5.19-rc4, as this now includes Linus' patch "Fix memchr_inv() misuse" on driver yamaha-yas530.
- Removed redundant Cc tags.
- Patch 2: Replaced "<= ... + 7" by "< ... + 8" and adapted commit message.
- Patch 3: Added default for switch statement, I forgot to add this.
- Patch 4: In function yas5xx_get_measure(), changed wording "milli degrees" to "millidegrees".
- Patch 6: Changed the renaming of function from "yas530_532_" to "yas530_". Same for registers. Added additional comments where appropriate.
- Patch 6: Removed "Reviewed-by:" tag of Andy.
- Split patch 7 v3 into two patches -> patch 7 v4 and patch 8 v4.
- Patch 8: Applied "if (a && b)" suggestion at memchr_inv() by Andy in function yas532_get_calibration_data().
- Patch 8: Removed defines for device IDs YAS537 and YAS539 and accordingly the comment "These variant IDs are known from code dumps".
- Patch 9: New patch to introduce the "chip_info" approach.
- Patch 10: In function yas537_get_calibration_data(), removed "the exact meaning is unknown" from comment "Writing SRST register".
- Patch 10: Also applied "if (a && b)" suggestion at memchr_inv() by Andy in function yas537_get_calibration_data(). Additionally changed the second condition from "== 0" to "!".
- Patch 10: In function yas537_get_calibration_data(), removed empty lines within switch statement. In that context, removed comment "Get data into these four blocks val1 to val4".
- Patch 10: In Kconfig, simplified wording.
- Patch 10: In function yas537_get_calibration_data() "case YAS537_VERSION_0", reduced indent of "for" loop by splitting it into multiple loops. I didn't use integer j, as it was suggested by Jonathan, because only using integer i is more consistant with the loop in "case YAS537_VERSION_1".
- Accordingly, split the "for" loop in "case YAS537_VERSION_1" into two loops as well. Technically this isn't neccessary but it improves readability.
- Patch 10: Added new defines of masks for YAS537 and applied these by FIELD_PREP and FIELD_GET in function yas537_get_calibration_data() within "case YAS537_VERSION_1".
- Patch 10: In function yas537_power_on(), added spaced at "YAS537_ADCCAL + 1".

Changes in v3:
- In patch 3 fixed 2x typo "Divide".
- In commit message of patch 4 fixed wording "in the yas5xx_get_measure() function".
- In patch 4 in the comment for the temperature calculation fixed wording "is the number of counts".
- In patch 4 added defaults to switch statements.
- Splitted stray changes into new patch 7 v3. "Add YAS537 variant" is now patch 8 v3. I haven't added "Reviewed-by:" tag of Linus to patch 7 v3 because as a separate patch these changes appear in a different context.
- In new patch 7 v3, changed printk format specifiers in the function yas530_get_calibration_data() to "%16ph" and in the function yas532_get_calibration_data() to "%14ph". The first one is also a minor correction in behaviour, as the calibration data array size of YAS530 is 16 (the dev_dbg printed 14 before).
- Rebased to linux-next to include patch bb52d3691db8 "iio: magnetometer:
yas530: Fix memchr_inv() misuse".
- In patch 7 v3, changed memchr_inv() line for YAS532.
- In patch 8 v3 in the function yas537_get_calibration_data(), changed memchr_inv() line for YAS537.
- Removed comment "corresponds to 0x70" at define YAS537_MAG_AVERAGE_32_MASK.
- Added suffixes _US and _MS in defines for YAS537.
- In the function yas537_measure(), removed comments "Read data", "Arrange data", "Assign data".
- In the function yas537_measure(), replaced bitwise shift by get_unaligned_be16().
- Replaced "if (h[i] < -8192)" etc. by clamp_val().
- In the functions yas537_measure() and yas537_get_measure(), replaced 8192 by BIT(13) and 16384 by BIT(14).
- Fixed typo "resolution" in the function yas5xx_read_raw().
- Fixed typo "Divide" in patch 8 v3 in the function yas5xx_read_raw().
- In patch 8 v3 in the yas537_get_calibration_data(), changed printk format specifier to "%17ph"
- In the functions yas537_measure() and yas537_get_calibration_data(), drop some parentheses in regmap_write().
- In the function yas537_power_on(), added comment "Wait until the coil has ramped up".
- In the function yas5xx_probe(), put YAS537 variant and version printings into one print.
- In the function yas537_get_measure(), fixed wording "is the number of counts" in the comment for the temperature calculation.
- In the function yas537_get_measure(), added product description document No. into the comment for the temperature calculation (as I first thought the review comment "the number" is related to this).
- In the function yas537_get_calibration_data(), corrected comment "Get data into these four blocks val1 to val4".

Changes in v2:
- Reordered the patchset by moving patch 4 v1 to patch 1 v2.
- Removed patch 6 v1 ("Remove redundant defaults on switch devid")
- Accordingly, added "default:" to each switch statement in patch 7.
- Moved renamings in patch 7 v1 into a separate new patch 6 v2. I added the "Reviewed-by:" tag of Linus to both patches, hope that's ok, else feel free to comment.
- Removed regmap reads and related debug dumps in patch 7 in function yas537_dump_calibration(). As this function now applies to version 1 only, replaced switch statement by if clause.
- Also removed "hard_offsets" debug dumps in that function.
- Fixed typo "initialized" in commit message of patch 7.

Jakob Hauser (10):
iio: magnetometer: yas530: Change data type of hard_offsets to signed
iio: magnetometer: yas530: Change range of data in volatile register
iio: magnetometer: yas530: Correct scaling of magnetic axes
iio: magnetometer: yas530: Correct temperature handling
iio: magnetometer: yas530: Change data type of calibration
coefficients
iio: magnetometer: yas530: Rename functions and registers
iio: magnetometer: yas530: Move printk %*ph parameters out from stack
iio: magnetometer: yas530: Apply documentation and style fixes
iio: magnetometer: yas530: Introduce "chip_info" structure
iio: magnetometer: yas530: Add YAS537 variant

 drivers/iio/magnetometer/Kconfig         |   4 +-
 drivers/iio/magnetometer/yamaha-yas530.c | 808 +++++++++++++++++++----
 2 files changed, 680 insertions(+), 132 deletions(-)
Signature · 1 line
2.35.1
#2 lore raw

PATCH v4 1/10 iio: magnetometer: yas530: Change data type of hard_offsets to signed

The "hard_offsets" are currently unsigned u8 but they should be signed as they can get negative. They are signed in function yas5xx_meaure_offsets() and in the Yamaha drivers [1][2].

[1] https://github.com/NovaFusion/android_kernel_samsung_golden/blob/cm-12.1/drivers/sensor/compass/yas.h#L156
[2] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas532.c#L91

Fixes de8860b1ed47 ("iio: magnetometer: Add driver for Yamaha YAS530")
---
 drivers/iio/magnetometer/yamaha-yas530.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
index b2bc637150bf..40192aa46b04 100644
@@ -132,7 +132,7 @@ struct yas5xx {
 	unsigned int version;
 	char name[16];
 	struct yas5xx_calibration calibration;
-	u8 hard_offsets[3];
+	s8 hard_offsets[3];
 	struct iio_mount_matrix orientation;
 	struct regmap *map;
 	struct regulator_bulk_data regs[2];
Signature · 1 line
2.35.1
#3 lore raw

PATCH v4 2/10 iio: magnetometer: yas530: Change range of data in volatile register

In reply to Jakob Hauser

In function yas5xx_volatile_reg(), register "YAS5XX_MEASURE_DATA + 8" shouldn't be volatile as we count from 0 to 7 here.

Instead of lowering the number from 8 to 7, the operator "<=" is replaced by "<". The size of the measure data array is 8, therefore it's more natural to use 8 as a constant.

This change is of low importance as the "+ 8" register isn't called.

---
 drivers/iio/magnetometer/yamaha-yas530.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
index 40192aa46b04..6fa29b96c013 100644
@@ -527,7 +527,7 @@ static bool yas5xx_volatile_reg(struct device *dev, unsigned int reg)
 {
 	return reg == YAS5XX_ACTUATE_INIT_COIL ||
 		reg == YAS5XX_MEASURE ||
-		(reg >= YAS5XX_MEASURE_DATA && reg <= YAS5XX_MEASURE_DATA + 8);
+		(reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8);
 }
 
 /* TODO: enable regmap cache, using mark dirty and sync at runtime resume */
Signature · 1 line
2.35.1
#4 lore raw

PATCH v4 3/10 iio: magnetometer: yas530: Correct scaling of magnetic axes

In reply to Jakob Hauser

Looks like YAS530 raw values return picotesla and YAS532 nanotesla. Adapt comments and scaling.

---
 drivers/iio/magnetometer/yamaha-yas530.c | 31 ++++++++++++++++--------
 1 file changed, 21 insertions(+), 10 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +21 -10
index 6fa29b96c013..8cad724fb328 100644
@@ -310,8 +310,6 @@ static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
  * @yo: Y axis out
  * @zo: Z axis out
  * @return: 0 on success or error code
- *
- * Returned values are in nanotesla according to some code.
  */
 static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
 {
@@ -417,14 +415,27 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev,
 			*val = 1;
 			return IIO_VAL_INT;
 		}
-		/*
-		 * The axis values are in nanotesla according to the vendor
-		 * drivers, but is clearly in microtesla according to
-		 * experiments. Since 1 uT = 0.01 Gauss, we need to divide
-		 * by 100000000 (10^8) to get to Gauss from the raw value.
-		 */
-		*val = 1;
-		*val2 = 100000000;
+		switch (yas5xx->devid) {
+		case YAS530_DEVICE_ID:
+			/*
+			 * Raw values of YAS530 are in picotesla. Divide by
+			 * 100000000 (10^8) to get Gauss.
+			 */
+			*val = 1;
+			*val2 = 100000000;
+			break;
+		case YAS532_DEVICE_ID:
+			/*
+			 * Raw values of YAS532 are in nanotesla. Divide by
+			 * 100000 (10^5) to get Gauss.
+			 */
+			*val = 1;
+			*val2 = 100000;
+			break;
+		default:
+			dev_err(yas5xx->dev, "unknown device type\n");
+			return -EINVAL;
+		}
 		return IIO_VAL_FRACTIONAL;
 	default:
 		/* Unknown request */
Signature · 1 line
2.35.1
#5 lore raw

PATCH v4 4/10 iio: magnetometer: yas530: Correct temperature handling

In reply to Jakob Hauser

The raw temperature value is a number of counts from a certain starting point. The resolution of the temperature counts is different for the YAS variants.

Temperature compensation for YAS532 version AC seems to be handled differently. It uses the deviation from 20 degree Celsius [1] whereas YAS530 and older versions of YAS532 apply solely the t value as a multiplier [2][3].

In funtion yas5xx_read_raw(), add case IIO_CHAN_INFO_PROCESSED. Remove scale of temperature as this isn't applied.

Additionally correct sign of temperature channel in iio_chan_spec. It's already defined that way in the yas5xx_get_measure() function.

[1] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas532.c#L442
[2] https://github.com/NovaFusion/android_kernel_samsung_golden/blob/cm-12.1/drivers/sensor/compass/yas_mag_driver-yas530.c#L881-L883
[3] https://github.com/LineageOS/android_kernel_samsung_msm8930-common/blob/lineage-18.1/drivers/sensors/geomagnetic/yas_mag_driver-yas53x.c#L856-L858

---
 drivers/iio/magnetometer/yamaha-yas530.c | 99 ++++++++++++++++++------
 1 file changed, 76 insertions(+), 23 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +76 -23
index 8cad724fb328..c6889a30a1b5 100644
@@ -77,6 +77,7 @@
 #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) */
@@ -88,7 +89,7 @@
 #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 /* Looks like Kelvin */
+#define YAS532_20DEGREES		390 /* Counts starting at -50 °C */
 
 /* These variant IDs are known from code dumps */
 #define YAS537_DEVICE_ID		0x07 /* YAS537 (MS-3T) */
@@ -314,7 +315,7 @@ static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
 {
 	struct yas5xx_calibration *c = &yas5xx->calibration;
-	u16 t, x, y1, y2;
+	u16 t_ref, t, x, y1, y2;
 	/* These are "signed x, signed y1 etc */
 	s32 sx, sy1, sy2, sy, sz;
 	int ret;
@@ -329,16 +330,46 @@ static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 	sy1 = yas5xx_linearize(yas5xx, y1, 1);
 	sy2 = yas5xx_linearize(yas5xx, y2, 2);
 
-	/*
-	 * Temperature compensation for x, y1, y2 respectively:
-	 *
-	 *          Cx * t
-	 * x' = x - ------
-	 *           100
-	 */
-	sx = sx - (c->Cx * t) / 100;
-	sy1 = sy1 - (c->Cy1 * t) / 100;
-	sy2 = sy2 - (c->Cy2 * t) / 100;
+	/* Set the temperature reference value (unit: counts) */
+	switch (yas5xx->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 */
+	if (yas5xx->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;
+	} 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;
+	}
 
 	/*
 	 * Break y1 and y2 into y and z, y1 and y2 are apparently encoding
@@ -347,11 +378,37 @@ static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 	sy = sy1 - sy2;
 	sz = -sy1 - sy2;
 
-	/*
-	 * FIXME: convert to Celsius? Just guessing this is given
-	 * as 1/10:s of degrees so multiply by 100 to get millicentigrades.
-	 */
-	*to = t * 100;
+	/* Process temperature readout */
+	switch (yas5xx->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;
+	}
+
 	/*
 	 * Calibrate [x,y,z] with some formulas like this:
 	 *
@@ -384,6 +441,7 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev,
 	int ret;
 
 	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
 	case IIO_CHAN_INFO_RAW:
 		pm_runtime_get_sync(yas5xx->dev);
 		ret = yas5xx_get_measure(yas5xx, &t, &x, &y, &z);
@@ -410,11 +468,6 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev,
 		}
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		if (chan->address == 0) {
-			/* Temperature is unscaled */
-			*val = 1;
-			return IIO_VAL_INT;
-		}
 		switch (yas5xx->devid) {
 		case YAS530_DEVICE_ID:
 			/*
@@ -516,7 +569,7 @@ static const struct iio_chan_spec yas5xx_channels[] = {
 		.address = 0,
 		.scan_index = 0,
 		.scan_type = {
-			.sign = 'u',
+			.sign = 's',
 			.realbits = 32,
 			.storagebits = 32,
 			.endianness = IIO_CPU,
Signature · 1 line
2.35.1
#6 lore raw

PATCH v4 5/10 iio: magnetometer: yas530: Change data type of calibration coefficients

In reply to Jakob Hauser

This is a preparation for adding YAS537 variant.

YAS537 uses other data types on the calibration coefficients [1] than YAS530 [2] and YAS532 [3].

On YAS537, at least for a4 and a7 this could matter because 8-bit unsigned data from the register gets stored into a signed data type, therefore this should be 8-bit as well.

For YAS530/532, on the other hand, it doesn't seem to matter. The size of a2-a9 and k is smaller than 8-bit at extraction, also the applied math is low. And Cx/Cy1/Cy2, now being defined as signed 16-bit, are extracted as unsigned 8-bit and undergo only minor math.

[1] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L76-L78
[2] https://github.com/NovaFusion/android_kernel_samsung_golden/blob/cm-12.1/drivers/sensor/compass/yas_mag_driver-yas530.c#L526-L527
[3] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas532.c#L76-L77

---
 drivers/iio/magnetometer/yamaha-yas530.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +4 -2
index c6889a30a1b5..839baeca673a 100644
@@ -103,9 +103,11 @@ struct yas5xx_calibration {
 	s32 r[3];
 	u32 f[3];
 	/* Temperature compensation calibration */
-	s32 Cx, Cy1, Cy2;
+	s16 Cx, Cy1, Cy2;
 	/* Misc calibration coefficients */
-	s32 a2, a3, a4, a5, a6, a7, a8, a9, k;
+	s8  a2, a3, a4, a6, a7, a8;
+	s16 a5, a9;
+	u8  k;
 	/* clock divider */
 	u8 dck;
 };
Signature · 1 line
2.35.1
#7 lore raw

PATCH v4 6/10 iio: magnetometer: yas530: Rename functions and registers

In reply to Jakob Hauser

This is a preparation for adding YAS537 variant.

Functions that are used only by YAS530, YAS532 and YAS533 are renamed from yas5xx to yas530. Same for the registers.

To avoid part listing in function and registers names, the name of the first variant is used. Where appropriate, comments were added that these functions are used by more than one variant.

Functions that will be used by all variants including YAS537 remain in the naming scheme yas5xx. Or YAS5XX for registers, respectively.

---
 drivers/iio/magnetometer/yamaha-yas530.c | 113 +++++++++++++----------
 1 file changed, 62 insertions(+), 51 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +62 -51
index 839baeca673a..c250909df8f4 100644
@@ -40,20 +40,22 @@
 
 #include <asm/unaligned.h>
 
-/* This register map covers YAS530 and YAS532 but differs in YAS 537 and YAS539 */
+/* Commonly used registers */
 #define YAS5XX_DEVICE_ID		0x80
-#define YAS5XX_ACTUATE_INIT_COIL	0x81
-#define YAS5XX_MEASURE			0x82
-#define YAS5XX_CONFIG			0x83
-#define YAS5XX_MEASURE_INTERVAL		0x84
-#define YAS5XX_OFFSET_X			0x85 /* [-31 .. 31] */
-#define YAS5XX_OFFSET_Y1		0x86 /* [-31 .. 31] */
-#define YAS5XX_OFFSET_Y2		0x87 /* [-31 .. 31] */
-#define YAS5XX_TEST1			0x88
-#define YAS5XX_TEST2			0x89
-#define YAS5XX_CAL			0x90
 #define YAS5XX_MEASURE_DATA		0xB0
 
+/* These registers are used by YAS530, YAS532 and YAS533 */
+#define YAS530_ACTUATE_INIT_COIL	0x81
+#define YAS530_MEASURE			0x82
+#define YAS530_CONFIG			0x83
+#define YAS530_MEASURE_INTERVAL		0x84
+#define YAS530_OFFSET_X			0x85 /* [-31 .. 31] */
+#define YAS530_OFFSET_Y1		0x86 /* [-31 .. 31] */
+#define YAS530_OFFSET_Y2		0x87 /* [-31 .. 31] */
+#define YAS530_TEST1			0x88
+#define YAS530_TEST2			0x89
+#define YAS530_CAL			0x90
+
 /* Bits in the YAS5xx config register */
 #define YAS5XX_CONFIG_INTON		BIT(0) /* Interrupt on? */
 #define YAS5XX_CONFIG_INTHACT		BIT(1) /* Interrupt active high? */
@@ -182,7 +184,7 @@ static u16 yas532_extract_axis(u8 *data)
 }
 
 /**
- * yas5xx_measure() - Make a measure from the hardware
+ * yas530_measure() - Make a measure from the hardware
  * @yas5xx: The device state
  * @t: the raw temperature measurement
  * @x: the raw x axis measurement
@@ -190,7 +192,8 @@ static u16 yas532_extract_axis(u8 *data)
  * @y2: the y2 axis measurement
  * @return: 0 on success or error code
  */
-static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
+/* Used by YAS530, YAS532 and YAS533 */
+static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
 {
 	unsigned int busy;
 	u8 data[8];
@@ -198,7 +201,7 @@ static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
 	u16 val;
 
 	mutex_lock(&yas5xx->lock);
-	ret = regmap_write(yas5xx->map, YAS5XX_MEASURE, YAS5XX_MEASURE_START);
+	ret = regmap_write(yas5xx->map, YAS530_MEASURE, YAS5XX_MEASURE_START);
 	if (ret < 0)
 		goto out_unlock;
 
@@ -264,7 +267,8 @@ static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
 	return ret;
 }
 
-static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
+/* Used by YAS530, YAS532 and YAS533 */
+static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 {
 	struct yas5xx_calibration *c = &yas5xx->calibration;
 	static const s32 yas532ac_coef[] = {
@@ -306,7 +310,7 @@ static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 }
 
 /**
- * yas5xx_get_measure() - Measure a sample of all axis and process
+ * yas530_get_measure() - Measure a sample of all axis and process
  * @yas5xx: The device state
  * @to: Temperature out
  * @xo: X axis out
@@ -314,7 +318,8 @@ static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
  * @zo: Z axis out
  * @return: 0 on success or error code
  */
-static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
+/* Used by YAS530, YAS532 and YAS533 */
+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;
@@ -323,14 +328,14 @@ static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 	int ret;
 
 	/* We first get raw data that needs to be translated to [x,y,z] */
-	ret = yas5xx_measure(yas5xx, &t, &x, &y1, &y2);
+	ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
 	if (ret)
 		return ret;
 
 	/* Do some linearization if available */
-	sx = yas5xx_linearize(yas5xx, x, 0);
-	sy1 = yas5xx_linearize(yas5xx, y1, 1);
-	sy2 = yas5xx_linearize(yas5xx, y2, 2);
+	sx = yas530_linearize(yas5xx, x, 0);
+	sy1 = yas530_linearize(yas5xx, y1, 1);
+	sy2 = yas530_linearize(yas5xx, y2, 2);
 
 	/* Set the temperature reference value (unit: counts) */
 	switch (yas5xx->devid) {
@@ -605,11 +610,12 @@ static const struct regmap_config yas5xx_regmap_config = {
 };
 
 /**
- * yas53x_extract_calibration() - extracts the a2-a9 and k calibration
+ * yas530_extract_calibration() - extracts the a2-a9 and k calibration
  * @data: the bitfield to use
  * @c: the calibration to populate
  */
-static void yas53x_extract_calibration(u8 *data, struct yas5xx_calibration *c)
+/* Used by YAS530, YAS532 and YAS533 */
+static void yas530_extract_calibration(u8 *data, struct yas5xx_calibration *c)
 {
 	u64 val = get_unaligned_be64(data);
 
@@ -647,12 +653,12 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 	int ret;
 
 	/* Dummy read, first read is ALWAYS wrong */
-	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
+	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
 
 	/* Actual calibration readout */
-	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
+	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
 	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
@@ -664,7 +670,7 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 	c->Cx = data[0] * 6 - 768;
 	c->Cy1 = data[1] * 6 - 768;
 	c->Cy2 = data[2] * 6 - 768;
-	yas53x_extract_calibration(&data[3], c);
+	yas530_extract_calibration(&data[3], c);
 
 	/*
 	 * Extract linearization:
@@ -695,11 +701,11 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	int ret;
 
 	/* Dummy read, first read is ALWAYS wrong */
-	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
+	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
 	/* Actual calibration readout */
-	ret = regmap_bulk_read(yas5xx->map, YAS5XX_CAL, data, sizeof(data));
+	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
 	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
@@ -718,7 +724,7 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	c->Cx = data[0] * 10 - 1280;
 	c->Cy1 = data[1] * 10 - 1280;
 	c->Cy2 = data[2] * 10 - 1280;
-	yas53x_extract_calibration(&data[3], c);
+	yas530_extract_calibration(&data[3], c);
 	/*
 	 * Extract linearization:
 	 * Linearization layout in the 32 bits at byte 10:
@@ -741,7 +747,8 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	return 0;
 }
 
-static void yas5xx_dump_calibration(struct yas5xx *yas5xx)
+/* Used by YAS530, YAS532 and YAS533 */
+static void yas530_dump_calibration(struct yas5xx *yas5xx)
 {
 	struct yas5xx_calibration *c = &yas5xx->calibration;
 
@@ -764,20 +771,22 @@ static void yas5xx_dump_calibration(struct yas5xx *yas5xx)
 	dev_dbg(yas5xx->dev, "dck = %d\n", c->dck);
 }
 
-static int yas5xx_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2)
+/* Used by YAS530, YAS532 and YAS533 */
+static int yas530_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2)
 {
 	int ret;
 
-	ret = regmap_write(yas5xx->map, YAS5XX_OFFSET_X, ox);
+	ret = regmap_write(yas5xx->map, YAS530_OFFSET_X, ox);
 	if (ret)
 		return ret;
-	ret = regmap_write(yas5xx->map, YAS5XX_OFFSET_Y1, oy1);
+	ret = regmap_write(yas5xx->map, YAS530_OFFSET_Y1, oy1);
 	if (ret)
 		return ret;
-	return regmap_write(yas5xx->map, YAS5XX_OFFSET_Y2, oy2);
+	return regmap_write(yas5xx->map, YAS530_OFFSET_Y2, oy2);
 }
 
-static s8 yas5xx_adjust_offset(s8 old, int bit, u16 center, u16 measure)
+/* Used by YAS530, YAS532 and YAS533 */
+static s8 yas530_adjust_offset(s8 old, int bit, u16 center, u16 measure)
 {
 	if (measure > center)
 		return old + BIT(bit);
@@ -786,7 +795,8 @@ static s8 yas5xx_adjust_offset(s8 old, int bit, u16 center, u16 measure)
 	return old;
 }
 
-static int yas5xx_meaure_offsets(struct yas5xx *yas5xx)
+/* Used by YAS530, YAS532 and YAS533 */
+static int yas530_measure_offsets(struct yas5xx *yas5xx)
 {
 	int ret;
 	u16 center;
@@ -795,7 +805,7 @@ static int yas5xx_meaure_offsets(struct yas5xx *yas5xx)
 	int i;
 
 	/* Actuate the init coil and measure offsets */
-	ret = regmap_write(yas5xx->map, YAS5XX_ACTUATE_INIT_COIL, 0);
+	ret = regmap_write(yas5xx->map, YAS530_ACTUATE_INIT_COIL, 0);
 	if (ret)
 		return ret;
 
@@ -829,26 +839,26 @@ static int yas5xx_meaure_offsets(struct yas5xx *yas5xx)
 	oy2 = 0;
 
 	for (i = 4; i >= 0; i--) {
-		ret = yas5xx_set_offsets(yas5xx, ox, oy1, oy2);
+		ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
 		if (ret)
 			return ret;
 
-		ret = yas5xx_measure(yas5xx, &t, &x, &y1, &y2);
+		ret = yas530_measure(yas5xx, &t, &x, &y1, &y2);
 		if (ret)
 			return ret;
 		dev_dbg(yas5xx->dev, "measurement %d: x=%d, y1=%d, y2=%d\n",
 			5-i, x, y1, y2);
 
-		ox = yas5xx_adjust_offset(ox, i, center, x);
-		oy1 = yas5xx_adjust_offset(oy1, i, center, y1);
-		oy2 = yas5xx_adjust_offset(oy2, i, center, y2);
+		ox = yas530_adjust_offset(ox, i, center, x);
+		oy1 = yas530_adjust_offset(oy1, i, center, y1);
+		oy2 = yas530_adjust_offset(oy2, i, center, y2);
 	}
 
 	/* Needed for calibration algorithm */
 	yas5xx->hard_offsets[0] = ox;
 	yas5xx->hard_offsets[1] = oy1;
 	yas5xx->hard_offsets[2] = oy2;
-	ret = yas5xx_set_offsets(yas5xx, ox, oy1, oy2);
+	ret = yas530_set_offsets(yas5xx, ox, oy1, oy2);
 	if (ret)
 		return ret;
 
@@ -857,27 +867,28 @@ static int yas5xx_meaure_offsets(struct yas5xx *yas5xx)
 	return 0;
 }
 
-static int yas5xx_power_on(struct yas5xx *yas5xx)
+/* Used by YAS530, YAS532 and YAS533 */
+static int yas530_power_on(struct yas5xx *yas5xx)
 {
 	unsigned int val;
 	int ret;
 
 	/* Zero the test registers */
-	ret = regmap_write(yas5xx->map, YAS5XX_TEST1, 0);
+	ret = regmap_write(yas5xx->map, YAS530_TEST1, 0);
 	if (ret)
 		return ret;
-	ret = regmap_write(yas5xx->map, YAS5XX_TEST2, 0);
+	ret = regmap_write(yas5xx->map, YAS530_TEST2, 0);
 	if (ret)
 		return ret;
 
 	/* Set up for no interrupts, calibrated clock divider */
 	val = FIELD_PREP(YAS5XX_CONFIG_CCK_MASK, yas5xx->calibration.dck);
-	ret = regmap_write(yas5xx->map, YAS5XX_CONFIG, val);
+	ret = regmap_write(yas5xx->map, YAS530_CONFIG, val);
 	if (ret)
 		return ret;
 
 	/* Measure interval 0 (back-to-back?)  */
-	return regmap_write(yas5xx->map, YAS5XX_MEASURE_INTERVAL, 0);
+	return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0);
 }
 
 static int yas5xx_probe(struct i2c_client *i2c,
@@ -959,11 +970,11 @@ static int yas5xx_probe(struct i2c_client *i2c,
 		goto assert_reset;
 	}
 
-	yas5xx_dump_calibration(yas5xx);
-	ret = yas5xx_power_on(yas5xx);
+	yas530_dump_calibration(yas5xx);
+	ret = yas530_power_on(yas5xx);
 	if (ret)
 		goto assert_reset;
-	ret = yas5xx_meaure_offsets(yas5xx);
+	ret = yas530_measure_offsets(yas5xx);
 	if (ret)
 		goto assert_reset;
 
Signature · 1 line
2.35.1
#8 lore raw

Re: [PATCH v4 06/10] iio: magnetometer: yas530: Rename functions and registers

Quoted 12 lines · Jakob Hauser

This is a preparation for adding YAS537 variant.

Functions that are used only by YAS530, YAS532 and YAS533 are renamed from yas5xx to yas530. Same for the registers.

To avoid part listing in function and registers names, the name of the first variant is used. Where appropriate, comments were added that these functions are used by more than one variant.

Functions that will be used by all variants including YAS537 remain in the naming scheme yas5xx. Or YAS5XX for registers, respectively.

...

drivers/iio/magnetometer/yamaha-yas530.c static u16 yas532_extract_axis(u8 *data) · line 195

Quoted 12 lines

/**
- * yas5xx_measure() - Make a measure from the hardware
+ * yas530_measure() - Make a measure from the hardware
* @yas5xx: The device state
* @t: the raw temperature measurement
* @x: the raw x axis measurement

drivers/iio/magnetometer/yamaha-yas530.c +1 -1
@@ -190,7 +192,8 @@ static u16 yas532_extract_axis(u8 *data)
  * @y2: the y2 axis measurement
  * @return: 0 on success or error code
  */
-static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
+/* Used by YAS530, YAS532 and YAS533 */

Why a separate comment and not embedded into the kernel doc above?

Quoted 1 line
drivers/iio/magnetometer/yamaha-yas530.c +1 -0
+static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)

...

drivers/iio/magnetometer/yamaha-yas530.c static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis) · line 321

Quoted 12 lines

/**
- * yas5xx_get_measure() - Measure a sample of all axis and process
+ * yas530_get_measure() - Measure a sample of all axis and process
* @yas5xx: The device state
* @to: Temperature out
* @xo: X axis out

drivers/iio/magnetometer/yamaha-yas530.c +1 -1
@@ -314,7 +318,8 @@ static s32 yas5xx_linearize(struct yas5xx *yas5xx, u16 val, int axis)
  * @zo: Z axis out
  * @return: 0 on success or error code
  */
-static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)
+/* Used by YAS530, YAS532 and YAS533 */

Ditto.

Quoted 1 line
drivers/iio/magnetometer/yamaha-yas530.c +1 -0
+static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo)

...

drivers/iio/magnetometer/yamaha-yas530.c static const struct regmap_config yas5xx_regmap_config = { · line 617

Quoted 8 lines

/**
- * yas53x_extract_calibration() - extracts the a2-a9 and k calibration
+ * yas530_extract_calibration() - extracts the a2-a9 and k calibration
* @data: the bitfield to use
* @c: the calibration to populate
*/

drivers/iio/magnetometer/yamaha-yas530.c +1 -1
-static void yas53x_extract_calibration(u8 *data, struct yas5xx_calibration *c)
+/* Used by YAS530, YAS532 and YAS533 */

Ditto.

Quoted 1 line

+static void yas530_extract_calibration(u8 *data, struct yas5xx_calibration *c)

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#9 lore raw

Re: [PATCH v4 06/10] iio: magnetometer: yas530: Rename functions and registers

Hi Andy,

Quoted 2 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

...

Quoted 6 lines
Quoted 6 lines

/**
- * yas5xx_measure() - Make a measure from the hardware
+ * yas530_measure() - Make a measure from the hardware
* @yas5xx: The device state
* @t: the raw temperature measurement
* @x: the raw x axis measurement

Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c static u16 yas532_extract_axis(u8 *data) · line 195

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
@@ -190,7 +192,8 @@ static u16 yas532_extract_axis(u8 *data)
  * @y2: the y2 axis measurement
  * @return: 0 on success or error code
  */
-static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2)
+/* Used by YAS530, YAS532 and YAS533 */

Why a separate comment and not embedded into the kernel doc above?

I thought of it as an internal comment or hint. I'm not familiar with kernel doc and didn't dare to add it there.

I'll move it to the bottom of the kernel doc part.

Kind regards,
Jakob

#10 lore raw

PATCH v4 7/10 iio: magnetometer: yas530: Move printk %*ph parameters out from stack

In reply to Jakob Hauser

Use less stack by modifying %*ph parameters.

Additionally, in the function yas530_get_calibration_data(), the debug dump was extended to 16 elements as this is the size of the calibration data array of YAS530.

---
 drivers/iio/magnetometer/yamaha-yas530.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +2 -2
index c250909df8f4..8358d4b3d1e2 100644
@@ -661,7 +661,7 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
-	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
+	dev_dbg(yas5xx->dev, "calibration data: %16ph\n", data);
 
 	add_device_randomness(data, sizeof(data));
 	yas5xx->version = data[15] & GENMASK(1, 0);
@@ -708,7 +708,7 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	ret = regmap_bulk_read(yas5xx->map, YAS530_CAL, data, sizeof(data));
 	if (ret)
 		return ret;
-	dev_dbg(yas5xx->dev, "calibration data: %*ph\n", 14, data);
+	dev_dbg(yas5xx->dev, "calibration data: %14ph\n", data);
 
 	/* Sanity check, is this all zeroes? */
 	if (memchr_inv(data, 0x00, 13) == NULL) {
Signature · 1 line
2.35.1
#11 lore raw

Re: [PATCH v4 07/10] iio: magnetometer: yas530: Move printk %*ph parameters out from stack

Quoted 6 lines · Jakob Hauser

Use less stack by modifying %*ph parameters.

Additionally, in the function yas530_get_calibration_data(), the debug dump was extended to 16 elements as this is the size of the calibration data array of YAS530.

Suggested-by?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#12 lore raw

PATCH v4 8/10 iio: magnetometer: yas530: Apply documentation and style fixes

In reply to Jakob Hauser

This commit gathers several minor changes.

In the device examples, "Xiaomi" is too generic, specific devices should be listed here. E.g. Xiaomi Redmi 2 seems to have YAS537 but it's not fully clear if this applies to all its variants. Samsung Galaxy S7 is often quoted in conjunction with YAS537.

Removed defines for device IDs of YAS537 and YAS539, they are not needed so far.

---
 drivers/iio/magnetometer/yamaha-yas530.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +11 -10
index 8358d4b3d1e2..4e2f460a4efd 100644
@@ -10,7 +10,7 @@
  * (YAS534 is a magnetic switch, not handled)
  * YAS535 MS-6C
  * YAS536 MS-3W
- * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Xiaomi)
+ * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Galaxy S7)
  * YAS539 MS-3S (2018 Samsung Galaxy A7 SM-A750FN)
  *
  * Code functions found in the MPU3050 YAS530 and YAS532 drivers
@@ -93,10 +93,6 @@
 #define YAS532_DATA_OVERFLOW		(BIT(YAS532_DATA_BITS) - 1)
 #define YAS532_20DEGREES		390 /* Counts starting at -50 °C */
 
-/* These variant IDs are known from code dumps */
-#define YAS537_DEVICE_ID		0x07 /* YAS537 (MS-3T) */
-#define YAS539_DEVICE_ID		0x08 /* YAS539 (MS-3S) */
-
 /* Turn off device regulators etc after 5 seconds of inactivity */
 #define YAS5XX_AUTOSUSPEND_DELAY_MS	5000
 
@@ -323,7 +319,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 {
 	struct yas5xx_calibration *c = &yas5xx->calibration;
 	u16 t_ref, t, x, y1, y2;
-	/* These are "signed x, signed y1 etc */
+	/* These are signed x, signed y1 etc */
 	s32 sx, sy1, sy2, sy, sz;
 	int ret;
 
@@ -663,7 +659,10 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 		return ret;
 	dev_dbg(yas5xx->dev, "calibration data: %16ph\n", data);
 
+	/* Contribute calibration data to the input pool for kernel entropy */
 	add_device_randomness(data, sizeof(data));
+
+	/* Extract version */
 	yas5xx->version = data[15] & GENMASK(1, 0);
 
 	/* Extract the calibration from the bitfield */
@@ -690,6 +689,7 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 	c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
 	c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
 	c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
+
 	return 0;
 }
 
@@ -711,12 +711,12 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	dev_dbg(yas5xx->dev, "calibration data: %14ph\n", data);
 
 	/* Sanity check, is this all zeroes? */
-	if (memchr_inv(data, 0x00, 13) == NULL) {
-		if (!(data[13] & BIT(7)))
-			dev_warn(yas5xx->dev, "calibration is blank!\n");
-	}
+	if (!memchr_inv(data, 0x00, 13) && !(data[13] & BIT(7)))
+		dev_warn(yas5xx->dev, "calibration is blank!\n");
 
+	/* Contribute calibration data to the input pool for kernel entropy */
 	add_device_randomness(data, sizeof(data));
+
 	/* Only one bit of version info reserved here as far as we know */
 	yas5xx->version = data[13] & BIT(0);
 
@@ -725,6 +725,7 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	c->Cy1 = data[1] * 10 - 1280;
 	c->Cy2 = data[2] * 10 - 1280;
 	yas530_extract_calibration(&data[3], c);
+
 	/*
 	 * Extract linearization:
 	 * Linearization layout in the 32 bits at byte 10:
Signature · 1 line
2.35.1
Reviewed-by on v4 8/10
#13 lore raw

Re: [PATCH v4 08/10] iio: magnetometer: yas530: Apply documentation and style fixes

Quoted 9 lines · Jakob Hauser

This commit gathers several minor changes.

In the device examples, "Xiaomi" is too generic, specific devices should be listed here. E.g. Xiaomi Redmi 2 seems to have YAS537 but it's not fully clear if this applies to all its variants. Samsung Galaxy S7 is often quoted in conjunction with YAS537.

Removed defines for device IDs of YAS537 and YAS539, they are not needed so far.

Quoted 85 lines
---
 drivers/iio/magnetometer/yamaha-yas530.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +11 -11
index 8358d4b3d1e2..4e2f460a4efd 100644
@@ -10,7 +10,7 @@
  * (YAS534 is a magnetic switch, not handled)
  * YAS535 MS-6C
  * YAS536 MS-3W
- * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Xiaomi)
+ * YAS537 MS-3T (2015 Samsung Galaxy S6, Note 5, Galaxy S7)
  * YAS539 MS-3S (2018 Samsung Galaxy A7 SM-A750FN)
  *
  * Code functions found in the MPU3050 YAS530 and YAS532 drivers
@@ -93,10 +93,6 @@
 #define YAS532_DATA_OVERFLOW           (BIT(YAS532_DATA_BITS) - 1)
 #define YAS532_20DEGREES               390 /* Counts starting at -50 °C */
 
-/* These variant IDs are known from code dumps */
-#define YAS537_DEVICE_ID               0x07 /* YAS537 (MS-3T) */
-#define YAS539_DEVICE_ID               0x08 /* YAS539 (MS-3S) */
-
 /* Turn off device regulators etc after 5 seconds of inactivity */
 #define YAS5XX_AUTOSUSPEND_DELAY_MS    5000
 
@@ -323,7 +319,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo,
 {
        struct yas5xx_calibration *c = &yas5xx->calibration;
        u16 t_ref, t, x, y1, y2;
-       /* These are "signed x, signed y1 etc */
+       /* These are signed x, signed y1 etc */
        s32 sx, sy1, sy2, sy, sz;
        int ret;
 
@@ -663,7 +659,10 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
                return ret;
        dev_dbg(yas5xx->dev, "calibration data: %16ph\n", data);
 
+       /* Contribute calibration data to the input pool for kernel entropy */
        add_device_randomness(data, sizeof(data));
+
+       /* Extract version */
        yas5xx->version = data[15] & GENMASK(1, 0);
 
        /* Extract the calibration from the bitfield */
@@ -690,6 +689,7 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
        c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
        c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
        c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
+
        return 0;
 }
 
@@ -711,12 +711,12 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
        dev_dbg(yas5xx->dev, "calibration data: %14ph\n", data);
 
        /* Sanity check, is this all zeroes? */
-       if (memchr_inv(data, 0x00, 13) == NULL) {
-               if (!(data[13] & BIT(7)))
-                       dev_warn(yas5xx->dev, "calibration is blank!\n");
-       }
+       if (!memchr_inv(data, 0x00, 13) && !(data[13] & BIT(7)))
+               dev_warn(yas5xx->dev, "calibration is blank!\n");
 
+       /* Contribute calibration data to the input pool for kernel entropy */
        add_device_randomness(data, sizeof(data));
+
        /* Only one bit of version info reserved here as far as we know */
        yas5xx->version = data[13] & BIT(0);
 
@@ -725,6 +725,7 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
        c->Cy1 = data[1] * 10 - 1280;
        c->Cy2 = data[2] * 10 - 1280;
        yas530_extract_calibration(&data[3], c);
+
        /*
         * Extract linearization:
         * Linearization layout in the 32 bits at byte 10:
--

2.35.1

Signature · 2 lines
With Best Regards,
Andy Shevchenko
Reviewed-by on v4 8/10
#14 lore raw

Re: [PATCH v4 08/10] iio: magnetometer: yas530: Apply documentation and style fixes

In reply to Jakob Hauser
Quoted 10 lines · Jakob Hauser

This commit gathers several minor changes.

In the device examples, "Xiaomi" is too generic, specific devices should be listed here. E.g. Xiaomi Redmi 2 seems to have YAS537 but it's not fully clear if this applies to all its variants. Samsung Galaxy S7 is often quoted in conjunction with YAS537.

Removed defines for device IDs of YAS537 and YAS539, they are not needed so far.

Yours,
Linus Walleij

#15 lore raw

PATCH v4 9/10 iio: magnetometer: yas530: Introduce "chip_info" structure

In reply to Jakob Hauser

This commit introduces the "chip_info" structure approach for better variant handling.

The variant to be used is now chosen by the devicetree (enum "chip_ids"), not by the chip ID in the register. However, there is a check to make sure they match (using integer "id_check").

---
Result of the patch can be seen at:
https://github.com/Jakko3/linux/blob/28a2a9ec27c6fb4073149b897415475a8f04e3f7/drivers/iio/magnetometer/yamaha-yas530.c

 drivers/iio/magnetometer/yamaha-yas530.c | 314 +++++++++++++----------
 1 file changed, 182 insertions(+), 132 deletions(-)
drivers/iio/magnetometer/yamaha-yas530.c +182 -132
index 4e2f460a4efd..ce9c1077c121 100644
@@ -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,11 +90,39 @@
 #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
 
+enum chip_ids {
+	yas530,
+	yas532,
+	yas533,
+};
+
+static const char yas5xx_product_name[][13] = {
+	"YAS530 MS-3E",
+	"YAS532 MS-3R",
+	"YAS533 MS-3F"
+};
+
+static const char yas5xx_version_name[][2][3] = {
+	{ "A", "B" },
+	{ "AB", "AC" },
+	{ "AB", "AC" }
+};
+
+static const int yas530_volatile_reg[] = {
+	YAS530_ACTUATE_INIT_COIL,
+	YAS530_MEASURE
+};
+
+/* Number of counts between minimum and reference temperature */
+const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/* Starting point of temperature counting in 1/10:s degrees Celsius */
+const s16 min_temp_celcius_x10[] = { -620, -500, -500 };
+
 struct yas5xx_calibration {
 	/* Linearization calibration x, y1, y2 */
 	s32 r[3];
@@ -110,12 +137,38 @@ struct yas5xx_calibration {
 	u8 dck;
 };
 
+struct yas5xx;
+
+/**
+ * struct yas5xx_chip_info - device-specific data and function pointers
+ * @devid: device ID number
+ * @volatile_reg: device-specific volatile registers
+ * @volatile_reg_qty: quantity of device-specific volatile registers
+ * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE
+ * @get_measure: function pointer to get a measurement
+ * @get_calibration_data: function pointer to get calibration data
+ * @dump_calibration: function pointer to dump calibration for debugging
+ * @measure_offsets: function pointer to measure the offsets
+ * @power_on: function pointer to power-on procedure
+ */
+struct yas5xx_chip_info {
+	unsigned int devid;
+	const int *volatile_reg;
+	const int volatile_reg_qty;
+	const u32 scaling_val2;
+	int (*get_measure)(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo);
+	int (*get_calibration_data)(struct yas5xx *yas5xx);
+	void (*dump_calibration)(struct yas5xx *yas5xx);
+	int (*measure_offsets)(struct yas5xx *yas5xx);
+	int (*power_on)(struct yas5xx *yas5xx);
+};
+
 /**
  * struct yas5xx - state container for the YAS5xx driver
  * @dev: parent device pointer
- * @devid: device ID number
+ * @chip: enumeration of the device variant
+ * @chip_info: device-specific data and function pointers
  * @version: device version
- * @name: device name
  * @calibration: calibration settings from the OTP storage
  * @hard_offsets: offsets for each axis measured with initcoil actuated
  * @orientation: mounting matrix, flipped axis etc
@@ -129,9 +182,9 @@ struct yas5xx_calibration {
  */
 struct yas5xx {
 	struct device *dev;
-	unsigned int devid;
+	enum chip_ids chip;
+	struct yas5xx_chip_info *chip_info;
 	unsigned int version;
-	char name[16];
 	struct yas5xx_calibration calibration;
 	s8 hard_offsets[3];
 	struct iio_mount_matrix orientation;
@@ -221,7 +274,7 @@ static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
 
 	mutex_unlock(&yas5xx->lock);
 
-	switch (yas5xx->devid) {
+	switch (yas5xx->chip_info->devid) {
 	case YAS530_DEVICE_ID:
 		/*
 		 * The t value is 9 bits in big endian format
@@ -275,7 +328,7 @@ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis)
 	s32 coef;
 
 	/* Select coefficients */
-	switch (yas5xx->devid) {
+	switch (yas5xx->chip_info->devid) {
 	case YAS530_DEVICE_ID:
 		if (yas5xx->version == YAS530_VERSION_A)
 			coef = YAS530_VERSION_A_COEF;
@@ -305,6 +358,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 = t_ref_counts[yas5xx->chip];
+	min_temp_x10 = min_temp_celcius_x10[yas5xx->chip];
+	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
@@ -318,7 +385,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;
@@ -333,47 +400,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->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 */
-	if (yas5xx->devid == YAS532_DEVICE_ID &&
+	/*
+	 * 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 = t_ref_counts[yas5xx->chip];
+	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.
@@ -381,36 +431,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->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:
@@ -447,7 +469,7 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_PROCESSED:
 	case IIO_CHAN_INFO_RAW:
 		pm_runtime_get_sync(yas5xx->dev);
-		ret = yas5xx_get_measure(yas5xx, &t, &x, &y, &z);
+		ret = yas5xx->chip_info->get_measure(yas5xx, &t, &x, &y, &z);
 		pm_runtime_mark_last_busy(yas5xx->dev);
 		pm_runtime_put_autosuspend(yas5xx->dev);
 		if (ret)
@@ -471,27 +493,8 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev,
 		}
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		switch (yas5xx->devid) {
-		case YAS530_DEVICE_ID:
-			/*
-			 * Raw values of YAS530 are in picotesla. Divide by
-			 * 100000000 (10^8) to get Gauss.
-			 */
-			*val = 1;
-			*val2 = 100000000;
-			break;
-		case YAS532_DEVICE_ID:
-			/*
-			 * Raw values of YAS532 are in nanotesla. Divide by
-			 * 100000 (10^5) to get Gauss.
-			 */
-			*val = 1;
-			*val2 = 100000;
-			break;
-		default:
-			dev_err(yas5xx->dev, "unknown device type\n");
-			return -EINVAL;
-		}
+		*val = 1;
+		*val2 = yas5xx->chip_info->scaling_val2;
 		return IIO_VAL_FRACTIONAL;
 	default:
 		/* Unknown request */
@@ -506,7 +509,7 @@ static void yas5xx_fill_buffer(struct iio_dev *indio_dev)
 	int ret;
 
 	pm_runtime_get_sync(yas5xx->dev);
-	ret = yas5xx_get_measure(yas5xx, &t, &x, &y, &z);
+	ret = yas5xx->chip_info->get_measure(yas5xx, &t, &x, &y, &z);
 	pm_runtime_mark_last_busy(yas5xx->dev);
 	pm_runtime_put_autosuspend(yas5xx->dev);
 	if (ret) {
@@ -592,9 +595,24 @@ static const struct iio_info yas5xx_info = {
 
 static bool yas5xx_volatile_reg(struct device *dev, unsigned int reg)
 {
-	return reg == YAS5XX_ACTUATE_INIT_COIL ||
-		reg == YAS5XX_MEASURE ||
-		(reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct yas5xx *yas5xx = iio_priv(indio_dev);
+	int i, j;
+
+	if (reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8)
+		return true;
+
+	/*
+	 * YAS versions share different registers on the same address,
+	 * need to differentiate.
+	 */
+	j = yas5xx->chip_info->volatile_reg_qty;
+	for (i = 0; i < j; i++) {
+		if (reg == yas5xx->chip_info->volatile_reg[i])
+			return true;
+	}
+
+	return false;
 }
 
 /* TODO: enable regmap cache, using mark dirty and sync at runtime resume */
@@ -811,7 +829,7 @@ static int yas530_measure_offsets(struct yas5xx *yas5xx)
 		return ret;
 
 	/* When the initcoil is active this should be around the center */
-	switch (yas5xx->devid) {
+	switch (yas5xx->chip_info->devid) {
 	case YAS530_DEVICE_ID:
 		center = YAS530_DATA_CENTER;
 		break;
@@ -892,13 +910,49 @@ static int yas530_power_on(struct yas5xx *yas5xx)
 	return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0);
 }
 
+static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
+	[yas530] = {
+		.devid = YAS530_DEVICE_ID,
+		.volatile_reg = yas530_volatile_reg,
+		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+		.scaling_val2 = 100000000, /* picotesla to Gauss */
+		.get_measure = yas530_get_measure,
+		.get_calibration_data = yas530_get_calibration_data,
+		.dump_calibration = yas530_dump_calibration,
+		.measure_offsets = yas530_measure_offsets,
+		.power_on = yas530_power_on,
+	},
+	[yas532] = {
+		.devid = YAS532_DEVICE_ID,
+		.volatile_reg = yas530_volatile_reg,
+		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+		.scaling_val2 = 100000, /* nanotesla to Gauss */
+		.get_measure = yas530_get_measure,
+		.get_calibration_data = yas532_get_calibration_data,
+		.dump_calibration = yas530_dump_calibration,
+		.measure_offsets = yas530_measure_offsets,
+		.power_on = yas530_power_on,
+	},
+	[yas533] = {
+		.devid = YAS532_DEVICE_ID,
+		.volatile_reg = yas530_volatile_reg,
+		.volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+		.scaling_val2 = 100000, /* nanotesla to Gauss */
+		.get_measure = yas530_get_measure,
+		.get_calibration_data = yas532_get_calibration_data,
+		.dump_calibration = yas530_dump_calibration,
+		.measure_offsets = yas530_measure_offsets,
+		.power_on = yas530_power_on,
+	}
+};
+
 static int yas5xx_probe(struct i2c_client *i2c,
 			const struct i2c_device_id *id)
 {
 	struct iio_dev *indio_dev;
 	struct device *dev = &i2c->dev;
 	struct yas5xx *yas5xx;
-	int ret;
+	int id_check, ret;
 
 	indio_dev = devm_iio_device_alloc(dev, sizeof(*yas5xx));
 	if (!indio_dev)
@@ -944,45 +998,41 @@ static int yas5xx_probe(struct i2c_client *i2c,
 		goto assert_reset;
 	}
 
-	ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &yas5xx->devid);
+	yas5xx->chip = id->driver_data;
+	yas5xx->chip_info = &yas5xx_chip_info_tbl[yas5xx->chip];
+
+	ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
 	if (ret)
 		goto assert_reset;
 
-	switch (yas5xx->devid) {
-	case YAS530_DEVICE_ID:
-		ret = yas530_get_calibration_data(yas5xx);
-		if (ret)
-			goto assert_reset;
-		dev_info(dev, "detected YAS530 MS-3E %s",
-			 yas5xx->version ? "B" : "A");
-		strncpy(yas5xx->name, "yas530", sizeof(yas5xx->name));
-		break;
-	case YAS532_DEVICE_ID:
-		ret = yas532_get_calibration_data(yas5xx);
-		if (ret)
-			goto assert_reset;
-		dev_info(dev, "detected YAS532/YAS533 MS-3R/F %s",
-			 yas5xx->version ? "AC" : "AB");
-		strncpy(yas5xx->name, "yas532", sizeof(yas5xx->name));
-		break;
-	default:
+	if (id_check != yas5xx->chip_info->devid) {
 		ret = -ENODEV;
-		dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
+		dev_err(dev, "device ID %02x doesn't match %s\n",
+			id_check, id->name);
 		goto assert_reset;
 	}
 
-	yas530_dump_calibration(yas5xx);
-	ret = yas530_power_on(yas5xx);
+	ret = yas5xx->chip_info->get_calibration_data(yas5xx);
 	if (ret)
 		goto assert_reset;
-	ret = yas530_measure_offsets(yas5xx);
+
+	dev_info(dev, "detected %s %s\n", yas5xx_product_name[yas5xx->chip],
+		 yas5xx_version_name[yas5xx->chip][yas5xx->version]);
+
+	yas5xx->chip_info->dump_calibration(yas5xx);
+
+	ret = yas5xx->chip_info->power_on(yas5xx);
+	if (ret)
+		goto assert_reset;
+
+	ret = yas5xx->chip_info->measure_offsets(yas5xx);
 	if (ret)
 		goto assert_reset;
 
 	indio_dev->info = &yas5xx_info;
 	indio_dev->available_scan_masks = yas5xx_scan_masks;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = yas5xx->name;
+	indio_dev->name = id->name;
 	indio_dev->channels = yas5xx_channels;
 	indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels);
 
@@ -1074,7 +1124,7 @@ static int __maybe_unused yas5xx_runtime_resume(struct device *dev)
 	usleep_range(31000, 40000);
 	gpiod_set_value_cansleep(yas5xx->reset, 0);
 
-	ret = yas5xx_power_on(yas5xx);
+	ret = yas5xx->chip_info->power_on(yas5xx);
 	if (ret) {
 		dev_err(dev, "cannot power on\n");
 		goto out_reset;
@@ -1097,9 +1147,9 @@ static const struct dev_pm_ops yas5xx_dev_pm_ops = {
 };
 
 static const struct i2c_device_id yas5xx_id[] = {
-	{"yas530", },
-	{"yas532", },
-	{"yas533", },
+	{"yas530", yas530 },
+	{"yas532", yas532 },
+	{"yas533", yas533 },
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, yas5xx_id);
Signature · 1 line
2.35.1
#16 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Quoted 5 lines · Jakob Hauser

This commit introduces the "chip_info" structure approach for better variant handling.

The variant to be used is now chosen by the devicetree (enum "chip_ids"),

Device Tree

Quoted 2 lines

not by the chip ID in the register. However, there is a check to make sure they match (using integer "id_check").

...

Thanks for a new version, it's getting better. My comments below.

But first of all, can you split this to at least two patches, i.e.
1) split out functions without introducing chip->info yet;
2) adding chip_info.

Possible alternative would be more steps in 2), i.e. introducing chip_info for the callback only, then add field (or semantically unified fields) by field with corresponding changes in the code. In this case it would be easier to review.

I leave this exercise to you if Jonathan thinks it worth it.

...

drivers/iio/magnetometer/yamaha-yas530.c

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +0 -2
-#define YAS530_20DEGREES               182 /* Counts starting at -62 °C */
 
-#define YAS532_20DEGREES               390 /* Counts starting at -50 °C */

The comments suddenly disappear from the file. See below.

...

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+enum chip_ids {
+       yas530,
+       yas532,
+       yas533,
+};
+

drivers/iio/magnetometer/yamaha-yas530.c line 112

Quoted 10 lines
drivers/iio/magnetometer/yamaha-yas530.c +10 -0
+static const char yas5xx_product_name[][13] = {
+       "YAS530 MS-3E",
+       "YAS532 MS-3R",
+       "YAS533 MS-3F"
+};
+
+static const char yas5xx_version_name[][2][3] = {
+       { "A", "B" },
+       { "AB", "AC" },
+       { "AB", "AC" }

Shan't we put indices here?
Also, use * instead of one dimension of array.

Quoted 1 line

+};

...

drivers/iio/magnetometer/yamaha-yas530.c line 117

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -0
+static const int yas530_volatile_reg[] = {
+       YAS530_ACTUATE_INIT_COIL,
+       YAS530_MEASURE

+ Comma.

Quoted 1 line

+};

...

drivers/iio/magnetometer/yamaha-yas530.c line 124

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+/* Number of counts between minimum and reference temperature */
+const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/* Starting point of temperature counting in 1/10:s degrees Celsius */
+const s16 min_temp_celcius_x10[] = { -620, -500, -500 };

See above.

...

drivers/iio/magnetometer/yamaha-yas530.c struct yas5xx_calibration { · line 158

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+struct yas5xx_chip_info {
+       unsigned int devid;
 
+       const int *volatile_reg;
+       const int volatile_reg_qty;
+       const u32 scaling_val2;

Why const here?
I assume entire structure is const, no?

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+       int (*get_measure)(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo);
+       int (*get_calibration_data)(struct yas5xx *yas5xx);
+       void (*dump_calibration)(struct yas5xx *yas5xx);
+       int (*measure_offsets)(struct yas5xx *yas5xx);
+       int (*power_on)(struct yas5xx *yas5xx);
+};

...

Quoted 1 line

+ int i, j;

j can have a proper name.

Quoted 1 line

+ j = yas5xx->chip_info->volatile_reg_qty;

...

Quoted 24 lines
drivers/iio/magnetometer/yamaha-yas530.c +24 -0
+static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
+       [yas530] = {
+               .devid = YAS530_DEVICE_ID,
+               .volatile_reg = yas530_volatile_reg,
+               .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+               .scaling_val2 = 100000000, /* picotesla to Gauss */
+               .get_measure = yas530_get_measure,
+               .get_calibration_data = yas530_get_calibration_data,
+               .dump_calibration = yas530_dump_calibration,
+               .measure_offsets = yas530_measure_offsets,
+               .power_on = yas530_power_on,
+       },
+       [yas532] = {
+               .devid = YAS532_DEVICE_ID,
+               .volatile_reg = yas530_volatile_reg,
+               .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+               .scaling_val2 = 100000, /* nanotesla to Gauss */
+               .get_measure = yas530_get_measure,
+               .get_calibration_data = yas532_get_calibration_data,
+               .dump_calibration = yas530_dump_calibration,
+               .measure_offsets = yas530_measure_offsets,
+               .power_on = yas530_power_on,
+       },
+       [yas533] = {

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 946

Quoted 10 lines
drivers/iio/magnetometer/yamaha-yas530.c +10 -0
+               .devid = YAS532_DEVICE_ID,
+               .volatile_reg = yas530_volatile_reg,
+               .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg),
+               .scaling_val2 = 100000, /* nanotesla to Gauss */
+               .get_measure = yas530_get_measure,
+               .get_calibration_data = yas532_get_calibration_data,
+               .dump_calibration = yas530_dump_calibration,
+               .measure_offsets = yas530_measure_offsets,
+               .power_on = yas530_power_on,
+       }

Keep comma here.

Quoted 1 line

+};

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 955

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
-       int ret;
+       int id_check, ret;

Don't add variables with different semantics on the same line.

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1011

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -1
+       if (id_check != yas5xx->chip_info->devid) {
                ret = -ENODEV;
-               dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
+               dev_err(dev, "device ID %02x doesn't match %s\n",
+                       id_check, id->name);

ret = dev_err_probe() ?

Quoted 2 lines
                goto assert_reset;
        }

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1020

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       dev_info(dev, "detected %s %s\n", yas5xx_product_name[yas5xx->chip],
+                yas5xx_version_name[yas5xx->chip][yas5xx->version]);

I'm wondering if these arrays can be actually embedded into chip_info?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
maintainer
#17 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Quoted 20 lines · On Mon, 4 Jul 2022 21:37:30 +0200 Andy Shevchenko <[email protected]>…
Quoted 5 lines · Jakob Hauser

This commit introduces the "chip_info" structure approach for better variant handling.

The variant to be used is now chosen by the devicetree (enum "chip_ids"),

Device Tree

Quoted 2 lines

not by the chip ID in the register. However, there is a check to make sure they match (using integer "id_check").

...

Thanks for a new version, it's getting better. My comments below.

But first of all, can you split this to at least two patches, i.e.
1) split out functions without introducing chip->info yet;
2) adding chip_info.

Quoted 6 lines

Possible alternative would be more steps in 2), i.e. introducing chip_info for the callback only, then add field (or semantically unified fields) by field with corresponding changes in the code. In this case it would be easier to review.

I leave this exercise to you if Jonathan thinks it worth it.

You are of course correct that it would be nicer to have it split, but I'm not going to be fussy about it this time ;)

Other than addressing Andy's eagle eyed review comments, this series looks good to me.

Thanks,

Jonathan

#18 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

In reply to Andy Shevchenko

Hi Andy,

Quoted 2 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

...

Quoted 5 lines

Thanks for a new version, it's getting better. My comments below.

But first of all, can you split this to at least two patches, i.e.
1) split out functions without introducing chip->info yet;
2) adding chip_info.

The only function that's split out newly is yas5xx_calc_temperature(). However, it uses "yas5xx->chip" to look up the right values in the array for "t_ref" and "min_temp_x10". So it cannot be easily split from the introduction to the chip_info approach.

Quoted 4 lines

Possible alternative would be more steps in 2), i.e. introducing chip_info for the callback only, then add field (or semantically unified fields) by field with corresponding changes in the code. In this case it would be easier to review.

What do you mean by "introducing chip_info for the callback only"? I guess you mean the function pointers?

According to this, the patch could be split into:
1) introduce function pointers
2) introduce arrays to look up values

However, what's missing there is the introduction of the chip_info approach as such. Admittedly difficult to follow are the changes in yas5xx_probe():
- yas5xx->devid gets removed, it was the main switch decider before
- (for usage on other switches it is moved to yas5xx->chip_info->devid)
- yas5xx->chip as an enumeration is newly introduced
- yas5xx->chip_info as a structure gets initiated
- As the chip_info now chooses according to the i2c_device_id (via enum chip_ids, thus yas5xx->chip), a new check is introduced to make sure it matches the device ID read from the register. This is done by "if (id_check != yas5xx->chip_info->devid)".
- The way of reporting product name and version name was changed because introducing chip_info required to do this in one place for all versions.
- As a consequence of this, yas5xx->name became obsolete.

This would have to be done before introducing function pointers and arrays, like:
1) introduce chip_info structural changes
2) add function pointers
3) add arrays to look up values

But it can't be easily split that way. I can't establish an "empty" chip_info approach as a fist step without removing or changing many other things. The structural changes are related to other changes in that patch.

I'm thinking about first introducing chip_info and thereafter establishing the function pointers. In between I could try to split out the new temperature function:
1) introduce chip_info structural changes incl. arrays to look up values
2) split out new yas5xx_calc_temperature() function
3) add function pointers

I'm not yet sure it can be split that way because things are entangled. But I will try to this in v5.

Btw, looking through this, I realized that in patch 6 "Rename functions and registers" I unfortunately missed to rename instances of "yas5xx_get_measure", "yas5xx_power_on", "YAS5XX_ACTUATE_INIT_COIL" and "YAS5XX_MEASURE". I'll correct this in v5.

...

Quoted 5 lines

drivers/iio/magnetometer/yamaha-yas530.c

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +0 -2
-#define YAS530_20DEGREES               182 /* Counts starting at -62 °C */
 
-#define YAS532_20DEGREES               390 /* Counts starting at -50 °C */

The comments suddenly disappear from the file. See below.

The comment's didn't actually disappear but rather got restructured by introducing new chip_info approach. See below.

Quoted 10 lines
Quoted 10 lines
drivers/iio/magnetometer/yamaha-yas530.c +10 -0
+enum chip_ids {
+       yas530,
+       yas532,
+       yas533,
+};
+
+static const char yas5xx_product_name[][13] = {
+       "YAS530 MS-3E",
+       "YAS532 MS-3R",
+       "YAS533 MS-3F"
Quoted 8 lines

drivers/iio/magnetometer/yamaha-yas530.c line 112

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+};
+
+static const char yas5xx_version_name[][2][3] = {
+       { "A", "B" },
+       { "AB", "AC" },
+       { "AB", "AC" }

Shan't we put indices here?

Do you mean:

        static const char yas5xx_version_name[][2][3] = {
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };

I can add this.

Quoted 1 line

Also, use * instead of one dimension of array.

Sorry, probably I lack the basic knowledge here. Can you explain how to do that?

...

Quoted 5 lines

drivers/iio/magnetometer/yamaha-yas530.c line 117

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -0
+static const int yas530_volatile_reg[] = {
+       YAS530_ACTUATE_INIT_COIL,
+       YAS530_MEASURE

+ Comma.

OK, I didn't know this is allowed. I'll add it here and at the other locations.

Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c line 124

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+/* Number of counts between minimum and reference temperature */
+const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/* Starting point of temperature counting in 1/10:s degrees Celsius */
+const s16 min_temp_celcius_x10[] = { -620, -500, -500 };

See above.

The former comments...

    182 /* Counts starting at -62 °C */
    390 /* Counts starting at -50 °C */

... and the two new comments above the arrays actually should say the same thing. At least that was my intention.

The first value is a number of counts. And the counting starts at a certain temperature, which is the second value. Both the old and the new comments are intended to describe this.

In the introduction of this temperature handling (patch 4), there is a lot more description on these values in function yas5xx_get_measure(). When creating the new "chip_info" patch 9, I was thinking about moving some of that description up here to these arrays. However, instead I tried to following Jonathan's suggestion in v3 to keep the describing text low and rather let the formulas speak for themselves. These values are applied at a formula in function yas5xx_calc_temperature() which is supposed to by kind of self explanatory.

What may lead to confusion is the equivalent usage of "starting" and "minimum" here. In the initial patchset I used "starting" related to the counts, Jonathan suggested "minimum" or actually "min_temp" related to the temperature. The comments here above are bit of a mixture of both. I still think it's good enough to understand. The sentence "Starting point of temperature ..." describes the value min_temp_celcius_x10. Using a term like "starting temperature" would probably be more confusing.

Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c struct yas5xx_calibration { · line 158

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+struct yas5xx_chip_info {
+       unsigned int devid;
 
+       const int *volatile_reg;
+       const int volatile_reg_qty;
+       const u32 scaling_val2;

Why const here?
I assume entire structure is const, no?

I'm rather new to C language, not having a good grasp of "const" in structures yet. I would have guessed it doesn't work well with the function pointers.

However, having some compile tests, there are no complaints about the function pointers.

To change the whole chip_info structure to "const", I would:
- within the "struct yas5xx" change to "const struct yas5xx_chip_info *chip_info;"
- change following typedef to "static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = ..."

Then, within the "struct yas5xx_chip_info", I can remove "const" from:
- int volatile_reg_qty;
- u32 scaling_val2;

However, I have to keep "const" at the following, otherwise the complier complains that "initialization discards 'const' qualifier from pointer target type":
- const int *volatile_reg;

Summarizing, after the changes it would look like the following (snippets):

        struct yas5xx_chip_info {
                unsigned int devid;
                const int *volatile_reg;
                int volatile_reg_qty;
                u32 scaling_val2;
                int (*get_measure)(struct yas5xx *yas5xx, s32 *to,
                                   s32 *xo, s32 *yo, s32 *zo);
                int (*get_calibration_data)(struct yas5xx *yas5xx);
                void (*dump_calibration)(struct yas5xx *yas5xx);
                int (*measure_offsets)(struct yas5xx *yas5xx);
                int (*power_on)(struct yas5xx *yas5xx);
        };

        struct yas5xx {
                struct device *dev;
                enum chip_ids chip;
                const struct yas5xx_chip_info *chip_info;

        	...

        };

        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {

        		...

                },
        };

If that's reasonable, I'll change it that way.

...

Quoted 3 lines
Quoted 1 line

+ int i, j;

j can have a proper name.

Ok, makes sense. I'll probably name it "reg_qty".

Quoted 2 lines
Quoted 1 line

+ j = yas5xx->chip_info->volatile_reg_qty;

...

Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 955

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
-       int ret;
+       int id_check, ret;

Don't add variables with different semantics on the same line.

Ok. I wasn't aware of putting different semantics on different lines, thanks for the hint, makes sense.

Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1011

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -1
+       if (id_check != yas5xx->chip_info->devid) {
                ret = -ENODEV;
-               dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
+               dev_err(dev, "device ID %02x doesn't match %s\n",
+                       id_check, id->name);

ret = dev_err_probe() ?

Makes sense, will change that.

Though I have difficulties to implement this nicely. dev_err_probe() requires an "error value to test". The current "if (id_check != yas5xx->chip_info->devid)" doesn't offer such a value by itself.

Do you think the following would be appropriate, nesting the check within the dev_err_probe()? It doesn't look too good to me.

        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;

If there are no better ideas, I would implement it that way. Additionally adding a comment and putting it into a block with the regmap_read before:

        /*
         * Check if the device ID from the register matches the one set
         * in the Device Tree.
         */
        ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
        if (ret)
                goto assert_reset;
        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;

Hm, I think it's a bit hard to read. Suggestions for improvement are welcome. Otherwise I'd add it that way.

...

Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1020

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       dev_info(dev, "detected %s %s\n", yas5xx_product_name[yas5xx->chip],
+                yas5xx_version_name[yas5xx->chip][yas5xx->version]);

I'm wondering if these arrays can be actually embedded into chip_info?

While the variants (like "YAS530") are listed in the chip_info, the versions (like "A") are not. Yet, including the versions in chip_info would double the amount, making it visually more unclear, with only minor benefit.

The first part of this call, the "product name", applies to the variants. Going the detour via chip_info, the array element to call could just be hard-coded in the chip_info table, like:

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
			...

The second part, the "version name", is currently in the three-dimensional array yas5xx_version_name[]. The first dimension is the variant, this would need to be hard-coded in the chip_info table, similar to the example above. The second dimension is the version, this would need to come from within the yas5xx_probe() the function. I couldn't find a way how to assign one dimension in one place and another dimension in another place.

To include the second part in the chip_info, I would split the three-dimensional array yas5xx_version_name[] into three separate two-dimensional arrays, one per variant. It would look like this (snippets):

        static const char yas530_version_name[][3] = { "A", "B" };

        static const char yas532_version_name[][3] = { "AB", "AC" };

        static const char yas533_version_name[][3] = { "AB", "AC" };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char (*version_name)[3];
        	...

        ...

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas530_version_name,
                        ...

        ...


        dev_info(dev, "detected %s %s\n",
                 yas5xx->chip_info->product_name,
                 yas5xx->chip_info->version_name[yas5xx->version]);

I'm not fully sure this is the best way. Also note that I had to set the size of the second dimension of yas530_version_name to 3.

Do you think I should do it this way to include "product_name" and "version_name" in the chip_info?

If yes, should I probably do a similar thing for the values "t_ref_counts" and "min_temp_celcius_x10"? Here as well, the array elements are directly called in function yas5xx_calc_temperature() without using the chip_info structure.

Also I noticed that I should add "static" to the typedef of arrays "t_ref_counts" and "min_temp_celcius_x10". Darn, and I have to correct the spelling of "celcius" into "celsius" in "min_temp_celcius_x10".

Kind regards,
Jakob

#19 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Mon, Jul 4, 2022 at 12:04 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 7 lines
Quoted 4 lines

Possible alternative would be more steps in 2), i.e. introducing chip_info for the callback only, then add field (or semantically unified fields) by field with corresponding changes in the code. In this case it would be easier to review.

What do you mean by "introducing chip_info for the callback only"? I guess you mean the function pointers?

Yes.

Quoted 38 lines

According to this, the patch could be split into:
1) introduce function pointers
2) introduce arrays to look up values

However, what's missing there is the introduction of the chip_info approach as such. Admittedly difficult to follow are the changes in yas5xx_probe():
- yas5xx->devid gets removed, it was the main switch decider before
- (for usage on other switches it is moved to yas5xx->chip_info->devid)
- yas5xx->chip as an enumeration is newly introduced
- yas5xx->chip_info as a structure gets initiated
- As the chip_info now chooses according to the i2c_device_id (via enum chip_ids, thus yas5xx->chip), a new check is introduced to make sure it matches the device ID read from the register. This is done by "if (id_check != yas5xx->chip_info->devid)".
- The way of reporting product name and version name was changed because introducing chip_info required to do this in one place for all versions.
- As a consequence of this, yas5xx->name became obsolete.

This would have to be done before introducing function pointers and arrays, like:
1) introduce chip_info structural changes
2) add function pointers
3) add arrays to look up values

But it can't be easily split that way. I can't establish an "empty" chip_info approach as a fist step without removing or changing many other things. The structural changes are related to other changes in that patch.

I'm thinking about first introducing chip_info and thereafter establishing the function pointers. In between I could try to split out the new temperature function:
1) introduce chip_info structural changes incl. arrays to look up values
2) split out new yas5xx_calc_temperature() function
3) add function pointers

Quoted 2 lines

I'm not yet sure it can be split that way because things are entangled. But I will try to this in v5.

Yes, my main point is to try to see under different angles on how you can split the series. We have plenty of time.

Quoted 4 lines

Btw, looking through this, I realized that in patch 6 "Rename functions and registers" I unfortunately missed to rename instances of "yas5xx_get_measure", "yas5xx_power_on", "YAS5XX_ACTUATE_INIT_COIL" and "YAS5XX_MEASURE". I'll correct this in v5.

Also my point why smaller changes are better.

...

Quoted 8 lines
Quoted 5 lines

drivers/iio/magnetometer/yamaha-yas530.c

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +0 -2
-#define YAS530_20DEGREES               182 /* Counts starting at -62 °C */
 
-#define YAS532_20DEGREES               390 /* Counts starting at -50 °C */

The comments suddenly disappear from the file. See below.

The comment's didn't actually disappear but rather got restructured by introducing new chip_info approach. See below.

See below.

...

Quoted 9 lines
Quoted 6 lines

drivers/iio/magnetometer/yamaha-yas530.c line 112

Quoted 4 lines
drivers/iio/magnetometer/yamaha-yas530.c +4 -0
+static const char yas5xx_version_name[][2][3] = {
+       { "A", "B" },
+       { "AB", "AC" },
+       { "AB", "AC" }

Shan't we put indices here?

Do you mean:

Quoted 7 lines
        static const char yas5xx_version_name[][2][3] = {
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };

I can add this.

Yes.

Quoted 4 lines
Quoted 1 line

Also, use * instead of one dimension of array.

Sorry, probably I lack the basic knowledge here. Can you explain how to do that?

  static const char *_name[][] = {
  };

?

...

Quoted 28 lines
Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c line 124

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+/* Number of counts between minimum and reference temperature */
+const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/* Starting point of temperature counting in 1/10:s degrees Celsius */
+const s16 min_temp_celcius_x10[] = { -620, -500, -500 };

See above.

The former comments...

    182 /* Counts starting at -62 °C */
    390 /* Counts starting at -50 °C */

... and the two new comments above the arrays actually should say the same thing. At least that was my intention.

The first value is a number of counts. And the counting starts at a certain temperature, which is the second value. Both the old and the new comments are intended to describe this.

In the introduction of this temperature handling (patch 4), there is a lot more description on these values in function yas5xx_get_measure(). When creating the new "chip_info" patch 9, I was thinking about moving some of that description up here to these arrays. However, instead I tried to following Jonathan's suggestion in v3 to keep the describing text low and rather let the formulas speak for themselves. These values are applied at a formula in function yas5xx_calc_temperature() which is supposed to by kind of self explanatory.

Quoted 7 lines

What may lead to confusion is the equivalent usage of "starting" and "minimum" here. In the initial patchset I used "starting" related to the counts, Jonathan suggested "minimum" or actually "min_temp" related to the temperature. The comments here above are bit of a mixture of both. I still think it's good enough to understand. The sentence "Starting point of temperature ..." describes the value min_temp_celcius_x10. Using a term like "starting temperature" would probably be more confusing.

Confusing to me, who doesn't know the specifics of the chip, it is easy to read '-62 °C' vs. "read comment, look into an array, calculate in your brain".

...

Quoted 64 lines
Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c struct yas5xx_calibration { · line 158

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+struct yas5xx_chip_info {
+       unsigned int devid;
 
+       const int *volatile_reg;
+       const int volatile_reg_qty;
+       const u32 scaling_val2;

Why const here?
I assume entire structure is const, no?

I'm rather new to C language, not having a good grasp of "const" in structures yet. I would have guessed it doesn't work well with the function pointers.

However, having some compile tests, there are no complaints about the function pointers.

To change the whole chip_info structure to "const", I would:
- within the "struct yas5xx" change to "const struct yas5xx_chip_info *chip_info;"
- change following typedef to "static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = ..."

Then, within the "struct yas5xx_chip_info", I can remove "const" from:
- int volatile_reg_qty;
- u32 scaling_val2;

However, I have to keep "const" at the following, otherwise the complier complains that "initialization discards 'const' qualifier from pointer target type":
- const int *volatile_reg;

Summarizing, after the changes it would look like the following (snippets):

        struct yas5xx_chip_info {
                unsigned int devid;
                const int *volatile_reg;
                int volatile_reg_qty;
                u32 scaling_val2;
                int (*get_measure)(struct yas5xx *yas5xx, s32 *to,
                                   s32 *xo, s32 *yo, s32 *zo);
                int (*get_calibration_data)(struct yas5xx *yas5xx);
                void (*dump_calibration)(struct yas5xx *yas5xx);
                int (*measure_offsets)(struct yas5xx *yas5xx);
                int (*power_on)(struct yas5xx *yas5xx);
        };

        struct yas5xx {
                struct device *dev;
                enum chip_ids chip;
                const struct yas5xx_chip_info *chip_info;

                ...

        };

        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {

                        ...

                },
        };
Quoted 1 line

If that's reasonable, I'll change it that way.

Yes, chip_info should be immutable, right? Otherwise it's something we may not rely on.

Quoted 40 lines
Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1011

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -1
+       if (id_check != yas5xx->chip_info->devid) {
                ret = -ENODEV;
-               dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
+               dev_err(dev, "device ID %02x doesn't match %s\n",
+                       id_check, id->name);

ret = dev_err_probe() ?

Makes sense, will change that.

Though I have difficulties to implement this nicely. dev_err_probe() requires an "error value to test". The current "if (id_check != yas5xx->chip_info->devid)" doesn't offer such a value by itself.

Do you think the following would be appropriate, nesting the check within the dev_err_probe()? It doesn't look too good to me.

        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;

If there are no better ideas, I would implement it that way. Additionally adding a comment and putting it into a block with the regmap_read before:

        /*
         * Check if the device ID from the register matches the one set
         * in the Device Tree.
         */
        ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
        if (ret)
                goto assert_reset;
        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;
Quoted 2 lines

Hm, I think it's a bit hard to read. Suggestions for improvement are welcome. Otherwise I'd add it that way.

It should be like:

  if (id_check != ...)
    return dev_err_probe(dev, -ENODEV, ...);

...

Quoted 64 lines
Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1020

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       dev_info(dev, "detected %s %s\n", yas5xx_product_name[yas5xx->chip],
+                yas5xx_version_name[yas5xx->chip][yas5xx->version]);

I'm wondering if these arrays can be actually embedded into chip_info?

While the variants (like "YAS530") are listed in the chip_info, the versions (like "A") are not. Yet, including the versions in chip_info would double the amount, making it visually more unclear, with only minor benefit.

The first part of this call, the "product name", applies to the variants. Going the detour via chip_info, the array element to call could just be hard-coded in the chip_info table, like:

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        ...

The second part, the "version name", is currently in the three-dimensional array yas5xx_version_name[]. The first dimension is the variant, this would need to be hard-coded in the chip_info table, similar to the example above. The second dimension is the version, this would need to come from within the yas5xx_probe() the function. I couldn't find a way how to assign one dimension in one place and another dimension in another place.

To include the second part in the chip_info, I would split the three-dimensional array yas5xx_version_name[] into three separate two-dimensional arrays, one per variant. It would look like this (snippets):

        static const char yas530_version_name[][3] = { "A", "B" };

        static const char yas532_version_name[][3] = { "AB", "AC" };

        static const char yas533_version_name[][3] = { "AB", "AC" };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char (*version_name)[3];
                ...

        ...

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas530_version_name,
                        ...

        ...


        dev_info(dev, "detected %s %s\n",
                 yas5xx->chip_info->product_name,
                 yas5xx->chip_info->version_name[yas5xx->version]);
Quoted 5 lines

I'm not fully sure this is the best way. Also note that I had to set the size of the second dimension of yas530_version_name to 3.

Do you think I should do it this way to include "product_name" and "version_name" in the chip_info?

Again, you are the author and my point is just to make you look at this from different angles. If you see no better way, go with the current approach, but just spend a half an hour and perhaps we may have a cleaner solution?

Quoted 8 lines

If yes, should I probably do a similar thing for the values "t_ref_counts" and "min_temp_celcius_x10"? Here as well, the array elements are directly called in function yas5xx_calc_temperature() without using the chip_info structure.

Also I noticed that I should add "static" to the typedef of arrays "t_ref_counts" and "min_temp_celcius_x10". Darn, and I have to correct the spelling of "celcius" into "celsius" in "min_temp_celcius_x10".

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#20 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Hi Andy,

Quoted 54 lines · Andy Shevchenko
Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Mon, Jul 4, 2022 at 12:04 AM Jakob Hauser <[email protected]> wrote:

..

Quoted 7 lines
Quoted 4 lines

Possible alternative would be more steps in 2), i.e. introducing chip_info for the callback only, then add field (or semantically unified fields) by field with corresponding changes in the code. In this case it would be easier to review.

What do you mean by "introducing chip_info for the callback only"? I guess you mean the function pointers?

Yes.

Quoted 38 lines

According to this, the patch could be split into:
1) introduce function pointers
2) introduce arrays to look up values

However, what's missing there is the introduction of the chip_info approach as such. Admittedly difficult to follow are the changes in yas5xx_probe():
- yas5xx->devid gets removed, it was the main switch decider before
- (for usage on other switches it is moved to yas5xx->chip_info->devid)
- yas5xx->chip as an enumeration is newly introduced
- yas5xx->chip_info as a structure gets initiated
- As the chip_info now chooses according to the i2c_device_id (via enum chip_ids, thus yas5xx->chip), a new check is introduced to make sure it matches the device ID read from the register. This is done by "if (id_check != yas5xx->chip_info->devid)".
- The way of reporting product name and version name was changed because introducing chip_info required to do this in one place for all versions.
- As a consequence of this, yas5xx->name became obsolete.

This would have to be done before introducing function pointers and arrays, like:
1) introduce chip_info structural changes
2) add function pointers
3) add arrays to look up values

But it can't be easily split that way. I can't establish an "empty" chip_info approach as a fist step without removing or changing many other things. The structural changes are related to other changes in that patch.

I'm thinking about first introducing chip_info and thereafter establishing the function pointers. In between I could try to split out the new temperature function:
1) introduce chip_info structural changes incl. arrays to look up values
2) split out new yas5xx_calc_temperature() function
3) add function pointers

Quoted 5 lines
Quoted 2 lines

I'm not yet sure it can be split that way because things are entangled. But I will try to this in v5.

Yes, my main point is to try to see under different angles on how you can split the series. We have plenty of time.

OK, I'll try it like this in v5.

...

Quoted 13 lines
Quoted 8 lines
Quoted 5 lines

drivers/iio/magnetometer/yamaha-yas530.c

Quoted 3 lines
drivers/iio/magnetometer/yamaha-yas530.c +0 -2
-#define YAS530_20DEGREES               182 /* Counts starting at -62 °C */
 
-#define YAS532_20DEGREES               390 /* Counts starting at -50 °C */

The comments suddenly disappear from the file. See below.

The comment's didn't actually disappear but rather got restructured by introducing new chip_info approach. See below.

See below.

..

...

Quoted 9 lines
Quoted 4 lines
Quoted 1 line

Also, use * instead of one dimension of array.

Sorry, probably I lack the basic knowledge here. Can you explain how to do that?

  static const char *_name[][] = {
  };

?

Indeed I was missing that basic knowledge. Thanks for showing!

After some trying and reading, I think it should be:

        static const char * const _name[][] = {
        };
Quoted 36 lines
Quoted 28 lines
Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c line 124

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+/* Number of counts between minimum and reference temperature */
+const u16 t_ref_counts[] = { 182, 390, 390 };
+
+/* Starting point of temperature counting in 1/10:s degrees Celsius */
+const s16 min_temp_celcius_x10[] = { -620, -500, -500 };

See above.

The former comments...

    182 /* Counts starting at -62 °C */
    390 /* Counts starting at -50 °C */

... and the two new comments above the arrays actually should say the same thing. At least that was my intention.

The first value is a number of counts. And the counting starts at a certain temperature, which is the second value. Both the old and the new comments are intended to describe this.

In the introduction of this temperature handling (patch 4), there is a lot more description on these values in function yas5xx_get_measure(). When creating the new "chip_info" patch 9, I was thinking about moving some of that description up here to these arrays. However, instead I tried to following Jonathan's suggestion in v3 to keep the describing text low and rather let the formulas speak for themselves. These values are applied at a formula in function yas5xx_calc_temperature() which is supposed to by kind of self explanatory.

Quoted 7 lines

What may lead to confusion is the equivalent usage of "starting" and "minimum" here. In the initial patchset I used "starting" related to the counts, Jonathan suggested "minimum" or actually "min_temp" related to the temperature. The comments here above are bit of a mixture of both. I still think it's good enough to understand. The sentence "Starting point of temperature ..." describes the value min_temp_celcius_x10. Using a term like "starting temperature" would probably be more confusing.

Quoted 3 lines

Confusing to me, who doesn't know the specifics of the chip, it is easy to read '-62 °C' vs. "read comment, look into an array, calculate in your brain".

I don't have a good idea how to fulfill your requirement in a brief way when the values are stored in an array altogether.

Instead I end up at a longer comment again.

Though this also offers the chance to add some additional information where the values were taken from.

Is it appropriate to include this to kernel doc? Generally I'm unsure on kernel doc but I guess yes...

It would look like:

/**
* const u16 t_ref_counts[] - 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, };

/**
* const s16 min_temp_celsius_x10[] - 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, };

Please note that I have to touch and extend these comments in the last patch "Add YAS537 variant". In the first comment I'll add that the value for YAS537 was approximately measured too. And in the second command I have to add the word "theoretical" temperatures because on YAS537 it is at -386 °C, which is below absolute zero Kelvin, thus a mere theoretical temperature.

Quoted 61 lines
Quoted 61 lines
Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c struct yas5xx_calibration { · line 158

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +5 -0
+struct yas5xx_chip_info {
+       unsigned int devid;
 
+       const int *volatile_reg;
+       const int volatile_reg_qty;
+       const u32 scaling_val2;

Why const here?
I assume entire structure is const, no?

I'm rather new to C language, not having a good grasp of "const" in structures yet. I would have guessed it doesn't work well with the function pointers.

However, having some compile tests, there are no complaints about the function pointers.

To change the whole chip_info structure to "const", I would:
- within the "struct yas5xx" change to "const struct yas5xx_chip_info *chip_info;"
- change following typedef to "static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = ..."

Then, within the "struct yas5xx_chip_info", I can remove "const" from:
- int volatile_reg_qty;
- u32 scaling_val2;

However, I have to keep "const" at the following, otherwise the complier complains that "initialization discards 'const' qualifier from pointer target type":
- const int *volatile_reg;

Summarizing, after the changes it would look like the following (snippets):

        struct yas5xx_chip_info {
                unsigned int devid;
                const int *volatile_reg;
                int volatile_reg_qty;
                u32 scaling_val2;
                int (*get_measure)(struct yas5xx *yas5xx, s32 *to,
                                   s32 *xo, s32 *yo, s32 *zo);
                int (*get_calibration_data)(struct yas5xx *yas5xx);
                void (*dump_calibration)(struct yas5xx *yas5xx);
                int (*measure_offsets)(struct yas5xx *yas5xx);
                int (*power_on)(struct yas5xx *yas5xx);
        };

        struct yas5xx {
                struct device *dev;
                enum chip_ids chip;
                const struct yas5xx_chip_info *chip_info;

                ...

        };

        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {

                        ...
Quoted 7 lines
Quoted 4 lines
                },
        };

If that's reasonable, I'll change it that way.

Yes, chip_info should be immutable, right? Otherwise it's something we may not rely on.

OK

Quoted 40 lines
Quoted 40 lines
Quoted 7 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1011

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +3 -1
+       if (id_check != yas5xx->chip_info->devid) {
                ret = -ENODEV;
-               dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid);
+               dev_err(dev, "device ID %02x doesn't match %s\n",
+                       id_check, id->name);

ret = dev_err_probe() ?

Makes sense, will change that.

Though I have difficulties to implement this nicely. dev_err_probe() requires an "error value to test". The current "if (id_check != yas5xx->chip_info->devid)" doesn't offer such a value by itself.

Do you think the following would be appropriate, nesting the check within the dev_err_probe()? It doesn't look too good to me.

        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;

If there are no better ideas, I would implement it that way. Additionally adding a comment and putting it into a block with the regmap_read before:

        /*
         * Check if the device ID from the register matches the one set
         * in the Device Tree.
         */
        ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
        if (ret)
                goto assert_reset;
        ret = dev_err_probe(dev, id_check != yas5xx->chip_info->devid,
                            "device ID %02x doesn't match %s\n",
                            id_check, id->name);
        if (ret)
                goto assert_reset;
Quoted 7 lines
Quoted 2 lines

Hm, I think it's a bit hard to read. Suggestions for improvement are welcome. Otherwise I'd add it that way.

It should be like:

  if (id_check != ...)
    return dev_err_probe(dev, -ENODEV, ...);

Ah! Thanks :)

Quoted 67 lines
Quoted 67 lines
Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1020

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       dev_info(dev, "detected %s %s\n", yas5xx_product_name[yas5xx->chip],
+                yas5xx_version_name[yas5xx->chip][yas5xx->version]);

I'm wondering if these arrays can be actually embedded into chip_info?

While the variants (like "YAS530") are listed in the chip_info, the versions (like "A") are not. Yet, including the versions in chip_info would double the amount, making it visually more unclear, with only minor benefit.

The first part of this call, the "product name", applies to the variants. Going the detour via chip_info, the array element to call could just be hard-coded in the chip_info table, like:

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        ...

The second part, the "version name", is currently in the three-dimensional array yas5xx_version_name[]. The first dimension is the variant, this would need to be hard-coded in the chip_info table, similar to the example above. The second dimension is the version, this would need to come from within the yas5xx_probe() the function. I couldn't find a way how to assign one dimension in one place and another dimension in another place.

To include the second part in the chip_info, I would split the three-dimensional array yas5xx_version_name[] into three separate two-dimensional arrays, one per variant. It would look like this (snippets):

        static const char yas530_version_name[][3] = { "A", "B" };

        static const char yas532_version_name[][3] = { "AB", "AC" };

        static const char yas533_version_name[][3] = { "AB", "AC" };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char (*version_name)[3];
                ...

        ...

        static struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas530_version_name,
                        ...

        ...


        dev_info(dev, "detected %s %s\n",
                 yas5xx->chip_info->product_name,
                 yas5xx->chip_info->version_name[yas5xx->version]);

I'm not fully sure this is the best way. Also note that I had to set the size of the second dimension of yas530_version_name to 3.

Quoted 7 lines
Quoted 2 lines

Do you think I should do it this way to include "product_name" and "version_name" in the chip_info?

Again, you are the author and my point is just to make you look at this from different angles. If you see no better way, go with the current approach, but just spend a half an hour and perhaps we may have a cleaner solution?

Indeed, to my own surprise I found a solution with the 2D array:

        static const char * const yas5xx_product_name[] = {
                "YAS530 MS-3E",
                "YAS532 MS-3R",
                "YAS533 MS-3F",
        };

        static const char * const yas5xx_version_name[][2] = {
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char * const *version_name;
                ...
        };

        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas5xx_version_name[0],
                        ...
                },
        };

        ...

        dev_info(dev, "detected %s %s\n",
                 yas5xx->chip_info->product_name,
                 yas5xx->chip_info->version_name[yas5xx->version]);
Quoted 4 lines
Quoted 4 lines

If yes, should I probably do a similar thing for the values "t_ref_counts" and "min_temp_celcius_x10"? Here as well, the array elements are directly called in function yas5xx_calc_temperature() without using the chip_info structure.

I then will include "product_name" and "version_name" as well as "t_ref_counts" and "min_temp_celsius_x10" to the chip_info struct to have everything collected.

...

Kind regards,
Jakob

#21 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Wed, Jul 27, 2022 at 12:01 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 1 line

Instead I end up at a longer comment again.

It's fine!

Quoted 5 lines

Though this also offers the chance to add some additional information where the values were taken from.

Is it appropriate to include this to kernel doc? Generally I'm unsure on kernel doc but I guess yes...

I'm unsure if it's appropriate for static (integer) arrays, you may run kernel doc script yourself and check man, html and pdf formats to see if it's rendered correctly.

...

Quoted 6 lines
Quoted 4 lines

Again, you are the author and my point is just to make you look at this from different angles. If you see no better way, go with the current approach, but just spend a half an hour and perhaps we may have a cleaner solution?

Indeed, to my own surprise I found a solution with the 2D array:

It looks better!

...

Quoted 3 lines
        dev_info(dev, "detected %s %s\n",
                 yas5xx->chip_info->product_name,
                 yas5xx->chip_info->version_name[yas5xx->version]);

Very good!

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#22 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Hi Andy,

Quoted 1 line · Andy Shevchenko

On Fri, Jul 29, 2022 at 1:06 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 6 lines
Quoted 2 lines

Is it appropriate to include this to kernel doc? Generally I'm unsure on kernel doc but I guess yes...

I'm unsure if it's appropriate for static (integer) arrays, you may run kernel doc script yourself and check man, html and pdf formats to see if it's rendered correctly.

Nope, doesn't work...

It was a beginner's mistake on my side. I did check Documentation/doc-guide/kernel-doc.rst before and followed the "typedef" part, which is quite short. I thought "typedef" is a more general designation – but after reading more on "typedef" I now know what it is :/
https://github.com/torvalds/linux/blob/v5.18/Documentation/doc-guide/kernel-doc.rst#typedef-documentation

So, as far as I can see, kernel doc applies to functions, structures, unions, enumerations and typedefs only.

I would then switch the comments to regular comments:

/*
* 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, };

...

Kind regards,
Jakob

#23 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

In reply to Jakob Hauser
Quoted 1 line · Jakob Hauser

On 27.07.22 19:39, Andy Shevchenko wrote:

...

Just a couple of remarks.

Quoted 9 lines

Indeed, to my own surprise I found a solution with the 2D array:

        static const char * const yas5xx_product_name[] = {
                "YAS530 MS-3E",
                "YAS532 MS-3R",
                "YAS533 MS-3F",
        };

        static const char * const yas5xx_version_name[][2] = {

yas5xx_version_names (note S at the end)

Quoted 11 lines
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char * const *version_name;
Quoted 8 lines
                ...
        };

        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas5xx_version_name[0],

Also 0 --> yas530 (use enum:ed indices)

Quoted 3 lines
                },
        };
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#24 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Hi Andy,

Quoted 14 lines · Andy Shevchenko

On Fri, Jul 29, 2022 at 1:06 AM Jakob Hauser <[email protected]> wrote:

..

Just a couple of remarks.

Quoted 8 lines

Indeed, to my own surprise I found a solution with the 2D array:

        static const char * const yas5xx_product_name[] = {
                "YAS530 MS-3E",
                "YAS532 MS-3R",
                "YAS533 MS-3F",
        };
Quoted 3 lines
Quoted 1 line
        static const char * const yas5xx_version_name[][2] = {

yas5xx_version_names (note S at the end)

As I understand you, it's to be applied on "yas5xx_version_names" only. In the chip_info table, it would then look like:

        .product_name = yas5xx_product_name[yas530],
        .version_name = yas5xx_version_names[yas530],
                                           ^
                                           S
Quoted 15 lines
Quoted 15 lines
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };

        ...

        struct yas5xx_chip_info {
                ...
                const char *product_name;
                const char * const *version_name;
                ...
        };
Quoted 7 lines
Quoted 5 lines
        static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
                [yas530] = {
                        ...
                        .product_name = yas5xx_product_name[0],
                        .version_name = yas5xx_version_name[0],

Also 0 --> yas530 (use enum:ed indices)

OK

Quoted 5 lines
Quoted 4 lines
                },
        };

Kind regards,
Jakob

#25 lore raw

Re: [PATCH v4 09/10] iio: magnetometer: yas530: Introduce "chip_info" structure

Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Fri, Jul 29, 2022 at 1:06 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 11 lines
Quoted 3 lines
Quoted 1 line
        static const char * const yas5xx_version_name[][2] = {

yas5xx_version_names (note S at the end)

As I understand you, it's to be applied on "yas5xx_version_names" only. In the chip_info table, it would then look like:

        .product_name = yas5xx_product_name[yas530],
        .version_name = yas5xx_version_names[yas530],
                                           ^
                                           S

Yes.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
                [yas530] = { "A", "B" },
                [yas532] = { "AB", "AC" },
                [yas533] = { "AB", "AC" },
        };
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#26 lore raw

PATCH v4 10/10 iio: magnetometer: yas530: Add YAS537 variant

In reply to Jakob Hauser

This adds support for the magnetometer Yamaha YAS537. The additions are based on comparison of Yamaha Android kernel drivers for YAS532 [1] and YAS537 [2].

In the Yamaha YAS537 Android driver, there is an overflow/underflow control implemented. For regular usage, this seems not necessary. A similar overflow/ underflow control of Yamaha YAS530/532 Android driver isn't integrated in the mainline driver. It is therefore skipped for YAS537 in mainline too.

Also in the Yamaha YAS537 Android driver, at the end of the reset_yas537() function, a measurement is saved in "last_after_rcoil". Later on, this is compared to current measurements. If the difference gets too big, a new reset is initialized. The difference in measurements needs to be quite big, it's hard to say if this is necessary for regular operation. Therefore this isn't integrated in the mainline driver either.

[1] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas532.c
[2] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c

---
Result of the patch can be seen at:
https://github.com/Jakko3/linux/blob/yas537_v4/drivers/iio/magnetometer/yamaha-yas530.c

 drivers/iio/magnetometer/Kconfig         |   4 +-
 drivers/iio/magnetometer/yamaha-yas530.c | 434 ++++++++++++++++++++++-
 2 files changed, 429 insertions(+), 9 deletions(-)
drivers/iio/magnetometer/Kconfig +2 -2
index 07eb619bcfe8..b91fc5e6a26e 100644
@@ -216,8 +216,8 @@ config YAMAHA_YAS530
 	select IIO_TRIGGERED_BUFFER
 	help
 	  Say Y here to add support for the Yamaha YAS530 series of
-	  3-Axis Magnetometers. Right now YAS530, YAS532 and YAS533 are
-	  fully supported.
+	  3-Axis Magnetometers. YAS530, YAS532, YAS533 and YAS537 are
+	  supported.
 
 	  This driver can also be compiled as a module.
 	  To compile this driver as a module, choose M here: the module
drivers/iio/magnetometer/yamaha-yas530.c +427 -7

537 lines not on this page · raw message

Signature · 1 line
2.35.1
#27 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Quoted 16 lines · Jakob Hauser

This adds support for the magnetometer Yamaha YAS537. The additions are based on comparison of Yamaha Android kernel drivers for YAS532 [1] and YAS537 [2].

In the Yamaha YAS537 Android driver, there is an overflow/underflow control implemented. For regular usage, this seems not necessary. A similar overflow/ underflow control of Yamaha YAS530/532 Android driver isn't integrated in the mainline driver. It is therefore skipped for YAS537 in mainline too.

Also in the Yamaha YAS537 Android driver, at the end of the reset_yas537() function, a measurement is saved in "last_after_rcoil". Later on, this is compared to current measurements. If the difference gets too big, a new reset is initialized. The difference in measurements needs to be quite big, it's hard to say if this is necessary for regular operation. Therefore this isn't integrated in the mainline driver either.

Quoted 2 lines

[1] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas532.c
[2] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c

Much better, my comments below.

...

drivers/iio/magnetometer/yamaha-yas530.c enum chip_ids { · line 144

Quoted 11 lines
        yas530,
        yas532,
        yas533,
drivers/iio/magnetometer/yamaha-yas530.c +2 -1
+       yas537,
 };
 
 static const char yas5xx_product_name[][13] = {
        "YAS530 MS-3E",
        "YAS532 MS-3R",
-       "YAS533 MS-3F"
+       "YAS533 MS-3F",

This is exactly the point why it's good practice to add comma for non-terminator entries.

Quoted 1 line

+ "YAS537 MS-3T"

...here.

drivers/iio/magnetometer/yamaha-yas530.c enum chip_ids { · line 151

Quoted 7 lines

};

 static const char yas5xx_version_name[][2][3] = {
        { "A", "B" },
        { "AB", "AC" },
drivers/iio/magnetometer/yamaha-yas530.c +1 -1
-       { "AB", "AC" }
+       { "AB", "AC" },

Ditto.

Quoted 2 lines

+ { "v0", "v1" }
};

...

Quoted 1 line

+ /* Write registers according to Android driver */

Would be nice to elaborate in the comment what exactly the flow is here, like "a) setting value of X; b) ...".

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1290

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL, GENMASK(1, 0));
+       if (ret)
+               return ret;
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL + 1, GENMASK(7, 3));
+       if (ret)
+               return ret;

Can bulk write be used here?

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1296

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       /* The interval value is static in regular operation */
+       intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * 1000

MILLI ?

Quoted 1 line

+ - YAS537_MEASURE_TIME_WORST_US) / 4100;

...

Quoted 3 lines

+ },

        }

And this is for chip_info and comma for non-terminator entries (see above).

...

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c,

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -3
-       ret = yas5xx->chip_info->measure_offsets(yas5xx);
-       if (ret)
-               goto assert_reset;
 
+       if (yas5xx->chip_info->measure_offsets) {

This can be done when you introduce this callback in the chip_info structure, so this patch won't need to shuffle code again. I.o.w. we can reduce ping-pong development in this series.

Quoted 4 lines
drivers/iio/magnetometer/yamaha-yas530.c +4 -0
+               ret = yas5xx->chip_info->measure_offsets(yas5xx);
+               if (ret)
+                       goto assert_reset;
+       }
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#28 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Hi Andy,

Quoted 2 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

...

Quoted 12 lines

drivers/iio/magnetometer/yamaha-yas530.c enum chip_ids { · line 144

Quoted 11 lines
        yas530,
        yas532,
        yas533,
drivers/iio/magnetometer/yamaha-yas530.c +2 -1
+       yas537,
 };
 
 static const char yas5xx_product_name[][13] = {
        "YAS530 MS-3E",
        "YAS532 MS-3R",
-       "YAS533 MS-3F"
+       "YAS533 MS-3F",
Quoted 8 lines

This is exactly the point why it's good practice to add comma for non-terminator entries.

Quoted 1 line

+ "YAS537 MS-3T"

..here.

Quoted 1 line

};

Yes, makes sense.

...

Quoted 4 lines
Quoted 1 line

+ /* Write registers according to Android driver */

Would be nice to elaborate in the comment what exactly the flow is here, like "a) setting value of X; b) ...".

Unfortunately, I don't know more than what the code already says. In the Yamaha Android driver, this part looks like this:
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L345-L350

The comment "Write registers according to Android driver" actually says "I don't know what I'm doing here, this is copy-paste from Android".

I can remove the comment if you find it inappropriate. Though from my point of view the comment is ok.

...

Quoted 8 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1290

Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL, GENMASK(1, 0));
+       if (ret)
+               return ret;
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL + 1, GENMASK(7, 3));
+       if (ret)
+               return ret;

Can bulk write be used here?

Technically yes. But in this case I strongly would like to keep the single regmap_write as we go through different registers step by step and write them. That way it's much better readable. And it's just these two that are neighboring each other. As this happens in yas537_power_on(), it isn't done very often, thus doesn't cost much resources.

...

Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1296

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       /* The interval value is static in regular operation */
+       intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * 1000

MILLI ?

What do you mean by this comment?

The suffixes _MS and _US were proposed by you in v2. I think they are fine.

...

Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c,

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -3
-       ret = yas5xx->chip_info->measure_offsets(yas5xx);
-       if (ret)
-               goto assert_reset;
 
+       if (yas5xx->chip_info->measure_offsets) {

This can be done when you introduce this callback in the chip_info structure, so this patch won't need to shuffle code again. I.o.w. we can reduce ping-pong development in this series.

I did this change in this patch on purpose because it's the introduction of YAS537 variant that's causing this change. YAS537 is the first variant that doesn't use yas5xx->chip_info->measure_offsets.

Shall I move it to patch 9 nonetheless?

Quoted 5 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c, · line 1448

Quoted 4 lines
drivers/iio/magnetometer/yamaha-yas530.c +4 -0
+               ret = yas5xx->chip_info->measure_offsets(yas5xx);
+               if (ret)
+                       goto assert_reset;
+       }

Kind regards,
Jakob

#29 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Mon, Jul 4, 2022 at 12:05 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ /* Write registers according to Android driver */

Would be nice to elaborate in the comment what exactly the flow is here, like "a) setting value of X; b) ...".

Unfortunately, I don't know more than what the code already says. In the Yamaha Android driver, this part looks like this:
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L345-L350

Quoted 5 lines

The comment "Write registers according to Android driver" actually says "I don't know what I'm doing here, this is copy-paste from Android".

I can remove the comment if you find it inappropriate. Though from my point of view the comment is ok.

The comment is okay for you, but for me it needs elaboration. So, something like above in compressed format (couple of short sentences to explain that nobody knows what the heck is that) will be appreciated.

...

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL, GENMASK(1, 0));
+       if (ret)
+               return ret;
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL + 1, GENMASK(7, 3));
+       if (ret)
+               return ret;
Quoted 8 lines
Quoted 1 line

Can bulk write be used here?

Technically yes. But in this case I strongly would like to keep the single regmap_write as we go through different registers step by step and write them. That way it's much better readable. And it's just these two that are neighboring each other. As this happens in yas537_power_on(), it isn't done very often, thus doesn't cost much resources.

You seems program the 16-bit register with a single value, I don't think it's a good idea to split a such. When it's a bulk write and value defined with __be16 / __le16 it makes much more clear what hardware is and what it expects.

...

Quoted 8 lines
Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1296

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       /* The interval value is static in regular operation */
+       intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * 1000

MILLI ?

What do you mean by this comment?

The suffixes _MS and _US were proposed by you in v2. I think they are fine.

1000 --> MILLI ?

10^-3 sec * 10^-3 = 10^-6 sec.

...

Quoted 10 lines
Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c,

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -3
-       ret = yas5xx->chip_info->measure_offsets(yas5xx);
-       if (ret)
-               goto assert_reset;
 
+       if (yas5xx->chip_info->measure_offsets) {

This can be done when you introduce this callback in the chip_info structure, so this patch won't need to shuffle code again. I.o.w. we can reduce ping-pong development in this series.

Quoted 5 lines

I did this change in this patch on purpose because it's the introduction of YAS537 variant that's causing this change. YAS537 is the first variant that doesn't use yas5xx->chip_info->measure_offsets.

Shall I move it to patch 9 nonetheless?

It's a bit hard to answer yes or no, I think after you try to resplit, we will see what is the best for this part.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/magnetometer/yamaha-yas530.c +4 -0
+               ret = yas5xx->chip_info->measure_offsets(yas5xx);
+               if (ret)
+                       goto assert_reset;
+       }
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#30 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Hi Andy,

Quoted 18 lines · Andy Shevchenko
Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Mon, Jul 4, 2022 at 12:05 AM Jakob Hauser <[email protected]> wrote:

..

Quoted 12 lines
Quoted 4 lines
Quoted 1 line

+ /* Write registers according to Android driver */

Would be nice to elaborate in the comment what exactly the flow is here, like "a) setting value of X; b) ...".

Unfortunately, I don't know more than what the code already says. In the Yamaha Android driver, this part looks like this:
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L345-L350

The comment "Write registers according to Android driver" actually says "I don't know what I'm doing here, this is copy-paste from Android".

Quoted 7 lines
Quoted 2 lines

I can remove the comment if you find it inappropriate. Though from my point of view the comment is ok.

The comment is okay for you, but for me it needs elaboration. So, something like above in compressed format (couple of short sentences to explain that nobody knows what the heck is that) will be appreciated.

I was thinking about:

/*
* Write registers according to Android driver, the exact meaning
* is unknown
*/

This reminded me of another location where I first had a comment "Writing SRST register, the exact meaning is unknown". There you criticized the part "the exact meaning is unknown", so I changed it to simply "Writing SRST register".

Accordingly, I would choose the following comment here:

/* Writing ADCCAL and TRM registers */

Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
drivers/iio/magnetometer/yamaha-yas530.c +6 -0
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL, GENMASK(1, 0));
+       if (ret)
+               return ret;
+       ret = regmap_write(yas5xx->map, YAS537_ADCCAL + 1, GENMASK(7, 3));
+       if (ret)
+               return ret;
Quoted 8 lines
Quoted 1 line

Can bulk write be used here?

Technically yes. But in this case I strongly would like to keep the single regmap_write as we go through different registers step by step and write them. That way it's much better readable. And it's just these two that are neighboring each other. As this happens in yas537_power_on(), it isn't done very often, thus doesn't cost much resources.

Quoted 4 lines

You seems program the 16-bit register with a single value, I don't think it's a good idea to split a such. When it's a bulk write and value defined with __be16 / __le16 it makes much more clear what hardware is and what it expects.

We don't know for sure whether it is a 16-bit register or an incomplete register naming.

Not all the registers are properly named in the original driver. E.g. there is a register called "YAS537_REG_MTCR" [1] with no names for the following registers. Further down, this and the following 11 registers are written by just counting up the register number [2].

It looks similar to the situation at register "YAS537_REG_ADCCALR", where the numerically following register (0x92) doesn't have a name [3]. It could be because of a 16-bit register, as you say, but it could also be a naming thing.

At the location in discussion, the original driver uses two single writes [4]. I'd stick to that.

[1]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L38
[2]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L277-L279
[3]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L37
[4]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L345-L348

Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas530_power_on(struct yas5xx *yas5xx) · line 1296

Quoted 2 lines
drivers/iio/magnetometer/yamaha-yas530.c +2 -0
+       /* The interval value is static in regular operation */
+       intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * 1000

MILLI ?

Quoted 7 lines
Quoted 3 lines

What do you mean by this comment?

The suffixes _MS and _US were proposed by you in v2. I think they are fine.

1000 --> MILLI ?

10^-3 sec * 10^-3 = 10^-6 sec.

Ah, well, the full formula is ...

intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * 1000
- YAS537_MEASURE_TIME_WORST_US) / 4100;

... with the fixed defined values:

        #define YAS537_DEFAULT_SENSOR_DELAY_MS	50
        #define YAS537_MEASURE_TIME_WORST_US	1500

So it means ...

        intrvl = (50 milliseconds * 1000 - 1500 microseconds) / 4100;

... which is:

        intrvl = (50000 microseconds - 1500 microseconds) / 4100;

The units of "4100" and "intrvl" are unclear. I don't know if "intrvl" is a time or some abstract value.

Still I didn't get your comment. Is your intention to change the "50 milliseconds * 1000" to "50000 microseconds" in the define?

It would look like ...

        #define YAS537_DEFAULT_SENSOR_DELAY_US	50000

... though I would prefer to keep current define, as it is implemented now and stated above:

        #define YAS537_DEFAULT_SENSOR_DELAY_MS	50
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

drivers/iio/magnetometer/yamaha-yas530.c static int yas5xx_probe(struct i2c_client *i2c,

Quoted 5 lines
drivers/iio/magnetometer/yamaha-yas530.c +1 -3
-       ret = yas5xx->chip_info->measure_offsets(yas5xx);
-       if (ret)
-               goto assert_reset;
 
+       if (yas5xx->chip_info->measure_offsets) {

This can be done when you introduce this callback in the chip_info structure, so this patch won't need to shuffle code again. I.o.w. we can reduce ping-pong development in this series.

Quoted 8 lines
Quoted 5 lines

I did this change in this patch on purpose because it's the introduction of YAS537 variant that's causing this change. YAS537 is the first variant that doesn't use yas5xx->chip_info->measure_offsets.

Shall I move it to patch 9 nonetheless?

It's a bit hard to answer yes or no, I think after you try to resplit, we will see what is the best for this part.

Hm... to avoid discussions and shorten iterations, I'll move it to the newly "add function pointers" patch in v5. I'll add a comment on this in the commit message of that patch.

...

Kind regards,
Jakob

#31 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Quoted 1 line · Jakob Hauser

On 27.07.22 19:46, Andy Shevchenko wrote:

...

Quoted 3 lines

/*
* Write registers according to Android driver, the exact meaning
* is unknown

With a period at the end :-)

Quoted 6 lines

*/

This reminded me of another location where I first had a comment "Writing SRST register, the exact meaning is unknown". There you criticized the part "the exact meaning is unknown", so I changed it to simply "Writing SRST register".

Yeah, but that is different, SRST seems like easy to deduce to "soft reset" (taking into account where it's programmed in the run flow).

Quoted 3 lines

Accordingly, I would choose the following comment here:

/* Writing ADCCAL and TRM registers */

Fine with me!

...

Quoted 7 lines
Quoted 4 lines

You seem to program the 16-bit register with a single value, I don't think it's a good idea to split a such. When it's a bulk write and value defined with __be16 / __le16 it makes much more clear what hardware is and what it expects.

We don't know for sure whether it is a 16-bit register or an incomplete register naming.

By the values you write into it seems to be a __be16 calibration register. The value to write is 0x3f8 which might ring a bell to you if you know what other values related to ADC.

Quoted 4 lines

Not all the registers are properly named in the original driver. E.g. there is a register called "YAS537_REG_MTCR" [1] with no names for the following registers. Further down, this and the following 11 registers are written by just counting up the register number [2].

12 (8-bit) registers, which may suggest 6 __be16, in any case looks like a mount matrix or so, with X,Y,Z values programmed.

This is interesting as well...
https://software-dl.ti.com/simplelink/esd/plugins/sail/1.10.00.06/exports/docs/sail/doxygen/html/structyas537__t.html

(Btw, it also suggest that ADC calibration is 16-bit register)

Quoted 8 lines

It looks similar to the situation at register "YAS537_REG_ADCCALR", where the numerically following register (0x92) doesn't have a name [3]. It could be because of a 16-bit register, as you say, but it could also be a naming thing.

At the location in discussion, the original driver uses two single writes [4]. I'd stick to that.

Quoted 8 lines

[1]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L38
[2]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L277-L279
[3]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L37
[4]
https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/GT-I9195I/drivers/iio/magnetometer/yas_mag_drv-yas537.c#L345-L348

It's all the joy of reverse engineering...

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

...

Quoted 11 lines

Still I didn't get your comment. Is your intention to change the "50 milliseconds * 1000" to "50000 microseconds" in the define?

It would look like ...

        #define YAS537_DEFAULT_SENSOR_DELAY_US  50000

... though I would prefer to keep current define, as it is implemented now and stated above:

        #define YAS537_DEFAULT_SENSOR_DELAY_MS  50

No, just to show in the actual calculation that you convert MS to US using MILLI.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#32 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Hi Andy,

Quoted 18 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

On 27.07.22 19:46, Andy Shevchenko wrote:

..

Quoted 3 lines

/*
* Write registers according to Android driver, the exact meaning
* is unknown

With a period at the end :-)

Quoted 6 lines

*/

This reminded me of another location where I first had a comment "Writing SRST register, the exact meaning is unknown". There you criticized the part "the exact meaning is unknown", so I changed it to simply "Writing SRST register".

Quoted 8 lines

Yeah, but that is different, SRST seems like easy to deduce to "soft reset" (taking into account where it's programmed in the run flow).

Quoted 3 lines

Accordingly, I would choose the following comment here:

/* Writing ADCCAL and TRM registers */

Fine with me!

OK, I'll apply the comment "Writing ADCCAL and TRM registers".

Quoted 8 lines

..

Quoted 5 lines
Quoted 4 lines

You seem to program the 16-bit register with a single value, I don't think it's a good idea to split a such. When it's a bulk write and value defined with __be16 / __le16 it makes much more clear what hardware is and what it expects.

Quoted 6 lines
Quoted 2 lines

We don't know for sure whether it is a 16-bit register or an incomplete register naming.

By the values you write into it seems to be a __be16 calibration register. The value to write is 0x3f8 which might ring a bell to you if you know what other values related to ADC.

Sigh, ok, I'll apply bulk write.

How to do it correctly? I guess:

        __be16 buf = cpu_to_be16(GENMASK(9, 3));
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);
        if (ret)
                return ret;

The whole block would then look like:

        /* Writing ADCCAL and TRM registers */
        __be16 buf = cpu_to_be16(GENMASK(9, 3));
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);
        if (ret)
                return ret;
        ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0));
        if (ret)
                return ret;

...

Quoted 4 lines

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

I've seen that comment before but I don't understand its meaning.

Quoted 7 lines
Quoted 7 lines

Still I didn't get your comment. Is your intention to change the "50 milliseconds * 1000" to "50000 microseconds" in the define?

It would look like ...

        #define YAS537_DEFAULT_SENSOR_DELAY_US  50000
Quoted 7 lines
Quoted 4 lines

... though I would prefer to keep current define, as it is implemented now and stated above:

        #define YAS537_DEFAULT_SENSOR_DELAY_MS  50

No, just to show in the actual calculation that you convert MS to US using MILLI.

Sorry, I still don't get what you want me to do. What do you mean by "using MILLI", can you elaborate?

Kind regards,
Jakob

#33 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Quoted 3 lines · Jakob Hauser
Quoted 2 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

On 27.07.22 19:46, Andy Shevchenko wrote:

...

Quoted 7 lines
Quoted 6 lines
Quoted 2 lines

We don't know for sure whether it is a 16-bit register or an incomplete register naming.

By the values you write into it seems to be a __be16 calibration register. The value to write is 0x3f8 which might ring a bell to you if you know what other values related to ADC.

Quoted 5 lines

Sigh, ok, I'll apply bulk write.

How to do it correctly? I guess:

        __be16 buf = cpu_to_be16(GENMASK(9, 3));

Looks like that, yes.

Quoted 1 line
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);

sizeof(buf)

Quoted 7 lines
        if (ret)
                return ret;

The whole block would then look like:

        /* Writing ADCCAL and TRM registers */
        __be16 buf = cpu_to_be16(GENMASK(9, 3));

(Taking into account that definitions are at the top of the function it would be

  __be16 buf;
  ...
  buf = cpu_to_be16(...);
Quoted 6 lines
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);
        if (ret)
                return ret;
        ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0));
        if (ret)
                return ret;

...

Quoted 6 lines
Quoted 4 lines

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

I've seen that comment before but I don't understand its meaning.

It points out that there is a SMPLTIM, which I decode as Sample Time, which is in 4.1 msec steps (up to 255 steps).

...

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

Still I didn't get your comment. Is your intention to change the "50 milliseconds * 1000" to "50000 microseconds" in the define?

It would look like ...

        #define YAS537_DEFAULT_SENSOR_DELAY_US  50000

... though I would prefer to keep current define, as it is implemented now and stated above:

Quoted 7 lines
Quoted 4 lines
Quoted 1 line
        #define YAS537_DEFAULT_SENSOR_DELAY_MS  50

No, just to show in the actual calculation that you convert MS to US using MILLI.

Sorry, I still don't get what you want me to do. What do you mean by "using MILLI", can you elaborate?

You use formula x * 1000 to convert milliseconds to microseconds. My suggestion is to replace 1000 with MILLI which adds information about exponent sign, i.e. 10^-3 (which may be important to the reader).

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#34 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Hi Andy,

Quoted 17 lines · Andy Shevchenko
Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Fri, Jul 29, 2022 at 1:13 AM Jakob Hauser <[email protected]> wrote:

..

Quoted 11 lines
Quoted 6 lines
Quoted 2 lines

We don't know for sure whether it is a 16-bit register or an incomplete register naming.

By the values you write into it seems to be a __be16 calibration register. The value to write is 0x3f8 which might ring a bell to you if you know what other values related to ADC.

Sigh, ok, I'll apply bulk write.

How to do it correctly? I guess:

Quoted 7 lines
Quoted 1 line
        __be16 buf = cpu_to_be16(GENMASK(9, 3));

Looks like that, yes.

Quoted 1 line
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);

sizeof(buf)

OK

Quoted 5 lines
Quoted 5 lines
        if (ret)
                return ret;

The whole block would then look like:

Quoted 8 lines
Quoted 2 lines
        /* Writing ADCCAL and TRM registers */
        __be16 buf = cpu_to_be16(GENMASK(9, 3));

(Taking into account that definitions are at the top of the function it would be

  __be16 buf;
  ...
  buf = cpu_to_be16(...);

Thanks for the details, I'll implement it like this.

Quoted 14 lines
Quoted 6 lines
        ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, 2);
        if (ret)
                return ret;
        ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0));
        if (ret)
                return ret;

..

Quoted 5 lines
Quoted 4 lines

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

Quoted 4 lines
Quoted 1 line

I've seen that comment before but I don't understand its meaning.

It points out that there is a SMPLTIM, which I decode as Sample Time, which is in 4.1 msec steps (up to 255 steps).

Also thanks for this interpretation, that makes sense. Then the denominator consists of factor 1000 to convert microseconds back to milliseconds and a factor of 4.1 milliseconds per step. The value "intrvl", which is written into the YAS537_MEASURE_INTERVAL register, would then be the number of steps of the sample time.

However, I wouldn't add anything of this into the driver as a comment or as a name, because we're just guessing.

Quoted 18 lines

..

Quoted 15 lines
Quoted 14 lines
Quoted 11 lines

Still I didn't get your comment. Is your intention to change the "50 milliseconds * 1000" to "50000 microseconds" in the define?

It would look like ...

        #define YAS537_DEFAULT_SENSOR_DELAY_US  50000

... though I would prefer to keep current define, as it is implemented now and stated above:

        #define YAS537_DEFAULT_SENSOR_DELAY_MS  50

No, just to show in the actual calculation that you convert MS to US using MILLI.

Quoted 6 lines
Quoted 2 lines

Sorry, I still don't get what you want me to do. What do you mean by "using MILLI", can you elaborate?

You use formula x * 1000 to convert milliseconds to microseconds. My suggestion is to replace 1000 with MILLI which adds information about exponent sign, i.e. 10^-3 (which may be important to the reader).

Hm, ok, but the MILLI has to be defined. Or is it predefined somewhere? I couldn't find any examples.

To my interpretation, it would look like this (upper part showing the location of the define, lower part the formula):

    ...
    #define YAS537_LCK_MASK_GET             GENMASK(3, 0)
    #define YAS537_OC_MASK_GET              GENMASK(5, 0)

    #define MILLI                           1000

    /* Turn off device regulators etc after 5 seconds of inactivity */
    #define YAS5XX_AUTOSUSPEND_DELAY_MS     5000

    enum chip_ids {
            ...
    };

    ...

    intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * MILLI
             - YAS537_MEASURE_TIME_WORST_US) / 4100;

I think the define and the formula both look strange.

Kind regards,
Jakob

#35 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Quoted 4 lines · Jakob Hauser
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Jakob Hauser
Quoted 1 line · Andy Shevchenko

On Fri, Jul 29, 2022 at 1:13 AM Jakob Hauser <[email protected]> wrote:

...

Quoted 10 lines
Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

I've seen that comment before but I don't understand its meaning.

It points out that there is a SMPLTIM, which I decode as Sample Time, which is in 4.1 msec steps (up to 255 steps).

Quoted 8 lines

Also thanks for this interpretation, that makes sense. Then the denominator consists of factor 1000 to convert microseconds back to milliseconds and a factor of 4.1 milliseconds per step. The value "intrvl", which is written into the YAS537_MEASURE_INTERVAL register, would then be the number of steps of the sample time.

However, I wouldn't add anything of this into the driver as a comment or as a name, because we're just guessing.

Or we can precisely tell that this is guesswork. Up to you.

...

Quoted 1 line

I think the define and the formula both look strange.

Definition is available in units.h, for most of the SI prefixes.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#36 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

Hi Andy,

Quoted 23 lines · Andy Shevchenko
Quoted 3 lines · Jakob Hauser
Quoted 2 lines · Andy Shevchenko
Quoted 1 line · Jakob Hauser

On 29.07.22 19:24, Andy Shevchenko wrote:

..

Quoted 16 lines
Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

To the 4100 denominator:
https://github.com/XPerience-AOSP-Lollipop/android_kernel_wingtech_msm8916/blob/xpe-11.1/drivers/input/misc/yas_mag_drv-yas537.c#L235,
seems you can find a lot by browsing someone's code and perhaps a Git history.

I've seen that comment before but I don't understand its meaning.

It points out that there is a SMPLTIM, which I decode as Sample Time, which is in 4.1 msec steps (up to 255 steps).

Also thanks for this interpretation, that makes sense. Then the denominator consists of factor 1000 to convert microseconds back to milliseconds and a factor of 4.1 milliseconds per step. The value "intrvl", which is written into the YAS537_MEASURE_INTERVAL register, would then be the number of steps of the sample time.

Quoted 4 lines
Quoted 2 lines

However, I wouldn't add anything of this into the driver as a comment or as a name, because we're just guessing.

Or we can precisely tell that this is guesswork. Up to you.

I would keep it as it is. It has no direct relevance.

Quoted 7 lines

..

Quoted 1 line

I think the define and the formula both look strange.

Definition is available in units.h, for most of the SI prefixes.

Ah, thanks, I didn't find that myself. Sorry for my incomprehension.

OK, everything clarified. I'll prepare v5 within the next days.

Kind regards,
Jakob

#37 lore raw

Re: [PATCH v4 10/10] iio: magnetometer: yas530: Add YAS537 variant

In reply to Andy Shevchenko
Quoted 3 lines · Andy Shevchenko
Quoted 1 line

I think the define and the formula both look strange.

Definition is available in units.h, for most of the SI prefixes.

WHoa news2me, I never saw that file before! Learn something new every day....

Yours,
Linus Walleij

#38 lore raw
In reply to Jakob Hauser
Quoted 6 lines · Jakob Hauser

This patchset adds YAS537 variant to the already existing driver for Yamaha YAS magnetometers.

Patch 1 is a fix on the current driver.
Patches 2-9 are cleanups and refactoring.
Patch 10 finally adds the YAS537 variant.

This patch set is really nice and getting nicer.

Maybe Jonathan could apply patches 1-5 so you don't have to resend so much code and get more focus on the top 5 patches? They are anyway nice in their own right.

Yours,
Linus Walleij

maintainer
#39 lore raw
Quoted 9 lines · On Tue, 5 Jul 2022 01:31:48 +0200 Linus Walleij <[email protected]>…
Quoted 6 lines · Jakob Hauser

This patchset adds YAS537 variant to the already existing driver for Yamaha YAS magnetometers.

Patch 1 is a fix on the current driver.
Patches 2-9 are cleanups and refactoring.
Patch 10 finally adds the YAS537 variant.

Quoted 6 lines

This patch set is really nice and getting nicer.

Maybe Jonathan could apply patches 1-5 so you don't have to resend so much code and get more focus on the top 5 patches? They are anyway nice in their own right.

Given I'm running way behind (at least I'm in the right month now ;) and my tree isn't stable currently (I'll rebase after rc1) and only pushed out as testing as a result that isn't a good idea right now. It would be at any other timing though.

So, please keep all the patches for v5.

Thanks,

Jonathan

Quoted 2 lines

Yours,
Linus Walleij