@@ -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,