diff options
Diffstat (limited to 'drivers/staging/iio')
68 files changed, 5664 insertions, 1765 deletions
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c new file mode 100644 index 000000000000..df23aeb9d529 --- /dev/null +++ b/drivers/staging/iio/Documentation/generic_buffer.c @@ -0,0 +1,318 @@ +/* Industrialio buffer test code. + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device, pretty printing the result after appropriate + * conversion. + * + * Command line parameters + * generic_buffer -n <device_name> -t <trigger_name> + * If trigger name is not specified the program assumes you want a dataready + * trigger associated with the device and goes looking for it. + * + */ + +#include <unistd.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/dir.h> +#include <linux/types.h> +#include "iio_utils.h" + +const int buf_len = 128; +const int num_loops = 2; + +/** + * size_from_channelarray() - calculate the storage size of a scan + * @channels: the channel info array + * @num_channels: size of the channel info array + * + * Has the side effect of filling the channels[i].location values used + * in processing the buffer output. + **/ +int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +{ + int bytes = 0; + int i = 0; + while (i < num_channels) { + if (bytes % channels[i].bytes == 0) + channels[i].location = bytes; + else + channels[i].location = bytes - bytes%channels[i].bytes + + channels[i].bytes; + bytes = channels[i].location + channels[i].bytes; + i++; + } + return bytes; +} + +/** + * process_scan() - print out the values in SI units + * @data: pointer to the start of the scan + * @infoarray: information about the channels. Note + * size_from_channelarray must have been called first to fill the + * location offsets. + * @num_channels: the number of active channels + **/ +void process_scan(char *data, + struct iio_channel_info *infoarray, + int num_channels) +{ + int k; + for (k = 0; k < num_channels; k++) + switch (infoarray[k].bytes) { + /* only a few cases implemented so far */ + case 2: + if (infoarray[k].is_signed) { + int16_t val = *(int16_t *) + (data + + infoarray[k].location); + if ((val >> infoarray[k].bits_used) & 1) + val = (val & infoarray[k].mask) | + ~infoarray[k].mask; + printf("%05f ", ((float)val + + infoarray[k].offset)* + infoarray[k].scale); + } else { + uint16_t val = *(uint16_t *) + (data + + infoarray[k].location); + val = (val & infoarray[k].mask); + printf("%05f ", ((float)val + + infoarray[k].offset)* + infoarray[k].scale); + } + break; + case 8: + if (infoarray[k].is_signed) { + int64_t val = *(int64_t *) + (data + + infoarray[k].location); + if ((val >> infoarray[k].bits_used) & 1) + val = (val & infoarray[k].mask) | + ~infoarray[k].mask; + /* special case for timestamp */ + if (infoarray[k].scale == 1.0f && + infoarray[k].offset == 0.0f) + printf(" %lld", val); + else + printf("%05f ", ((float)val + + infoarray[k].offset)* + infoarray[k].scale); + } + break; + default: + break; + } + printf("\n"); +} + +int main(int argc, char **argv) +{ + int ret, c, i, j, toread; + + FILE *fp_ev; + int fp; + + int num_channels; + char *trigger_name = NULL, *device_name = NULL; + char *dev_dir_name, *buf_dir_name; + + int datardytrigger = 1; + char *data; + size_t read_size; + struct iio_event_data dat; + int dev_num, trig_num; + char *buffer_access, *buffer_event; + int scan_size; + + struct iio_channel_info *infoarray; + + while ((c = getopt(argc, argv, "t:n:")) != -1) { + switch (c) { + case 'n': + device_name = optarg; + break; + case 't': + trigger_name = optarg; + datardytrigger = 0; + break; + case '?': + return -1; + } + } + + /* Find the device requested */ + dev_num = find_type_by_name(device_name, "device"); + if (dev_num < 0) { + printf("Failed to find the %s\n", device_name); + ret = -ENODEV; + goto error_ret; + } + printf("iio device number being used is %d\n", dev_num); + + asprintf(&dev_dir_name, "%sdevice%d", iio_dir, dev_num); + if (trigger_name == NULL) { + /* + * Build the trigger name. If it is device associated it's + * name is <device_name>_dev[n] where n matches the device + * number found above + */ + ret = asprintf(&trigger_name, + "%s-dev%d", device_name, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + } + + /* Verify the trigger exists */ + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + printf("Failed to find the trigger %s\n", trigger_name); + ret = -ENODEV; + goto error_free_triggername; + } + printf("iio trigger number being used is %d\n", trig_num); + + /* + * Parse the files in scan_elements to identify what channels are + * present + */ + ret = build_channel_array(dev_dir_name, &infoarray, &num_channels); + if (ret) { + printf("Problem reading scan element information \n"); + goto error_free_triggername; + } + + /* + * Construct the directory name for the associated buffer. + * As we know that the lis3l02dq has only one buffer this may + * be built rather than found. + */ + ret = asprintf(&buf_dir_name, "%sdevice%d:buffer0", iio_dir, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_triggername; + } + printf("%s %s\n", dev_dir_name, trigger_name); + /* Set the device trigger to be the data rdy trigger found above */ + ret = write_sysfs_string_and_verify("trigger/current_trigger", + dev_dir_name, + trigger_name); + if (ret < 0) { + printf("Failed to write current_trigger file\n"); + goto error_free_buf_dir_name; + } + + /* Setup ring buffer parameters */ + ret = write_sysfs_int("length", buf_dir_name, buf_len); + if (ret < 0) + goto error_free_buf_dir_name; + + /* Enable the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 1); + if (ret < 0) + goto error_free_buf_dir_name; + scan_size = size_from_channelarray(infoarray, num_channels); + data = malloc(scan_size*buf_len); + if (!data) { + ret = -ENOMEM; + goto error_free_buf_dir_name; + } + + ret = asprintf(&buffer_access, + "/dev/device%d:buffer0:access0", + dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_data; + } + + ret = asprintf(&buffer_event, "/dev/device%d:buffer0:event0", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_buffer_access; + } + /* Attempt to open non blocking the access dev */ + fp = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fp == -1) { /*If it isn't there make the node */ + printf("Failed to open %s\n", buffer_access); + ret = -errno; + goto error_free_buffer_event; + } + /* Attempt to open the event access dev (blocking this time) */ + fp_ev = fopen(buffer_event, "rb"); + if (fp_ev == NULL) { + printf("Failed to open %s\n", buffer_event); + ret = -errno; + goto error_close_buffer_access; + } + + /* Wait for events 10 times */ + for (j = 0; j < num_loops; j++) { + read_size = fread(&dat, 1, sizeof(struct iio_event_data), + fp_ev); + switch (dat.id) { + case IIO_EVENT_CODE_RING_100_FULL: + toread = buf_len; + break; + case IIO_EVENT_CODE_RING_75_FULL: + toread = buf_len*3/4; + break; + case IIO_EVENT_CODE_RING_50_FULL: + toread = buf_len/2; + break; + default: + printf("Unexpecteded event code\n"); + continue; + } + read_size = read(fp, + data, + toread*scan_size); + if (read_size == -EAGAIN) { + printf("nothing available\n"); + continue; + } + for (i = 0; i < read_size/scan_size; i++) + process_scan(data + scan_size*i, + infoarray, + num_channels); + } + + /* Stop the ring buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + goto error_close_buffer_event; + + /* Disconnect from the trigger - just write a dummy name.*/ + write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + +error_close_buffer_event: + fclose(fp_ev); +error_close_buffer_access: + close(fp); +error_free_data: + free(data); +error_free_buffer_access: + free(buffer_access); +error_free_buffer_event: + free(buffer_event); +error_free_buf_dir_name: + free(buf_dir_name); +error_free_triggername: + if (datardytrigger) + free(trigger_name); +error_ret: + return ret; +} diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index 014f6684faba..03724246b95a 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -10,12 +10,23 @@ /* Made up value to limit allocation sizes */ #include <string.h> #include <stdlib.h> +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> #define IIO_MAX_NAME_LENGTH 30 -#define IIO_EVENT_CODE_RING_50_FULL 200 -#define IIO_EVENT_CODE_RING_75_FULL 201 -#define IIO_EVENT_CODE_RING_100_FULL 202 +#define IIO_EV_CLASS_BUFFER 0 +#define IIO_BUFFER_EVENT_CODE(code) \ + (IIO_EV_CLASS_BUFFER | (code << 8)) + +#define IIO_EVENT_CODE_RING_50_FULL IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_RING_75_FULL IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_RING_100_FULL IIO_BUFFER_EVENT_CODE(2) + + +#define FORMAT_SCAN_ELEMENTS_DIR "%s:buffer0/scan_elements" +#define FORMAT_TYPE_FILE "%s_type" const char *iio_dir = "/sys/bus/iio/devices/"; @@ -25,6 +36,380 @@ struct iio_event_data { }; /** + * iioutils_break_up_name() - extract generic name from full channel name + * @full_name: the full channel name + * @generic_name: the output generic channel name + **/ +static int iioutils_break_up_name(const char *full_name, + char **generic_name) +{ + char *current; + char *w, *r; + char *working; + current = strdup(full_name); + working = strtok(current, "_\0"); + w = working; + r = working; + + while(*r != '\0') { + if (!isdigit(*r)) { + *w = *r; + w++; + } + r++; + } + *w = '\0'; + *generic_name = strdup(working); + free(current); + + return 0; +} + +/** + * struct iio_channel_info - information about a given channel + * @name: channel name + * @generic_name: general name for channel type + * @scale: scale factor to be applied for conversion to si units + * @offset: offset to be applied for conversion to si units + * @index: the channel index in the buffer output + * @bytes: number of bytes occupied in buffer output + * @mask: a bit mask for the raw output + * @is_signed: is the raw value stored signed + * @enabled: is this channel enabled + **/ +struct iio_channel_info { + char *name; + char *generic_name; + float scale; + float offset; + unsigned index; + unsigned bytes; + unsigned bits_used; + uint64_t mask; + unsigned is_signed; + unsigned enabled; + unsigned location; +}; + +/** + * iioutils_get_type() - find and process _type attribute data + * @is_signed: output whether channel is signed + * @bytes: output how many bytes the channel storage occupies + * @mask: output a bit mask for the raw data + * @device_dir: the iio device directory + * @name: the channel name + * @generic_name: the channel type name + **/ +inline int iioutils_get_type(unsigned *is_signed, + unsigned *bytes, + unsigned *bits_used, + uint64_t *mask, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; + char signchar; + unsigned sizeint, padint; + const struct dirent *ent; + + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_scan_el_dir; + } + ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + /* + * Do we allow devices to override a generic name with + * a specific one? + */ + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", filename); + ret = -errno; + goto error_free_filename; + } + fscanf(sysfsfp, + "%c%u/%u", &signchar, bits_used, &padint); + *bytes = padint / 8; + if (sizeint == 64) + *mask = ~0; + else + *mask = (1 << *bits_used) - 1; + if (signchar == 's') + *is_signed = 1; + else + *is_signed = 0; + } +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_free_scan_el_dir: + free(scan_el_dir); +error_ret: + return ret; +} + +inline int iioutils_get_param_float(float *output, + const char *param_name, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *builtname, *builtname_generic; + char *filename = NULL; + const struct dirent *ent; + + ret = asprintf(&builtname, "%s_%s", name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname_generic, + "%s_%s", generic_name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + dp = opendir(device_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", device_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free_filename; + } + fscanf(sysfsfp, "%f", output); + break; + } +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_ret: + return ret; +} + + +/** + * build_channel_array() - function to figure out what channels are present + * @device_dir: the IIO device directory in sysfs + * @ + **/ +inline int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, + int *counter) +{ + DIR *dp; + FILE *sysfsfp; + int count = 0, temp, i; + struct iio_channel_info *current; + int ret; + const struct dirent *ent; + char *scan_el_dir; + char *filename; + + *counter = 0; + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_name; + } + while (ent = readdir(dp), ent != NULL) + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_close_dir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + ret = -errno; + free(filename); + goto error_close_dir; + } + fscanf(sysfsfp, "%u", &ret); + if (ret == 1) + (*counter)++; + fclose(sysfsfp); + free(filename); + } + *ci_array = malloc(sizeof(**ci_array)*(*counter)); + if (*ci_array == NULL) { + ret = -ENOMEM; + goto error_close_dir; + } + seekdir(dp, 0); + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + current = &(*ci_array)[count++]; + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + /* decrement count to avoid freeing name */ + count--; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + free(filename); + ret = -errno; + goto error_cleanup_array; + } + fscanf(sysfsfp, "%u", ¤t->enabled); + fclose(sysfsfp); + free(filename); + current->scale = 1.0; + current->offset = 0; + current->name = strndup(ent->d_name, + strlen(ent->d_name) - + strlen("_en")); + if (current->name == NULL) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + /* Get the generic and specific name elements */ + ret = iioutils_break_up_name(current->name, + ¤t->generic_name); + if (ret) { + free(filename); + goto error_cleanup_array; + } + ret = asprintf(&filename, + "%s/%s_index", + scan_el_dir, + current->name); + if (ret < 0) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + fscanf(sysfsfp, "%u", ¤t->index); + fclose(sysfsfp); + free(filename); + /* Find the scale */ + ret = iioutils_get_param_float(¤t->scale, + "scale", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_param_float(¤t->offset, + "offset", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_type(¤t->is_signed, + ¤t->bytes, + ¤t->bits_used, + ¤t->mask, + device_dir, + current->name, + current->generic_name); + } + } + /* reorder so that the array is in index order*/ + current = malloc(sizeof(**ci_array)**counter); + if (current == NULL) { + ret = -ENOMEM; + goto error_cleanup_array; + } + closedir(dp); + count = 0; + temp = 0; + while (count < *counter) + for (i = 0; i < *counter; i++) + if ((*ci_array)[i].index == temp) { + memcpy(¤t[count++], + &(*ci_array)[i], + sizeof(*current)); + temp++; + break; + } + free(*ci_array); + *ci_array = current; + + return 0; + +error_cleanup_array: + for (i = count - 1; i >= 0; i++) + free((*ci_array)[i].name); + free(*ci_array); +error_close_dir: + closedir(dp); +error_free_name: + free(scan_el_dir); +error_ret: + return ret; +} + +/** * find_type_by_name() - function to match top level types by name * @name: top level type instance name * @type: the type of top level instance being sort @@ -40,7 +425,6 @@ inline int find_type_by_name(const char *name, const char *type) DIR *dp; char thisname[IIO_MAX_NAME_LENGTH]; char *filename; - struct stat Stat; dp = opendir(iio_dir); if (dp == NULL) { @@ -134,7 +518,7 @@ int write_sysfs_int_and_verify(char *filename, char *basedir, int val) int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) { - int ret; + int ret = 0; FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (temp == NULL) { @@ -153,6 +537,7 @@ int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) if (verify) { sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { + printf("could not open file to verify\n"); ret = -errno; goto error_free; } @@ -173,6 +558,7 @@ error_free: return ret; } + /** * write_sysfs_string_and_verify() - string write, readback and verify * @filename: name of file to write to diff --git a/drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c b/drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c deleted file mode 100644 index 3a580284020c..000000000000 --- a/drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c +++ /dev/null @@ -1,238 +0,0 @@ -/* Industrialio ring buffer with a lis3l02dq accelerometer - * - * Copyright (c) 2008 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is primarily intended as an example application. - */ - -#include <dirent.h> -#include <fcntl.h> -#include <stdio.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/dir.h> -#include <linux/types.h> -#include "iio_utils.h" - -const char *device_name = "lis3l02dq"; -const char *trigger_name_base = "lis3l02dq-dev"; -const int num_vals = 3; -const int scan_ts = 1; -const int buf_len = 128; -const int num_loops = 10; - -/* - * Could get this from ring bps, but only after starting the ring - * which is a bit late for it to be useful. - * - * Todo: replace with much more generic version based on scan_elements - * directory. - */ -int size_from_scanmode(int num_vals, int timestamp) -{ - if (num_vals && timestamp) - return 16; - else if (timestamp) - return 8; - else - return num_vals*2; -} - -int main(int argc, char **argv) -{ - int ret; - int i, j, k, toread; - FILE *fp_ev; - int fp; - - char *trigger_name, *dev_dir_name, *buf_dir_name; - char *data; - size_t read_size; - struct iio_event_data dat; - int dev_num, trig_num; - - char *buffer_access, *buffer_event; - const char *iio_dir = "/sys/bus/iio/devices/"; - int scan_size; - float gain = 1; - - - /* Find out which iio device is the accelerometer. */ - dev_num = find_type_by_name(device_name, "device"); - if (dev_num < 0) { - printf("Failed to find the %s\n", device_name); - ret = -ENODEV; - goto error_ret; - } - printf("iio device number being used is %d\n", dev_num); - asprintf(&dev_dir_name, "%sdevice%d", iio_dir, dev_num); - - /* - * Build the trigger name. - * In this case we want the lis3l02dq's data ready trigger - * for this lis3l02dq. The naming is lis3l02dq_dev[n], where - * n matches the device number found above. - */ - ret = asprintf(&trigger_name, "%s%d", trigger_name_base, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_dev_dir_name; - } - - /* - * Find the trigger by name. - * This is techically unecessary here as we only need to - * refer to the trigger by name and that name is already - * known. - */ - trig_num = find_type_by_name(trigger_name, "trigger"); - if (trig_num < 0) { - printf("Failed to find the %s\n", trigger_name); - ret = -ENODEV; - goto error_free_triggername; - } - printf("iio trigger number being used is %d\n", trig_num); - - /* - * Read in the scale value - in a more generic case, first - * check for accel_scale, then the indivual channel scales - */ - ret = read_sysfs_float("accel_scale", dev_dir_name, &gain); - if (ret) - goto error_free_triggername;; - - /* - * Construct the directory name for the associated buffer. - * As we know that the lis3l02dq has only one buffer this may - * be built rather than found. - */ - ret = asprintf(&buf_dir_name, "%sdevice%d:buffer0", iio_dir, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_triggername; - } - /* Set the device trigger to be the data rdy trigger found above */ - ret = write_sysfs_string_and_verify("trigger/current_trigger", - dev_dir_name, - trigger_name); - if (ret < 0) { - printf("Failed to write current_trigger file\n"); - goto error_free_buf_dir_name; - } - - /* Setup ring buffer parameters */ - ret = write_sysfs_int("length", buf_dir_name, buf_len); - if (ret < 0) - goto error_free_buf_dir_name; - - /* Enable the buffer */ - ret = write_sysfs_int("ring_enable", buf_dir_name, 1); - if (ret < 0) - goto error_free_buf_dir_name; - - data = malloc(size_from_scanmode(num_vals, scan_ts)*buf_len); - if (!data) { - ret = -ENOMEM; - goto error_free_buf_dir_name; - } - - ret = asprintf(&buffer_access, - "/dev/device%d:buffer0:access0", - dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_data; - } - - ret = asprintf(&buffer_event, "/dev/device%d:buffer0:event0", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_data; - } - /* Attempt to open non blocking the access dev */ - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); - if (fp == -1) { /*If it isn't there make the node */ - printf("Failed to open %s\n", buffer_access); - ret = -errno; - goto error_free_buffer_event; - } - /* Attempt to open the event access dev (blocking this time) */ - fp_ev = fopen(buffer_event, "rb"); - if (fp_ev == NULL) { - printf("Failed to open %s\n", buffer_event); - ret = -errno; - goto error_close_buffer_access; - } - - /* Wait for events 10 times */ - for (j = 0; j < num_loops; j++) { - read_size = fread(&dat, 1, sizeof(struct iio_event_data), - fp_ev); - switch (dat.id) { - case IIO_EVENT_CODE_RING_100_FULL: - toread = buf_len; - break; - case IIO_EVENT_CODE_RING_75_FULL: - toread = buf_len*3/4; - break; - case IIO_EVENT_CODE_RING_50_FULL: - toread = buf_len/2; - break; - default: - printf("Unexpecteded event code\n"); - continue; - } - read_size = read(fp, - data, - toread*size_from_scanmode(num_vals, scan_ts)); - if (read_size == -EAGAIN) { - printf("nothing available\n"); - continue; - } - scan_size = size_from_scanmode(num_vals, scan_ts); - for (i = 0; i < read_size/scan_size; i++) { - for (k = 0; k < num_vals; k++) { - __s16 val = *(__s16 *)(&data[i*scan_size - + (k)*2]); - printf("%05f ", (float)val*gain); - } - printf(" %lld\n", - *(__s64 *)(&data[(i + 1) - *size_from_scanmode(num_vals, - scan_ts) - - sizeof(__s64)])); - } - } - - /* Stop the ring buffer */ - ret = write_sysfs_int("ring_enable", buf_dir_name, 0); - if (ret < 0) - goto error_close_buffer_event; - - /* Disconnect from the trigger - just write a dummy name.*/ - write_sysfs_string("trigger/current_trigger", - dev_dir_name, "NULL"); - -error_close_buffer_event: - fclose(fp_ev); -error_close_buffer_access: - close(fp); -error_free_data: - free(data); -error_free_buffer_access: - free(buffer_access); -error_free_buffer_event: - free(buffer_event); -error_free_buf_dir_name: - free(buf_dir_name); -error_free_triggername: - free(trigger_name); -error_free_dev_dir_name: - free(dev_dir_name); -error_ret: - return ret; -} diff --git a/drivers/staging/iio/Documentation/overview.txt b/drivers/staging/iio/Documentation/overview.txt index cc6ecad4035c..d97106cb2b96 100644 --- a/drivers/staging/iio/Documentation/overview.txt +++ b/drivers/staging/iio/Documentation/overview.txt @@ -1,8 +1,8 @@ Overview of IIO -The Industrial I/O subsytem is intended to provide support for devices -that in some sense are analog to digital convertors (ADCs). As many -actual devices combine some ADCs with digital to analog convertors +The Industrial I/O subsystem is intended to provide support for devices +that in some sense are analog to digital converters (ADCs). As many +actual devices combine some ADCs with digital to analog converters (DACs) the intention is to add that functionality at a future date (hence the name). @@ -46,18 +46,17 @@ external signal (trigger). These triggers might be a data ready signal, a gpio line connected to some external system or an on processor periodic interrupt. A single trigger may initialize data capture or reading from a number of sensors. These triggers are -used in iio to fill software ring buffers acting in a very similar +used in IIO to fill software ring buffers acting in a very similar fashion to the hardware buffers described above. Other documentation: -userspace.txt - overview of ring buffer reading from userspace +userspace.txt - overview of ring buffer reading from userspace. -device.txt - elemennts of a typical device driver. +device.txt - elements of a typical device driver. trigger.txt - elements of a typical trigger driver. -ring.txt - additional elements required for ring buffer support - - +ring.txt - additional elements required for ring buffer support. +sysfs-bus-iio - abi documentation file. diff --git a/drivers/staging/iio/Documentation/ring.txt b/drivers/staging/iio/Documentation/ring.txt index d2ca6834c169..3696c364e644 100644 --- a/drivers/staging/iio/Documentation/ring.txt +++ b/drivers/staging/iio/Documentation/ring.txt @@ -47,10 +47,8 @@ request_update If parameters have changed that require reinitialization or configuration of the ring buffer this will trigger it. -get_bpd, set_bpd - Get/set the number of bytes for a given reading (single element, not sample set) - The value of bps (bytes per set) is created from a combination of this and the - enabled scan elements. +get_bytes_per_datum, set_bytes_per_datum + Get/set the number of bytes for a complete scan. (All samples + timestamp) get_length / set_length Get/set the number of sample sets that may be held by the buffer. diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio new file mode 100644 index 000000000000..fdb017a1c1a2 --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio @@ -0,0 +1,390 @@ +What: /sys/bus/iio/devices/device[n] +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Hardware chip or device accessed by on communication port. + Corresponds to a grouping of sensor channels. + +What: /sys/bus/iio/devices/trigger[n] +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + An event driven driver of data capture to an in kernel buffer. + May be provided by a device driver that also has an IIO device + based on hardware generated events (e.g. data ready) or + provided by a separate driver for other hardware (e.g. + periodic timer, gpio or high resolution timer). + Contains trigger type specific elements. These do not + generalize well and hence are not documented in this file. + +What: /sys/bus/iio/devices/device[n]:buffer +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Link to /sys/class/iio/device[n]/device[n]:buffer. n indicates + the device with which this buffer buffer is associated. + +What: /sys/.../device[n]/name +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Description of the physical chip / device. Typically a part + number. + +What: /sys/.../device[n]/sampling_frequency +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Some devices have internal clocks. This parameter sets the + resulting sampling frequency. In many devices this + parameter has an effect on input filters etc rather than + simply controlling when the input is sampled. As this + effects datardy triggers, hardware buffers and the sysfs + direct access interfaces, it may be found in any of the + relevant directories. If it effects all of the above + then it is to be found in the base device directory as here. + +What: /sys/.../device[n]/sampling_frequency_available +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + When the internal sampling clock can only take a small + discrete set of values, this file lists those availale. + +What: /sys/.../device[n]/in[m][_name]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled no bias removal etc) voltage measurement from + channel m. name is used in special cases where this does + not correspond to externally available input (e.g. supply + voltage monitoring in which case the file is in_supply_raw). + If the device supports events on this channel then m must be + specified (even on named channels) so as to allow the source + of event codes to be identified. + +What: /sys/.../device[n]/in[m][_name]_offset +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + If known for a device, offset to be added to in[m]_raw prior + to scaling by in[_name][m]_scale in order to obtain voltage in + millivolts. Not present if the offset is always 0 or unknown. + If m is not present, then voltage offset applies to all in + channels. May be writable if a variable offset is controlled + by the device. Note that this is different to calibbias which + is for devices that apply offsets to compensate for variation + between different instances of the part, typically adjusted by + using some hardware supported calibration procedure. + +What: /sys/.../device[n]/in[m][_name]_offset_available +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + If a small number of discrete offset values are available, this + will be a space separated list. If these are independant (but + options the same) for individual offsets then m should not be + present. + +What: /sys/.../device[n]/in[m][_name]_offset_[min|max] +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + If a more or less continuous range of voltage offsets are + supported then these specify the minimum and maximum. If shared + by all in channels then m is not present. + +What: /sys/.../device[n]/in[m][_name]_calibbias +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Hardware applied calibration offset. (assumed to fix production + inaccuracies) + +What /sys/.../device[n]/in[m][_name]_calibscale +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Hardware applied calibration scale factor. (assumed to fix + production inaccuracies) + +What: /sys/.../device[n]/in[m][_name]_scale +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + If known for a device, scale to be applied to volt[m]_raw post + addition of in[_name][m]_offset in order to obtain the measured + voltage in millivolts. If shared across all in channels then + m is not present. + +What: /sys/.../device[n]/in[m]-in[o]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled) differential voltage measurement equivalent to + channel m - channel o where these channel numbers apply to the + physically equivalent inputs when non differential readings are + separately available. In differential only parts, then all that + is required is a consistent labelling. + +What: /sys/.../device[n]/accel[_x|_y|_z][m]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Acceleration in direction x, y or z (may be arbitrarily assigned + but should match other such assignments on device) + channel m (not present if only one accelerometer channel at + this orientation). Has all of the equivalent parameters as per + in[m]. Units after application of scale and offset are m/s^2. + +What: /sys/.../device[n]/gyro[_x|_y|_z][m]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Angular velocity about axis x, y or z (may be arbitrarily + assigned) channel m (not present if only one gyroscope at + this orientation). + Data converted by application of offset then scale to + radians per second. Has all the equivalent parameters as + per in[m]. + +What: /sys/.../device[n]/incli[_x|_y|_z][m]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Inclination raw reading about axis x, y or z (may be arbitarily + assigned) channel m (not present if only one inclinometer at + this orientation). Data converted by application of offset + and scale to Degrees. + +What: /sys/.../device[n]/magn[_x|_y|_z][m]_raw +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Magnetic field along axis x, y or z (may be arbitrarily + assigned) channel m (not present if only one magnetometer + at this orientation). Data converted by application of + offset then scale to Gauss. Has all the equivalent modifiers + as per in[m]. + +What: /sys/.../device[n]/device[n]:event[m] +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Configuration of which hardware generated events are passed up to + userspace. Some of these are a bit complex to generalize so this + section is a work in progress. + +What: /sys/.../device[n]:event[m]/dev +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + major:minor character device numbers for the event line. + +Taking accel_x0 as an example + +What: /sys/.../device[n]:event[m]/accel_x0_thresh[_rising|_falling]_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Event generated when accel_x0 passes a threshold in the specfied + (_rising|_falling) direction. If the direction is not specified, + then either the device will report an event which ever direction + a single threshold value is called in (e.g. + accel_x0_<raw|input>_thresh_value) or + accel_x0_<raw|input>_thresh_rising_value and + accel_x0_<raw|input>_thresh_falling_value may take different + values, but the device can only enable both thresholds or + neither. + Note the driver will assume the last p events requested are + to be enabled where p is however many it supports (which may + vary depending on the exact set requested. So if you want to be + sure you have set what you think you have, check the contents of + these attributes after everything is configured. Drivers may + have to buffer any parameters so that they are consistent when + a given event type is enabled a future point (and not those for + whatever event was previously enabled). + +What: /sys/.../accel_x0_<raw|input>_thresh[_rising|_falling]_value +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the value of threshold that the device is comparing + against for the events enabled by + accel_x0_<raw|input>_thresh[_rising|falling]_en. + If seperate exist for the two directions, but direction is + not specified for this attribute, then a single threshold value + applies to both directions. + The raw or input element of the name indicates whether the + value is in raw device units or in processed units (as _raw + and _input do on sysfs direct channel read attributes). + +What: /sys/.../accel_x0_thresh[_rising|_falling]_meanperiod +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) over which the raw channel value + is averaged before being compared with the threshold set in + accel_x0_thresh[_rising|_falling]_meanperiod. If direction is + not specified then this mean period applies to both directions. + +What: /sys/.../accel_x0_thresh[_rising|_falling]_period +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) for which the threshold must be + passed before an event is generated. If direction is not + specified then this period applies to both directions. + +What: /sys/.../device[n]:event[m]/accel_x0_mag[_rising|_falling]_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Similar to accel_x0_thresh[_rising|_falling]_en, but here the + magnitude of the channel is compared to the threshold, not its + signed value. + +What: /sys/.../accel_x0_<raw|input>_mag[_rising|_falling]_value +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + The value to which the magnitude of the channel is compared. + +What: /sys/.../accel_x0_mag[_rising|_falling]_meanperiod +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) over which the value of the channel + is averaged before being compared to the threshold + +What: /sys/.../accel_x0_mag[_rising|_falling]_period +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) for which the condition must be true + before an event occurs. + +What: /sys/.../device[n]:event[m]/accel_x0_roc[_rising|_falling]_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Similar to accel_x0_thresh[_rising|_falling]_en, but here the + first differential is compared with the threshold. + +What: /sys/.../accel_x0_<raw|input>_roc[_rising|_falling]_value +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + The value to which the first differential of the channel is + compared. + +What: /sys/.../accel_x0_roc[_rising|_falling]_meanperiod +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) over which the value of the channel + is averaged before being compared to the threshold + +What: /sys/.../accel_x0_roc[_rising|_falling]_period +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Period of time (in seconds) for which the condition must be true + before an event occurs. + +What: /sys/.../device[n]/device[n]:buffer:event/dev +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Buffer for device n event character device major:minor numbers. + +What: /sys/.../device[n]/device[n]:buffer:access/dev +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Buffer for device n access character device o major:minor numbers. + +What: /sys/.../device[n]:buffer/trigger +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + The name of the trigger source being used, as per string given + in /sys/class/iio/trigger[n]/name. + +What: /sys/.../device[n]:buffer/length +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Number of scans contained by the buffer. + +What: /sys/.../device[n]:buffer/bytes_per_datum +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Bytes per scan. Due to alignment fun, the scan may be larger + than implied directly by the scan_element parameters. + +What: /sys/.../device[n]:buffer/enable +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Actually start the buffer capture up. Will start trigger + if first device and appropriate. + +What: /sys/.../device[n]:buffer/alignment +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Minimum data alignment. Scan elements larger than this are + aligned to the nearest power of 2 times this. (may not be + true in weird hardware buffers that pack data well) + +What: /sys/.../device[n]/buffer/scan_elements +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Directory containing interfaces for elements that will be + captured for a single triggered sample set in the buffer. + +What: /sys/.../device[n]/buffer/scan_elements/accel_x0_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Scan element control for triggered data capture. + +What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_type +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Description of the scan element data storage within the buffer + and hence the form in which it is read from userspace. + Form is [s|u]bits/storagebits. s or u specifies if signed + (2's complement) or unsigned. bits is the number of bits of + data and storagebits is the space (after padding) that it + occupies in the buffer. Note that some devices will have + additional information in the unused bits so to get a clean + value, the bits value must be used to mask the buffer output + value appropriately. The storagebits value also specifies the + data alignment. So s48/64 will be a signed 48 bit integer + stored in a 64 bit location aligned to a a64 bit boundary. + For other storage combinations this attribute will be extended + appropriately. + +What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_index +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the position of this + scan element in the buffer. Note these are not dependant on + what is enabled and may not be contiguous. Thus for userspace + to establish the full layout these must be used in conjunction + with all _en attributes to establish which channels are present, + and the relevant _type attributes to establish the data storage + format. + +What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_shift +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + A bit shift (to right) that must be applied prior to + extracting the bits specified by accel[_x0]_precision. diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light new file mode 100644 index 000000000000..5d84856dc14a --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light @@ -0,0 +1,64 @@ + +What: /sys/bus/iio/devices/device[n]/range +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Hardware dependent ADC Full Scale Range used for some ambient + light sensors in calculating lux. + +What: /sys/bus/iio/devices/device[n]/range_available +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Hardware dependent supported vales for ADC Full Scale Range. + +What: /sys/bus/iio/devices/device[n]/adc_resolution +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Hardware dependent ADC resolution of the ambient light sensor + used in calculating the lux. + +What: /sys/bus/iio/devices/device[n]/adc_resolution_available +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Hardware dependent list of possible values supported for the + adc_resolution of the given sensor. + +What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw] +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + This should return the calculated lux from the light sensor. If + it comes back in SI units, it should also include _input else it + should include _raw to signify it is not in SI units. + +What: /sys/.../device[n]/proximity_on_chip_ambient_infrared_supression +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Hardware dependent mode for an ALS device to calculate the value + in proximity mode. When this is enabled, then the device should + use a infrared sensor reading to remove infrared noise from the + proximity reading. If this is not enabled, the driver can still + do this calculation manually by reading the infrared sensor + value and doing the negation in sw. + +What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw] +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + This property is supported by proximity sensors and should be + used to return the value of a reading by the sensor. If this + value is returned in SI units, it should also include _input + but if it is not, then it should include _raw. + +What: /sys/bus/iio/devices/device[n]/intensity_infrared[_input|_raw] +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + This property is supported by sensors that have an infrared + sensing mode. This value should be the output from a reading + and if expressed in SI units, should include _input. If this + value is not in SI units, then it should include _raw. diff --git a/drivers/staging/iio/Documentation/sysfs-class-iio b/drivers/staging/iio/Documentation/sysfs-class-iio deleted file mode 100644 index 714b4c57c82a..000000000000 --- a/drivers/staging/iio/Documentation/sysfs-class-iio +++ /dev/null @@ -1,294 +0,0 @@ - -What: /sys/bus/iio/devices/device[n] -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Hardware chip or device accessed by on communication port. - Corresponds to a grouping of sensor channels. - -What: /sys/bus/iio/devices/trigger[n] -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - An event driven driver of data capture to an in kernel buffer. - May be provided by a device driver that also has an IIO device - based on hardware generated events (e.g. data ready) or - provided by a separate driver for other hardware (e.g. - periodic timer, gpio or high resolution timer). - Contains trigger type specific elements. These do not - generalize well and hence are not documented in this file. - -What: /sys/bus/iio/devices/device[n]:buffer -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Link to /sys/class/iio/device[n]/device[n]:buffer. n indicates the - device with which this buffer buffer is associated. - -What: /sys/.../device[n]/name -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Description of the physical chip / device. Typically a part - number. - -What: /sys/.../device[n]/sampling_frequency -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Some devices have internal clocks. This parameter sets the - resulting sampling frequency. In many devices this - parameter has an effect on input filters etc rather than - simply controlling when the input is sampled. As this - effects datardy triggers, hardware buffers and the sysfs - direct access interfaces, it may be found in any of the - relevant directories. If it effects all of the above - then it is to be found in the base device directory as here. - -What: /sys/.../device[n]/sampling_frequency_available -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - When the internal sampling clock can only take a small - discrete set of values, this file lists those availale. - -What: /sys/.../device[n]/in[_name][m]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Raw (unscaled no bias removal etc) voltage measurement from - channel m. name is used in special cases where this does - not correspond to externally available input (e.g. supply - voltage monitoring in which case the file is in_supply_raw). - -What: /sys/.../device[n]/in[_name][m]_offset -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - If known for a device, offset to be added to in[m]_raw prior - to scaling by in[_name][m]_scale in order to obtain voltage in - millivolts. Not present if the offset is always 0 or unknown. - If m is not present, then voltage offset applies to all in - channels. May be writable if a variable offset is controlled - by the device. Note that this is different to calibbias which - is for devices that apply offsets to compensate for variation - between different instances of the part, typically adjusted by - using some hardware supported calibration procedure. - -What: /sys/.../device[n]/in[_name][m]_offset_available -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - If a small number of discrete offset values are available, this - will be a space separated list. If these are independant (but - options the same) for individual offsets then m should not be - present. - -What: /sys/.../device[n]/in[_name][m]_offset_[min|max] -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - If a more or less continuous range of voltage offsets are supported - then these specify the minimum and maximum. If shared by all - in channels then m is not present. - -What: /sys/.../device[n]/in[_name][m]_calibbias -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Hardware applied calibration offset. (assumed to fix production - inaccuracies) - -What /sys/.../device[n]/in[_name][m]_calibscale -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Hardware applied calibration scale factor. (assumed to fix production - inaccuracies) - -What: /sys/.../device[n]/in[_name][m]_scale -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - If known for a device, scale to be applied to volt[m]_raw post - addition of in[_name][m]_offset in order to obtain the measured - voltage in millivolts. If shared across all in channels then m is not present. - -What: /sys/.../device[n]/in[m]-in[o]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Raw (unscaled) differential voltage measurement equivalent to - channel m - channel o where these channel numbers apply to the physically - equivalent inputs when non differential readings are separately available. - In differential only parts, then all that is required is a consistent - labelling. - -What: /sys/.../device[n]/accel[_x|_y|_z][m]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Acceleration in direction x, y or z (may be arbitrarily assigned - but should match other such assignments on device) - channel m (not present if only one accelerometer channel at - this orientation). Has all of the equivalent parameters as per in[m]. - Units after application of scale and offset are m/s^2. - -What: /sys/.../device[n]/gyro[_x|_y|_z][m]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Angular velocity about axis x, y or z (may be arbitrarily assigned) - channel m (not present if only one gyroscope at this orientation). - Data converted by application of offset then scale to - radians per second. Has all the equivalent parameters as per in[m]. - -What: /sys/.../device[n]/incli[_x|_y|_z][m]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Inclination raw reading about axis x, y or z (may be arbitarily - assigned) channel m (not present if only one inclinometer at - this orientation). Data converted by application of offset - and scale to Degrees. - -What: /sys/.../device[n]/magn[_x|_y|_z][m]_raw -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Magnetic field along axis x, y or z (may be arbitrarily assigned) - channel m (not present if only one magnetometer at this orientation). - Data converted by application of offset then scale to Gauss - Has all the equivalent modifiers as per in[m]. - -What: /sys/.../device[n]/device[n]:event[m] -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Configuration of which hardware generated events are passed up to - userspace. Some of these are a bit complex to generalize so this - section is a work in progress. - -What: /sys/.../device[n]:event[m]/dev -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - major:minor character device numbers for the event line. - -Taking accel_x0 as an example - -What: /sys/.../device[n]:event[m]/accel_x0_thresh[_high|_low]_en -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Event generated when accel_x0 passes a threshold in correction direction - (or stays beyond one). If direction isn't specified, either triggers it. - Note driver will assume last p events requested are enabled where p is - however many it supports. So if you want to be sure you have - set what you think you have, check the contents of these. Drivers - may have to buffer any parameters so that they are consistent when a - given event type is enabled a future point (and not those for whatever - alarm was previously enabled). - -What: /sys/.../device[n]:event[m]/accel_x0_roc[_high|_low]_en -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Same as above but based on the first differential of the value. - - -What: /sys/.../device[n]:event[m]/accel_x0[_thresh|_roc][_high|_low]_period -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - A period of time (microsecs) for which the condition must be broken - before an interrupt is triggered. Applies to all alarms if type is not - specified. - -What: /sys/.../device[n]:event[m]/accel_x0[_thresh|_roc][_high|_low]_value -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - The actual value of the threshold in raw device units obtained by - reverse application of scale and offfset to the acceleration in m/s^2. - -What: /sys/.../device[n]/scan_elements -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Directory containing interfaces for elements that will be captured - for a single triggered sample set in the buffer. - -What: /sys/.../device[n]/scan_elements/[m]_accel_x0_en -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Scan element control for triggered data capture. m implies the - ordering within the buffer. Next the type is specified with - modifier and channel number as per the sysfs single channel - access above. - -What: /sys/.../device[n]/scan_elements/accel[_x0]_precision -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Scan element precision within the buffer. Note that the - data alignment must restrictions must be read from within - buffer to work out full data alignment for data read - via buffer_access chrdev. _x0 dropped if shared across all - acceleration channels. - -What: /sys/.../device[n]/scan_elements/accel[_x0]_shift -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - A bit shift (to right) that must be applied prior to - extracting the bits specified by accel[_x0]_precision. - -What: /sys/.../device[n]/device[n]:buffer:event/dev -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Buffer for device n event character device major:minor numbers. - -What: /sys/.../device[n]/device[n]:buffer:access/dev -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Buffer for device n access character device o major:minor numbers. - -What: /sys/.../device[n]:buffer/trigger -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - The name of the trigger source being used, as per string given - in /sys/class/iio/trigger[n]/name. - -What: /sys/.../device[n]:buffer/length -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Number of scans contained by the buffer. - -What: /sys/.../device[n]:buffer/bps -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Bytes per scan. Due to alignment fun, the scan may be larger - than implied directly by the scan_element parameters. - -What: /sys/.../device[n]:buffer/enable -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Actually start the buffer capture up. Will start trigger - if first device and appropriate. - -What: /sys/.../device[n]:buffer/alignment -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Minimum data alignment. Scan elements larger than this are aligned - to the nearest power of 2 times this. (may not be true in weird - hardware buffers that pack data well) - diff --git a/drivers/staging/iio/Documentation/userspace.txt b/drivers/staging/iio/Documentation/userspace.txt index 4838818f65ef..ff06e5dc7188 100644 --- a/drivers/staging/iio/Documentation/userspace.txt +++ b/drivers/staging/iio/Documentation/userspace.txt @@ -1,60 +1,12 @@ Userspace access to IIO -Example, ST Microelectronics LIS3L02DQ accelerometer. - -Typical sysfs entries (pruned for clarity) - -/sys/class/iio - device0 - iio_dev related elements - name - driver specific identifier (here lis3l02dq) - accel_x - polled (or from ring) raw readout of acceleration - accel_x_gain - hardware gain (calibration) - accel_x_offset - hardware offset (calibration) - available_sampling_frequency - - available_sampling_frequency - what options are there - sampling_frequency - control of internal sampling frequency - scan_elements - controls which channels will be stored in the ring buffer - scan_en_accel_x - scan_en_accel_y - scan_en_timestamp - device - link to underlying hardware device - uevent - udev related element - - thresh - unified threshold used for detection on all axis - event_line0_sources - which events are enabled - accel_x_high - enable x axis high threshold event - accel_x_low - enable x axis low threshold event - - event_line0 - event interface - dev - major:minor for the chrdev (note major allocation dynamic) - trigger - consumer attachement - current_trigger - name based association with a trigger - ring_buffer0 - ring buffer interface - bps - byptes per sample (read only), dependant on scan element selection - length - (rw) specificy length fo software ring buffer (typically ro in hw case) - ring_enable - turn the ring on. If its the first to be enabled attached to this - trigger will also enable the trigger. - ring_access0 - dev - major:minor for ring buffer access chrdev - ring_event_line0 - dev - major:minor for ring buffer event chrdev - - trigger0 - data ready trigger elements - name - unqiue name of trigger +The sysfs attributes are documented in sysfs-bus-iio. Udev will create the following entries under /dev by default: -ring_access0 - ring access chrdev -ring_event0 - ring event chrdev -event_line0 - general event chrdev. - -For the example code we assume the following rules have been used to ensure -unique and consistent naming of these for the lis3l02dq in question: - -KERNEL="ring_event_line*", ID="spi1.0", DRIVER="lis3l02dq", NAME="iio/lis3l02dq_ring_event" -KERNEL="event_line*", ID="spi1.0", DRIVER="lis3l02dq", NAME="iio/lis3l02dq_event" -KERNEL="ring_access*", ID="spi1.0", DRIVER="lis3l02dq", NAME="iio/lis3l02dq_ring_access" +device0:buffer0:access0 - ring access chrdev +device0:buffer0:event0 - ring event chrdev +device0:event0 - general event chrdev. The files, lis3l02dqbuffersimple.c and iio_utils.h in this directory provide an example of how to use the ring buffer and event interfaces. diff --git a/drivers/staging/iio/accel/accel.h b/drivers/staging/iio/accel/accel.h index 1b6e37f76200..f5f61b2497aa 100644 --- a/drivers/staging/iio/accel/accel.h +++ b/drivers/staging/iio/accel/accel.h @@ -14,158 +14,54 @@ #define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_ACCEL_X_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(accel_x_gain, _mode, _show, _store, _addr) +#define IIO_CONST_ATTR_ACCEL_SCALE(_string) \ + IIO_CONST_ATTR(accel_scale, _string) -#define IIO_DEV_ATTR_ACCEL_Y_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(accel_y_gain, _mode, _show, _store, _addr) +#define IIO_DEV_ATTR_ACCEL_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_scale, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_ACCEL_Z_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(accel_z_gain, _mode, _show, _store, _addr) +#define IIO_DEV_ATTR_ACCEL_X_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_x_scale, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_ACCEL(_show, _addr) \ - IIO_DEVICE_ATTR(accel_raw, S_IRUGO, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \ - IIO_DEVICE_ATTR(accel_x_raw, S_IRUGO, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ACCEL_Y(_show, _addr) \ - IIO_DEVICE_ATTR(accel_y_raw, S_IRUGO, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \ - IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr) - -/* Thresholds are somewhat chip dependent - may need quite a few defs here */ -/* For unified thresholds (shared across all directions */ - -/** - * IIO_DEV_ATTR_ACCEL_THRESH: unified threshold - * @_mode: read/write - * @_show: read detector threshold value - * @_store: write detector threshold value - * @_addr: driver specific data, typically a register address - * - * This one is for cases where as single threshold covers all directions - **/ -#define IIO_DEV_ATTR_ACCEL_THRESH(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(thresh, _mode, _show, _store, _addr) - -/** - * IIO_DEV_ATTR_ACCEL_THRESH_X: independant direction threshold, x axis - * @_mode: readable / writable - * @_show: read x axis detector threshold value - * @_store: write x axis detector threshold value - * @_addr: device driver dependant, typically a register address - **/ -#define IIO_DEV_ATTR_ACCEL_THRESH_X(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(thresh_accel_x, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACCEL_THRESH_Y(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(thresh_accel_y, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACCEL_THRESH_Z(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(thresh_accel_z, _mode, _show, _store, _addr) - -/** - * IIO_EVENT_ATTR_ACCEL_X_HIGH: threshold event, x acceleration - * @_show: read x acceleration high threshold - * @_store: write x acceleration high threshold - * @_mask: device dependant, typically a bit mask - * @_handler: the iio_handler associated with this attribute - **/ -#define IIO_EVENT_ATTR_ACCEL_X_HIGH(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_x_high, _show, _store, _mask, _handler) - -/** - * IIO_EVENT_ATTR_ACCEL_X_HIGH_SH: threshold event, x accel high, shared handler - * @_evlist: event list used to share the handler - * @_show: attribute read - * @_store: attribute write - * @_mask: driver specific data, typically a bit mask - **/ -#define IIO_EVENT_ATTR_ACCEL_X_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_x_high, _evlist, _show, _store, _mask) - -/** - * IIO_EVENT_CODE_ACCEL_X_HIGH - event code for x axis high accel threshold - **/ -#define IIO_EVENT_CODE_ACCEL_X_HIGH IIO_EVENT_CODE_ACCEL_BASE - -#define IIO_EVENT_ATTR_ACCEL_Y_HIGH(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_y_high, _show, _store, _mask, _handler) - -#define IIO_EVENT_ATTR_ACCEL_Y_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_y_high, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_Y_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 1) +#define IIO_DEV_ATTR_ACCEL_Y_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_y_scale, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_Z_HIGH(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_z_high, _show, _store, _mask, _handler) +#define IIO_DEV_ATTR_ACCEL_Z_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_z_scale, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_Z_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_z_high, _evlist, _show, _store, _mask) +#define IIO_DEV_ATTR_ACCEL_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_calibbias, _mode, _show, _store, _addr) -#define IIO_EVENT_CODE_ACCEL_Z_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 2) +#define IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_x_calibbias, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_X_LOW(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_x_low, _show, _store, _mask, _handler) +#define IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_y_calibbias, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_X_LOW_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_x_low, _evlist, _show, _store, _mask) +#define IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_z_calibbias, _mode, _show, _store, _addr) -#define IIO_EVENT_CODE_ACCEL_X_LOW (IIO_EVENT_CODE_ACCEL_BASE + 3) +#define IIO_DEV_ATTR_ACCEL_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_calibscale, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_Y_LOW(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_y_low, _show, _store, _mask, _handler) +#define IIO_DEV_ATTR_ACCEL_X_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_x_calibscale, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_Y_LOW_SH(_evlist, _show, _store, _mask)\ - IIO_EVENT_ATTR_SH(accel_y_low, _evlist, _show, _store, _mask) +#define IIO_DEV_ATTR_ACCEL_Y_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_y_calibscale, _mode, _show, _store, _addr) -#define IIO_EVENT_CODE_ACCEL_Y_LOW (IIO_EVENT_CODE_ACCEL_BASE + 4) +#define IIO_DEV_ATTR_ACCEL_Z_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(accel_z_calibscale, _mode, _show, _store, _addr) -#define IIO_EVENT_ATTR_ACCEL_Z_LOW(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(accel_z_low, _show, _store, _mask, _handler) - -#define IIO_EVENT_ATTR_ACCEL_Z_LOW_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_z_low, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_Z_LOW (IIO_EVENT_CODE_ACCEL_BASE + 5) - -#define IIO_EVENT_ATTR_FREE_FALL_DETECT(_show, _store, _mask, _handler) \ - IIO_EVENT_ATTR(free_fall, _show, _store, _mask, _handler) - -#define IIO_EVENT_ATTR_FREE_FALL_DETECT_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(free_fall, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_FREE_FALL (IIO_EVENT_CODE_ACCEL_BASE + 6) - - -#define IIO_EVENT_ATTR_ACCEL_X_ROC_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_x_roc_high, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_X_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 10) - -#define IIO_EVENT_ATTR_ACCEL_X_ROC_LOW_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_x_roc_low, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_X_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 11) - -#define IIO_EVENT_ATTR_ACCEL_Y_ROC_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_y_roc_high, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_Y_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 12) - -#define IIO_EVENT_ATTR_ACCEL_Y_ROC_LOW_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_y_roc_low, _evlist, _show, _store, _mask) - -#define IIO_EVENT_CODE_ACCEL_Y_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 13) +#define IIO_DEV_ATTR_ACCEL(_show, _addr) \ + IIO_DEVICE_ATTR(accel_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_EVENT_ATTR_ACCEL_Z_ROC_HIGH_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_z_roc_high, _evlist, _show, _store, _mask) +#define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \ + IIO_DEVICE_ATTR(accel_x_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_EVENT_CODE_ACCEL_Z_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 14) +#define IIO_DEV_ATTR_ACCEL_Y(_show, _addr) \ + IIO_DEVICE_ATTR(accel_y_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_EVENT_ATTR_ACCEL_Z_ROC_LOW_SH(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(accel_z_roc_low, _evlist, _show, _store, _mask) +#define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \ + IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_EVENT_CODE_ACCEL_Z_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 15) diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index 6c6923f2eaa5..e4ac956208a6 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -391,51 +391,43 @@ err_ret: return ret; } -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16209_read_14bit_unsigned, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16209_read_14bit_unsigned, ADIS16209_SUPPLY_OUT); -static IIO_CONST_ATTR(in_supply_scale, "0.30518"); -static IIO_DEV_ATTR_IN_RAW(0, adis16209_read_12bit_unsigned, +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.30518"); +static IIO_DEV_ATTR_IN_RAW(1, adis16209_read_12bit_unsigned, ADIS16209_AUX_ADC); -static IIO_CONST_ATTR(in0_scale, "0.6105"); +static IIO_CONST_ATTR(in1_scale, "0.6105"); static IIO_DEV_ATTR_ACCEL_X(adis16209_read_14bit_signed, ADIS16209_XACCL_OUT); static IIO_DEV_ATTR_ACCEL_Y(adis16209_read_14bit_signed, ADIS16209_YACCL_OUT); -static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(S_IWUSR | S_IRUGO, adis16209_read_14bit_signed, adis16209_write_16bit, ADIS16209_XACCL_NULL); -static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(S_IWUSR | S_IRUGO, adis16209_read_14bit_signed, adis16209_write_16bit, ADIS16209_YACCL_NULL); -static IIO_CONST_ATTR(accel_scale, "0.24414"); +static IIO_CONST_ATTR_ACCEL_SCALE("0.002394195531"); static IIO_DEV_ATTR_INCLI_X(adis16209_read_14bit_signed, ADIS16209_XINCL_OUT); static IIO_DEV_ATTR_INCLI_Y(adis16209_read_14bit_signed, ADIS16209_YINCL_OUT); -static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO, - adis16209_read_14bit_signed, - adis16209_write_16bit, - ADIS16209_XACCL_NULL); -static IIO_DEV_ATTR_INCLI_Y_OFFSET(S_IWUSR | S_IRUGO, - adis16209_read_14bit_signed, - adis16209_write_16bit, - ADIS16209_YACCL_NULL); -static IIO_CONST_ATTR(incli_scale, "0.025"); +static IIO_CONST_ATTR(incli_scale, "0.00043633231"); static IIO_DEVICE_ATTR(rot_raw, S_IRUGO, adis16209_read_14bit_signed, NULL, ADIS16209_ROT_OUT); -static IIO_DEV_ATTR_TEMP(adis16209_read_temp); -static IIO_CONST_ATTR(temp_offset, "25"); -static IIO_CONST_ATTR(temp_scale, "-0.47"); +static IIO_DEV_ATTR_TEMP_RAW(adis16209_read_temp); +static IIO_CONST_ATTR_TEMP_OFFSET("25"); +static IIO_CONST_ATTR_TEMP_SCALE("-0.47"); static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16209_write_reset, 0); -static IIO_CONST_ATTR(name, "adis16209"); +static IIO_CONST_ATTR_NAME("adis16209"); static struct attribute *adis16209_event_attributes[] = { NULL @@ -446,24 +438,22 @@ static struct attribute_group adis16209_event_attribute_group = { }; static struct attribute *adis16209_attributes[] = { - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, - &iio_dev_attr_temp.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_temp_raw.dev_attr.attr, &iio_const_attr_temp_offset.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, - &iio_const_attr_in0_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_accel_x_raw.dev_attr.attr, &iio_dev_attr_accel_y_raw.dev_attr.attr, - &iio_dev_attr_accel_x_offset.dev_attr.attr, - &iio_dev_attr_accel_y_offset.dev_attr.attr, + &iio_dev_attr_accel_x_calibbias.dev_attr.attr, + &iio_dev_attr_accel_y_calibbias.dev_attr.attr, &iio_const_attr_accel_scale.dev_attr.attr, &iio_dev_attr_incli_x_raw.dev_attr.attr, &iio_dev_attr_incli_y_raw.dev_attr.attr, - &iio_dev_attr_incli_x_offset.dev_attr.attr, - &iio_dev_attr_incli_y_offset.dev_attr.attr, &iio_const_attr_incli_scale.dev_attr.attr, &iio_dev_attr_rot_raw.dev_attr.attr, NULL diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index 25fde659d098..033135c6f226 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -17,35 +17,52 @@ #include "../trigger.h" #include "adis16209.h" -static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14), +static IIO_SCAN_EL_C(in_supply, ADIS16209_SCAN_SUPPLY, ADIS16209_SUPPLY_OUT, NULL); -static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14), - ADIS16209_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, IIO_SIGNED(14), - ADIS16209_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(aux_adc, ADIS16209_SCAN_AUX_ADC, IIO_UNSIGNED(12), - ADIS16209_AUX_ADC, NULL); -static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, IIO_UNSIGNED(12), - ADIS16209_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, IIO_SIGNED(14), +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 14, 16) +static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, ADIS16209_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, ADIS16209_YACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); +static IIO_SCAN_EL_C(in0, ADIS16209_SCAN_AUX_ADC, ADIS16209_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16); +static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, ADIS16209_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16); +static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, ADIS16209_XINCL_OUT, NULL); -static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, IIO_SIGNED(14), +static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, ADIS16209_YINCL_OUT, NULL); -static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, IIO_SIGNED(14), - ADIS16209_ROT_OUT, NULL); - +static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16); +static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, ADIS16209_ROT_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(rot, s, 14, 16); static IIO_SCAN_EL_TIMESTAMP(8); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16209_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, - &iio_scan_el_aux_adc.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, &iio_scan_el_incli_x.dev_attr.attr, + &iio_const_attr_incli_x_index.dev_attr.attr, &iio_scan_el_incli_y.dev_attr.attr, + &iio_const_attr_incli_y_index.dev_attr.attr, + &iio_const_attr_incli_type.dev_attr.attr, &iio_scan_el_rot.dev_attr.attr, + &iio_const_attr_rot_index.dev_attr.attr, + &iio_const_attr_rot_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -115,11 +132,11 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s) struct adis16209_state *st = container_of(work_s, struct adis16209_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -127,19 +144,19 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); iio_trigger_notify_done(st->indio_dev->trig); kfree(data); @@ -159,19 +176,6 @@ int adis16209_configure_ring(struct iio_dev *indio_dev) struct adis16209_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16209_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_rot.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_y.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16209_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -182,11 +186,23 @@ int adis16209_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16209_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_rot.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + iio_scan_mask_set(ring, iio_scan_el_incli_x.number); + iio_scan_mask_set(ring, iio_scan_el_incli_y.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16209_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c index 1487effa2e30..d2980dc74440 100644 --- a/drivers/staging/iio/accel/adis16209_trigger.c +++ b/drivers/staging/iio/accel/adis16209_trigger.c @@ -30,7 +30,7 @@ static int adis16209_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16209_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16209_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index bb7d76539cd7..c86d1498737d 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -485,9 +485,9 @@ static struct bin_attribute adc2_bin = { .size = ADIS16220_CAPTURE_SIZE, }; -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16220_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16220_read_12bit_unsigned, ADIS16220_CAPT_SUPPLY); -static IIO_CONST_ATTR(in_supply_scale, "0.0012207"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.0012207"); static IIO_DEV_ATTR_ACCEL(adis16220_read_16bit, ADIS16220_CAPT_BUFA); static IIO_DEVICE_ATTR(accel_peak_raw, S_IRUGO, adis16220_read_16bit, NULL, ADIS16220_CAPT_PEAKA); @@ -495,12 +495,13 @@ static IIO_DEV_ATTR_ACCEL_OFFSET(S_IWUSR | S_IRUGO, adis16220_read_16bit, adis16220_write_16bit, ADIS16220_ACCL_NULL); +static IIO_CONST_ATTR_ACCEL_SCALE("0.18704223545"); static IIO_DEV_ATTR_TEMP_RAW(adis16220_read_12bit_unsigned); -static IIO_CONST_ATTR(temp_offset, "25"); -static IIO_CONST_ATTR(temp_scale, "-0.47"); +static IIO_CONST_ATTR_TEMP_OFFSET("25"); +static IIO_CONST_ATTR_TEMP_SCALE("-0.47"); -static IIO_DEV_ATTR_IN_RAW(0, adis16220_read_16bit, ADIS16220_CAPT_BUF1); -static IIO_DEV_ATTR_IN_RAW(1, adis16220_read_16bit, ADIS16220_CAPT_BUF2); +static IIO_DEV_ATTR_IN_RAW(1, adis16220_read_16bit, ADIS16220_CAPT_BUF1); +static IIO_DEV_ATTR_IN_RAW(2, adis16220_read_16bit, ADIS16220_CAPT_BUF2); static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16220_write_reset, 0); @@ -518,22 +519,23 @@ static IIO_DEV_ATTR_CAPTURE_COUNT(S_IWUSR | S_IRUGO, adis16220_write_16bit, ADIS16220_CAPT_PNTR); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("100200"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100200"); -static IIO_CONST_ATTR(name, "adis16220"); +static IIO_CONST_ATTR_NAME("adis16220"); static struct attribute *adis16220_attributes[] = { - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, &iio_dev_attr_accel_raw.dev_attr.attr, &iio_dev_attr_accel_offset.dev_attr.attr, &iio_dev_attr_accel_peak_raw.dev_attr.attr, + &iio_const_attr_accel_scale.dev_attr.attr, &iio_dev_attr_temp_raw.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in2_raw.dev_attr.attr, &iio_const_attr_temp_offset.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_dev_attr_capture.dev_attr.attr, &iio_dev_attr_capture_count.dev_attr.attr, diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index 3e9531dd0000..d11d164207ee 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -376,11 +376,14 @@ err_ret: return ret; } -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16240_read_10bit_unsigned, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16240_read_10bit_unsigned, ADIS16240_SUPPLY_OUT); -static IIO_DEV_ATTR_IN_RAW(0, adis16240_read_10bit_signed, +static IIO_DEV_ATTR_IN_RAW(1, adis16240_read_10bit_signed, ADIS16240_AUX_ADC); -static IIO_CONST_ATTR(in_supply_scale, "0.00488"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.00488"); + +static IIO_CONST_ATTR_ACCEL_SCALE("0.50406181"); +static IIO_CONST_ATTR(accel_peak_scale, "6.6292954"); static IIO_DEV_ATTR_ACCEL_X(adis16240_read_10bit_signed, ADIS16240_XACCL_OUT); static IIO_DEVICE_ATTR(accel_x_peak_raw, S_IRUGO, @@ -400,26 +403,26 @@ static IIO_DEVICE_ATTR(accel_z_peak_raw, S_IRUGO, static IIO_DEVICE_ATTR(accel_xyz_squared_peak_raw, S_IRUGO, adis16240_read_12bit_signed, NULL, ADIS16240_XYZPEAK_OUT); -static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(S_IWUSR | S_IRUGO, adis16240_read_10bit_signed, adis16240_write_16bit, ADIS16240_XACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(S_IWUSR | S_IRUGO, adis16240_read_10bit_signed, adis16240_write_16bit, ADIS16240_YACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(S_IWUSR | S_IRUGO, adis16240_read_10bit_signed, adis16240_write_16bit, ADIS16240_ZACCL_OFF); static IIO_DEV_ATTR_TEMP_RAW(adis16240_read_10bit_unsigned); -static IIO_CONST_ATTR(temp_scale, "0.244"); +static IIO_CONST_ATTR_TEMP_SCALE("0.244"); static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16240_write_reset, 0); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("4096"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096"); -static IIO_CONST_ATTR(name, "adis16240"); +static IIO_CONST_ATTR_NAME("adis16240"); static struct attribute *adis16240_event_attributes[] = { NULL @@ -430,22 +433,24 @@ static struct attribute_group adis16240_event_attribute_group = { }; static struct attribute *adis16240_attributes[] = { - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_accel_scale.dev_attr.attr, + &iio_const_attr_accel_peak_scale.dev_attr.attr, &iio_dev_attr_accel_x_raw.dev_attr.attr, - &iio_dev_attr_accel_x_offset.dev_attr.attr, + &iio_dev_attr_accel_x_calibbias.dev_attr.attr, &iio_dev_attr_accel_x_peak_raw.dev_attr.attr, &iio_dev_attr_accel_y_raw.dev_attr.attr, - &iio_dev_attr_accel_y_offset.dev_attr.attr, + &iio_dev_attr_accel_y_calibbias.dev_attr.attr, &iio_dev_attr_accel_y_peak_raw.dev_attr.attr, &iio_dev_attr_accel_z_raw.dev_attr.attr, - &iio_dev_attr_accel_z_offset.dev_attr.attr, + &iio_dev_attr_accel_z_calibbias.dev_attr.attr, &iio_dev_attr_accel_z_peak_raw.dev_attr.attr, &iio_dev_attr_accel_xyz_squared_peak_raw.dev_attr.attr, &iio_dev_attr_temp_raw.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, NULL diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c index cd69a2e2bb9a..f882e9c150e2 100644 --- a/drivers/staging/iio/accel/adis16240_ring.c +++ b/drivers/staging/iio/accel/adis16240_ring.c @@ -17,29 +17,40 @@ #include "../trigger.h" #include "adis16240.h" -static IIO_SCAN_EL_C(supply, ADIS16240_SCAN_SUPPLY, IIO_UNSIGNED(10), +static IIO_SCAN_EL_C(in_supply, ADIS16240_SCAN_SUPPLY, ADIS16240_SUPPLY_OUT, NULL); -static IIO_SCAN_EL_C(accel_x, ADIS16240_SCAN_ACC_X, IIO_SIGNED(10), - ADIS16240_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16240_SCAN_ACC_Y, IIO_SIGNED(10), - ADIS16240_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_z, ADIS16240_SCAN_ACC_Z, IIO_SIGNED(10), - ADIS16240_ZACCL_OUT, NULL); -static IIO_SCAN_EL_C(aux_adc, ADIS16240_SCAN_AUX_ADC, IIO_UNSIGNED(10), - ADIS16240_AUX_ADC, NULL); -static IIO_SCAN_EL_C(temp, ADIS16240_SCAN_TEMP, IIO_UNSIGNED(10), - ADIS16240_TEMP_OUT, NULL); - +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 10, 16); +static IIO_SCAN_EL_C(accel_x, ADIS16240_SCAN_ACC_X, ADIS16240_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16240_SCAN_ACC_Y, ADIS16240_YACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_z, ADIS16240_SCAN_ACC_Z, ADIS16240_ZACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 10, 16); +static IIO_SCAN_EL_C(in0, ADIS16240_SCAN_AUX_ADC, ADIS16240_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 10, 16); +static IIO_SCAN_EL_C(temp, ADIS16240_SCAN_TEMP, ADIS16240_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 10, 16); static IIO_SCAN_EL_TIMESTAMP(6); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16240_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, - &iio_scan_el_aux_adc.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -107,11 +118,11 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s) struct adis16240_state *st = container_of(work_s, struct adis16240_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -119,17 +130,17 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16240_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, + ring->access.store_to(ring, (u8 *)data, st->last_timestamp); @@ -151,17 +162,6 @@ int adis16240_configure_ring(struct iio_dev *indio_dev) struct adis16240_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16240_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16240_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -172,11 +172,21 @@ int adis16240_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16240_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_accel_z.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16240_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c index 2ba71fd73a47..6cb8681f2853 100644 --- a/drivers/staging/iio/accel/adis16240_trigger.c +++ b/drivers/staging/iio/accel/adis16240_trigger.c @@ -30,7 +30,7 @@ static int adis16240_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16240_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16240_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/accel/inclinometer.h b/drivers/staging/iio/accel/inclinometer.h index 5b49f835eac5..faf73d7892e0 100644 --- a/drivers/staging/iio/accel/inclinometer.h +++ b/drivers/staging/iio/accel/inclinometer.h @@ -21,3 +21,5 @@ #define IIO_DEV_ATTR_INCLI_Z_OFFSET(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(incli_z_offset, _mode, _show, _store, _addr) +#define IIO_CONST_ATTR_INCLI_SCALE(_string) \ + IIO_CONST_ATTR(incli_scale, _string) diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 0ee933737545..c4b4ab7e6423 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -497,7 +497,7 @@ static LIS3L02DQ_UNSIGNED_ATTR(accel_y_calibscale, static LIS3L02DQ_UNSIGNED_ATTR(accel_z_calibscale, LIS3L02DQ_REG_GAIN_Z_ADDR); -static IIO_DEVICE_ATTR(accel_mag_either_rising_value, +static IIO_DEVICE_ATTR(accel_raw_mag_value, S_IWUSR | S_IRUGO, lis3l02dq_read_16bit_signed, lis3l02dq_write_16bit_signed, @@ -639,32 +639,56 @@ static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s) if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Z_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Z_LOW, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Y_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Y_LOW, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_X_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->thresh_timestamp); if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW) iio_push_event(st->help.indio_dev, 0, - IIO_EVENT_CODE_ACCEL_X_LOW, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), st->thresh_timestamp); /* reenable the irq */ enable_irq(st->us->irq); @@ -679,37 +703,37 @@ static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s) /* A shared handler for a number of threshold types */ IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th); -IIO_EVENT_ATTR_SH(accel_x_mag_pos_rising_en, +IIO_EVENT_ATTR_SH(accel_x_thresh_rising_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_HIGH); -IIO_EVENT_ATTR_SH(accel_y_mag_pos_rising_en, +IIO_EVENT_ATTR_SH(accel_y_thresh_rising_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_HIGH); -IIO_EVENT_ATTR_SH(accel_z_mag_pos_rising_en, +IIO_EVENT_ATTR_SH(accel_z_thresh_rising_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH); -IIO_EVENT_ATTR_SH(accel_x_mag_neg_rising_en, +IIO_EVENT_ATTR_SH(accel_x_thresh_falling_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_LOW); -IIO_EVENT_ATTR_SH(accel_y_mag_neg_rising_en, +IIO_EVENT_ATTR_SH(accel_y_thresh_falling_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_LOW); -IIO_EVENT_ATTR_SH(accel_z_mag_neg_rising_en, +IIO_EVENT_ATTR_SH(accel_z_thresh_falling_en, iio_event_threshold, lis3l02dq_read_interrupt_config, lis3l02dq_write_interrupt_config, @@ -717,13 +741,13 @@ IIO_EVENT_ATTR_SH(accel_z_mag_neg_rising_en, static struct attribute *lis3l02dq_event_attributes[] = { - &iio_event_attr_accel_x_mag_pos_rising_en.dev_attr.attr, - &iio_event_attr_accel_y_mag_pos_rising_en.dev_attr.attr, - &iio_event_attr_accel_z_mag_pos_rising_en.dev_attr.attr, - &iio_event_attr_accel_x_mag_neg_rising_en.dev_attr.attr, - &iio_event_attr_accel_y_mag_neg_rising_en.dev_attr.attr, - &iio_event_attr_accel_z_mag_neg_rising_en.dev_attr.attr, - &iio_dev_attr_accel_mag_either_rising_value.dev_attr.attr, + &iio_event_attr_accel_x_thresh_rising_en.dev_attr.attr, + &iio_event_attr_accel_y_thresh_rising_en.dev_attr.attr, + &iio_event_attr_accel_z_thresh_rising_en.dev_attr.attr, + &iio_event_attr_accel_x_thresh_falling_en.dev_attr.attr, + &iio_event_attr_accel_y_thresh_falling_en.dev_attr.attr, + &iio_event_attr_accel_z_thresh_falling_en.dev_attr.attr, + &iio_dev_attr_accel_raw_mag_value.dev_attr.attr, NULL }; @@ -731,7 +755,7 @@ static struct attribute_group lis3l02dq_event_attribute_group = { .attrs = lis3l02dq_event_attributes, }; -static IIO_CONST_ATTR(name, "lis3l02dq"); +static IIO_CONST_ATTR_NAME("lis3l02dq"); static IIO_CONST_ATTR(accel_scale, "0.00958"); static struct attribute *lis3l02dq_attributes[] = { diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index a960a8ff3c40..330d5d6dbba4 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -75,22 +75,30 @@ error_ret: return ret; } -static IIO_SCAN_EL_C(accel_x, 0, IIO_SIGNED(16), +static IIO_SCAN_EL_C(accel_x, 0, LIS3L02DQ_REG_OUT_X_L_ADDR, &lis3l02dq_scan_el_set_state); -static IIO_SCAN_EL_C(accel_y, 1, IIO_SIGNED(16), +static IIO_SCAN_EL_C(accel_y, 1, LIS3L02DQ_REG_OUT_Y_L_ADDR, &lis3l02dq_scan_el_set_state); -static IIO_SCAN_EL_C(accel_z, 2, IIO_SIGNED(16), +static IIO_SCAN_EL_C(accel_z, 2, LIS3L02DQ_REG_OUT_Z_L_ADDR, &lis3l02dq_scan_el_set_state); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 12, 16); static IIO_SCAN_EL_TIMESTAMP(3); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *lis3l02dq_scan_el_attrs[] = { &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -150,38 +158,40 @@ ssize_t lis3l02dq_read_accel_from_ring(struct device *dev, int ret, len = 0, i = 0; struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_info->ring; + struct attribute_group *scan_el_attrs = ring->scan_el_attrs; s16 *data; - while (dev_info->scan_el_attrs->attrs[i]) { + while (scan_el_attrs->attrs[i]) { el = to_iio_scan_el((struct device_attribute *) - (dev_info->scan_el_attrs->attrs[i])); + (scan_el_attrs->attrs[i])); /* label is in fact the address */ if (el->label == this_attr->address) break; i++; } - if (!dev_info->scan_el_attrs->attrs[i]) { + if (!scan_el_attrs->attrs[i]) { ret = -EINVAL; goto error_ret; } /* If this element is in the scan mask */ - ret = iio_scan_mask_query(dev_info, el->number); + ret = iio_scan_mask_query(ring, el->number); if (ret < 0) goto error_ret; if (ret) { - data = kmalloc(dev_info->ring->access.get_bpd(dev_info->ring), + data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); if (data == NULL) return -ENOMEM; - ret = dev_info->ring->access.read_last(dev_info->ring, - (u8 *)data); + ret = ring->access.read_last(ring, + (u8 *)data); if (ret) goto error_free_data; } else { ret = -EINVAL; goto error_ret; } - len = iio_scan_mask_count_to_right(dev_info, el->number); + len = iio_scan_mask_count_to_right(ring, el->number); if (len < 0) { ret = len; goto error_free_data; @@ -211,11 +221,12 @@ static const u8 read_all_tx_array[] = { **/ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) { + struct iio_ring_buffer *ring = st->help.indio_dev->ring; struct spi_transfer *xfers; struct spi_message msg; int ret, i, j = 0; - xfers = kzalloc((st->help.indio_dev->scan_count) * 2 + xfers = kzalloc((ring->scan_count) * 2 * sizeof(*xfers), GFP_KERNEL); if (!xfers) return -ENOMEM; @@ -223,7 +234,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) mutex_lock(&st->buf_lock); for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++) { - if (st->help.indio_dev->scan_mask & (1 << i)) { + if (ring->scan_mask & (1 << i)) { /* lower byte */ xfers[j].tx_buf = st->tx + 2*j; st->tx[2*j] = read_all_tx_array[i*4]; @@ -251,7 +262,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) * values in alternate bytes */ spi_message_init(&msg); - for (j = 0; j < st->help.indio_dev->scan_count * 2; j++) + for (j = 0; j < ring->scan_count * 2; j++) spi_message_add_tail(&xfers[j], &msg); ret = spi_sync(st->us, &msg); @@ -279,13 +290,13 @@ static int lis3l02dq_get_ring_element(struct iio_sw_ring_helper_state *h, u8 *rx_array ; s16 *data = (s16 *)buf; - rx_array = kzalloc(4 * (h->indio_dev->scan_count), GFP_KERNEL); + rx_array = kzalloc(4 * (h->indio_dev->ring->scan_count), GFP_KERNEL); if (rx_array == NULL) return -ENOMEM; ret = lis3l02dq_read_all(lis3l02dq_h_to_s(h), rx_array); if (ret < 0) return ret; - for (i = 0; i < h->indio_dev->scan_count; i++) + for (i = 0; i < h->indio_dev->ring->scan_count; i++) data[i] = combine_8_to_16(rx_array[i*4+1], rx_array[i*4+3]); kfree(rx_array); @@ -379,7 +390,8 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, &t); return ret; } -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static IIO_TRIGGER_NAME_ATTR; static struct attribute *lis3l02dq_trigger_attrs[] = { &dev_attr_name.attr, @@ -479,28 +491,29 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev) { int ret; struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev); - + struct iio_ring_buffer *ring; INIT_WORK(&h->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring); - /* Set default scan mode */ h->get_ring_element = &lis3l02dq_get_ring_element; - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); - indio_dev->scan_timestamp = true; - indio_dev->scan_el_attrs = &lis3l02dq_scan_el_group; - - indio_dev->ring = iio_sw_rb_allocate(indio_dev); - if (!indio_dev->ring) + ring = iio_sw_rb_allocate(indio_dev); + if (!ring) return -ENOMEM; + indio_dev->ring = ring; /* Effectively select the ring buffer implementation */ - iio_ring_sw_register_funcs(&indio_dev->ring->access); - indio_dev->ring->bpe = 2; - indio_dev->ring->preenable = &iio_sw_ring_preenable; - indio_dev->ring->postenable = &iio_triggered_ring_postenable; - indio_dev->ring->predisable = &iio_triggered_ring_predisable; - indio_dev->ring->owner = THIS_MODULE; + iio_ring_sw_register_funcs(&ring->access); + ring->bpe = 2; + ring->scan_el_attrs = &lis3l02dq_scan_el_group; + ring->scan_timestamp = true; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; + ring->owner = THIS_MODULE; + + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_accel_z.number); ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th); if (ret) diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h index 09d9470bb9a0..23892848f5ae 100644 --- a/drivers/staging/iio/accel/sca3000.h +++ b/drivers/staging/iio/accel/sca3000.h @@ -91,7 +91,7 @@ #define SCA3000_INT_STATUS_X_TRIGGER 0x02 #define SCA3000_INT_STATUS_Z_TRIGGER 0x01 -/* Used to allow accesss to multiplexed registers */ +/* Used to allow access to multiplexed registers */ #define SCA3000_REG_ADDR_CTRL_SEL 0x18 /* Only available for SCA3000-D03 and SCA3000-D01 */ #define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index b78b6b66ffe0..5b06dea6af25 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -721,8 +721,8 @@ error_ret: } static IIO_DEV_ATTR_TEMP_RAW(sca3000_read_temp); -static IIO_CONST_ATTR(temp_scale, "0.555556"); -static IIO_CONST_ATTR(temp_offset, "-214.6"); +static IIO_CONST_ATTR_TEMP_SCALE("0.555556"); +static IIO_CONST_ATTR_TEMP_OFFSET("-214.6"); /** * sca3000_show_thresh() sysfs query of a threshold @@ -774,19 +774,19 @@ static ssize_t sca3000_write_thresh(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(accel_x_mag_either_rising_value, +static IIO_DEVICE_ATTR(accel_x_raw_mag_rising_value, S_IRUGO | S_IWUSR, sca3000_show_thresh, sca3000_write_thresh, SCA3000_REG_CTRL_SEL_MD_X_TH); -static IIO_DEVICE_ATTR(accel_y_mag_either_rising_value, +static IIO_DEVICE_ATTR(accel_y_raw_mag_rising_value, S_IRUGO | S_IWUSR, sca3000_show_thresh, sca3000_write_thresh, SCA3000_REG_CTRL_SEL_MD_Y_TH); -static IIO_DEVICE_ATTR(accel_z_mag_either_rising_value, +static IIO_DEVICE_ATTR(accel_z_raw_mag_rising_value, S_IRUGO | S_IWUSR, sca3000_show_thresh, sca3000_write_thresh, @@ -865,22 +865,38 @@ static void sca3000_interrupt_handler_bh(struct work_struct *work_s) if (rx[1] & SCA3000_INT_STATUS_FREE_FALL) iio_push_event(st->indio_dev, 0, - IIO_EVENT_CODE_FREE_FALL, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), st->last_timestamp); if (rx[1] & SCA3000_INT_STATUS_Y_TRIGGER) iio_push_event(st->indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Y_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Y, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), st->last_timestamp); if (rx[1] & SCA3000_INT_STATUS_X_TRIGGER) iio_push_event(st->indio_dev, 0, - IIO_EVENT_CODE_ACCEL_X_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_X, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), st->last_timestamp); if (rx[1] & SCA3000_INT_STATUS_Z_TRIGGER) iio_push_event(st->indio_dev, 0, - IIO_EVENT_CODE_ACCEL_Z_HIGH, + IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL, + 0, + IIO_EV_MOD_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), st->last_timestamp); done: @@ -1156,25 +1172,31 @@ exit_point: IIO_EVENT_SH(all, &sca3000_handler_th); /* Free fall detector related event attribute */ -IIO_EVENT_ATTR_FREE_FALL_DETECT_SH(iio_event_all, - sca3000_query_free_fall_mode, - sca3000_set_free_fall_mode, - 0) +IIO_EVENT_ATTR_NAMED_SH(accel_xayaz_mag_falling_en, + accel_x&y&z_mag_falling_en, + iio_event_all, + sca3000_query_free_fall_mode, + sca3000_set_free_fall_mode, + 0); + +IIO_CONST_ATTR_NAMED(accel_xayaz_mag_falling_period, + accel_x&y&z_mag_falling_period, + "0.226"); /* Motion detector related event attributes */ -IIO_EVENT_ATTR_SH(accel_x_mag_either_rising_en, +IIO_EVENT_ATTR_SH(accel_x_mag_rising_en, iio_event_all, sca3000_query_mo_det, sca3000_set_mo_det, SCA3000_MD_CTRL_OR_X); -IIO_EVENT_ATTR_SH(accel_y_mag_either_rising_en, +IIO_EVENT_ATTR_SH(accel_y_mag_rising_en, iio_event_all, sca3000_query_mo_det, sca3000_set_mo_det, SCA3000_MD_CTRL_OR_Y); -IIO_EVENT_ATTR_SH(accel_z_mag_either_rising_en, +IIO_EVENT_ATTR_SH(accel_z_mag_rising_en, iio_event_all, sca3000_query_mo_det, sca3000_set_mo_det, @@ -1192,15 +1214,16 @@ IIO_EVENT_ATTR_RING_75_FULL_SH(iio_event_all, SCA3000_INT_MASK_RING_THREE_QUARTER); static struct attribute *sca3000_event_attributes[] = { - &iio_event_attr_free_fall.dev_attr.attr, - &iio_event_attr_accel_x_mag_either_rising_en.dev_attr.attr, - &iio_event_attr_accel_y_mag_either_rising_en.dev_attr.attr, - &iio_event_attr_accel_z_mag_either_rising_en.dev_attr.attr, + &iio_event_attr_accel_xayaz_mag_falling_en.dev_attr.attr, + &iio_const_attr_accel_xayaz_mag_falling_period.dev_attr.attr, + &iio_event_attr_accel_x_mag_rising_en.dev_attr.attr, + &iio_dev_attr_accel_x_raw_mag_rising_value.dev_attr.attr, + &iio_event_attr_accel_y_mag_rising_en.dev_attr.attr, + &iio_dev_attr_accel_y_raw_mag_rising_value.dev_attr.attr, + &iio_event_attr_accel_z_mag_rising_en.dev_attr.attr, + &iio_dev_attr_accel_z_raw_mag_rising_value.dev_attr.attr, &iio_event_attr_ring_50_full.dev_attr.attr, &iio_event_attr_ring_75_full.dev_attr.attr, - &iio_dev_attr_accel_x_mag_either_rising_value.dev_attr.attr, - &iio_dev_attr_accel_y_mag_either_rising_value.dev_attr.attr, - &iio_dev_attr_accel_z_mag_either_rising_value.dev_attr.attr, NULL, }; @@ -1358,7 +1381,7 @@ static int __devinit __sca3000_probe(struct spi_device *spi, * might be worthwhile. */ iio_add_event_to_list( - iio_event_attr_accel_z_mag_either_rising_en.listel, + iio_event_attr_accel_z_mag_rising_en.listel, &st->indio_dev ->interrupts[0]->ev_list); } diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index 8e8c068d401b..c872fddfb2bf 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -53,7 +53,8 @@ static int sca3000_rip_hw_rb(struct iio_ring_buffer *r, struct iio_dev *indio_dev = hw_ring->private; struct sca3000_state *st = indio_dev->dev_data; u8 *rx; - int ret, num_available, num_read = 0; + s16 *samples; + int ret, i, num_available, num_read = 0; int bytes_per_sample = 1; if (st->bpse == 11) @@ -87,6 +88,17 @@ static int sca3000_rip_hw_rb(struct iio_ring_buffer *r, ret = sca3000_read_data(st, SCA3000_REG_ADDR_RING_OUT, data, num_read); + + /* Convert byte order and shift to default resolution */ + if (st->bpse == 11) { + samples = (s16*)(*data+1); + for (i = 0; i < (num_read/2); i++) { + samples[i] = be16_to_cpup( + (__be16 *)&(samples[i])); + samples[i] >>= 3; + } + } + error_ret: mutex_unlock(&st->lock); @@ -100,7 +112,7 @@ static int sca3000_ring_get_length(struct iio_ring_buffer *r) } /* only valid if resolution is kept at 11bits */ -static int sca3000_ring_get_bpd(struct iio_ring_buffer *r) +static int sca3000_ring_get_bytes_per_datum(struct iio_ring_buffer *r) { return 6; } @@ -111,7 +123,7 @@ static void sca3000_ring_release(struct device *dev) } static IIO_RING_ENABLE_ATTR; -static IIO_RING_BPS_ATTR; +static IIO_RING_BYTES_PER_DATUM_ATTR; static IIO_RING_LENGTH_ATTR; /** @@ -126,14 +138,18 @@ static ssize_t sca3000_show_ring_bpse(struct device *dev, { int len = 0, ret; u8 *rx; - struct iio_ring_buffer *r = dev_get_drvdata(dev); - struct sca3000_state *st = r->indio_dev->dev_data; + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct sca3000_state *st = indio_dev->dev_data; mutex_lock(&st->lock); ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1); if (ret) goto error_ret; - len = sprintf(buf, "%d\n", (rx[1] & SCA3000_RING_BUF_8BIT) ? 8 : 11); + if (rx[1] & SCA3000_RING_BUF_8BIT) + len = sprintf(buf, "s8/8\n"); + else + len = sprintf(buf, "s11/16\n"); kfree(rx); error_ret: mutex_unlock(&st->lock); @@ -153,44 +169,38 @@ static ssize_t sca3000_store_ring_bpse(struct device *dev, const char *buf, size_t len) { - struct iio_ring_buffer *r = dev_get_drvdata(dev); - struct sca3000_state *st = r->indio_dev->dev_data; + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct sca3000_state *st = indio_dev->dev_data; int ret; u8 *rx; - long val; - ret = strict_strtol(buf, 10, &val); - if (ret) - return ret; mutex_lock(&st->lock); ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1); - if (!ret) - switch (val) { - case 8: - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - rx[1] | SCA3000_RING_BUF_8BIT); - st->bpse = 8; - break; - case 11: - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - rx[1] & ~SCA3000_RING_BUF_8BIT); - st->bpse = 11; - break; - default: - ret = -EINVAL; - break; - } + if (ret) + goto error_ret; + if (strncmp(buf, "s8/8", 4) == 0) { + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + rx[1] | SCA3000_RING_BUF_8BIT); + st->bpse = 8; + } else if (strncmp(buf, "s11/16", 5) == 0) { + ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, + rx[1] & ~SCA3000_RING_BUF_8BIT); + st->bpse = 11; + } else + ret = -EINVAL; +error_ret: mutex_unlock(&st->lock); return ret ? ret : len; } -static IIO_SCAN_EL_C(accel_x, 0, 0, 0, NULL); -static IIO_SCAN_EL_C(accel_y, 1, 0, 0, NULL); -static IIO_SCAN_EL_C(accel_z, 2, 0, 0, NULL); -static IIO_CONST_ATTR(accel_precision_available, "8 11"); -static IIO_DEVICE_ATTR(accel_precision, +static IIO_SCAN_EL_C(accel_x, 0, 0, NULL); +static IIO_SCAN_EL_C(accel_y, 1, 0, NULL); +static IIO_SCAN_EL_C(accel_z, 2, 0, NULL); +static IIO_CONST_ATTR(accel_type_available, "s8/8 s11/16"); +static IIO_DEVICE_ATTR(accel_type, S_IRUGO | S_IWUSR, sca3000_show_ring_bpse, sca3000_store_ring_bpse, @@ -198,10 +208,13 @@ static IIO_DEVICE_ATTR(accel_precision, static struct attribute *sca3000_scan_el_attrs[] = { &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, - &iio_const_attr_accel_precision_available.dev_attr.attr, - &iio_dev_attr_accel_precision.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type_available.dev_attr.attr, + &iio_dev_attr_accel_type.dev_attr.attr, NULL }; @@ -218,8 +231,8 @@ static struct attribute_group sca3000_scan_el_group = { */ static struct attribute *sca3000_ring_attributes[] = { &dev_attr_length.attr, - &dev_attr_bps.attr, - &dev_attr_ring_enable.attr, + &dev_attr_bytes_per_datum.attr, + &dev_attr_enable.attr, NULL, }; @@ -264,15 +277,15 @@ static inline void sca3000_rb_free(struct iio_ring_buffer *r) int sca3000_configure_ring(struct iio_dev *indio_dev) { - indio_dev->scan_el_attrs = &sca3000_scan_el_group; indio_dev->ring = sca3000_rb_allocate(indio_dev); if (indio_dev->ring == NULL) return -ENOMEM; indio_dev->modes |= INDIO_RING_HARDWARE_BUFFER; + indio_dev->ring->scan_el_attrs = &sca3000_scan_el_group; indio_dev->ring->access.rip_lots = &sca3000_rip_hw_rb; indio_dev->ring->access.get_length = &sca3000_ring_get_length; - indio_dev->ring->access.get_bpd = &sca3000_ring_get_bpd; + indio_dev->ring->access.get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum; return 0; } diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 0835fbc86c2a..acb67677e563 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -26,3 +26,38 @@ config MAX1363_RING_BUFFER help Say yes here to include ring buffer support in the MAX1363 ADC driver. + +config AD799X + tristate "Analog Devices AD799x ADC driver" + depends on I2C + select IIO_TRIGGER if IIO_RING_BUFFER + select AD799X_RING_BUFFER + help + Say yes here to build support for Analog Devices: + ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 + i2c analog to digital convertors (ADC). Provides direct access + via sysfs. + +config AD799X_RING_BUFFER + bool "Analog Devices AD799x: use ring buffer" + depends on AD799X + select IIO_RING_BUFFER + select IIO_SW_RING + help + Say yes here to include ring buffer support in the AD799X + ADC driver. + +config AD7476 + tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver" + depends on SPI + select IIO_RING_BUFFER + select IIO_SW_RING + select IIO_TRIGGER + help + Say yes here to build support for Analog Devices + AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495 + SPI analog to digital convertors (ADC). + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called ad7476. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 688510fd8bbb..b62c319bcedd 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -6,3 +6,11 @@ max1363-y := max1363_core.o max1363-y += max1363_ring.o obj-$(CONFIG_MAX1363) += max1363.o + +ad799x-y := ad799x_core.o +ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o +obj-$(CONFIG_AD799X) += ad799x.o + +ad7476-y := ad7476_core.o +ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o +obj-$(CONFIG_AD7476) += ad7476.o diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h new file mode 100644 index 000000000000..b51b49e4abd6 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476.h @@ -0,0 +1,77 @@ +/* + * AD7476/5/7/8 (A) SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_ADC_AD7476_H_ +#define IIO_ADC_AD7476_H_ + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +/* + * TODO: struct ad7476_platform_data needs to go into include/linux/iio + */ + +struct ad7476_platform_data { + u16 vref_mv; +}; + +struct ad7476_chip_info { + u8 bits; + u8 storagebits; + u8 res_shift; + char sign; + u16 int_vref_mv; +}; + +struct ad7476_state { + struct iio_dev *indio_dev; + struct spi_device *spi; + const struct ad7476_chip_info *chip_info; + struct regulator *reg; + struct work_struct poll_work; + atomic_t protect_ring; + u16 int_vref_mv; + struct spi_transfer xfer; + struct spi_message msg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + unsigned char data[2] ____cacheline_aligned; +}; + +enum ad7476_supported_device_ids { + ID_AD7466, + ID_AD7467, + ID_AD7468, + ID_AD7475, + ID_AD7476, + ID_AD7477, + ID_AD7478, + ID_AD7495 +}; + +#ifdef CONFIG_IIO_RING_BUFFER +int ad7476_scan_from_ring(struct ad7476_state *st); +int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev); +void ad7476_ring_cleanup(struct iio_dev *indio_dev); +#else /* CONFIG_IIO_RING_BUFFER */ +static inline int ad7476_scan_from_ring(struct ad7476_state *st) +{ + return 0; +} + +static inline int +ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* IIO_ADC_AD7476_H_ */ diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c new file mode 100644 index 000000000000..deb68c8a6e18 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_core.c @@ -0,0 +1,293 @@ +/* + * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_generic.h" +#include "adc.h" + +#include "ad7476.h" + +static int ad7476_scan_direct(struct ad7476_state *st) +{ + int ret; + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + return (st->data[0] << 8) | st->data[1]; +} + +static ssize_t ad7476_scan(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = dev_info->dev_data; + int ret; + + mutex_lock(&dev_info->mlock); + if (iio_ring_enabled(dev_info)) + ret = ad7476_scan_from_ring(st); + else + ret = ad7476_scan_direct(st); + mutex_unlock(&dev_info->mlock); + + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", (ret >> st->chip_info->res_shift) & + RES_MASK(st->chip_info->bits)); +} +static IIO_DEV_ATTR_IN_RAW(0, ad7476_scan, 0); + +static ssize_t ad7476_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* Driver currently only support internal vref */ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = iio_dev_get_devdata(dev_info); + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0); + +static ssize_t ad7476_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = iio_dev_get_devdata(dev_info); + + return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); +} +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7476_show_name, NULL, 0); + +static struct attribute *ad7476_attributes[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7476_attribute_group = { + .attrs = ad7476_attributes, +}; + +static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { + [ID_AD7466] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7467] = { + .bits = 10, + .storagebits = 16, + .res_shift = 2, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7468] = { + .bits = 8, + .storagebits = 16, + .res_shift = 4, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7475] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7476] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7477] = { + .bits = 10, + .storagebits = 16, + .res_shift = 2, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7478] = { + .bits = 8, + .storagebits = 16, + .res_shift = 4, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7495] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .int_vref_mv = 2500, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, +}; + +static int __devinit ad7476_probe(struct spi_device *spi) +{ + struct ad7476_platform_data *pdata = spi->dev.platform_data; + struct ad7476_state *st; + int ret, voltage_uv = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + voltage_uv = regulator_get_voltage(st->reg); + } + + st->chip_info = + &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + if (st->chip_info->int_vref_mv) + st->int_vref_mv = st->chip_info->int_vref_mv; + else if (pdata && pdata->vref_mv) + st->int_vref_mv = pdata->vref_mv; + else if (voltage_uv) + st->int_vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + + spi_set_drvdata(spi, st); + + atomic_set(&st->protect_ring, 0); + st->spi = spi; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the i2c device */ + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->attrs = &ad7476_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default message */ + + st->xfer.rx_buf = &st->data; + st->xfer.len = st->chip_info->storagebits / 8; + + spi_message_init(&st->msg); + spi_message_add_tail(&st->xfer, &st->msg); + + ret = ad7476_register_ring_funcs_and_init(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto error_cleanup_ring; + return 0; + +error_cleanup_ring: + ad7476_ring_cleanup(st->indio_dev); + iio_device_unregister(st->indio_dev); +error_free_device: + iio_free_device(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static int ad7476_remove(struct spi_device *spi) +{ + struct ad7476_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + iio_ring_buffer_unregister(indio_dev->ring); + ad7476_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + return 0; +} + +static const struct spi_device_id ad7476_id[] = { + {"ad7466", ID_AD7466}, + {"ad7467", ID_AD7467}, + {"ad7468", ID_AD7468}, + {"ad7475", ID_AD7475}, + {"ad7476", ID_AD7476}, + {"ad7476a", ID_AD7476}, + {"ad7477", ID_AD7477}, + {"ad7477a", ID_AD7477}, + {"ad7478", ID_AD7478}, + {"ad7478a", ID_AD7478}, + {"ad7495", ID_AD7495}, + {} +}; + +static struct spi_driver ad7476_driver = { + .driver = { + .name = "ad7476", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7476_probe, + .remove = __devexit_p(ad7476_remove), + .id_table = ad7476_id, +}; + +static int __init ad7476_init(void) +{ + return spi_register_driver(&ad7476_driver); +} +module_init(ad7476_init); + +static void __exit ad7476_exit(void) +{ + spi_unregister_driver(&ad7476_driver); +} +module_exit(ad7476_exit); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad7476"); diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c new file mode 100644 index 000000000000..85de14274ad7 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_ring.c @@ -0,0 +1,207 @@ +/* + * Copyright 2010 Analog Devices Inc. + * Copyright (C) 2008 Jonathan Cameron + * + * Licensed under the GPL-2 or later. + * + * ad7476_ring.c + */ + +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/spi/spi.h> + +#include "../iio.h" +#include "../ring_generic.h" +#include "../ring_sw.h" +#include "../trigger.h" +#include "../sysfs.h" + +#include "ad7476.h" + +static IIO_SCAN_EL_C(in0, 0, 0, NULL); + +static ssize_t ad7476_show_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad7476_state *st = indio_dev->dev_data; + + return sprintf(buf, "%c%d/%d>>%d\n", st->chip_info->sign, + st->chip_info->bits, st->chip_info->storagebits, + st->chip_info->res_shift); +} +static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7476_show_type, NULL, 0); + +static struct attribute *ad7476_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7476_scan_el_group = { + .name = "scan_elements", + .attrs = ad7476_scan_el_attrs, +}; + +int ad7476_scan_from_ring(struct ad7476_state *st) +{ + struct iio_ring_buffer *ring = st->indio_dev->ring; + int ret; + u8 *ring_data; + + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); + if (ring_data == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = ring->access.read_last(ring, ring_data); + if (ret) + goto error_free_ring_data; + + ret = (ring_data[0] << 8) | ring_data[1]; + +error_free_ring_data: + kfree(ring_data); +error_ret: + return ret; +} + +/** + * ad7476_ring_preenable() setup the parameters of the ring before enabling + * + * The complex nature of the setting of the nuber of bytes per datum is due + * to this driver currently ensuring that the timestamp is stored at an 8 + * byte boundary. + **/ +static int ad7476_ring_preenable(struct iio_dev *indio_dev) +{ + struct ad7476_state *st = indio_dev->dev_data; + size_t d_size; + + if (indio_dev->ring->access.set_bytes_per_datum) { + d_size = st->chip_info->storagebits / 8 + sizeof(s64); + if (d_size % 8) + d_size += 8 - (d_size % 8); + indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring, + d_size); + } + + return 0; +} + +/** + * ad7476_poll_func_th() th of trigger launched polling to ring buffer + * + * As sampling only occurs on i2c comms occuring, leave timestamping until + * then. Some triggers will generate their own time stamp. Currently + * there is no way of notifying them when no one cares. + **/ +static void ad7476_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ad7476_state *st = indio_dev->dev_data; + + schedule_work(&st->poll_work); + return; +} +/** + * ad7476_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad7476_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad7476_state *st = container_of(work_s, struct ad7476_state, + poll_work); + struct iio_dev *indio_dev = st->indio_dev; + struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring); + s64 time_ns; + __u8 *rxbuf; + int b_sent; + size_t d_size; + + /* Ensure the timestamp is 8 byte aligned */ + d_size = st->chip_info->storagebits / 8 + sizeof(s64); + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + + /* Ensure only one copy of this function running at a time */ + if (atomic_inc_return(&st->protect_ring) > 1) + return; + + rxbuf = kzalloc(d_size, GFP_KERNEL); + if (rxbuf == NULL) + return; + + b_sent = spi_read(st->spi, rxbuf, st->chip_info->storagebits / 8); + if (b_sent < 0) + goto done; + + time_ns = iio_get_time_ns(); + + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns); +done: + kfree(rxbuf); + atomic_dec(&st->protect_ring); +} + +int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + struct ad7476_state *st = indio_dev->dev_data; + int ret = 0; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) { + ret = -ENOMEM; + goto error_ret; + } + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&indio_dev->ring->access); + ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7476_poll_func_th); + if (ret) + goto error_deallocate_sw_rb; + + /* Ring buffer functions - here trigger setup related */ + + indio_dev->ring->preenable = &ad7476_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + indio_dev->ring->scan_el_attrs = &ad7476_scan_el_group; + + INIT_WORK(&st->poll_work, &ad7476_poll_bh_to_ring); + + /* Flag that polled ring buffering is possible */ + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +void ad7476_ring_cleanup(struct iio_dev *indio_dev) +{ + /* ensure that the trigger has been detached */ + if (indio_dev->trig) { + iio_put_trigger(indio_dev->trig); + iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h new file mode 100644 index 000000000000..81a20d524b77 --- /dev/null +++ b/drivers/staging/iio/adc/ad799x.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2008-2010 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x.h + */ + +#ifndef _AD799X_H_ +#define _AD799X_H_ + +#define AD799X_CHANNEL_SHIFT 4 +#define AD799X_STORAGEBITS 16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR 0x08 +#define AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_ALERT 0x02 +#define AD7998_BUSY_ALERT_POL 0x01 + +#define AD7998_CONV_RES_REG 0x0 +#define AD7998_ALERT_STAT_REG 0x1 +#define AD7998_CONF_REG 0x2 +#define AD7998_CYCLE_TMR_REG 0x3 +#define AD7998_DATALOW_CH1_REG 0x4 +#define AD7998_DATAHIGH_CH1_REG 0x5 +#define AD7998_HYST_CH1_REG 0x6 +#define AD7998_DATALOW_CH2_REG 0x7 +#define AD7998_DATAHIGH_CH2_REG 0x8 +#define AD7998_HYST_CH2_REG 0x9 +#define AD7998_DATALOW_CH3_REG 0xA +#define AD7998_DATAHIGH_CH3_REG 0xB +#define AD7998_HYST_CH3_REG 0xC +#define AD7998_DATALOW_CH4_REG 0xD +#define AD7998_DATAHIGH_CH4_REG 0xE +#define AD7998_HYST_CH4_REG 0xF + +#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_DIS 0x0 +#define AD7998_CYC_TCONF_32 0x1 +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCONF_128 0x3 +#define AD7998_CYC_TCONF_256 0x4 +#define AD7998_CYC_TCONF_512 0x5 +#define AD7998_CYC_TCONF_1024 0x6 +#define AD7998_CYC_TCONF_2048 0x7 + +#define AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 + +enum { + ad7991, + ad7995, + ad7999, + ad7992, + ad7993, + ad7994, + ad7997, + ad7998 +}; + +struct ad799x_state; + +/** + * struct ad799x_chip_info - chip specifc information + * @num_inputs: number of physical inputs on chip + * @bits: accuracy of the adc in bits + * @int_vref_mv: the internal reference voltage + * @monitor_mode: whether the chip supports monitor interrupts + * @default_config: device default configuration + * @dev_attrs: pointer to the device attribute group + * @scan_attrs: pointer to the scan element attribute group + * @event_attrs: pointer to the monitor event attribute group + * @ad799x_set_scan_mode: function pointer to the device specific mode function + + */ +struct ad799x_chip_info { + u8 num_inputs; + u8 bits; + u8 storagebits; + char sign; + u16 int_vref_mv; + bool monitor_mode; + u16 default_config; + struct attribute_group *dev_attrs; + struct attribute_group *scan_attrs; + struct attribute_group *event_attrs; + int (*ad799x_set_scan_mode) (struct ad799x_state *st, + unsigned mask); +}; + +struct ad799x_state { + struct iio_dev *indio_dev; + struct i2c_client *client; + const struct ad799x_chip_info *chip_info; + struct work_struct poll_work; + struct work_struct work_thresh; + atomic_t protect_ring; + struct iio_trigger *trig; + struct regulator *reg; + s64 last_timestamp; + u16 int_vref_mv; + unsigned id; + char *name; + u16 config; +}; + +/* + * TODO: struct ad799x_platform_data needs to go into include/linux/iio + */ + +struct ad799x_platform_data { + u16 vref_mv; +}; + +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask); + +#ifdef CONFIG_AD799X_RING_BUFFER +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask); +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); +void ad799x_ring_cleanup(struct iio_dev *indio_dev); +#else /* CONFIG_AD799X_RING_BUFFER */ +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask) +{ + return -EINVAL; +} + + +static inline int +ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev) +{ +} +#endif /* CONFIG_AD799X_RING_BUFFER */ +#endif /* _AD799X_H_ */ diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c new file mode 100644 index 000000000000..6309d521a864 --- /dev/null +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -0,0 +1,923 @@ +/* + * iio/adc/ad799x.c + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * + * based on iio/adc/max1363 + * Copyright (C) 2008-2010 Jonathan Cameron + * + * based on linux/drivers/i2c/chips/max123x + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x.c + * + * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, + * ad7998 and similar chips. + * + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/err.h> + +#include "../iio.h" +#include "../sysfs.h" + +#include "../ring_generic.h" +#include "adc.h" +#include "ad799x.h" + +/* + * ad799x register access by I2C + */ +static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = swab16((u16)ret); + + return 0; +} + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = (u8)ret; + + return 0; +} + +static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_word_data(client, reg, swab16(data)); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad799x_scan_el_set_state(struct iio_scan_el *scan_el, + struct iio_dev *indio_dev, + bool state) +{ + struct ad799x_state *st = indio_dev->dev_data; + return ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask); +} + +/* Here we claim all are 16 bits. This currently does no harm and saves + * us a lot of scan element listings */ + +#define AD799X_SCAN_EL(number) \ + IIO_SCAN_EL_C(in##number, number, 0, ad799x_scan_el_set_state); + +static AD799X_SCAN_EL(0); +static AD799X_SCAN_EL(1); +static AD799X_SCAN_EL(2); +static AD799X_SCAN_EL(3); +static AD799X_SCAN_EL(4); +static AD799X_SCAN_EL(5); +static AD799X_SCAN_EL(6); +static AD799X_SCAN_EL(7); + +static ssize_t ad799x_show_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad799x_state *st = indio_dev->dev_data; + + return sprintf(buf, "%c%d/%d\n", st->chip_info->sign, + st->chip_info->bits, AD799X_STORAGEBITS); +} +static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad799x_show_type, NULL, 0); + +static int ad7991_5_9_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return i2c_smbus_write_byte(st->client, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +static int ad7992_3_4_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return ad799x_i2c_write8(st, AD7998_CONF_REG, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +static int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return ad799x_i2c_write16(st, AD7998_CONF_REG, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + int ret; + + if (st->chip_info->ad799x_set_scan_mode != NULL) { + ret = st->chip_info->ad799x_set_scan_mode(st, mask); + return (ret > 0) ? 0 : ret; + } + + return 0; +} + +static ssize_t ad799x_read_single_channel(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret = 0, len = 0; + u32 data ; + u16 rxbuf[1]; + u8 cmd; + long mask; + + mutex_lock(&dev_info->mlock); + mask = 1 << this_attr->address; + /* If ring buffer capture is occuring, query the buffer */ + if (iio_ring_enabled(dev_info)) { + data = ret = ad799x_single_channel_from_ring(st, mask); + if (ret < 0) + goto error_ret; + ret = 0; + } else { + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | (mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = mask << AD799X_CHANNEL_SHIFT; + break; + case ad7997: + case ad7998: + cmd = (this_attr->address << + AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE; + break; + default: + cmd = 0; + + } + ret = ad799x_i2c_read16(st, cmd, rxbuf); + if (ret < 0) + goto error_ret; + + data = rxbuf[0]; + } + + /* Pretty print the result */ + len = sprintf(buf, "%u\n", data & ((1 << (st->chip_info->bits)) - 1)); + +error_ret: + mutex_unlock(&dev_info->mlock); + return ret ? ret : len; +} + +static ssize_t ad799x_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + int ret, len = 0; + u8 val; + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + if (ret) + return ret; + + val &= AD7998_CYC_MASK; + + switch (val) { + case AD7998_CYC_DIS: + len = sprintf(buf, "0\n"); + break; + case AD7998_CYC_TCONF_32: + len = sprintf(buf, "15625\n"); + break; + case AD7998_CYC_TCONF_64: + len = sprintf(buf, "7812\n"); + break; + case AD7998_CYC_TCONF_128: + len = sprintf(buf, "3906\n"); + break; + case AD7998_CYC_TCONF_256: + len = sprintf(buf, "1953\n"); + break; + case AD7998_CYC_TCONF_512: + len = sprintf(buf, "976\n"); + break; + case AD7998_CYC_TCONF_1024: + len = sprintf(buf, "488\n"); + break; + case AD7998_CYC_TCONF_2048: + len = sprintf(buf, "244\n"); + break; + } + return len; +} + +static ssize_t ad799x_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + long val; + int ret; + u8 t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&dev_info->mlock); + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); + if (ret) + goto error_ret_mutex; + /* Wipe the bits clean */ + t &= ~AD7998_CYC_MASK; + + switch (val) { + case 15625: + t |= AD7998_CYC_TCONF_32; + break; + case 7812: + t |= AD7998_CYC_TCONF_64; + break; + case 3906: + t |= AD7998_CYC_TCONF_128; + break; + case 1953: + t |= AD7998_CYC_TCONF_256; + break; + case 976: + t |= AD7998_CYC_TCONF_512; + break; + case 488: + t |= AD7998_CYC_TCONF_1024; + break; + case 244: + t |= AD7998_CYC_TCONF_2048; + break; + case 0: + t |= AD7998_CYC_DIS; + break; + default: + ret = -EINVAL; + goto error_ret_mutex; + } + + ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + +error_ret_mutex: + mutex_unlock(&dev_info->mlock); + + return ret ? ret : len; +} + + +static ssize_t ad799x_read_channel_config(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + + int ret; + u16 val; + ret = ad799x_i2c_read16(st, this_attr->mask, &val); + if (ret) + return ret; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t ad799x_write_channel_config(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + + long val; + int ret; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&dev_info->mlock); + ret = ad799x_i2c_write16(st, this_attr->mask, val); + mutex_unlock(&dev_info->mlock); + + return ret ? ret : len; +} + +static void ad799x_interrupt_bh(struct work_struct *work_s) +{ + struct ad799x_state *st = container_of(work_s, + struct ad799x_state, work_thresh); + u8 status; + int i; + + if (ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status)) + goto err_out; + + if (!status) + goto err_out; + + ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); + + for (i = 0; i < 8; i++) { + if (status & (1 << i)) + iio_push_event(st->indio_dev, 0, + i & 0x1 ? + IIO_EVENT_CODE_IN_HIGH_THRESH(i >> 1) : + IIO_EVENT_CODE_IN_LOW_THRESH(i >> 1), + st->last_timestamp); + } + +err_out: + enable_irq(st->client->irq); +} + +static int ad799x_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad799x_state *st = dev_info->dev_data; + + st->last_timestamp = timestamp; + schedule_work(&st->work_thresh); + return 0; +} + +IIO_EVENT_SH(ad799x, &ad799x_interrupt); + +/* Direct read attribtues */ +static IIO_DEV_ATTR_IN_RAW(0, ad799x_read_single_channel, 0); +static IIO_DEV_ATTR_IN_RAW(1, ad799x_read_single_channel, 1); +static IIO_DEV_ATTR_IN_RAW(2, ad799x_read_single_channel, 2); +static IIO_DEV_ATTR_IN_RAW(3, ad799x_read_single_channel, 3); +static IIO_DEV_ATTR_IN_RAW(4, ad799x_read_single_channel, 4); +static IIO_DEV_ATTR_IN_RAW(5, ad799x_read_single_channel, 5); +static IIO_DEV_ATTR_IN_RAW(6, ad799x_read_single_channel, 6); +static IIO_DEV_ATTR_IN_RAW(7, ad799x_read_single_channel, 7); + +static ssize_t ad799x_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* Driver currently only support internal vref */ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} + +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, 0); + +static ssize_t ad799x_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "%s\n", st->client->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad799x_show_name, NULL, 0); + +static struct attribute *ad7991_5_9_3_4_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in2_raw.dev_attr.attr, + &iio_dev_attr_in3_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7991_5_9_3_4_dev_attr_group = { + .attrs = ad7991_5_9_3_4_device_attrs, +}; + +static struct attribute *ad7991_5_9_3_4_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7991_5_9_3_4_scan_el_group = { + .name = "scan_elements", + .attrs = ad7991_5_9_3_4_scan_el_attrs, +}; + +static struct attribute *ad7992_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7992_dev_attr_group = { + .attrs = ad7992_device_attrs, +}; + +static struct attribute *ad7992_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7992_scan_el_group = { + .name = "scan_elements", + .attrs = ad7992_scan_el_attrs, +}; + +static struct attribute *ad7997_8_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in2_raw.dev_attr.attr, + &iio_dev_attr_in3_raw.dev_attr.attr, + &iio_dev_attr_in4_raw.dev_attr.attr, + &iio_dev_attr_in5_raw.dev_attr.attr, + &iio_dev_attr_in6_raw.dev_attr.attr, + &iio_dev_attr_in7_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7997_8_dev_attr_group = { + .attrs = ad7997_8_device_attrs, +}; + +static struct attribute *ad7997_8_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7997_8_scan_el_group = { + .name = "scan_elements", + .attrs = ad7997_8_scan_el_attrs, +}; + +IIO_EVENT_ATTR_SH(in0_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH1_REG); + +IIO_EVENT_ATTR_SH(in0_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH1_REG); + +IIO_EVENT_ATTR_SH(in0_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH1_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH2_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH2_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH2_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH3_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH3_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH3_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH4_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH4_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH4_REG); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ad799x_read_frequency, + ad799x_write_frequency); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); + +static struct attribute *ad7993_4_7_8_event_attributes[] = { + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in2_thresh_low_value.dev_attr.attr, + &iio_event_attr_in2_thresh_high_value.dev_attr.attr, + &iio_event_attr_in2_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in3_thresh_low_value.dev_attr.attr, + &iio_event_attr_in3_thresh_high_value.dev_attr.attr, + &iio_event_attr_in3_thresh_both_hyst_raw.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7993_4_7_8_event_attrs_group = { + .attrs = ad7993_4_7_8_event_attributes, +}; + +static struct attribute *ad7992_event_attributes[] = { + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7992_event_attrs_group = { + .attrs = ad7992_event_attributes, +}; + +static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { + [ad7991] = { + .num_inputs = 4, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7995] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7999] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7992] = { + .num_inputs = 2, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7992_dev_attr_group, + .scan_attrs = &ad7992_scan_el_group, + .event_attrs = &ad7992_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7993] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7994] = { + .num_inputs = 4, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7997] = { + .num_inputs = 8, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7997_8_dev_attr_group, + .scan_attrs = &ad7997_8_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, + }, + [ad7998] = { + .num_inputs = 8, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7997_8_dev_attr_group, + .scan_attrs = &ad7997_8_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, + }, +}; + +static int __devinit ad799x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret, regdone = 0; + struct ad799x_platform_data *pdata = client->dev.platform_data; + struct ad799x_state *st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, st); + + atomic_set(&st->protect_ring, 0); + st->id = id->driver_data; + st->chip_info = &ad799x_chip_info_tbl[st->id]; + st->config = st->chip_info->default_config; + + /* TODO: Add pdata options for filtering and bit delay */ + + if (pdata) + st->int_vref_mv = pdata->vref_mv; + else + st->int_vref_mv = st->chip_info->int_vref_mv; + + st->reg = regulator_get(&client->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + } + st->client = client; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the i2c device */ + st->indio_dev->dev.parent = &client->dev; + st->indio_dev->attrs = st->chip_info->dev_attrs; + st->indio_dev->event_attrs = st->chip_info->event_attrs; + + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + st->indio_dev->num_interrupt_lines = 1; + + ret = ad799x_set_scan_mode(st, 0); + if (ret) + goto error_free_device; + + ret = ad799x_register_ring_funcs_and_init(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_cleanup_ring; + regdone = 1; + + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto error_cleanup_ring; + + if (client->irq > 0 && st->chip_info->monitor_mode) { + INIT_WORK(&st->work_thresh, ad799x_interrupt_bh); + + ret = iio_register_interrupt_line(client->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + client->name); + if (ret) + goto error_cleanup_ring; + + /* + * The event handler list element refer to iio_event_ad799x. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_ad799x, + &st->indio_dev->interrupts[0]->ev_list); + } + + return 0; +error_cleanup_ring: + ad799x_ring_cleanup(st->indio_dev); +error_free_device: + if (!regdone) + iio_free_device(st->indio_dev); + else + iio_device_unregister(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static __devexit int ad799x_remove(struct i2c_client *client) +{ + struct ad799x_state *st = i2c_get_clientdata(client); + struct iio_dev *indio_dev = st->indio_dev; + + if (client->irq > 0 && st->chip_info->monitor_mode) + iio_unregister_interrupt_line(indio_dev, 0); + + iio_ring_buffer_unregister(indio_dev->ring); + ad799x_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + + return 0; +} + +static const struct i2c_device_id ad799x_id[] = { + { "ad7991", ad7991 }, + { "ad7995", ad7995 }, + { "ad7999", ad7999 }, + { "ad7992", ad7992 }, + { "ad7993", ad7993 }, + { "ad7994", ad7994 }, + { "ad7997", ad7997 }, + { "ad7998", ad7998 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_id); + +static struct i2c_driver ad799x_driver = { + .driver = { + .name = "ad799x", + }, + .probe = ad799x_probe, + .remove = __devexit_p(ad799x_remove), + .id_table = ad799x_id, +}; + +static __init int ad799x_init(void) +{ + return i2c_add_driver(&ad799x_driver); +} + +static __exit void ad799x_exit(void) +{ + i2c_del_driver(&ad799x_driver); +} + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD799x ADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:ad799x"); + +module_init(ad799x_init); +module_exit(ad799x_exit); diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c new file mode 100644 index 000000000000..975cdcbf0830 --- /dev/null +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2008-2010 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x_ring.c + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/bitops.h> + +#include "../iio.h" +#include "../ring_generic.h" +#include "../ring_sw.h" +#include "../trigger.h" +#include "../sysfs.h" + +#include "ad799x.h" + +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask) +{ + struct iio_ring_buffer *ring = st->indio_dev->ring; + int count = 0, ret; + u16 *ring_data; + + if (!(ring->scan_mask & mask)) { + ret = -EBUSY; + goto error_ret; + } + + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); + if (ring_data == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = ring->access.read_last(ring, (u8 *) ring_data); + if (ret) + goto error_free_ring_data; + /* Need a count of channels prior to this one */ + mask >>= 1; + while (mask) { + if (mask & ring->scan_mask) + count++; + mask >>= 1; + } + + ret = be16_to_cpu(ring_data[count]); + +error_free_ring_data: + kfree(ring_data); +error_ret: + return ret; +} + +/** + * ad799x_ring_preenable() setup the parameters of the ring before enabling + * + * The complex nature of the setting of the nuber of bytes per datum is due + * to this driver currently ensuring that the timestamp is stored at an 8 + * byte boundary. + **/ +static int ad799x_ring_preenable(struct iio_dev *indio_dev) +{ + struct iio_ring_buffer *ring = indio_dev->ring; + struct ad799x_state *st = indio_dev->dev_data; + size_t d_size; + unsigned long numvals; + + /* + * Need to figure out the current mode based upon the requested + * scan mask in iio_dev + */ + + if (st->id == ad7997 || st->id == ad7998) + ad799x_set_scan_mode(st, ring->scan_mask); + + numvals = ring->scan_count; + + if (ring->access.set_bytes_per_datum) { + d_size = numvals*2 + sizeof(s64); + if (d_size % 8) + d_size += 8 - (d_size % 8); + ring->access.set_bytes_per_datum(ring, d_size); + } + + return 0; +} + +/** + * ad799x_poll_func_th() th of trigger launched polling to ring buffer + * + * As sampling only occurs on i2c comms occuring, leave timestamping until + * then. Some triggers will generate their own time stamp. Currently + * there is no way of notifying them when no one cares. + **/ +static void ad799x_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ad799x_state *st = indio_dev->dev_data; + + schedule_work(&st->poll_work); + + return; +} +/** + * ad799x_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad799x_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad799x_state *st = container_of(work_s, struct ad799x_state, + poll_work); + struct iio_dev *indio_dev = st->indio_dev; + struct iio_ring_buffer *ring = indio_dev->ring; + struct iio_sw_ring_buffer *ring_sw = iio_to_sw_ring(indio_dev->ring); + s64 time_ns; + __u8 *rxbuf; + int b_sent; + size_t d_size; + u8 cmd; + + unsigned long numvals = ring->scan_count; + + /* Ensure the timestamp is 8 byte aligned */ + d_size = numvals*2 + sizeof(s64); + + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + + /* Ensure only one copy of this function running at a time */ + if (atomic_inc_return(&st->protect_ring) > 1) + return; + + /* Monitor mode prevents reading. Whilst not currently implemented + * might as well have this test in here in the meantime as it does + * no harm. + */ + if (numvals == 0) + return; + + rxbuf = kmalloc(d_size, GFP_KERNEL); + if (rxbuf == NULL) + return; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | (ring->scan_mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (ring->scan_mask << AD799X_CHANNEL_SHIFT) | + AD7998_CONV_RES_REG; + break; + case ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; + break; + default: + cmd = 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, + cmd, numvals*2, rxbuf); + if (b_sent < 0) + goto done; + + time_ns = iio_get_time_ns(); + + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + ring->access.store_to(&ring_sw->buf, rxbuf, time_ns); +done: + kfree(rxbuf); + atomic_dec(&st->protect_ring); +} + + +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + struct ad799x_state *st = indio_dev->dev_data; + int ret = 0; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) { + ret = -ENOMEM; + goto error_ret; + } + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&st->indio_dev->ring->access); + ret = iio_alloc_pollfunc(indio_dev, NULL, &ad799x_poll_func_th); + if (ret) + goto error_deallocate_sw_rb; + + /* Ring buffer functions - here trigger setup related */ + + indio_dev->ring->preenable = &ad799x_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + + INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); + + indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; + + /* Flag that polled ring buffering is possible */ + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +void ad799x_ring_cleanup(struct iio_dev *indio_dev) +{ + /* ensure that the trigger has been detached */ + if (indio_dev->trig) { + iio_put_trigger(indio_dev->trig); + iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h index 7841e6ad4349..40c5949880b4 100644 --- a/drivers/staging/iio/adc/adc.h +++ b/drivers/staging/iio/adc/adc.h @@ -16,8 +16,8 @@ #define IIO_DEV_ATTR_IN_RAW(_num, _show, _addr) \ IIO_DEVICE_ATTR(in##_num##_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_DEV_ATTR_IN_NAMED_RAW(_name, _show, _addr) \ - IIO_DEVICE_ATTR(in_##_name##_raw, S_IRUGO, _show, NULL, _addr) +#define IIO_DEV_ATTR_IN_NAMED_RAW(_num, _name, _show, _addr) \ + IIO_DEVICE_ATTR(in##_num##_##_name##_raw, S_IRUGO, _show, NULL, _addr) #define IIO_DEV_ATTR_IN_DIFF_RAW(_nump, _numn, _show, _addr) \ IIO_DEVICE_ATTR_NAMED(in##_nump##min##_numn##_raw, \ @@ -27,5 +27,16 @@ NULL, \ _addr) -#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a) -#define IIO_EVENT_CODE_IN_LOW_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a + 32) + +#define IIO_CONST_ATTR_IN_NAMED_OFFSET(_num, _name, _string) \ + IIO_CONST_ATTR(in##_num##_##_name##_offset, _string) + +#define IIO_CONST_ATTR_IN_NAMED_SCALE(_num, _name, _string) \ + IIO_CONST_ATTR(in##_num##_##_name##_scale, _string) + +#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) \ + IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ + IIO_EV_DIR_RISING) +#define IIO_EVENT_CODE_IN_LOW_THRESH(a) \ + IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ + IIO_EV_DIR_FALLING) diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 6435e509dd56..dde097afb430 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -42,11 +42,10 @@ /* Here we claim all are 16 bits. This currently does no harm and saves * us a lot of scan element listings */ -#define MAX1363_SCAN_EL(number) \ - IIO_SCAN_EL_C(in##number, number, IIO_UNSIGNED(16), 0, NULL); +#define MAX1363_SCAN_EL(number) \ + IIO_SCAN_EL_C(in##number, number, 0, NULL); #define MAX1363_SCAN_EL_D(p, n, number) \ - IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, \ - number, IIO_SIGNED(16), 0, NULL); + IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, number, 0, NULL); static MAX1363_SCAN_EL(0); static MAX1363_SCAN_EL(1); @@ -148,17 +147,59 @@ const struct max1363_mode return NULL; } -static ssize_t max1363_show_precision(struct device *dev, +static ssize_t max1363_show_precision_u(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *dev_info = ring->indio_dev; + struct max1363_state *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "u%d/16\n", st->chip_info->bits); +} + +static ssize_t max1363_show_precision_s(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *dev_info = ring->indio_dev; struct max1363_state *st = iio_dev_get_devdata(dev_info); - return sprintf(buf, "%d\n", st->chip_info->bits); + return sprintf(buf, "s%d/16\n", st->chip_info->bits); } -static IIO_DEVICE_ATTR(in_precision, S_IRUGO, max1363_show_precision, - NULL, 0); +#define MAX1363_SCAN_TYPE(n) \ + DEVICE_ATTR(in##n##_type, S_IRUGO, \ + max1363_show_precision_u, NULL); +#define MAX1363_SCAN_TYPE_D(p, n) \ + struct device_attribute dev_attr_in##p##m##in##n##_type = \ + __ATTR(in##p-in##n##_type, S_IRUGO, \ + max1363_show_precision_s, NULL); + +static MAX1363_SCAN_TYPE(0); +static MAX1363_SCAN_TYPE(1); +static MAX1363_SCAN_TYPE(2); +static MAX1363_SCAN_TYPE(3); +static MAX1363_SCAN_TYPE(4); +static MAX1363_SCAN_TYPE(5); +static MAX1363_SCAN_TYPE(6); +static MAX1363_SCAN_TYPE(7); +static MAX1363_SCAN_TYPE(8); +static MAX1363_SCAN_TYPE(9); +static MAX1363_SCAN_TYPE(10); +static MAX1363_SCAN_TYPE(11); + +static MAX1363_SCAN_TYPE_D(0, 1); +static MAX1363_SCAN_TYPE_D(2, 3); +static MAX1363_SCAN_TYPE_D(4, 5); +static MAX1363_SCAN_TYPE_D(6, 7); +static MAX1363_SCAN_TYPE_D(8, 9); +static MAX1363_SCAN_TYPE_D(10, 11); +static MAX1363_SCAN_TYPE_D(1, 0); +static MAX1363_SCAN_TYPE_D(3, 2); +static MAX1363_SCAN_TYPE_D(5, 4); +static MAX1363_SCAN_TYPE_D(7, 6); +static MAX1363_SCAN_TYPE_D(9, 8); +static MAX1363_SCAN_TYPE_D(11, 10); static int max1363_write_basic_config(struct i2c_client *client, unsigned char d1, @@ -345,15 +386,22 @@ static struct attribute_group max1363_dev_attr_group = { }; static struct attribute *max1363_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, NULL, }; @@ -419,31 +467,54 @@ static struct attribute_group max1238_dev_attr_group = { }; static struct attribute *max1238_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in4.dev_attr.attr, - &iio_scan_el_in5.dev_attr.attr, - &iio_scan_el_in6.dev_attr.attr, - &iio_scan_el_in7.dev_attr.attr, - &iio_scan_el_in8.dev_attr.attr, - &iio_scan_el_in9.dev_attr.attr, - &iio_scan_el_in10.dev_attr.attr, - &iio_scan_el_in11.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in4min5.dev_attr.attr, - &iio_scan_el_in6min7.dev_attr.attr, - &iio_scan_el_in8min9.dev_attr.attr, - &iio_scan_el_in10min11.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_scan_el_in5min4.dev_attr.attr, - &iio_scan_el_in7min6.dev_attr.attr, - &iio_scan_el_in9min8.dev_attr.attr, - &iio_scan_el_in11min10.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_scan_el_in8.dev_attr.attr, &dev_attr_in8_type.attr, + &iio_const_attr_in8_index.dev_attr.attr, + &iio_scan_el_in9.dev_attr.attr, &dev_attr_in9_type.attr, + &iio_const_attr_in9_index.dev_attr.attr, + &iio_scan_el_in10.dev_attr.attr, &dev_attr_in10_type.attr, + &iio_const_attr_in10_index.dev_attr.attr, + &iio_scan_el_in11.dev_attr.attr, &dev_attr_in11_type.attr, + &iio_const_attr_in11_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr, + &iio_const_attr_in4min5_index.dev_attr.attr, + &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr, + &iio_const_attr_in6min7_index.dev_attr.attr, + &iio_scan_el_in8min9.dev_attr.attr, &dev_attr_in8min9_type.attr, + &iio_const_attr_in8min9_index.dev_attr.attr, + &iio_scan_el_in10min11.dev_attr.attr, &dev_attr_in10min11_type.attr, + &iio_const_attr_in10min11_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, + &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr, + &iio_const_attr_in5min4_index.dev_attr.attr, + &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr, + &iio_const_attr_in7min6_index.dev_attr.attr, + &iio_scan_el_in9min8.dev_attr.attr, &dev_attr_in9min8_type.attr, + &iio_const_attr_in9min8_index.dev_attr.attr, + &iio_scan_el_in11min10.dev_attr.attr, &dev_attr_in11min10_type.attr, + &iio_const_attr_in11min10_index.dev_attr.attr, NULL, }; @@ -498,23 +569,39 @@ static struct attribute_group max11608_dev_attr_group = { }; static struct attribute *max11608_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in4.dev_attr.attr, - &iio_scan_el_in5.dev_attr.attr, - &iio_scan_el_in6.dev_attr.attr, - &iio_scan_el_in7.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in4min5.dev_attr.attr, - &iio_scan_el_in6min7.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_scan_el_in5min4.dev_attr.attr, - &iio_scan_el_in7min6.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr, + &iio_const_attr_in4min5_index.dev_attr.attr, + &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr, + &iio_const_attr_in6min7_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, + &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr, + &iio_const_attr_in5min4_index.dev_attr.attr, + &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr, + &iio_const_attr_in7min6_index.dev_attr.attr, + NULL }; static struct attribute_group max11608_scan_el_group = { @@ -1631,7 +1718,6 @@ static int __devinit max1363_probe(struct i2c_client *client, st->indio_dev->attrs = st->chip_info->dev_attrs; /* Todo: this shouldn't be here. */ - st->indio_dev->scan_el_attrs = st->chip_info->scan_attrs; st->indio_dev->dev_data = (void *)(st); st->indio_dev->driver_module = THIS_MODULE; st->indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index 786b17a0d6b0..5532f3e466bc 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -30,22 +30,20 @@ /* Todo: test this */ int max1363_single_channel_from_ring(long mask, struct max1363_state *st) { - unsigned long numvals; + struct iio_ring_buffer *ring = st->indio_dev->ring; int count = 0, ret; u8 *ring_data; if (!(st->current_mode->modemask & mask)) { ret = -EBUSY; goto error_ret; } - numvals = hweight_long(st->current_mode->modemask); - ring_data = kmalloc(numvals*2, GFP_KERNEL); + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); if (ring_data == NULL) { ret = -ENOMEM; goto error_ret; } - ret = st->indio_dev->ring->access.read_last(st->indio_dev->ring, - ring_data); + ret = ring->access.read_last(ring, ring_data); if (ret) goto error_free_ring_data; /* Need a count of channels prior to this one */ @@ -77,6 +75,7 @@ error_ret: static int max1363_ring_preenable(struct iio_dev *indio_dev) { struct max1363_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring = indio_dev->ring; size_t d_size; unsigned long numvals; @@ -84,7 +83,7 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) * Need to figure out the current mode based upon the requested * scan mask in iio_dev */ - st->current_mode = max1363_match_mode(st->indio_dev->scan_mask, + st->current_mode = max1363_match_mode(ring->scan_mask, st->chip_info); if (!st->current_mode) return -EINVAL; @@ -92,14 +91,14 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) max1363_set_scan_mode(st); numvals = hweight_long(st->current_mode->modemask); - if (indio_dev->ring->access.set_bpd) { + if (ring->access.set_bytes_per_datum) { if (st->chip_info->bits != 8) d_size = numvals*2 + sizeof(s64); else d_size = numvals + sizeof(s64); if (d_size % 8) d_size += 8 - (d_size % 8); - indio_dev->ring->access.set_bpd(indio_dev->ring, d_size); + ring->access.set_bytes_per_datum(ring, d_size); } return 0; @@ -135,7 +134,7 @@ static void max1363_poll_bh_to_ring(struct work_struct *work_s) struct max1363_state *st = container_of(work_s, struct max1363_state, poll_work); struct iio_dev *indio_dev = st->indio_dev; - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(indio_dev->ring); + struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring); s64 time_ns; __u8 *rxbuf; int b_sent; @@ -175,7 +174,7 @@ static void max1363_poll_bh_to_ring(struct work_struct *work_s) memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); - indio_dev->ring->access.store_to(&ring->buf, rxbuf, time_ns); + indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns); done: kfree(rxbuf); atomic_dec(&st->protect_ring); @@ -193,12 +192,13 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) goto error_ret; } /* Effectively select the ring buffer implementation */ - iio_ring_sw_register_funcs(&st->indio_dev->ring->access); + iio_ring_sw_register_funcs(&indio_dev->ring->access); ret = iio_alloc_pollfunc(indio_dev, NULL, &max1363_poll_func_th); if (ret) goto error_deallocate_sw_rb; /* Ring buffer functions - here trigger setup related */ + indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; indio_dev->ring->postenable = &iio_triggered_ring_postenable; indio_dev->ring->preenable = &max1363_ring_preenable; indio_dev->ring->predisable = &iio_triggered_ring_predisable; diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h index fd23bd1ea7b6..98d1a2c12df2 100644 --- a/drivers/staging/iio/chrdev.h +++ b/drivers/staging/iio/chrdev.h @@ -73,7 +73,6 @@ struct iio_shared_ev_pointer { * @det_events: list of detected events * @max_events: maximum number of events before new ones are dropped * @current_events: number of events in detected list - * @attr: this chrdev's minor number sysfs attribute * @owner: ensure the driver module owns the file, not iio * @private: driver specific data * @_name: used internally to store the sysfs name for minor id @@ -88,7 +87,6 @@ struct iio_event_interface { struct iio_detected_event_list det_events; int max_events; int current_events; - struct iio_chrdev_minor_attr attr; struct module *owner; void *private; char _name[35]; diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 134dfaae2f0c..7d7716e5857c 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -442,29 +442,30 @@ err_ret: return ret; } -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16260_read_12bit_unsigned, ADIS16260_SUPPLY_OUT); -static IIO_CONST_ATTR(in_supply_scale, "0.0018315"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.0018315"); static IIO_DEV_ATTR_GYRO(adis16260_read_14bit_signed, ADIS16260_GYRO_OUT); -static IIO_DEV_ATTR_GYRO_SCALE(S_IWUSR | S_IRUGO, +static IIO_CONST_ATTR_GYRO_SCALE("0.00127862821"); +static IIO_DEV_ATTR_GYRO_CALIBSCALE(S_IWUSR | S_IRUGO, adis16260_read_14bit_signed, adis16260_write_16bit, ADIS16260_GYRO_SCALE); -static IIO_DEV_ATTR_GYRO_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_GYRO_CALIBBIAS(S_IWUSR | S_IRUGO, adis16260_read_12bit_signed, adis16260_write_16bit, ADIS16260_GYRO_OFF); static IIO_DEV_ATTR_TEMP_RAW(adis16260_read_12bit_unsigned); -static IIO_CONST_ATTR(temp_offset, "25"); -static IIO_CONST_ATTR(temp_scale, "0.1453"); +static IIO_CONST_ATTR_TEMP_OFFSET("25"); +static IIO_CONST_ATTR_TEMP_SCALE("0.1453"); -static IIO_DEV_ATTR_IN_RAW(0, adis16260_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_RAW(1, adis16260_read_12bit_unsigned, ADIS16260_AUX_ADC); -static IIO_CONST_ATTR(in0_scale, "0.0006105"); +static IIO_CONST_ATTR(in1_scale, "0.0006105"); static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16260_read_frequency, @@ -474,9 +475,9 @@ static IIO_DEV_ATTR_ANGL(adis16260_read_14bit_signed, static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16260_write_reset, 0); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("256 2048"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("256 2048"); -static IIO_CONST_ATTR(name, "adis16260"); +static IIO_CONST_ATTR_NAME("adis16260"); static struct attribute *adis16260_event_attributes[] = { NULL @@ -487,19 +488,20 @@ static struct attribute_group adis16260_event_attribute_group = { }; static struct attribute *adis16260_attributes[] = { - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, &iio_dev_attr_gyro_raw.dev_attr.attr, - &iio_dev_attr_gyro_scale.dev_attr.attr, - &iio_dev_attr_gyro_offset.dev_attr.attr, + &iio_const_attr_gyro_scale.dev_attr.attr, + &iio_dev_attr_gyro_calibscale.dev_attr.attr, + &iio_dev_attr_gyro_calibbias.dev_attr.attr, &iio_dev_attr_angl_raw.dev_attr.attr, &iio_dev_attr_temp_raw.dev_attr.attr, &iio_const_attr_temp_offset.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, - &iio_const_attr_in0_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, NULL diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c index 9ef7f9080dcd..23428894b1ee 100644 --- a/drivers/staging/iio/gyro/adis16260_ring.c +++ b/drivers/staging/iio/gyro/adis16260_ring.c @@ -17,26 +17,39 @@ #include "../trigger.h" #include "adis16260.h" -static IIO_SCAN_EL_C(supply, ADIS16260_SCAN_SUPPLY, IIO_UNSIGNED(12), +static IIO_SCAN_EL_C(in_supply, ADIS16260_SCAN_SUPPLY, ADIS16260_SUPPLY_OUT, NULL); -static IIO_SCAN_EL_C(gyro, ADIS16260_SCAN_GYRO, IIO_SIGNED(14), - ADIS16260_GYRO_OUT, NULL); -static IIO_SCAN_EL_C(aux_adc, ADIS16260_SCAN_AUX_ADC, IIO_SIGNED(14), - ADIS16260_AUX_ADC, NULL); -static IIO_SCAN_EL_C(temp, ADIS16260_SCAN_TEMP, IIO_UNSIGNED(12), - ADIS16260_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(angl, ADIS16260_SCAN_ANGL, IIO_UNSIGNED(12), - ADIS16260_ANGL_OUT, NULL); - +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16); +static IIO_SCAN_EL_C(gyro, ADIS16260_SCAN_GYRO, ADIS16260_GYRO_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(gyro, s, 14, 16); +static IIO_SCAN_EL_C(in0, ADIS16260_SCAN_AUX_ADC, ADIS16260_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16); +static IIO_SCAN_EL_C(temp, ADIS16260_SCAN_TEMP, ADIS16260_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16); +static IIO_SCAN_EL_C(angl, ADIS16260_SCAN_ANGL, ADIS16260_ANGL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(angl, u, 14, 16); static IIO_SCAN_EL_TIMESTAMP(5); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16260_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, &iio_scan_el_gyro.dev_attr.attr, - &iio_scan_el_aux_adc.dev_attr.attr, + &iio_const_attr_gyro_index.dev_attr.attr, + &iio_const_attr_gyro_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, &iio_scan_el_angl.dev_attr.attr, + &iio_const_attr_angl_index.dev_attr.attr, + &iio_const_attr_angl_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -110,11 +123,11 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s) struct adis16260_state *st = container_of(work_s, struct adis16260_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -122,17 +135,17 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16260_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, + ring->access.store_to(ring, (u8 *)data, st->last_timestamp); @@ -154,16 +167,6 @@ int adis16260_configure_ring(struct iio_dev *indio_dev) struct adis16260_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16260_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro.number); - iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_angl.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16260_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -174,11 +177,20 @@ int adis16260_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16260_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_gyro.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_angl.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16260_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c index de01537d257e..4a744c11ca6c 100644 --- a/drivers/staging/iio/gyro/adis16260_trigger.c +++ b/drivers/staging/iio/gyro/adis16260_trigger.c @@ -30,7 +30,7 @@ static int adis16260_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16260_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16260_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/gyro/gyro.h b/drivers/staging/iio/gyro/gyro.h index f68edab8f30d..98b837b775a2 100644 --- a/drivers/staging/iio/gyro/gyro.h +++ b/drivers/staging/iio/gyro/gyro.h @@ -3,6 +3,9 @@ /* Gyroscope types of attribute */ +#define IIO_CONST_ATTR_GYRO_OFFSET(_string) \ + IIO_CONST_ATTR(gyro_offset, _string) + #define IIO_DEV_ATTR_GYRO_OFFSET(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(gyro_offset, _mode, _show, _store, _addr) @@ -15,18 +18,45 @@ #define IIO_DEV_ATTR_GYRO_Z_OFFSET(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(gyro_z_offset, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_GYRO_X_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(gyro_x_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_GYRO_Y_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(gyro_y_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_GYRO_Z_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(gyro_z_gain, _mode, _show, _store, _addr) +#define IIO_CONST_ATTR_GYRO_SCALE(_string) \ + IIO_CONST_ATTR(gyro_scale, _string) #define IIO_DEV_ATTR_GYRO_SCALE(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(gyro_scale, S_IRUGO, _show, _store, _addr) +#define IIO_DEV_ATTR_GYRO_X_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_x_scale, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Y_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_y_scale, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Z_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_z_scale, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_calibbias, S_IRUGO, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_X_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_x_calibbias, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Y_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_y_calibbias, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Z_CALIBBIAS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_z_calibbias, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_calibscale, S_IRUGO, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_X_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_x_calibscale, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Y_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_y_calibscale, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_GYRO_Z_CALIBSCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(gyro_z_calibscale, _mode, _show, _store, _addr) + #define IIO_DEV_ATTR_GYRO(_show, _addr) \ IIO_DEVICE_ATTR(gyro_raw, S_IRUGO, _show, NULL, _addr) diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h index 9d0ca128679e..248bdd2846fd 100644 --- a/drivers/staging/iio/iio.h +++ b/drivers/staging/iio/iio.h @@ -90,12 +90,7 @@ void iio_remove_event_from_list(struct iio_event_handler_list *el, * @ring: [DRIVER] any ring buffer present * @mlock: [INTERN] lock used to prevent simultaneous device state * changes - * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode - * control method is used - * @scan_count: [INTERN] the number of elements in the current scan mode - * @scan_mask: [INTERN] bitmask used in masking scan mode elements * @available_scan_masks: [DRIVER] optional array of allowed bitmasks - * @scan_timestamp: [INTERN] does the scan mode include a timestamp * @trig: [INTERN] current device trigger (ring buffer modes) * @pollfunc: [DRIVER] function run on trigger being recieved **/ @@ -118,104 +113,11 @@ struct iio_dev { struct iio_ring_buffer *ring; struct mutex mlock; - struct attribute_group *scan_el_attrs; - int scan_count; - - u32 scan_mask; u32 *available_scan_masks; - bool scan_timestamp; struct iio_trigger *trig; struct iio_poll_func *pollfunc; }; -/* - * These are mainly provided to allow for a change of implementation if a device - * has a large number of scan elements - */ -#define IIO_MAX_SCAN_LENGTH 31 - -/* note 0 used as error indicator as it doesn't make sense. */ -static inline u32 iio_scan_mask_match(u32 *av_masks, u32 mask) -{ - while (*av_masks) { - if (!(~*av_masks & mask)) - return *av_masks; - av_masks++; - } - return 0; -} - -static inline int iio_scan_mask_query(struct iio_dev *dev_info, int bit) -{ - u32 mask; - - if (bit > IIO_MAX_SCAN_LENGTH) - return -EINVAL; - - if (!dev_info->scan_mask) - return 0; - - if (dev_info->available_scan_masks) - mask = iio_scan_mask_match(dev_info->available_scan_masks, - dev_info->scan_mask); - else - mask = dev_info->scan_mask; - - if (!mask) - return -EINVAL; - - return !!(mask & (1 << bit)); -}; - -static inline int iio_scan_mask_set(struct iio_dev *dev_info, int bit) -{ - u32 mask; - u32 trialmask = dev_info->scan_mask | (1 << bit); - - if (bit > IIO_MAX_SCAN_LENGTH) - return -EINVAL; - if (dev_info->available_scan_masks) { - mask = iio_scan_mask_match(dev_info->available_scan_masks, - trialmask); - if (!mask) - return -EINVAL; - } - dev_info->scan_mask = trialmask; - dev_info->scan_count++; - - return 0; -}; - -static inline int iio_scan_mask_clear(struct iio_dev *dev_info, int bit) -{ - if (bit > IIO_MAX_SCAN_LENGTH) - return -EINVAL; - dev_info->scan_mask &= ~(1 << bit); - dev_info->scan_count--; - return 0; -}; - -/** - * iio_scan_mask_count_to_right() - how many scan elements occur before here - * @dev_info: the iio_device whose scan mode we are querying - * @bit: which number scan element is this - **/ -static inline int iio_scan_mask_count_to_right(struct iio_dev *dev_info, - int bit) -{ - int count = 0; - int mask = (1 << bit); - if (bit > IIO_MAX_SCAN_LENGTH) - return -EINVAL; - while (mask) { - mask >>= 1; - if (mask & dev_info->scan_mask) - count++; - } - - return count; -} - /** * iio_device_register() - register a device with the IIO subsystem * @dev_info: Device structure filled by the device driver @@ -233,7 +135,7 @@ void iio_device_unregister(struct iio_dev *dev_info); * physical interrupt lines * @dev_info: the iio device for which the is an interrupt line * @line_number: associated line number - * @id: idr allocated unique id number + * @id: ida allocated unique id number * @irq: associate interrupt number * @ev_list: event handler list for associated events * @ev_list_lock: ensure only one access to list at a time @@ -400,8 +302,8 @@ static inline bool iio_ring_enabled(struct iio_dev *dev_info) | INDIO_RING_HARDWARE_BUFFER); }; -struct idr; +struct ida; -int iio_get_new_idr_val(struct idr *this_idr); -void iio_free_idr_val(struct idr *this_idr, int id); +int iio_get_new_ida_val(struct ida *this_ida); +void iio_free_ida_val(struct ida *this_ida, int id); #endif /* _INDUSTRIAL_IO_H_ */ diff --git a/drivers/staging/iio/imu/adis16300_core.c b/drivers/staging/iio/imu/adis16300_core.c index f1950d56cb1f..7ad13f4d3d74 100644 --- a/drivers/staging/iio/imu/adis16300_core.c +++ b/drivers/staging/iio/imu/adis16300_core.c @@ -503,28 +503,33 @@ err_ret: return ret; } -static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_GYRO_X_CALIBBIAS(S_IWUSR | S_IRUGO, + adis16300_read_12bit_signed, + adis16300_write_16bit, + ADIS16300_XGYRO_OFF); + +static IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(S_IWUSR | S_IRUGO, adis16300_read_12bit_signed, adis16300_write_16bit, ADIS16300_XACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(S_IWUSR | S_IRUGO, adis16300_read_12bit_signed, adis16300_write_16bit, ADIS16300_YACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(S_IWUSR | S_IRUGO, adis16300_read_12bit_signed, adis16300_write_16bit, ADIS16300_ZACCL_OFF); -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16300_read_14bit_unsigned, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16300_read_14bit_unsigned, ADIS16300_SUPPLY_OUT); -static IIO_CONST_ATTR(in_supply_scale, "0.00242"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.00242"); static IIO_DEV_ATTR_GYRO_X(adis16300_read_14bit_signed, ADIS16300_XGYRO_OUT); -static IIO_CONST_ATTR(gyro_scale, "0.05 deg/s"); +static IIO_CONST_ATTR_GYRO_SCALE("0.000872664"); static IIO_DEV_ATTR_ACCEL_X(adis16300_read_14bit_signed, ADIS16300_XACCL_OUT); @@ -532,21 +537,21 @@ static IIO_DEV_ATTR_ACCEL_Y(adis16300_read_14bit_signed, ADIS16300_YACCL_OUT); static IIO_DEV_ATTR_ACCEL_Z(adis16300_read_14bit_signed, ADIS16300_ZACCL_OUT); -static IIO_CONST_ATTR(accel_scale, "0.0006 g"); +static IIO_CONST_ATTR_ACCEL_SCALE("0.00588399"); static IIO_DEV_ATTR_INCLI_X(adis16300_read_13bit_signed, ADIS16300_XINCLI_OUT); static IIO_DEV_ATTR_INCLI_Y(adis16300_read_13bit_signed, ADIS16300_YINCLI_OUT); -static IIO_CONST_ATTR(incli_scale, "0.044 d"); +static IIO_CONST_ATTR_INCLI_SCALE("0.00076794487"); static IIO_DEV_ATTR_TEMP_RAW(adis16300_read_12bit_unsigned); -static IIO_CONST_ATTR(temp_offset, "198.16 K"); -static IIO_CONST_ATTR(temp_scale, "0.14 K"); +static IIO_CONST_ATTR_TEMP_OFFSET("198.16"); +static IIO_CONST_ATTR_TEMP_SCALE("0.14"); -static IIO_DEV_ATTR_IN_RAW(0, adis16300_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_RAW(1, adis16300_read_12bit_unsigned, ADIS16300_AUX_ADC); -static IIO_CONST_ATTR(in0_scale, "0.000806"); +static IIO_CONST_ATTR(in1_scale, "0.000806"); static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16300_read_frequency, @@ -554,9 +559,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16300_write_reset, 0); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("409 546 819 1638"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); -static IIO_CONST_ATTR(name, "adis16300"); +static IIO_CONST_ATTR_NAME("adis16300"); static struct attribute *adis16300_event_attributes[] = { NULL @@ -567,11 +572,12 @@ static struct attribute_group adis16300_event_attribute_group = { }; static struct attribute *adis16300_attributes[] = { - &iio_dev_attr_accel_x_offset.dev_attr.attr, - &iio_dev_attr_accel_y_offset.dev_attr.attr, - &iio_dev_attr_accel_z_offset.dev_attr.attr, - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, + &iio_dev_attr_gyro_x_calibbias.dev_attr.attr, + &iio_dev_attr_accel_x_calibbias.dev_attr.attr, + &iio_dev_attr_accel_y_calibbias.dev_attr.attr, + &iio_dev_attr_accel_z_calibbias.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, &iio_dev_attr_gyro_x_raw.dev_attr.attr, &iio_const_attr_gyro_scale.dev_attr.attr, &iio_dev_attr_accel_x_raw.dev_attr.attr, @@ -584,10 +590,10 @@ static struct attribute *adis16300_attributes[] = { &iio_dev_attr_temp_raw.dev_attr.attr, &iio_const_attr_temp_offset.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, - &iio_const_attr_in0_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, NULL diff --git a/drivers/staging/iio/imu/adis16300_ring.c b/drivers/staging/iio/imu/adis16300_ring.c index fc93160acb26..114fdf4fd47d 100644 --- a/drivers/staging/iio/imu/adis16300_ring.c +++ b/drivers/staging/iio/imu/adis16300_ring.c @@ -17,42 +17,60 @@ #include "../trigger.h" #include "adis16300.h" -static IIO_SCAN_EL_C(supply, ADIS16300_SCAN_SUPPLY, IIO_UNSIGNED(14), +static IIO_SCAN_EL_C(in0_supply, ADIS16300_SCAN_SUPPLY, ADIS16300_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0_supply, u, 12, 16); +static IIO_SCAN_EL_C(gyro_x, ADIS16300_SCAN_GYRO_X, ADIS16300_XGYRO_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(gyro, s, 14, 16); -static IIO_SCAN_EL_C(gyro_x, ADIS16300_SCAN_GYRO_X, IIO_SIGNED(14), - ADIS16300_XGYRO_OUT, NULL); +static IIO_SCAN_EL_C(accel_x, ADIS16300_SCAN_ACC_X, ADIS16300_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16300_SCAN_ACC_Y, ADIS16300_YACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_z, ADIS16300_SCAN_ACC_Z, ADIS16300_ZACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); -static IIO_SCAN_EL_C(accel_x, ADIS16300_SCAN_ACC_X, IIO_SIGNED(14), - ADIS16300_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16300_SCAN_ACC_Y, IIO_SIGNED(14), - ADIS16300_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_z, ADIS16300_SCAN_ACC_Z, IIO_SIGNED(14), - ADIS16300_ZACCL_OUT, NULL); +static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, ADIS16300_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, s, 12, 16); -static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, IIO_UNSIGNED(12), - ADIS16300_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(adc_0, ADIS16300_SCAN_ADC_0, IIO_UNSIGNED(12), - ADIS16300_AUX_ADC, NULL); +static IIO_SCAN_EL_C(in1, ADIS16300_SCAN_ADC_0, ADIS16300_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in1, u, 12, 16); -static IIO_SCAN_EL_C(incli_x, ADIS16300_SCAN_INCLI_X, IIO_SIGNED(12), +static IIO_SCAN_EL_C(incli_x, ADIS16300_SCAN_INCLI_X, ADIS16300_XINCLI_OUT, NULL); -static IIO_SCAN_EL_C(incli_y, ADIS16300_SCAN_INCLI_Y, IIO_SIGNED(12), +static IIO_SCAN_EL_C(incli_y, ADIS16300_SCAN_INCLI_Y, ADIS16300_YINCLI_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 13, 16); static IIO_SCAN_EL_TIMESTAMP(9); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16300_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in0_supply.dev_attr.attr, + &iio_const_attr_in0_supply_index.dev_attr.attr, + &iio_const_attr_in0_supply_type.dev_attr.attr, &iio_scan_el_gyro_x.dev_attr.attr, + &iio_const_attr_gyro_x_index.dev_attr.attr, + &iio_const_attr_gyro_type.dev_attr.attr, &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, &iio_scan_el_incli_x.dev_attr.attr, + &iio_const_attr_incli_x_index.dev_attr.attr, &iio_scan_el_incli_y.dev_attr.attr, - &iio_scan_el_adc_0.dev_attr.attr, + &iio_const_attr_incli_y_index.dev_attr.attr, + &iio_const_attr_incli_type.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_const_attr_in1_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -134,11 +152,11 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s) struct adis16300_state *st = container_of(work_s, struct adis16300_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -146,19 +164,19 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16300_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); iio_trigger_notify_done(st->indio_dev->trig); kfree(data); @@ -178,20 +196,6 @@ int adis16300_configure_ring(struct iio_dev *indio_dev) struct adis16300_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16300_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_adc_0.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_incli_y.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16300_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -202,11 +206,24 @@ int adis16300_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16300_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in0_supply.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_accel_z.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in1.number); + iio_scan_mask_set(ring, iio_scan_el_incli_x.number); + iio_scan_mask_set(ring, iio_scan_el_incli_y.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16300_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/imu/adis16300_trigger.c b/drivers/staging/iio/imu/adis16300_trigger.c index 64036cd99102..d6677b64edb9 100644 --- a/drivers/staging/iio/imu/adis16300_trigger.c +++ b/drivers/staging/iio/imu/adis16300_trigger.c @@ -30,7 +30,7 @@ static int adis16300_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16300_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16300_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/imu/adis16350_core.c b/drivers/staging/iio/imu/adis16350_core.c index 1575b7b5d44f..97c1ec8594ce 100644 --- a/drivers/staging/iio/imu/adis16350_core.c +++ b/drivers/staging/iio/imu/adis16350_core.c @@ -475,24 +475,39 @@ err_ret: return ret; } -static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_GYRO_X_CALIBBIAS(S_IWUSR | S_IRUGO, + adis16350_read_12bit_signed, + adis16350_write_16bit, + ADIS16350_XGYRO_OFF); + +static IIO_DEV_ATTR_GYRO_Y_CALIBBIAS(S_IWUSR | S_IRUGO, + adis16350_read_12bit_signed, + adis16350_write_16bit, + ADIS16350_YGYRO_OFF); + +static IIO_DEV_ATTR_GYRO_Z_CALIBBIAS(S_IWUSR | S_IRUGO, + adis16350_read_12bit_signed, + adis16350_write_16bit, + ADIS16350_ZGYRO_OFF); + +static IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(S_IWUSR | S_IRUGO, adis16350_read_12bit_signed, adis16350_write_16bit, ADIS16350_XACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(S_IWUSR | S_IRUGO, adis16350_read_12bit_signed, adis16350_write_16bit, ADIS16350_YACCL_OFF); -static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(S_IWUSR | S_IRUGO, adis16350_read_12bit_signed, adis16350_write_16bit, ADIS16350_ZACCL_OFF); -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16350_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16350_read_12bit_unsigned, ADIS16350_SUPPLY_OUT); -static IIO_CONST_ATTR(in_supply_scale, "0.002418"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.002418"); static IIO_DEV_ATTR_GYRO_X(adis16350_read_14bit_signed, ADIS16350_XGYRO_OUT); @@ -500,7 +515,7 @@ static IIO_DEV_ATTR_GYRO_Y(adis16350_read_14bit_signed, ADIS16350_YGYRO_OUT); static IIO_DEV_ATTR_GYRO_Z(adis16350_read_14bit_signed, ADIS16350_ZGYRO_OUT); -static IIO_CONST_ATTR(gyro_scale, "0.05"); +static IIO_CONST_ATTR_GYRO_SCALE("0.00127862821"); static IIO_DEV_ATTR_ACCEL_X(adis16350_read_14bit_signed, ADIS16350_XACCL_OUT); @@ -508,7 +523,7 @@ static IIO_DEV_ATTR_ACCEL_Y(adis16350_read_14bit_signed, ADIS16350_YACCL_OUT); static IIO_DEV_ATTR_ACCEL_Z(adis16350_read_14bit_signed, ADIS16350_ZACCL_OUT); -static IIO_CONST_ATTR(accel_scale, "0.00333"); +static IIO_CONST_ATTR_ACCEL_SCALE("0.0247323713"); static IIO_DEVICE_ATTR(temp_x_raw, S_IRUGO, adis16350_read_12bit_signed, NULL, ADIS16350_XTEMP_OUT); @@ -516,11 +531,12 @@ static IIO_DEVICE_ATTR(temp_y_raw, S_IRUGO, adis16350_read_12bit_signed, NULL, ADIS16350_YTEMP_OUT); static IIO_DEVICE_ATTR(temp_z_raw, S_IRUGO, adis16350_read_12bit_signed, NULL, ADIS16350_ZTEMP_OUT); -static IIO_CONST_ATTR(temp_scale, "0.0005"); +static IIO_CONST_ATTR_TEMP_SCALE("0.14534"); +static IIO_CONST_ATTR_TEMP_OFFSET("198.16"); -static IIO_DEV_ATTR_IN_RAW(0, adis16350_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_RAW(1, adis16350_read_12bit_unsigned, ADIS16350_AUX_ADC); -static IIO_CONST_ATTR(in0_scale, "0.000806"); +static IIO_CONST_ATTR(in1_scale, "0.000806"); static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16350_read_frequency, @@ -529,16 +545,19 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16350_write_reset, 0); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("409 546 819 1638"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); -static IIO_CONST_ATTR(name, "adis16350"); +static IIO_CONST_ATTR_NAME("adis16350"); static struct attribute *adis16350_attributes[] = { - &iio_dev_attr_accel_x_offset.dev_attr.attr, - &iio_dev_attr_accel_y_offset.dev_attr.attr, - &iio_dev_attr_accel_z_offset.dev_attr.attr, - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, + &iio_dev_attr_gyro_x_calibbias.dev_attr.attr, + &iio_dev_attr_gyro_y_calibbias.dev_attr.attr, + &iio_dev_attr_gyro_z_calibbias.dev_attr.attr, + &iio_dev_attr_accel_x_calibbias.dev_attr.attr, + &iio_dev_attr_accel_y_calibbias.dev_attr.attr, + &iio_dev_attr_accel_z_calibbias.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, &iio_dev_attr_gyro_x_raw.dev_attr.attr, &iio_dev_attr_gyro_y_raw.dev_attr.attr, &iio_dev_attr_gyro_z_raw.dev_attr.attr, @@ -551,10 +570,10 @@ static struct attribute *adis16350_attributes[] = { &iio_dev_attr_temp_y_raw.dev_attr.attr, &iio_dev_attr_temp_z_raw.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, - &iio_const_attr_in0_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, NULL diff --git a/drivers/staging/iio/imu/adis16350_ring.c b/drivers/staging/iio/imu/adis16350_ring.c index e053e9aaa2ed..56b70cfb5822 100644 --- a/drivers/staging/iio/imu/adis16350_ring.c +++ b/drivers/staging/iio/imu/adis16350_ring.c @@ -17,48 +17,62 @@ #include "../trigger.h" #include "adis16350.h" -static IIO_SCAN_EL_C(supply, ADIS16350_SCAN_SUPPLY, IIO_UNSIGNED(12), +static IIO_SCAN_EL_C(in0_supply, ADIS16350_SCAN_SUPPLY, ADIS16350_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0_supply, u, 12, 16); -static IIO_SCAN_EL_C(gyro_x, ADIS16350_SCAN_GYRO_X, IIO_SIGNED(14), - ADIS16350_XGYRO_OUT, NULL); -static IIO_SCAN_EL_C(gyro_y, ADIS16350_SCAN_GYRO_Y, IIO_SIGNED(14), - ADIS16350_YGYRO_OUT, NULL); -static IIO_SCAN_EL_C(gyro_z, ADIS16350_SCAN_GYRO_Z, IIO_SIGNED(14), - ADIS16350_ZGYRO_OUT, NULL); - -static IIO_SCAN_EL_C(accel_x, ADIS16350_SCAN_ACC_X, IIO_SIGNED(14), - ADIS16350_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16350_SCAN_ACC_Y, IIO_SIGNED(14), - ADIS16350_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_z, ADIS16350_SCAN_ACC_Z, IIO_SIGNED(14), - ADIS16350_ZACCL_OUT, NULL); - -static IIO_SCAN_EL_C(temp_x, ADIS16350_SCAN_TEMP_X, IIO_SIGNED(12), - ADIS16350_XTEMP_OUT, NULL); -static IIO_SCAN_EL_C(temp_y, ADIS16350_SCAN_TEMP_Y, IIO_SIGNED(12), - ADIS16350_YTEMP_OUT, NULL); -static IIO_SCAN_EL_C(temp_z, ADIS16350_SCAN_TEMP_Z, IIO_SIGNED(12), - ADIS16350_ZTEMP_OUT, NULL); - -static IIO_SCAN_EL_C(adc_0, ADIS16350_SCAN_ADC_0, IIO_UNSIGNED(12), - ADIS16350_AUX_ADC, NULL); +static IIO_SCAN_EL_C(gyro_x, ADIS16350_SCAN_GYRO_X, ADIS16350_XGYRO_OUT, NULL); +static IIO_SCAN_EL_C(gyro_y, ADIS16350_SCAN_GYRO_Y, ADIS16350_YGYRO_OUT, NULL); +static IIO_SCAN_EL_C(gyro_z, ADIS16350_SCAN_GYRO_Z, ADIS16350_ZGYRO_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(gyro, s, 14, 16); + +static IIO_SCAN_EL_C(accel_x, ADIS16350_SCAN_ACC_X, ADIS16350_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16350_SCAN_ACC_Y, ADIS16350_YACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_z, ADIS16350_SCAN_ACC_Z, ADIS16350_ZACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); + +static IIO_SCAN_EL_C(temp_x, ADIS16350_SCAN_TEMP_X, ADIS16350_XTEMP_OUT, NULL); +static IIO_SCAN_EL_C(temp_y, ADIS16350_SCAN_TEMP_Y, ADIS16350_YTEMP_OUT, NULL); +static IIO_SCAN_EL_C(temp_z, ADIS16350_SCAN_TEMP_Z, ADIS16350_ZTEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, s, 12, 16); + +static IIO_SCAN_EL_C(in1, ADIS16350_SCAN_ADC_0, ADIS16350_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in1, u, 12, 16); static IIO_SCAN_EL_TIMESTAMP(11); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16350_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in0_supply.dev_attr.attr, + &iio_const_attr_in0_supply_index.dev_attr.attr, + &iio_const_attr_in0_supply_type.dev_attr.attr, &iio_scan_el_gyro_x.dev_attr.attr, + &iio_const_attr_gyro_x_index.dev_attr.attr, &iio_scan_el_gyro_y.dev_attr.attr, + &iio_const_attr_gyro_y_index.dev_attr.attr, &iio_scan_el_gyro_z.dev_attr.attr, + &iio_const_attr_gyro_z_index.dev_attr.attr, + &iio_const_attr_gyro_type.dev_attr.attr, &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, &iio_scan_el_temp_x.dev_attr.attr, + &iio_const_attr_temp_x_index.dev_attr.attr, &iio_scan_el_temp_y.dev_attr.attr, + &iio_const_attr_temp_y_index.dev_attr.attr, &iio_scan_el_temp_z.dev_attr.attr, - &iio_scan_el_adc_0.dev_attr.attr, + &iio_const_attr_temp_z_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_const_attr_in1_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -134,11 +148,11 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s) struct adis16350_state *st = container_of(work_s, struct adis16350_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -146,19 +160,19 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16350_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); iio_trigger_notify_done(st->indio_dev->trig); kfree(data); @@ -178,22 +192,6 @@ int adis16350_configure_ring(struct iio_dev *indio_dev) struct adis16350_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16350_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_adc_0.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16350_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -204,11 +202,26 @@ int adis16350_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16350_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in0_supply.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_x.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_y.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_z.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_accel_z.number); + iio_scan_mask_set(ring, iio_scan_el_temp_x.number); + iio_scan_mask_set(ring, iio_scan_el_temp_y.number); + iio_scan_mask_set(ring, iio_scan_el_temp_z.number); + iio_scan_mask_set(ring, iio_scan_el_in1.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16350_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/imu/adis16350_trigger.c b/drivers/staging/iio/imu/adis16350_trigger.c index 76edccc85b71..739b7ecb2e7c 100644 --- a/drivers/staging/iio/imu/adis16350_trigger.c +++ b/drivers/staging/iio/imu/adis16350_trigger.c @@ -30,7 +30,7 @@ static int adis16350_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16350_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16350_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 6013fee218e9..cfb108a1545b 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -490,24 +490,24 @@ err_ret: return ret; } -static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, - adis16400_read_12bit_signed, - adis16400_write_16bit, - ADIS16400_XACCL_OFF); - -static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, - adis16400_read_12bit_signed, - adis16400_write_16bit, - ADIS16400_YACCL_OFF); - -static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, - adis16400_read_12bit_signed, - adis16400_write_16bit, - ADIS16400_ZACCL_OFF); - -static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16400_read_14bit_signed, +#define ADIS16400_DEV_ATTR_CALIBBIAS(_channel, _reg) \ + IIO_DEV_ATTR_##_channel##_CALIBBIAS(S_IWUSR | S_IRUGO, \ + adis16400_read_12bit_signed, \ + adis16400_write_16bit, \ + _reg) + +static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_X, ADIS16400_XGYRO_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Y, ADIS16400_XGYRO_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Z, ADIS16400_XGYRO_OFF); + +static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_X, ADIS16400_XACCL_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Y, ADIS16400_XACCL_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Z, ADIS16400_XACCL_OFF); + + +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16400_read_14bit_signed, ADIS16400_SUPPLY_OUT); -static IIO_CONST_ATTR(in_supply_scale, "0.002418"); +static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.002418 V"); static IIO_DEV_ATTR_GYRO_X(adis16400_read_14bit_signed, ADIS16400_XGYRO_OUT); @@ -515,7 +515,7 @@ static IIO_DEV_ATTR_GYRO_Y(adis16400_read_14bit_signed, ADIS16400_YGYRO_OUT); static IIO_DEV_ATTR_GYRO_Z(adis16400_read_14bit_signed, ADIS16400_ZGYRO_OUT); -static IIO_CONST_ATTR(gyro_scale, "0.05 deg/s"); +static IIO_CONST_ATTR(gyro_scale, "0.0008726646"); static IIO_DEV_ATTR_ACCEL_X(adis16400_read_14bit_signed, ADIS16400_XACCL_OUT); @@ -523,7 +523,7 @@ static IIO_DEV_ATTR_ACCEL_Y(adis16400_read_14bit_signed, ADIS16400_YACCL_OUT); static IIO_DEV_ATTR_ACCEL_Z(adis16400_read_14bit_signed, ADIS16400_ZACCL_OUT); -static IIO_CONST_ATTR(accel_scale, "0.00333 g"); +static IIO_CONST_ATTR(accel_scale, "0.0326561445"); static IIO_DEV_ATTR_MAGN_X(adis16400_read_14bit_signed, ADIS16400_XMAGN_OUT); @@ -535,12 +535,12 @@ static IIO_CONST_ATTR(magn_scale, "0.0005 Gs"); static IIO_DEV_ATTR_TEMP_RAW(adis16400_read_12bit_signed); -static IIO_CONST_ATTR(temp_offset, "198.16 K"); -static IIO_CONST_ATTR(temp_scale, "0.14 K"); +static IIO_CONST_ATTR_TEMP_OFFSET("198.16 K"); +static IIO_CONST_ATTR_TEMP_SCALE("0.14 K"); -static IIO_DEV_ATTR_IN_RAW(0, adis16400_read_12bit_unsigned, +static IIO_DEV_ATTR_IN_RAW(1, adis16400_read_12bit_unsigned, ADIS16400_AUX_ADC); -static IIO_CONST_ATTR(in0_scale, "0.000806"); +static IIO_CONST_ATTR(in1_scale, "0.000806 V"); static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16400_read_frequency, @@ -548,9 +548,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16400_write_reset, 0); -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("409 546 819 1638"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); -static IIO_CONST_ATTR(name, "adis16400"); +static IIO_CONST_ATTR_NAME("adis16400"); static struct attribute *adis16400_event_attributes[] = { NULL @@ -561,11 +561,14 @@ static struct attribute_group adis16400_event_attribute_group = { }; static struct attribute *adis16400_attributes[] = { - &iio_dev_attr_accel_x_offset.dev_attr.attr, - &iio_dev_attr_accel_y_offset.dev_attr.attr, - &iio_dev_attr_accel_z_offset.dev_attr.attr, - &iio_dev_attr_in_supply_raw.dev_attr.attr, - &iio_const_attr_in_supply_scale.dev_attr.attr, + &iio_dev_attr_gyro_x_calibbias.dev_attr.attr, + &iio_dev_attr_gyro_y_calibbias.dev_attr.attr, + &iio_dev_attr_gyro_z_calibbias.dev_attr.attr, + &iio_dev_attr_accel_x_calibbias.dev_attr.attr, + &iio_dev_attr_accel_y_calibbias.dev_attr.attr, + &iio_dev_attr_accel_z_calibbias.dev_attr.attr, + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, &iio_dev_attr_gyro_x_raw.dev_attr.attr, &iio_dev_attr_gyro_y_raw.dev_attr.attr, &iio_dev_attr_gyro_z_raw.dev_attr.attr, @@ -581,10 +584,10 @@ static struct attribute *adis16400_attributes[] = { &iio_dev_attr_temp_raw.dev_attr.attr, &iio_const_attr_temp_offset.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, - &iio_dev_attr_in0_raw.dev_attr.attr, - &iio_const_attr_in0_scale.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_reset.dev_attr.attr, &iio_const_attr_name.dev_attr.attr, NULL diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index 949db76283d7..33293fba9bcc 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -17,51 +17,68 @@ #include "../trigger.h" #include "adis16400.h" -static IIO_SCAN_EL_C(supply, ADIS16400_SCAN_SUPPLY, IIO_SIGNED(14), +static IIO_SCAN_EL_C(in0_supply, ADIS16400_SCAN_SUPPLY, ADIS16400_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0_supply, u, 14, 16); -static IIO_SCAN_EL_C(gyro_x, ADIS16400_SCAN_GYRO_X, IIO_SIGNED(14), - ADIS16400_XGYRO_OUT, NULL); -static IIO_SCAN_EL_C(gyro_y, ADIS16400_SCAN_GYRO_Y, IIO_SIGNED(14), - ADIS16400_YGYRO_OUT, NULL); -static IIO_SCAN_EL_C(gyro_z, ADIS16400_SCAN_GYRO_Z, IIO_SIGNED(14), - ADIS16400_ZGYRO_OUT, NULL); - -static IIO_SCAN_EL_C(accel_x, ADIS16400_SCAN_ACC_X, IIO_SIGNED(14), - ADIS16400_XACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_y, ADIS16400_SCAN_ACC_Y, IIO_SIGNED(14), - ADIS16400_YACCL_OUT, NULL); -static IIO_SCAN_EL_C(accel_z, ADIS16400_SCAN_ACC_Z, IIO_SIGNED(14), - ADIS16400_ZACCL_OUT, NULL); - -static IIO_SCAN_EL_C(magn_x, ADIS16400_SCAN_MAGN_X, IIO_SIGNED(14), - ADIS16400_XMAGN_OUT, NULL); -static IIO_SCAN_EL_C(magn_y, ADIS16400_SCAN_MAGN_Y, IIO_SIGNED(14), - ADIS16400_YMAGN_OUT, NULL); -static IIO_SCAN_EL_C(magn_z, ADIS16400_SCAN_MAGN_Z, IIO_SIGNED(14), - ADIS16400_ZMAGN_OUT, NULL); - -static IIO_SCAN_EL_C(temp, ADIS16400_SCAN_TEMP, IIO_SIGNED(12), - ADIS16400_TEMP_OUT, NULL); -static IIO_SCAN_EL_C(adc_0, ADIS16400_SCAN_ADC_0, IIO_SIGNED(12), - ADIS16400_AUX_ADC, NULL); +static IIO_SCAN_EL_C(gyro_x, ADIS16400_SCAN_GYRO_X, ADIS16400_XGYRO_OUT, NULL); +static IIO_SCAN_EL_C(gyro_y, ADIS16400_SCAN_GYRO_Y, ADIS16400_YGYRO_OUT, NULL); +static IIO_SCAN_EL_C(gyro_z, ADIS16400_SCAN_GYRO_Z, ADIS16400_ZGYRO_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(gyro, s, 14, 16); + +static IIO_SCAN_EL_C(accel_x, ADIS16400_SCAN_ACC_X, ADIS16400_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16400_SCAN_ACC_Y, ADIS16400_YACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_z, ADIS16400_SCAN_ACC_Z, ADIS16400_ZACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); + +static IIO_SCAN_EL_C(magn_x, ADIS16400_SCAN_MAGN_X, ADIS16400_XMAGN_OUT, NULL); +static IIO_SCAN_EL_C(magn_y, ADIS16400_SCAN_MAGN_Y, ADIS16400_YMAGN_OUT, NULL); +static IIO_SCAN_EL_C(magn_z, ADIS16400_SCAN_MAGN_Z, ADIS16400_ZMAGN_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(magn, s, 14, 16); + +static IIO_SCAN_EL_C(temp, ADIS16400_SCAN_TEMP, ADIS16400_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, s, 12, 16); + +static IIO_SCAN_EL_C(in1, ADIS16400_SCAN_ADC_0, ADIS16400_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in1, u, 12, 16); static IIO_SCAN_EL_TIMESTAMP(12); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); static struct attribute *adis16400_scan_el_attrs[] = { - &iio_scan_el_supply.dev_attr.attr, + &iio_scan_el_in0_supply.dev_attr.attr, + &iio_const_attr_in0_supply_index.dev_attr.attr, + &iio_const_attr_in0_supply_type.dev_attr.attr, &iio_scan_el_gyro_x.dev_attr.attr, + &iio_const_attr_gyro_x_index.dev_attr.attr, &iio_scan_el_gyro_y.dev_attr.attr, + &iio_const_attr_gyro_y_index.dev_attr.attr, &iio_scan_el_gyro_z.dev_attr.attr, + &iio_const_attr_gyro_z_index.dev_attr.attr, + &iio_const_attr_gyro_type.dev_attr.attr, &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, &iio_scan_el_accel_z.dev_attr.attr, + &iio_const_attr_accel_z_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, &iio_scan_el_magn_x.dev_attr.attr, + &iio_const_attr_magn_x_index.dev_attr.attr, &iio_scan_el_magn_y.dev_attr.attr, + &iio_const_attr_magn_y_index.dev_attr.attr, &iio_scan_el_magn_z.dev_attr.attr, + &iio_const_attr_magn_z_index.dev_attr.attr, + &iio_const_attr_magn_type.dev_attr.attr, &iio_scan_el_temp.dev_attr.attr, - &iio_scan_el_adc_0.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_const_attr_in1_type.dev_attr.attr, &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, NULL, }; @@ -143,11 +160,11 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) struct adis16400_state *st = container_of(work_s, struct adis16400_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int i = 0; s16 *data; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -155,19 +172,19 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) if (adis16400_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < st->indio_dev->scan_count; i++) + for (; i < ring->scan_count; i++) data[i] = be16_to_cpup( (__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, - st->last_timestamp); + ring->access.store_to(ring, + (u8 *) data, + st->last_timestamp); iio_trigger_notify_done(st->indio_dev->trig); kfree(data); @@ -187,23 +204,6 @@ int adis16400_configure_ring(struct iio_dev *indio_dev) struct adis16400_state *st = indio_dev->dev_data; struct iio_ring_buffer *ring; INIT_WORK(&st->work_trigger_to_ring, adis16400_trigger_bh_to_ring); - /* Set default scan mode */ - - iio_scan_mask_set(indio_dev, iio_scan_el_supply.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_gyro_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_magn_x.number); - iio_scan_mask_set(indio_dev, iio_scan_el_magn_y.number); - iio_scan_mask_set(indio_dev, iio_scan_el_magn_z.number); - iio_scan_mask_set(indio_dev, iio_scan_el_temp.number); - iio_scan_mask_set(indio_dev, iio_scan_el_adc_0.number); - indio_dev->scan_timestamp = true; - - indio_dev->scan_el_attrs = &adis16400_scan_el_group; ring = iio_sw_rb_allocate(indio_dev); if (!ring) { @@ -214,11 +214,27 @@ int adis16400_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ iio_ring_sw_register_funcs(&ring->access); ring->bpe = 2; + ring->scan_el_attrs = &adis16400_scan_el_group; + ring->scan_timestamp = true; ring->preenable = &iio_sw_ring_preenable; ring->postenable = &iio_triggered_ring_postenable; ring->predisable = &iio_triggered_ring_predisable; ring->owner = THIS_MODULE; + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in0_supply.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_x.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_y.number); + iio_scan_mask_set(ring, iio_scan_el_gyro_z.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_accel_z.number); + iio_scan_mask_set(ring, iio_scan_el_magn_x.number); + iio_scan_mask_set(ring, iio_scan_el_magn_y.number); + iio_scan_mask_set(ring, iio_scan_el_magn_z.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in1.number); + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16400_poll_func_th); if (ret) goto error_iio_sw_rb_free; diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c index aafe6010f1b1..36b5ff5be983 100644 --- a/drivers/staging/iio/imu/adis16400_trigger.c +++ b/drivers/staging/iio/imu/adis16400_trigger.c @@ -30,7 +30,7 @@ static int adis16400_data_rdy_trig_poll(struct iio_dev *dev_info, IIO_EVENT_SH(data_rdy_trig, &adis16400_data_rdy_trig_poll); -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *adis16400_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index 92a212f064bd..f3bf111f354f 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -29,11 +29,11 @@ #define IIO_ID_FORMAT IIO_ID_PREFIX "%d" /* IDR to assign each registered device a unique id*/ -static DEFINE_IDR(iio_idr); +static DEFINE_IDA(iio_ida); /* IDR to allocate character device minor numbers */ -static DEFINE_IDR(iio_chrdev_idr); +static DEFINE_IDA(iio_chrdev_ida); /* Lock used to protect both of the above */ -static DEFINE_SPINLOCK(iio_idr_lock); +static DEFINE_SPINLOCK(iio_ida_lock); dev_t iio_devt; EXPORT_SYMBOL(iio_devt); @@ -59,7 +59,7 @@ EXPORT_SYMBOL(__iio_change_event); * are queued. Hence a client MUST open the chrdev before the ring buffer is * switched on. */ - int __iio_push_event(struct iio_event_interface *ev_int, +int __iio_push_event(struct iio_event_interface *ev_int, int ev_code, s64 timestamp, struct iio_shared_ev_pointer * @@ -125,19 +125,10 @@ static irqreturn_t iio_interrupt_handler(int irq, void *_int_info) } time_ns = iio_get_time_ns(); - /* detect single element list*/ - if (list_is_singular(&int_info->ev_list)) { + list_for_each_entry(p, &int_info->ev_list, list) { disable_irq_nosync(irq); - p = list_first_entry(&int_info->ev_list, - struct iio_event_handler_list, - list); - /* single event handler - maybe shared */ p->handler(dev_info, 1, time_ns, !(p->refcount > 1)); - } else - list_for_each_entry(p, &int_info->ev_list, list) { - disable_irq_nosync(irq); - p->handler(dev_info, 1, time_ns, 0); - } + } spin_unlock_irqrestore(&int_info->ev_list_lock, flags); return IRQ_HANDLED; @@ -368,14 +359,14 @@ int iio_device_get_chrdev_minor(void) { int ret, val; -idr_again: - if (unlikely(idr_pre_get(&iio_chrdev_idr, GFP_KERNEL) == 0)) +ida_again: + if (unlikely(ida_pre_get(&iio_chrdev_ida, GFP_KERNEL) == 0)) return -ENOMEM; - spin_lock(&iio_idr_lock); - ret = idr_get_new(&iio_chrdev_idr, NULL, &val); - spin_unlock(&iio_idr_lock); + spin_lock(&iio_ida_lock); + ret = ida_get_new(&iio_chrdev_ida, &val); + spin_unlock(&iio_ida_lock); if (unlikely(ret == -EAGAIN)) - goto idr_again; + goto ida_again; else if (unlikely(ret)) return ret; if (val > IIO_DEV_MAX) @@ -385,9 +376,9 @@ idr_again: void iio_device_free_chrdev_minor(int val) { - spin_lock(&iio_idr_lock); - idr_remove(&iio_chrdev_idr, val); - spin_unlock(&iio_idr_lock); + spin_lock(&iio_ida_lock); + ida_remove(&iio_chrdev_ida, val); + spin_unlock(&iio_ida_lock); } int iio_setup_ev_int(struct iio_event_interface *ev_int, @@ -508,62 +499,49 @@ static int iio_device_register_sysfs(struct iio_dev *dev_info) goto error_ret; } - if (dev_info->scan_el_attrs) { - ret = sysfs_create_group(&dev_info->dev.kobj, - dev_info->scan_el_attrs); - if (ret) - dev_err(&dev_info->dev, - "Failed to add sysfs scan els\n"); - } - error_ret: return ret; } static void iio_device_unregister_sysfs(struct iio_dev *dev_info) { - if (dev_info->scan_el_attrs) - sysfs_remove_group(&dev_info->dev.kobj, - dev_info->scan_el_attrs); - sysfs_remove_group(&dev_info->dev.kobj, dev_info->attrs); } /* Return a negative errno on failure */ -int iio_get_new_idr_val(struct idr *this_idr) +int iio_get_new_ida_val(struct ida *this_ida) { int ret; int val; -idr_again: - if (unlikely(idr_pre_get(this_idr, GFP_KERNEL) == 0)) +ida_again: + if (unlikely(ida_pre_get(this_ida, GFP_KERNEL) == 0)) return -ENOMEM; - spin_lock(&iio_idr_lock); - ret = idr_get_new(this_idr, NULL, &val); - spin_unlock(&iio_idr_lock); + spin_lock(&iio_ida_lock); + ret = ida_get_new(this_ida, &val); + spin_unlock(&iio_ida_lock); if (unlikely(ret == -EAGAIN)) - goto idr_again; + goto ida_again; else if (unlikely(ret)) return ret; return val; } -EXPORT_SYMBOL(iio_get_new_idr_val); +EXPORT_SYMBOL(iio_get_new_ida_val); -void iio_free_idr_val(struct idr *this_idr, int id) +void iio_free_ida_val(struct ida *this_ida, int id) { - spin_lock(&iio_idr_lock); - idr_remove(this_idr, id); - spin_unlock(&iio_idr_lock); + spin_lock(&iio_ida_lock); + ida_remove(this_ida, id); + spin_unlock(&iio_ida_lock); } -EXPORT_SYMBOL(iio_free_idr_val); +EXPORT_SYMBOL(iio_free_ida_val); static int iio_device_register_id(struct iio_dev *dev_info, - struct idr *this_idr) + struct ida *this_ida) { - - dev_info->id = iio_get_new_idr_val(&iio_idr); + dev_info->id = iio_get_new_ida_val(&iio_ida); if (dev_info->id < 0) return dev_info->id; return 0; @@ -571,7 +549,7 @@ static int iio_device_register_id(struct iio_dev *dev_info, static void iio_device_unregister_id(struct iio_dev *dev_info) { - iio_free_idr_val(&iio_idr, dev_info->id); + iio_free_ida_val(&iio_ida, dev_info->id); } static inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i) @@ -770,7 +748,7 @@ int iio_device_register(struct iio_dev *dev_info) { int ret; - ret = iio_device_register_id(dev_info, &iio_idr); + ret = iio_device_register_id(dev_info, &iio_ida); if (ret) { dev_err(&dev_info->dev, "Failed to get id\n"); goto error_ret; @@ -779,7 +757,7 @@ int iio_device_register(struct iio_dev *dev_info) ret = device_add(&dev_info->dev); if (ret) - goto error_free_idr; + goto error_free_ida; ret = iio_device_register_sysfs(dev_info); if (ret) { dev_err(dev_info->dev.parent, @@ -801,7 +779,7 @@ error_free_sysfs: iio_device_unregister_sysfs(dev_info); error_del_device: device_del(&dev_info->dev); -error_free_idr: +error_free_ida: iio_device_unregister_id(dev_info); error_ret: return ret; diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c index 1c5f67253b82..9a98fcdbe109 100644 --- a/drivers/staging/iio/industrialio-ring.c +++ b/drivers/staging/iio/industrialio-ring.c @@ -15,10 +15,8 @@ */ #include <linux/kernel.h> #include <linux/device.h> -#include <linux/interrupt.h> #include <linux/fs.h> #include <linux/poll.h> -#include <linux/module.h> #include <linux/cdev.h> #include <linux/slab.h> @@ -53,7 +51,7 @@ int iio_push_or_escallate_ring_event(struct iio_ring_buffer *ring_buf, EXPORT_SYMBOL(iio_push_or_escallate_ring_event); /** - * iio_ring_open() chrdev file open for ring buffer access + * iio_ring_open() - chrdev file open for ring buffer access * * This function relies on all ring buffer implementations having an * iio_ring_buffer as their first element. @@ -72,7 +70,7 @@ static int iio_ring_open(struct inode *inode, struct file *filp) } /** - * iio_ring_release() -chrdev file close ring buffer access + * iio_ring_release() - chrdev file close ring buffer access * * This function relies on all ring buffer implementations having an * iio_ring_buffer as their first element. @@ -91,7 +89,7 @@ static int iio_ring_release(struct inode *inode, struct file *filp) } /** - * iio_ring_rip_outer() chrdev read for ring buffer access + * iio_ring_rip_outer() - chrdev read for ring buffer access * * This function relies on all ring buffer implementations having an * iio_ring _bufer as their first element. @@ -107,7 +105,7 @@ static ssize_t iio_ring_rip_outer(struct file *filp, char __user *buf, return -EINVAL; copied = rb->access.rip_lots(rb, count, &data, &dead_offset); - if (copied < 0) { + if (copied <= 0) { ret = copied; goto error_ret; } @@ -137,8 +135,9 @@ static const struct file_operations iio_ring_fileops = { }; /** - * __iio_request_ring_buffer_event_chrdev() allocate ring event chrdev + * __iio_request_ring_buffer_event_chrdev() - allocate ring event chrdev * @buf: ring buffer whose event chrdev we are allocating + * @id: id of this ring buffer (typically 0) * @owner: the module who owns the ring buffer (for ref counting) * @dev: device with which the chrdev is associated **/ @@ -280,6 +279,16 @@ int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id) if (ret) goto error_free_ring_buffer_event_chrdev; + if (ring->scan_el_attrs) { + ret = sysfs_create_group(&ring->dev.kobj, + ring->scan_el_attrs); + if (ret) { + dev_err(&ring->dev, + "Failed to add sysfs scan elements\n"); + goto error_free_ring_buffer_event_chrdev; + } + } + return ret; error_free_ring_buffer_event_chrdev: __iio_free_ring_buffer_event_chrdev(ring); @@ -292,6 +301,10 @@ EXPORT_SYMBOL(iio_ring_buffer_register); void iio_ring_buffer_unregister(struct iio_ring_buffer *ring) { + if (ring->scan_el_attrs) + sysfs_remove_group(&ring->dev.kobj, + ring->scan_el_attrs); + __iio_free_ring_buffer_access_chrdev(ring); __iio_free_ring_buffer_event_chrdev(ring); device_del(&ring->dev); @@ -313,7 +326,7 @@ ssize_t iio_read_ring_length(struct device *dev, } EXPORT_SYMBOL(iio_read_ring_length); - ssize_t iio_write_ring_length(struct device *dev, +ssize_t iio_write_ring_length(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -339,20 +352,20 @@ EXPORT_SYMBOL(iio_read_ring_length); } EXPORT_SYMBOL(iio_write_ring_length); -ssize_t iio_read_ring_bps(struct device *dev, +ssize_t iio_read_ring_bytes_per_datum(struct device *dev, struct device_attribute *attr, char *buf) { int len = 0; struct iio_ring_buffer *ring = dev_get_drvdata(dev); - if (ring->access.get_bpd) + if (ring->access.get_bytes_per_datum) len = sprintf(buf, "%d\n", - ring->access.get_bpd(ring)); + ring->access.get_bytes_per_datum(ring)); return len; } -EXPORT_SYMBOL(iio_read_ring_bps); +EXPORT_SYMBOL(iio_read_ring_bytes_per_datum); ssize_t iio_store_ring_enable(struct device *dev, struct device_attribute *attr, @@ -466,10 +479,10 @@ ssize_t iio_scan_el_show(struct device *dev, char *buf) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); struct iio_scan_el *this_el = to_iio_scan_el(attr); - ret = iio_scan_mask_query(indio_dev, this_el->number); + ret = iio_scan_mask_query(ring, this_el->number); if (ret < 0) return ret; return sprintf(buf, "%d\n", ret); @@ -483,7 +496,8 @@ ssize_t iio_scan_el_store(struct device *dev, { int ret = 0; bool state; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; struct iio_scan_el *this_el = to_iio_scan_el(attr); state = !(buf[0] == '0'); @@ -492,19 +506,17 @@ ssize_t iio_scan_el_store(struct device *dev, ret = -EBUSY; goto error_ret; } - ret = iio_scan_mask_query(indio_dev, this_el->number); + ret = iio_scan_mask_query(ring, this_el->number); if (ret < 0) goto error_ret; if (!state && ret) { - ret = iio_scan_mask_clear(indio_dev, this_el->number); + ret = iio_scan_mask_clear(ring, this_el->number); if (ret) goto error_ret; - indio_dev->scan_count--; } else if (state && !ret) { - ret = iio_scan_mask_set(indio_dev, this_el->number); + ret = iio_scan_mask_set(ring, this_el->number); if (ret) goto error_ret; - indio_dev->scan_count++; } if (this_el->set_state) ret = this_el->set_state(this_el, indio_dev, state); @@ -520,8 +532,8 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", indio_dev->scan_timestamp); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", ring->scan_timestamp); } EXPORT_SYMBOL(iio_scan_el_ts_show); @@ -531,7 +543,8 @@ ssize_t iio_scan_el_ts_store(struct device *dev, size_t len) { int ret = 0; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; bool state; state = !(buf[0] == '0'); mutex_lock(&indio_dev->mlock); @@ -539,7 +552,7 @@ ssize_t iio_scan_el_ts_store(struct device *dev, ret = -EBUSY; goto error_ret; } - indio_dev->scan_timestamp = state; + ring->scan_timestamp = state; error_ret: mutex_unlock(&indio_dev->mlock); diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 3ddc478e6182..36d8bbe1a9cc 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -12,3 +12,15 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. + +config SENSORS_ISL29018 + tristate "ISL 29018 light and proximity sensor" + depends on I2C + default n + help + If you say yes here you get support for ambient light sensing and + proximity infrared sensing from Intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. + diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 30f3300e2a68..9142c0e5a1b6 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c new file mode 100644 index 000000000000..f919cc1d35e1 --- /dev/null +++ b/drivers/staging/iio/light/isl29018.c @@ -0,0 +1,563 @@ +/* + * A iio driver for the light sensor ISL 29018. + * + * IIO driver for monitoring ambient light intensity in luxi, proximity + * sensing and infrared sensing. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include "../iio.h" + +#define CONVERSION_TIME_MS 100 + +#define ISL29018_REG_ADD_COMMAND1 0x00 +#define COMMMAND1_OPMODE_SHIFT 5 +#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT) +#define COMMMAND1_OPMODE_POWER_DOWN 0 +#define COMMMAND1_OPMODE_ALS_ONCE 1 +#define COMMMAND1_OPMODE_IR_ONCE 2 +#define COMMMAND1_OPMODE_PROX_ONCE 3 + +#define ISL29018_REG_ADD_COMMANDII 0x01 +#define COMMANDII_RESOLUTION_SHIFT 2 +#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT) + +#define COMMANDII_RANGE_SHIFT 0 +#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT) + +#define COMMANDII_SCHEME_SHIFT 7 +#define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT) + +#define ISL29018_REG_ADD_DATA_LSB 0x02 +#define ISL29018_REG_ADD_DATA_MSB 0x03 +#define ISL29018_MAX_REGS ISL29018_REG_ADD_DATA_MSB + +struct isl29018_chip { + struct iio_dev *indio_dev; + struct i2c_client *client; + struct mutex lock; + unsigned int range; + unsigned int adc_bit; + int prox_scheme; + u8 reg_cache[ISL29018_MAX_REGS]; +}; + +static int isl29018_write_data(struct i2c_client *client, u8 reg, + u8 val, u8 mask, u8 shift) +{ + u8 regval; + int ret = 0; + struct isl29018_chip *chip = i2c_get_clientdata(client); + + regval = chip->reg_cache[reg]; + regval &= ~mask; + regval |= val << shift; + + ret = i2c_smbus_write_byte_data(client, reg, regval); + if (ret) { + dev_err(&client->dev, "Write to device fails status %x\n", ret); + return ret; + } + chip->reg_cache[reg] = regval; + + return 0; +} + +static int isl29018_set_range(struct i2c_client *client, unsigned long range, + unsigned int *new_range) +{ + static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; + int i; + + for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) { + if (range <= supp_ranges[i]) { + *new_range = (unsigned int)supp_ranges[i]; + break; + } + } + + if (i >= ARRAY_SIZE(supp_ranges)) + return -EINVAL; + + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); +} + +static int isl29018_set_resolution(struct i2c_client *client, + unsigned long adcbit, unsigned int *conf_adc_bit) +{ + static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; + int i; + + for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) { + if (adcbit >= supp_adcbit[i]) { + *conf_adc_bit = (unsigned int)supp_adcbit[i]; + break; + } + } + + if (i >= ARRAY_SIZE(supp_adcbit)) + return -EINVAL; + + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + i, COMMANDII_RESOLUTION_MASK, + COMMANDII_RESOLUTION_SHIFT); +} + +static int isl29018_read_sensor_input(struct i2c_client *client, int mode) +{ + int status; + int lsb; + int msb; + + /* Set mode */ + status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, + mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); + if (status) { + dev_err(&client->dev, "Error in setting operating mode\n"); + return status; + } + msleep(CONVERSION_TIME_MS); + lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); + if (lsb < 0) { + dev_err(&client->dev, "Error in reading LSB DATA\n"); + return lsb; + } + + msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); + if (msb < 0) { + dev_err(&client->dev, "Error in reading MSB DATA\n"); + return msb; + } + dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); + + return (msb << 8) | lsb; +} + +static int isl29018_read_lux(struct i2c_client *client, int *lux) +{ + int lux_data; + struct isl29018_chip *chip = i2c_get_clientdata(client); + + lux_data = isl29018_read_sensor_input(client, + COMMMAND1_OPMODE_ALS_ONCE); + + if (lux_data < 0) + return lux_data; + + *lux = (lux_data * chip->range) >> chip->adc_bit; + + return 0; +} + +static int isl29018_read_ir(struct i2c_client *client, int *ir) +{ + int ir_data; + + ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); + + if (ir_data < 0) + return ir_data; + + *ir = ir_data; + + return 0; +} + +static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, + int *near_ir) +{ + int status; + int prox_data = -1; + int ir_data = -1; + + /* Do proximity sensing with required scheme */ + status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); + if (status) { + dev_err(&client->dev, "Error in setting operating mode\n"); + return status; + } + + prox_data = isl29018_read_sensor_input(client, + COMMMAND1_OPMODE_PROX_ONCE); + if (prox_data < 0) + return prox_data; + + if (scheme == 1) { + *near_ir = prox_data; + return 0; + } + + ir_data = isl29018_read_sensor_input(client, + COMMMAND1_OPMODE_IR_ONCE); + + if (ir_data < 0) + return ir_data; + + if (prox_data >= ir_data) + *near_ir = prox_data - ir_data; + else + *near_ir = 0; + + return 0; +} + +static ssize_t get_sensor_data(struct device *dev, char *buf, int mode) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + int value = 0; + int status; + + mutex_lock(&chip->lock); + switch (mode) { + case COMMMAND1_OPMODE_PROX_ONCE: + status = isl29018_read_proximity_ir(client, + chip->prox_scheme, &value); + break; + + case COMMMAND1_OPMODE_ALS_ONCE: + status = isl29018_read_lux(client, &value); + break; + + case COMMMAND1_OPMODE_IR_ONCE: + status = isl29018_read_ir(client, &value); + break; + + default: + dev_err(&client->dev, "Mode %d is not supported\n", mode); + mutex_unlock(&chip->lock); + return -EBUSY; + } + if (status < 0) { + dev_err(&client->dev, "Error in Reading data"); + mutex_unlock(&chip->lock); + return status; + } + + mutex_unlock(&chip->lock); + + return sprintf(buf, "%d\n", value); +} + +/* Sysfs interface */ +/* range */ +static ssize_t show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%u\n", chip->range); +} + +static ssize_t store_range(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + int status; + unsigned long lval; + unsigned int new_range; + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + + if (!(lval == 1000UL || lval == 4000UL || + lval == 16000UL || lval == 64000UL)) { + dev_err(dev, "The range is not supported\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + status = isl29018_set_range(client, lval, &new_range); + if (status < 0) { + mutex_unlock(&chip->lock); + dev_err(dev, "Error in setting max range\n"); + return status; + } + chip->range = new_range; + mutex_unlock(&chip->lock); + + return count; +} + +/* resolution */ +static ssize_t show_resolution(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%u\n", chip->adc_bit); +} + +static ssize_t store_resolution(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + int status; + unsigned long lval; + unsigned int new_adc_bit; + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { + dev_err(dev, "The resolution is not supported\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + status = isl29018_set_resolution(client, lval, &new_adc_bit); + if (status < 0) { + mutex_unlock(&chip->lock); + dev_err(dev, "Error in setting resolution\n"); + return status; + } + chip->adc_bit = new_adc_bit; + mutex_unlock(&chip->lock); + + return count; +} + +/* proximity scheme */ +static ssize_t show_prox_infrared_supression(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + /* return the "proximity scheme" i.e. if the chip does on chip + infrared supression (1 means perform on chip supression) */ + return sprintf(buf, "%d\n", chip->prox_scheme); +} + +static ssize_t store_prox_infrared_supression(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + unsigned long lval; + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + if (!(lval == 0UL || lval == 1UL)) { + dev_err(dev, "The mode is not supported\n"); + return -EINVAL; + } + + /* get the "proximity scheme" i.e. if the chip does on chip + infrared supression (1 means perform on chip supression) */ + mutex_lock(&chip->lock); + chip->prox_scheme = (int)lval; + mutex_unlock(&chip->lock); + + return count; +} + +/* Read lux */ +static ssize_t show_lux(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_ALS_ONCE); +} + +/* Read ir */ +static ssize_t show_ir(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_IR_ONCE); +} + +/* Read nearest ir */ +static ssize_t show_proxim_ir(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_PROX_ONCE); +} + +/* Read name */ +static ssize_t show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%s\n", chip->client->name); +} + +static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); +static IIO_CONST_ATTR(range_available, "1000 4000 16000 64000"); +static IIO_CONST_ATTR(adc_resolution_available, "4 8 12 16"); +static IIO_DEVICE_ATTR(adc_resolution, S_IRUGO | S_IWUSR, + show_resolution, store_resolution, 0); +static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_supression, + S_IRUGO | S_IWUSR, + show_prox_infrared_supression, + store_prox_infrared_supression, 0); +static IIO_DEVICE_ATTR(illuminance0_input, S_IRUGO, show_lux, NULL, 0); +static IIO_DEVICE_ATTR(intensity_infrared_raw, S_IRUGO, show_ir, NULL, 0); +static IIO_DEVICE_ATTR(proximity_raw, S_IRUGO, show_proxim_ir, NULL, 0); +static IIO_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) +#define ISL29018_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) +static struct attribute *isl29018_attributes[] = { + ISL29018_DEV_ATTR(name), + ISL29018_DEV_ATTR(range), + ISL29018_CONST_ATTR(range_available), + ISL29018_DEV_ATTR(adc_resolution), + ISL29018_CONST_ATTR(adc_resolution_available), + ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression), + ISL29018_DEV_ATTR(illuminance0_input), + ISL29018_DEV_ATTR(intensity_infrared_raw), + ISL29018_DEV_ATTR(proximity_raw), + NULL +}; + +static const struct attribute_group isl29108_group = { + .attrs = isl29018_attributes, +}; + +static int isl29018_chip_init(struct i2c_client *client) +{ + struct isl29018_chip *chip = i2c_get_clientdata(client); + int status; + int new_adc_bit; + unsigned int new_range; + + memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); + + /* set defaults */ + status = isl29018_set_range(client, chip->range, &new_range); + if (status < 0) { + dev_err(&client->dev, "Init of isl29018 fails\n"); + return status; + } + + status = isl29018_set_resolution(client, chip->adc_bit, + &new_adc_bit); + + return 0; +} + +static int __devinit isl29018_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29018_chip *chip; + int err; + + chip = kzalloc(sizeof(struct isl29018_chip), GFP_KERNEL); + if (!chip) { + dev_err(&client->dev, "Memory allocation fails\n"); + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, chip); + chip->client = client; + + mutex_init(&chip->lock); + + chip->range = 1000; + chip->adc_bit = 16; + + err = isl29018_chip_init(client); + if (err) + goto exit_free; + + chip->indio_dev = iio_allocate_device(); + if (!chip->indio_dev) { + dev_err(&client->dev, "iio allocation fails\n"); + goto exit_free; + } + chip->indio_dev->attrs = &isl29108_group; + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->dev_data = (void *)(chip); + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + err = iio_device_register(chip->indio_dev); + if (err) { + dev_err(&client->dev, "iio registration fails\n"); + goto exit_iio_free; + } + + return 0; +exit_iio_free: + iio_free_device(chip->indio_dev); +exit_free: + kfree(chip); +exit: + return err; +} + +static int __devexit isl29018_remove(struct i2c_client *client) +{ + struct isl29018_chip *chip = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s()\n", __func__); + iio_device_unregister(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id isl29018_id[] = { + {"isl29018", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, isl29018_id); + +static struct i2c_driver isl29018_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "isl29018", + .owner = THIS_MODULE, + }, + .probe = isl29018_probe, + .remove = __devexit_p(isl29018_remove), + .id_table = isl29018_id, +}; + +static int __init isl29018_init(void) +{ + return i2c_add_driver(&isl29018_driver); +} + +static void __exit isl29018_exit(void) +{ + i2c_del_driver(&isl29018_driver); +} + +module_init(isl29018_init); +module_exit(isl29018_exit); + +MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/light.h b/drivers/staging/iio/light/light.h deleted file mode 100644 index e4e1e2c4139c..000000000000 --- a/drivers/staging/iio/light/light.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "../sysfs.h" - -/* Light to digital sensor attributes */ - -#define IIO_EVENT_CODE_LIGHT_THRESH IIO_EVENT_CODE_LIGHT_BASE - - diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 98f8b78f5d8c..dadae7527d5c 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -584,14 +584,14 @@ static ssize_t tsl2563_calib_store(struct device *dev, return len; } -static IIO_DEVICE_ATTR(intensity_both_raw, S_IRUGO, +static IIO_DEVICE_ATTR(intensity0_both_raw, S_IRUGO, tsl2563_adc_show, NULL, 0); -static IIO_DEVICE_ATTR(intensity_ir_raw, S_IRUGO, +static IIO_DEVICE_ATTR(intensity1_ir_raw, S_IRUGO, tsl2563_adc_show, NULL, 1); static DEVICE_ATTR(illuminance0_input, S_IRUGO, tsl2563_lux_show, NULL); -static IIO_DEVICE_ATTR(intensity_both_calibgain, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(intensity0_both_calibgain, S_IRUGO | S_IWUSR, tsl2563_calib_show, tsl2563_calib_store, 0); -static IIO_DEVICE_ATTR(intensity_ir_calibgain, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(intensity1_ir_calibgain, S_IRUGO | S_IWUSR, tsl2563_calib_show, tsl2563_calib_store, 1); static ssize_t tsl2563_show_name(struct device *dev, @@ -606,11 +606,11 @@ static ssize_t tsl2563_show_name(struct device *dev, static DEVICE_ATTR(name, S_IRUGO, tsl2563_show_name, NULL); static struct attribute *tsl2563_attributes[] = { - &iio_dev_attr_intensity_both_raw.dev_attr.attr, - &iio_dev_attr_intensity_ir_raw.dev_attr.attr, + &iio_dev_attr_intensity0_both_raw.dev_attr.attr, + &iio_dev_attr_intensity1_ir_raw.dev_attr.attr, &dev_attr_illuminance0_input.attr, - &iio_dev_attr_intensity_both_calibgain.dev_attr.attr, - &iio_dev_attr_intensity_ir_calibgain.dev_attr.attr, + &iio_dev_attr_intensity0_both_calibgain.dev_attr.attr, + &iio_dev_attr_intensity1_ir_calibgain.dev_attr.attr, &dev_attr_name.attr, NULL }; @@ -673,13 +673,13 @@ error_ret: return ret < 0 ? ret : len; } -static IIO_DEVICE_ATTR(intensity_both_thresh_high_value, +static IIO_DEVICE_ATTR(intensity0_both_raw_thresh_rising_value, S_IRUGO | S_IWUSR, tsl2563_read_thresh, tsl2563_write_thresh, TSL2563_REG_HIGHLOW); -static IIO_DEVICE_ATTR(intensity_both_thresh_low_value, +static IIO_DEVICE_ATTR(intensity0_both_raw_thresh_falling_value, S_IRUGO | S_IWUSR, tsl2563_read_thresh, tsl2563_write_thresh, @@ -706,8 +706,11 @@ static void tsl2563_int_bh(struct work_struct *work_s) u8 cmd = TSL2563_CMD | TSL2563_CLEARINT; iio_push_event(chip->indio_dev, 0, - IIO_EVENT_CODE_LIGHT_BASE, - chip->event_timestamp); + IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_LIGHT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + chip->event_timestamp); /* reenable_irq */ enable_irq(chip->client->irq); @@ -788,16 +791,16 @@ error_ret: return (ret < 0) ? ret : len; } -IIO_EVENT_ATTR(intensity_both_thresh_both_en, +IIO_EVENT_ATTR(intensity0_both_thresh_en, tsl2563_read_interrupt_config, tsl2563_write_interrupt_config, 0, tsl2563_int_th); static struct attribute *tsl2563_event_attributes[] = { - &iio_event_attr_intensity_both_thresh_both_en.dev_attr.attr, - &iio_dev_attr_intensity_both_thresh_high_value.dev_attr.attr, - &iio_dev_attr_intensity_both_thresh_low_value.dev_attr.attr, + &iio_event_attr_intensity0_both_thresh_en.dev_attr.attr, + &iio_dev_attr_intensity0_both_raw_thresh_rising_value.dev_attr.attr, + &iio_dev_attr_intensity0_both_raw_thresh_falling_value.dev_attr.attr, NULL, }; diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig index d01445060f51..81b579d371df 100644 --- a/drivers/staging/iio/magnetometer/Kconfig +++ b/drivers/staging/iio/magnetometer/Kconfig @@ -3,6 +3,16 @@ # comment "Magnetometer sensors" +config SENSORS_AK8975 + tristate "Asahi Kasei AK8975 3-Axis Magnetometer" + depends on I2C + help + Say yes here to build support for Asahi Kasei AK8975 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak8975. + config SENSORS_HMC5843 tristate "Honeywell HMC5843 3-Axis Magnetometer" depends on I2C diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile index f9bfb2e11d7d..f2a753f80796 100644 --- a/drivers/staging/iio/magnetometer/Makefile +++ b/drivers/staging/iio/magnetometer/Makefile @@ -2,4 +2,5 @@ # Makefile for industrial I/O Magnetometer sensors # +obj-$(CONFIG_SENSORS_AK8975) += ak8975.o obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c new file mode 100644 index 000000000000..420f206cf517 --- /dev/null +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -0,0 +1,558 @@ +/* + * A sensor driver for the magnetometer AK8975. + * + * Magnetic compass sensor driver for monitoring magnetic flux information. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> + +#include <linux/gpio.h> + +#include "../iio.h" +#include "magnet.h" + +/* + * Register definitions, as well as various shifts and masks to get at the + * individual fields of the registers. + */ +#define AK8975_REG_WIA 0x00 +#define AK8975_DEVICE_ID 0x48 + +#define AK8975_REG_INFO 0x01 + +#define AK8975_REG_ST1 0x02 +#define AK8975_REG_ST1_DRDY_SHIFT 0 +#define AK8975_REG_ST1_DRDY_MASK (1 << AK8975_REG_ST1_DRDY_SHIFT) + +#define AK8975_REG_HXL 0x03 +#define AK8975_REG_HXH 0x04 +#define AK8975_REG_HYL 0x05 +#define AK8975_REG_HYH 0x06 +#define AK8975_REG_HZL 0x07 +#define AK8975_REG_HZH 0x08 +#define AK8975_REG_ST2 0x09 +#define AK8975_REG_ST2_DERR_SHIFT 2 +#define AK8975_REG_ST2_DERR_MASK (1 << AK8975_REG_ST2_DERR_SHIFT) + +#define AK8975_REG_ST2_HOFL_SHIFT 3 +#define AK8975_REG_ST2_HOFL_MASK (1 << AK8975_REG_ST2_HOFL_SHIFT) + +#define AK8975_REG_CNTL 0x0A +#define AK8975_REG_CNTL_MODE_SHIFT 0 +#define AK8975_REG_CNTL_MODE_MASK (0xF << AK8975_REG_CNTL_MODE_SHIFT) +#define AK8975_REG_CNTL_MODE_POWER_DOWN 0 +#define AK8975_REG_CNTL_MODE_ONCE 1 +#define AK8975_REG_CNTL_MODE_SELF_TEST 8 +#define AK8975_REG_CNTL_MODE_FUSE_ROM 0xF + +#define AK8975_REG_RSVC 0x0B +#define AK8975_REG_ASTC 0x0C +#define AK8975_REG_TS1 0x0D +#define AK8975_REG_TS2 0x0E +#define AK8975_REG_I2CDIS 0x0F +#define AK8975_REG_ASAX 0x10 +#define AK8975_REG_ASAY 0x11 +#define AK8975_REG_ASAZ 0x12 + +#define AK8975_MAX_REGS AK8975_REG_ASAZ + +/* + * Miscellaneous values. + */ +#define AK8975_MAX_CONVERSION_TIMEOUT 500 +#define AK8975_CONVERSION_DONE_POLL_TIME 10 + +/* + * Per-instance context data for the device. + */ +struct ak8975_data { + struct i2c_client *client; + struct iio_dev *indio_dev; + struct attribute_group attrs; + struct mutex lock; + u8 asa[3]; + long raw_to_gauss[3]; + unsigned long mode; + u8 reg_cache[AK8975_MAX_REGS]; + int eoc_gpio; + int eoc_irq; +}; + +/* + * Helper function to write to the I2C device's registers. + */ +static int ak8975_write_data(struct i2c_client *client, + u8 reg, u8 val, u8 mask, u8 shift) +{ + u8 regval; + struct i2c_msg msg; + u8 w_data[2]; + int ret = 0; + + struct ak8975_data *data = i2c_get_clientdata(client); + + regval = data->reg_cache[reg]; + regval &= ~mask; + regval |= val << shift; + + w_data[0] = reg; + w_data[1] = regval; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2; + msg.buf = w_data; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "Write to device fails status %x\n", ret); + return ret; + } + data->reg_cache[reg] = regval; + + return 0; +} + +/* + * Helper function to read a contiguous set of the I2C device's registers. + */ +static int ak8975_read_data(struct i2c_client *client, + u8 reg, u8 length, u8 *buffer) +{ + struct i2c_msg msg[2]; + u8 w_data[2]; + int ret; + + w_data[0] = reg; + + msg[0].addr = client->addr; + msg[0].flags = I2C_M_NOSTART; /* set repeated start and write */ + msg[0].len = 1; + msg[0].buf = w_data; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = buffer; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) { + dev_err(&client->dev, "Read from device fails\n"); + return ret; + } + + return 0; +} + +/* + * Perform some start-of-day setup, including reading the asa calibration + * values and caching them. + */ +static int ak8975_setup(struct i2c_client *client) +{ + struct ak8975_data *data = i2c_get_clientdata(client); + u8 device_id; + int ret; + + /* Confirm that the device we're talking to is really an AK8975. */ + ret = ak8975_read_data(client, AK8975_REG_WIA, 1, &device_id); + if (ret < 0) { + dev_err(&client->dev, "Error reading WIA\n"); + return ret; + } + if (device_id != AK8975_DEVICE_ID) { + dev_err(&client->dev, "Device ak8975 not found\n"); + return -ENODEV; + } + + /* Write the fused rom access mode. */ + ret = ak8975_write_data(client, + AK8975_REG_CNTL, + AK8975_REG_CNTL_MODE_FUSE_ROM, + AK8975_REG_CNTL_MODE_MASK, + AK8975_REG_CNTL_MODE_SHIFT); + if (ret < 0) { + dev_err(&client->dev, "Error in setting fuse access mode\n"); + return ret; + } + + /* Get asa data and store in the device data. */ + ret = ak8975_read_data(client, AK8975_REG_ASAX, 3, data->asa); + if (ret < 0) { + dev_err(&client->dev, "Not able to read asa data\n"); + return ret; + } + + /* Precalculate scale factor for each axis and + store in the device data. */ + data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8; + data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8; + data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8; + + return 0; +} + +/* + * Shows the device's mode. 0 = off, 1 = on. + */ +static ssize_t show_mode(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ak8975_data *data = indio_dev->dev_data; + + return sprintf(buf, "%lu\n", data->mode); +} + +/* + * Sets the device's mode. 0 = off, 1 = on. The device's mode must be on + * for the magn raw attributes to be available. + */ +static ssize_t store_mode(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ak8975_data *data = indio_dev->dev_data; + struct i2c_client *client = data->client; + unsigned long oval; + int ret; + + /* Convert mode string and do some basic sanity checking on it. + only 0 or 1 are valid. */ + if (strict_strtoul(buf, 10, &oval)) + return -EINVAL; + + if (oval > 1) { + dev_err(dev, "mode value is not supported\n"); + return -EINVAL; + } + + mutex_lock(&data->lock); + + /* Write the mode to the device. */ + if (data->mode != oval) { + ret = ak8975_write_data(client, + AK8975_REG_CNTL, + (u8)oval, + AK8975_REG_CNTL_MODE_MASK, + AK8975_REG_CNTL_MODE_SHIFT); + + if (ret < 0) { + dev_err(&client->dev, "Error in setting mode\n"); + mutex_unlock(&data->lock); + return ret; + } + data->mode = oval; + } + + mutex_unlock(&data->lock); + + return count; +} + +/* + * Emits the scale factor to bring the raw value into Gauss units. + * + * This scale factor is axis-dependent, and is derived from 3 calibration + * factors ASA(x), ASA(y), and ASA(z). + * + * These ASA values are read from the sensor device at start of day, and + * cached in the device context struct. + * + * Adjusting the flux value with the sensitivity adjustment value should be + * done via the following formula: + * + * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 ) + * + * where H is the raw value, ASA is the sensitivity adjustment, and Hadj + * is the resultant adjusted value. + * + * We reduce the formula to: + * + * Hadj = H * (ASA + 128) / 256 + * + * H is in the range of -4096 to 4095. The magnetometer has a range of + * +-1229uT. To go from the raw value to uT is: + * + * HuT = H * 1229/4096, or roughly, 3/10. + * + * Since 1uT = 100 gauss, our final scale factor becomes: + * + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100 + * Hadj = H * ((ASA + 128) * 30 / 256 + * + * Since ASA doesn't change, we cache the resultant scale factor into the + * device context in ak8975_setup(). + */ +static ssize_t show_scale(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ak8975_data *data = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(devattr); + + return sprintf(buf, "%ld\n", data->raw_to_gauss[this_attr->address]); +} + +/* + * Emits the raw flux value for the x, y, or z axis. + */ +static ssize_t show_raw(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ak8975_data *data = indio_dev->dev_data; + struct i2c_client *client = data->client; + struct iio_dev_attr *this_attr = to_iio_dev_attr(devattr); + u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; + u16 meas_reg; + s16 raw; + u8 read_status; + int ret; + + mutex_lock(&data->lock); + + if (data->mode == 0) { + dev_err(&client->dev, "Operating mode is in power down mode\n"); + ret = -EBUSY; + goto exit; + } + + /* Set up the device for taking a sample. */ + ret = ak8975_write_data(client, + AK8975_REG_CNTL, + AK8975_REG_CNTL_MODE_ONCE, + AK8975_REG_CNTL_MODE_MASK, + AK8975_REG_CNTL_MODE_SHIFT); + if (ret < 0) { + dev_err(&client->dev, "Error in setting operating mode\n"); + goto exit; + } + + /* Wait for the conversion to complete. */ + while (timeout_ms) { + msleep(AK8975_CONVERSION_DONE_POLL_TIME); + if (gpio_get_value(data->eoc_gpio)) + break; + timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; + } + if (!timeout_ms) { + dev_err(&client->dev, "Conversion timeout happened\n"); + ret = -EINVAL; + goto exit; + } + + ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status); + if (ret < 0) { + dev_err(&client->dev, "Error in reading ST1\n"); + goto exit; + } + + if (read_status & AK8975_REG_ST1_DRDY_MASK) { + ret = ak8975_read_data(client, AK8975_REG_ST2, 1, &read_status); + if (ret < 0) { + dev_err(&client->dev, "Error in reading ST2\n"); + goto exit; + } + if (read_status & (AK8975_REG_ST2_DERR_MASK | + AK8975_REG_ST2_HOFL_MASK)) { + dev_err(&client->dev, "ST2 status error 0x%x\n", + read_status); + ret = -EINVAL; + goto exit; + } + } + + /* Read the flux value from the appropriate register + (the register is specified in the iio device attributes). */ + ret = ak8975_read_data(client, this_attr->address, 2, (u8 *)&meas_reg); + if (ret < 0) { + dev_err(&client->dev, "Read axis data fails\n"); + goto exit; + } + + mutex_unlock(&data->lock); + + /* Endian conversion of the measured values. */ + raw = (s16) (le16_to_cpu(meas_reg)); + + /* Clamp to valid range. */ + raw = clamp_t(s16, raw, -4096, 4095); + + return sprintf(buf, "%d\n", raw); + +exit: + mutex_unlock(&data->lock); + return ret; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode, 0); +static IIO_DEV_ATTR_MAGN_X_SCALE(S_IRUGO, show_scale, NULL, 0); +static IIO_DEV_ATTR_MAGN_Y_SCALE(S_IRUGO, show_scale, NULL, 1); +static IIO_DEV_ATTR_MAGN_Z_SCALE(S_IRUGO, show_scale, NULL, 2); +static IIO_DEV_ATTR_MAGN_X(show_raw, AK8975_REG_HXL); +static IIO_DEV_ATTR_MAGN_Y(show_raw, AK8975_REG_HYL); +static IIO_DEV_ATTR_MAGN_Z(show_raw, AK8975_REG_HZL); + +static struct attribute *ak8975_attr[] = { + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_magn_x_scale.dev_attr.attr, + &iio_dev_attr_magn_y_scale.dev_attr.attr, + &iio_dev_attr_magn_z_scale.dev_attr.attr, + &iio_dev_attr_magn_x_raw.dev_attr.attr, + &iio_dev_attr_magn_y_raw.dev_attr.attr, + &iio_dev_attr_magn_z_raw.dev_attr.attr, + NULL +}; + +static struct attribute_group ak8975_attr_group = { + .attrs = ak8975_attr, +}; + +static int ak8975_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ak8975_data *data; + int err; + + /* Allocate our device context. */ + data = kzalloc(sizeof(struct ak8975_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Memory allocation fails\n"); + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->client = client; + + mutex_init(&data->lock); + + /* Grab and set up the supplied GPIO. */ + data->eoc_irq = client->irq; + data->eoc_gpio = irq_to_gpio(client->irq); + + if (!data->eoc_gpio) { + dev_err(&client->dev, "failed, no valid GPIO\n"); + err = -EINVAL; + goto exit_free; + } + + err = gpio_request(data->eoc_gpio, "ak_8975"); + if (err < 0) { + dev_err(&client->dev, "failed to request GPIO %d, error %d\n", + data->eoc_gpio, err); + goto exit_free; + } + + err = gpio_direction_input(data->eoc_gpio); + if (err < 0) { + dev_err(&client->dev, "Failed to configure input direction for" + " GPIO %d, error %d\n", data->eoc_gpio, err); + goto exit_gpio; + } + + /* Perform some basic start-of-day setup of the device. */ + err = ak8975_setup(client); + if (err < 0) { + dev_err(&client->dev, "AK8975 initialization fails\n"); + goto exit_gpio; + } + + /* Register with IIO */ + data->indio_dev = iio_allocate_device(); + if (data->indio_dev == NULL) { + err = -ENOMEM; + goto exit_gpio; + } + + data->indio_dev->dev.parent = &client->dev; + data->indio_dev->attrs = &ak8975_attr_group; + data->indio_dev->dev_data = (void *)(data); + data->indio_dev->driver_module = THIS_MODULE; + data->indio_dev->modes = INDIO_DIRECT_MODE; + + err = iio_device_register(data->indio_dev); + if (err < 0) + goto exit_free_iio; + + return 0; + +exit_free_iio: + iio_free_device(data->indio_dev); +exit_gpio: + gpio_free(data->eoc_gpio); +exit_free: + kfree(data); +exit: + return err; +} + +static int ak8975_remove(struct i2c_client *client) +{ + struct ak8975_data *data = i2c_get_clientdata(client); + + iio_device_unregister(data->indio_dev); + iio_free_device(data->indio_dev); + + gpio_free(data->eoc_gpio); + + kfree(data); + + return 0; +} + +static const struct i2c_device_id ak8975_id[] = { + {"ak8975", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak8975_id); + +static struct i2c_driver ak8975_driver = { + .driver = { + .name = "ak8975", + }, + .probe = ak8975_probe, + .remove = __devexit_p(ak8975_remove), + .id_table = ak8975_id, +}; + +static int __init ak8975_init(void) +{ + return i2c_add_driver(&ak8975_driver); +} + +static void __exit ak8975_exit(void) +{ + i2c_del_driver(&ak8975_driver); +} + +module_init(ak8975_init); +module_exit(ak8975_exit); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("AK8975 magnetometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index 92f6c6fb90fe..51689177e00e 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -95,15 +95,15 @@ #define CONF_NOT_USED 0x03 #define MEAS_CONF_MASK 0x03 -static const int regval_to_counts_per_mg[] = { - 1620, - 1300, - 970, - 780, - 530, - 460, - 390, - 280 +static const char *regval_to_scale[] = { + "0.0000006173", + "0.0000007692", + "0.0000010309", + "0.0000012821", + "0.0000018868", + "0.0000021739", + "0.0000025641", + "0.0000035714", }; static const int regval_to_input_field_mg[] = { 700, @@ -220,11 +220,15 @@ static ssize_t hmc5843_set_operating_mode(struct device *dev, int error; mutex_lock(&data->lock); error = strict_strtoul(buf, 10, &operating_mode); - if (error) - return error; + if (error) { + count = error; + goto exit; + } dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode); - if (operating_mode > MODE_SLEEP) - return -EINVAL; + if (operating_mode > MODE_SLEEP) { + count = -EINVAL; + goto exit; + } status = i2c_smbus_write_byte_data(client, this_attr->address, operating_mode); @@ -322,7 +326,7 @@ static IIO_DEVICE_ATTR(meas_conf, * 6 | 50 * 7 | Not used */ -static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("0.5 1 2 5 10 20 50"); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.5 1 2 5 10 20 50"); static s32 hmc5843_set_rate(struct i2c_client *client, u8 rate) @@ -385,11 +389,11 @@ static ssize_t show_sampling_frequency(struct device *dev, struct iio_dev *indio_dev = dev_get_drvdata(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u32 rate; + s32 rate; rate = i2c_smbus_read_byte_data(client, this_attr->address); if (rate < 0) - return -EINVAL; + return rate; rate = (rate & RATE_BITMASK) >> RATE_OFFSET; return sprintf(buf, "%s\n", regval_to_samp_freq[rate]); } @@ -437,18 +441,23 @@ static ssize_t set_range(struct device *dev, int error; mutex_lock(&data->lock); error = strict_strtoul(buf, 10, &range); - if (error) - return error; + if (error) { + count = error; + goto exit; + } dev_dbg(dev, "set range to %lu\n", range); - if (range > RANGE_6_5) - return -EINVAL; + if (range > RANGE_6_5) { + count = -EINVAL; + goto exit; + } data->range = range; range = range << RANGE_GAIN_OFFSET; if (i2c_smbus_write_byte_data(client, this_attr->address, range)) count = -EINVAL; +exit: mutex_unlock(&data->lock); return count; @@ -459,17 +468,17 @@ static IIO_DEVICE_ATTR(magn_range, set_range, HMC5843_CONFIG_REG_B); -static ssize_t show_gain(struct device *dev, +static ssize_t show_scale(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hmc5843_data *data = indio_dev->dev_data; - return sprintf(buf, "%d\n", regval_to_counts_per_mg[data->range]); + return strlen(strcpy(buf, regval_to_scale[data->range])); } -static IIO_DEVICE_ATTR(magn_gain, +static IIO_DEVICE_ATTR(magn_scale, S_IRUGO, - show_gain, + show_scale, NULL , 0); static struct attribute *hmc5843_attributes[] = { @@ -477,11 +486,11 @@ static struct attribute *hmc5843_attributes[] = { &iio_dev_attr_operating_mode.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_magn_range.dev_attr.attr, - &iio_dev_attr_magn_gain.dev_attr.attr, + &iio_dev_attr_magn_scale.dev_attr.attr, &iio_dev_attr_magn_x_raw.dev_attr.attr, &iio_dev_attr_magn_y_raw.dev_attr.attr, &iio_dev_attr_magn_z_raw.dev_attr.attr, - &iio_const_attr_available_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; diff --git a/drivers/staging/iio/magnetometer/magnet.h b/drivers/staging/iio/magnetometer/magnet.h index 64338301f8df..1260eb7bd41e 100644 --- a/drivers/staging/iio/magnetometer/magnet.h +++ b/drivers/staging/iio/magnetometer/magnet.h @@ -12,14 +12,14 @@ #define IIO_DEV_ATTR_MAGN_Z_OFFSET(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(magn_z_offset, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_MAGN_X_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(magn_x_gain, _mode, _show, _store, _addr) +#define IIO_DEV_ATTR_MAGN_X_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(magn_x_scale, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_MAGN_Y_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(magn_y_gain, _mode, _show, _store, _addr) +#define IIO_DEV_ATTR_MAGN_Y_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(magn_y_scale, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_MAGN_Z_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(magn_z_gain, _mode, _show, _store, _addr) +#define IIO_DEV_ATTR_MAGN_Z_SCALE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(magn_z_scale, _mode, _show, _store, _addr) #define IIO_DEV_ATTR_MAGN_X(_show, _addr) \ IIO_DEVICE_ATTR(magn_x_raw, S_IRUGO, _show, NULL, _addr) diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h index a872d3904a33..8ecb1895cec2 100644 --- a/drivers/staging/iio/ring_generic.h +++ b/drivers/staging/iio/ring_generic.h @@ -13,9 +13,7 @@ #ifdef CONFIG_IIO_RING_BUFFER -struct iio_handler; struct iio_ring_buffer; -struct iio_dev; /** * iio_push_ring_event() - ring buffer specific push to event chrdev @@ -52,8 +50,8 @@ int iio_push_or_escallate_ring_event(struct iio_ring_buffer *ring_buf, * change. * @request_update: if a parameter change has been marked, update underlying * storage. - * @get_bpd: get current bytes per datum - * @set_bpd: set number of bytes per datum + * @get_bytes_per_datum:get current bytes per datum + * @set_bytes_per_datum:set number of bytes per datum * @get_length: get number of datums in ring * @set_length: set number of datums in ring * @is_enabled: query if ring is currently being used @@ -81,8 +79,8 @@ struct iio_ring_access_funcs { int (*mark_param_change)(struct iio_ring_buffer *ring); int (*request_update)(struct iio_ring_buffer *ring); - int (*get_bpd)(struct iio_ring_buffer *ring); - int (*set_bpd)(struct iio_ring_buffer *ring, size_t bpd); + int (*get_bytes_per_datum)(struct iio_ring_buffer *ring); + int (*set_bytes_per_datum)(struct iio_ring_buffer *ring, size_t bpd); int (*get_length)(struct iio_ring_buffer *ring); int (*set_length)(struct iio_ring_buffer *ring, int length); @@ -99,9 +97,14 @@ struct iio_ring_access_funcs { * @id: unique id number * @access_id: device id number * @length: [DEVICE] number of datums in ring - * @bpd: [DEVICE] size of individual datum including timestamp + * @bytes_per_datum: [DEVICE] size of individual datum including timestamp * @bpe: [DEVICE] size of individual channel value * @loopcount: [INTERN] number of times the ring has looped + * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode + * control method is used + * @scan_count: [INTERN] the number of elements in the current scan mode + * @scan_mask: [INTERN] bitmask used in masking scan mode elements + * @scan_timestamp: [INTERN] does the scan mode include a timestamp * @access_handler: [INTERN] chrdev access handling * @ev_int: [INTERN] chrdev interface for the event chrdev * @shared_ev_pointer: [INTERN] the shared event pointer to allow escalation of @@ -121,9 +124,13 @@ struct iio_ring_buffer { int id; int access_id; int length; - int bpd; + int bytes_per_datum; int bpe; int loopcount; + struct attribute_group *scan_el_attrs; + int scan_count; + u32 scan_mask; + bool scan_timestamp; struct iio_handler access_handler; struct iio_event_interface ev_int; struct iio_shared_ev_pointer shared_ev_pointer; @@ -134,6 +141,12 @@ struct iio_ring_buffer { int (*postdisable)(struct iio_dev *); }; + +/** + * iio_ring_buffer_init() - Initialize the buffer structure + * @ring: buffer to be initialized + * @dev_info: the iio device the buffer is assocated with + **/ void iio_ring_buffer_init(struct iio_ring_buffer *ring, struct iio_dev *dev_info); @@ -146,7 +159,7 @@ void iio_ring_buffer_init(struct iio_ring_buffer *ring, static inline void __iio_update_ring_buffer(struct iio_ring_buffer *ring, int bytes_per_datum, int length) { - ring->bpd = bytes_per_datum; + ring->bytes_per_datum = bytes_per_datum; ring->length = length; ring->loopcount = 0; } @@ -155,7 +168,6 @@ static inline void __iio_update_ring_buffer(struct iio_ring_buffer *ring, * struct iio_scan_el - an individual element of a scan * @dev_attr: control attribute (if directly controllable) * @number: unique identifier of element (used for bit mask) - * @bit_count: number of bits in scan element * @label: useful data for the scan el (often reg address) * @set_state: for some devices datardy signals are generated * for any enabled lines. This allows unwanted lines @@ -164,7 +176,6 @@ static inline void __iio_update_ring_buffer(struct iio_ring_buffer *ring, struct iio_scan_el { struct device_attribute dev_attr; unsigned int number; - int bit_count; unsigned int label; int (*set_state)(struct iio_scan_el *scanel, @@ -192,7 +203,7 @@ struct iio_scan_el { ssize_t iio_scan_el_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len); /** - * iio_scal_el_show() - sysfs interface to query whether a scan element is + * iio_scan_el_show() - sysfs interface to query whether a scan element * is enabled or not * @dev: the target device * @attr: the device attribute that is being processed @@ -201,9 +212,16 @@ ssize_t iio_scan_el_store(struct device *dev, struct device_attribute *attr, ssize_t iio_scan_el_show(struct device *dev, struct device_attribute *attr, char *buf); +/** + * iio_scan_el_ts_store() - sysfs interface to set whether a timestamp is included + * in the scan. + **/ ssize_t iio_scan_el_ts_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len); - +/** + * iio_scan_el_ts_show() - sysfs interface to query if a timestamp is included + * in the scan. + **/ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, char *buf); /** @@ -212,52 +230,189 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr, * @_name: identifying name. Resulting struct is iio_scan_el_##_name, * sysfs element, _name##_en. * @_number: unique id number for the scan element. - * @_bits: number of bits in the scan element result (used in mixed bit * length devices). * @_label: indentification variable used by drivers. Often a reg address. * @_controlfunc: function used to notify hardware of whether state changes **/ -#define __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \ +#define __IIO_SCAN_EL_C(_name, _number, _label, _controlfunc) \ struct iio_scan_el iio_scan_el_##_name = { \ - .dev_attr = __ATTR(_number##_##_name##_en, \ + .dev_attr = __ATTR(_name##_en, \ S_IRUGO | S_IWUSR, \ iio_scan_el_show, \ iio_scan_el_store), \ .number = _number, \ - .bit_count = _bits, \ .label = _label, \ .set_state = _controlfunc, \ - } + }; \ + static IIO_CONST_ATTR(_name##_index, #_number) -#define IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \ - __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) +#define IIO_SCAN_EL_C(_name, _number, _label, _controlfunc) \ + __IIO_SCAN_EL_C(_name, _number, _label, _controlfunc) -#define __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \ +#define __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _label, _cf) \ struct iio_scan_el iio_scan_el_##_name = { \ - .dev_attr = __ATTR(_number##_##_string##_en, \ + .dev_attr = __ATTR(_string##_en, \ S_IRUGO | S_IWUSR, \ iio_scan_el_show, \ iio_scan_el_store), \ .number = _number, \ - .bit_count = _bits, \ .label = _label, \ .set_state = _cf, \ + }; \ + static struct iio_const_attr iio_const_attr_##_name##_index = { \ + .string = #_number, \ + .dev_attr = __ATTR(_string##_index, \ + S_IRUGO, iio_read_const_attr, NULL) \ } -#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \ - __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) + + +#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _label, _cf) \ + __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _label, _cf) /** * IIO_SCAN_EL_TIMESTAMP - declare a special scan element for timestamps + * @number: specify where in the scan order this is stored. * * Odd one out. Handled slightly differently from other scan elements. **/ #define IIO_SCAN_EL_TIMESTAMP(number) \ struct iio_scan_el iio_scan_el_timestamp = { \ - .dev_attr = __ATTR(number##_timestamp_en, \ + .dev_attr = __ATTR(timestamp_en, \ S_IRUGO | S_IWUSR, \ iio_scan_el_ts_show, \ iio_scan_el_ts_store), \ + }; \ + static IIO_CONST_ATTR(timestamp_index, #number) + +/** + * IIO_CONST_ATTR_SCAN_EL_TYPE - attr to specify the data format of a scan el + * @name: the scan el name (may be more general and cover a set of scan elements + * @_sign: either s or u for signed or unsigned + * @_bits: number of actual bits occuplied by the value + * @_storagebits: number of bits _bits is padded to when read out of buffer + **/ +#define IIO_CONST_ATTR_SCAN_EL_TYPE(_name, _sign, _bits, _storagebits) \ + IIO_CONST_ATTR(_name##_type, #_sign#_bits"/"#_storagebits); + +/** + * IIO_CONST_ATTR_SCAN_EL_TYPE_WITH_SHIFT - attr to specify the data format of a scan el + * @name: the scan el name (may be more general and cover a set of scan elements + * @_sign: either s or u for signed or unsigned + * @_bits: number of actual bits occuplied by the value + * @_storagebits: number of bits _bits is padded to when read out of buffer + * @_shiftbits: number of bits _shiftbits the result must be shifted + **/ +#define IIO_CONST_ATTR_SCAN_EL_TYPE_WITH_SHIFT(_name, _sign, _bits, \ + _storagebits, _shiftbits) \ + IIO_CONST_ATTR(_name##_type, #_sign#_bits"/"#_storagebits \ + ">>"#_shiftbits); + +#define IIO_SCAN_EL_TYPE_SIGNED 's' +#define IIO_SCAN_EL_TYPE_UNSIGNED 'u' + +/* + * These are mainly provided to allow for a change of implementation if a device + * has a large number of scan elements + */ +#define IIO_MAX_SCAN_LENGTH 31 + +/* note 0 used as error indicator as it doesn't make sense. */ +static inline u32 iio_scan_mask_match(u32 *av_masks, u32 mask) +{ + while (*av_masks) { + if (!(~*av_masks & mask)) + return *av_masks; + av_masks++; + } + return 0; +} + +static inline int iio_scan_mask_query(struct iio_ring_buffer *ring, int bit) +{ + struct iio_dev *dev_info = ring->indio_dev; + u32 mask; + + if (bit > IIO_MAX_SCAN_LENGTH) + return -EINVAL; + + if (!ring->scan_mask) + return 0; + + if (dev_info->available_scan_masks) + mask = iio_scan_mask_match(dev_info->available_scan_masks, + ring->scan_mask); + else + mask = ring->scan_mask; + + if (!mask) + return -EINVAL; + + return !!(mask & (1 << bit)); +}; + +/** + * iio_scan_mask_set() - set particular bit in the scan mask + * @ring: the ring buffer whose scan mask we are interested in + * @bit: the bit to be set. + **/ +static inline int iio_scan_mask_set(struct iio_ring_buffer *ring, int bit) +{ + struct iio_dev *dev_info = ring->indio_dev; + u32 mask; + u32 trialmask = ring->scan_mask | (1 << bit); + + if (bit > IIO_MAX_SCAN_LENGTH) + return -EINVAL; + if (dev_info->available_scan_masks) { + mask = iio_scan_mask_match(dev_info->available_scan_masks, + trialmask); + if (!mask) + return -EINVAL; + } + ring->scan_mask = trialmask; + ring->scan_count++; + + return 0; +}; + +/** + * iio_scan_mask_clear() - clear a particular element from the scan mask + * @ring: the ring buffer whose scan mask we are interested in + * @bit: the bit to clear + **/ +static inline int iio_scan_mask_clear(struct iio_ring_buffer *ring, int bit) +{ + if (bit > IIO_MAX_SCAN_LENGTH) + return -EINVAL; + ring->scan_mask &= ~(1 << bit); + ring->scan_count--; + return 0; +}; + +/** + * iio_scan_mask_count_to_right() - how many scan elements occur before here + * @ring: the ring buffer whose scan mask we interested in + * @bit: which number scan element is this + **/ +static inline int iio_scan_mask_count_to_right(struct iio_ring_buffer *ring, + int bit) +{ + int count = 0; + int mask = (1 << bit); + if (bit > IIO_MAX_SCAN_LENGTH) + return -EINVAL; + while (mask) { + mask >>= 1; + if (mask & ring->scan_mask) + count++; } + return count; +} + +/** + * iio_put_ring_buffer() - notify done with buffer + * @ring: the buffer we are done with. + **/ static inline void iio_put_ring_buffer(struct iio_ring_buffer *ring) { put_device(&ring->dev); @@ -267,32 +422,58 @@ static inline void iio_put_ring_buffer(struct iio_ring_buffer *ring) container_of(d, struct iio_ring_buffer, dev) #define access_dev_to_iio_ring_buffer(d) \ container_of(d, struct iio_ring_buffer, access_dev) + +/** + * iio_ring_buffer_register() - register the buffer with IIO core + * @ring: the buffer to be registered + * @id: the id of the buffer (typically 0) + **/ int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id); + +/** + * iio_ring_buffer_unregister() - unregister the buffer from IIO core + * @ring: the buffer to be unregistered + **/ void iio_ring_buffer_unregister(struct iio_ring_buffer *ring); +/** + * iio_read_ring_length() - attr func to get number of datums in the buffer + **/ ssize_t iio_read_ring_length(struct device *dev, struct device_attribute *attr, char *buf); +/** + * iio_write_ring_length() - attr func to set number of datums in the buffer + **/ ssize_t iio_write_ring_length(struct device *dev, struct device_attribute *attr, const char *buf, size_t len); -ssize_t iio_read_ring_bps(struct device *dev, +/** + * iio_read_ring_bytes_per_datum() - attr for number of bytes in whole datum + **/ +ssize_t iio_read_ring_bytes_per_datum(struct device *dev, struct device_attribute *attr, char *buf); +/** + * iio_store_ring_enable() - attr to turn the buffer on + **/ ssize_t iio_store_ring_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t len); +/** + * iio_show_ring_enable() - attr to see if the buffer is on + **/ ssize_t iio_show_ring_enable(struct device *dev, struct device_attribute *attr, char *buf); #define IIO_RING_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR, \ iio_read_ring_length, \ iio_write_ring_length) -#define IIO_RING_BPS_ATTR DEVICE_ATTR(bps, S_IRUGO | S_IWUSR, \ - iio_read_ring_bps, NULL) -#define IIO_RING_ENABLE_ATTR DEVICE_ATTR(ring_enable, S_IRUGO | S_IWUSR, \ +#define IIO_RING_BYTES_PER_DATUM_ATTR DEVICE_ATTR(bytes_per_datum, S_IRUGO | S_IWUSR, \ + iio_read_ring_bytes_per_datum, NULL) +#define IIO_RING_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, \ iio_show_ring_enable, \ iio_store_ring_enable) #else /* CONFIG_IIO_RING_BUFFER */ diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c index e2f01c640baf..52624ace0bc5 100644 --- a/drivers/staging/iio/ring_sw.c +++ b/drivers/staging/iio/ring_sw.c @@ -21,7 +21,7 @@ static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; __iio_update_ring_buffer(&ring->buf, bytes_per_datum, length); - ring->data = kmalloc(length*ring->buf.bpd, GFP_ATOMIC); + ring->data = kmalloc(length*ring->buf.bytes_per_datum, GFP_ATOMIC); ring->read_p = NULL; ring->write_p = NULL; ring->last_written_p = NULL; @@ -77,10 +77,10 @@ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, * as long as the read pointer is valid before this * passes it - guaranteed as set later in this function. */ - ring->half_p = ring->data - ring->buf.length*ring->buf.bpd/2; + ring->half_p = ring->data - ring->buf.length*ring->buf.bytes_per_datum/2; } /* Copy data to where ever the current write pointer says */ - memcpy(ring->write_p, data, ring->buf.bpd); + memcpy(ring->write_p, data, ring->buf.bytes_per_datum); barrier(); /* Update the pointer used to get most recent value. * Always valid as either points to latest or second latest value. @@ -91,9 +91,9 @@ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, /* temp_ptr used to ensure we never have an invalid pointer * it may be slightly lagging, but never invalid */ - temp_ptr = ring->write_p + ring->buf.bpd; + temp_ptr = ring->write_p + ring->buf.bytes_per_datum; /* End of ring, back to the beginning */ - if (temp_ptr == ring->data + ring->buf.length*ring->buf.bpd) + if (temp_ptr == ring->data + ring->buf.length*ring->buf.bytes_per_datum) temp_ptr = ring->data; /* Update the write pointer * always valid as long as this is the only function able to write. @@ -112,9 +112,9 @@ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, */ else if (ring->write_p == ring->read_p) { change_test_ptr = ring->read_p; - temp_ptr = change_test_ptr + ring->buf.bpd; + temp_ptr = change_test_ptr + ring->buf.bytes_per_datum; if (temp_ptr - == ring->data + ring->buf.length*ring->buf.bpd) { + == ring->data + ring->buf.length*ring->buf.bytes_per_datum) { temp_ptr = ring->data; } /* We are moving pointer on one because the ring is full. Any @@ -135,8 +135,8 @@ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, /* There are definite 'issues' with this and chances of * simultaneous read */ /* Also need to use loop count to ensure this only happens once */ - ring->half_p += ring->buf.bpd; - if (ring->half_p == ring->data + ring->buf.length*ring->buf.bpd) + ring->half_p += ring->buf.bytes_per_datum; + if (ring->half_p == ring->data + ring->buf.length*ring->buf.bytes_per_datum) ring->half_p = ring->data; if (ring->half_p == ring->read_p) { spin_lock(&ring->buf.shared_ev_pointer.lock); @@ -164,15 +164,15 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r, * read something that is not a whole number of bpds. * Return an error. */ - if (count % ring->buf.bpd) { + if (count % ring->buf.bytes_per_datum) { ret = -EINVAL; printk(KERN_INFO "Ring buffer read request not whole number of" - "samples: Request bytes %zd, Current bpd %d\n", - count, ring->buf.bpd); + "samples: Request bytes %zd, Current bytes per datum %d\n", + count, ring->buf.bytes_per_datum); goto error_ret; } /* Limit size to whole of ring buffer */ - bytes_to_rip = min((size_t)(ring->buf.bpd*ring->buf.length), count); + bytes_to_rip = min((size_t)(ring->buf.bytes_per_datum*ring->buf.length), count); *data = kmalloc(bytes_to_rip, GFP_KERNEL); if (*data == NULL) { @@ -214,7 +214,7 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r, } else { /* going through 'end' of ring buffer */ max_copied = ring->data - + ring->buf.length*ring->buf.bpd - initial_read_p; + + ring->buf.length*ring->buf.bytes_per_datum - initial_read_p; memcpy(*data, initial_read_p, max_copied); /* possible we are done if we align precisely with end */ if (max_copied == bytes_to_rip) @@ -240,7 +240,7 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r, if (initial_read_p <= current_read_p) *dead_offset = current_read_p - initial_read_p; else - *dead_offset = ring->buf.length*ring->buf.bpd + *dead_offset = ring->buf.length*ring->buf.bytes_per_datum - (initial_read_p - current_read_p); /* possible issue if the initial write has been lapped or indeed @@ -293,7 +293,7 @@ again: /* Check there is anything here */ if (last_written_p_copy == NULL) return -EAGAIN; - memcpy(data, last_written_p_copy, ring->buf.bpd); + memcpy(data, last_written_p_copy, ring->buf.bytes_per_datum); if (unlikely(ring->last_written_p != last_written_p_copy)) goto again; @@ -322,7 +322,7 @@ int iio_request_update_sw_rb(struct iio_ring_buffer *r) goto error_ret; } __iio_free_sw_ring_buffer(ring); - ret = __iio_allocate_sw_ring_buffer(ring, ring->buf.bpd, + ret = __iio_allocate_sw_ring_buffer(ring, ring->buf.bytes_per_datum, ring->buf.length); error_ret: spin_unlock(&ring->use_lock); @@ -330,23 +330,23 @@ error_ret: } EXPORT_SYMBOL(iio_request_update_sw_rb); -int iio_get_bpd_sw_rb(struct iio_ring_buffer *r) +int iio_get_bytes_per_datum_sw_rb(struct iio_ring_buffer *r) { struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - return ring->buf.bpd; + return ring->buf.bytes_per_datum; } -EXPORT_SYMBOL(iio_get_bpd_sw_rb); +EXPORT_SYMBOL(iio_get_bytes_per_datum_sw_rb); -int iio_set_bpd_sw_rb(struct iio_ring_buffer *r, size_t bpd) +int iio_set_bytes_per_datum_sw_rb(struct iio_ring_buffer *r, size_t bpd) { - if (r->bpd != bpd) { - r->bpd = bpd; + if (r->bytes_per_datum != bpd) { + r->bytes_per_datum = bpd; if (r->access.mark_param_change) r->access.mark_param_change(r); } return 0; } -EXPORT_SYMBOL(iio_set_bpd_sw_rb); +EXPORT_SYMBOL(iio_set_bytes_per_datum_sw_rb); int iio_get_length_sw_rb(struct iio_ring_buffer *r) { @@ -380,14 +380,14 @@ static void iio_sw_rb_release(struct device *dev) } static IIO_RING_ENABLE_ATTR; -static IIO_RING_BPS_ATTR; +static IIO_RING_BYTES_PER_DATUM_ATTR; static IIO_RING_LENGTH_ATTR; /* Standard set of ring buffer attributes */ static struct attribute *iio_ring_attributes[] = { &dev_attr_length.attr, - &dev_attr_bps.attr, - &dev_attr_ring_enable.attr, + &dev_attr_bytes_per_datum.attr, + &dev_attr_enable.attr, NULL, }; @@ -435,23 +435,24 @@ EXPORT_SYMBOL(iio_sw_rb_free); int iio_sw_ring_preenable(struct iio_dev *indio_dev) { + struct iio_ring_buffer *ring = indio_dev->ring; size_t size; dev_dbg(&indio_dev->dev, "%s\n", __func__); /* Check if there are any scan elements enabled, if not fail*/ - if (!(indio_dev->scan_count || indio_dev->scan_timestamp)) + if (!(ring->scan_count || ring->scan_timestamp)) return -EINVAL; - if (indio_dev->scan_timestamp) - if (indio_dev->scan_count) + if (ring->scan_timestamp) + if (ring->scan_count) /* Timestamp (aligned to s64) and data */ - size = (((indio_dev->scan_count * indio_dev->ring->bpe) + size = (((ring->scan_count * ring->bpe) + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) + sizeof(s64); else /* Timestamp only */ size = sizeof(s64); else /* Data only */ - size = indio_dev->scan_count * indio_dev->ring->bpe; - indio_dev->ring->access.set_bpd(indio_dev->ring, size); + size = ring->scan_count * ring->bpe; + ring->access.set_bytes_per_datum(ring, size); return 0; } @@ -462,9 +463,9 @@ void iio_sw_trigger_bh_to_ring(struct work_struct *work_s) struct iio_sw_ring_helper_state *st = container_of(work_s, struct iio_sw_ring_helper_state, work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; int len = 0; - size_t datasize = st->indio_dev - ->ring->access.get_bpd(st->indio_dev->ring); + size_t datasize = ring->access.get_bytes_per_datum(ring); char *data = kmalloc(datasize, GFP_KERNEL); if (data == NULL) { @@ -473,16 +474,16 @@ void iio_sw_trigger_bh_to_ring(struct work_struct *work_s) return; } - if (st->indio_dev->scan_count) + if (ring->scan_count) len = st->get_ring_element(st, data); /* Guaranteed to be aligned with 8 byte boundary */ - if (st->indio_dev->scan_timestamp) + if (ring->scan_timestamp) *(s64 *)(((phys_addr_t)data + len + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) = st->last_timestamp; - st->indio_dev->ring->access.store_to(st->indio_dev->ring, - (u8 *)data, + ring->access.store_to(ring, + (u8 *)data, st->last_timestamp); iio_trigger_notify_done(st->indio_dev->trig); diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h index 61f1ed650392..ad03d832c1b9 100644 --- a/drivers/staging/iio/ring_sw.h +++ b/drivers/staging/iio/ring_sw.h @@ -121,19 +121,19 @@ int iio_mark_update_needed_sw_rb(struct iio_ring_buffer *r); /** - * iio_get_bpd_sw_rb() - get the datum size in bytes + * iio_get_bytes_per_datum_sw_rb() - get the datum size in bytes * @r: pointer to a software ring buffer created by an * iio_create_sw_rb call **/ -int iio_get_bpd_sw_rb(struct iio_ring_buffer *r); +int iio_get_bytes_per_datum_sw_rb(struct iio_ring_buffer *r); /** - * iio_set_bpd_sw_rb() - set the datum size in bytes + * iio_set_bytes_per_datum_sw_rb() - set the datum size in bytes * @r: pointer to a software ring buffer created by an * iio_create_sw_rb call * @bpd: bytes per datum value **/ -int iio_set_bpd_sw_rb(struct iio_ring_buffer *r, size_t bpd); +int iio_set_bytes_per_datum_sw_rb(struct iio_ring_buffer *r, size_t bpd); /** * iio_get_length_sw_rb() - get how many datums the rb may contain @@ -166,8 +166,8 @@ static inline void iio_ring_sw_register_funcs(struct iio_ring_access_funcs *ra) ra->mark_param_change = &iio_mark_update_needed_sw_rb; ra->request_update = &iio_request_update_sw_rb; - ra->get_bpd = &iio_get_bpd_sw_rb; - ra->set_bpd = &iio_set_bpd_sw_rb; + ra->get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb; + ra->set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb; ra->get_length = &iio_get_length_sw_rb; ra->set_length = &iio_set_length_sw_rb; diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h index 60834162eb32..ee91a95a8b95 100644 --- a/drivers/staging/iio/sysfs.h +++ b/drivers/staging/iio/sysfs.h @@ -30,27 +30,6 @@ struct iio_event_attr { container_of(_dev_attr, struct iio_event_attr, dev_attr) /** - * struct iio_chrdev_minor_attr - simple attribute to allow reading of chrdev - * minor number - * @dev_attr: underlying device attribute - * @minor: the minor number - */ -struct iio_chrdev_minor_attr { - struct device_attribute dev_attr; - int minor; -}; - -void -__init_iio_chrdev_minor_attr(struct iio_chrdev_minor_attr *minor_attr, - const char *name, - struct module *owner, - int id); - - -#define to_iio_chrdev_minor_attr(_dev_attr) \ - container_of(_dev_attr, struct iio_chrdev_minor_attr, dev_attr); - -/** * struct iio_dev_attr - iio specific device attribute * @dev_attr: underlying device attribute * @address: associated register address @@ -89,11 +68,6 @@ struct iio_const_attr { { .dev_attr = __ATTR(_name, _mode, _show, _store), \ .address = _addr } -#define IIO_ATTR_2(_name, _mode, _show, _store, _addr, _val2) \ - { .dev_attr = __ATTR(_name, _mode, _show, _store), \ - .address = _addr, \ - .val2 = _val2 } - #define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr) \ struct iio_dev_attr iio_dev_attr_##_name \ = IIO_ATTR(_name, _mode, _show, _store, _addr) @@ -111,6 +85,10 @@ struct iio_const_attr { = { .string = _string, \ .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)} +#define IIO_CONST_ATTR_NAMED(_vname, _name, _string) \ + struct iio_const_attr iio_const_attr_##_vname \ + = { .string = _string, \ + .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)} /* Generic attributes of onetype or another */ /** @@ -130,6 +108,13 @@ struct iio_const_attr { IIO_DEVICE_ATTR(name, S_IRUGO, _show, NULL, 0) /** + * IIO_CONST_ATTR_NAME - constant identifier + * @_string: the name + **/ +#define IIO_CONST_ATTR_NAME(_string) \ + IIO_CONST_ATTR(name, _string) + +/** * IIO_DEV_ATTR_SAMP_FREQ - sets any internal clock frequency * @_mode: sysfs file mode/permissions * @_show: output method for the attribute @@ -156,48 +141,10 @@ struct iio_const_attr { * * Constant version **/ -/* Deprecated */ -#define IIO_CONST_ATTR_AVAIL_SAMP_FREQ(_string) \ - IIO_CONST_ATTR(available_sampling_frequency, _string) - #define IIO_CONST_ATTR_SAMP_FREQ_AVAIL(_string) \ IIO_CONST_ATTR(sampling_frequency_available, _string) /** - * IIO_DEV_ATTR_SCAN_MODE - select a scan mode - * @_mode: sysfs file mode/permissions - * @_show: output method for the attribute - * @_store: input method for the attribute - * - * This is used when only certain combinations of inputs may be read in one - * scan. - **/ -#define IIO_DEV_ATTR_SCAN_MODE(_mode, _show, _store) \ - IIO_DEVICE_ATTR(scan_mode, _mode, _show, _store, 0) - -/** - * IIO_DEV_ATTR_AVAIL_SCAN_MODES - list available scan modes - * @_show: output method for the attribute - **/ -#define IIO_DEV_ATTR_AVAIL_SCAN_MODES(_show) \ - IIO_DEVICE_ATTR(available_scan_modes, S_IRUGO, _show, NULL, 0) - -/** - * IIO_DEV_ATTR_SCAN - result of scan of multiple channels - * @_show: output method for the attribute - **/ -#define IIO_DEV_ATTR_SCAN(_show) \ - IIO_DEVICE_ATTR(scan, S_IRUGO, _show, NULL, 0); - -/** - * IIO_DEV_ATTR_INPUT - direct read of a single input channel - * @_number: input channel number - * @_show: output method for the attribute - **/ -#define IIO_DEV_ATTR_INPUT(_number, _show) \ - IIO_DEVICE_ATTR(in##_number, S_IRUGO, _show, NULL, _number) - -/** * IIO_DEV_ATTR_SW_RING_ENABLE - enable software ring buffer * @_show: output method for the attribute * @_store: input method for the attribute @@ -218,32 +165,15 @@ struct iio_const_attr { #define IIO_DEV_ATTR_HW_RING_ENABLE(_show, _store) \ IIO_DEVICE_ATTR(hw_ring_enable, S_IRUGO | S_IWUSR, _show, _store, 0) -/** - * IIO_DEV_ATTR_BPSE - set number of bits per scan element - * @_mode: sysfs file mode/permissions - * @_show: output method for the attribute - * @_store: input method for the attribute - **/ -#define IIO_DEV_ATTR_BPSE(_mode, _show, _store) \ - IIO_DEVICE_ATTR(bpse, _mode, _show, _store, 0) - -/** - * IIO_DEV_ATTR_BPSE_AVAILABLE - number of bits per scan element supported - * @_show: output method for the attribute - **/ -#define IIO_DEV_ATTR_BPSE_AVAILABLE(_show) \ - IIO_DEVICE_ATTR(bpse_available, S_IRUGO, _show, NULL, 0) - -/** - * IIO_DEV_ATTR_TEMP - many sensors have auxiliary temperature sensors - * @_show: output method for the attribute - **/ -#define IIO_DEV_ATTR_TEMP(_show) \ - IIO_DEVICE_ATTR(temp, S_IRUGO, _show, NULL, 0) - #define IIO_DEV_ATTR_TEMP_RAW(_show) \ IIO_DEVICE_ATTR(temp_raw, S_IRUGO, _show, NULL, 0) +#define IIO_CONST_ATTR_TEMP_OFFSET(_string) \ + IIO_CONST_ATTR(temp_offset, _string) + +#define IIO_CONST_ATTR_TEMP_SCALE(_string) \ + IIO_CONST_ATTR(temp_scale, _string) + /** * IIO_EVENT_SH - generic shared event handler * @_name: event name @@ -323,15 +253,49 @@ struct iio_const_attr { #define IIO_EVENT_ATTR_DATA_RDY(_show, _store, _mask, _handler) \ IIO_EVENT_ATTR(data_rdy, _show, _store, _mask, _handler) -#define IIO_EVENT_CODE_DATA_RDY 100 -#define IIO_EVENT_CODE_RING_BASE 200 -#define IIO_EVENT_CODE_ACCEL_BASE 300 -#define IIO_EVENT_CODE_GYRO_BASE 400 -#define IIO_EVENT_CODE_ADC_BASE 500 -#define IIO_EVENT_CODE_MISC_BASE 600 -#define IIO_EVENT_CODE_LIGHT_BASE 700 - -#define IIO_EVENT_CODE_DEVICE_SPECIFIC 1000 +#define IIO_EV_CLASS_BUFFER 0 +#define IIO_EV_CLASS_IN 1 +#define IIO_EV_CLASS_ACCEL 2 +#define IIO_EV_CLASS_GYRO 3 +#define IIO_EV_CLASS_MAGN 4 +#define IIO_EV_CLASS_LIGHT 5 +#define IIO_EV_CLASS_PROXIMITY 6 + +#define IIO_EV_MOD_X 0 +#define IIO_EV_MOD_Y 1 +#define IIO_EV_MOD_Z 2 +#define IIO_EV_MOD_X_AND_Y 3 +#define IIO_EV_MOD_X_ANX_Z 4 +#define IIO_EV_MOD_Y_AND_Z 5 +#define IIO_EV_MOD_X_AND_Y_AND_Z 6 +#define IIO_EV_MOD_X_OR_Y 7 +#define IIO_EV_MOD_X_OR_Z 8 +#define IIO_EV_MOD_Y_OR_Z 9 +#define IIO_EV_MOD_X_OR_Y_OR_Z 10 + +#define IIO_EV_TYPE_THRESH 0 +#define IIO_EV_TYPE_MAG 1 +#define IIO_EV_TYPE_ROC 2 + +#define IIO_EV_DIR_EITHER 0 +#define IIO_EV_DIR_RISING 1 +#define IIO_EV_DIR_FALLING 2 + +#define IIO_EVENT_CODE(channelclass, orient_bit, number, \ + modifier, type, direction) \ + (channelclass | (orient_bit << 8) | ((number) << 9) | \ + ((modifier) << 13) | ((type) << 16) | ((direction) << 24)) + +#define IIO_MOD_EVENT_CODE(channelclass, number, modifier, \ + type, direction) \ + IIO_EVENT_CODE(channelclass, 1, number, modifier, type, direction) + +#define IIO_UNMOD_EVENT_CODE(channelclass, number, type, direction) \ + IIO_EVENT_CODE(channelclass, 0, number, 0, type, direction) + + +#define IIO_BUFFER_EVENT_CODE(code) \ + (IIO_EV_CLASS_BUFFER | (code << 8)) /** * IIO_EVENT_ATTR_RING_50_FULL - ring buffer event to indicate 50% full @@ -363,8 +327,8 @@ struct iio_const_attr { #define IIO_EVENT_ATTR_RING_75_FULL_SH(_evlist, _show, _store, _mask) \ IIO_EVENT_ATTR_SH(ring_75_full, _evlist, _show, _store, _mask) -#define IIO_EVENT_CODE_RING_50_FULL IIO_EVENT_CODE_RING_BASE -#define IIO_EVENT_CODE_RING_75_FULL (IIO_EVENT_CODE_RING_BASE + 1) -#define IIO_EVENT_CODE_RING_100_FULL (IIO_EVENT_CODE_RING_BASE + 2) +#define IIO_EVENT_CODE_RING_50_FULL IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_RING_75_FULL IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_RING_100_FULL IIO_BUFFER_EVENT_CODE(2) #endif /* _INDUSTRIAL_IO_SYSFS_H_ */ diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h index 4699586a5931..469beba3e71d 100644 --- a/drivers/staging/iio/trigger.h +++ b/drivers/staging/iio/trigger.h @@ -152,7 +152,7 @@ int iio_alloc_pollfunc(struct iio_dev *indio_dev, /* * Two functions for common case where all that happens is a pollfunc - * is attached and detached form a trigger + * is attached and detached from a trigger */ int iio_triggered_ring_postenable(struct iio_dev *indio_dev); int iio_triggered_ring_predisable(struct iio_dev *indio_dev); @@ -161,8 +161,4 @@ struct iio_trigger *iio_allocate_trigger(void); void iio_free_trigger(struct iio_trigger *trig); - -struct iio_simple_trigger { - struct iio_trigger trig; -}; #endif /* _IIO_TRIGGER_H_ */ diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c index f93cc9169832..2ce95e964cfd 100644 --- a/drivers/staging/iio/trigger/iio-trig-gpio.c +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -47,7 +47,7 @@ static irqreturn_t iio_gpio_trigger_poll(int irq, void *private) return IRQ_HANDLED; } -static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); +static IIO_TRIGGER_NAME_ATTR; static struct attribute *iio_gpio_trigger_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index b0b52f84edfd..24f174e1cda5 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -72,17 +72,7 @@ error_ret: return ret; } -static ssize_t iio_trig_periodic_read_name(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_trigger *trig = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", trig->name); -} - -static DEVICE_ATTR(name, S_IRUGO, - iio_trig_periodic_read_name, - NULL); +static IIO_TRIGGER_NAME_ATTR; static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_trig_periodic_read_freq, iio_trig_periodic_write_freq); |