Jonathan Cameron wrote on 2010-10-01: > On 10/01/10 16:07, Hennerich, Michael wrote: >> Jonathan Cameron wrote on 2010-10-01: >>> Hi Michael, >>> >>> I was pretty much happy with this last time round. Couple of comments >>> inline. The new line missing in the Makefile is probably the only one >>> that I'd advocate doing pre merge. >>> >>> The precision attrs have gone away to be replaced by the more >>> informative type attributes in the scan_elements directory. This can >>> trivially be done as an additional patch post merge. >>> >>> There are some subtle changes to the event naming (post discussion on >>> lkml) but I'll just do this driver alongside the others in the patch >>> set implementing those changes. This is the first driver providing >>> hyst so that attribute will also need documenting. Again that should >>> happen post merge. >>> >>> I think we can also take advantage of some of the helper functions >>> that are now in place for buffer registration (came out of Barry's >>> work), but that can definitely happen at a later date. >>> >>> So in summary I'm happy to see this merge right now. The sooner the >>> better as far as I'm concerned >> >> Hi Jonathan, >> >> We have a few more iio drivers in our repository. Over the next couple >> of weeks I'm trying to get them out. Excellent. >> >>> because I would like it to go in before >>> the event clean up series currently sat in my tree. That way I can >>> update this one at the same time. >> >> Oops - this patch was already against your tree: >> http://git.kernel.org/?p=linux/kernel/git/jic23/iio_temp.git >> >> Need to check if it works on Greg's staging. > Ah. Shouldn't be too bad. That's what I get for putting temporary trees > up - that one only exists for testing the adis16260 and adis16350 driver > changes. Well - it looks bad. It basically errors on everything I changed in order to make it work on your temp tree. I'll send Greg my original version... drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_single_channel_from_ring': drivers/staging/iio/adc/ad799x_ring.c:35: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_ring.c:39: error: 'struct iio_ring_buffer' has no member named 'scan_count' drivers/staging/iio/adc/ad799x_ring.c:53: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_ring_preenable': drivers/staging/iio/adc/ad799x_ring.c:85: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_ring.c:87: error: 'struct iio_ring_buffer' has no member named 'scan_count' drivers/staging/iio/adc/ad799x_ring.c:89: error: 'struct iio_ring_access_funcs' has no member named 'set_bytes_per_datum' drivers/staging/iio/adc/ad799x_ring.c:93: error: 'struct iio_ring_access_funcs' has no member named 'set_bytes_per_datum' drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_poll_bh_to_ring': drivers/staging/iio/adc/ad799x_ring.c:136: error: 'struct iio_ring_buffer' has no member named 'scan_count' drivers/staging/iio/adc/ad799x_ring.c:163: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_ring.c:169: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_register_ring_funcs_and_init': drivers/staging/iio/adc/ad799x_ring.c:225: error: 'struct iio_ring_buffer' has no member named 'scan_el_attrs' LD drivers/staging/iio/light/built-in.o drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_scan_el_set_state': drivers/staging/iio/adc/ad799x_core.c:108: error: 'struct iio_ring_buffer' has no member named 'scan_mask' drivers/staging/iio/adc/ad799x_core.c:117:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c: At top level: drivers/staging/iio/adc/ad799x_core.c:117: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:118:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:118: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:119:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:119: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:120:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:120: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:121:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:121: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:122:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:122: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:123:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:123: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c:124:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given drivers/staging/iio/adc/ad799x_core.c:124: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C' drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_interrupt_bh': drivers/staging/iio/adc/ad799x_core.c:391: warning: suggest parentheses around + or - inside shift drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count >= width of type drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest parentheses around + or - inside shift drivers/staging/iio/adc/ad799x_core.c: At top level: drivers/staging/iio/adc/ad799x_core.c:469: error: 'iio_scan_el_in0' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:470: error: 'iio_const_attr_in0_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:471: error: 'iio_scan_el_in1' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:472: error: 'iio_const_attr_in1_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:473: error: 'iio_scan_el_in2' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:474: error: 'iio_const_attr_in2_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:475: error: 'iio_scan_el_in3' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:476: error: 'iio_const_attr_in3_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:499: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:499: error: (near initialization for 'ad7992_scan_el_attrs[0]') drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:500: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:500: error: (near initialization for 'ad7992_scan_el_attrs[1]') drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:501: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:501: error: (near initialization for 'ad7992_scan_el_attrs[2]') drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:502: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:502: error: (near initialization for 'ad7992_scan_el_attrs[3]') drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:531: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:531: error: (near initialization for 'ad7997_8_scan_el_attrs[0]') drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:532: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:532: error: (near initialization for 'ad7997_8_scan_el_attrs[1]') drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:533: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:533: error: (near initialization for 'ad7997_8_scan_el_attrs[2]') drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:534: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:534: error: (near initialization for 'ad7997_8_scan_el_attrs[3]') drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:535: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:535: error: (near initialization for 'ad7997_8_scan_el_attrs[4]') drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:536: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:536: error: (near initialization for 'ad7997_8_scan_el_attrs[5]') drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:537: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:537: error: (near initialization for 'ad7997_8_scan_el_attrs[6]') drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:538: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:538: error: (near initialization for 'ad7997_8_scan_el_attrs[7]') drivers/staging/iio/adc/ad799x_core.c:539: error: 'iio_scan_el_in4' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:539: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:539: error: (near initialization for 'ad7997_8_scan_el_attrs[8]') drivers/staging/iio/adc/ad799x_core.c:540: error: 'iio_const_attr_in4_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:540: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:540: error: (near initialization for 'ad7997_8_scan_el_attrs[9]') drivers/staging/iio/adc/ad799x_core.c:541: error: 'iio_scan_el_in5' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:541: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:541: error: (near initialization for 'ad7997_8_scan_el_attrs[10]') drivers/staging/iio/adc/ad799x_core.c:542: error: 'iio_const_attr_in5_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:542: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:542: error: (near initialization for 'ad7997_8_scan_el_attrs[11]') drivers/staging/iio/adc/ad799x_core.c:543: error: 'iio_scan_el_in6' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:543: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:543: error: (near initialization for 'ad7997_8_scan_el_attrs[12]') drivers/staging/iio/adc/ad799x_core.c:544: error: 'iio_const_attr_in6_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:544: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:544: error: (near initialization for 'ad7997_8_scan_el_attrs[13]') drivers/staging/iio/adc/ad799x_core.c:545: error: 'iio_scan_el_in7' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:545: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:545: error: (near initialization for 'ad7997_8_scan_el_attrs[14]') drivers/staging/iio/adc/ad799x_core.c:546: error: 'iio_const_attr_in7_index' undeclared here (not in a function) drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'dev_attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'attr' in something not a structure or union drivers/staging/iio/adc/ad799x_core.c:546: error: initializer element is not constant drivers/staging/iio/adc/ad799x_core.c:546: error: (near initialization for 'ad7997_8_scan_el_attrs[15]') > >> ...It's time to get out of staging > Couple of big bits that I think will need doing before we are ready > to run that gauntlet. Now its mainly stuff around the buffer code. > >> >>> Acked-by: Jonathan Cameron <jic23@xxxxxxxxx> >>> >>> Please send on to Greg KH <greg@xxxxxxxxx> for him to merge. >>> >>> Thanks, >>> >>> Jonathan >>> >>>> Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 >>>> and >>>> ad7998 multichannel ADC. >>>> >>>> Signed-off-by: Michael Hennerich <michael.hennerich@xxxxxxxxxx> >>>> --- >>>> drivers/staging/iio/adc/Kconfig | 20 + >>>> drivers/staging/iio/adc/Makefile | 4 + >>>> drivers/staging/iio/adc/ad799x.h | 157 ++++++ >>>> drivers/staging/iio/adc/ad799x_core.c | 918 >>>> +++++++++++++++++++++++++++++++++ >>>> drivers/staging/iio/adc/ad799x_ring.c | 246 +++++++++ >>>> 5 files changed, 1345 insertions(+), 0 deletions(-) create mode >>>> 100644 drivers/staging/iio/adc/ad799x.h create mode 100644 >>>> drivers/staging/iio/adc/ad799x_core.c >>>> create mode 100644 drivers/staging/iio/adc/ad799x_ring.c >>>> diff --git a/drivers/staging/iio/adc/Kconfig >>>> b/drivers/staging/iio/adc/Kconfig index 0835fbc..3ea4da8 100644 >>>> --- a/drivers/staging/iio/adc/Kconfig >>>> +++ b/drivers/staging/iio/adc/Kconfig >>>> @@ -26,3 +26,23 @@ config MAX1363_RING_BUFFER >>>> help >>>> Say yes here to include ring buffer support in the MAX1363 >>>> ADC driver. >>>> + >>>> +config AD799X >>>> + tristate "Analog Devices AD799x ADC driver" >>> I'll express my usual anti comment on driver names with wild cards, >>> but as there are hardly any numbers left in the range it is probably >>> fine here. >>>> + depends on I2C + select IIO_TRIGGER if IIO_RING_BUFFER + >>>> select AD799X_RING_BUFFER + help + Say yes here to build >>>> support for Analog Devices: + ad7991, ad7995, ad7999, ad7992, >>>> ad7993, ad7994, ad7997, ad7998 + i2c analog to digital >>>> convertors (ADC). Provides direct access + via sysfs. + +config >>>> AD799X_RING_BUFFER + bool "Analog Devices AD799x: use ring buffer" >>>> + depends on AD799X + select IIO_RING_BUFFER + select >>>> IIO_SW_RING + help + Say yes here to include ring buffer >>>> support in the AD799X + ADC driver. diff --git >>>> a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile >>>> index 688510f..f4aa63a 100644 --- a/drivers/staging/iio/adc/Makefile >>>> +++ b/drivers/staging/iio/adc/Makefile @@ -6,3 +6,7 @@ max1363-y := >>>> max1363_core.o max1363-y += max1363_ring.o >>>> >>>> obj-$(CONFIG_MAX1363) += max1363.o >>>> + +ad799x-y := ad799x_core.o +ad799x-$(CONFIG_AD799X_RING_BUFFER) += >>>> ad799x_ring.o +obj-$(CONFIG_AD799X) += ad799x.o Please add a new line >>>> after this. \ No newline at end of file diff --git >>>> a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h >>>> new file mode 100644 index 0000000..73f3ec5 --- /dev/null +++ >>>> b/drivers/staging/iio/adc/ad799x.h @@ -0,0 +1,157 @@ +/* + * >>>> Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * >>>> Copyright (C) 2008-2010 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. + * + * ad799x.h + */ + +#ifndef >>>> _AD799X_H_ +#define _AD799X_H_ + +#define AD799X_CHANNEL_SHIFT >>>> 4 + +/* + * AD7991, AD7995 and AD7999 defines */ + >>>> +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR >>>> 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 >>>> +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, >>>> AD7993, AD7994, AD7997 and AD7998 defines */ + +#define AD7998_FLTR >>>> 0x08 +#define AD7998_ALERT_EN 0x04 >>>> +#define AD7998_BUSY_ALERT 0x02 +#define >>>> AD7998_BUSY_ALERT_POL 0x01 + +#define >>>> AD7998_CONV_RES_REG 0x0 +#define >>>> AD7998_ALERT_STAT_REG 0x1 +#define >>>> AD7998_CONF_REG 0x2 +#define >>>> AD7998_CYCLE_TMR_REG 0x3 +#define >>>> AD7998_DATALOW_CH1_REG 0x4 +#define >>>> AD7998_DATAHIGH_CH1_REG 0x5 +#define >>>> AD7998_HYST_CH1_REG 0x6 +#define >>>> AD7998_DATALOW_CH2_REG 0x7 +#define >>>> AD7998_DATAHIGH_CH2_REG 0x8 +#define >>>> AD7998_HYST_CH2_REG 0x9 +#define >>>> AD7998_DATALOW_CH3_REG 0xA +#define >>>> AD7998_DATAHIGH_CH3_REG 0xB +#define >>>> AD7998_HYST_CH3_REG 0xC +#define >>>> AD7998_DATALOW_CH4_REG 0xD +#define >>>> AD7998_DATAHIGH_CH4_REG 0xE +#define >>>> AD7998_HYST_CH4_REG 0xF + +#define AD7998_CYC_MASK >>>> 0x7 +#define AD7998_CYC_DIS >>>> 0x0 +#define AD7998_CYC_TCONF_32 0x1 >>>> +#define AD7998_CYC_TCONF_64 0x2 +#define >>>> AD7998_CYC_TCONF_128 0x3 +#define >>>> AD7998_CYC_TCONF_256 0x4 +#define >>>> AD7998_CYC_TCONF_512 0x5 +#define >>>> AD7998_CYC_TCONF_1024 0x6 +#define >>>> AD7998_CYC_TCONF_2048 0x7 + +#define >>>> AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and >>>> AD7997 defines + */ + +#define AD7997_8_READ_SINGLE >>>> 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 + +enum >>>> { + ad7991, + ad7995, + ad7999, + ad7992, + >>>> ad7993, + ad7994, + ad7997, + ad7998 +}; + +struct >>>> ad799x_state; + +/** + * struct ad799x_chip_info - chip specifc >>>> information + * @num_inputs: number of physical inputs on chip + * >>>> @bits: accuracy of the adc in bits + * @int_vref_mv: >>>> the internal reference voltage + * @monitor_mode: whether the >>>> chip supports monitor interrupts + * @default_config: device >>>> default configuration + * @dev_attrs: pointer to the >>>> device attribute group + * @scan_attrs: pointer to the >>>> scan element attribute group + * @event_attrs: pointer to the >>>> monitor event attribute group + * @ad799x_set_scan_mode: function >>>> pointer to the device specific +mode function + + */ +struct >>>> ad799x_chip_info { + u8 num_inputs; + u8 >>>> bits; + u16 int_vref_mv; + bool >>>> monitor_mode; + u16 default_config; + >>>> struct attribute_group *dev_attrs; + struct >>>> attribute_group *scan_attrs; + struct attribute_group >>>> *event_attrs; + int (*ad799x_set_scan_mode) (struct >>>> ad799x_state *st, + unsigned mask); +}; + +struct ad799x_state { + >>>> struct iio_dev *indio_dev; + struct i2c_client >>>> *client; + const struct ad799x_chip_info *chip_info; + >>>> struct work_struct poll_work; + struct work_struct >>>> work_thresh; + atomic_t protect_ring; + struct iio_trigger >>>> *trig; + struct regulator *reg; + s64 >>>> last_timestamp; + u16 int_vref_mv; >>>> + unsigned id; + char *name; + u16 >>>> config; +}; + +/* + * TODO: struct >>>> ad799x_platform_data needs to go into +inlude/linux/iio Typo in >>>> comment. + */ + +struct ad799x_platform_data { + u16 vref_mv; +}; >>>> + +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask); >>>> + +#ifdef CONFIG_AD799X_RING_BUFFER +int >>>> ad799x_single_channel_from_ring(struct ad799x_state *st, long +mask); >>>> int ad799x_register_ring_funcs_and_init(struct iio_dev +*indio_dev); >>>> void ad799x_ring_cleanup(struct iio_dev *indio_dev); +#else /* >>>> CONFIG_AD799X_RING_BUFFER */ int >>>> +ad799x_single_channel_from_ring(struct ad799x_state *st, long mask) >>>> { + return -EINVAL; +} + + +static inline int >>>> +ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) { + >>>> return 0; +} + +static inline void ad799x_ring_cleanup(struct >>>> iio_dev *indio_dev) { } +#endif /* CONFIG_AD799X_RING_BUFFER */ >>>> #endif /* _AD799X_H_ */ diff --git >>>> a/drivers/staging/iio/adc/ad799x_core.c >>>> b/drivers/staging/iio/adc/ad799x_core.c new file mode 100644 index >>>> 0000000..772c664 --- /dev/null +++ >>>> b/drivers/staging/iio/adc/ad799x_core.c @@ -0,0 +1,918 @@ +/* + * >>>> iio/adc/ad799x.c + * Copyright (C) 2010 Michael Hennerich, Analog >>>> Devices Inc. + * + * based on iio/adc/max1363 + * Copyright (C) >>>> 2008-2010 Jonathan Cameron + * + * based on >>>> linux/drivers/i2c/chips/max123x + * Copyright (C) 2002-2004 Stefan >>>> Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * >>>> Copyright (C) 2000 Russell King + * + * 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. + * + * ad799x.c + * + * Support for >>>> ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, +ad7997, + * ad7998 >>>> and similar chips. + * + */ + +#include <linux/interrupt.h> +#include >>>> <linux/workqueue.h> +#include <linux/device.h> +#include >>>> <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> >>>> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> >>>> #include <linux/slab.h> +#include <linux/types.h> #include >>>> <linux/err.h> + +#include "../iio.h" +#include "../sysfs.h" + >>>> +#include "../ring_generic.h" +#include "adc.h" +#include "ad799x.h" >>>> + +/* + * ad799x register access by I2C + */ +static int >>>> ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 +*data) { + >>>> struct i2c_client *client = st->client; + int ret = 0; + + >>>> ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) { >>>> + dev_err(&client->dev, "I2C read error\n"); + >>>> return ret; + } + + *data = swab16((u16)ret); + + return 0; +} >>>> + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 >>>> +*data) { + struct i2c_client *client = st->client; + int ret >>>> = 0; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < >>>> 0) { + dev_err(&client->dev, "I2C read error\n"); + return >>>> ret; + } + + *data = ret; + + return 0; +} + +static int >>>> ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 +data) { + >>>> struct i2c_client *client = st->client; + int ret = 0; + + >>>> ret = i2c_smbus_write_word_data(client, reg, swab16(data)); + >>>> if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + >>>> return ret; +} + +static int ad799x_i2c_write8(struct ad799x_state >>>> *st, u8 reg, u8 +data) { + struct i2c_client *client = >>>> st->client; + int ret = 0; + + ret = >>>> i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + >>>> dev_err(&client->dev, "I2C write error\n"); + + return >>>> ret; +} + +static int ad799x_scan_el_set_state(struct iio_scan_el >>>> *scan_el, + struct iio_dev *indio_dev, + >>>> bool state) +{ + struct ad799x_state *st = indio_dev->dev_data; + >>>> return ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask); } + >>>> +/* Here we claim all are 16 bits. This currently does no harm and >>>> +saves + * us a lot of scan element listings */ + +#define >>>> AD799X_SCAN_EL(number) \ + IIO_SCAN_EL_C(in##number, number, 0, >>>> ad799x_scan_el_set_state); + +static AD799X_SCAN_EL(0); +static >>>> AD799X_SCAN_EL(1); +static AD799X_SCAN_EL(2); +static >>>> AD799X_SCAN_EL(3); +static AD799X_SCAN_EL(4); +static >>>> AD799X_SCAN_EL(5); +static AD799X_SCAN_EL(6); +static >>>> AD799X_SCAN_EL(7); + +static ssize_t ad799x_show_precision(struct >>>> device *dev, + struct device_attribute >>>> *attr, + char *buf) +{ + struct >>>> iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state >>>> *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "%d\n", >>>> st->chip_info->bits); } + +static IIO_DEVICE_ATTR(in_precision, >>>> S_IRUGO, ad799x_show_precision, + NULL, 0); + >>>> +static int ad7991_5_9_set_scan_mode(struct ad799x_state *st, >>>> unsigned +mask) { + return i2c_smbus_write_byte(st->client, + >>>> st- config | (mask << AD799X_CHANNEL_SHIFT)); } + +static >>>> int ad7992_3_4_set_scan_mode(struct ad799x_state *st, unsigned +mask) >>>> { + return ad799x_i2c_write8(st, AD7998_CONF_REG, + >>>> st->config | (mask << AD799X_CHANNEL_SHIFT)); } + +static int >>>> ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned +mask) { + >>>> return ad799x_i2c_write16(st, AD7998_CONF_REG, + st->config | (mask >>>> << AD799X_CHANNEL_SHIFT)); } + +int ad799x_set_scan_mode(struct >>>> ad799x_state *st, unsigned mask) { + int ret; + + if >>>> (st->chip_info->ad799x_set_scan_mode != NULL) { + ret = >>>> st->chip_info->ad799x_set_scan_mode(st, mask); + return >>>> (ret > 0) ? 0 : ret; + } + + return 0; +} + +static ssize_t >>>> ad799x_read_single_channel(struct device *dev, + struct >>>> device_attribute *attr, + char *buf) +{ >>>> + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct >>>> ad799x_state *st = iio_dev_get_devdata(dev_info); + struct >>>> iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret = 0, >>>> len = 0; + u32 data ; + u16 rxbuf[1]; + u8 cmd; + long mask; + >>>> + mutex_lock(&dev_info- mlock); + mask = 1 << this_attr->address; >>>> + /* If ring buffer capture is occuring, query the buffer */ + >>>> if (iio_ring_enabled(dev_info)) { + data = >>>> ad799x_single_channel_from_ring(st, mask); + if (data < 0) { + >>>> ret = data; + goto > error_ret; + } + } else { + switch (st- >> id) >>>> { + case ad7991: + case ad7995: + case >>>> ad7999: + cmd = st->config | (mask << >>>> AD799X_CHANNEL_SHIFT); + break; + case ad7992: + >>>> case ad7993: + case ad7994: + cmd = >>>> mask << AD799X_CHANNEL_SHIFT; + break; + >>>> case ad7997: + case ad7998: + cmd = >>>> (this_attr->address << + AD799X_CHANNEL_SHIFT) | >>>> AD7997_8_READ_SINGLE; + break; + > default: + cmd = 0; + + } + > ret >>>> = ad799x_i2c_read16(st, cmd, rxbuf); + if (ret < 0) + >>>> goto error_ret; + + data = rxbuf[0] & 0xFFF; + } + >>>> + /* Pretty print the result */ + len = sprintf(buf, "%u\n", data); >>>> + +error_ret: + mutex_unlock(&dev_info->mlock); + return ret >>>> ? ret : len; +} + +static ssize_t ad799x_read_frequency(struct device >>>> *dev, + struct device_attribute *attr, + >>>> char *buf) +{ + struct iio_dev *dev_info = >>>> dev_get_drvdata(dev); + struct ad799x_state *st = >>>> iio_dev_get_devdata(dev_info); + + int ret, len = 0; + u8 val; >>>> + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + if >>>> (ret) + return ret; + + val &= AD7998_CYC_MASK; + + switch >>>> (val) { + case AD7998_CYC_DIS: + len = sprintf(buf, >>>> "0\n"); + break; + case AD7998_CYC_TCONF_32: + >>>> len = sprintf(buf, "15625\n"); + break; + case >>>> AD7998_CYC_TCONF_64: + len = sprintf(buf, "7812\n"); + >>>> break; + case AD7998_CYC_TCONF_128: + len >>>> = sprintf(buf, "3906\n"); + break; + case >>>> AD7998_CYC_TCONF_256: + len = sprintf(buf, "1953\n"); + >>>> break; + case AD7998_CYC_TCONF_512: + len >>>> = sprintf(buf, "976\n"); + break; + case >>>> AD7998_CYC_TCONF_1024: + len = sprintf(buf, "488\n"); + >>>> break; + case AD7998_CYC_TCONF_2048: + len = >>>> sprintf(buf, "244\n"); + break; + } + return len; +} + >>>> +static ssize_t ad799x_write_frequency(struct device *dev, + >>>> struct > device_attribute *attr, + const > char *buf, >>>> + size_t len) +{ + struct >>>> iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state >>>> *st = iio_dev_get_devdata(dev_info); + + long val; + int ret; + >>>> u8 t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + >>>> return ret; + + mutex_lock(&dev_info->mlock); + ret = >>>> ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); + if (ret) + >>>> goto error_ret_mutex; + /* Wipe the bits clean */ + t &= >>>> ~AD7998_CYC_MASK; + + switch (val) { + case 15625: + >>>> t |= AD7998_CYC_TCONF_32; + break; + case 7812: + >>>> t |= AD7998_CYC_TCONF_64; + break; + case 3906: + t >>>> |= AD7998_CYC_TCONF_128; + break; + case 1953: + >>>> t |= AD7998_CYC_TCONF_256; + break; + case 976: + >>>> t |= AD7998_CYC_TCONF_512; + break; + case 488: + >>>> t |= AD7998_CYC_TCONF_1024; + break; + case 244: + >>>> t |= AD7998_CYC_TCONF_2048; + break; + case 0: + >>>> t |= AD7998_CYC_DIS; + break; + default: + >>>> ret = -EINVAL; + goto error_ret_mutex; + } + + >>>> ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + >>>> +error_ret_mutex: + mutex_unlock(&dev_info->mlock); + + return >>>> ret ? ret : len; +} + + +static ssize_t >>>> ad799x_read_channel_config(struct device *dev, + >>>> struct > device_attribute *attr, + char > *buf) +{ >>>> + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct >>>> ad799x_state *st = iio_dev_get_devdata(dev_info); + struct >>>> iio_event_attr *this_attr = to_iio_event_attr(attr); + + int ret; >>>> + u16 val; + ret = ad799x_i2c_read16(st, this_attr->mask, >>>> &val); + if (ret) + return ret; + + return sprintf(buf, >>>> "%d\n", val); +} + +static ssize_t ad799x_write_channel_config(struct >>>> device *dev, + struct device_attribute *attr, + >>>> const char *buf, + >>>> size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); >>>> + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + >>>> struct iio_event_attr *this_attr = to_iio_event_attr(attr); + + >>>> long val; + int ret; + + ret = strict_strtol(buf, 10, &val); + >>>> if (ret) + return ret; + + >>>> mutex_lock(&dev_info->mlock); + ret = ad799x_i2c_write16(st, >>>> this_attr->mask, val); + mutex_unlock(&dev_info->mlock); + + >>>> return ret ? ret : len; +} + +static void ad799x_interrupt_bh(struct >>>> work_struct *work_s) { + struct ad799x_state *st = >>>> container_of(work_s, + struct ad799x_state, work_thresh); + u8 >>>> status; + int i; + + if (ad799x_i2c_read8(st, >>>> AD7998_ALERT_STAT_REG, &status)) + goto err_out; + + if (!status) + >>>> goto err_out; + + ad799x_i2c_write8(st, >>>> AD7998_ALERT_STAT_REG, +AD7998_ALERT_STAT_CLEAR); + + for (i = >>>> 0; i < 8; i++) { + if (status & (1 << i)) + >>>> iio_push_event(st->indio_dev, 0, + i & 0x1 ? >>>> + IIO_EVENT_CODE_IN_HIGH_THRESH(i >> 1) : + >>>> IIO_EVENT_CODE_IN_LOW_THRESH(i >> 1), + >>>> st->last_timestamp); + } + +err_out: + >>>> enable_irq(st->client->irq); +} + +static int ad799x_interrupt(struct >>>> iio_dev *dev_info, + int index, + s64 timestamp, + >>>> int no_test) +{ + struct ad799x_state *st = dev_info->dev_data; >>>> + + st->last_timestamp = timestamp; + >>>> schedule_work(&st->work_thresh); + return 0; +} + >>>> +IIO_EVENT_SH(ad799x, &ad799x_interrupt); + +/* Direct read >>>> attribtues */ +static IIO_DEV_ATTR_IN_RAW(0, >>>> ad799x_read_single_channel, 0); +static IIO_DEV_ATTR_IN_RAW(1, >>>> ad799x_read_single_channel, 1); +static IIO_DEV_ATTR_IN_RAW(2, >>>> ad799x_read_single_channel, 2); +static IIO_DEV_ATTR_IN_RAW(3, >>>> ad799x_read_single_channel, 3); +static IIO_DEV_ATTR_IN_RAW(4, >>>> ad799x_read_single_channel, 4); +static IIO_DEV_ATTR_IN_RAW(5, >>>> ad799x_read_single_channel, 5); +static IIO_DEV_ATTR_IN_RAW(6, >>>> ad799x_read_single_channel, 6); +static IIO_DEV_ATTR_IN_RAW(7, >>>> ad799x_read_single_channel, 7); + +static ssize_t >>>> ad799x_show_scale(struct device *dev, + struct device_attribute >>>> *attr, + char *buf) +{ + /* Driver >>>> currently only support internal vref */ + struct iio_dev *dev_info >>>> = dev_get_drvdata(dev); + struct ad799x_state *st = >>>> iio_dev_get_devdata(dev_info); + /* Corresponds to Vref / >>>> 2^(bits) */ + + if ((1 << (st->chip_info->bits + 1)) + > >>>> st->int_vref_mv) + return sprintf(buf, "0.5\n"); + else + >>>> return sprintf(buf, "%d\n", + >>>> st->int_vref_mv >> st->chip_info->bits); } + +static >>>> IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, +0); + >>>> +static ssize_t ad799x_show_name(struct device *dev, + struct >>>> device_attribute *attr, + char *buf) +{ + >>>> struct iio_dev *dev_info = dev_get_drvdata(dev); + struct >>>> ad799x_state *st = iio_dev_get_devdata(dev_info); + return >>>> sprintf(buf, "%s\n", st->client->name); } + +static >>>> IIO_DEVICE_ATTR(name, S_IRUGO, ad799x_show_name, NULL, 0); + +static >>>> struct attribute *ad7991_5_9_3_4_device_attrs[] = { + >>>> &iio_dev_attr_in0_raw.dev_attr.attr, + >>>> &iio_dev_attr_in1_raw.dev_attr.attr, + >>>> &iio_dev_attr_in2_raw.dev_attr.attr, + >>>> &iio_dev_attr_in3_raw.dev_attr.attr, + >>>> &iio_dev_attr_name.dev_attr.attr, + >>>> &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct >>>> attribute_group ad7991_5_9_3_4_dev_attr_group = { + .attrs = >>>> ad7991_5_9_3_4_device_attrs, }; + +static struct attribute >>>> *ad7991_5_9_3_4_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, >>>> + &iio_const_attr_in0_index.dev_attr.attr, + >>>> &iio_scan_el_in1.dev_attr.attr, + >>>> &iio_const_attr_in1_index.dev_attr.attr, + >>>> &iio_scan_el_in2.dev_attr.attr, + >>>> &iio_const_attr_in2_index.dev_attr.attr, + >>>> &iio_scan_el_in3.dev_attr.attr, + >>>> &iio_const_attr_in3_index.dev_attr.attr, >>> The precision attribute has been replaced by the _type attributes in >>> the scan_elements directory as they give all the information in one >>> consice form. Lets do that change as an additional patch post merge >>> though. >>> >>>> + &iio_dev_attr_in_precision.dev_attr.attr, + NULL, +}; + >>>> +static struct attribute_group ad7991_5_9_3_4_scan_el_group = { + >>>> .name = "scan_elements", + .attrs = ad7991_5_9_3_4_scan_el_attrs, >>>> }; + +static struct attribute *ad7992_device_attrs[] = { + >>>> &iio_dev_attr_in0_raw.dev_attr.attr, + >>>> &iio_dev_attr_in1_raw.dev_attr.attr, + >>>> &iio_dev_attr_name.dev_attr.attr, + >>>> &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct >>>> attribute_group ad7992_dev_attr_group = { + .attrs = >>>> ad7992_device_attrs, +}; + +static struct attribute >>>> *ad7992_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + >>>> &iio_const_attr_in0_index.dev_attr.attr, + >>>> &iio_scan_el_in1.dev_attr.attr, + >>>> &iio_const_attr_in1_index.dev_attr.attr, + >>>> &iio_dev_attr_in_precision.dev_attr.attr, + NULL, +}; + +static >>>> struct attribute_group ad7992_scan_el_group = { + .name = >>>> "scan_elements", + .attrs = ad7992_scan_el_attrs, +}; + +static >>>> struct attribute *ad7997_8_device_attrs[] = { + >>>> &iio_dev_attr_in0_raw.dev_attr.attr, + >>>> &iio_dev_attr_in1_raw.dev_attr.attr, + >>>> &iio_dev_attr_in2_raw.dev_attr.attr, + >>>> &iio_dev_attr_in3_raw.dev_attr.attr, + >>>> &iio_dev_attr_in4_raw.dev_attr.attr, + >>>> &iio_dev_attr_in5_raw.dev_attr.attr, + >>>> &iio_dev_attr_in6_raw.dev_attr.attr, + >>>> &iio_dev_attr_in7_raw.dev_attr.attr, + >>>> &iio_dev_attr_name.dev_attr.attr, + >>>> &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct >>>> attribute_group ad7997_8_dev_attr_group = { + .attrs = >>>> ad7997_8_device_attrs, +}; + +static struct attribute >>>> *ad7997_8_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + >>>> &iio_const_attr_in0_index.dev_attr.attr, + >>>> &iio_scan_el_in1.dev_attr.attr, + >>>> &iio_const_attr_in1_index.dev_attr.attr, + >>>> &iio_scan_el_in2.dev_attr.attr, + >>>> &iio_const_attr_in2_index.dev_attr.attr, + >>>> &iio_scan_el_in3.dev_attr.attr, + >>>> &iio_const_attr_in3_index.dev_attr.attr, + >>>> &iio_scan_el_in4.dev_attr.attr, + >>>> &iio_const_attr_in4_index.dev_attr.attr, + >>>> &iio_scan_el_in5.dev_attr.attr, + >>>> &iio_const_attr_in5_index.dev_attr.attr, + >>>> &iio_scan_el_in6.dev_attr.attr, + >>>> &iio_const_attr_in6_index.dev_attr.attr, + >>>> &iio_scan_el_in7.dev_attr.attr, + >>>> &iio_const_attr_in7_index.dev_attr.attr, + >>>> &iio_dev_attr_in_precision.dev_attr.attr, + NULL, +}; + +static >>>> struct attribute_group ad7997_8_scan_el_group = { + .name = >>>> "scan_elements", + .attrs = ad7997_8_scan_el_attrs, +}; + >>>> +IIO_EVENT_ATTR_SH(in0_thresh_low_value, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_DATALOW_CH1_REG); + +IIO_EVENT_ATTR_SH(in0_thresh_high_value, >>>> + iio_event_ad799x, + >>>> ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + AD7998_DATAHIGH_CH1_REG); >>>> + +IIO_EVENT_ATTR_SH(in0_thresh_both_hyst_raw, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_HYST_CH1_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_low_value, + >>>> iio_event_ad799x, + >>>> ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + AD7998_DATALOW_CH2_REG); >>>> + +IIO_EVENT_ATTR_SH(in1_thresh_high_value, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_DATAHIGH_CH2_REG); + >>>> +IIO_EVENT_ATTR_SH(in1_thresh_both_hyst_raw, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_HYST_CH2_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_low_value, + >>>> iio_event_ad799x, + >>>> ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + AD7998_DATALOW_CH3_REG); >>>> + +IIO_EVENT_ATTR_SH(in2_thresh_high_value, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_DATAHIGH_CH3_REG); + >>>> +IIO_EVENT_ATTR_SH(in2_thresh_both_hyst_raw, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_HYST_CH3_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_low_value, + >>>> iio_event_ad799x, + >>>> ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + AD7998_DATALOW_CH4_REG); >>>> + +IIO_EVENT_ATTR_SH(in3_thresh_high_value, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_DATAHIGH_CH4_REG); + >>>> +IIO_EVENT_ATTR_SH(in3_thresh_both_hyst_raw, + >>>> iio_event_ad799x, + ad799x_read_channel_config, + >>>> ad799x_write_channel_config, + >>>> AD7998_HYST_CH4_REG); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | >>>> S_IRUGO, + ad799x_read_frequency, + >>>> ad799x_write_frequency); +static >>>> IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 +244 >>>> 0"); + +static struct attribute *ad7993_4_7_8_event_attributes[] = { >>>> + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_event_attr_in2_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in2_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in2_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_event_attr_in3_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in3_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in3_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_dev_attr_sampling_frequency.dev_attr.attr, + >>>> &iio_const_attr_sampling_frequency_available.dev_attr.attr, + >>>> NULL, +}; + +static struct attribute_group >>>> ad7993_4_7_8_event_attrs_group = { + .attrs = >>>> ad7993_4_7_8_event_attributes, }; + +static struct attribute >>>> *ad7992_event_attributes[] = { + >>>> &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + >>>> &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + >>>> &iio_dev_attr_sampling_frequency.dev_attr.attr, + >>>> &iio_const_attr_sampling_frequency_available.dev_attr.attr, + >>>> NULL, +}; + +static struct attribute_group ad7992_event_attrs_group = >>>> { + .attrs = ad7992_event_attributes, +}; + +static const struct >>>> ad799x_chip_info ad799x_chip_info_tbl[] = { + [ad7991] = { + >>>> .num_inputs = 4, + .bits = 12, + >>>> .int_vref_mv = 4096, + .dev_attrs = >>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = >>>> &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = >>>> ad7991_5_9_set_scan_mode, + }, + [ad7995] = { + >>>> .num_inputs = 4, + .bits = 10, + .int_vref_mv = >>>> 1024, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + >>>> .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + >>>> .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + >>>> [ad7999] = { + .num_inputs = 4, + .bits = 10, + >>>> .int_vref_mv = 1024, + .dev_attrs = >>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = >>>> &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = >>>> ad7991_5_9_set_scan_mode, + }, + [ad7992] = { + >>>> .num_inputs = 2, + .bits = 12, + .int_vref_mv = >>>> 4096, + .monitor_mode = true, + .default_config >>>> = AD7998_ALERT_EN, + .dev_attrs = &ad7992_dev_attr_group, >>>> + .scan_attrs = &ad7992_scan_el_group, + >>>> .event_attrs = &ad7992_event_attrs_group, + >>>> .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + >>>> [ad7993] = { + .num_inputs = 4, + .bits = 10, + >>>> .int_vref_mv = 1024, + .monitor_mode = true, + >>>> .default_config = AD7998_ALERT_EN, + .dev_attrs >>>> = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = >>>> &ad7991_5_9_3_4_scan_el_group, + .event_attrs = >>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = >>>> ad7992_3_4_set_scan_mode, + }, + [ad7994] = { + >>>> .num_inputs = 4, + .bits = 12, + .int_vref_mv = >>>> 4096, + .monitor_mode = true, + .default_config >>>> = AD7998_ALERT_EN, + .dev_attrs = >>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = >>>> &ad7991_5_9_3_4_scan_el_group, + .event_attrs = >>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = >>>> ad7992_3_4_set_scan_mode, + }, + [ad7997] = { + >>>> .num_inputs = 8, + .bits = 10, + .int_vref_mv = >>>> 1024, + .monitor_mode = true, + .default_config >>>> = AD7998_ALERT_EN, + .dev_attrs = >>>> &ad7997_8_dev_attr_group, + .scan_attrs = >>>> &ad7997_8_scan_el_group, + .event_attrs = >>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = >>>> ad7997_8_set_scan_mode, + }, + [ad7998] = { + >>>> .num_inputs = 8, + .bits = 12, + .int_vref_mv = >>>> 4096, + .monitor_mode = true, + .default_config >>>> = AD7998_ALERT_EN, + .dev_attrs = >>>> &ad7997_8_dev_attr_group, + .scan_attrs = >>>> &ad7997_8_scan_el_group, + .event_attrs = >>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = >>>> ad7997_8_set_scan_mode, + }, +}; + +static int __devinit >>>> ad799x_probe(struct i2c_client *client, + >>>> const struct i2c_device_id *id) { + int ret, regdone = 0; + >>>> struct ad799x_platform_data *pdata = client- dev.platform_data; + >>>> struct ad799x_state *st = kzalloc(sizeof(*st), GFP_KERNEL); + if >>>> (st == NULL) { + ret = -ENOMEM; + goto >>>> error_ret; + } + + /* this is only used for device removal >>>> purposes */ + i2c_set_clientdata(client, st); + + >>>> atomic_set(&st->protect_ring, 0); + st->id = id->driver_data; + >>>> st->chip_info = &ad799x_chip_info_tbl[st->id]; + st->config = >>>> st->chip_info->default_config; + + /* TODO: Add pdata options for >>>> filtering and bit delay */ >>> We also need to add userspace attributes to cover filtering for these >>> devices. However, that is definitely a discussion for another day! >>>> + + if (pdata) + st->int_vref_mv = pdata->vref_mv; + else >>>> + st->int_vref_mv = st->chip_info->int_vref_mv; + + >>>> st->reg = regulator_get(&client->dev, "vcc"); + if >>>> (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); >>>> + if (ret) + goto error_put_reg; + } + st->client = >>>> client; + + st->indio_dev = iio_allocate_device(); + if >>>> (st->indio_dev == NULL) { + ret = -ENOMEM; + goto >>>> error_disable_reg; + } + + /* Estabilish that the iio_dev is a >>>> child of the i2c device */ + st->indio_dev->dev.parent = >>>> &client->dev; + st->indio_dev- attrs = st->chip_info->dev_attrs; >>>> + st->indio_dev->event_attrs = st->chip_info->event_attrs; + + >>>> st->indio_dev->dev_data = (void *)(st); + >>>> st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev- modes >>>> = INDIO_DIRECT_MODE; + st->indio_dev->num_interrupt_lines = 1; + + >>>> ret = ad799x_set_scan_mode(st, 0); + if (ret) + >>>> goto error_free_device; + + ret = >>>> ad799x_register_ring_funcs_and_init(st->indio_dev); + if (ret) + >>>> goto error_free_device; + + ret = >>>> iio_device_register(st->indio_dev); + if (ret) + goto >>>> error_cleanup_ring; + regdone = 1; + + ret = >>>> iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto >>>> error_cleanup_ring; + + if (client->irq > 0 && >>>> st->chip_info->monitor_mode) { + INIT_WORK(&st- >>>> work_thresh, ad799x_interrupt_bh); + + ret = >>>> iio_register_interrupt_line(client->irq, + st->indio_dev, + >>>> 0, + >>>> IRQF_TRIGGER_FALLING, + client->name); + if (ret) + >>>> goto error_cleanup_ring; + + /* + >>>> * The event handler list element refer to iio_event_ad799x. + >>>> * All event attributes bind to the same event handler. >>>> + * So, only register event handler once. + */ + >>>> iio_add_event_to_list(&iio_event_ad799x, + >>>> &st->indio_dev->interrupts[0]- ev_list); + } + + return 0; >>>> +error_cleanup_ring: + ad799x_ring_cleanup(st->indio_dev); >>>> +error_free_device: + if (!regdone) + >>>> iio_free_device(st->indio_dev); + else + >>>> iio_device_unregister(st->indio_dev); +error_disable_reg: + if >>>> (!IS_ERR(st->reg)) + regulator_disable(st->reg); >>>> +error_put_reg: + if (!IS_ERR(st->reg)) + >>>> regulator_put(st->reg); + kfree(st); +error_ret: + return ret; >>>> +} + +static __devexit int ad799x_remove(struct i2c_client *client) { >>>> + struct ad799x_state *st = i2c_get_clientdata(client); + >>>> struct iio_dev *indio_dev = st->indio_dev; + + if (client->irq > 0 >>>> && st->chip_info- monitor_mode) + >>>> iio_unregister_interrupt_line(indio_dev, 0); + + >>>> iio_ring_buffer_unregister(indio_dev->ring); + >>>> ad799x_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + >>>> if (!IS_ERR(st->reg)) { + regulator_disable(st- >>>> reg); + regulator_put(st->reg); + } + kfree(st); >>>> + + return 0; +} + +static const struct i2c_device_id ad799x_id[] = { >>>> + { "ad7991", ad7991 }, + { "ad7995", ad7995 }, + { "ad7999", >>>> ad7999 }, + { "ad7992", ad7992 }, + { "ad7993", ad7993 }, + { >>>> "ad7994", ad7994 }, + { "ad7997", ad7997 }, + { "ad7998", ad7998 }, + >>>> {} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_id); + +static >>>> struct i2c_driver ad799x_driver = { + .driver = { + .name = >>>> "ad799x", + }, + .probe = ad799x_probe, + .remove = >>>> __devexit_p(ad799x_remove), + .id_table = ad799x_id, +}; + >>>> +static __init int ad799x_init(void) { + return >>>> i2c_add_driver(&ad799x_driver); } + +static __exit void >>>> ad799x_exit(void) { + i2c_del_driver(&ad799x_driver); +} + >>>> +MODULE_AUTHOR("Michael Hennerich >>>> +<hennerich@xxxxxxxxxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("Analog >>>> Devices AD799x ADC"); +MODULE_LICENSE("GPL v2"); >>>> MODULE_ALIAS("i2c:ad799x"); + +module_init(ad799x_init); >>>> +module_exit(ad799x_exit); diff --git >>>> a/drivers/staging/iio/adc/ad799x_ring.c >>>> b/drivers/staging/iio/adc/ad799x_ring.c new file mode 100644 index >>>> 0000000..0f2041a --- /dev/null +++ >>>> b/drivers/staging/iio/adc/ad799x_ring.c @@ -0,0 +1,246 @@ +/* + * >>>> Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * >>>> Copyright (C) 2008-2010 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. + * + * ad799x_ring.c + */ + >>>> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include >>>> <linux/device.h> +#include <linux/slab.h> +#include <linux/kernel.h> >>>> +#include <linux/sysfs.h> +#include <linux/list.h> +#include >>>> <linux/i2c.h> +#include <linux/bitops.h> + +#include "../iio.h" >>>> +#include "../ring_generic.h" +#include "../ring_sw.h" +#include >>>> "../trigger.h" +#include "../sysfs.h" + +#include "ad799x.h" + +int >>>> ad799x_single_channel_from_ring(struct ad799x_state *st, long +mask) >>>> { + unsigned long numvals; + int count = 0, ret; + u16 >>>> *ring_data; + if (!(st->indio_dev->ring->scan_mask & mask)) { + >>>> ret = -EBUSY; + goto error_ret; + } + >>>> numvals = st->indio_dev->ring->scan_count; + + ring_data = >>>> kmalloc(numvals*2, GFP_KERNEL); + if (ring_data == NULL) { + >>>> ret = -ENOMEM; + goto error_ret; + } + ret = >>>> st->indio_dev->ring->access.read_last(st->indio_dev->ring, + (u8 *) >>>> ring_data); + if (ret) + goto error_free_ring_data; >>>> + /* Need a count of channels prior to this one */ + mask >>= >>>> 1; + while (mask) { + if (mask & >>>> st->indio_dev->ring->scan_mask) + count++; + mask >>= 1; >>>> + } + + ret = be16_to_cpu(ring_data[count]) & 0xFFF; + >>>> +error_free_ring_data: + kfree(ring_data); +error_ret: + return >>>> ret; +} + +/** + * ad799x_ring_preenable() setup the parameters of >>>> the ring before +enabling + * + * The complex nature of the setting >>>> of the nuber of bytes per +datum is due + * to this driver currently >>>> ensuring that the timestamp is stored +at an 8 + * byte boundary. + >>>> **/ +static int ad799x_ring_preenable(struct iio_dev *indio_dev) { + >>>> struct ad799x_state *st = indio_dev->dev_data; + size_t d_size; + >>>> unsigned long numvals; + + /* + * Need to figure out the >>>> current mode based upon the requested + * scan mask in iio_dev + >>>> */ + + if (st->id == ad7997 || st->id == ad7998) + >>>> ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask); + + numvals >>>> = st->indio_dev->ring->scan_count; + + if >>>> (indio_dev->ring->access.set_bytes_per_datum) { + d_size = >>>> numvals*2 + sizeof(s64); + if (d_size % 8) + d_size += >>>> 8 - (d_size % 8); + >>>> indio_dev->ring->access.set_bytes_per_datum(indio_dev- ring, + >>>> d_size); + } + + >>>> return 0; +} + +/** + * ad799x_poll_func_th() th of trigger launched >>>> polling to ring +buffer + * + * As sampling only occurs on i2c comms >>>> occuring, leave +timestamping until + * then. Some triggers will >>>> generate their own time stamp. +Currently + * there is no way of >>>> notifying them when no one cares. + **/ +static void >>>> ad799x_poll_func_th(struct iio_dev *indio_dev, s64 +time) { + >>>> struct ad799x_state *st = indio_dev->dev_data; + + >>>> schedule_work(&st->poll_work); + + return; +} +/** + * >>>> ad799x_poll_bh_to_ring() bh of trigger launched polling to ring >>>> buffer + * @work_s: the work struct through which this was >>>> scheduled + * + * Currently there is no option in this driver to >>>> disable the +saving of + * timestamps within the ring. + * I think >>>> the one copy of this at a time was to avoid problems if +the + * >>>> trigger was set far too high and the reads then locked up the >>>> computer. + **/ +static void ad799x_poll_bh_to_ring(struct >>>> work_struct *work_s) { + struct ad799x_state *st = >>>> container_of(work_s, struct ad799x_state, + >>>> poll_work); + struct iio_dev *indio_dev = >>>> st->indio_dev; + struct iio_sw_ring_buffer *ring = >>>> iio_to_sw_ring(indio_dev- ring); + s64 time_ns; + __u8 *rxbuf; + >>>> int b_sent; + size_t d_size; + u8 cmd; + + unsigned long >>>> numvals = st->indio_dev->ring->scan_count; + + /* Ensure the >>>> timestamp is 8 byte aligned */ + d_size = numvals*2 + sizeof(s64); + >>>> + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - >>>> (d_size % sizeof(s64)); + + /* Ensure only one copy of this function >>>> running at a time */ + if (atomic_inc_return(&st- protect_ring) >>>> > 1) + return; + + /* Monitor mode prevents reading. >>>> Whilst not currently implemented + * might as well have this >>>> test in here in the meantime as it does + * no harm. + */ + if >>>> (numvals == 0) + return; + + rxbuf = kmalloc(d_size, >>>> GFP_KERNEL); + if (rxbuf == NULL) + return; + + switch (st->id) { >>>> + case ad7991: + case ad7995: + case ad7999: + cmd = >>>> st->config | (st->indio_dev->ring->scan_mask << + >>>> AD799X_CHANNEL_SHIFT); + break; + case ad7992: >>>> + case ad7993: + case ad7994: + cmd = >>>> (st->indio_dev->ring->scan_mask << + >>>> AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG; + break; + case >>>> ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | >>>> AD7998_CONV_RES_REG; + break; + default: + cmd = >>>> 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, >>>> + cmd, numvals*2, rxbuf); + if (b_sent < 0) + >>>> goto done; + + time_ns = iio_get_time_ns(); + + >>>> memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + >>>> indio_dev->ring->access.store_to(&ring->buf, rxbuf, time_ns); >>>> +done: + kfree(rxbuf); + atomic_dec(&st->protect_ring); +} + + >>>> +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) { >>>> + struct ad799x_state *st = indio_dev->dev_data; + int ret >>>> = 0; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + >>>> if (!indio_dev->ring) { + ret = -ENOMEM; + goto >>>> error_ret; + } + /* Effectively select the ring buffer >>>> implementation */ + >>>> iio_ring_sw_register_funcs(&st->indio_dev->ring->access); + >>>> indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), >>>> GFP_KERNEL); + if (indio_dev->pollfunc == NULL) { + ret = >>>> -ENOMEM; + goto error_deallocate_sw_rb; + } + /* >>>> Configure the polling function called on trigger interrupts */ + >>>> indio_dev->pollfunc- poll_func_main = &ad799x_poll_func_th; + >>>> indio_dev->pollfunc->private_data = indio_dev; + + /* Ring buffer >>>> functions - here trigger setup related */ + + >>>> indio_dev->ring->preenable = &ad799x_ring_preenable; + >>>> indio_dev->ring->postenable = &iio_triggered_ring_postenable; + >>>> indio_dev->ring->predisable = &iio_triggered_ring_predisable; + + >>>> INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); + + >>>> indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; + + /* >>>> Flag that polled ring buffering is possible */ + indio_dev- modes >>>> |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + >>>> iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + >>>> +void ad799x_ring_cleanup(struct iio_dev *indio_dev) { + /* ensure >>>> that the trigger has been detached */ + if (indio_dev->trig) { >>>> + iio_put_trigger(indio_dev->trig); + >>>> iio_trigger_dettach_poll_func(indio_dev->trig, + >>>> indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + >>>> iio_sw_rb_free(indio_dev->ring); +} >> >> Greetings, >> Michael >> >> Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen >> Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 >> Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif >> >> Greetings, Michael Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html