iio: magnetometer: ak8974: Break out measurement
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 20 Apr 2020 20:40:21 +0000 (22:40 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 3 May 2020 08:47:22 +0000 (09:47 +0100)
This breaks out the measurement code to its own function
so we can handle this without swirling it up with the
big switch() statement inside ak8974_read_raw().

Keep a local s16 helper variable for the signed value
coming out of the measurement before assigning it to the
integer *val. The local variable makes the code easier
to read and the compiler will optimize it if possible.

Cc: Nick Reitemeyer <nick.reitemeyer@web.de>
Cc: Stephan Gerhold <stephan@gerhold.net>
Reviewed-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/magnetometer/ak8974.c

index bbda572..71a879c 100644 (file)
@@ -554,47 +554,61 @@ static int ak8974_detect(struct ak8974 *ak8974)
        return 0;
 }
 
+static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address,
+                                 int *val)
+{
+       __le16 hw_values[3];
+       int ret;
+
+       pm_runtime_get_sync(&ak8974->i2c->dev);
+       mutex_lock(&ak8974->lock);
+
+       /*
+        * We read all axes and discard all but one, for optimized
+        * reading, use the triggered buffer.
+        */
+       ret = ak8974_trigmeas(ak8974);
+       if (ret)
+               goto out_unlock;
+       ret = ak8974_getresult(ak8974, hw_values);
+       if (ret)
+               goto out_unlock;
+       /*
+        * This explicit cast to (s16) is necessary as the measurement
+        * is done in 2's complement with positive and negative values.
+        * The follwing assignment to *val will then convert the signed
+        * s16 value to a signed int value.
+        */
+       *val = (s16)le16_to_cpu(hw_values[address]);
+out_unlock:
+       mutex_unlock(&ak8974->lock);
+       pm_runtime_mark_last_busy(&ak8974->i2c->dev);
+       pm_runtime_put_autosuspend(&ak8974->i2c->dev);
+
+       return ret;
+}
+
 static int ak8974_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2,
                           long mask)
 {
        struct ak8974 *ak8974 = iio_priv(indio_dev);
-       __le16 hw_values[3];
-       int ret = -EINVAL;
-
-       pm_runtime_get_sync(&ak8974->i2c->dev);
-       mutex_lock(&ak8974->lock);
+       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
                if (chan->address > 2) {
                        dev_err(&ak8974->i2c->dev, "faulty channel address\n");
-                       ret = -EIO;
-                       goto out_unlock;
+                       return -EIO;
                }
-               ret = ak8974_trigmeas(ak8974);
+               ret = ak8974_measure_channel(ak8974, chan->address, val);
                if (ret)
-                       goto out_unlock;
-               ret = ak8974_getresult(ak8974, hw_values);
-               if (ret)
-                       goto out_unlock;
-
-               /*
-                * We read all axes and discard all but one, for optimized
-                * reading, use the triggered buffer.
-                */
-               *val = (s16)le16_to_cpu(hw_values[chan->address]);
-
-               ret = IIO_VAL_INT;
+                       return ret;
+               return IIO_VAL_INT;
        }
 
- out_unlock:
-       mutex_unlock(&ak8974->lock);
-       pm_runtime_mark_last_busy(&ak8974->i2c->dev);
-       pm_runtime_put_autosuspend(&ak8974->i2c->dev);
-
-       return ret;
+       return -EINVAL;
 }
 
 static void ak8974_fill_buffer(struct iio_dev *indio_dev)