Re: [PATCH v2 4/4] iio: adc: add viperboard adc driver
On Monday 15 October 2012 at 16:26:36, Lars-Peter Clausen wrote: > Added linux-...@vger.kernel.org to Cc. > > On 10/12/2012 04:34 PM, Lars Poeschel wrote: > > From: Lars Poeschel > > > > This adds the mfd cell to use the adc part of the Nano River Technologies > > viperboard. > > > > Signed-off-by: Lars Poeschel > > Looks good in general, just some minor code style issues. > > > --- > > > > drivers/iio/adc/Kconfig |7 ++ > > drivers/iio/adc/Makefile |1 + > > drivers/iio/adc/viperboard_adc.c | 185 > > ++ drivers/mfd/viperboard.c > > |3 + > > 4 files changed, 196 insertions(+) > > create mode 100644 drivers/iio/adc/viperboard_adc.c > > [...] > > > diff --git a/drivers/iio/adc/viperboard_adc.c > > b/drivers/iio/adc/viperboard_adc.c new file mode 100644 > > index 000..8ae6634 > > --- /dev/null > > +++ b/drivers/iio/adc/viperboard_adc.c > > @@ -0,0 +1,185 @@ > > +/* > > + * Nano River Technologies viperboard iio ADC driver > > + * > > + * (C) 2012 by Lemonage GmbH > > + * Author: Lars Poeschel > > + * All rights reserved. > > + * > > + * 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. > > + * > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > + > > +#include > > + > > +#define VPRBRD_ADC_CMD_GET 0x00 > > + > > +struct __packed vprbrd_adc_msg { > > + u8 cmd; > > + u8 chan; > > + u8 val; > > +}; > > put the __packed between } and ; GCC allows both alternatives, but you are right: Most kernel code is doing it between } and ; so I will change this. > > + > > +struct vprbrd_adc { > > + struct vprbrd *vb; > > +}; > > + > > +#define VPRBRD_ADC_CHANNEL(_index) { \ > > + .type = IIO_VOLTAGE,\ > > + .indexed = 1, \ > > + .channel = _index, \ > > + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ > > It would be good if you could also report the channel scale. I saw that there is the possibility to supply a channel scale, which is way cool. :-) The doc of the viperboard says nothing about the scale of the ADC. At the moment I do not have the right measuring equipment here to measure a scale myself. I would do another tiny patch if I have the oppotunity to measure somewhere. > > + .scan_index = _index, \ > > + .scan_type.sign = 'u', \ > > + .scan_type.realbits = 8,\ > > + .scan_type.storagebits = 8, \ > > Usually this is written as > .scan_type = { > .sign = 'u', > > }, > > > +} > > + > > +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { > > const > > > + VPRBRD_ADC_CHANNEL(0), > > + VPRBRD_ADC_CHANNEL(1), > > + VPRBRD_ADC_CHANNEL(2), > > + VPRBRD_ADC_CHANNEL(3), > > +}; > > + > > +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, > > + struct iio_chan_spec const *chan, > > + int *val, > > + int *val2, > > + long mask) > > 'mask' used to be a mask and that's why it is still called 'mask' in older > drivers. For new drivers we should use 'info'. > > > +{ > > + int ret, error = 0; > > + struct vprbrd_adc *adc = iio_priv(iio_dev); > > + struct vprbrd *vb = adc->vb; > > + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf; > > + > > + if (mask == IIO_CHAN_INFO_RAW) { > > + > > Use switch instead of if. Otherwise you'd end up with if(mask == ...) else > if(mask == ...) else if (mask == ...) if you add support for more channel > attributes. > > > + mutex_lock(>lock); > > + > > + admsg->cmd = VPRBRD_ADC_CMD_GET; > > + admsg->chan = chan->scan_index; > > + admsg->val = 0x00; > > + > > + ret = usb_control_msg(vb->usb_dev, > > + usb_sndctrlpipe(vb->usb_dev, 0), 0xec, 0x40, > > + 0x, 0x, admsg, > > + sizeof(struct vprbrd_adc_msg), 100); > > + if (ret != sizeof(struct vprbrd_adc_msg)) { > > + dev_err(_dev->dev, "usb send error on adc read\n"); > > + error = -EREMOTEIO; > > + } > > Does it make sense to send out the second msg if the first one failed? This is a good question. I can not fully answer it, because I did not build the hardware. I thought it is better to try send the second message, because there is some chance it reaches the device. I would opt for trying it. > > + > > +
Re: [PATCH v2 4/4] iio: adc: add viperboard adc driver
On Monday 15 October 2012 at 16:26:36, Lars-Peter Clausen wrote: Added linux-...@vger.kernel.org to Cc. On 10/12/2012 04:34 PM, Lars Poeschel wrote: From: Lars Poeschel poesc...@lemonage.de This adds the mfd cell to use the adc part of the Nano River Technologies viperboard. Signed-off-by: Lars Poeschel poesc...@lemonage.de Looks good in general, just some minor code style issues. --- drivers/iio/adc/Kconfig |7 ++ drivers/iio/adc/Makefile |1 + drivers/iio/adc/viperboard_adc.c | 185 ++ drivers/mfd/viperboard.c |3 + 4 files changed, 196 insertions(+) create mode 100644 drivers/iio/adc/viperboard_adc.c [...] diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 000..8ae6634 --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c @@ -0,0 +1,185 @@ +/* + * Nano River Technologies viperboard iio ADC driver + * + * (C) 2012 by Lemonage GmbH + * Author: Lars Poeschel poesc...@lemonage.de + * All rights reserved. + * + * 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. + * + */ + +#include linux/kernel.h +#include linux/errno.h +#include linux/module.h +#include linux/slab.h +#include linux/types.h +#include linux/mutex.h +#include linux/platform_device.h + +#include linux/usb.h +#include linux/iio/iio.h + +#include linux/mfd/viperboard.h + +#define VPRBRD_ADC_CMD_GET 0x00 + +struct __packed vprbrd_adc_msg { + u8 cmd; + u8 chan; + u8 val; +}; put the __packed between } and ; GCC allows both alternatives, but you are right: Most kernel code is doing it between } and ; so I will change this. + +struct vprbrd_adc { + struct vprbrd *vb; +}; + +#define VPRBRD_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE,\ + .indexed = 1, \ + .channel = _index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ It would be good if you could also report the channel scale. I saw that there is the possibility to supply a channel scale, which is way cool. :-) The doc of the viperboard says nothing about the scale of the ADC. At the moment I do not have the right measuring equipment here to measure a scale myself. I would do another tiny patch if I have the oppotunity to measure somewhere. + .scan_index = _index, \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 8,\ + .scan_type.storagebits = 8, \ Usually this is written as .scan_type = { .sign = 'u', }, +} + +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { const + VPRBRD_ADC_CHANNEL(0), + VPRBRD_ADC_CHANNEL(1), + VPRBRD_ADC_CHANNEL(2), + VPRBRD_ADC_CHANNEL(3), +}; + +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) 'mask' used to be a mask and that's why it is still called 'mask' in older drivers. For new drivers we should use 'info'. +{ + int ret, error = 0; + struct vprbrd_adc *adc = iio_priv(iio_dev); + struct vprbrd *vb = adc-vb; + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb-buf; + + if (mask == IIO_CHAN_INFO_RAW) { + Use switch instead of if. Otherwise you'd end up with if(mask == ...) else if(mask == ...) else if (mask == ...) if you add support for more channel attributes. + mutex_lock(vb-lock); + + admsg-cmd = VPRBRD_ADC_CMD_GET; + admsg-chan = chan-scan_index; + admsg-val = 0x00; + + ret = usb_control_msg(vb-usb_dev, + usb_sndctrlpipe(vb-usb_dev, 0), 0xec, 0x40, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(iio_dev-dev, usb send error on adc read\n); + error = -EREMOTEIO; + } Does it make sense to send out the second msg if the first one failed? This is a good question. I can not fully answer it, because I did not build the hardware. I thought it is better to try send the second message, because there is some chance it reaches the device. I would opt for trying it. + + ret = usb_control_msg(vb-usb_dev, +
Re: [PATCH v2 4/4] iio: adc: add viperboard adc driver
Added linux-...@vger.kernel.org to Cc. On 10/12/2012 04:34 PM, Lars Poeschel wrote: > From: Lars Poeschel > > This adds the mfd cell to use the adc part of the Nano River Technologies > viperboard. > > Signed-off-by: Lars Poeschel Looks good in general, just some minor code style issues. > --- > drivers/iio/adc/Kconfig |7 ++ > drivers/iio/adc/Makefile |1 + > drivers/iio/adc/viperboard_adc.c | 185 > ++ > drivers/mfd/viperboard.c |3 + > 4 files changed, 196 insertions(+) > create mode 100644 drivers/iio/adc/viperboard_adc.c > [...] > diff --git a/drivers/iio/adc/viperboard_adc.c > b/drivers/iio/adc/viperboard_adc.c > new file mode 100644 > index 000..8ae6634 > --- /dev/null > +++ b/drivers/iio/adc/viperboard_adc.c > @@ -0,0 +1,185 @@ > +/* > + * Nano River Technologies viperboard iio ADC driver > + * > + * (C) 2012 by Lemonage GmbH > + * Author: Lars Poeschel > + * All rights reserved. > + * > + * 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. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include > + > +#define VPRBRD_ADC_CMD_GET 0x00 > + > +struct __packed vprbrd_adc_msg { > + u8 cmd; > + u8 chan; > + u8 val; > +}; put the __packed between } and ; > + > +struct vprbrd_adc { > + struct vprbrd *vb; > +}; > + > +#define VPRBRD_ADC_CHANNEL(_index) { \ > + .type = IIO_VOLTAGE,\ > + .indexed = 1, \ > + .channel = _index, \ > + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ It would be good if you could also report the channel scale. > + .scan_index = _index, \ > + .scan_type.sign = 'u', \ > + .scan_type.realbits = 8,\ > + .scan_type.storagebits = 8, \ Usually this is written as .scan_type = { .sign = 'u', }, > +} > + > +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { const > + VPRBRD_ADC_CHANNEL(0), > + VPRBRD_ADC_CHANNEL(1), > + VPRBRD_ADC_CHANNEL(2), > + VPRBRD_ADC_CHANNEL(3), > +}; > + > +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, > + struct iio_chan_spec const *chan, > + int *val, > + int *val2, > + long mask) 'mask' used to be a mask and that's why it is still called 'mask' in older drivers. For new drivers we should use 'info'. > +{ > + int ret, error = 0; > + struct vprbrd_adc *adc = iio_priv(iio_dev); > + struct vprbrd *vb = adc->vb; > + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf; > + > + if (mask == IIO_CHAN_INFO_RAW) { > + Use switch instead of if. Otherwise you'd end up with if(mask == ...) else if(mask == ...) else if (mask == ...) if you add support for more channel attributes. > + mutex_lock(>lock); > + > + admsg->cmd = VPRBRD_ADC_CMD_GET; > + admsg->chan = chan->scan_index; > + admsg->val = 0x00; > + > + ret = usb_control_msg(vb->usb_dev, > + usb_sndctrlpipe(vb->usb_dev, 0), 0xec, 0x40, > + 0x, 0x, admsg, > + sizeof(struct vprbrd_adc_msg), 100); > + if (ret != sizeof(struct vprbrd_adc_msg)) { > + dev_err(_dev->dev, "usb send error on adc read\n"); > + error = -EREMOTEIO; > + } Does it make sense to send out the second msg if the first one failed? > + > + ret = usb_control_msg(vb->usb_dev, > + usb_rcvctrlpipe(vb->usb_dev, 0), 0xec, 0xc0, > + 0x, 0x, admsg, > + sizeof(struct vprbrd_adc_msg), 100); > + It would be good to have some defines for the magic constants used for request and request_type. > + *val = admsg->val; > + > + mutex_unlock(>lock); > + > + if (ret != sizeof(struct vprbrd_adc_msg)) { > + dev_err(_dev->dev, "usb recv error on adc read\n"); > + error = -EREMOTEIO; > + } > + > + if (error) > + goto error; > + > + return IIO_VAL_INT; > + } > + error = -EINVAL; > +error: > + return error; > +} > + > +static const struct iio_info vprbrd_adc_iio_info = { > + .read_raw = _iio_read_raw, > + .driver_module = THIS_MODULE, > +}; > + > +static int
Re: [PATCH v2 4/4] iio: adc: add viperboard adc driver
Added linux-...@vger.kernel.org to Cc. On 10/12/2012 04:34 PM, Lars Poeschel wrote: From: Lars Poeschel poesc...@lemonage.de This adds the mfd cell to use the adc part of the Nano River Technologies viperboard. Signed-off-by: Lars Poeschel poesc...@lemonage.de Looks good in general, just some minor code style issues. --- drivers/iio/adc/Kconfig |7 ++ drivers/iio/adc/Makefile |1 + drivers/iio/adc/viperboard_adc.c | 185 ++ drivers/mfd/viperboard.c |3 + 4 files changed, 196 insertions(+) create mode 100644 drivers/iio/adc/viperboard_adc.c [...] diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 000..8ae6634 --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c @@ -0,0 +1,185 @@ +/* + * Nano River Technologies viperboard iio ADC driver + * + * (C) 2012 by Lemonage GmbH + * Author: Lars Poeschel poesc...@lemonage.de + * All rights reserved. + * + * 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. + * + */ + +#include linux/kernel.h +#include linux/errno.h +#include linux/module.h +#include linux/slab.h +#include linux/types.h +#include linux/mutex.h +#include linux/platform_device.h + +#include linux/usb.h +#include linux/iio/iio.h + +#include linux/mfd/viperboard.h + +#define VPRBRD_ADC_CMD_GET 0x00 + +struct __packed vprbrd_adc_msg { + u8 cmd; + u8 chan; + u8 val; +}; put the __packed between } and ; + +struct vprbrd_adc { + struct vprbrd *vb; +}; + +#define VPRBRD_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE,\ + .indexed = 1, \ + .channel = _index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ It would be good if you could also report the channel scale. + .scan_index = _index, \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 8,\ + .scan_type.storagebits = 8, \ Usually this is written as .scan_type = { .sign = 'u', }, +} + +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { const + VPRBRD_ADC_CHANNEL(0), + VPRBRD_ADC_CHANNEL(1), + VPRBRD_ADC_CHANNEL(2), + VPRBRD_ADC_CHANNEL(3), +}; + +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) 'mask' used to be a mask and that's why it is still called 'mask' in older drivers. For new drivers we should use 'info'. +{ + int ret, error = 0; + struct vprbrd_adc *adc = iio_priv(iio_dev); + struct vprbrd *vb = adc-vb; + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb-buf; + + if (mask == IIO_CHAN_INFO_RAW) { + Use switch instead of if. Otherwise you'd end up with if(mask == ...) else if(mask == ...) else if (mask == ...) if you add support for more channel attributes. + mutex_lock(vb-lock); + + admsg-cmd = VPRBRD_ADC_CMD_GET; + admsg-chan = chan-scan_index; + admsg-val = 0x00; + + ret = usb_control_msg(vb-usb_dev, + usb_sndctrlpipe(vb-usb_dev, 0), 0xec, 0x40, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(iio_dev-dev, usb send error on adc read\n); + error = -EREMOTEIO; + } Does it make sense to send out the second msg if the first one failed? + + ret = usb_control_msg(vb-usb_dev, + usb_rcvctrlpipe(vb-usb_dev, 0), 0xec, 0xc0, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + It would be good to have some defines for the magic constants used for request and request_type. + *val = admsg-val; + + mutex_unlock(vb-lock); + + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(iio_dev-dev, usb recv error on adc read\n); + error = -EREMOTEIO; + } + + if (error) + goto error; + + return IIO_VAL_INT; + } + error = -EINVAL; +error: + return error; +} + +static const struct iio_info vprbrd_adc_iio_info = { + .read_raw =
[PATCH v2 4/4] iio: adc: add viperboard adc driver
From: Lars Poeschel This adds the mfd cell to use the adc part of the Nano River Technologies viperboard. Signed-off-by: Lars Poeschel --- drivers/iio/adc/Kconfig |7 ++ drivers/iio/adc/Makefile |1 + drivers/iio/adc/viperboard_adc.c | 185 ++ drivers/mfd/viperboard.c |3 + 4 files changed, 196 insertions(+) create mode 100644 drivers/iio/adc/viperboard_adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 4927581..35ad77d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -60,4 +60,11 @@ config LP8788_ADC help Say yes here to build support for TI LP8788 ADC. +config VIPERBOARD_ADC + tristate "Viperboard ADC support" + depends on MFD_VIPERBOARD && USB + help + Say yes here to access the ADC part of the Nano River + Technologies Viperboard. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 900995d..4852c2e 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o +obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 000..8ae6634 --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c @@ -0,0 +1,185 @@ +/* + * Nano River Technologies viperboard iio ADC driver + * + * (C) 2012 by Lemonage GmbH + * Author: Lars Poeschel + * All rights reserved. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define VPRBRD_ADC_CMD_GET 0x00 + +struct __packed vprbrd_adc_msg { + u8 cmd; + u8 chan; + u8 val; +}; + +struct vprbrd_adc { + struct vprbrd *vb; +}; + +#define VPRBRD_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE,\ + .indexed = 1, \ + .channel = _index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ + .scan_index = _index, \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 8,\ + .scan_type.storagebits = 8, \ +} + +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { + VPRBRD_ADC_CHANNEL(0), + VPRBRD_ADC_CHANNEL(1), + VPRBRD_ADC_CHANNEL(2), + VPRBRD_ADC_CHANNEL(3), +}; + +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret, error = 0; + struct vprbrd_adc *adc = iio_priv(iio_dev); + struct vprbrd *vb = adc->vb; + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf; + + if (mask == IIO_CHAN_INFO_RAW) { + + mutex_lock(>lock); + + admsg->cmd = VPRBRD_ADC_CMD_GET; + admsg->chan = chan->scan_index; + admsg->val = 0x00; + + ret = usb_control_msg(vb->usb_dev, + usb_sndctrlpipe(vb->usb_dev, 0), 0xec, 0x40, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(_dev->dev, "usb send error on adc read\n"); + error = -EREMOTEIO; + } + + ret = usb_control_msg(vb->usb_dev, + usb_rcvctrlpipe(vb->usb_dev, 0), 0xec, 0xc0, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + + *val = admsg->val; + + mutex_unlock(>lock); + + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(_dev->dev, "usb recv error on adc read\n"); + error = -EREMOTEIO; + } + + if (error) + goto error; + + return IIO_VAL_INT; + } + error = -EINVAL; +error: + return error; +} + +static const struct iio_info vprbrd_adc_iio_info = { + .read_raw = _iio_read_raw, + .driver_module = THIS_MODULE, +}; + +static int __devinit vprbrd_adc_probe(struct platform_device *pdev) +{ + struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); +
[PATCH v2 4/4] iio: adc: add viperboard adc driver
From: Lars Poeschel poesc...@lemonage.de This adds the mfd cell to use the adc part of the Nano River Technologies viperboard. Signed-off-by: Lars Poeschel poesc...@lemonage.de --- drivers/iio/adc/Kconfig |7 ++ drivers/iio/adc/Makefile |1 + drivers/iio/adc/viperboard_adc.c | 185 ++ drivers/mfd/viperboard.c |3 + 4 files changed, 196 insertions(+) create mode 100644 drivers/iio/adc/viperboard_adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 4927581..35ad77d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -60,4 +60,11 @@ config LP8788_ADC help Say yes here to build support for TI LP8788 ADC. +config VIPERBOARD_ADC + tristate Viperboard ADC support + depends on MFD_VIPERBOARD USB + help + Say yes here to access the ADC part of the Nano River + Technologies Viperboard. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 900995d..4852c2e 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o +obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 000..8ae6634 --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c @@ -0,0 +1,185 @@ +/* + * Nano River Technologies viperboard iio ADC driver + * + * (C) 2012 by Lemonage GmbH + * Author: Lars Poeschel poesc...@lemonage.de + * All rights reserved. + * + * 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. + * + */ + +#include linux/kernel.h +#include linux/errno.h +#include linux/module.h +#include linux/slab.h +#include linux/types.h +#include linux/mutex.h +#include linux/platform_device.h + +#include linux/usb.h +#include linux/iio/iio.h + +#include linux/mfd/viperboard.h + +#define VPRBRD_ADC_CMD_GET 0x00 + +struct __packed vprbrd_adc_msg { + u8 cmd; + u8 chan; + u8 val; +}; + +struct vprbrd_adc { + struct vprbrd *vb; +}; + +#define VPRBRD_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE,\ + .indexed = 1, \ + .channel = _index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,\ + .scan_index = _index, \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 8,\ + .scan_type.storagebits = 8, \ +} + +static struct iio_chan_spec vprbrd_adc_iio_channels[] = { + VPRBRD_ADC_CHANNEL(0), + VPRBRD_ADC_CHANNEL(1), + VPRBRD_ADC_CHANNEL(2), + VPRBRD_ADC_CHANNEL(3), +}; + +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret, error = 0; + struct vprbrd_adc *adc = iio_priv(iio_dev); + struct vprbrd *vb = adc-vb; + struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb-buf; + + if (mask == IIO_CHAN_INFO_RAW) { + + mutex_lock(vb-lock); + + admsg-cmd = VPRBRD_ADC_CMD_GET; + admsg-chan = chan-scan_index; + admsg-val = 0x00; + + ret = usb_control_msg(vb-usb_dev, + usb_sndctrlpipe(vb-usb_dev, 0), 0xec, 0x40, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(iio_dev-dev, usb send error on adc read\n); + error = -EREMOTEIO; + } + + ret = usb_control_msg(vb-usb_dev, + usb_rcvctrlpipe(vb-usb_dev, 0), 0xec, 0xc0, + 0x, 0x, admsg, + sizeof(struct vprbrd_adc_msg), 100); + + *val = admsg-val; + + mutex_unlock(vb-lock); + + if (ret != sizeof(struct vprbrd_adc_msg)) { + dev_err(iio_dev-dev, usb recv error on adc read\n); + error = -EREMOTEIO; + } + + if (error) + goto error; + + return IIO_VAL_INT; + } + error = -EINVAL; +error: + return error; +} + +static const struct iio_info vprbrd_adc_iio_info = { + .read_raw =