linux/drivers/iio/adc/viperboard_adc.c
<<
>>
Prefs
   1/*
   2 *  Nano River Technologies viperboard IIO ADC driver
   3 *
   4 *  (C) 2012 by Lemonage GmbH
   5 *  Author: Lars Poeschel <poeschel@lemonage.de>
   6 *  All rights reserved.
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 *
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/errno.h>
  17#include <linux/module.h>
  18#include <linux/slab.h>
  19#include <linux/types.h>
  20#include <linux/mutex.h>
  21#include <linux/platform_device.h>
  22
  23#include <linux/usb.h>
  24#include <linux/iio/iio.h>
  25
  26#include <linux/mfd/viperboard.h>
  27
  28#define VPRBRD_ADC_CMD_GET              0x00
  29
  30struct vprbrd_adc_msg {
  31        u8 cmd;
  32        u8 chan;
  33        u8 val;
  34} __packed;
  35
  36struct vprbrd_adc {
  37        struct vprbrd *vb;
  38};
  39
  40#define VPRBRD_ADC_CHANNEL(_index) {                    \
  41        .type = IIO_VOLTAGE,                            \
  42        .indexed = 1,                                   \
  43        .channel = _index,                              \
  44        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
  45        .scan_index = _index,                           \
  46        .scan_type = {                                  \
  47                .sign = 'u',                            \
  48                .realbits = 8,                          \
  49                .storagebits = 8,                       \
  50        },                                              \
  51}
  52
  53static struct iio_chan_spec const vprbrd_adc_iio_channels[] = {
  54        VPRBRD_ADC_CHANNEL(0),
  55        VPRBRD_ADC_CHANNEL(1),
  56        VPRBRD_ADC_CHANNEL(2),
  57        VPRBRD_ADC_CHANNEL(3),
  58};
  59
  60static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,
  61                                struct iio_chan_spec const *chan,
  62                                int *val,
  63                                int *val2,
  64                                long info)
  65{
  66        int ret, error = 0;
  67        struct vprbrd_adc *adc = iio_priv(iio_dev);
  68        struct vprbrd *vb = adc->vb;
  69        struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf;
  70
  71        switch (info) {
  72        case IIO_CHAN_INFO_RAW:
  73                mutex_lock(&vb->lock);
  74
  75                admsg->cmd = VPRBRD_ADC_CMD_GET;
  76                admsg->chan = chan->scan_index;
  77                admsg->val = 0x00;
  78
  79                ret = usb_control_msg(vb->usb_dev,
  80                        usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
  81                        VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,
  82                        sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
  83                if (ret != sizeof(struct vprbrd_adc_msg)) {
  84                        dev_err(&iio_dev->dev, "usb send error on adc read\n");
  85                        error = -EREMOTEIO;
  86                }
  87
  88                ret = usb_control_msg(vb->usb_dev,
  89                        usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
  90                        VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg,
  91                        sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
  92
  93                *val = admsg->val;
  94
  95                mutex_unlock(&vb->lock);
  96
  97                if (ret != sizeof(struct vprbrd_adc_msg)) {
  98                        dev_err(&iio_dev->dev, "usb recv error on adc read\n");
  99                        error = -EREMOTEIO;
 100                }
 101
 102                if (error)
 103                        goto error;
 104
 105                return IIO_VAL_INT;
 106        default:
 107                error = -EINVAL;
 108                break;
 109        }
 110error:
 111        return error;
 112}
 113
 114static const struct iio_info vprbrd_adc_iio_info = {
 115        .read_raw = &vprbrd_iio_read_raw,
 116        .driver_module = THIS_MODULE,
 117};
 118
 119static int vprbrd_adc_probe(struct platform_device *pdev)
 120{
 121        struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
 122        struct vprbrd_adc *adc;
 123        struct iio_dev *indio_dev;
 124        int ret;
 125
 126        /* registering iio */
 127        indio_dev = iio_device_alloc(sizeof(*adc));
 128        if (!indio_dev) {
 129                dev_err(&pdev->dev, "failed allocating iio device\n");
 130                return -ENOMEM;
 131        }
 132
 133        adc = iio_priv(indio_dev);
 134        adc->vb = vb;
 135        indio_dev->name = "viperboard adc";
 136        indio_dev->dev.parent = &pdev->dev;
 137        indio_dev->info = &vprbrd_adc_iio_info;
 138        indio_dev->modes = INDIO_DIRECT_MODE;
 139        indio_dev->channels = vprbrd_adc_iio_channels;
 140        indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels);
 141
 142        ret = iio_device_register(indio_dev);
 143        if (ret) {
 144                dev_err(&pdev->dev, "could not register iio (adc)");
 145                goto error;
 146        }
 147
 148        platform_set_drvdata(pdev, indio_dev);
 149
 150        return 0;
 151
 152error:
 153        iio_device_free(indio_dev);
 154        return ret;
 155}
 156
 157static int vprbrd_adc_remove(struct platform_device *pdev)
 158{
 159        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 160
 161        iio_device_unregister(indio_dev);
 162        iio_device_free(indio_dev);
 163
 164        return 0;
 165}
 166
 167static struct platform_driver vprbrd_adc_driver = {
 168        .driver = {
 169                .name   = "viperboard-adc",
 170                .owner  = THIS_MODULE,
 171        },
 172        .probe          = vprbrd_adc_probe,
 173        .remove         = vprbrd_adc_remove,
 174};
 175
 176module_platform_driver(vprbrd_adc_driver);
 177
 178MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
 179MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard");
 180MODULE_LICENSE("GPL");
 181MODULE_ALIAS("platform:viperboard-adc");
 182