]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/iio/inkern.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
[karo-tx-linux.git] / drivers / iio / inkern.c
index b5afc2ff34fd5c5f58d0c83e3d1538a3d901acac..f2b78d4fe45778d01f05a97eb1e3a9b1bc8164e4 100644 (file)
@@ -111,6 +111,7 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
 {
        struct iio_map_internal *c_i = NULL, *c = NULL;
        struct iio_channel *channel;
+       int err;
 
        if (name == NULL && channel_name == NULL)
                return ERR_PTR(-ENODEV);
@@ -130,18 +131,32 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
        if (c == NULL)
                return ERR_PTR(-ENODEV);
 
-       channel = kmalloc(sizeof(*channel), GFP_KERNEL);
-       if (channel == NULL)
-               return ERR_PTR(-ENOMEM);
+       channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+       if (channel == NULL) {
+               err = -ENOMEM;
+               goto error_no_mem;
+       }
 
        channel->indio_dev = c->indio_dev;
 
-       if (c->map->adc_channel_label)
+       if (c->map->adc_channel_label) {
                channel->channel =
                        iio_chan_spec_from_name(channel->indio_dev,
                                                c->map->adc_channel_label);
 
+               if (channel->channel == NULL) {
+                       err = -EINVAL;
+                       goto error_no_chan;
+               }
+       }
+
        return channel;
+
+error_no_chan:
+       kfree(channel);
+error_no_mem:
+       iio_device_put(c->indio_dev);
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iio_channel_get);
 
@@ -229,9 +244,21 @@ void iio_channel_release_all(struct iio_channel *channels)
 }
 EXPORT_SYMBOL_GPL(iio_channel_release_all);
 
+static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
+       enum iio_chan_info_enum info)
+{
+       int unused;
+
+       if (val2 == NULL)
+               val2 = &unused;
+
+       return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
+                                               val, val2, info);
+}
+
 int iio_read_channel_raw(struct iio_channel *chan, int *val)
 {
-       int val2, ret;
+       int ret;
 
        mutex_lock(&chan->indio_dev->info_exist_lock);
        if (chan->indio_dev->info == NULL) {
@@ -239,8 +266,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
                goto err_unlock;
        }
 
-       ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
-                                             val, &val2, 0);
+       ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
 err_unlock:
        mutex_unlock(&chan->indio_dev->info_exist_lock);
 
@@ -248,6 +274,100 @@ err_unlock:
 }
 EXPORT_SYMBOL_GPL(iio_read_channel_raw);
 
+static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
+       int raw, int *processed, unsigned int scale)
+{
+       int scale_type, scale_val, scale_val2, offset;
+       s64 raw64 = raw;
+       int ret;
+
+       ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE);
+       if (ret == 0)
+               raw64 += offset;
+
+       scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
+                                       IIO_CHAN_INFO_SCALE);
+       if (scale_type < 0)
+               return scale_type;
+
+       switch (scale_type) {
+       case IIO_VAL_INT:
+               *processed = raw64 * scale_val;
+               break;
+       case IIO_VAL_INT_PLUS_MICRO:
+               if (scale_val2 < 0)
+                       *processed = -raw64 * scale_val;
+               else
+                       *processed = raw64 * scale_val;
+               *processed += div_s64(raw64 * (s64)scale_val2 * scale,
+                                     1000000LL);
+               break;
+       case IIO_VAL_INT_PLUS_NANO:
+               if (scale_val2 < 0)
+                       *processed = -raw64 * scale_val;
+               else
+                       *processed = raw64 * scale_val;
+               *processed += div_s64(raw64 * (s64)scale_val2 * scale,
+                                     1000000000LL);
+               break;
+       case IIO_VAL_FRACTIONAL:
+               *processed = div_s64(raw64 * (s64)scale_val * scale,
+                                    scale_val2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
+       int *processed, unsigned int scale)
+{
+       int ret;
+
+       mutex_lock(&chan->indio_dev->info_exist_lock);
+       if (chan->indio_dev->info == NULL) {
+               ret = -ENODEV;
+               goto err_unlock;
+       }
+
+       ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
+                                                       scale);
+err_unlock:
+       mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
+
+int iio_read_channel_processed(struct iio_channel *chan, int *val)
+{
+       int ret;
+
+       mutex_lock(&chan->indio_dev->info_exist_lock);
+       if (chan->indio_dev->info == NULL) {
+               ret = -ENODEV;
+               goto err_unlock;
+       }
+
+       if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
+               ret = iio_channel_read(chan, val, NULL,
+                                      IIO_CHAN_INFO_PROCESSED);
+       } else {
+               ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
+               if (ret < 0)
+                       goto err_unlock;
+               ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
+       }
+
+err_unlock:
+       mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_processed);
+
 int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
 {
        int ret;
@@ -258,10 +378,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
                goto err_unlock;
        }
 
-       ret = chan->indio_dev->info->read_raw(chan->indio_dev,
-                                             chan->channel,
-                                             val, val2,
-                                             IIO_CHAN_INFO_SCALE);
+       ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE);
 err_unlock:
        mutex_unlock(&chan->indio_dev->info_exist_lock);