151 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Nano River Technologies viperboard IIO ADC driver4 *5 * (C) 2012 by Lemonage GmbH6 * Author: Lars Poeschel <poeschel@lemonage.de>7 * All rights reserved.8 */9 10#include <linux/kernel.h>11#include <linux/errno.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/types.h>15#include <linux/mutex.h>16#include <linux/platform_device.h>17 18#include <linux/usb.h>19#include <linux/iio/iio.h>20 21#include <linux/mfd/viperboard.h>22 23#define VPRBRD_ADC_CMD_GET 0x0024 25struct vprbrd_adc_msg {26 u8 cmd;27 u8 chan;28 u8 val;29} __packed;30 31struct vprbrd_adc {32 struct vprbrd *vb;33};34 35#define VPRBRD_ADC_CHANNEL(_index) { \36 .type = IIO_VOLTAGE, \37 .indexed = 1, \38 .channel = _index, \39 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \40}41 42static struct iio_chan_spec const vprbrd_adc_iio_channels[] = {43 VPRBRD_ADC_CHANNEL(0),44 VPRBRD_ADC_CHANNEL(1),45 VPRBRD_ADC_CHANNEL(2),46 VPRBRD_ADC_CHANNEL(3),47};48 49static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,50 struct iio_chan_spec const *chan,51 int *val,52 int *val2,53 long info)54{55 int ret, error = 0;56 struct vprbrd_adc *adc = iio_priv(iio_dev);57 struct vprbrd *vb = adc->vb;58 struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf;59 60 switch (info) {61 case IIO_CHAN_INFO_RAW:62 mutex_lock(&vb->lock);63 64 admsg->cmd = VPRBRD_ADC_CMD_GET;65 admsg->chan = chan->channel;66 admsg->val = 0x00;67 68 ret = usb_control_msg(vb->usb_dev,69 usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,70 VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,71 sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);72 if (ret != sizeof(struct vprbrd_adc_msg)) {73 dev_err(&iio_dev->dev, "usb send error on adc read\n");74 error = -EREMOTEIO;75 }76 77 ret = usb_control_msg(vb->usb_dev,78 usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,79 VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg,80 sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);81 82 *val = admsg->val;83 84 mutex_unlock(&vb->lock);85 86 if (ret != sizeof(struct vprbrd_adc_msg)) {87 dev_err(&iio_dev->dev, "usb recv error on adc read\n");88 error = -EREMOTEIO;89 }90 91 if (error)92 goto error;93 94 return IIO_VAL_INT;95 default:96 error = -EINVAL;97 break;98 }99error:100 return error;101}102 103static const struct iio_info vprbrd_adc_iio_info = {104 .read_raw = &vprbrd_iio_read_raw,105};106 107static int vprbrd_adc_probe(struct platform_device *pdev)108{109 struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);110 struct vprbrd_adc *adc;111 struct iio_dev *indio_dev;112 int ret;113 114 /* registering iio */115 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));116 if (!indio_dev) {117 dev_err(&pdev->dev, "failed allocating iio device\n");118 return -ENOMEM;119 }120 121 adc = iio_priv(indio_dev);122 adc->vb = vb;123 indio_dev->name = "viperboard adc";124 indio_dev->info = &vprbrd_adc_iio_info;125 indio_dev->modes = INDIO_DIRECT_MODE;126 indio_dev->channels = vprbrd_adc_iio_channels;127 indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels);128 129 ret = devm_iio_device_register(&pdev->dev, indio_dev);130 if (ret) {131 dev_err(&pdev->dev, "could not register iio (adc)");132 return ret;133 }134 135 return 0;136}137 138static struct platform_driver vprbrd_adc_driver = {139 .driver = {140 .name = "viperboard-adc",141 },142 .probe = vprbrd_adc_probe,143};144 145module_platform_driver(vprbrd_adc_driver);146 147MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");148MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard");149MODULE_LICENSE("GPL");150MODULE_ALIAS("platform:viperboard-adc");151