Saturday, 29 June 2013

Adding Scaled values to the ADC driver within the IIO Subsystem

For the 3.8 tree for BBB, the bone-helper module tries to assist and provide voltage values scaled to 1.8V as limited by the AVDD in the BBB.

However, this is a clumsy hack.
I looked around IIO and other drivers and found that the subsystem supported scaled voltage values. The bone-helper was a workaround to fix the ADC drivers and get scaled values.

I used the IIO Simple driver document to trace and see how scaled values are implemented. And added the required code to the ADC driver.

Preliminary tests show that it runs correctly. :)

Previously there would only be /sys/bus/iio/device/iio:device0/in_voltageX_raw.
Now we see in_voltageX_scale as well :)

I still need to test /dev/iio soon. I haven't touched the adc driver from userspace c applications yet. hopefully they'll work as the sysfs interface works.

I have tried to test the touchscreen with evtest. However, I haven't actually set up the hardware required for it. Connecting ground did register triggers in evtest so I'm hoping it hasn't broken.

I'll look into seeing if I can keep bone-helper so that I don't disturb a bunch of people and capes by this update.
And /dev entries as well..



The patch looks like this.
The last one on

From 26aa738a0394e39889b4515dde5e2baf99118141 Mon Sep 17 00:00:00 2001
From: ZubairLK <zubairlk@zubairlk-HP-G62-Notebook-PC.(none)>
Date: Sat, 29 Jun 2013 19:05:54 +0100
Subject: [PATCH] Added iio_voltageX_scale

The bone-helper driver tried to display the voltage in the range 1800mV
which represents the actual ADC range of the BBB. This feature is available
in the IIO system. in_voltageX_raw points to unscaled raw values
which give the output of the ADC register directly.

in_voltageX_scale is supposed to give scaled voltages. This was
missing in the TI driver and has been added.
 drivers/iio/adc/ti_am335x_adc.c |   18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index f78d2c1..c030078 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -26,6 +26,7 @@
 #include <linux/of_device.h>
 #include <linux/iio/machine.h>
 #include <linux/iio/driver.h>
+#include <linux/math64.h>

 #include <linux/mfd/ti_am335x_tscadc.h>
 #include <linux/platform_data/ti_am335x_adc.h>
@@ -119,7 +120,8 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
         chan->type = IIO_VOLTAGE;
         chan->indexed = 1;
         chan->channel = adc_dev->channel_line[i];
-        chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+        chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT
+                                | IIO_CHAN_INFO_SCALE_SEPARATE_BIT;
         chan->datasheet_name = chan_name_ain[chan->channel];
         chan->scan_type.sign = 'u';
         chan->scan_type.realbits = 12;
@@ -189,7 +191,19 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
             *val = read;
+        switch (mask){
+            case IIO_CHAN_INFO_RAW : /*Do nothing. Above code works fine.*/
+                   break;       
+            case IIO_CHAN_INFO_SCALE : {
+                    /*12 Bit adc. Scale value for 1800mV AVDD. Ideally
+                    AVDD should come from DT.*/
+                    *val = div_u64( (u64)(*val) * 1800 , 4096);
+                    break;
+            }               
+            default: break;
+        }  
     if (found == false)
         return -EBUSY;
     return IIO_VAL_INT;


  1. Where you are using IIO_CHAN_INFO_SCALE, you should be using IIO_CHAN_INFO_PROCESSED instead. It will appear as a file in_voltageX_input.

    You can also use IIO_CHAN_INFO_SCALE, but it is just supposed to return the channel's scale factor. You should probably set chan->info_mask_shared_by_all to IIO_CHAN_INFO_SCALE_SEPARATE_BIT, since the scale factor is common to all channels.

    1. The IIO subsystem would have changed in the two years. These posts are quite old :)