Browse Source

add adc module

encrypt 8 years ago
parent
commit
c47062607e
2 changed files with 180 additions and 0 deletions
  1. 16 0
      adc/Makefile
  2. 164 0
      adc/usbio-adc.c

+ 16 - 0
adc/Makefile

@@ -0,0 +1,16 @@
+obj-m := usbio-adc.o
+KDIR  := /lib/modules/$(shell uname -r)/build
+PWD   := $(shell pwd)
+DEPMOD:=$(shell which depmod)
+# possible bug: maybe this will work only on debian based systems
+SYSMAP:= /boot/System.map-$(shell uname -r)
+
+default:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+install:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
+	$(DEPMOD) -ae -F $(SYSMAP)
+
+clean:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

+ 164 - 0
adc/usbio-adc.c

@@ -0,0 +1,164 @@
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/machine.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#define USBIO_VENDOR_ID  0x04d8
+#define USBIO_PRODUCT_ID 0x003f
+
+struct usbio_adc {
+  struct usb_device *udev;
+  int value;
+};
+
+static const struct iio_chan_spec const usbio_adc_channels[] = {
+  {
+    .indexed = 1,
+    .type = IIO_VOLTAGE,
+    .channel = 0,
+    .datasheet_name = "DM0",
+    .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+  }, {
+    .indexed = 1,
+    .type = IIO_VOLTAGE,
+    .channel = 1,
+    .datasheet_name = "DM1",
+    .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+  }
+};
+
+static int usbio_adc_read(struct usb_device *usb_dev, int channel, int *val)
+{
+  u8 data[64];
+  int ret, actual_len;
+  actual_len = 1;
+  data[0] = 0x37+channel;
+  *val = 0;
+  printk(KERN_INFO "reading from %x", data[0]);
+  ret = usb_interrupt_msg(usb_dev,
+			  usb_sndintpipe(usb_dev, 1),
+			  data, sizeof(data), &actual_len, USB_CTRL_SET_TIMEOUT);
+  if(ret < 0)
+    return -EIO;
+  actual_len = 64;
+  memset(data, 0, 64);
+  ret = usb_bulk_msg(usb_dev,
+		     usb_rcvbulkpipe(usb_dev, 0x81),
+		     data, sizeof(data), &actual_len, USB_CTRL_SET_TIMEOUT);
+  if(ret < 0)
+    return -EIO;
+  printk(KERN_INFO "back from %x",data[0]);
+  *val = (data[2] << 8) | data[1];
+  return IIO_VAL_INT;  
+}
+
+static int usbio_adc_read_raw(struct iio_dev *usbio_adc_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+  int ret;
+  struct usbio_adc *adc = iio_priv(usbio_adc_dev);
+
+  mutex_lock(&usbio_adc_dev->mlock);
+  switch(mask) {
+  case IIO_CHAN_INFO_RAW:
+    ret = usbio_adc_read(adc->udev, chan->channel, val);
+    break;
+  default:
+    ret = -EINVAL;
+  }
+  mutex_unlock(&usbio_adc_dev->mlock);
+  return ret;
+}
+
+static const struct iio_info usbio_adc_iio_info = {
+  .read_raw = &usbio_adc_read_raw,
+  .driver_module = THIS_MODULE
+};
+  
+static struct iio_map usbio_adc_default_maps[] = {
+  {						
+    .adc_channel_label = "DM0",
+    .consumer_dev_name = "usbio-adc",
+    .consumer_channel  = "usbio-adc0",
+  },
+  {						
+    .adc_channel_label = "DM1",
+    .consumer_dev_name = "usbio-adc",
+    .consumer_channel  = "usbio-adc1",
+  }
+};
+
+static int usbio_adc_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+  struct usb_device *udev = interface_to_usbdev(interface);
+  struct iio_dev *usbio_adc_dev;
+  struct usbio_adc *adc = NULL;
+  int ret;
+
+  usbio_adc_dev = devm_iio_device_alloc(&udev->dev, sizeof(*adc));
+  if(!usbio_adc_dev)
+    return -ENOMEM;
+
+  adc = iio_priv(usbio_adc_dev);
+  adc->udev = udev;
+  adc->value = 0;
+  usb_set_intfdata(interface, usbio_adc_dev);
+  usbio_adc_dev->dev.parent = &udev->dev;
+  usbio_adc_dev->name = "usbio-adc";
+  usbio_adc_dev->channels = usbio_adc_channels;
+  usbio_adc_dev->num_channels = ARRAY_SIZE(usbio_adc_channels);
+  usbio_adc_dev->info = &usbio_adc_iio_info;
+  usbio_adc_dev->modes = INDIO_DIRECT_MODE;
+  
+  ret = iio_map_array_register(usbio_adc_dev, usbio_adc_default_maps);
+
+  if(ret < 0) {
+    dev_err(&udev->dev, "something went wrong");
+    return ret;
+  }
+  ret = iio_device_register(usbio_adc_dev);
+  if(ret < 0) {
+    dev_err(&udev->dev, "unable to register iiodevice \n");
+    goto err_array_unregister;
+  }
+  return 0;
+
+ err_array_unregister:
+  iio_map_array_unregister(usbio_adc_dev);
+  return ret;
+}
+
+static void usbio_adc_disconnect(struct usb_interface *interface)
+{
+  struct iio_dev *usbio_adc_dev = usb_get_intfdata(interface);
+  struct usbio_adc *adc = iio_priv(usbio_adc_dev);
+  //usb_set_intfdata(interface, NULL);
+  usb_put_dev(adc->udev);
+  // kfree(adc);
+  iio_device_unregister(usbio_adc_dev);
+  iio_map_array_unregister(usbio_adc_dev);
+}
+
+static struct usb_device_id usbio_id_table[] = {
+  { USB_DEVICE(USBIO_VENDOR_ID, USBIO_PRODUCT_ID) },
+  {}
+};
+
+MODULE_DEVICE_TABLE(usb, usbio_id_table);
+
+static struct usb_driver usbio_adc_driver = {
+  .name = "usbio_adc",
+  .probe = usbio_adc_probe,
+  .disconnect = usbio_adc_disconnect,
+  .id_table = usbio_id_table
+};
+
+module_usb_driver(usbio_adc_driver);
+
+MODULE_DESCRIPTION("USBIO ADC");
+MODULE_AUTHOR("encrypt <encrypt@labr.xyz>");
+MODULE_LICENSE("GPL");