lkml.org 
[lkml]   [2011]   [Oct]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4/6] IIO:Core add in kernel interface mapping and getting IIO channels.
    Date
    Two elements here:
    * Map as defined in include/linux/iio/inkern.h
    * Matching code to actually get the iio_dev and channel
    that we want from the global list of IIO devices.

    Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
    ---
    drivers/Makefile | 2 +-
    drivers/iio/Makefile | 1 +
    drivers/iio/iio.c | 112 ++++++++++++++++++++++++++++++++++++++++++++
    drivers/iio/inkern.c | 21 ++++++++
    include/linux/iio/iio.h | 7 ++-
    include/linux/iio/inkern.h | 63 +++++++++++++++++++++++++
    6 files changed, 204 insertions(+), 2 deletions(-)

    diff --git a/drivers/Makefile b/drivers/Makefile
    index df39628..2b389c5 100644
    --- a/drivers/Makefile
    +++ b/drivers/Makefile
    @@ -130,5 +130,5 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/

    obj-$(CONFIG_HYPERV) += hv/

    -obj-$(CONFIG_IIO) += iio/
    +obj-y += iio/

    diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
    index db3c426..cfb588a 100644
    --- a/drivers/iio/Makefile
    +++ b/drivers/iio/Makefile
    @@ -1,6 +1,7 @@
    #
    # Makefile for the Industrial I/O subsystem
    #
    +obj-y = inkern.o

    obj-$(CONFIG_IIO) += iio.o
    industrialio-y := core.o
    diff --git a/drivers/iio/iio.c b/drivers/iio/iio.c
    index 246a093..ae2daf0 100644
    --- a/drivers/iio/iio.c
    +++ b/drivers/iio/iio.c
    @@ -12,8 +12,10 @@
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/idr.h>
    +#include <linux/err.h>
    #include <linux/iio/iio.h>
    #include <linux/iio/sysfs.h>
    +#include <linux/iio/inkern.h>

    static DEFINE_MUTEX(iio_device_list_lock);
    static LIST_HEAD(iio_device_list);
    @@ -71,6 +73,116 @@ static const char * const iio_chan_info_postfix[] = {
    = "quadrature_correction_raw",
    };

    +struct iio_channel *iio_channel_get(const struct device *dev,
    + const char *name,
    + const char *channel_name)
    +{
    + struct iio_map *c_i = NULL, *c = NULL;
    + struct iio_dev *i_i = NULL, *indio_dev = NULL;
    + const struct iio_chan_spec *chan = NULL;
    +
    + int i;
    + struct iio_channel *channel;
    +
    + if (dev == NULL && name == NULL && channel_name == NULL)
    + return ERR_PTR(-ENODEV);
    + /* first find matching entry the channel map */
    + list_for_each_entry(c_i, &iio_map_list, l) {
    + if (dev && dev != c_i->consumer_dev)
    + continue;
    + if (name && strcmp(name, c_i->consumer_dev_name) != 0)
    + continue;
    +
    + if (channel_name && strcmp(channel_name, c_i->consumer_channel)
    + != 0)
    + continue;
    + c = c_i;
    + break;
    + }
    + if (c == NULL)
    + return ERR_PTR(-ENODEV);
    +
    + mutex_lock(&iio_device_list_lock);
    + /* now find the iio device if it has been registered */
    + if (c->adc_dev) {
    + list_for_each_entry(i_i, &iio_device_list,
    + dev_list_entry) {
    + if (i_i->info->get_hardware_id && c->adc_dev ==
    + indio_dev->info->get_hardware_id(indio_dev)) {
    + indio_dev = i_i;
    + break;
    + } else if (indio_dev->dev.parent &&
    + c->adc_dev == indio_dev->dev.parent) {
    + indio_dev = i_i;
    + break;
    + }
    + }
    + } else if (c->adc_dev_name) {
    + list_for_each_entry(i_i, &iio_device_list,
    + dev_list_entry) {
    + if (i_i->info->get_hardware_id) {
    + if (c->adc_dev_name ==
    + dev_name(i_i->info->get_hardware_id(i_i))) {
    + indio_dev = i_i;
    + break;
    + }
    + } else if (i_i->dev.parent) {
    + if (strcmp(c->adc_dev_name,
    + dev_name(i_i->dev.parent)) == 0) {
    + indio_dev = i_i;
    + break;
    + }
    + } else {
    + printk(KERN_ERR "invalid map\n");
    + mutex_unlock(&iio_device_list_lock);
    + return ERR_PTR(-ENODEV);
    + }
    + }
    + }
    + if (indio_dev)
    + get_device(&indio_dev->dev);
    + mutex_unlock(&iio_device_list_lock);
    + if (indio_dev == NULL)
    + return ERR_PTR(-ENODEV);
    +
    + /* finally verify the channel exists */
    + if (c->adc_channel_label)
    + for (i = 0; i < indio_dev->num_channels; i++)
    + if (indio_dev->channels[i].datasheet_name &&
    + strcmp(c->adc_channel_label,
    + indio_dev->channels[i].datasheet_name)
    + == 0) {
    + chan = &indio_dev->channels[i];
    + break;
    + }
    + channel = kmalloc(sizeof(*channel), GFP_KERNEL);
    + if (channel == NULL)
    + return ERR_PTR(-ENOMEM);
    + channel->indio_dev = indio_dev;
    + if (chan == NULL)
    + channel->channel = &indio_dev->channels[c->channel_number];
    + else
    + channel->channel = chan;
    + return channel;
    +}
    +EXPORT_SYMBOL_GPL(iio_channel_get);
    +
    +void iio_channel_release(struct iio_channel *channel)
    +{
    + put_device(&channel->indio_dev->dev);
    + kfree(channel);
    +}
    +EXPORT_SYMBOL_GPL(iio_channel_release);
    +
    +
    +int iio_read_channel_raw(struct iio_channel *chan, int *val)
    +{
    + int val2;
    + return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
    + val, &val2, 0);
    +}
    +EXPORT_SYMBOL_GPL(iio_read_channel_raw);
    +
    static void iio_device_free_read_attr(struct iio_dev *indio_dev,
    struct iio_dev_attr *p)
    {
    diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
    new file mode 100644
    index 0000000..e2ba5d6
    --- /dev/null
    +++ b/drivers/iio/inkern.c
    @@ -0,0 +1,21 @@
    +/* The industrial I/O core in kernel channel mapping
    + *
    + * Copyright (c) 2011 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.
    + */
    +#include <linux/iio/inkern.h>
    +#include <linux/err.h>
    +
    +LIST_HEAD(iio_map_list);
    +EXPORT_SYMBOL_GPL(iio_map_list);
    +void iio_map_array_register(struct iio_map *map, int nummaps)
    +{
    + int i;
    + for (i = 0; i < nummaps; i++)
    + list_add(&map[i].l, &iio_map_list);
    +}
    +EXPORT_SYMBOL(iio_map_array_register);
    +
    diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
    index f14e7dc..34c51b7 100644
    --- a/include/linux/iio/iio.h
    +++ b/include/linux/iio/iio.h
    @@ -153,7 +153,10 @@ struct iio_dev;
    * @write_raw_get_fmt: callback function to query the expected
    * format/precision. If not set by the driver, write_raw
    * returns IIO_VAL_INT_PLUS_MICRO.
    - **/
    + * @get_hardware_id: obtain device relating to hardware. Typically based on
    + * the parent device (actual hardware). Note that if
    + * not specified then iio_dev.dev->parent is used.
    + */
    struct iio_info {
    struct module *driver_module;
    const struct attribute_group *attrs;
    @@ -173,6 +176,7 @@ struct iio_info {
    int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
    struct iio_chan_spec const *chan,
    long mask);
    + struct device *(*get_hardware_id)(struct iio_dev *indio_dev);
    };

    /**
    @@ -208,6 +212,7 @@ struct iio_dev {
    #define IIO_MAX_GROUPS 1
    const struct attribute_group *groups[IIO_MAX_GROUPS + 1];
    int groupcounter;
    + struct list_head dev_list_entry;
    };

    /**
    diff --git a/include/linux/iio/inkern.h b/include/linux/iio/inkern.h
    new file mode 100644
    index 0000000..89b43d32
    --- /dev/null
    +++ b/include/linux/iio/inkern.h
    @@ -0,0 +1,63 @@
    +#include <linux/device.h>
    +#include <linux/list.h>
    +
    +struct iio_dev;
    +struct iio_chan_spec;
    +
    +struct iio_channel {
    + struct iio_dev *indio_dev;
    + const struct iio_chan_spec *channel;
    +};
    +
    +extern struct list_head iio_map_list;
    +
    +struct iio_map {
    + /* iio device side */
    + struct device *adc_dev;
    + const char *adc_dev_name;
    + const char *adc_channel_label;
    + int channel_number; /*naughty starting point */
    +
    + /* consumer side */
    + struct device *consumer_dev;
    + const char *consumer_dev_name;
    + const char *consumer_channel;
    +
    + /* management - probably neater ways of doing this */
    + struct list_head l;
    +};
    +
    +void iio_map_array_register(struct iio_map *map, int nummaps);
    +/**
    + * iio_channel_get() - get an opaque reference to a specified device.
    + */
    +struct iio_channel *iio_channel_get(const struct device *dev,
    + const char *name,
    + const char *consumer_channel);
    +void iio_channel_release(struct iio_channel *chan);
    +
    +/**
    + * iio_read_channel_raw() - read from a given channel
    + * @channel: the channel being queried.
    + * @val: value read back.
    + *
    + * Note raw reads from iio channels are in adc counts and hence
    + * scale will need to be applied if standard units required.
    + *
    + * Maybe want to pass the type as a sanity check.
    + */
    +int iio_read_channel_raw(struct iio_channel *chan,
    + int *val);
    +
    +/**
    + * iio_read_channel_scale() - read the scale value for a channel
    + * @channel: the channel being queried.
    + * @val: first part of value read back.
    + * @val2: second part of value read back.
    + *
    + * Note returns a description of what is in val and val2, such
    + * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
    + * + val2/1e6
    + */
    +int iio_read_channel_scale(struct iio_channel *chan, int *val,
    + int *val2);
    --
    1.7.7


    \
     
     \ /
      Last update: 2011-10-18 17:31    [W:0.034 / U:60.212 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site