From c3b4afb1825b120481798512dd6a647804c5e521 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 7 Aug 2022 19:45:33 +0100 Subject: iio: magn: hmc5843: Drop excessive indentation of assignments of hmc5843_driver This formatting is odd, so fix it to be more standard. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220807184534.1037363-2-jic23@kernel.org --- drivers/iio/magnetometer/hmc5843_spi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 8403f09aba39..310027a53342 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -86,13 +86,13 @@ static const struct spi_device_id hmc5843_id[] = { MODULE_DEVICE_TABLE(spi, hmc5843_id); static struct spi_driver hmc5843_driver = { - .driver = { - .name = "hmc5843", - .pm = HMC5843_PM_OPS, - }, - .id_table = hmc5843_id, - .probe = hmc5843_spi_probe, - .remove = hmc5843_spi_remove, + .driver = { + .name = "hmc5843", + .pm = HMC5843_PM_OPS, + }, + .id_table = hmc5843_id, + .probe = hmc5843_spi_probe, + .remove = hmc5843_spi_remove, }; module_spi_driver(hmc5843_driver); -- cgit v1.2.3 From 71041f73dc685ccaa7d150aa5eecc02609117739 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 7 Aug 2022 19:45:34 +0100 Subject: iio: magn: hmc5843: Move struct dev_pm_ops out of header Having this structure defined static in the header lead to unnecessary duplication and required additional symbol exports. Use the EXPORT_NS_SIMPLE_DEV_PM_OPS() to clean this up in the same fashion as many other drivers do this. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220807184534.1037363-3-jic23@kernel.org --- drivers/iio/magnetometer/hmc5843.h | 13 +------------ drivers/iio/magnetometer/hmc5843_core.c | 8 ++++---- drivers/iio/magnetometer/hmc5843_i2c.c | 2 +- drivers/iio/magnetometer/hmc5843_spi.c | 2 +- 4 files changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h index 9120c8bbf3dd..60fbb5431c88 100644 --- a/drivers/iio/magnetometer/hmc5843.h +++ b/drivers/iio/magnetometer/hmc5843.h @@ -52,16 +52,5 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, enum hmc5843_ids id, const char *name); void hmc5843_common_remove(struct device *dev); -int hmc5843_common_suspend(struct device *dev); -int hmc5843_common_resume(struct device *dev); - -#ifdef CONFIG_PM_SLEEP -static __maybe_unused SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, - hmc5843_common_suspend, - hmc5843_common_resume); -#define HMC5843_PM_OPS (&hmc5843_pm_ops) -#else -#define HMC5843_PM_OPS NULL -#endif - +extern const struct dev_pm_ops hmc5843_pm_ops; #endif /* HMC5843_CORE_H */ diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 4a63b2da9df0..c5521d61da29 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -603,19 +603,19 @@ static const struct iio_info hmc5843_info = { static const unsigned long hmc5843_scan_masks[] = {0x7, 0}; -int hmc5843_common_suspend(struct device *dev) +static int hmc5843_common_suspend(struct device *dev) { return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), HMC5843_MODE_SLEEP); } -EXPORT_SYMBOL_NS(hmc5843_common_suspend, IIO_HMC5843); -int hmc5843_common_resume(struct device *dev) +static int hmc5843_common_resume(struct device *dev) { return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), HMC5843_MODE_CONVERSION_CONTINUOUS); } -EXPORT_SYMBOL_NS(hmc5843_common_resume, IIO_HMC5843); +EXPORT_NS_SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_common_suspend, + hmc5843_common_resume, IIO_HMC5843); int hmc5843_common_probe(struct device *dev, struct regmap *regmap, enum hmc5843_ids id, const char *name) diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index 8d2ff8fc204d..825a881d37fb 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -93,7 +93,7 @@ MODULE_DEVICE_TABLE(of, hmc5843_of_match); static struct i2c_driver hmc5843_driver = { .driver = { .name = "hmc5843", - .pm = HMC5843_PM_OPS, + .pm = pm_sleep_ptr(&hmc5843_pm_ops), .of_match_table = hmc5843_of_match, }, .id_table = hmc5843_id, diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 310027a53342..c42d2e2a6a6c 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -88,7 +88,7 @@ MODULE_DEVICE_TABLE(spi, hmc5843_id); static struct spi_driver hmc5843_driver = { .driver = { .name = "hmc5843", - .pm = HMC5843_PM_OPS, + .pm = pm_sleep_ptr(&hmc5843_pm_ops), }, .id_table = hmc5843_id, .probe = hmc5843_spi_probe, -- cgit v1.2.3 From e137fafc8985cf152a4bb6f18ae83ebb06816df1 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:06 +0200 Subject: 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") Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/40f052bf6491457d0c5c0ed4c3534dc6fa251c3c.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index aeaa4da6923b..d1f16729c60e 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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]; -- cgit v1.2.3 From 4efdfbc16cceffbcb29e53a5be55d83a4c76a9c0 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:07 +0200 Subject: iio: magnetometer: yas530: Change range of data in volatile register 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. Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/dabba10feb80171350525ac874f944076c46e084.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index d1f16729c60e..76bff4818461 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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 */ -- cgit v1.2.3 From 413cf691633c985c3b49d005aa07b0e9c70c14a1 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:08 +0200 Subject: iio: magnetometer: yas530: Correct scaling of magnetic axes Looks like YAS530 raw values return picotesla and YAS532 nanotesla. Adapt comments and scaling. Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/053ab05cb9a0f6b0536ab5e0de57009f513c6f81.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 76bff4818461..199d83013e6f 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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 */ -- cgit v1.2.3 From 8239f904f97c94b25a9983aa243090bb393abe81 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:09 +0200 Subject: iio: magnetometer: yas530: Correct temperature handling 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 Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/eb45f328c7a81eb622c6a8cfc5c468ea58bbdace.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 99 ++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 23 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 199d83013e6f..6296ea3140ef 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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, -- cgit v1.2.3 From 0ca09faadef13bd6f7a59fa9f6858ccb88dac539 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:10 +0200 Subject: iio: magnetometer: yas530: Change data type of calibration coefficients 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 Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/f1e53bd6672aebe59f9b236b41374482edf888f8.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 6296ea3140ef..a9d7cf3ad77f 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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; }; -- cgit v1.2.3 From 6e3bfa97c5b8a9ea702ad0b8a28e703b6d561ac1 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:11 +0200 Subject: iio: magnetometer: yas530: Rename functions and registers This is a preparation for adding the 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. Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/344d3b2f5e050eab79ce9962c24781486774d9fb.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 126 +++++++++++++++++-------------- 1 file changed, 70 insertions(+), 56 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index a9d7cf3ad77f..40cd6bbc9952 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -40,20 +40,22 @@ #include -/* 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,15 +184,17 @@ 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 * @y1: the y1 axis measurement * @y2: the y2 axis measurement * @return: 0 on success or error code + * + * Used by YAS530, YAS532 and YAS533. */ -static int yas5xx_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2) +static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2) { unsigned int busy; u8 data[8]; @@ -198,7 +202,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 +268,8 @@ out_unlock: 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,15 +311,17 @@ 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 * @yo: Y axis out * @zo: Z axis out * @return: 0 on success or error code + * + * Used by YAS530, YAS532 and YAS533. */ -static int yas5xx_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo) +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 +330,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) { @@ -446,7 +453,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 = yas530_get_measure(yas5xx, &t, &x, &y, &z); pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) @@ -505,7 +512,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 = yas530_get_measure(yas5xx, &t, &x, &y, &z); pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) { @@ -591,8 +598,8 @@ 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 || + return reg == YAS530_ACTUATE_INIT_COIL || + reg == YAS530_MEASURE || (reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8); } @@ -605,11 +612,13 @@ 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 + * + * Used by YAS530, YAS532 and YAS533. */ -static void yas53x_extract_calibration(u8 *data, struct yas5xx_calibration *c) +static void yas530_extract_calibration(u8 *data, struct yas5xx_calibration *c) { u64 val = get_unaligned_be64(data); @@ -647,12 +656,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 +673,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 +704,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 +727,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 +750,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 +774,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 +798,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 +808,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 +842,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 +870,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 +973,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; @@ -1062,7 +1076,7 @@ static int yas5xx_runtime_resume(struct device *dev) usleep_range(31000, 40000); gpiod_set_value_cansleep(yas5xx->reset, 0); - ret = yas5xx_power_on(yas5xx); + ret = yas530_power_on(yas5xx); if (ret) { dev_err(dev, "cannot power on\n"); goto out_reset; -- cgit v1.2.3 From bdef8dcfbb94dc16e9750cd109bb9b7d8edfa1ca Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:12 +0200 Subject: iio: magnetometer: yas530: Move printk %*ph parameters out from stack Use less stack by modifying %*ph parameters. While at it, 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: Andy Shevchenko Signed-off-by: Jakob Hauser Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/93b50c20adb1b2acb4cddb1ab25755070edd7c07.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 40cd6bbc9952..beb48f3a959c 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -664,7 +664,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); @@ -711,7 +711,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) { -- cgit v1.2.3 From 92d9c05ca7324aed6695b53d3ce11b3e1387f470 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:13 +0200 Subject: iio: magnetometer: yas530: Apply documentation and style fixes 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. Signed-off-by: Jakob Hauser Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/300e394a76eb30fa031ecb69b594e9f9a70dac42.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index beb48f3a959c..f81868de5995 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -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 @@ -325,7 +321,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; @@ -666,7 +662,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 */ @@ -693,6 +692,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; } @@ -714,12 +714,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); @@ -728,6 +728,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: -- cgit v1.2.3 From a70f60e5b6b37e8b9f0967235bf89aebd2d9fbb9 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:14 +0200 Subject: iio: magnetometer: yas530: Introduce "chip_info" structure Introduce the "chip_info" structure approach for better variant handling. The variant to be used is now chosen by the Device Tree (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"). Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/57236545107286771d351b95091bf56815d3717d.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 98 ++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 24 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index f81868de5995..4fe7e8c820c3 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -96,6 +96,12 @@ /* Turn off device regulators etc after 5 seconds of inactivity */ #define YAS5XX_AUTOSUSPEND_DELAY_MS 5000 +enum chip_ids { + yas530, + yas532, + yas533, +}; + struct yas5xx_calibration { /* Linearization calibration x, y1, y2 */ s32 r[3]; @@ -110,12 +116,25 @@ struct yas5xx_calibration { u8 dck; }; +struct yas5xx; + +/** + * struct yas5xx_chip_info - device-specific data and function pointers + * @devid: device ID number + * @product_name: product name of the YAS variant + * @version_names: version letters or namings + */ +struct yas5xx_chip_info { + unsigned int devid; + char *product_name; + char *version_names[2]; +}; + /** * struct yas5xx - state container for the YAS5xx driver * @dev: parent device pointer - * @devid: device ID number + * @chip_info: device-specific data * @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 +148,8 @@ struct yas5xx_calibration { */ struct yas5xx { struct device *dev; - unsigned int devid; + const 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; @@ -192,6 +210,7 @@ static u16 yas532_extract_axis(u8 *data) */ static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2) { + const struct yas5xx_chip_info *ci = yas5xx->chip_info; unsigned int busy; u8 data[8]; int ret; @@ -222,7 +241,7 @@ static int yas530_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y mutex_unlock(&yas5xx->lock); - switch (yas5xx->devid) { + switch (ci->devid) { case YAS530_DEVICE_ID: /* * The t value is 9 bits in big endian format @@ -267,6 +286,7 @@ out_unlock: /* Used by YAS530, YAS532 and YAS533 */ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis) { + const struct yas5xx_chip_info *ci = yas5xx->chip_info; struct yas5xx_calibration *c = &yas5xx->calibration; static const s32 yas532ac_coef[] = { YAS532_VERSION_AC_COEF_X, @@ -276,7 +296,7 @@ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis) s32 coef; /* Select coefficients */ - switch (yas5xx->devid) { + switch (ci->devid) { case YAS530_DEVICE_ID: if (yas5xx->version == YAS530_VERSION_A) coef = YAS530_VERSION_A_COEF; @@ -319,6 +339,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) { + const struct yas5xx_chip_info *ci = yas5xx->chip_info; struct yas5xx_calibration *c = &yas5xx->calibration; u16 t_ref, t, x, y1, y2; /* These are signed x, signed y1 etc */ @@ -336,7 +357,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, sy2 = yas530_linearize(yas5xx, y2, 2); /* Set the temperature reference value (unit: counts) */ - switch (yas5xx->devid) { + switch (ci->devid) { case YAS530_DEVICE_ID: t_ref = YAS530_20DEGREES; break; @@ -349,7 +370,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, } /* Temperature compensation for x, y1, y2 respectively */ - if (yas5xx->devid == YAS532_DEVICE_ID && + if (ci->devid == YAS532_DEVICE_ID && yas5xx->version == YAS532_VERSION_AC) { /* * YAS532 version AC uses the temperature deviation as a @@ -384,7 +405,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, sz = -sy1 - sy2; /* Process temperature readout */ - switch (yas5xx->devid) { + switch (ci->devid) { case YAS530_DEVICE_ID: /* * Raw temperature value t is the number of counts starting @@ -442,6 +463,7 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev, long mask) { struct yas5xx *yas5xx = iio_priv(indio_dev); + const struct yas5xx_chip_info *ci = yas5xx->chip_info; s32 t, x, y, z; int ret; @@ -473,7 +495,7 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev, } return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - switch (yas5xx->devid) { + switch (ci->devid) { case YAS530_DEVICE_ID: /* * Raw values of YAS530 are in picotesla. Divide by @@ -802,6 +824,7 @@ static s8 yas530_adjust_offset(s8 old, int bit, u16 center, u16 measure) /* Used by YAS530, YAS532 and YAS533 */ static int yas530_measure_offsets(struct yas5xx *yas5xx) { + const struct yas5xx_chip_info *ci = yas5xx->chip_info; int ret; u16 center; u16 t, x, y1, y2; @@ -814,7 +837,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 (ci->devid) { case YAS530_DEVICE_ID: center = YAS530_DATA_CENTER; break; @@ -895,12 +918,32 @@ static int yas530_power_on(struct yas5xx *yas5xx) return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0); } +static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { + [yas530] = { + .devid = YAS530_DEVICE_ID, + .product_name = "YAS530 MS-3E", + .version_names = { "A", "B" }, + }, + [yas532] = { + .devid = YAS532_DEVICE_ID, + .product_name = "YAS532 MS-3R", + .version_names = { "AB", "AC" }, + }, + [yas533] = { + .devid = YAS532_DEVICE_ID, + .product_name = "YAS533 MS-3F", + .version_names = { "AB", "AC" }, + }, +}; + 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; + const struct yas5xx_chip_info *ci; + int id_check; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*yas5xx)); @@ -947,33 +990,40 @@ static int yas5xx_probe(struct i2c_client *i2c, goto assert_reset; } - ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &yas5xx->devid); + yas5xx->chip_info = &yas5xx_chip_info_tbl[id->driver_data]; + ci = yas5xx->chip_info; + + ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check); if (ret) goto assert_reset; - switch (yas5xx->devid) { + if (id_check != ci->devid) { + ret = dev_err_probe(dev, -ENODEV, + "device ID %02x doesn't match %s\n", + id_check, id->name); + goto assert_reset; + } + + switch (ci->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: ret = -ENODEV; - dev_err(dev, "unhandled device ID %02x\n", yas5xx->devid); + dev_err(dev, "unhandled device ID %02x\n", ci->devid); goto assert_reset; } + dev_info(dev, "detected %s %s\n", ci->product_name, + ci->version_names[yas5xx->version]); + yas530_dump_calibration(yas5xx); ret = yas530_power_on(yas5xx); if (ret) @@ -985,7 +1035,7 @@ static int yas5xx_probe(struct i2c_client *i2c, 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); @@ -1096,9 +1146,9 @@ static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend, yas5xx_runtime_resume, NULL); static const struct i2c_device_id yas5xx_id[] = { - {"yas530", }, - {"yas532", }, - {"yas533", }, + {"yas530", yas530 }, + {"yas532", yas532 }, + {"yas533", yas533 }, {} }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); -- cgit v1.2.3 From dd9bd44f877d8935b7359f083626786cead98adb Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Fri, 12 Aug 2022 23:54:15 +0200 Subject: iio: magnetometer: yas530: Add volatile registers to "chip_info" Add volatile registers to the "chip_info" structure to ease the handling of different YAS variants. Signed-off-by: Jakob Hauser Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/aeba3877933ba9d2c920b459a9037d9186c15a4f.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 38 +++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 4fe7e8c820c3..fa317b975f8f 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -102,6 +102,11 @@ enum chip_ids { yas533, }; +static const int yas530_volatile_reg[] = { + YAS530_ACTUATE_INIT_COIL, + YAS530_MEASURE, +}; + struct yas5xx_calibration { /* Linearization calibration x, y1, y2 */ s32 r[3]; @@ -123,11 +128,15 @@ struct yas5xx; * @devid: device ID number * @product_name: product name of the YAS variant * @version_names: version letters or namings + * @volatile_reg: device-specific volatile registers + * @volatile_reg_qty: quantity of device-specific volatile registers */ struct yas5xx_chip_info { unsigned int devid; char *product_name; char *version_names[2]; + const int *volatile_reg; + int volatile_reg_qty; }; /** @@ -616,9 +625,26 @@ static const struct iio_info yas5xx_info = { static bool yas5xx_volatile_reg(struct device *dev, unsigned int reg) { - return reg == YAS530_ACTUATE_INIT_COIL || - reg == YAS530_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); + const struct yas5xx_chip_info *ci = yas5xx->chip_info; + int reg_qty; + int i; + + if (reg >= YAS5XX_MEASURE_DATA && reg < YAS5XX_MEASURE_DATA + 8) + return true; + + /* + * YAS versions share different registers on the same address, + * need to differentiate. + */ + reg_qty = ci->volatile_reg_qty; + for (i = 0; i < reg_qty; i++) { + if (reg == ci->volatile_reg[i]) + return true; + } + + return false; } /* TODO: enable regmap cache, using mark dirty and sync at runtime resume */ @@ -923,16 +949,22 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .devid = YAS530_DEVICE_ID, .product_name = "YAS530 MS-3E", .version_names = { "A", "B" }, + .volatile_reg = yas530_volatile_reg, + .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), }, [yas532] = { .devid = YAS532_DEVICE_ID, .product_name = "YAS532 MS-3R", .version_names = { "AB", "AC" }, + .volatile_reg = yas530_volatile_reg, + .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), }, [yas533] = { .devid = YAS532_DEVICE_ID, .product_name = "YAS533 MS-3F", .version_names = { "AB", "AC" }, + .volatile_reg = yas530_volatile_reg, + .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), }, }; -- cgit v1.2.3 From 913fd409668b7fd54db5efd979417a9f94dcc79b Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sat, 13 Aug 2022 00:05:00 +0200 Subject: iio: magnetometer: yas530: Add IIO scaling to "chip_info" Add IIO scaling to the "chip_info" structure to ease the handling to different YAS variants. Signed-off-by: Jakob Hauser Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/a12f892633bbee13a8856c231dc793ebbc5d3a03.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index fa317b975f8f..af5c090098fb 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -130,6 +130,7 @@ struct yas5xx; * @version_names: version letters or namings * @volatile_reg: device-specific volatile registers * @volatile_reg_qty: quantity of device-specific volatile registers + * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE */ struct yas5xx_chip_info { unsigned int devid; @@ -137,6 +138,7 @@ struct yas5xx_chip_info { char *version_names[2]; const int *volatile_reg; int volatile_reg_qty; + u32 scaling_val2; }; /** @@ -504,27 +506,8 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev, } return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - switch (ci->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 = ci->scaling_val2; return IIO_VAL_FRACTIONAL; default: /* Unknown request */ @@ -951,6 +934,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .version_names = { "A", "B" }, .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), + .scaling_val2 = 100000000, /* picotesla to Gauss */ }, [yas532] = { .devid = YAS532_DEVICE_ID, @@ -958,6 +942,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), + .scaling_val2 = 100000, /* nanotesla to Gauss */ }, [yas533] = { .devid = YAS532_DEVICE_ID, @@ -965,6 +950,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), + .scaling_val2 = 100000, /* nanotesla to Gauss */ }, }; -- cgit v1.2.3 From 2d6676ecbe6a39fb1e002b89781e4158e77a784e Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sat, 13 Aug 2022 00:05:01 +0200 Subject: iio: magnetometer: yas530: Add temperature calculation to "chip_info" Add temperature calculation to the "chip_info" structure to ease the handling of different YAS variants. Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/1a8bffdb7e807455620a73f2d61981e7f9aab8d5.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 123 ++++++++++++++----------------- 1 file changed, 54 insertions(+), 69 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index af5c090098fb..a5d3f0bff024 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -79,7 +79,6 @@ #define YAS530_DATA_BITS 12 #define YAS530_DATA_CENTER BIT(YAS530_DATA_BITS - 1) #define YAS530_DATA_OVERFLOW (BIT(YAS530_DATA_BITS) - 1) -#define YAS530_20DEGREES 182 /* Counts starting at -62 °C */ #define YAS532_DEVICE_ID 0x02 /* YAS532/YAS533 (MS-3R/F) */ #define YAS532_VERSION_AB 0 /* YAS532/533 AB (MS-3R/F AB) */ @@ -91,7 +90,6 @@ #define YAS532_DATA_BITS 13 #define YAS532_DATA_CENTER BIT(YAS532_DATA_BITS - 1) #define YAS532_DATA_OVERFLOW (BIT(YAS532_DATA_BITS) - 1) -#define YAS532_20DEGREES 390 /* Counts starting at -50 °C */ /* Turn off device regulators etc after 5 seconds of inactivity */ #define YAS5XX_AUTOSUSPEND_DELAY_MS 5000 @@ -131,6 +129,14 @@ struct yas5xx; * @volatile_reg: device-specific volatile registers * @volatile_reg_qty: quantity of device-specific volatile registers * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE + * @t_ref: number of counts at reference temperature 20 °C + * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius + * + * The "t_ref" value for YAS532/533 is known from the Android driver. + * For YAS530 it was approximately measured. + * + * The temperatures "min_temp_x10" are derived from the temperature resolutions + * given in the data sheets. */ struct yas5xx_chip_info { unsigned int devid; @@ -139,6 +145,8 @@ struct yas5xx_chip_info { const int *volatile_reg; int volatile_reg_qty; u32 scaling_val2; + u16 t_ref; + s16 min_temp_x10; }; /** @@ -337,6 +345,22 @@ 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) +{ + const struct yas5xx_chip_info *ci = yas5xx->chip_info; + s32 to; + u16 t_ref; + s16 min_temp_x10; + int ref_temp_x10; + + t_ref = ci->t_ref; + min_temp_x10 = ci->min_temp_x10; + ref_temp_x10 = 200; + + to = (min_temp_x10 + ((ref_temp_x10 - min_temp_x10) * t / t_ref)) * 100; + return to; +} + /** * yas530_get_measure() - Measure a sample of all axis and process * @yas5xx: The device state @@ -352,7 +376,7 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, { const struct yas5xx_chip_info *ci = yas5xx->chip_info; 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; @@ -367,47 +391,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 (ci->devid) { - case YAS530_DEVICE_ID: - t_ref = YAS530_20DEGREES; - break; - case YAS532_DEVICE_ID: - t_ref = YAS532_20DEGREES; - break; - default: - dev_err(yas5xx->dev, "unknown device type\n"); - return -EINVAL; - } - - /* Temperature compensation for x, y1, y2 respectively */ + /* + * Set the temperature for compensation (unit: counts): + * YAS532/YAS533 version AC uses the temperature deviation as a + * multiplier. YAS530 and YAS532 version AB use solely the t value. + */ + t_ref = ci->t_ref; if (ci->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. @@ -415,36 +422,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 (ci->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: @@ -935,6 +914,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), .scaling_val2 = 100000000, /* picotesla to Gauss */ + .t_ref = 182, /* counts */ + .min_temp_x10 = -620, /* 1/10:s degrees Celsius */ }, [yas532] = { .devid = YAS532_DEVICE_ID, @@ -943,6 +924,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), .scaling_val2 = 100000, /* nanotesla to Gauss */ + .t_ref = 390, /* counts */ + .min_temp_x10 = -500, /* 1/10:s degrees Celsius */ }, [yas533] = { .devid = YAS532_DEVICE_ID, @@ -951,6 +934,8 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .volatile_reg = yas530_volatile_reg, .volatile_reg_qty = ARRAY_SIZE(yas530_volatile_reg), .scaling_val2 = 100000, /* nanotesla to Gauss */ + .t_ref = 390, /* counts */ + .min_temp_x10 = -500, /* 1/10:s degrees Celsius */ }, }; -- cgit v1.2.3 From 059ff0f9a10508c39f2c22d4144e88156bbf86ef Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sat, 13 Aug 2022 00:05:02 +0200 Subject: iio: magnetometer: yas530: Add function pointers to "chip_info" Add function pointers to the "chip_info" structure to ease the handling of different YAS variants. In the function yas5xx_probe(), the function call for "measure_offsets" was added as a conditional "if (ci->measure_offsets)". This is a preparatory step for YAS537, as this variant doesn't need an offset measurement. Signed-off-by: Jakob Hauser Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/4bd3f96262e0132b7f9720521a801da3c18abd95.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 66 ++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 24 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index a5d3f0bff024..18933d8937ae 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -131,6 +131,11 @@ struct yas5xx; * @scaling_val2: scaling value for IIO_CHAN_INFO_SCALE * @t_ref: number of counts at reference temperature 20 °C * @min_temp_x10: starting point of temperature counting in 1/10:s degrees Celsius + * @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 * * The "t_ref" value for YAS532/533 is known from the Android driver. * For YAS530 it was approximately measured. @@ -147,12 +152,17 @@ struct yas5xx_chip_info { u32 scaling_val2; u16 t_ref; s16 min_temp_x10; + 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 - * @chip_info: device-specific data + * @chip_info: device-specific data and function pointers * @version: device version * @calibration: calibration settings from the OTP storage * @hard_offsets: offsets for each axis measured with initcoil actuated @@ -461,7 +471,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 = yas530_get_measure(yas5xx, &t, &x, &y, &z); + ret = ci->get_measure(yas5xx, &t, &x, &y, &z); pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) @@ -497,11 +507,12 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev, static void yas5xx_fill_buffer(struct iio_dev *indio_dev) { struct yas5xx *yas5xx = iio_priv(indio_dev); + const struct yas5xx_chip_info *ci = yas5xx->chip_info; s32 t, x, y, z; int ret; pm_runtime_get_sync(yas5xx->dev); - ret = yas530_get_measure(yas5xx, &t, &x, &y, &z); + ret = ci->get_measure(yas5xx, &t, &x, &y, &z); pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) { @@ -916,6 +927,11 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .scaling_val2 = 100000000, /* picotesla to Gauss */ .t_ref = 182, /* counts */ .min_temp_x10 = -620, /* 1/10:s degrees Celsius */ + .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, @@ -926,6 +942,11 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .scaling_val2 = 100000, /* nanotesla to Gauss */ .t_ref = 390, /* counts */ .min_temp_x10 = -500, /* 1/10:s degrees Celsius */ + .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, @@ -936,6 +957,11 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .scaling_val2 = 100000, /* nanotesla to Gauss */ .t_ref = 390, /* counts */ .min_temp_x10 = -500, /* 1/10:s degrees Celsius */ + .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, }, }; @@ -1007,34 +1033,25 @@ static int yas5xx_probe(struct i2c_client *i2c, goto assert_reset; } - switch (ci->devid) { - case YAS530_DEVICE_ID: - ret = yas530_get_calibration_data(yas5xx); - if (ret) - goto assert_reset; - break; - case YAS532_DEVICE_ID: - ret = yas532_get_calibration_data(yas5xx); - if (ret) - goto assert_reset; - break; - default: - ret = -ENODEV; - dev_err(dev, "unhandled device ID %02x\n", ci->devid); + ret = ci->get_calibration_data(yas5xx); + if (ret) goto assert_reset; - } dev_info(dev, "detected %s %s\n", ci->product_name, ci->version_names[yas5xx->version]); - yas530_dump_calibration(yas5xx); - ret = yas530_power_on(yas5xx); - if (ret) - goto assert_reset; - ret = yas530_measure_offsets(yas5xx); + ci->dump_calibration(yas5xx); + + ret = ci->power_on(yas5xx); if (ret) goto assert_reset; + if (ci->measure_offsets) { + ret = ci->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; @@ -1114,6 +1131,7 @@ static int yas5xx_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct yas5xx *yas5xx = iio_priv(indio_dev); + const struct yas5xx_chip_info *ci = yas5xx->chip_info; int ret; ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs); @@ -1130,7 +1148,7 @@ static int yas5xx_runtime_resume(struct device *dev) usleep_range(31000, 40000); gpiod_set_value_cansleep(yas5xx->reset, 0); - ret = yas530_power_on(yas5xx); + ret = ci->power_on(yas5xx); if (ret) { dev_err(dev, "cannot power on\n"); goto out_reset; -- cgit v1.2.3 From 65f79b501030678393eae0ae03d60a8151fbef55 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sat, 13 Aug 2022 00:05:03 +0200 Subject: iio: magnetometer: yas530: Add YAS537 variant Add 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 the 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 Signed-off-by: Jakob Hauser Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/264c6488733a5c32089c9ab406a5bcb808c48fef.1660337264.git.jahau@rocketmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/Kconfig | 4 +- drivers/iio/magnetometer/yamaha-yas530.c | 422 ++++++++++++++++++++++++++++++- 2 files changed, 423 insertions(+), 3 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 07eb619bcfe8..b91fc5e6a26e 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -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 diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 18933d8937ae..65bb34c24810 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -17,6 +17,9 @@ * named "inv_compass" in the Tegra Android kernel tree. * Copyright (C) 2012 InvenSense Corporation * + * Code functions for YAS537 based on Yamaha Android kernel driver. + * Copyright (c) 2014 Yamaha Corporation + * * Author: Linus Walleij */ #include @@ -32,6 +35,7 @@ #include #include #include +#include #include #include @@ -56,6 +60,23 @@ #define YAS530_TEST2 0x89 #define YAS530_CAL 0x90 +/* Registers used by YAS537 */ +#define YAS537_MEASURE 0x81 /* Originally YAS537_REG_CMDR */ +#define YAS537_CONFIG 0x82 /* Originally YAS537_REG_CONFR */ +#define YAS537_MEASURE_INTERVAL 0x83 /* Originally YAS537_REG_INTRVLR */ +#define YAS537_OFFSET_X 0x84 /* Originally YAS537_REG_OXR */ +#define YAS537_OFFSET_Y1 0x85 /* Originally YAS537_REG_OY1R */ +#define YAS537_OFFSET_Y2 0x86 /* Originally YAS537_REG_OY2R */ +#define YAS537_AVR 0x87 +#define YAS537_HCK 0x88 +#define YAS537_LCK 0x89 +#define YAS537_SRST 0x90 +#define YAS537_ADCCAL 0x91 +#define YAS537_MTC 0x93 +#define YAS537_OC 0x9E +#define YAS537_TRM 0x9F +#define YAS537_CAL 0xC0 + /* Bits in the YAS5xx config register */ #define YAS5XX_CONFIG_INTON BIT(0) /* Interrupt on? */ #define YAS5XX_CONFIG_INTHACT BIT(1) /* Interrupt active high? */ @@ -67,6 +88,7 @@ #define YAS5XX_MEASURE_LDTC BIT(1) #define YAS5XX_MEASURE_FORS BIT(2) #define YAS5XX_MEASURE_DLYMES BIT(4) +#define YAS5XX_MEASURE_CONT BIT(5) /* Bits in the measure data register */ #define YAS5XX_MEASURE_DATA_BUSY BIT(7) @@ -91,6 +113,22 @@ #define YAS532_DATA_CENTER BIT(YAS532_DATA_BITS - 1) #define YAS532_DATA_OVERFLOW (BIT(YAS532_DATA_BITS) - 1) +#define YAS537_DEVICE_ID 0x07 /* YAS537 (MS-3T) */ +#define YAS537_VERSION_0 0 /* Version naming unknown */ +#define YAS537_VERSION_1 1 /* Version naming unknown */ +#define YAS537_MAG_AVERAGE_32_MASK GENMASK(6, 4) +#define YAS537_MEASURE_TIME_WORST_US 1500 +#define YAS537_DEFAULT_SENSOR_DELAY_MS 50 +#define YAS537_MAG_RCOIL_TIME_US 65 +#define YAS537_MTC3_MASK_PREP GENMASK(7, 0) +#define YAS537_MTC3_MASK_GET GENMASK(7, 5) +#define YAS537_MTC3_ADD_BIT BIT(4) +#define YAS537_HCK_MASK_PREP GENMASK(4, 0) +#define YAS537_HCK_MASK_GET GENMASK(7, 4) +#define YAS537_LCK_MASK_PREP GENMASK(4, 0) +#define YAS537_LCK_MASK_GET GENMASK(3, 0) +#define YAS537_OC_MASK_GET GENMASK(5, 0) + /* Turn off device regulators etc after 5 seconds of inactivity */ #define YAS5XX_AUTOSUSPEND_DELAY_MS 5000 @@ -98,6 +136,7 @@ enum chip_ids { yas530, yas532, yas533, + yas537, }; static const int yas530_volatile_reg[] = { @@ -105,6 +144,10 @@ static const int yas530_volatile_reg[] = { YAS530_MEASURE, }; +static const int yas537_volatile_reg[] = { + YAS537_MEASURE, +}; + struct yas5xx_calibration { /* Linearization calibration x, y1, y2 */ s32 r[3]; @@ -138,7 +181,7 @@ struct yas5xx; * @power_on: function pointer to power-on procedure * * The "t_ref" value for YAS532/533 is known from the Android driver. - * For YAS530 it was approximately measured. + * For YAS530 and YAS537 it was approximately measured. * * The temperatures "min_temp_x10" are derived from the temperature resolutions * given in the data sheets. @@ -312,6 +355,77 @@ out_unlock: return ret; } +/** + * yas537_measure() - Make a measure from the hardware + * @yas5xx: The device state + * @t: the raw temperature measurement + * @x: the raw x axis measurement + * @y1: the y1 axis measurement + * @y2: the y2 axis measurement + * @return: 0 on success or error code + */ +static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y2) +{ + struct yas5xx_calibration *c = &yas5xx->calibration; + unsigned int busy; + u8 data[8]; + u16 xy1y2[3]; + s32 h[3], s[3]; + int i, ret; + + mutex_lock(&yas5xx->lock); + + /* Contrary to YAS530/532, also a "cont" bit is set, meaning unknown */ + ret = regmap_write(yas5xx->map, YAS537_MEASURE, YAS5XX_MEASURE_START | + YAS5XX_MEASURE_CONT); + if (ret < 0) + goto out_unlock; + + /* Use same timeout like YAS530/532 but the bit is in data row 2 */ + ret = regmap_read_poll_timeout(yas5xx->map, YAS5XX_MEASURE_DATA + 2, busy, + !(busy & YAS5XX_MEASURE_DATA_BUSY), + 500, 20000); + if (ret) { + dev_err(yas5xx->dev, "timeout waiting for measurement\n"); + goto out_unlock; + } + + ret = regmap_bulk_read(yas5xx->map, YAS5XX_MEASURE_DATA, + data, sizeof(data)); + if (ret) + goto out_unlock; + + mutex_unlock(&yas5xx->lock); + + *t = get_unaligned_be16(&data[0]); + xy1y2[0] = FIELD_GET(GENMASK(13, 0), get_unaligned_be16(&data[2])); + xy1y2[1] = get_unaligned_be16(&data[4]); + xy1y2[2] = get_unaligned_be16(&data[6]); + + /* The second version of YAS537 needs to include calibration coefficients */ + if (yas5xx->version == YAS537_VERSION_1) { + for (i = 0; i < 3; i++) + s[i] = xy1y2[i] - BIT(13); + h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13); + h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13); + h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13); + for (i = 0; i < 3; i++) { + clamp_val(h[i], -BIT(13), BIT(13) - 1); + xy1y2[i] = h[i] + BIT(13); + } + } + + *x = xy1y2[0]; + *y1 = xy1y2[1]; + *y2 = xy1y2[2]; + + return 0; + +out_unlock: + mutex_unlock(&yas5xx->lock); + return ret; +} + /* Used by YAS530, YAS532 and YAS533 */ static s32 yas530_linearize(struct yas5xx *yas5xx, u16 val, int axis) { @@ -457,6 +571,41 @@ static int yas530_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, return 0; } +/** + * yas537_get_measure() - Measure a sample of all axis and process + * @yas5xx: The device state + * @to: Temperature out + * @xo: X axis out + * @yo: Y axis out + * @zo: Z axis out + * @return: 0 on success or error code + */ +static int yas537_get_measure(struct yas5xx *yas5xx, s32 *to, s32 *xo, s32 *yo, s32 *zo) +{ + u16 t, x, y1, y2; + int ret; + + /* We first get raw data that needs to be translated to [x,y,z] */ + ret = yas537_measure(yas5xx, &t, &x, &y1, &y2); + if (ret) + return ret; + + /* Calculate temperature readout */ + *to = yas5xx_calc_temperature(yas5xx, t); + + /* + * Unfortunately, no linearization or temperature compensation formulas + * are known for YAS537. + */ + + /* Calculate x, y, z from x, y1, y2 */ + *xo = (x - BIT(13)) * 300; + *yo = (y1 - y2) * 1732 / 10; + *zo = (-y1 - y2 + BIT(14)) * 300; + + return 0; +} + static int yas5xx_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, @@ -772,6 +921,202 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx) return 0; } +static int yas537_get_calibration_data(struct yas5xx *yas5xx) +{ + struct yas5xx_calibration *c = &yas5xx->calibration; + u8 data[17]; + u32 val1, val2, val3, val4; + int i, ret; + + /* Writing SRST register */ + ret = regmap_write(yas5xx->map, YAS537_SRST, BIT(1)); + if (ret) + return ret; + + /* Calibration readout, YAS537 needs one readout only */ + ret = regmap_bulk_read(yas5xx->map, YAS537_CAL, data, sizeof(data)); + if (ret) + return ret; + dev_dbg(yas5xx->dev, "calibration data: %17ph\n", data); + + /* Sanity check, is this all zeroes? */ + if (!memchr_inv(data, 0x00, 16) && !FIELD_GET(GENMASK(5, 0), data[16])) + dev_warn(yas5xx->dev, "calibration is blank!\n"); + + /* Contribute calibration data to the input pool for kernel entropy */ + add_device_randomness(data, sizeof(data)); + + /* Extract version information */ + yas5xx->version = FIELD_GET(GENMASK(7, 6), data[16]); + + /* There are two versions of YAS537 behaving differently */ + switch (yas5xx->version) { + case YAS537_VERSION_0: + /* + * The first version simply writes data back into registers: + * + * data[0] YAS537_MTC 0x93 + * data[1] 0x94 + * data[2] 0x95 + * data[3] 0x96 + * data[4] 0x97 + * data[5] 0x98 + * data[6] 0x99 + * data[7] 0x9a + * data[8] 0x9b + * data[9] 0x9c + * data[10] 0x9d + * data[11] YAS537_OC 0x9e + * + * data[12] YAS537_OFFSET_X 0x84 + * data[13] YAS537_OFFSET_Y1 0x85 + * data[14] YAS537_OFFSET_Y2 0x86 + * + * data[15] YAS537_HCK 0x88 + * data[16] YAS537_LCK 0x89 + */ + for (i = 0; i < 12; i++) { + ret = regmap_write(yas5xx->map, YAS537_MTC + i, + data[i]); + if (ret) + return ret; + } + for (i = 0; i < 3; i++) { + ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i, + data[i + 12]); + if (ret) + return ret; + yas5xx->hard_offsets[i] = data[i + 12]; + } + for (i = 0; i < 2; i++) { + ret = regmap_write(yas5xx->map, YAS537_HCK + i, + data[i + 15]); + if (ret) + return ret; + } + break; + case YAS537_VERSION_1: + /* + * The second version writes some data into registers but also + * extracts calibration coefficients. + * + * Registers being written: + * + * data[0] YAS537_MTC 0x93 + * data[1] YAS537_MTC+1 0x94 + * data[2] YAS537_MTC+2 0x95 + * data[3] YAS537_MTC+3 (partially) 0x96 + * + * data[12] YAS537_OFFSET_X 0x84 + * data[13] YAS537_OFFSET_Y1 0x85 + * data[14] YAS537_OFFSET_Y2 0x86 + * + * data[15] YAS537_HCK (partially) 0x88 + * YAS537_LCK (partially) 0x89 + * data[16] YAS537_OC (partially) 0x9e + */ + for (i = 0; i < 3; i++) { + ret = regmap_write(yas5xx->map, YAS537_MTC + i, + data[i]); + if (ret) + return ret; + } + for (i = 0; i < 3; i++) { + ret = regmap_write(yas5xx->map, YAS537_OFFSET_X + i, + data[i + 12]); + if (ret) + return ret; + yas5xx->hard_offsets[i] = data[i + 12]; + } + /* + * Visualization of partially taken data: + * + * data[3] n 7 6 5 4 3 2 1 0 + * YAS537_MTC+3 x x x 1 0 0 0 0 + * + * data[15] n 7 6 5 4 3 2 1 0 + * YAS537_HCK x x x x 0 + * + * data[15] n 7 6 5 4 3 2 1 0 + * YAS537_LCK x x x x 0 + * + * data[16] n 7 6 5 4 3 2 1 0 + * YAS537_OC x x x x x x + */ + ret = regmap_write(yas5xx->map, YAS537_MTC + 3, + FIELD_PREP(YAS537_MTC3_MASK_PREP, + FIELD_GET(YAS537_MTC3_MASK_GET, data[3])) | + YAS537_MTC3_ADD_BIT); + if (ret) + return ret; + ret = regmap_write(yas5xx->map, YAS537_HCK, + FIELD_PREP(YAS537_HCK_MASK_PREP, + FIELD_GET(YAS537_HCK_MASK_GET, data[15]))); + if (ret) + return ret; + ret = regmap_write(yas5xx->map, YAS537_LCK, + FIELD_PREP(YAS537_LCK_MASK_PREP, + FIELD_GET(YAS537_LCK_MASK_GET, data[15]))); + if (ret) + return ret; + ret = regmap_write(yas5xx->map, YAS537_OC, + FIELD_GET(YAS537_OC_MASK_GET, data[16])); + if (ret) + return ret; + /* + * For data extraction, build some blocks. Four 32-bit blocks + * look appropriate. + * + * n 7 6 5 4 3 2 1 0 + * data[0] 0 [ Cx Cx Cx Cx Cx Cx Cx Cx ] bits 31 .. 24 + * data[1] 1 [ Cx C1 C1 C1 C1 C1 C1 C1 ] bits 23 .. 16 + * data[2] 2 [ C1 C1 C2 C2 C2 C2 C2 C2 ] bits 15 .. 8 + * data[3] 3 [ C2 C2 C2 ] bits 7 .. 0 + * + * n 7 6 5 4 3 2 1 0 + * data[3] 0 [ a2 a2 a2 a2 a2 ] bits 31 .. 24 + * data[4] 1 [ a2 a2 a3 a3 a3 a3 a3 a3 ] bits 23 .. 16 + * data[5] 2 [ a3 a4 a4 a4 a4 a4 a4 a4 ] bits 15 .. 8 + * data[6] 3 [ a4 ] bits 7 .. 0 + * + * n 7 6 5 4 3 2 1 0 + * data[6] 0 [ a5 a5 a5 a5 a5 a5 a5 ] bits 31 .. 24 + * data[7] 1 [ a5 a5 a6 a6 a6 a6 a6 a6 ] bits 23 .. 16 + * data[8] 2 [ a6 a7 a7 a7 a7 a7 a7 a7 ] bits 15 .. 8 + * data[9] 3 [ a7 ] bits 7 .. 0 + * + * n 7 6 5 4 3 2 1 0 + * data[9] 0 [ a8 a8 a8 a8 a8 a8 a8 ] bits 31 .. 24 + * data[10] 1 [ a9 a9 a9 a9 a9 a9 a9 a9 ] bits 23 .. 16 + * data[11] 2 [ a9 k k k k k k k ] bits 15 .. 8 + * data[12] 3 [ ] bits 7 .. 0 + */ + val1 = get_unaligned_be32(&data[0]); + val2 = get_unaligned_be32(&data[3]); + val3 = get_unaligned_be32(&data[6]); + val4 = get_unaligned_be32(&data[9]); + /* Extract calibration coefficients and modify */ + c->Cx = FIELD_GET(GENMASK(31, 23), val1) - 256; + c->Cy1 = FIELD_GET(GENMASK(22, 14), val1) - 256; + c->Cy2 = FIELD_GET(GENMASK(13, 5), val1) - 256; + c->a2 = FIELD_GET(GENMASK(28, 22), val2) - 64; + c->a3 = FIELD_GET(GENMASK(21, 15), val2) - 64; + c->a4 = FIELD_GET(GENMASK(14, 7), val2) - 128; + c->a5 = FIELD_GET(GENMASK(30, 22), val3) - 112; + c->a6 = FIELD_GET(GENMASK(21, 15), val3) - 64; + c->a7 = FIELD_GET(GENMASK(14, 7), val3) - 128; + c->a8 = FIELD_GET(GENMASK(30, 24), val4) - 64; + c->a9 = FIELD_GET(GENMASK(23, 15), val4) - 112; + c->k = FIELD_GET(GENMASK(14, 8), val4); + break; + default: + dev_err(yas5xx->dev, "unknown version of YAS537\n"); + return -EINVAL; + } + + return 0; +} + /* Used by YAS530, YAS532 and YAS533 */ static void yas530_dump_calibration(struct yas5xx *yas5xx) { @@ -796,6 +1141,26 @@ static void yas530_dump_calibration(struct yas5xx *yas5xx) dev_dbg(yas5xx->dev, "dck = %d\n", c->dck); } +static void yas537_dump_calibration(struct yas5xx *yas5xx) +{ + struct yas5xx_calibration *c = &yas5xx->calibration; + + if (yas5xx->version == YAS537_VERSION_1) { + dev_dbg(yas5xx->dev, "Cx = %d\n", c->Cx); + dev_dbg(yas5xx->dev, "Cy1 = %d\n", c->Cy1); + dev_dbg(yas5xx->dev, "Cy2 = %d\n", c->Cy2); + dev_dbg(yas5xx->dev, "a2 = %d\n", c->a2); + dev_dbg(yas5xx->dev, "a3 = %d\n", c->a3); + dev_dbg(yas5xx->dev, "a4 = %d\n", c->a4); + dev_dbg(yas5xx->dev, "a5 = %d\n", c->a5); + dev_dbg(yas5xx->dev, "a6 = %d\n", c->a6); + dev_dbg(yas5xx->dev, "a7 = %d\n", c->a7); + dev_dbg(yas5xx->dev, "a8 = %d\n", c->a8); + dev_dbg(yas5xx->dev, "a9 = %d\n", c->a9); + dev_dbg(yas5xx->dev, "k = %d\n", c->k); + } +} + /* Used by YAS530, YAS532 and YAS533 */ static int yas530_set_offsets(struct yas5xx *yas5xx, s8 ox, s8 oy1, s8 oy2) { @@ -917,6 +1282,44 @@ static int yas530_power_on(struct yas5xx *yas5xx) return regmap_write(yas5xx->map, YAS530_MEASURE_INTERVAL, 0); } +static int yas537_power_on(struct yas5xx *yas5xx) +{ + __be16 buf; + int ret; + u8 intrvl; + + /* Writing ADCCAL and TRM registers */ + buf = cpu_to_be16(GENMASK(9, 3)); + ret = regmap_bulk_write(yas5xx->map, YAS537_ADCCAL, &buf, sizeof(buf)); + if (ret) + return ret; + ret = regmap_write(yas5xx->map, YAS537_TRM, GENMASK(7, 0)); + if (ret) + return ret; + + /* The interval value is static in regular operation */ + intrvl = (YAS537_DEFAULT_SENSOR_DELAY_MS * MILLI + - YAS537_MEASURE_TIME_WORST_US) / 4100; + ret = regmap_write(yas5xx->map, YAS537_MEASURE_INTERVAL, intrvl); + if (ret) + return ret; + + /* The average value is also static in regular operation */ + ret = regmap_write(yas5xx->map, YAS537_AVR, YAS537_MAG_AVERAGE_32_MASK); + if (ret) + return ret; + + /* Perform the "rcoil" part but skip the "last_after_rcoil" read */ + ret = regmap_write(yas5xx->map, YAS537_CONFIG, BIT(3)); + if (ret) + return ret; + + /* Wait until the coil has ramped up */ + usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100); + + return 0; +} + static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { [yas530] = { .devid = YAS530_DEVICE_ID, @@ -963,6 +1366,21 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { .measure_offsets = yas530_measure_offsets, .power_on = yas530_power_on, }, + [yas537] = { + .devid = YAS537_DEVICE_ID, + .product_name = "YAS537 MS-3T", + .version_names = { "v0", "v1" }, /* version naming unknown */ + .volatile_reg = yas537_volatile_reg, + .volatile_reg_qty = ARRAY_SIZE(yas537_volatile_reg), + .scaling_val2 = 100000, /* nanotesla to Gauss */ + .t_ref = 8120, /* counts */ + .min_temp_x10 = -3860, /* 1/10:s degrees Celsius */ + .get_measure = yas537_get_measure, + .get_calibration_data = yas537_get_calibration_data, + .dump_calibration = yas537_dump_calibration, + /* .measure_offets is not needed for yas537 */ + .power_on = yas537_power_on, + }, }; static int yas5xx_probe(struct i2c_client *i2c, @@ -1170,6 +1588,7 @@ static const struct i2c_device_id yas5xx_id[] = { {"yas530", yas530 }, {"yas532", yas532 }, {"yas533", yas533 }, + {"yas537", yas537 }, {} }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); @@ -1178,6 +1597,7 @@ static const struct of_device_id yas5xx_of_match[] = { { .compatible = "yamaha,yas530", }, { .compatible = "yamaha,yas532", }, { .compatible = "yamaha,yas533", }, + { .compatible = "yamaha,yas537", }, {} }; MODULE_DEVICE_TABLE(of, yas5xx_of_match); -- cgit v1.2.3 From 741d1e3783d9486d76534f2f08442e1f0eb108a1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Aug 2022 17:15:28 +0300 Subject: iio: magnetometer: yamaha-yas530: Use pointers as driver data Unify ID tables to use pointers for driver data. It will allow to simplify the driver later on. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220831141530.80572-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 65bb34c24810..533fd8c73024 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1437,8 +1438,10 @@ static int yas5xx_probe(struct i2c_client *i2c, goto assert_reset; } - yas5xx->chip_info = &yas5xx_chip_info_tbl[id->driver_data]; - ci = yas5xx->chip_info; + ci = device_get_match_data(dev); + if (!ci) + ci = (const struct yas5xx_chip_info *)id->driver_data; + yas5xx->chip_info = ci; ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check); if (ret) @@ -1585,19 +1588,19 @@ static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend, yas5xx_runtime_resume, NULL); static const struct i2c_device_id yas5xx_id[] = { - {"yas530", yas530 }, - {"yas532", yas532 }, - {"yas533", yas533 }, - {"yas537", yas537 }, + {"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] }, + {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, + {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, + {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, {} }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); static const struct of_device_id yas5xx_of_match[] = { - { .compatible = "yamaha,yas530", }, - { .compatible = "yamaha,yas532", }, - { .compatible = "yamaha,yas533", }, - { .compatible = "yamaha,yas537", }, + { .compatible = "yamaha,yas530", &yas5xx_chip_info_tbl[yas530] }, + { .compatible = "yamaha,yas532", &yas5xx_chip_info_tbl[yas532] }, + { .compatible = "yamaha,yas533", &yas5xx_chip_info_tbl[yas533] }, + { .compatible = "yamaha,yas537", &yas5xx_chip_info_tbl[yas537] }, {} }; MODULE_DEVICE_TABLE(of, yas5xx_of_match); -- cgit v1.2.3 From ff1c17e9a7623f73aa44c605a5e6a4396df46a5e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Aug 2022 17:15:29 +0300 Subject: iio: magnetometer: yamaha-yas530: Make strings const in chip info For better compiler coverage mark strings consts in the chip info. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220831141530.80572-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 533fd8c73024..c56c7c9efeb8 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -189,8 +189,8 @@ struct yas5xx; */ struct yas5xx_chip_info { unsigned int devid; - char *product_name; - char *version_names[2]; + const char *product_name; + const char *version_names[2]; const int *volatile_reg; int volatile_reg_qty; u32 scaling_val2; -- cgit v1.2.3 From d05d73779145f6d1addc10b516f589f803fcdb56 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Aug 2022 17:15:30 +0300 Subject: iio: magnetometer: yamaha-yas530: Use dev_err_probe() Unify error message format by using dev_err_probe(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220831141530.80572-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/iio/magnetometer') diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index c56c7c9efeb8..fdb92a6420e1 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1415,10 +1415,8 @@ static int yas5xx_probe(struct i2c_client *i2c, return dev_err_probe(dev, ret, "cannot get regulators\n"); ret = regulator_bulk_enable(ARRAY_SIZE(yas5xx->regs), yas5xx->regs); - if (ret) { - dev_err(dev, "cannot enable regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "cannot enable regulators\n"); /* See comment in runtime resume callback */ usleep_range(31000, 40000); @@ -1426,15 +1424,13 @@ static int yas5xx_probe(struct i2c_client *i2c, /* This will take the device out of reset if need be */ yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(yas5xx->reset)) { - ret = dev_err_probe(dev, PTR_ERR(yas5xx->reset), - "failed to get reset line\n"); + ret = dev_err_probe(dev, PTR_ERR(yas5xx->reset), "failed to get reset line\n"); goto reg_off; } yas5xx->map = devm_regmap_init_i2c(i2c, &yas5xx_regmap_config); if (IS_ERR(yas5xx->map)) { - dev_err(dev, "failed to allocate register map\n"); - ret = PTR_ERR(yas5xx->map); + ret = dev_err_probe(dev, PTR_ERR(yas5xx->map), "failed to allocate register map\n"); goto assert_reset; } @@ -1484,13 +1480,13 @@ static int yas5xx_probe(struct i2c_client *i2c, yas5xx_handle_trigger, NULL); if (ret) { - dev_err(dev, "triggered buffer setup failed\n"); + dev_err_probe(dev, ret, "triggered buffer setup failed\n"); goto assert_reset; } ret = iio_device_register(indio_dev); if (ret) { - dev_err(dev, "device register failed\n"); + dev_err_probe(dev, ret, "device register failed\n"); goto cleanup_buffer; } -- cgit v1.2.3