summaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio')
-rw-r--r--drivers/staging/iio/Documentation/dac/max51741
-rw-r--r--drivers/staging/iio/Documentation/generic_buffer.c66
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h63
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio81
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs11
-rw-r--r--drivers/staging/iio/Kconfig9
-rw-r--r--drivers/staging/iio/Makefile1
-rw-r--r--drivers/staging/iio/accel/Kconfig23
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h10
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c9
-rw-r--r--drivers/staging/iio/adc/Kconfig35
-rw-r--r--drivers/staging/iio/adc/Makefile11
-rw-r--r--drivers/staging/iio/adc/ad7298.c501
-rw-r--r--drivers/staging/iio/adc/ad7298.h80
-rw-r--r--drivers/staging/iio/adc/ad7298_core.c287
-rw-r--r--drivers/staging/iio/adc/ad7298_ring.c258
-rw-r--r--drivers/staging/iio/adc/ad7476.h1
-rw-r--r--drivers/staging/iio/adc/ad7476_core.c2
-rw-r--r--drivers/staging/iio/adc/ad7476_ring.c37
-rw-r--r--drivers/staging/iio/adc/ad7606.h117
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c556
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c188
-rw-r--r--drivers/staging/iio/adc/ad7606_ring.c280
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c126
-rw-r--r--drivers/staging/iio/adc/ad7887.h1
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c36
-rw-r--r--drivers/staging/iio/adc/ad799x.h1
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c12
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c43
-rw-r--r--drivers/staging/iio/dac/Kconfig15
-rw-r--r--drivers/staging/iio/dac/Makefile1
-rw-r--r--drivers/staging/iio/dac/ad5446.c193
-rw-r--r--drivers/staging/iio/dac/ad5446.h24
-rw-r--r--drivers/staging/iio/dac/ad5624r.h89
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c247
-rw-r--r--drivers/staging/iio/dac/max517.c298
-rw-r--r--drivers/staging/iio/dac/max517.h19
-rw-r--r--drivers/staging/iio/dds/Kconfig5
-rw-r--r--drivers/staging/iio/dds/ad9832.c488
-rw-r--r--drivers/staging/iio/dds/ad9832.h128
-rw-r--r--drivers/staging/iio/gyro/Kconfig14
-rw-r--r--drivers/staging/iio/gyro/adis16060.h101
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c178
-rw-r--r--drivers/staging/iio/gyro/adis16080.h102
-rw-r--r--drivers/staging/iio/gyro/adis16080_core.c163
-rw-r--r--drivers/staging/iio/gyro/adis16130.h108
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c207
-rw-r--r--drivers/staging/iio/gyro/adis16251.h185
-rw-r--r--drivers/staging/iio/gyro/adis16251_core.c777
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c49
-rw-r--r--drivers/staging/iio/industrialio-ring.c25
-rw-r--r--drivers/staging/iio/kfifo_buf.c196
-rw-r--r--drivers/staging/iio/kfifo_buf.h56
-rw-r--r--drivers/staging/iio/meter/ade7753.c208
-rw-r--r--drivers/staging/iio/meter/ade7753.h64
-rw-r--r--drivers/staging/iio/meter/ade7754.c165
-rw-r--r--drivers/staging/iio/meter/ade7754.h67
-rw-r--r--drivers/staging/iio/meter/ade7759.c165
-rw-r--r--drivers/staging/iio/meter/ade7759.h65
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c120
-rw-r--r--drivers/staging/iio/meter/ade7854.c78
-rw-r--r--drivers/staging/iio/meter/ade7854.h69
-rw-r--r--drivers/staging/iio/ring_generic.h2
-rw-r--r--drivers/staging/iio/ring_sw.c27
-rw-r--r--drivers/staging/iio/ring_sw.h4
-rw-r--r--drivers/staging/iio/trigger/Kconfig20
-rw-r--r--drivers/staging/iio/trigger/Makefile2
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c252
-rw-r--r--drivers/staging/iio/trigger/iio-trig-sysfs.c108
69 files changed, 4522 insertions, 3448 deletions
diff --git a/drivers/staging/iio/Documentation/dac/max517 b/drivers/staging/iio/Documentation/dac/max517
new file mode 100644
index 000000000000..e60ec2f91a7a
--- /dev/null
+++ b/drivers/staging/iio/Documentation/dac/max517
@@ -0,0 +1,41 @@
+Kernel driver max517
+====================
+
+Supported chips:
+ * Maxim MAX517, MAX518, MAX519
+ Prefix: 'max517'
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/
+
+Author:
+ Roland Stigge <stigge@antcom.de>
+
+Description
+-----------
+
+The Maxim MAX517/518/519 is an 8-bit DAC on the I2C bus. The following table
+shows the different feature sets of the variants MAX517, MAX518 and MAX519:
+
+Feature MAX517 MAX518 MAX519
+--------------------------------------------------------------------------
+One output channel X
+Two output channels X X
+Simultaneous output updates X X
+Supply voltage as reference X
+Separate reference input X
+Reference input for each DAC X
+
+Via the iio sysfs interface, there are three attributes available: out1_raw,
+out2_raw and out12_raw. With out1_raw and out2_raw, the current output values
+(0..255) of the DACs can be written to the device. out12_raw can be used to set
+both output channel values simultaneously.
+
+With MAX517, only out1_raw is available.
+
+Via out1_scale (and where appropriate, out2_scale), the current scaling factor
+in mV can be read.
+
+When the operating system goes to a power down state, the Power Down function
+of the chip is activated, reducing the supply current to 4uA.
+
+On power-up, the device is in 0V-output state.
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index df23aeb9d529..3cc18ab4ebfd 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -26,11 +26,9 @@
#include <sys/stat.h>
#include <sys/dir.h>
#include <linux/types.h>
+#include <string.h>
#include "iio_utils.h"
-const int buf_len = 128;
-const int num_loops = 2;
-
/**
* size_from_channelarray() - calculate the storage size of a scan
* @channels: the channel info array
@@ -118,6 +116,11 @@ void process_scan(char *data,
int main(int argc, char **argv)
{
+ unsigned long num_loops = 2;
+ unsigned long timedelay = 1000000;
+ unsigned long buf_len = 128;
+
+
int ret, c, i, j, toread;
FILE *fp_ev;
@@ -134,10 +137,12 @@ int main(int argc, char **argv)
int dev_num, trig_num;
char *buffer_access, *buffer_event;
int scan_size;
+ int noevents = 0;
+ char *dummy;
struct iio_channel_info *infoarray;
- while ((c = getopt(argc, argv, "t:n:")) != -1) {
+ while ((c = getopt(argc, argv, "l:w:c:et:n:")) != -1) {
switch (c) {
case 'n':
device_name = optarg;
@@ -146,11 +151,26 @@ int main(int argc, char **argv)
trigger_name = optarg;
datardytrigger = 0;
break;
+ case 'e':
+ noevents = 1;
+ break;
+ case 'c':
+ num_loops = strtoul(optarg, &dummy, 10);
+ break;
+ case 'w':
+ timedelay = strtoul(optarg, &dummy, 10);
+ break;
+ case 'l':
+ buf_len = strtoul(optarg, &dummy, 10);
+ break;
case '?':
return -1;
}
}
+ if (device_name == NULL)
+ return -1;
+
/* Find the device requested */
dev_num = find_type_by_name(device_name, "device");
if (dev_num < 0) {
@@ -260,22 +280,30 @@ int main(int argc, char **argv)
/* Wait for events 10 times */
for (j = 0; j < num_loops; j++) {
- read_size = fread(&dat, 1, sizeof(struct iio_event_data),
- fp_ev);
- switch (dat.id) {
- case IIO_EVENT_CODE_RING_100_FULL:
- toread = buf_len;
- break;
- case IIO_EVENT_CODE_RING_75_FULL:
- toread = buf_len*3/4;
- break;
- case IIO_EVENT_CODE_RING_50_FULL:
- toread = buf_len/2;
- break;
- default:
- printf("Unexpecteded event code\n");
- continue;
+ if (!noevents) {
+ read_size = fread(&dat,
+ 1,
+ sizeof(struct iio_event_data),
+ fp_ev);
+ switch (dat.id) {
+ case IIO_EVENT_CODE_RING_100_FULL:
+ toread = buf_len;
+ break;
+ case IIO_EVENT_CODE_RING_75_FULL:
+ toread = buf_len*3/4;
+ break;
+ case IIO_EVENT_CODE_RING_50_FULL:
+ toread = buf_len/2;
+ break;
+ default:
+ printf("Unexpecteded event code\n");
+ continue;
+ }
+ } else {
+ usleep(timedelay);
+ toread = 64;
}
+
read_size = read(fp,
data,
toread*scan_size);
diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h
index 03724246b95a..8095727b3966 100644
--- a/drivers/staging/iio/Documentation/iio_utils.h
+++ b/drivers/staging/iio/Documentation/iio_utils.h
@@ -51,7 +51,7 @@ static int iioutils_break_up_name(const char *full_name,
w = working;
r = working;
- while(*r != '\0') {
+ while (*r != '\0') {
if (!isdigit(*r)) {
*w = *r;
w++;
@@ -113,7 +113,7 @@ inline int iioutils_get_type(unsigned *is_signed,
DIR *dp;
char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
char signchar;
- unsigned sizeint, padint;
+ unsigned padint;
const struct dirent *ent;
ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
@@ -159,7 +159,7 @@ inline int iioutils_get_type(unsigned *is_signed,
fscanf(sysfsfp,
"%c%u/%u", &signchar, bits_used, &padint);
*bytes = padint / 8;
- if (sizeint == 64)
+ if (*bits_used == 64)
*mask = ~0;
else
*mask = (1 << *bits_used) - 1;
@@ -242,6 +242,26 @@ error_ret:
return ret;
}
+/**
+ * bsort_channel_array_by_index() - reorder so that the array is in index order
+ *
+ **/
+
+inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
+ int cnt)
+{
+
+ struct iio_channel_info temp;
+ int x, y;
+
+ for (x = 0; x < cnt; x++)
+ for (y = 0; y < (cnt - 1); y++)
+ if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
+ temp = (*ci_array)[y + 1];
+ (*ci_array)[y + 1] = (*ci_array)[y];
+ (*ci_array)[y] = temp;
+ }
+}
/**
* build_channel_array() - function to figure out what channels are present
@@ -254,7 +274,7 @@ inline int build_channel_array(const char *device_dir,
{
DIR *dp;
FILE *sysfsfp;
- int count = 0, temp, i;
+ int count, temp, i;
struct iio_channel_info *current;
int ret;
const struct dirent *ent;
@@ -293,12 +313,13 @@ inline int build_channel_array(const char *device_dir,
fclose(sysfsfp);
free(filename);
}
- *ci_array = malloc(sizeof(**ci_array)*(*counter));
+ *ci_array = malloc(sizeof(**ci_array) * (*counter));
if (*ci_array == NULL) {
ret = -ENOMEM;
goto error_close_dir;
}
seekdir(dp, 0);
+ count = 0;
while (ent = readdir(dp), ent != NULL) {
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) {
@@ -319,7 +340,13 @@ inline int build_channel_array(const char *device_dir,
}
fscanf(sysfsfp, "%u", &current->enabled);
fclose(sysfsfp);
- free(filename);
+
+ if (!current->enabled) {
+ free(filename);
+ count--;
+ continue;
+ }
+
current->scale = 1.0;
current->offset = 0;
current->name = strndup(ent->d_name,
@@ -374,31 +401,15 @@ inline int build_channel_array(const char *device_dir,
current->generic_name);
}
}
- /* reorder so that the array is in index order*/
- current = malloc(sizeof(**ci_array)**counter);
- if (current == NULL) {
- ret = -ENOMEM;
- goto error_cleanup_array;
- }
+
closedir(dp);
- count = 0;
- temp = 0;
- while (count < *counter)
- for (i = 0; i < *counter; i++)
- if ((*ci_array)[i].index == temp) {
- memcpy(&current[count++],
- &(*ci_array)[i],
- sizeof(*current));
- temp++;
- break;
- }
- free(*ci_array);
- *ci_array = current;
+ /* reorder so that the array is in index order */
+ bsort_channel_array_by_index(ci_array, *counter);
return 0;
error_cleanup_array:
- for (i = count - 1; i >= 0; i++)
+ for (i = count - 1; i >= 0; i--)
free((*ci_array)[i].name);
free(*ci_array);
error_close_dir:
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio
index 2dde97de75f8..4915aee14d88 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio
@@ -53,6 +53,31 @@ Description:
When the internal sampling clock can only take a small
discrete set of values, this file lists those available.
+What: /sys/bus/iio/devices/deviceX/range
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware dependent ADC Full Scale Range in mVolt.
+
+What: /sys/bus/iio/devices/deviceX/range_available
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware dependent supported vales for ADC Full Scale Range.
+
+What: /sys/bus/iio/devices/deviceX/oversampling_ratio
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware dependent ADC oversampling. Controls the sampling ratio
+ of the digital filter if available.
+
+What: /sys/bus/iio/devices/deviceX/oversampling_ratio_available
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware dependent values supported by the oversampling filter.
+
What: /sys/bus/iio/devices/deviceX/inY_raw
What: /sys/bus/iio/devices/deviceX/inY_supply_raw
KernelVersion: 2.6.35
@@ -86,6 +111,12 @@ Description:
sensor is associated with one part of a compound device (e.g.
a gyroscope axis).
+What: /sys/bus/iio/devices/deviceX/tempX_input
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Scaled temperature measurement in milli degrees Celsius.
+
What: /sys/bus/iio/devices/deviceX/accel_x_raw
What: /sys/bus/iio/devices/deviceX/accel_y_raw
What: /sys/bus/iio/devices/deviceX/accel_z_raw
@@ -168,6 +199,7 @@ Description:
What: /sys/bus/iio/devices/deviceX/inY_scale
What: /sys/bus/iio/devices/deviceX/inY_supply_scale
What: /sys/bus/iio/devices/deviceX/in_scale
+What: /sys/bus/iio/devices/deviceX/outY_scale
What: /sys/bus/iio/devices/deviceX/accel_scale
What: /sys/bus/iio/devices/deviceX/accel_peak_scale
What: /sys/bus/iio/devices/deviceX/gyro_scale
@@ -222,6 +254,55 @@ Description:
If a discrete set of scale values are available, they
are listed in this attribute.
+What: /sys/bus/iio/devices/deviceX/outY_raw
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled, no bias etc.) output voltage for
+ channel Y. The number must always be specified and
+ unique if the output corresponds to a single channel.
+
+What: /sys/bus/iio/devices/deviceX/outY&Z_raw
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled, no bias etc.) output voltage for an aggregate of
+ channel Y, channel Z, etc. This interface is available in cases
+ where a single output sets the value for multiple channels
+ simultaneously.
+
+What: /sys/bus/iio/devices/deviceX/outY_powerdown_mode
+What: /sys/bus/iio/devices/deviceX/out_powerdown_mode
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specifies the output powerdown mode.
+ DAC output stage is disconnected from the amplifier and
+ 1kohm_to_gnd: connected to ground via an 1kOhm resistor
+ 100kohm_to_gnd: connected to ground via an 100kOhm resistor
+ three_state: left floating
+ For a list of available output power down options read
+ outX_powerdown_mode_available. If Y is not present the
+ mode is shared across all outputs.
+
+What: /sys/bus/iio/devices/deviceX/outY_powerdown_mode_available
+What: /sys/bus/iio/devices/deviceX/out_powerdown_mode_available
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Lists all available output power down modes.
+ If Y is not present the mode is shared across all outputs.
+
+What: /sys/bus/iio/devices/deviceX/outY_powerdown
+What: /sys/bus/iio/devices/deviceX/out_powerdown
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ Writing 1 causes output Y to enter the power down mode specified
+ by the corresponding outY_powerdown_mode. Clearing returns to
+ normal operation. Y may be suppressed if all outputs are
+ controlled together.
+
What: /sys/bus/iio/devices/deviceX/deviceX:eventY
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs b/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs
new file mode 100644
index 000000000000..5235e6c749ab
--- /dev/null
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs
@@ -0,0 +1,11 @@
+What: /sys/bus/iio/devices/triggerX/trigger_now
+KernelVersion: 2.6.38
+Contact: linux-iio@vger.kernel.org
+Description:
+ This file is provided by the iio-trig-sysfs stand-alone trigger
+ driver. Writing this file with any value triggers an event
+ driven driver, associated with this trigger, to capture data
+ into an in kernel buffer. This approach can be valuable during
+ automated testing or in situations, where other trigger methods
+ are not applicable. For example no RTC or spare GPIOs.
+ X is the IIO index of the trigger.
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index e2ac07d86110..6775bf90e2f1 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -29,6 +29,15 @@ config IIO_SW_RING
with the intention that some devices would be able to write
in interrupt context.
+config IIO_KFIFO_BUF
+ select IIO_TRIGGER
+ tristate "Industrial I/O buffering based on kfifo"
+ help
+ A simple fifo based on kfifo. Use this if you want a fifo
+ rather than a ring buffer. Note that this currently provides
+ no buffer events so it is up to userspace to work out how
+ often to read from the buffer.
+
endif # IIO_RINGBUFFER
config IIO_TRIGGER
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index f9b5fb2fe8f1..bb5c95c7d694 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -8,6 +8,7 @@ industrialio-$(CONFIG_IIO_RING_BUFFER) += industrialio-ring.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/
obj-y += adc/
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index a34f1d3e673c..81a33b60512b 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -66,12 +66,33 @@ config LIS3L02DQ
tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
depends on SPI
select IIO_TRIGGER if IIO_RING_BUFFER
- select IIO_SW_RING if IIO_RING_BUFFER
+ depends on !IIO_RING_BUFFER || IIO_KFIFO_BUF || IIO_SW_RING
help
Say yes here to build SPI support for the ST microelectronics
accelerometer. The driver supplies direct access via sysfs files
and an event interface via a character device.
+choice
+ prompt "Buffer type"
+ depends on LIS3L02DQ && IIO_RING_BUFFER
+
+config LIS3L02DQ_BUF_KFIFO
+ depends on IIO_KFIFO_BUF
+ bool "Simple FIFO"
+ help
+ Kfifo based FIFO. Does not provide any events so it is up
+ to userspace to ensure it reads often enough that data is not
+ lost.
+
+config LIS3L02DQ_BUF_RING_SW
+ depends on IIO_SW_RING
+ bool "IIO Software Ring"
+ help
+ Original IIO ring buffer implementation. Provides simple
+ buffer events, half full etc.
+
+endchoice
+
config SCA3000
depends on IIO_RING_BUFFER
depends on SPI
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index 6e730553fca8..579b3a26e5d7 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -196,6 +196,16 @@ ssize_t lis3l02dq_read_accel_from_ring(struct device *dev,
int lis3l02dq_configure_ring(struct iio_dev *indio_dev);
void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev);
+#ifdef CONFIG_LIS3L02DQ_BUF_RING_SW
+#define lis3l02dq_free_buf iio_sw_rb_free
+#define lis3l02dq_alloc_buf iio_sw_rb_allocate
+#define lis3l02dq_register_buf_funcs iio_ring_sw_register_funcs
+#endif
+#ifdef CONFIG_LIS3L02DQ_BUF_KFIFO
+#define lis3l02dq_free_buf iio_kfifo_free
+#define lis3l02dq_alloc_buf iio_kfifo_allocate
+#define lis3l02dq_register_buf_funcs iio_kfifo_register_funcs
+#endif
#else /* CONFIG_IIO_RING_BUFFER */
static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 1fd088a11076..2c461a31f129 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -13,6 +13,7 @@
#include "../iio.h"
#include "../sysfs.h"
#include "../ring_sw.h"
+#include "../kfifo_buf.h"
#include "accel.h"
#include "../trigger.h"
#include "lis3l02dq.h"
@@ -484,7 +485,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev)
{
kfree(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->ring);
+ lis3l02dq_free_buf(indio_dev->ring);
}
int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
@@ -495,13 +496,13 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
INIT_WORK(&h->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring);
h->get_ring_element = &lis3l02dq_get_ring_element;
- ring = iio_sw_rb_allocate(indio_dev);
+ ring = lis3l02dq_alloc_buf(indio_dev);
if (!ring)
return -ENOMEM;
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
- iio_ring_sw_register_funcs(&ring->access);
+ lis3l02dq_register_buf_funcs(&ring->access);
ring->bpe = 2;
ring->scan_el_attrs = &lis3l02dq_scan_el_group;
ring->scan_timestamp = true;
@@ -522,6 +523,6 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
return 0;
error_iio_sw_rb_free:
- iio_sw_rb_free(indio_dev->ring);
+ lis3l02dq_free_buf(indio_dev->ring);
return ret;
}
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 86869cd233ae..6692a3d87f23 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -49,11 +49,14 @@ config AD7291
temperature sensors.
config AD7298
- tristate "Analog Devices AD7298 temperature sensor and ADC driver"
+ tristate "Analog Devices AD7298 ADC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7298
- temperature sensors and ADC.
+ 8 Channel ADC with temperature sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7298.
config AD7314
tristate "Analog Devices AD7314 temperature sensor driver"
@@ -62,6 +65,34 @@ config AD7314
Say yes here to build support for Analog Devices AD7314
temperature sensors.
+config AD7606
+ tristate "Analog Devices AD7606 ADC driver"
+ depends on GPIOLIB
+ select IIO_RING_BUFFER
+ select IIO_TRIGGER
+ select IIO_SW_RING
+ help
+ Say yes here to build support for Analog Devices:
+ ad7606, ad7606-6, ad7606-4 analog to digital convertors (ADC).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7606.
+
+config AD7606_IFACE_PARALLEL
+ tristate "parallel interface support"
+ depends on AD7606
+ help
+ Say yes here to include parallel interface support on the AD7606
+ ADC driver.
+
+config AD7606_IFACE_SPI
+ tristate "spi interface support"
+ depends on AD7606
+ depends on SPI
+ help
+ Say yes here to include parallel interface support on the AD7606
+ ADC driver.
+
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index 6f231a2cb777..31067defd79b 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -7,6 +7,12 @@ max1363-y += max1363_ring.o
obj-$(CONFIG_MAX1363) += max1363.o
+ad7606-y := ad7606_core.o
+ad7606-$(CONFIG_IIO_RING_BUFFER) += ad7606_ring.o
+ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
+ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
+obj-$(CONFIG_AD7606) += ad7606.o
+
ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
obj-$(CONFIG_AD799X) += ad799x.o
@@ -19,10 +25,13 @@ ad7887-y := ad7887_core.o
ad7887-$(CONFIG_IIO_RING_BUFFER) += ad7887_ring.o
obj-$(CONFIG_AD7887) += ad7887.o
+ad7298-y := ad7298_core.o
+ad7298-$(CONFIG_IIO_RING_BUFFER) += ad7298_ring.o
+obj-$(CONFIG_AD7298) += ad7298.o
+
obj-$(CONFIG_AD7150) += ad7150.o
obj-$(CONFIG_AD7152) += ad7152.o
obj-$(CONFIG_AD7291) += ad7291.o
-obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7314) += ad7314.o
obj-$(CONFIG_AD7745) += ad7745.o
obj-$(CONFIG_AD7816) += ad7816.o
diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c
deleted file mode 100644
index 1a080c977637..000000000000
--- a/drivers/staging/iio/adc/ad7298.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * AD7298 digital temperature sensor driver supporting AD7298
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/spi/spi.h>
-#include <linux/rtc.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-/*
- * AD7298 command
- */
-#define AD7298_PD 0x1
-#define AD7298_T_AVG_MASK 0x2
-#define AD7298_EXT_REF 0x4
-#define AD7298_T_SENSE_MASK 0x20
-#define AD7298_VOLTAGE_MASK 0x3fc0
-#define AD7298_VOLTAGE_OFFSET 0x6
-#define AD7298_VOLTAGE_LIMIT_COUNT 8
-#define AD7298_REPEAT 0x40
-#define AD7298_WRITE 0x80
-
-/*
- * AD7298 value masks
- */
-#define AD7298_CHANNEL_MASK 0xf000
-#define AD7298_VALUE_MASK 0xfff
-#define AD7298_T_VALUE_SIGN 0x400
-#define AD7298_T_VALUE_FLOAT_OFFSET 2
-#define AD7298_T_VALUE_FLOAT_MASK 0x2
-
-/*
- * struct ad7298_chip_info - chip specifc information
- */
-
-struct ad7298_chip_info {
- const char *name;
- struct spi_device *spi_dev;
- struct iio_dev *indio_dev;
- u16 command;
- u16 busy_pin;
- u8 channels; /* Active voltage channels */
-};
-
-/*
- * ad7298 register access by SPI
- */
-static int ad7298_spi_write(struct ad7298_chip_info *chip, u16 data)
-{
- struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
-
- data |= AD7298_WRITE;
- data = cpu_to_be16(data);
- ret = spi_write(spi_dev, (u8 *)&data, sizeof(data));
- if (ret < 0)
- dev_err(&spi_dev->dev, "SPI write error\n");
-
- return ret;
-}
-
-static int ad7298_spi_read(struct ad7298_chip_info *chip, u16 mask, u16 *data)
-{
- struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
- u8 count = chip->channels;
- u16 command;
- int i;
-
- if (mask & AD7298_T_SENSE_MASK) {
- command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_VOLTAGE_MASK);
- command |= AD7298_T_SENSE_MASK;
- count = 1;
- } else if (mask & AD7298_T_AVG_MASK) {
- command = chip->command & ~AD7298_VOLTAGE_MASK;
- command |= AD7298_T_SENSE_MASK | AD7298_T_AVG_MASK;
- count = 2;
- } else if (mask & AD7298_VOLTAGE_MASK) {
- command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_T_SENSE_MASK);
- count = chip->channels;
- }
-
- ret = ad7298_spi_write(chip, chip->command);
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI write command error\n");
- return ret;
- }
-
- ret = spi_read(spi_dev, (u8 *)&command, sizeof(command));
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI read error\n");
- return ret;
- }
-
- i = 10000;
- while (i && gpio_get_value(chip->busy_pin)) {
- cpu_relax();
- i--;
- }
- if (!i) {
- dev_err(&spi_dev->dev, "Always in busy convertion.\n");
- return -EBUSY;
- }
-
- for (i = 0; i < count; i++) {
- ret = spi_read(spi_dev, (u8 *)&data[i], sizeof(data[i]));
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI read error\n");
- return ret;
- }
- *data = be16_to_cpu(data[i]);
- }
-
- return 0;
-}
-
-static ssize_t ad7298_show_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- if (chip->command & AD7298_REPEAT)
- return sprintf(buf, "repeat\n");
- else
- return sprintf(buf, "normal\n");
-}
-
-static ssize_t ad7298_store_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- if (strcmp(buf, "repeat"))
- chip->command |= AD7298_REPEAT;
- else
- chip->command &= (~AD7298_REPEAT);
-
- return 1;
-}
-
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
- ad7298_show_mode,
- ad7298_store_mode,
- 0);
-
-static ssize_t ad7298_show_available_modes(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "normal\nrepeat\n");
-}
-
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7298_show_available_modes, NULL, 0);
-
-static ssize_t ad7298_store_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 command;
- int ret;
-
- command = chip->command & ~AD7298_PD;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- command = chip->command | AD7298_PD;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
- NULL,
- ad7298_store_reset,
- 0);
-
-static ssize_t ad7298_show_ext_ref(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- return sprintf(buf, "%d\n", !!(chip->command & AD7298_EXT_REF));
-}
-
-static ssize_t ad7298_store_ext_ref(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 command;
- int ret;
-
- command = chip->command & (~AD7298_EXT_REF);
- if (strcmp(buf, "1"))
- command |= AD7298_EXT_REF;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- chip->command = command;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
- ad7298_show_ext_ref,
- ad7298_store_ext_ref,
- 0);
-
-static ssize_t ad7298_show_t_sense(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data;
- char sign = ' ';
- int ret;
-
- ret = ad7298_spi_read(chip, AD7298_T_SENSE_MASK, &data);
- if (ret)
- return -EIO;
-
- if (data & AD7298_T_VALUE_SIGN) {
- /* convert supplement to positive value */
- data = (AD7298_T_VALUE_SIGN << 1) - data;
- sign = '-';
- }
-
- return sprintf(buf, "%c%d.%.2d\n", sign,
- (data >> AD7298_T_VALUE_FLOAT_OFFSET),
- (data & AD7298_T_VALUE_FLOAT_MASK) * 25);
-}
-
-static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7298_show_t_sense, NULL, 0);
-
-static ssize_t ad7298_show_t_average(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data[2];
- char sign = ' ';
- int ret;
-
- ret = ad7298_spi_read(chip, AD7298_T_AVG_MASK, data);
- if (ret)
- return -EIO;
-
- if (data[1] & AD7298_T_VALUE_SIGN) {
- /* convert supplement to positive value */
- data[1] = (AD7298_T_VALUE_SIGN << 1) - data[1];
- sign = '-';
- }
-
- return sprintf(buf, "%c%d.%.2d\n", sign,
- (data[1] >> AD7298_T_VALUE_FLOAT_OFFSET),
- (data[1] & AD7298_T_VALUE_FLOAT_MASK) * 25);
-}
-
-static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7298_show_t_average, NULL, 0);
-
-static ssize_t ad7298_show_voltage(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data[AD7298_VOLTAGE_LIMIT_COUNT];
- int i, size, ret;
-
- ret = ad7298_spi_read(chip, AD7298_VOLTAGE_MASK, data);
- if (ret)
- return -EIO;
-
- for (i = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
- if (chip->command & (AD7298_T_SENSE_MASK << i)) {
- ret = sprintf(buf, "channel[%d]=%d\n", i,
- data[i] & AD7298_VALUE_MASK);
- if (ret < 0)
- break;
- buf += ret;
- size += ret;
- }
- }
-
- return size;
-}
-
-static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7298_show_voltage, NULL, 0);
-
-static ssize_t ad7298_show_channel_mask(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- return sprintf(buf, "0x%x\n", (chip->command & AD7298_VOLTAGE_MASK) >>
- AD7298_VOLTAGE_OFFSET);
-}
-
-static ssize_t ad7298_store_channel_mask(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- unsigned long data;
- int i, ret;
-
- ret = strict_strtoul(buf, 16, &data);
- if (ret || data > 0xff)
- return -EINVAL;
-
- chip->command &= (~AD7298_VOLTAGE_MASK);
- chip->command |= data << AD7298_VOLTAGE_OFFSET;
-
- for (i = 0, chip->channels = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
- if (chip->command & (AD7298_T_SENSE_MASK << i))
- chip->channels++;
- }
-
- return ret;
-}
-
-static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
- ad7298_show_channel_mask,
- ad7298_store_channel_mask,
- 0);
-
-static ssize_t ad7298_show_name(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- return sprintf(buf, "%s\n", chip->name);
-}
-
-static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
-
-static struct attribute *ad7298_attributes[] = {
- &iio_dev_attr_available_modes.dev_attr.attr,
- &iio_dev_attr_mode.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
- &iio_dev_attr_ext_ref.dev_attr.attr,
- &iio_dev_attr_t_sense.dev_attr.attr,
- &iio_dev_attr_t_average.dev_attr.attr,
- &iio_dev_attr_voltage.dev_attr.attr,
- &iio_dev_attr_channel_mask.dev_attr.attr,
- &iio_dev_attr_name.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad7298_attribute_group = {
- .attrs = ad7298_attributes,
-};
-
-/*
- * device probe and remove
- */
-static int __devinit ad7298_probe(struct spi_device *spi_dev)
-{
- struct ad7298_chip_info *chip;
- unsigned short *pins = spi_dev->dev.platform_data;
- int ret = 0;
-
- chip = kzalloc(sizeof(struct ad7298_chip_info), GFP_KERNEL);
-
- if (chip == NULL)
- return -ENOMEM;
-
- /* this is only used for device removal purposes */
- dev_set_drvdata(&spi_dev->dev, chip);
-
- chip->spi_dev = spi_dev;
- chip->name = spi_dev->modalias;
- chip->busy_pin = pins[0];
-
- ret = gpio_request(chip->busy_pin, chip->name);
- if (ret) {
- dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
- chip->busy_pin);
- goto error_free_chip;
- }
- gpio_direction_input(chip->busy_pin);
-
- chip->indio_dev = iio_allocate_device();
- if (chip->indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_free_gpio;
- }
-
- chip->indio_dev->dev.parent = &spi_dev->dev;
- chip->indio_dev->attrs = &ad7298_attribute_group;
- chip->indio_dev->dev_data = (void *)chip;
- chip->indio_dev->driver_module = THIS_MODULE;
- chip->indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = iio_device_register(chip->indio_dev);
- if (ret)
- goto error_free_dev;
-
- dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
- chip->name);
-
- return 0;
-
-error_free_dev:
- iio_free_device(chip->indio_dev);
-error_free_gpio:
- gpio_free(chip->busy_pin);
-error_free_chip:
- kfree(chip);
-
- return ret;
-}
-
-static int __devexit ad7298_remove(struct spi_device *spi_dev)
-{
- struct ad7298_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
- struct iio_dev *indio_dev = chip->indio_dev;
-
- dev_set_drvdata(&spi_dev->dev, NULL);
- iio_device_unregister(indio_dev);
- iio_free_device(chip->indio_dev);
- gpio_free(chip->busy_pin);
- kfree(chip);
-
- return 0;
-}
-
-static const struct spi_device_id ad7298_id[] = {
- { "ad7298", 0 },
- {}
-};
-
-MODULE_DEVICE_TABLE(spi, ad7298_id);
-
-static struct spi_driver ad7298_driver = {
- .driver = {
- .name = "ad7298",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = ad7298_probe,
- .remove = __devexit_p(ad7298_remove),
- .id_table = ad7298_id,
-};
-
-static __init int ad7298_init(void)
-{
- return spi_register_driver(&ad7298_driver);
-}
-
-static __exit void ad7298_exit(void)
-{
- spi_unregister_driver(&ad7298_driver);
-}
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7298 digital"
- " temperature sensor and ADC driver");
-MODULE_LICENSE("GPL v2");
-
-module_init(ad7298_init);
-module_exit(ad7298_exit);
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
new file mode 100644
index 000000000000..fe7ed77d638f
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -0,0 +1,80 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_ADC_AD7298_H_
+#define IIO_ADC_AD7298_H_
+
+#define AD7298_WRITE (1 << 15) /* write to the control register */
+#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
+#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
+#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
+#define AD7298_EXTREF (1 << 2) /* external reference enable */
+#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
+#define AD7298_PDD (1 << 0) /* partial power down enable */
+
+#define AD7298_CH_MASK (AD7298_CH0 | AD7298_CH1 | AD7298_CH2 | AD7298_CH3 | \
+ AD7298_CH4 | AD7298_CH5 | AD7298_CH6 | AD7298_CH7)
+
+#define AD7298_MAX_CHAN 8
+#define AD7298_BITS 12
+#define AD7298_STORAGE_BITS 16
+#define AD7298_INTREF_mV 2500
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/*
+ * TODO: struct ad7298_platform_data needs to go into include/linux/iio
+ */
+
+struct ad7298_platform_data {
+ /* External Vref voltage applied */
+ u16 vref_mv;
+};
+
+struct ad7298_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ atomic_t protect_ring;
+ size_t d_size;
+ u16 int_vref_mv;
+ unsigned ext_ref;
+ struct spi_transfer ring_xfer[10];
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message ring_msg;
+ struct spi_message scan_single_msg;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned short rx_buf[8] ____cacheline_aligned;
+ unsigned short tx_buf[2];
+};
+
+#ifdef CONFIG_IIO_RING_BUFFER
+int ad7298_scan_from_ring(struct ad7298_state *st, long ch);
+int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev);
+void ad7298_ring_cleanup(struct iio_dev *indio_dev);
+#else /* CONFIG_IIO_RING_BUFFER */
+static inline int ad7298_scan_from_ring(struct ad7298_state *st, long ch)
+{
+ return 0;
+}
+
+static inline int
+ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void ad7298_ring_cleanup(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* IIO_ADC_AD7298_H_ */
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
new file mode 100644
index 000000000000..2e9154e7d887
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -0,0 +1,287 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "adc.h"
+
+#include "ad7298.h"
+
+static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
+{
+ int ret;
+ st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref |
+ (AD7298_CH(0) >> ch));
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret)
+ return ret;
+
+ return be16_to_cpu(st->rx_buf[0]);
+}
+
+static ssize_t ad7298_scan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+
+ mutex_lock(&dev_info->mlock);
+ if (iio_ring_enabled(dev_info))
+ ret = ad7298_scan_from_ring(st, this_attr->address);
+ else
+ ret = ad7298_scan_direct(st, this_attr->address);
+ mutex_unlock(&dev_info->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret & RES_MASK(AD7298_BITS));
+}
+
+static IIO_DEV_ATTR_IN_RAW(0, ad7298_scan, 0);
+static IIO_DEV_ATTR_IN_RAW(1, ad7298_scan, 1);
+static IIO_DEV_ATTR_IN_RAW(2, ad7298_scan, 2);
+static IIO_DEV_ATTR_IN_RAW(3, ad7298_scan, 3);
+static IIO_DEV_ATTR_IN_RAW(4, ad7298_scan, 4);
+static IIO_DEV_ATTR_IN_RAW(5, ad7298_scan, 5);
+static IIO_DEV_ATTR_IN_RAW(6, ad7298_scan, 6);
+static IIO_DEV_ATTR_IN_RAW(7, ad7298_scan, 7);
+
+static ssize_t ad7298_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+ int tmp;
+
+ tmp = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
+ AD7298_TAVG | st->ext_ref);
+
+ mutex_lock(&dev_info->mlock);
+ spi_write(st->spi, (u8 *)&tmp, 2);
+ tmp = 0;
+ spi_write(st->spi, (u8 *)&tmp, 2);
+ usleep_range(101, 1000); /* sleep > 100us */
+ spi_read(st->spi, (u8 *)&tmp, 2);
+ mutex_unlock(&dev_info->mlock);
+
+ tmp = be16_to_cpu(tmp) & RES_MASK(AD7298_BITS);
+
+ /*
+ * One LSB of the ADC corresponds to 0.25 deg C.
+ * The temperature reading is in 12-bit twos complement format
+ */
+
+ if (tmp & (1 << (AD7298_BITS - 1))) {
+ tmp = (4096 - tmp) * 250;
+ tmp -= (2 * tmp);
+
+ } else {
+ tmp *= 250; /* temperature in milli degrees Celsius */
+ }
+
+ return sprintf(buf, "%d\n", tmp);
+}
+
+static IIO_DEVICE_ATTR(temp0_input, S_IRUGO, ad7298_show_temp, NULL, 0);
+
+static ssize_t ad7298_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7298_show_scale, NULL, 0);
+
+static ssize_t ad7298_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
+
+static struct attribute *ad7298_attributes[] = {
+ &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_in_scale.dev_attr.attr,
+ &iio_dev_attr_temp0_input.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7298_attribute_group = {
+ .attrs = ad7298_attributes,
+};
+
+static int __devinit ad7298_probe(struct spi_device *spi)
+{
+ struct ad7298_platform_data *pdata = spi->dev.platform_data;
+ struct ad7298_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ spi_set_drvdata(spi, st);
+
+ atomic_set(&st->protect_ring, 0);
+ st->spi = spi;
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad7298_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default message */
+
+ st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
+ st->scan_single_xfer[0].len = 2;
+ st->scan_single_xfer[0].cs_change = 1;
+ st->scan_single_xfer[1].tx_buf = &st->tx_buf[1];
+ st->scan_single_xfer[1].len = 2;
+ st->scan_single_xfer[1].cs_change = 1;
+ st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[2].len = 2;
+
+ spi_message_init(&st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
+
+ if (pdata && pdata->vref_mv) {
+ st->int_vref_mv = pdata->vref_mv;
+ st->ext_ref = AD7298_EXTREF;
+ } else {
+ st->int_vref_mv = AD7298_INTREF_mV;
+ }
+
+ ret = ad7298_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_free_device;
+
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
+ if (ret)
+ goto error_cleanup_ring;
+ return 0;
+
+error_cleanup_ring:
+ ad7298_ring_cleanup(st->indio_dev);
+ iio_device_unregister(st->indio_dev);
+error_free_device:
+ iio_free_device(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 int __devexit ad7298_remove(struct spi_device *spi)
+{
+ struct ad7298_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ iio_ring_buffer_unregister(indio_dev->ring);
+ ad7298_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 spi_device_id ad7298_id[] = {
+ {"ad7298", 0},
+ {}
+};
+
+static struct spi_driver ad7298_driver = {
+ .driver = {
+ .name = "ad7298",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7298_probe,
+ .remove = __devexit_p(ad7298_remove),
+ .id_table = ad7298_id,
+};
+
+static int __init ad7298_init(void)
+{
+ return spi_register_driver(&ad7298_driver);
+}
+module_init(ad7298_init);
+
+static void __exit ad7298_exit(void)
+{
+ spi_unregister_driver(&ad7298_driver);
+}
+module_exit(ad7298_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad7298");
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
new file mode 100644
index 000000000000..19d1aced1e6c
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -0,0 +1,258 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+#include "../trigger.h"
+#include "../sysfs.h"
+
+#include "ad7298.h"
+
+static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_C(in2, 2, 0, NULL);
+static IIO_SCAN_EL_C(in3, 3, 0, NULL);
+static IIO_SCAN_EL_C(in4, 4, 0, NULL);
+static IIO_SCAN_EL_C(in5, 5, 0, NULL);
+static IIO_SCAN_EL_C(in6, 6, 0, NULL);
+static IIO_SCAN_EL_C(in7, 7, 0, NULL);
+
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static IIO_CONST_ATTR(in_type, "u12/16") ;
+
+static struct attribute *ad7298_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_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ &iio_const_attr_in_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad7298_scan_el_group = {
+ .name = "scan_elements",
+ .attrs = ad7298_scan_el_attrs,
+};
+
+int ad7298_scan_from_ring(struct ad7298_state *st, long ch)
+{
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+ int ret;
+ u16 *ring_data;
+
+ if (!(ring->scan_mask & (1 << ch))) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+
+ ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL);
+ if (ring_data == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = ring->access.read_last(ring, (u8 *) ring_data);
+ if (ret)
+ goto error_free_ring_data;
+
+ ret = be16_to_cpu(ring_data[ch]);
+
+error_free_ring_data:
+ kfree(ring_data);
+error_ret:
+ return ret;
+}
+
+/**
+ * ad7298_ring_preenable() setup the parameters of the ring before enabling
+ *
+ * The complex nature of the setting of the number of bytes per datum is due
+ * to this driver currently ensuring that the timestamp is stored at an 8
+ * byte boundary.
+ **/
+static int ad7298_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ size_t d_size;
+ int i, m;
+ unsigned short command;
+
+ d_size = ring->scan_count * (AD7298_STORAGE_BITS / 8);
+
+ if (ring->scan_timestamp) {
+ d_size += sizeof(s64);
+
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+ }
+
+ if (ring->access.set_bytes_per_datum)
+ ring->access.set_bytes_per_datum(ring, d_size);
+
+ st->d_size = d_size;
+
+ command = AD7298_WRITE | st->ext_ref;
+
+ for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
+ if (ring->scan_mask & (1 << i))
+ command |= m;
+
+ st->tx_buf[0] = cpu_to_be16(command);
+
+ /* build spi ring message */
+ st->ring_xfer[0].tx_buf = &st->tx_buf[0];
+ st->ring_xfer[0].len = 2;
+ st->ring_xfer[0].cs_change = 1;
+ st->ring_xfer[1].tx_buf = &st->tx_buf[1];
+ st->ring_xfer[1].len = 2;
+ st->ring_xfer[1].cs_change = 1;
+
+ spi_message_init(&st->ring_msg);
+ spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
+ spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
+
+ for (i = 0; i < ring->scan_count; i++) {
+ st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
+ st->ring_xfer[i + 2].len = 2;
+ st->ring_xfer[i + 2].cs_change = 1;
+ spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
+ }
+ /* make sure last transfer cs_change is not set */
+ st->ring_xfer[i + 1].cs_change = 0;
+
+ return 0;
+}
+
+/**
+ * ad7298_poll_func_th() th of trigger launched polling to ring buffer
+ *
+ * As sampling only occurs on spi 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 ad7298_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+
+ schedule_work(&st->poll_work);
+ return;
+}
+
+/**
+ * ad7298_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 ad7298_poll_bh_to_ring(struct work_struct *work_s)
+{
+ struct ad7298_state *st = container_of(work_s, struct ad7298_state,
+ poll_work);
+ struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring);
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ s64 time_ns;
+ __u16 buf[16];
+ int b_sent, i;
+
+ /* Ensure only one copy of this function running at a time */
+ if (atomic_inc_return(&st->protect_ring) > 1)
+ return;
+
+ b_sent = spi_sync(st->spi, &st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ if (ring->scan_timestamp) {
+ time_ns = iio_get_time_ns();
+ memcpy((u8 *)buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+ }
+
+ for (i = 0; i < ring->scan_count; i++)
+ buf[i] = be16_to_cpu(st->rx_buf[i]);
+
+ indio_dev->ring->access.store_to(&sw_ring->buf, (u8 *)buf, time_ns);
+done:
+ atomic_dec(&st->protect_ring);
+}
+
+int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+ int ret;
+
+ 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(&indio_dev->ring->access);
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7298_poll_func_th);
+ if (ret)
+ goto error_deallocate_sw_rb;
+
+ /* Ring buffer functions - here trigger setup related */
+
+ indio_dev->ring->preenable = &ad7298_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_el_attrs = &ad7298_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
+
+ INIT_WORK(&st->poll_work, &ad7298_poll_bh_to_ring);
+
+ /* 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 ad7298_ring_cleanup(struct iio_dev *indio_dev)
+{
+ 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);
+}
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
index b51b49e4abd6..f917e9c3d54f 100644
--- a/drivers/staging/iio/adc/ad7476.h
+++ b/drivers/staging/iio/adc/ad7476.h
@@ -33,6 +33,7 @@ struct ad7476_state {
struct regulator *reg;
struct work_struct poll_work;
atomic_t protect_ring;
+ size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index b8b54da67c63..d263904b3d1d 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -190,7 +190,7 @@ static int __devinit ad7476_probe(struct spi_device *spi)
goto error_disable_reg;
}
- /* Estabilish that the iio_dev is a child of the i2c device */
+ /* Establish that the iio_dev is a child of the spi device */
st->indio_dev->dev.parent = &spi->dev;
st->indio_dev->attrs = &ad7476_attribute_group;
st->indio_dev->dev_data = (void *)(st);
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 85de14274ad7..1d654c86099d 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -26,6 +26,8 @@
#include "ad7476.h"
static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_TIMESTAMP(1);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
static ssize_t ad7476_show_type(struct device *dev,
struct device_attribute *attr,
@@ -44,6 +46,9 @@ static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7476_show_type, NULL, 0);
static struct attribute *ad7476_scan_el_attrs[] = {
&iio_scan_el_in0.dev_attr.attr,
&iio_const_attr_in0_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -86,16 +91,21 @@ error_ret:
static int ad7476_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7476_state *st = indio_dev->dev_data;
- size_t d_size;
+ struct iio_ring_buffer *ring = indio_dev->ring;
- if (indio_dev->ring->access.set_bytes_per_datum) {
- d_size = st->chip_info->storagebits / 8 + 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);
+ st->d_size = ring->scan_count * st->chip_info->storagebits / 8;
+
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
return 0;
}
@@ -131,18 +141,12 @@ static void ad7476_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *rxbuf;
int b_sent;
- size_t d_size;
-
- /* Ensure the timestamp is 8 byte aligned */
- d_size = st->chip_info->storagebits / 8 + 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;
- rxbuf = kzalloc(d_size, GFP_KERNEL);
+ rxbuf = kzalloc(st->d_size, GFP_KERNEL);
if (rxbuf == NULL)
return;
@@ -152,7 +156,9 @@ static void ad7476_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
- memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+ if (indio_dev->ring->scan_timestamp)
+ memcpy(rxbuf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns);
done:
@@ -182,6 +188,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
indio_dev->ring->scan_el_attrs = &ad7476_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7476_poll_bh_to_ring);
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h
new file mode 100644
index 000000000000..338bade801a7
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606.h
@@ -0,0 +1,117 @@
+/*
+ * AD7606 ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_ADC_AD7606_H_
+#define IIO_ADC_AD7606_H_
+
+/*
+ * TODO: struct ad7606_platform_data needs to go into include/linux/iio
+ */
+
+/**
+ * struct ad7606_platform_data - platform/board specifc information
+ * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64}
+ * @default_range: default range +/-{5000, 10000} mVolt
+ * @gpio_convst: number of gpio connected to the CONVST pin
+ * @gpio_reset: gpio connected to the RESET pin, if not used set to -1
+ * @gpio_range: gpio connected to the RANGE pin, if not used set to -1
+ * @gpio_os0: gpio connected to the OS0 pin, if not used set to -1
+ * @gpio_os1: gpio connected to the OS1 pin, if not used set to -1
+ * @gpio_os2: gpio connected to the OS2 pin, if not used set to -1
+ * @gpio_frstdata: gpio connected to the FRSTDAT pin, if not used set to -1
+ * @gpio_stby: gpio connected to the STBY pin, if not used set to -1
+ */
+
+struct ad7606_platform_data {
+ unsigned default_os;
+ unsigned default_range;
+ unsigned gpio_convst;
+ unsigned gpio_reset;
+ unsigned gpio_range;
+ unsigned gpio_os0;
+ unsigned gpio_os1;
+ unsigned gpio_os2;
+ unsigned gpio_frstdata;
+ unsigned gpio_stby;
+};
+
+/**
+ * struct ad7606_chip_info - chip specifc information
+ * @name: indentification string for chip
+ * @bits: accuracy of the adc in bits
+ * @bits: output coding [s]igned or [u]nsigned
+ * @int_vref_mv: the internal reference voltage
+ * @num_channels: number of physical inputs on chip
+ */
+
+struct ad7606_chip_info {
+ char name[10];
+ u8 bits;
+ char sign;
+ u16 int_vref_mv;
+ unsigned num_channels;
+};
+
+/**
+ * struct ad7606_state - driver instance specific data
+ */
+
+struct ad7606_state {
+ struct iio_dev *indio_dev;
+ struct device *dev;
+ const struct ad7606_chip_info *chip_info;
+ struct ad7606_platform_data *pdata;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ wait_queue_head_t wq_data_avail;
+ atomic_t protect_ring;
+ size_t d_size;
+ const struct ad7606_bus_ops *bops;
+ int irq;
+ unsigned id;
+ unsigned range;
+ unsigned oversampling;
+ bool done;
+ bool have_frstdata;
+ bool have_os;
+ bool have_stby;
+ bool have_reset;
+ bool have_range;
+ void __iomem *base_address;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+
+ unsigned short data[8] ____cacheline_aligned;
+};
+
+struct ad7606_bus_ops {
+ /* more methods added in future? */
+ int (*read_block)(struct device *, int, void *);
+};
+
+void ad7606_suspend(struct ad7606_state *st);
+void ad7606_resume(struct ad7606_state *st);
+struct ad7606_state *ad7606_probe(struct device *dev, int irq,
+ void __iomem *base_address, unsigned id,
+ const struct ad7606_bus_ops *bops);
+int ad7606_remove(struct ad7606_state *st);
+int ad7606_reset(struct ad7606_state *st);
+
+enum ad7606_supported_device_ids {
+ ID_AD7606_8,
+ ID_AD7606_6,
+ ID_AD7606_4
+};
+
+int ad7606_scan_from_ring(struct ad7606_state *st, unsigned ch);
+int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev);
+void ad7606_ring_cleanup(struct iio_dev *indio_dev);
+#endif /* IIO_ADC_AD7606_H_ */
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
new file mode 100644
index 000000000000..4c700f07fb83
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -0,0 +1,556 @@
+/*
+ * AD7606 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "adc.h"
+
+#include "ad7606.h"
+
+int ad7606_reset(struct ad7606_state *st)
+{
+ if (st->have_reset) {
+ gpio_set_value(st->pdata->gpio_reset, 1);
+ ndelay(100); /* t_reset >= 100ns */
+ gpio_set_value(st->pdata->gpio_reset, 0);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int ad7606_scan_direct(struct ad7606_state *st, unsigned ch)
+{
+ int ret;
+
+ st->done = false;
+ gpio_set_value(st->pdata->gpio_convst, 1);
+
+ ret = wait_event_interruptible(st->wq_data_avail, st->done);
+ if (ret)
+ goto error_ret;
+
+ if (st->have_frstdata) {
+ ret = st->bops->read_block(st->dev, 1, st->data);
+ if (ret)
+ goto error_ret;
+ if (!gpio_get_value(st->pdata->gpio_frstdata)) {
+ /* This should never happen */
+ ad7606_reset(st);
+ ret = -EIO;
+ goto error_ret;
+ }
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels - 1, &st->data[1]);
+ if (ret)
+ goto error_ret;
+ } else {
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels, st->data);
+ if (ret)
+ goto error_ret;
+ }
+
+ ret = st->data[ch];
+
+error_ret:
+ gpio_set_value(st->pdata->gpio_convst, 0);
+
+ return ret;
+}
+
+static ssize_t ad7606_scan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+
+ mutex_lock(&dev_info->mlock);
+ if (iio_ring_enabled(dev_info))
+ ret = ad7606_scan_from_ring(st, this_attr->address);
+ else
+ ret = ad7606_scan_direct(st, this_attr->address);
+ mutex_unlock(&dev_info->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", (short) ret);
+}
+
+static IIO_DEV_ATTR_IN_RAW(0, ad7606_scan, 0);
+static IIO_DEV_ATTR_IN_RAW(1, ad7606_scan, 1);
+static IIO_DEV_ATTR_IN_RAW(2, ad7606_scan, 2);
+static IIO_DEV_ATTR_IN_RAW(3, ad7606_scan, 3);
+static IIO_DEV_ATTR_IN_RAW(4, ad7606_scan, 4);
+static IIO_DEV_ATTR_IN_RAW(5, ad7606_scan, 5);
+static IIO_DEV_ATTR_IN_RAW(6, ad7606_scan, 6);
+static IIO_DEV_ATTR_IN_RAW(7, ad7606_scan, 7);
+
+static ssize_t ad7606_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 ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned int scale_uv = (st->range * 1000 * 2) >> st->chip_info->bits;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7606_show_scale, NULL, 0);
+
+static ssize_t ad7606_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", st->chip_info->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7606_show_name, NULL, 0);
+
+static ssize_t ad7606_show_range(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%u\n", st->range);
+}
+
+static ssize_t ad7606_store_range(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned long lval;
+
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+ if (!(lval == 5000 || lval == 10000)) {
+ dev_err(dev, "range is not supported\n");
+ return -EINVAL;
+ }
+ mutex_lock(&dev_info->mlock);
+ gpio_set_value(st->pdata->gpio_range, lval == 10000);
+ st->range = lval;
+ mutex_unlock(&dev_info->mlock);
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, \
+ ad7606_show_range, ad7606_store_range, 0);
+static IIO_CONST_ATTR(range_available, "5000 10000");
+
+static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%u\n", st->oversampling);
+}
+
+static int ad7606_oversampling_get_index(unsigned val)
+{
+ unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported); i++)
+ if (val == supported[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned long lval;
+ int ret;
+
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+
+ ret = ad7606_oversampling_get_index(lval);
+ if (ret < 0) {
+ dev_err(dev, "oversampling %lu is not supported\n", lval);
+ return ret;
+ }
+
+ mutex_lock(&dev_info->mlock);
+ gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1);
+ gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1);
+ gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1);
+ st->oversampling = lval;
+ mutex_unlock(&dev_info->mlock);
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR,
+ ad7606_show_oversampling_ratio,
+ ad7606_store_oversampling_ratio, 0);
+static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64");
+
+static struct attribute *ad7606_attributes[] = {
+ &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_in_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ &iio_dev_attr_range.dev_attr.attr,
+ &iio_const_attr_range_available.dev_attr.attr,
+ &iio_dev_attr_oversampling_ratio.dev_attr.attr,
+ &iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7606_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (st->chip_info->num_channels <= 6 &&
+ (attr == &iio_dev_attr_in7_raw.dev_attr.attr ||
+ attr == &iio_dev_attr_in6_raw.dev_attr.attr))
+ mode = 0;
+ else if (st->chip_info->num_channels <= 4 &&
+ (attr == &iio_dev_attr_in5_raw.dev_attr.attr ||
+ attr == &iio_dev_attr_in4_raw.dev_attr.attr))
+ mode = 0;
+ else if (!st->have_os &&
+ (attr == &iio_dev_attr_oversampling_ratio.dev_attr.attr ||
+ attr ==
+ &iio_const_attr_oversampling_ratio_available.dev_attr.attr))
+ mode = 0;
+ else if (!st->have_range &&
+ (attr == &iio_dev_attr_range.dev_attr.attr ||
+ attr == &iio_const_attr_range_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group ad7606_attribute_group = {
+ .attrs = ad7606_attributes,
+ .is_visible = ad7606_attr_is_visible,
+};
+
+static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
+ /*
+ * More devices added in future
+ */
+ [ID_AD7606_8] = {
+ .name = "ad7606",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
+ [ID_AD7606_6] = {
+ .name = "ad7606-6",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 6,
+ },
+ [ID_AD7606_4] = {
+ .name = "ad7606-4",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ },
+};
+
+static int ad7606_request_gpios(struct ad7606_state *st)
+{
+ struct gpio gpio_array[3] = {
+ [0] = {
+ .gpio = st->pdata->gpio_os0,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 1) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS0",
+ },
+ [1] = {
+ .gpio = st->pdata->gpio_os1,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 2) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS1",
+ },
+ [2] = {
+ .gpio = st->pdata->gpio_os2,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 4) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS2",
+ },
+ };
+ int ret;
+
+ ret = gpio_request_one(st->pdata->gpio_convst, GPIOF_OUT_INIT_LOW,
+ "AD7606_CONVST");
+ if (ret) {
+ dev_err(st->dev, "failed to request GPIO CONVST\n");
+ return ret;
+ }
+
+ ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
+ if (!ret) {
+ st->have_os = true;
+ }
+
+ ret = gpio_request_one(st->pdata->gpio_reset, GPIOF_OUT_INIT_LOW,
+ "AD7606_RESET");
+ if (!ret)
+ st->have_reset = true;
+
+ ret = gpio_request_one(st->pdata->gpio_range, GPIOF_DIR_OUT |
+ ((st->range == 10000) ? GPIOF_INIT_HIGH :
+ GPIOF_INIT_LOW), "AD7606_RANGE");
+ if (!ret)
+ st->have_range = true;
+
+ ret = gpio_request_one(st->pdata->gpio_stby, GPIOF_OUT_INIT_HIGH,
+ "AD7606_STBY");
+ if (!ret)
+ st->have_stby = true;
+
+ if (gpio_is_valid(st->pdata->gpio_frstdata)) {
+ ret = gpio_request_one(st->pdata->gpio_frstdata, GPIOF_IN,
+ "AD7606_FRSTDATA");
+ if (!ret)
+ st->have_frstdata = true;
+ }
+
+ return 0;
+}
+
+static void ad7606_free_gpios(struct ad7606_state *st)
+{
+ if (st->have_range)
+ gpio_free(st->pdata->gpio_range);
+
+ if (st->have_stby)
+ gpio_free(st->pdata->gpio_stby);
+
+ if (st->have_os) {
+ gpio_free(st->pdata->gpio_os0);
+ gpio_free(st->pdata->gpio_os1);
+ gpio_free(st->pdata->gpio_os2);
+ }
+
+ if (st->have_reset)
+ gpio_free(st->pdata->gpio_reset);
+
+ if (st->have_frstdata)
+ gpio_free(st->pdata->gpio_frstdata);
+
+ gpio_free(st->pdata->gpio_convst);
+}
+
+/**
+ * Interrupt handler
+ */
+static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
+{
+ struct ad7606_state *st = dev_id;
+
+ if (iio_ring_enabled(st->indio_dev)) {
+ if (!work_pending(&st->poll_work))
+ schedule_work(&st->poll_work);
+ } else {
+ st->done = true;
+ wake_up_interruptible(&st->wq_data_avail);
+ }
+
+ return IRQ_HANDLED;
+};
+
+struct ad7606_state *ad7606_probe(struct device *dev, int irq,
+ void __iomem *base_address,
+ unsigned id,
+ const struct ad7606_bus_ops *bops)
+{
+ struct ad7606_platform_data *pdata = dev->platform_data;
+ struct ad7606_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->dev = dev;
+ st->id = id;
+ st->irq = irq;
+ st->bops = bops;
+ st->base_address = base_address;
+ st->range = pdata->default_range == 10000 ? 10000 : 5000;
+
+ ret = ad7606_oversampling_get_index(pdata->default_os);
+ if (ret < 0) {
+ dev_warn(dev, "oversampling %d is not supported\n",
+ pdata->default_os);
+ st->oversampling = 0;
+ } else {
+ st->oversampling = pdata->default_os;
+ }
+
+ st->reg = regulator_get(dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ st->pdata = pdata;
+ st->chip_info = &ad7606_chip_info_tbl[id];
+
+ atomic_set(&st->protect_ring, 0);
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ st->indio_dev->dev.parent = dev;
+ st->indio_dev->attrs = &ad7606_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ init_waitqueue_head(&st->wq_data_avail);
+
+ ret = ad7606_request_gpios(st);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad7606_reset(st);
+ if (ret)
+ dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
+
+ ret = request_irq(st->irq, ad7606_interrupt,
+ IRQF_TRIGGER_FALLING, st->chip_info->name, st);
+ if (ret)
+ goto error_free_gpios;
+
+ ret = ad7606_register_ring_funcs_and_init(st->indio_dev);
+ if (ret)
+ goto error_free_irq;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_irq;
+
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
+ if (ret)
+ goto error_cleanup_ring;
+
+ return st;
+
+error_cleanup_ring:
+ ad7606_ring_cleanup(st->indio_dev);
+ iio_device_unregister(st->indio_dev);
+
+error_free_irq:
+ free_irq(st->irq, st);
+
+error_free_gpios:
+ ad7606_free_gpios(st);
+
+error_free_device:
+ iio_free_device(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 ERR_PTR(ret);
+}
+
+int ad7606_remove(struct ad7606_state *st)
+{
+ struct iio_dev *indio_dev = st->indio_dev;
+ iio_ring_buffer_unregister(indio_dev->ring);
+ ad7606_ring_cleanup(indio_dev);
+ iio_device_unregister(indio_dev);
+ free_irq(st->irq, st);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+
+ ad7606_free_gpios(st);
+
+ kfree(st);
+ return 0;
+}
+
+void ad7606_suspend(struct ad7606_state *st)
+{
+ if (st->have_stby) {
+ if (st->have_range)
+ gpio_set_value(st->pdata->gpio_range, 1);
+ gpio_set_value(st->pdata->gpio_stby, 0);
+ }
+}
+
+void ad7606_resume(struct ad7606_state *st)
+{
+ if (st->have_stby) {
+ if (st->have_range)
+ gpio_set_value(st->pdata->gpio_range,
+ st->range == 10000);
+
+ gpio_set_value(st->pdata->gpio_stby, 1);
+ ad7606_reset(st);
+ }
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
new file mode 100644
index 000000000000..43a554ce753d
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -0,0 +1,188 @@
+/*
+ * AD7606 Parallel Interface ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include "ad7606.h"
+
+static int ad7606_par16_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+
+ insw((unsigned long) st->base_address, buf, count);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_par16_bops = {
+ .read_block = ad7606_par16_read_block,
+};
+
+static int ad7606_par8_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+
+ insb((unsigned long) st->base_address, buf, count * 2);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_par8_bops = {
+ .read_block = ad7606_par8_read_block,
+};
+
+static int __devinit ad7606_par_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct ad7606_state *st;
+ void __iomem *addr;
+ resource_size_t remap_size;
+ int ret, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ remap_size = resource_size(res);
+
+ /* Request the regions */
+ if (!request_mem_region(res->start, remap_size, "iio-ad7606")) {
+ ret = -EBUSY;
+ goto out1;
+ }
+ addr = ioremap(res->start, remap_size);
+ if (!addr) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ st = ad7606_probe(&pdev->dev, irq, addr,
+ platform_get_device_id(pdev)->driver_data,
+ remap_size > 1 ? &ad7606_par16_bops :
+ &ad7606_par8_bops);
+
+ if (IS_ERR(st)) {
+ ret = PTR_ERR(st);
+ goto out2;
+ }
+
+ platform_set_drvdata(pdev, st);
+
+ return 0;
+
+out2:
+ iounmap(addr);
+out1:
+ release_mem_region(res->start, remap_size);
+
+ return ret;
+}
+
+static int __devexit ad7606_par_remove(struct platform_device *pdev)
+{
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ ad7606_remove(st);
+
+ iounmap(st->base_address);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ad7606_par_suspend(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_suspend(st);
+
+ return 0;
+}
+
+static int ad7606_par_resume(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_resume(st);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ad7606_pm_ops = {
+ .suspend = ad7606_par_suspend,
+ .resume = ad7606_par_resume,
+};
+#define AD7606_PAR_PM_OPS (&ad7606_pm_ops)
+
+#else
+#define AD7606_PAR_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_device_id ad7606_driver_ids[] = {
+ {
+ .name = "ad7606-8",
+ .driver_data = ID_AD7606_8,
+ }, {
+ .name = "ad7606-6",
+ .driver_data = ID_AD7606_6,
+ }, {
+ .name = "ad7606-4",
+ .driver_data = ID_AD7606_4,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
+
+static struct platform_driver ad7606_driver = {
+ .probe = ad7606_par_probe,
+ .remove = __devexit_p(ad7606_par_remove),
+ .id_table = ad7606_driver_ids,
+ .driver = {
+ .name = "ad7606",
+ .owner = THIS_MODULE,
+ .pm = AD7606_PAR_PM_OPS,
+ },
+};
+
+static int __init ad7606_init(void)
+{
+ return platform_driver_register(&ad7606_driver);
+}
+
+static void __exit ad7606_cleanup(void)
+{
+ platform_driver_unregister(&ad7606_driver);
+}
+
+module_init(ad7606_init);
+module_exit(ad7606_cleanup);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ad7606_par");
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
new file mode 100644
index 000000000000..b32cb0dea6d8
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+#include "../trigger.h"
+#include "../sysfs.h"
+
+#include "ad7606.h"
+
+static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_C(in2, 2, 0, NULL);
+static IIO_SCAN_EL_C(in3, 3, 0, NULL);
+static IIO_SCAN_EL_C(in4, 4, 0, NULL);
+static IIO_SCAN_EL_C(in5, 5, 0, NULL);
+static IIO_SCAN_EL_C(in6, 6, 0, NULL);
+static IIO_SCAN_EL_C(in7, 7, 0, NULL);
+
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static ssize_t ad7606_show_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7606_state *st = indio_dev->dev_data;
+
+ return sprintf(buf, "%c%d/%d\n", st->chip_info->sign,
+ st->chip_info->bits, st->chip_info->bits);
+}
+static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7606_show_type, NULL, 0);
+
+static struct attribute *ad7606_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_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ &iio_dev_attr_in_type.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7606_scan_el_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7606_state *st = indio_dev->dev_data;
+
+ mode_t mode = attr->mode;
+
+ if (st->chip_info->num_channels <= 6 &&
+ (attr == &iio_scan_el_in7.dev_attr.attr ||
+ attr == &iio_const_attr_in7_index.dev_attr.attr ||
+ attr == &iio_scan_el_in6.dev_attr.attr ||
+ attr == &iio_const_attr_in6_index.dev_attr.attr))
+ mode = 0;
+ else if (st->chip_info->num_channels <= 4 &&
+ (attr == &iio_scan_el_in5.dev_attr.attr ||
+ attr == &iio_const_attr_in5_index.dev_attr.attr ||
+ attr == &iio_scan_el_in4.dev_attr.attr ||
+ attr == &iio_const_attr_in4_index.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static struct attribute_group ad7606_scan_el_group = {
+ .name = "scan_elements",
+ .attrs = ad7606_scan_el_attrs,
+ .is_visible = ad7606_scan_el_attr_is_visible,
+};
+
+int ad7606_scan_from_ring(struct ad7606_state *st, unsigned ch)
+{
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+ int ret;
+ u16 *ring_data;
+
+ ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL);
+ if (ring_data == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = ring->access.read_last(ring, (u8 *) ring_data);
+ if (ret)
+ goto error_free_ring_data;
+
+ ret = ring_data[ch];
+
+error_free_ring_data:
+ kfree(ring_data);
+error_ret:
+ return ret;
+}
+
+/**
+ * ad7606_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 ad7606_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ size_t d_size;
+
+ d_size = st->chip_info->num_channels *
+ st->chip_info->bits / 8;
+
+ if (ring->scan_timestamp) {
+ d_size += sizeof(s64);
+
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+ }
+
+ if (ring->access.set_bytes_per_datum)
+ ring->access.set_bytes_per_datum(ring, d_size);
+
+ st->d_size = d_size;
+
+ return 0;
+}
+
+/**
+ * ad7606_poll_func_th() th of trigger launched polling to ring buffer
+ *
+ **/
+static void ad7606_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ gpio_set_value(st->pdata->gpio_convst, 1);
+
+ return;
+}
+/**
+ * ad7606_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 ad7606_poll_bh_to_ring(struct work_struct *work_s)
+{
+ struct ad7606_state *st = container_of(work_s, struct ad7606_state,
+ poll_work);
+ struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring);
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ s64 time_ns;
+ __u8 *buf;
+ int ret;
+
+ /* Ensure only one copy of this function running at a time */
+ if (atomic_inc_return(&st->protect_ring) > 1)
+ return;
+
+ buf = kzalloc(st->d_size, GFP_KERNEL);
+ if (buf == NULL)
+ return;
+
+ if (st->have_frstdata) {
+ ret = st->bops->read_block(st->dev, 1, buf);
+ if (ret)
+ goto done;
+ if (!gpio_get_value(st->pdata->gpio_frstdata)) {
+ /* This should never happen. However
+ * some signal glitch caused by bad PCB desgin or
+ * electrostatic discharge, could cause an extra read
+ * or clock. This allows recovery.
+ */
+ ad7606_reset(st);
+ goto done;
+ }
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels - 1, buf + 2);
+ if (ret)
+ goto done;
+ } else {
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels, buf);
+ if (ret)
+ goto done;
+ }
+
+ time_ns = iio_get_time_ns();
+
+ if (ring->scan_timestamp)
+ memcpy(buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+
+ ring->access.store_to(&sw_ring->buf, buf, time_ns);
+done:
+ gpio_set_value(st->pdata->gpio_convst, 0);
+ kfree(buf);
+ atomic_dec(&st->protect_ring);
+}
+
+int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ int ret;
+
+ 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(&indio_dev->ring->access);
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7606_poll_func_th);
+ if (ret)
+ goto error_deallocate_sw_rb;
+
+ /* Ring buffer functions - here trigger setup related */
+
+ indio_dev->ring->preenable = &ad7606_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_el_attrs = &ad7606_scan_el_group;
+ indio_dev->ring->scan_timestamp = true ;
+
+ INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
+
+ /* 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 ad7606_ring_cleanup(struct iio_dev *indio_dev)
+{
+ 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);
+}
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
new file mode 100644
index 000000000000..d738491222f2
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -0,0 +1,126 @@
+/*
+ * AD7606 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include "ad7606.h"
+
+#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
+
+static int ad7606_spi_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int i, ret;
+ unsigned short *data = buf;
+
+ ret = spi_read(spi, (u8 *)buf, count * 2);
+ if (ret < 0) {
+ dev_err(&spi->dev, "SPI read error\n");
+ return ret;
+ }
+
+ for (i = 0; i < count; i++)
+ data[i] = be16_to_cpu(data[i]);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_spi_bops = {
+ .read_block = ad7606_spi_read_block,
+};
+
+static int __devinit ad7606_spi_probe(struct spi_device *spi)
+{
+ struct ad7606_state *st;
+
+ st = ad7606_probe(&spi->dev, spi->irq, NULL,
+ spi_get_device_id(spi)->driver_data,
+ &ad7606_spi_bops);
+
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ spi_set_drvdata(spi, st);
+
+ return 0;
+}
+
+static int __devexit ad7606_spi_remove(struct spi_device *spi)
+{
+ struct ad7606_state *st = dev_get_drvdata(&spi->dev);
+
+ return ad7606_remove(st);
+}
+
+#ifdef CONFIG_PM
+static int ad7606_spi_suspend(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_suspend(st);
+
+ return 0;
+}
+
+static int ad7606_spi_resume(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_resume(st);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ad7606_pm_ops = {
+ .suspend = ad7606_spi_suspend,
+ .resume = ad7606_spi_resume,
+};
+#define AD7606_SPI_PM_OPS (&ad7606_pm_ops)
+
+#else
+#define AD7606_SPI_PM_OPS NULL
+#endif
+
+static const struct spi_device_id ad7606_id[] = {
+ {"ad7606-8", ID_AD7606_8},
+ {"ad7606-6", ID_AD7606_6},
+ {"ad7606-4", ID_AD7606_4},
+ {}
+};
+
+static struct spi_driver ad7606_driver = {
+ .driver = {
+ .name = "ad7606",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ .pm = AD7606_SPI_PM_OPS,
+ },
+ .probe = ad7606_spi_probe,
+ .remove = __devexit_p(ad7606_spi_remove),
+ .id_table = ad7606_id,
+};
+
+static int __init ad7606_spi_init(void)
+{
+ return spi_register_driver(&ad7606_driver);
+}
+module_init(ad7606_spi_init);
+
+static void __exit ad7606_spi_exit(void)
+{
+ spi_unregister_driver(&ad7606_driver);
+}
+module_exit(ad7606_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad7606_spi");
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
index 8c2a218c9496..439c802b38f2 100644
--- a/drivers/staging/iio/adc/ad7887.h
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -63,6 +63,7 @@ struct ad7887_state {
struct regulator *reg;
struct work_struct poll_work;
atomic_t protect_ring;
+ size_t d_size;
u16 int_vref_mv;
bool en_dual;
struct spi_transfer xfer[4];
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index 6b9cb1f95a1e..2d7fe65049dd 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -27,6 +27,8 @@
static IIO_SCAN_EL_C(in0, 0, 0, NULL);
static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_TIMESTAMP(2);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
static ssize_t ad7887_show_type(struct device *dev,
struct device_attribute *attr,
@@ -47,6 +49,9 @@ static struct attribute *ad7887_scan_el_attrs[] = {
&iio_const_attr_in0_index.dev_attr.attr,
&iio_scan_el_in1.dev_attr.attr,
&iio_const_attr_in1_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -118,16 +123,20 @@ static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = indio_dev->dev_data;
struct iio_ring_buffer *ring = indio_dev->ring;
- size_t d_size;
- if (indio_dev->ring->access.set_bytes_per_datum) {
- d_size = st->chip_info->storagebits / 8 + 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);
+ st->d_size = ring->scan_count * st->chip_info->storagebits / 8;
+
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
switch (ring->scan_mask) {
case (1 << 0):
st->ring_msg = &st->msg[AD7887_CH0];
@@ -186,20 +195,14 @@ static void ad7887_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *buf;
int b_sent;
- size_t d_size;
unsigned int bytes = ring->scan_count * st->chip_info->storagebits / 8;
- /* Ensure the timestamp is 8 byte aligned */
- d_size = bytes + 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;
- buf = kzalloc(d_size, GFP_KERNEL);
+ buf = kzalloc(st->d_size, GFP_KERNEL);
if (buf == NULL)
return;
@@ -210,7 +213,9 @@ static void ad7887_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
memcpy(buf, st->data, bytes);
- memcpy(buf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+ if (ring->scan_timestamp)
+ memcpy(buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
indio_dev->ring->access.store_to(&sw_ring->buf, buf, time_ns);
done:
@@ -241,6 +246,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
indio_dev->ring->postdisable = &ad7887_ring_postdisable;
indio_dev->ring->scan_el_attrs = &ad7887_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7887_poll_bh_to_ring);
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 81a20d524b77..a421362c77f9 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -116,6 +116,7 @@ struct ad799x_state {
struct work_struct poll_work;
struct work_struct work_thresh;
atomic_t protect_ring;
+ size_t d_size;
struct iio_trigger *trig;
struct regulator *reg;
s64 last_timestamp;
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index 89ccf375a188..e50841b3ac69 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -123,6 +123,9 @@ static AD799X_SCAN_EL(5);
static AD799X_SCAN_EL(6);
static AD799X_SCAN_EL(7);
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64)
+
static ssize_t ad799x_show_type(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -471,6 +474,9 @@ static struct attribute *ad7991_5_9_3_4_scan_el_attrs[] = {
&iio_const_attr_in2_index.dev_attr.attr,
&iio_scan_el_in3.dev_attr.attr,
&iio_const_attr_in3_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -497,6 +503,9 @@ static struct attribute *ad7992_scan_el_attrs[] = {
&iio_const_attr_in0_index.dev_attr.attr,
&iio_scan_el_in1.dev_attr.attr,
&iio_const_attr_in1_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -541,6 +550,9 @@ static struct attribute *ad7997_8_scan_el_attrs[] = {
&iio_const_attr_in6_index.dev_attr.attr,
&iio_scan_el_in7.dev_attr.attr,
&iio_const_attr_in7_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 975cdcbf0830..56abc395f177 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -73,8 +73,6 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
{
struct iio_ring_buffer *ring = indio_dev->ring;
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
@@ -84,15 +82,19 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
if (st->id == ad7997 || st->id == ad7998)
ad799x_set_scan_mode(st, ring->scan_mask);
- numvals = ring->scan_count;
+ st->d_size = ring->scan_count * 2;
- if (ring->access.set_bytes_per_datum) {
- d_size = numvals*2 + sizeof(s64);
- if (d_size % 8)
- d_size += 8 - (d_size % 8);
- ring->access.set_bytes_per_datum(ring, d_size);
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
return 0;
}
@@ -130,29 +132,13 @@ static void ad799x_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *rxbuf;
int b_sent;
- size_t d_size;
u8 cmd;
- unsigned long numvals = 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);
+ rxbuf = kmalloc(st->d_size, GFP_KERNEL);
if (rxbuf == NULL)
return;
@@ -177,13 +163,15 @@ static void ad799x_poll_bh_to_ring(struct work_struct *work_s)
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
- cmd, numvals*2, rxbuf);
+ cmd, ring->scan_count * 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));
+ if (ring->scan_timestamp)
+ memcpy(rxbuf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
ring->access.store_to(&ring_sw->buf, rxbuf, time_ns);
done:
@@ -213,6 +201,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->preenable = &ad799x_ring_preenable;
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring);
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index 9191bd23cc08..67defcb359b1 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -11,11 +11,22 @@ config AD5624R_SPI
AD5664R convertors (DAC). This driver uses the common SPI interface.
config AD5446
- tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5541A/12A DAC SPI driver"
+ tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5444, AD5446,
- AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs.
+ AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621,
+ AD5640, AD5660 DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.
+
+config MAX517
+ tristate "Maxim MAX517/518/519 DAC driver"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Maxim chips MAX517,
+ MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
+
+ This driver can also be built as a module. If so, the module
+ will be called max517.
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile
index 7cf331b4e001..1197aef54abb 100644
--- a/drivers/staging/iio/dac/Makefile
+++ b/drivers/staging/iio/dac/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_MAX517) += max517.o
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 0f87ecac82fc..8623a72e046c 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -48,6 +48,20 @@ static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
st->data.d24[2] = val & 0xFF;
}
+static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
+{
+ st->data.d16 = cpu_to_be16(mode << 14);
+}
+
+static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
+{
+ unsigned val = mode << 16;
+
+ st->data.d24[0] = (val >> 16) & 0xFF;
+ st->data.d24[1] = (val >> 8) & 0xFF;
+ st->data.d24[2] = val & 0xFF;
+}
+
static ssize_t ad5446_write(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -68,6 +82,7 @@ static ssize_t ad5446_write(struct device *dev,
}
mutex_lock(&dev_info->mlock);
+ st->cached_val = val;
st->chip_info->store_sample(st, val);
ret = spi_sync(st->spi, &st->msg);
mutex_unlock(&dev_info->mlock);
@@ -102,15 +117,119 @@ static ssize_t ad5446_show_name(struct device *dev,
}
static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0);
+static ssize_t ad5446_write_powerdown_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ if (sysfs_streq(buf, "1kohm_to_gnd"))
+ st->pwr_down_mode = MODE_PWRDWN_1k;
+ else if (sysfs_streq(buf, "100kohm_to_gnd"))
+ st->pwr_down_mode = MODE_PWRDWN_100k;
+ else if (sysfs_streq(buf, "three_state"))
+ st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
+ else
+ return -EINVAL;
+
+ return len;
+}
+
+static ssize_t ad5446_read_powerdown_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
+
+ return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
+}
+
+static ssize_t ad5446_read_dac_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5446_write_dac_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+ unsigned long readin;
+ int ret;
+
+ ret = strict_strtol(buf, 10, &readin);
+ if (ret)
+ return ret;
+
+ if (readin > 1)
+ ret = -EINVAL;
+
+ mutex_lock(&dev_info->mlock);
+ st->pwr_down = readin;
+
+ if (st->pwr_down)
+ st->chip_info->store_pwr_down(st, st->pwr_down_mode);
+ else
+ st->chip_info->store_sample(st, st->cached_val);
+
+ ret = spi_sync(st->spi, &st->msg);
+ mutex_unlock(&dev_info->mlock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR,
+ ad5446_read_powerdown_mode,
+ ad5446_write_powerdown_mode, 0);
+
+static IIO_CONST_ATTR(out_powerdown_mode_available,
+ "1kohm_to_gnd 100kohm_to_gnd three_state");
+
+static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR,
+ ad5446_read_dac_powerdown,
+ ad5446_write_dac_powerdown, 0);
+
static struct attribute *ad5446_attributes[] = {
&iio_dev_attr_out0_raw.dev_attr.attr,
&iio_dev_attr_out_scale.dev_attr.attr,
+ &iio_dev_attr_out0_powerdown.dev_attr.attr,
+ &iio_dev_attr_out_powerdown_mode.dev_attr.attr,
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr,
&iio_dev_attr_name.dev_attr.attr,
NULL,
};
+static mode_t ad5446_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (!st->chip_info->store_pwr_down &&
+ (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr ||
+ attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr ||
+ attr ==
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
static const struct attribute_group ad5446_attribute_group = {
.attrs = ad5446_attributes,
+ .is_visible = ad5446_attr_is_visible,
};
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
@@ -132,18 +251,52 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.store_sample = ad5542_store_sample,
},
+ [ID_AD5543] = {
+ .bits = 16,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5542_store_sample,
+ },
[ID_AD5512A] = {
.bits = 12,
.storagebits = 16,
.left_shift = 4,
.store_sample = ad5542_store_sample,
},
+ [ID_AD5553] = {
+ .bits = 14,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5542_store_sample,
+ },
+ [ID_AD5601] = {
+ .bits = 8,
+ .storagebits = 16,
+ .left_shift = 6,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
+ [ID_AD5611] = {
+ .bits = 10,
+ .storagebits = 16,
+ .left_shift = 4,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
+ [ID_AD5621] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 2,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
[ID_AD5620_2500] = {
.bits = 12,
.storagebits = 16,
.left_shift = 2,
.int_vref_mv = 2500,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5620_1250] = {
.bits = 12,
@@ -151,6 +304,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 2,
.int_vref_mv = 1250,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5640_2500] = {
.bits = 14,
@@ -158,6 +312,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 2500,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5640_1250] = {
.bits = 14,
@@ -165,6 +320,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 1250,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5660_2500] = {
.bits = 16,
@@ -172,6 +328,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 2500,
.store_sample = ad5660_store_sample,
+ .store_pwr_down = ad5660_store_pwr_down,
},
[ID_AD5660_1250] = {
.bits = 16,
@@ -179,6 +336,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 1250,
.store_sample = ad5660_store_sample,
+ .store_pwr_down = ad5660_store_pwr_down,
},
};
@@ -231,20 +389,20 @@ static int __devinit ad5446_probe(struct spi_device *spi)
spi_message_add_tail(&st->xfer, &st->msg);
switch (spi_get_device_id(spi)->driver_data) {
- case ID_AD5620_2500:
- case ID_AD5620_1250:
- case ID_AD5640_2500:
- case ID_AD5640_1250:
- case ID_AD5660_2500:
- case ID_AD5660_1250:
- st->vref_mv = st->chip_info->int_vref_mv;
- break;
- default:
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- dev_warn(&spi->dev,
- "reference voltage unspecified\n");
+ case ID_AD5620_2500:
+ case ID_AD5620_1250:
+ case ID_AD5640_2500:
+ case ID_AD5640_1250:
+ case ID_AD5660_2500:
+ case ID_AD5660_1250:
+ st->vref_mv = st->chip_info->int_vref_mv;
+ break;
+ default:
+ if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev,
+ "reference voltage unspecified\n");
}
ret = iio_device_register(st->indio_dev);
@@ -283,8 +441,13 @@ static int ad5446_remove(struct spi_device *spi)
static const struct spi_device_id ad5446_id[] = {
{"ad5444", ID_AD5444},
{"ad5446", ID_AD5446},
- {"ad5542a", ID_AD5542A},
{"ad5512a", ID_AD5512A},
+ {"ad5542a", ID_AD5542A},
+ {"ad5543", ID_AD5543},
+ {"ad5553", ID_AD5553},
+ {"ad5601", ID_AD5601},
+ {"ad5611", ID_AD5611},
+ {"ad5621", ID_AD5621},
{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
{"ad5640-2500", ID_AD5640_2500},
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
index 902542e22c4a..7ac63ab8a11d 100644
--- a/drivers/staging/iio/dac/ad5446.h
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -27,6 +27,10 @@
#define RES_MASK(bits) ((1 << (bits)) - 1)
+#define MODE_PWRDWN_1k 0x1
+#define MODE_PWRDWN_100k 0x2
+#define MODE_PWRDWN_TRISTATE 0x3
+
/**
* struct ad5446_state - driver instance specific data
* @indio_dev: the industrial I/O device
@@ -47,6 +51,9 @@ struct ad5446_state {
struct regulator *reg;
struct work_struct poll_work;
unsigned short vref_mv;
+ unsigned cached_val;
+ unsigned pwr_down_mode;
+ unsigned pwr_down;
struct spi_transfer xfer;
struct spi_message msg;
union {
@@ -62,14 +69,16 @@ struct ad5446_state {
* @left_shift: number of bits the datum must be shifted
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @store_sample: chip specific helper function to store the datum
+ * @store_sample: chip specific helper function to store the powerpown cmd
*/
struct ad5446_chip_info {
- u8 bits;
- u8 storagebits;
- u8 left_shift;
- u16 int_vref_mv;
- void (*store_sample) (struct ad5446_state *st, unsigned val);
+ u8 bits;
+ u8 storagebits;
+ u8 left_shift;
+ u16 int_vref_mv;
+ void (*store_sample) (struct ad5446_state *st, unsigned val);
+ void (*store_pwr_down) (struct ad5446_state *st, unsigned mode);
};
/**
@@ -84,7 +93,12 @@ enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5542A,
+ ID_AD5543,
ID_AD5512A,
+ ID_AD5553,
+ ID_AD5601,
+ ID_AD5611,
+ ID_AD5621,
ID_AD5620_2500,
ID_AD5620_1250,
ID_AD5640_2500,
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h
index ce518be652b7..c16df4ed52ca 100644
--- a/drivers/staging/iio/dac/ad5624r.h
+++ b/drivers/staging/iio/dac/ad5624r.h
@@ -1,21 +1,80 @@
+/*
+ * AD5624R SPI DAC driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
#ifndef SPI_AD5624R_H_
#define SPI_AD5624R_H_
-#define AD5624R_DAC_CHANNELS 4
+#define AD5624R_DAC_CHANNELS 4
-#define AD5624R_ADDR_DAC0 0x0
-#define AD5624R_ADDR_DAC1 0x1
-#define AD5624R_ADDR_DAC2 0x2
-#define AD5624R_ADDR_DAC3 0x3
-#define AD5624R_ADDR_ALL_DAC 0x7
+#define AD5624R_ADDR_DAC0 0x0
+#define AD5624R_ADDR_DAC1 0x1
+#define AD5624R_ADDR_DAC2 0x2
+#define AD5624R_ADDR_DAC3 0x3
+#define AD5624R_ADDR_ALL_DAC 0x7
-#define AD5624R_CMD_WRITE_INPUT_N 0x0
-#define AD5624R_CMD_UPDATE_DAC_N 0x1
-#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
-#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3
-#define AD5624R_CMD_POWERDOWN_DAC 0x4
-#define AD5624R_CMD_RESET 0x5
-#define AD5624R_CMD_LDAC_SETUP 0x6
-#define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7
+#define AD5624R_CMD_WRITE_INPUT_N 0x0
+#define AD5624R_CMD_UPDATE_DAC_N 0x1
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3
+#define AD5624R_CMD_POWERDOWN_DAC 0x4
+#define AD5624R_CMD_RESET 0x5
+#define AD5624R_CMD_LDAC_SETUP 0x6
+#define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7
-#endif
+#define AD5624R_LDAC_PWRDN_NONE 0x0
+#define AD5624R_LDAC_PWRDN_1K 0x1
+#define AD5624R_LDAC_PWRDN_100K 0x2
+#define AD5624R_LDAC_PWRDN_3STATE 0x3
+
+/**
+ * struct ad5624r_chip_info - chip specific information
+ * @bits: accuracy of the DAC in bits
+ * @int_vref_mv: AD5620/40/60: the internal reference voltage
+ */
+
+struct ad5624r_chip_info {
+ u8 bits;
+ u16 int_vref_mv;
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @indio_dev: the industrial I/O device
+ * @us: spi_device
+ * @chip_info: chip model specific constants, available modes etc
+ * @reg: supply regulator
+ * @vref_mv: actual reference voltage used
+ * @pwr_down_mask power down mask
+ * @pwr_down_mode current power down mode
+ */
+
+struct ad5624r_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *us;
+ const struct ad5624r_chip_info *chip_info;
+ struct regulator *reg;
+ unsigned short vref_mv;
+ unsigned pwr_down_mask;
+ unsigned pwr_down_mode;
+};
+
+/**
+ * ad5624r_supported_device_ids:
+ * The AD5624/44/64 parts are available in different
+ * fixed internal reference voltage options.
+ */
+
+enum ad5624r_supported_device_ids {
+ ID_AD5624R3,
+ ID_AD5644R3,
+ ID_AD5664R3,
+ ID_AD5624R5,
+ ID_AD5644R5,
+ ID_AD5664R5,
+};
+
+#endif /* SPI_AD5624R_H_ */
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
index 2b1c6dde4fdd..a945b18ff843 100644
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -1,9 +1,9 @@
/*
* AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
*
- * Copyright 2010 Analog Devices Inc.
+ * Copyright 2010-2011 Analog Devices Inc.
*
- * Licensed under the GPL-2 or later.
+ * Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
@@ -14,25 +14,38 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
#include "../iio.h"
#include "../sysfs.h"
#include "dac.h"
#include "ad5624r.h"
-/**
- * struct ad5624r_state - device related storage
- * @indio_dev: associated industrial IO device
- * @us: spi device
- **/
-struct ad5624r_state {
- struct iio_dev *indio_dev;
- struct spi_device *us;
- int data_len;
- int ldac_mode;
- int dac_power_mode[AD5624R_DAC_CHANNELS];
- int internal_ref;
+static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
+ [ID_AD5624R3] = {
+ .bits = 12,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5644R3] = {
+ .bits = 14,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5664R3] = {
+ .bits = 16,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5624R5] = {
+ .bits = 12,
+ .int_vref_mv = 2500,
+ },
+ [ID_AD5644R5] = {
+ .bits = 14,
+ .int_vref_mv = 2500,
+ },
+ [ID_AD5664R5] = {
+ .bits = 16,
+ .int_vref_mv = 2500,
+ },
};
static int ad5624r_spi_write(struct spi_device *spi,
@@ -42,11 +55,12 @@ static int ad5624r_spi_write(struct spi_device *spi,
u8 msg[3];
/*
- * The input shift register is 24 bits wide. The first two bits are don't care bits.
- * The next three are the command bits, C2 to C0, followed by the 3-bit DAC address,
- * A2 to A0, and then the 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
- * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, for the AD5664R,
- * AD5644R, and AD5624R, respectively.
+ * The input shift register is 24 bits wide. The first two bits are
+ * don't care bits. The next three are the command bits, C2 to C0,
+ * followed by the 3-bit DAC address, A2 to A0, and then the
+ * 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
+ * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
+ * for the AD5664R, AD5644R, and AD5624R, respectively.
*/
data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
msg[0] = data >> 16;
@@ -63,7 +77,7 @@ static ssize_t ad5624r_write_dac(struct device *dev,
long readin;
int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = strict_strtol(buf, 10, &readin);
@@ -71,138 +85,144 @@ static ssize_t ad5624r_write_dac(struct device *dev,
return ret;
ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
- this_attr->address, readin, st->data_len);
+ this_attr->address, readin,
+ st->chip_info->bits);
return ret ? ret : len;
}
-static ssize_t ad5624r_read_ldac_mode(struct device *dev,
+static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
- return sprintf(buf, "%x\n", st->ldac_mode);
+ char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
+
+ return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
}
-static ssize_t ad5624r_write_ldac_mode(struct device *dev,
+static ssize_t ad5624r_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- long readin;
- int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
-
- ret = strict_strtol(buf, 16, &readin);
- if (ret)
- return ret;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0,
- readin & 0xF, 16);
- st->ldac_mode = readin & 0xF;
+ if (sysfs_streq(buf, "1kohm_to_gnd"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_1K;
+ else if (sysfs_streq(buf, "100kohm_to_gnd"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_100K;
+ else if (sysfs_streq(buf, "three_state"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_3STATE;
+ else
+ ret = -EINVAL;
return ret ? ret : len;
}
-static ssize_t ad5624r_read_dac_power_mode(struct device *dev,
+static ssize_t ad5624r_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- return sprintf(buf, "%d\n", st->dac_power_mode[this_attr->address]);
+ return sprintf(buf, "%d\n",
+ !!(st->pwr_down_mask & (1 << this_attr->address)));
}
-static ssize_t ad5624r_write_dac_power_mode(struct device *dev,
+static ssize_t ad5624r_write_dac_powerdown(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
long readin;
int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = strict_strtol(buf, 10, &readin);
if (ret)
return ret;
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
- ((readin & 0x3) << 4) |
- (1 << this_attr->address), 16);
+ if (readin == 1)
+ st->pwr_down_mask |= (1 << this_attr->address);
+ else if (!readin)
+ st->pwr_down_mask &= ~(1 << this_attr->address);
+ else
+ ret = -EINVAL;
- st->dac_power_mode[this_attr->address] = readin & 0x3;
+ ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
+ (st->pwr_down_mode << 4) |
+ st->pwr_down_mask, 16);
return ret ? ret : len;
}
-static ssize_t ad5624r_read_internal_ref_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t ad5624r_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
- return sprintf(buf, "%d\n", st->internal_ref);
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
}
+static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5624r_show_scale, NULL, 0);
-static ssize_t ad5624r_write_internal_ref_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t ad5624r_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- long readin;
- int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
-
- ret = strict_strtol(buf, 10, &readin);
- if (ret)
- return ret;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
- !!readin, 16);
-
- st->internal_ref = !!readin;
-
- return ret ? ret : len;
+ return sprintf(buf, "%s\n", spi_get_device_id(st->us)->name);
}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad5624r_show_name, NULL, 0);
static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0);
static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1);
static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2);
static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3);
-static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode,
- ad5624r_write_ldac_mode, 0);
-static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR,
- ad5624r_read_internal_ref_mode,
- ad5624r_write_internal_ref_mode, 0);
+static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO |
+ S_IWUSR, ad5624r_read_powerdown_mode,
+ ad5624r_write_powerdown_mode, 0);
+
+static IIO_CONST_ATTR(out_powerdown_mode_available,
+ "1kohm_to_gnd 100kohm_to_gnd three_state");
-#define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr)
+#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out##_num##_powerdown, \
+ S_IRUGO | S_IWUSR, _show, _store, _addr)
-static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 0);
-static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 1);
-static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 2);
-static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 3);
+static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 0);
+static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 1);
+static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 2);
+static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 3);
static struct attribute *ad5624r_attributes[] = {
&iio_dev_attr_out0_raw.dev_attr.attr,
&iio_dev_attr_out1_raw.dev_attr.attr,
&iio_dev_attr_out2_raw.dev_attr.attr,
&iio_dev_attr_out3_raw.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_0.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_1.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_2.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_3.dev_attr.attr,
- &iio_dev_attr_ldac_mode.dev_attr.attr,
- &iio_dev_attr_internal_ref.dev_attr.attr,
+ &iio_dev_attr_out0_powerdown.dev_attr.attr,
+ &iio_dev_attr_out1_powerdown.dev_attr.attr,
+ &iio_dev_attr_out2_powerdown.dev_attr.attr,
+ &iio_dev_attr_out3_powerdown.dev_attr.attr,
+ &iio_dev_attr_out_powerdown_mode.dev_attr.attr,
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr,
+ &iio_dev_attr_out_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
NULL,
};
@@ -213,7 +233,7 @@ static const struct attribute_group ad5624r_attribute_group = {
static int __devinit ad5624r_probe(struct spi_device *spi)
{
struct ad5624r_state *st;
- int ret = 0;
+ int ret, voltage_uv = 0;
st = kzalloc(sizeof(*st), GFP_KERNEL);
if (st == NULL) {
@@ -222,18 +242,30 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
}
spi_set_drvdata(spi, st);
- st->data_len = spi_get_device_id(spi)->driver_data;
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ voltage_uv = regulator_get_voltage(st->reg);
+ }
+
+ st->chip_info =
+ &ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ st->vref_mv = st->chip_info->int_vref_mv;
st->us = spi;
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_st;
+ goto error_disable_reg;
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 0;
- st->indio_dev->event_attrs = NULL;
-
st->indio_dev->attrs = &ad5624r_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
@@ -243,14 +275,22 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
if (ret)
goto error_free_dev;
- spi->mode = SPI_MODE_0;
- spi_setup(spi);
+ ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
+ !!voltage_uv, 16);
+ if (ret)
+ goto error_free_dev;
return 0;
error_free_dev:
iio_free_device(st->indio_dev);
-error_free_st:
+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;
@@ -261,15 +301,24 @@ static int __devexit ad5624r_remove(struct spi_device *spi)
struct ad5624r_state *st = spi_get_drvdata(spi);
iio_device_unregister(st->indio_dev);
+
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+
kfree(st);
return 0;
}
static const struct spi_device_id ad5624r_id[] = {
- {"ad5624r", 12},
- {"ad5644r", 14},
- {"ad5664r", 16},
+ {"ad5624r3", ID_AD5624R3},
+ {"ad5644r3", ID_AD5644R3},
+ {"ad5664r3", ID_AD5664R3},
+ {"ad5624r5", ID_AD5624R5},
+ {"ad5644r5", ID_AD5644R5},
+ {"ad5664r5", ID_AD5664R5},
{}
};
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
new file mode 100644
index 000000000000..7071f713604a
--- /dev/null
+++ b/drivers/staging/iio/dac/max517.c
@@ -0,0 +1,298 @@
+/*
+ * max517.c - Support for Maxim MAX517, MAX518 and MAX519
+ *
+ * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include "../iio.h"
+#include "dac.h"
+
+#include "max517.h"
+
+#define MAX517_DRV_NAME "max517"
+
+/* Commands */
+#define COMMAND_CHANNEL0 0x00
+#define COMMAND_CHANNEL1 0x01 /* for MAX518 and MAX519 */
+#define COMMAND_PD 0x08 /* Power Down */
+
+enum max517_device_ids {
+ ID_MAX517,
+ ID_MAX518,
+ ID_MAX519,
+};
+
+struct max517_data {
+ struct iio_dev *indio_dev;
+ struct i2c_client *client;
+ unsigned short vref_mv[2];
+};
+
+/*
+ * channel: bit 0: channel 1
+ * bit 1: channel 2
+ * (this way, it's possible to set both channels at once)
+ */
+static ssize_t max517_set_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count, int channel)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max517_data *data = iio_dev_get_devdata(dev_info);
+ struct i2c_client *client = data->client;
+ u8 outbuf[4]; /* 1x or 2x command + value */
+ int outbuf_size = 0;
+ int res;
+ long val;
+
+ res = strict_strtol(buf, 10, &val);
+
+ if (res)
+ return res;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ if (channel & 1) {
+ outbuf[outbuf_size++] = COMMAND_CHANNEL0;
+ outbuf[outbuf_size++] = val;
+ }
+ if (channel & 2) {
+ outbuf[outbuf_size++] = COMMAND_CHANNEL1;
+ outbuf[outbuf_size++] = val;
+ }
+
+ /*
+ * At this point, there are always 1 or 2 two-byte commands in
+ * outbuf. With 2 commands, the device can set two outputs
+ * simultaneously, latching the values upon the end of the I2C
+ * transfer.
+ */
+
+ res = i2c_master_send(client, outbuf, outbuf_size);
+ if (res < 0)
+ return res;
+
+ return count;
+}
+
+static ssize_t max517_set_value_1(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 1);
+}
+static IIO_DEV_ATTR_OUT_RAW(1, max517_set_value_1, 0);
+
+static ssize_t max517_set_value_2(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 2);
+}
+static IIO_DEV_ATTR_OUT_RAW(2, max517_set_value_2, 1);
+
+static ssize_t max517_set_value_both(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 3);
+}
+static IIO_DEVICE_ATTR_NAMED(out1and2_raw, out1&2_raw, S_IWUSR, NULL,
+ max517_set_value_both, -1);
+
+static ssize_t max517_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int channel)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max517_data *data = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+
+static ssize_t max517_show_scale1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max517_show_scale(dev, attr, buf, 1);
+}
+static IIO_DEVICE_ATTR(out1_scale, S_IRUGO, max517_show_scale1, NULL, 0);
+
+static ssize_t max517_show_scale2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max517_show_scale(dev, attr, buf, 2);
+}
+static IIO_DEVICE_ATTR(out2_scale, S_IRUGO, max517_show_scale2, NULL, 0);
+
+/* On MAX517 variant, we have one output */
+static struct attribute *max517_attributes[] = {
+ &iio_dev_attr_out1_raw.dev_attr.attr,
+ &iio_dev_attr_out1_scale.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group max517_attribute_group = {
+ .attrs = max517_attributes,
+};
+
+/* On MAX518 and MAX519 variant, we have two outputs */
+static struct attribute *max518_attributes[] = {
+ &iio_dev_attr_out1_raw.dev_attr.attr,
+ &iio_dev_attr_out1_scale.dev_attr.attr,
+ &iio_dev_attr_out2_raw.dev_attr.attr,
+ &iio_dev_attr_out2_scale.dev_attr.attr,
+ &iio_dev_attr_out1and2_raw.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group max518_attribute_group = {
+ .attrs = max518_attributes,
+};
+
+static int max517_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ u8 outbuf = COMMAND_PD;
+
+ return i2c_master_send(client, &outbuf, 1);
+}
+
+static int max517_resume(struct i2c_client *client)
+{
+ u8 outbuf = 0;
+
+ return i2c_master_send(client, &outbuf, 1);
+}
+
+static int max517_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max517_data *data;
+ struct max517_platform_data *platform_data = client->dev.platform_data;
+ int err;
+
+ data = kzalloc(sizeof(struct max517_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ data->client = client;
+
+ data->indio_dev = iio_allocate_device();
+ if (data->indio_dev == NULL) {
+ err = -ENOMEM;
+ goto exit_free_data;
+ }
+
+ /* establish that the iio_dev is a child of the i2c device */
+ data->indio_dev->dev.parent = &client->dev;
+
+ /* reduced attribute set for MAX517 */
+ if (id->driver_data == ID_MAX517)
+ data->indio_dev->attrs = &max517_attribute_group;
+ else
+ data->indio_dev->attrs = &max518_attribute_group;
+ data->indio_dev->dev_data = (void *)(data);
+ data->indio_dev->driver_module = THIS_MODULE;
+ data->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /*
+ * Reference voltage on MAX518 and default is 5V, else take vref_mv
+ * from platform_data
+ */
+ if (id->driver_data == ID_MAX518 || !platform_data) {
+ data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
+ } else {
+ data->vref_mv[0] = platform_data->vref_mv[0];
+ data->vref_mv[1] = platform_data->vref_mv[1];
+ }
+
+ err = iio_device_register(data->indio_dev);
+ if (err)
+ goto exit_free_device;
+
+ dev_info(&client->dev, "DAC registered\n");
+
+ return 0;
+
+exit_free_device:
+ iio_free_device(data->indio_dev);
+exit_free_data:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max517_remove(struct i2c_client *client)
+{
+ struct max517_data *data = i2c_get_clientdata(client);
+
+ iio_free_device(data->indio_dev);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id max517_id[] = {
+ { "max517", ID_MAX517 },
+ { "max518", ID_MAX518 },
+ { "max519", ID_MAX519 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max517_id);
+
+static struct i2c_driver max517_driver = {
+ .driver = {
+ .name = MAX517_DRV_NAME,
+ },
+ .probe = max517_probe,
+ .remove = max517_remove,
+ .suspend = max517_suspend,
+ .resume = max517_resume,
+ .id_table = max517_id,
+};
+
+static int __init max517_init(void)
+{
+ return i2c_add_driver(&max517_driver);
+}
+
+static void __exit max517_exit(void)
+{
+ i2c_del_driver(&max517_driver);
+}
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
+MODULE_LICENSE("GPL");
+
+module_init(max517_init);
+module_exit(max517_exit);
diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h
new file mode 100644
index 000000000000..8106cf24642a
--- /dev/null
+++ b/drivers/staging/iio/dac/max517.h
@@ -0,0 +1,19 @@
+/*
+ * MAX517 DAC driver
+ *
+ * Copyright 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_MAX517_H_
+#define IIO_DAC_MAX517_H_
+
+/*
+ * TODO: struct max517_platform_data needs to go into include/linux/iio
+ */
+
+struct max517_platform_data {
+ u16 vref_mv[2];
+};
+
+#endif /* IIO_DAC_MAX517_H_ */
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig
index a047da62daf0..06b6f3a8e420 100644
--- a/drivers/staging/iio/dds/Kconfig
+++ b/drivers/staging/iio/dds/Kconfig
@@ -15,7 +15,10 @@ config AD9832
depends on SPI
help
Say yes here to build support for Analog Devices DDS chip
- ad9832 and ad9835, provides direct access via sysfs.
+ AD9832 and AD9835, provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad9832.
config AD9834
tristate "Analog Devices ad9833/4/ driver"
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
index e911893b3db0..3e8491f60cfe 100644
--- a/drivers/staging/iio/dds/ad9832.c
+++ b/drivers/staging/iio/dds/ad9832.c
@@ -1,228 +1,336 @@
/*
- * Driver for ADI Direct Digital Synthesis ad9832
+ * AD9832 SPI DDS driver
*
- * Copyright (c) 2010 Analog Devices Inc.
- *
- * 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.
+ * Copyright 2011 Analog Devices Inc.
*
+ * Licensed under the GPL-2.
*/
-#include <linux/types.h>
-#include <linux/mutex.h>
+
#include <linux/device.h>
-#include <linux/spi/spi.h>
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <asm/div64.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "dds.h"
-#define DRV_NAME "ad9832"
-
-#define value_mask (u16)0xf000
-#define cmd_shift 12
-#define add_shift 8
-#define AD9832_SYNC (1 << 13)
-#define AD9832_SELSRC (1 << 12)
-#define AD9832_SLEEP (1 << 13)
-#define AD9832_RESET (1 << 12)
-#define AD9832_CLR (1 << 11)
-
-#define ADD_FREQ0LL 0x0
-#define ADD_FREQ0HL 0x1
-#define ADD_FREQ0LM 0x2
-#define ADD_FREQ0HM 0x3
-#define ADD_FREQ1LL 0x4
-#define ADD_FREQ1HL 0x5
-#define ADD_FREQ1LM 0x6
-#define ADD_FREQ1HM 0x7
-#define ADD_PHASE0L 0x8
-#define ADD_PHASE0H 0x9
-#define ADD_PHASE1L 0xa
-#define ADD_PHASE1H 0xb
-#define ADD_PHASE2L 0xc
-#define ADD_PHASE2H 0xd
-#define ADD_PHASE3L 0xe
-#define ADD_PHASE3H 0xf
-
-#define CMD_PHA8BITSW 0x1
-#define CMD_PHA16BITSW 0x0
-#define CMD_FRE8BITSW 0x3
-#define CMD_FRE16BITSW 0x2
-#define CMD_SELBITSCTL 0x6
-
-struct ad9832_setting {
- u16 freq0[4];
- u16 freq1[4];
- u16 phase0[2];
- u16 phase1[2];
- u16 phase2[2];
- u16 phase3[2];
-};
+#include "ad9832.h"
-struct ad9832_state {
- struct mutex lock;
- struct iio_dev *idev;
- struct spi_device *sdev;
-};
-
-static ssize_t ad9832_set_parameter(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout)
{
- struct spi_message msg;
- struct spi_transfer xfer;
- int ret;
- struct ad9832_setting config;
- struct iio_dev *idev = dev_get_drvdata(dev);
- struct ad9832_state *st = idev->dev_data;
-
- config.freq0[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LL << add_shift | buf[0]);
- config.freq0[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HL << add_shift | buf[1]);
- config.freq0[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LM << add_shift | buf[2]);
- config.freq0[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HM << add_shift | buf[3]);
- config.freq1[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LL << add_shift | buf[4]);
- config.freq1[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HL << add_shift | buf[5]);
- config.freq1[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LM << add_shift | buf[6]);
- config.freq1[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HM << add_shift | buf[7]);
-
- config.phase0[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE0L << add_shift | buf[9]);
- config.phase0[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE0H << add_shift | buf[10]);
- config.phase1[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE1L << add_shift | buf[11]);
- config.phase1[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE1H << add_shift | buf[12]);
- config.phase2[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE2L << add_shift | buf[13]);
- config.phase2[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE2H << add_shift | buf[14]);
- config.phase3[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE3L << add_shift | buf[15]);
- config.phase3[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE3H << add_shift | buf[16]);
-
- xfer.len = 2 * len;
- xfer.tx_buf = &config;
- mutex_lock(&st->lock);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->sdev, &msg);
- if (ret)
- goto error_ret;
-error_ret:
- mutex_unlock(&st->lock);
+ unsigned long long freqreg = (u64) fout *
+ (u64) ((u64) 1L << AD9832_FREQ_BITS);
+ do_div(freqreg, mclk);
+ return freqreg;
+}
- return ret ? ret : len;
+static int ad9832_write_frequency(struct ad9832_state *st,
+ unsigned addr, unsigned long fout)
+{
+ unsigned long regval;
+
+ if (fout > (st->mclk / 2))
+ return -EINVAL;
+
+ regval = ad9832_calc_freqreg(st->mclk, fout);
+
+ st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
+ (addr << ADD_SHIFT) |
+ ((regval >> 24) & 0xFF));
+ st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
+ ((addr - 1) << ADD_SHIFT) |
+ ((regval >> 16) & 0xFF));
+ st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
+ ((addr - 2) << ADD_SHIFT) |
+ ((regval >> 8) & 0xFF));
+ st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
+ ((addr - 3) << ADD_SHIFT) |
+ ((regval >> 0) & 0xFF));
+
+ return spi_sync(st->spi, &st->freq_msg);;
}
-static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9832_set_parameter, 0);
+static int ad9832_write_phase(struct ad9832_state *st,
+ unsigned long addr, unsigned long phase)
+{
+ if (phase > (1 << AD9832_PHASE_BITS))
+ return -EINVAL;
-static struct attribute *ad9832_attributes[] = {
- &iio_dev_attr_dds.dev_attr.attr,
- NULL,
-};
+ st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) |
+ (addr << ADD_SHIFT) |
+ ((phase >> 8) & 0xFF));
+ st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) |
+ ((addr - 1) << ADD_SHIFT) |
+ (phase & 0xFF));
-static const struct attribute_group ad9832_attribute_group = {
- .name = DRV_NAME,
- .attrs = ad9832_attributes,
-};
+ return spi_sync(st->spi, &st->phase_msg);
+}
-static void ad9832_init(struct ad9832_state *st)
+static ssize_t ad9832_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
- struct spi_message msg;
- struct spi_transfer xfer;
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9832_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
- u16 config = 0;
-
- config = 0x3 << 14 | AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+ long val;
- mutex_lock(&st->lock);
-
- xfer.len = 2;
- xfer.tx_buf = &config;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->sdev, &msg);
+ ret = strict_strtoul(buf, 10, &val);
if (ret)
goto error_ret;
- config = 0x2 << 14 | AD9832_SYNC | AD9832_SELSRC;
- xfer.len = 2;
- xfer.tx_buf = &config;
+ mutex_lock(&dev_info->mlock);
+ switch (this_attr->address) {
+ case AD9832_FREQ0HM:
+ case AD9832_FREQ1HM:
+ ret = ad9832_write_frequency(st, this_attr->address, val);
+ break;
+ case AD9832_PHASE0H:
+ case AD9832_PHASE1H:
+ case AD9832_PHASE2H:
+ case AD9832_PHASE3H:
+ ret = ad9832_write_phase(st, this_attr->address, val);
+ break;
+ case AD9832_PINCTRL_EN:
+ if (val)
+ st->ctrl_ss &= ~AD9832_SELSRC;
+ else
+ st->ctrl_ss |= AD9832_SELSRC;
+ st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) |
+ st->ctrl_ss);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9832_FREQ_SYM:
+ if (val == 1)
+ st->ctrl_fp |= AD9832_FREQ;
+ else if (val == 0)
+ st->ctrl_fp &= ~AD9832_FREQ;
+ else {
+ ret = -EINVAL;
+ break;
+ }
+ st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
+ st->ctrl_fp);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9832_PHASE_SYM:
+ if (val < 0 || val > 3) {
+ ret = -EINVAL;
+ break;
+ }
+
+ st->ctrl_fp &= ~AD9832_PHASE(3);
+ st->ctrl_fp |= AD9832_PHASE(val);
+
+ st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
+ st->ctrl_fp);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9832_OUTPUT_EN:
+ if (val)
+ st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
+ AD9832_CLR);
+ else
+ st->ctrl_src |= AD9832_RESET;
+
+ st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
+ st->ctrl_src);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ mutex_unlock(&dev_info->mlock);
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->sdev, &msg);
- if (ret)
- goto error_ret;
+error_ret:
+ return ret ? ret : len;
+}
- config = CMD_SELBITSCTL << cmd_shift;
- xfer.len = 2;
- xfer.tx_buf = &config;
+static ssize_t ad9832_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9832_state *st = iio_dev_get_devdata(dev_info);
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->sdev, &msg);
- if (ret)
- goto error_ret;
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad9832_show_name, NULL, 0);
- config = 0x3 << 14;
+/**
+ * see dds.h for further information
+ */
- xfer.len = 2;
- xfer.tx_buf = &config;
+static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ0HM);
+static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM);
+static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM);
+static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->sdev, &msg);
- if (ret)
- goto error_ret;
-error_ret:
- mutex_unlock(&st->lock);
+static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_PHASE0H);
+static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_PHASE1H);
+static IIO_DEV_ATTR_PHASE(0, 2, S_IWUSR, NULL, ad9832_write, AD9832_PHASE2H);
+static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H);
+static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL,
+ ad9832_write, AD9832_PHASE_SYM);
+static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
+static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+ ad9832_write, AD9832_PINCTRL_EN);
+static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
+ ad9832_write, AD9832_OUTPUT_EN);
+static struct attribute *ad9832_attributes[] = {
+ &iio_dev_attr_dds0_freq0.dev_attr.attr,
+ &iio_dev_attr_dds0_freq1.dev_attr.attr,
+ &iio_const_attr_dds0_freq_scale.dev_attr.attr,
+ &iio_dev_attr_dds0_phase0.dev_attr.attr,
+ &iio_dev_attr_dds0_phase1.dev_attr.attr,
+ &iio_dev_attr_dds0_phase2.dev_attr.attr,
+ &iio_dev_attr_dds0_phase3.dev_attr.attr,
+ &iio_const_attr_dds0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
+ &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_dds0_out_enable.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
-}
+static const struct attribute_group ad9832_attribute_group = {
+ .attrs = ad9832_attributes,
+};
static int __devinit ad9832_probe(struct spi_device *spi)
{
+ struct ad9832_platform_data *pdata = spi->dev.platform_data;
struct ad9832_state *st;
- int ret = 0;
+ int ret;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
st = kzalloc(sizeof(*st), GFP_KERNEL);
if (st == NULL) {
ret = -ENOMEM;
goto error_ret;
}
- spi_set_drvdata(spi, st);
- mutex_init(&st->lock);
- st->sdev = spi;
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ st->mclk = pdata->mclk;
+
+ spi_set_drvdata(spi, st);
+ st->spi = spi;
- st->idev = iio_allocate_device();
- if (st->idev == NULL) {
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_st;
+ goto error_disable_reg;
}
- st->idev->dev.parent = &spi->dev;
- st->idev->num_interrupt_lines = 0;
- st->idev->event_attrs = NULL;
- st->idev->attrs = &ad9832_attribute_group;
- st->idev->dev_data = (void *)(st);
- st->idev->driver_module = THIS_MODULE;
- st->idev->modes = INDIO_DIRECT_MODE;
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad9832_attribute_group;
+ st->indio_dev->dev_data = (void *) st;
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default messages */
+
+ st->xfer.tx_buf = &st->data;
+ st->xfer.len = 2;
+
+ spi_message_init(&st->msg);
+ spi_message_add_tail(&st->xfer, &st->msg);
+
+ st->freq_xfer[0].tx_buf = &st->freq_data[0];
+ st->freq_xfer[0].len = 2;
+ st->freq_xfer[0].cs_change = 1;
+ st->freq_xfer[1].tx_buf = &st->freq_data[1];
+ st->freq_xfer[1].len = 2;
+ st->freq_xfer[1].cs_change = 1;
+ st->freq_xfer[2].tx_buf = &st->freq_data[2];
+ st->freq_xfer[2].len = 2;
+ st->freq_xfer[2].cs_change = 1;
+ st->freq_xfer[3].tx_buf = &st->freq_data[3];
+ st->freq_xfer[3].len = 2;
+
+ spi_message_init(&st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[2], &st->freq_msg);
+ spi_message_add_tail(&st->freq_xfer[3], &st->freq_msg);
+
+ st->phase_xfer[0].tx_buf = &st->phase_data[0];
+ st->phase_xfer[0].len = 2;
+ st->phase_xfer[0].cs_change = 1;
+ st->phase_xfer[1].tx_buf = &st->phase_data[1];
+ st->phase_xfer[1].len = 2;
+
+ spi_message_init(&st->phase_msg);
+ spi_message_add_tail(&st->phase_xfer[0], &st->phase_msg);
+ spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg);
+
+ st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+ st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
+ st->ctrl_src);
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret) {
+ dev_err(&spi->dev, "device init failed\n");
+ goto error_free_device;
+ }
+
+ ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1);
+ if (ret)
+ goto error_free_device;
- ret = iio_device_register(st->idev);
+ ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2);
if (ret)
- goto error_free_dev;
- spi->max_speed_hz = 2000000;
- spi->mode = SPI_MODE_3;
- spi->bits_per_word = 16;
- spi_setup(spi);
- ad9832_init(st);
+ goto error_free_device;
+
+ ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3);
+ if (ret)
+ goto error_free_device;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
return 0;
-error_free_dev:
- iio_free_device(st->idev);
-error_free_st:
+error_free_device:
+ iio_free_device(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;
@@ -232,33 +340,45 @@ static int __devexit ad9832_remove(struct spi_device *spi)
{
struct ad9832_state *st = spi_get_drvdata(spi);
- iio_device_unregister(st->idev);
+ iio_device_unregister(st->indio_dev);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
kfree(st);
-
return 0;
}
+static const struct spi_device_id ad9832_id[] = {
+ {"ad9832", 0},
+ {"ad9835", 0},
+ {}
+};
+
static struct spi_driver ad9832_driver = {
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = "ad9832",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
},
- .probe = ad9832_probe,
- .remove = __devexit_p(ad9832_remove),
+ .probe = ad9832_probe,
+ .remove = __devexit_p(ad9832_remove),
+ .id_table = ad9832_id,
};
-static __init int ad9832_spi_init(void)
+static int __init ad9832_init(void)
{
return spi_register_driver(&ad9832_driver);
}
-module_init(ad9832_spi_init);
+module_init(ad9832_init);
-static __exit void ad9832_spi_exit(void)
+static void __exit ad9832_exit(void)
{
spi_unregister_driver(&ad9832_driver);
}
-module_exit(ad9832_spi_exit);
+module_exit(ad9832_exit);
-MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("Analog Devices ad9832 driver");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad9832");
diff --git a/drivers/staging/iio/dds/ad9832.h b/drivers/staging/iio/dds/ad9832.h
new file mode 100644
index 000000000000..5d474543dfce
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9832.h
@@ -0,0 +1,128 @@
+/*
+ * AD9832 SPI DDS driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DDS_AD9832_H_
+#define IIO_DDS_AD9832_H_
+
+/* Registers */
+
+#define AD9832_FREQ0LL 0x0
+#define AD9832_FREQ0HL 0x1
+#define AD9832_FREQ0LM 0x2
+#define AD9832_FREQ0HM 0x3
+#define AD9832_FREQ1LL 0x4
+#define AD9832_FREQ1HL 0x5
+#define AD9832_FREQ1LM 0x6
+#define AD9832_FREQ1HM 0x7
+#define AD9832_PHASE0L 0x8
+#define AD9832_PHASE0H 0x9
+#define AD9832_PHASE1L 0xA
+#define AD9832_PHASE1H 0xB
+#define AD9832_PHASE2L 0xC
+#define AD9832_PHASE2H 0xD
+#define AD9832_PHASE3L 0xE
+#define AD9832_PHASE3H 0xF
+
+#define AD9832_PHASE_SYM 0x10
+#define AD9832_FREQ_SYM 0x11
+#define AD9832_PINCTRL_EN 0x12
+#define AD9832_OUTPUT_EN 0x13
+
+/* Command Control Bits */
+
+#define AD9832_CMD_PHA8BITSW 0x1
+#define AD9832_CMD_PHA16BITSW 0x0
+#define AD9832_CMD_FRE8BITSW 0x3
+#define AD9832_CMD_FRE16BITSW 0x2
+#define AD9832_CMD_FPSELECT 0x6
+#define AD9832_CMD_SYNCSELSRC 0x8
+#define AD9832_CMD_SLEEPRESCLR 0xC
+
+#define AD9832_FREQ (1 << 11)
+#define AD9832_PHASE(x) (((x) & 3) << 9)
+#define AD9832_SYNC (1 << 13)
+#define AD9832_SELSRC (1 << 12)
+#define AD9832_SLEEP (1 << 13)
+#define AD9832_RESET (1 << 12)
+#define AD9832_CLR (1 << 11)
+#define CMD_SHIFT 12
+#define ADD_SHIFT 8
+#define AD9832_FREQ_BITS 32
+#define AD9832_PHASE_BITS 12
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/**
+ * struct ad9832_state - driver instance specific data
+ * @indio_dev: the industrial I/O device
+ * @spi: spi_device
+ * @reg: supply regulator
+ * @mclk: external master clock
+ * @ctrl_fp: cached frequency/phase control word
+ * @ctrl_ss: cached sync/selsrc control word
+ * @ctrl_src: cached sleep/reset/clr word
+ * @xfer: default spi transfer
+ * @msg: default spi message
+ * @freq_xfer: tuning word spi transfer
+ * @freq_msg: tuning word spi message
+ * @phase_xfer: tuning word spi transfer
+ * @phase_msg: tuning word spi message
+ * @data: spi transmit buffer
+ * @phase_data: tuning word spi transmit buffer
+ * @freq_data: tuning word spi transmit buffer
+ */
+
+struct ad9832_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned long mclk;
+ unsigned short ctrl_fp;
+ unsigned short ctrl_ss;
+ unsigned short ctrl_src;
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ struct spi_transfer freq_xfer[4];
+ struct spi_message freq_msg;
+ struct spi_transfer phase_xfer[2];
+ struct spi_message phase_msg;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ union {
+ unsigned short freq_data[4]____cacheline_aligned;
+ unsigned short phase_data[2];
+ unsigned short data;
+ };
+};
+
+/*
+ * TODO: struct ad9832_platform_data needs to go into include/linux/iio
+ */
+
+/**
+ * struct ad9832_platform_data - platform specific information
+ * @mclk: master clock in Hz
+ * @freq0: power up freq0 tuning word in Hz
+ * @freq1: power up freq1 tuning word in Hz
+ * @phase0: power up phase0 value [0..4095] correlates with 0..2PI
+ * @phase1: power up phase1 value [0..4095] correlates with 0..2PI
+ * @phase2: power up phase2 value [0..4095] correlates with 0..2PI
+ * @phase3: power up phase3 value [0..4095] correlates with 0..2PI
+ */
+
+struct ad9832_platform_data {
+ unsigned long mclk;
+ unsigned long freq0;
+ unsigned long freq1;
+ unsigned short phase0;
+ unsigned short phase1;
+ unsigned short phase2;
+ unsigned short phase3;
+};
+
+#endif /* IIO_DDS_AD9832_H_ */
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig
index 236f15fdbfc9..8b78fa0e6316 100644
--- a/drivers/staging/iio/gyro/Kconfig
+++ b/drivers/staging/iio/gyro/Kconfig
@@ -25,23 +25,13 @@ config ADIS16130
Angular Rate Sensor driver.
config ADIS16260
- tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver"
+ tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
depends on SPI
select IIO_TRIGGER if IIO_RING_BUFFER
select IIO_SW_RING if IIO_RING_BUFFER
help
Say yes here to build support for Analog Devices ADIS16260 ADIS16265
- programmable digital gyroscope sensor.
+ ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
This driver can also be built as a module. If so, the module
will be called adis16260.
-
-config ADIS16251
- tristate "Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver"
- depends on SPI
- help
- Say yes here to build support for Analog Devices adis16261 programmable
- digital gyroscope sensor.
-
- This driver can also be built as a module. If so, the module
- will be called adis16251.
diff --git a/drivers/staging/iio/gyro/adis16060.h b/drivers/staging/iio/gyro/adis16060.h
deleted file mode 100644
index 5c00e5385ee0..000000000000
--- a/drivers/staging/iio/gyro/adis16060.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef SPI_ADIS16060_H_
-#define SPI_ADIS16060_H_
-
-#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
-#define ADIS16060_SUPPLY_OUT 0x10 /* Measure Temperature */
-#define ADIS16060_AIN2 0x80 /* Measure AIN2 */
-#define ADIS16060_AIN1 0x40 /* Measure AIN1 */
-#define ADIS16060_TEMP_OUT 0x22 /* Set Positive Self-Test and Output for Angular Rate */
-#define ADIS16060_ANGL_OUT 0x21 /* Set Negative Self-Test and Output for Angular Rate */
-
-#define ADIS16060_MAX_TX 3
-#define ADIS16060_MAX_RX 3
-
-/**
- * struct adis16060_state - device instance specific data
- * @us_w: actual spi_device to write data
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
- * @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: recieve buffer
- * @buf_lock: mutex to protect tx and rx
- **/
-struct adis16060_state {
- struct spi_device *us_w;
- struct spi_device *us_r;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
- struct iio_dev *indio_dev;
- struct iio_trigger *trig;
- u8 *tx;
- u8 *rx;
- struct mutex buf_lock;
-};
-
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum adis16060_scan {
- ADIS16060_SCAN_GYRO,
- ADIS16060_SCAN_TEMP,
- ADIS16060_SCAN_ADC_1,
- ADIS16060_SCAN_ADC_2,
-};
-
-void adis16060_remove_trigger(struct iio_dev *indio_dev);
-int adis16060_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t adis16060_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int adis16060_configure_ring(struct iio_dev *indio_dev);
-void adis16060_unconfigure_ring(struct iio_dev *indio_dev);
-
-int adis16060_initialize_ring(struct iio_ring_buffer *ring);
-void adis16060_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void adis16060_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16060_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16060_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16060_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16060_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16060_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16060_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
-#endif /* CONFIG_IIO_RING_BUFFER */
-#endif /* SPI_ADIS16060_H_ */
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index fc48aca04bd3..700eb3980f9e 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -6,9 +6,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
@@ -16,20 +13,38 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/list.h>
+
#include "../iio.h"
#include "../sysfs.h"
#include "gyro.h"
#include "../adc/adc.h"
-#include "adis16060.h"
-
-#define DRIVER_NAME "adis16060"
+#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
+#define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */
+#define ADIS16060_AIN2 0x80 /* Measure AIN2 */
+#define ADIS16060_AIN1 0x40 /* Measure AIN1 */
+
+/**
+ * struct adis16060_state - device instance specific data
+ * @us_w: actual spi_device to write config
+ * @us_r: actual spi_device to read back data
+ * @indio_dev: industrial I/O device structure
+ * @buf: transmit or recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16060_state {
+ struct spi_device *us_w;
+ struct spi_device *us_r;
+ struct iio_dev *indio_dev;
+ struct mutex buf_lock;
+
+ u8 buf[3] ____cacheline_aligned;
+};
-struct adis16060_state *adis16060_st;
+static struct adis16060_state *adis16060_st;
-int adis16060_spi_write(struct device *dev,
+static int adis16060_spi_write(struct device *dev,
u8 val)
{
int ret;
@@ -37,17 +52,14 @@ int adis16060_spi_write(struct device *dev,
struct adis16060_state *st = iio_dev_get_devdata(indio_dev);
mutex_lock(&st->buf_lock);
- st->tx[0] = 0;
- st->tx[1] = 0;
- st->tx[2] = val; /* The last 8 bits clocked in are latched */
-
- ret = spi_write(st->us_w, st->tx, 3);
+ st->buf[2] = val; /* The last 8 bits clocked in are latched */
+ ret = spi_write(st->us_w, st->buf, 3);
mutex_unlock(&st->buf_lock);
return ret;
}
-int adis16060_spi_read(struct device *dev,
+static int adis16060_spi_read(struct device *dev,
u16 *val)
{
int ret;
@@ -56,14 +68,17 @@ int adis16060_spi_read(struct device *dev,
mutex_lock(&st->buf_lock);
- ret = spi_read(st->us_r, st->rx, 3);
+ ret = spi_read(st->us_r, st->buf, 3);
- /* The internal successive approximation ADC begins the conversion process
- * on the falling edge of MSEL1 and starts to place data MSB first on the
- * DOUT line at the 6th falling edge of SCLK
+ /* The internal successive approximation ADC begins the
+ * conversion process on the falling edge of MSEL1 and
+ * starts to place data MSB first on the DOUT line at
+ * the 6th falling edge of SCLK
*/
if (ret == 0)
- *val = ((st->rx[0] & 0x3) << 12) | (st->rx[1] << 4) | ((st->rx[2] >> 4) & 0xF);
+ *val = ((st->buf[0] & 0x3) << 12) |
+ (st->buf[1] << 4) |
+ ((st->buf[2] >> 4) & 0xF);
mutex_unlock(&st->buf_lock);
return ret;
@@ -73,13 +88,19 @@ static ssize_t adis16060_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- u16 val;
+ u16 val = 0;
ssize_t ret;
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
- ret = adis16060_spi_read(dev, &val);
+
+ ret = adis16060_spi_write(dev, this_attr->address);
+ if (ret < 0)
+ goto error_ret;
+ ret = adis16060_spi_read(dev, &val);
+error_ret:
mutex_unlock(&indio_dev->mlock);
if (ret == 0)
@@ -88,45 +109,22 @@ static ssize_t adis16060_read(struct device *dev,
return ret;
}
-static ssize_t adis16060_write(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- long val;
-
- ret = strict_strtol(buf, 16, &val);
- if (ret)
- goto error_ret;
- ret = adis16060_spi_write(dev, val);
-
-error_ret:
- return ret ? ret : len;
-}
-
-#define IIO_DEV_ATTR_IN(_show) \
- IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
-
-#define IIO_DEV_ATTR_OUT(_store) \
- IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
-
-static IIO_DEV_ATTR_IN(adis16060_read);
-static IIO_DEV_ATTR_OUT(adis16060_write);
-
+static IIO_DEV_ATTR_GYRO_Z(adis16060_read, ADIS16060_GYRO);
+static IIO_DEVICE_ATTR(temp_raw, S_IRUGO, adis16060_read, NULL,
+ ADIS16060_TEMP_OUT);
+static IIO_CONST_ATTR_TEMP_SCALE("34"); /* Milli degrees C */
+static IIO_CONST_ATTR_TEMP_OFFSET("-7461.117"); /* Milli degrees C */
+static IIO_DEV_ATTR_IN_RAW(0, adis16060_read, ADIS16060_AIN1);
+static IIO_DEV_ATTR_IN_RAW(1, adis16060_read, ADIS16060_AIN2);
static IIO_CONST_ATTR(name, "adis16060");
-static struct attribute *adis16060_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group adis16060_event_attribute_group = {
- .attrs = adis16060_event_attributes,
-};
-
static struct attribute *adis16060_attributes[] = {
- &iio_dev_attr_in.dev_attr.attr,
- &iio_dev_attr_out.dev_attr.attr,
+ &iio_dev_attr_gyro_z_raw.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_const_attr_temp_scale.dev_attr.attr,
+ &iio_const_attr_temp_offset.dev_attr.attr,
+ &iio_dev_attr_in0_raw.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
NULL
};
@@ -146,82 +144,34 @@ static int __devinit adis16060_r_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, st);
- /* Allocate the comms buffers */
- st->rx = kzalloc(sizeof(*st->rx)*ADIS16060_MAX_RX, GFP_KERNEL);
- if (st->rx == NULL) {
- ret = -ENOMEM;
- goto error_free_st;
- }
- st->tx = kzalloc(sizeof(*st->tx)*ADIS16060_MAX_TX, GFP_KERNEL);
- if (st->tx == NULL) {
- ret = -ENOMEM;
- goto error_free_rx;
- }
st->us_r = spi;
mutex_init(&st->buf_lock);
/* setup the industrialio driver allocated elements */
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_tx;
+ goto error_free_st;
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &adis16060_event_attribute_group;
st->indio_dev->attrs = &adis16060_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis16060_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
+ goto error_free_dev;
regdone = 1;
- ret = adis16060_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_RISING,
- "adis16060");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = adis16060_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
-
adis16060_st = st;
return 0;
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- adis16060_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- adis16060_unconfigure_ring(st->indio_dev);
error_free_dev:
if (regdone)
iio_device_unregister(st->indio_dev);
else
iio_free_device(st->indio_dev);
-error_free_tx:
- kfree(st->tx);
-error_free_rx:
- kfree(st->rx);
error_free_st:
kfree(st);
error_ret:
@@ -234,17 +184,7 @@ static int adis16060_r_remove(struct spi_device *spi)
struct adis16060_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->indio_dev;
- flush_scheduled_work();
-
- adis16060_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- adis16060_uninitialize_ring(indio_dev->ring);
- adis16060_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
- kfree(st->tx);
- kfree(st->rx);
kfree(st);
return 0;
@@ -315,5 +255,5 @@ static __exit void adis16060_exit(void)
module_exit(adis16060_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16080.h b/drivers/staging/iio/gyro/adis16080.h
deleted file mode 100644
index 3fcbe67f7c31..000000000000
--- a/drivers/staging/iio/gyro/adis16080.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef SPI_ADIS16080_H_
-#define SPI_ADIS16080_H_
-
-#define ADIS16080_DIN_CODE 4 /* Output data format setting. 0: Twos complement. 1: Offset binary. */
-#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
-#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
-#define ADIS16080_DIN_AIN1 (2 << 10)
-#define ADIS16080_DIN_AIN2 (3 << 10)
-#define ADIS16080_DIN_WRITE (1 << 15) /* 1: Write contents on DIN to control register.
- * 0: No changes to control register.
- */
-
-#define ADIS16080_MAX_TX 2
-#define ADIS16080_MAX_RX 2
-
-/**
- * struct adis16080_state - device instance specific data
- * @us: actual spi_device to write data
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
- * @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: recieve buffer
- * @buf_lock: mutex to protect tx and rx
- **/
-struct adis16080_state {
- struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
- struct iio_dev *indio_dev;
- struct iio_trigger *trig;
- u8 *tx;
- u8 *rx;
- struct mutex buf_lock;
-};
-
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum adis16080_scan {
- ADIS16080_SCAN_GYRO,
- ADIS16080_SCAN_TEMP,
- ADIS16080_SCAN_ADC_1,
- ADIS16080_SCAN_ADC_2,
-};
-
-void adis16080_remove_trigger(struct iio_dev *indio_dev);
-int adis16080_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t adis16080_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int adis16080_configure_ring(struct iio_dev *indio_dev);
-void adis16080_unconfigure_ring(struct iio_dev *indio_dev);
-
-int adis16080_initialize_ring(struct iio_ring_buffer *ring);
-void adis16080_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void adis16080_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16080_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16080_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16080_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16080_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16080_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16080_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
-#endif /* CONFIG_IIO_RING_BUFFER */
-#endif /* SPI_ADIS16080_H_ */
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 0efb768db7d3..fb4336c7d2a6 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -5,9 +5,6 @@
*
* Licensed under the GPL-2 or later.
*/
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -16,20 +13,40 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
#include "gyro.h"
#include "../adc/adc.h"
-#include "adis16080.h"
+#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
+#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
+#define ADIS16080_DIN_AIN1 (2 << 10)
+#define ADIS16080_DIN_AIN2 (3 << 10)
-#define DRIVER_NAME "adis16080"
+/*
+ * 1: Write contents on DIN to control register.
+ * 0: No changes to control register.
+ */
-struct adis16080_state *adis16080_st;
+#define ADIS16080_DIN_WRITE (1 << 15)
+
+/**
+ * struct adis16080_state - device instance specific data
+ * @us: actual spi_device to write data
+ * @indio_dev: industrial I/O device structure
+ * @buf: transmit or recieve buffer
+ * @buf_lock: mutex to protect tx and rx
+ **/
+struct adis16080_state {
+ struct spi_device *us;
+ struct iio_dev *indio_dev;
+ struct mutex buf_lock;
+
+ u8 buf[2] ____cacheline_aligned;
+};
-int adis16080_spi_write(struct device *dev,
+static int adis16080_spi_write(struct device *dev,
u16 val)
{
int ret;
@@ -37,16 +54,16 @@ int adis16080_spi_write(struct device *dev,
struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
mutex_lock(&st->buf_lock);
- st->tx[0] = val >> 8;
- st->tx[1] = val;
+ st->buf[0] = val >> 8;
+ st->buf[1] = val;
- ret = spi_write(st->us, st->tx, 2);
+ ret = spi_write(st->us, st->buf, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
-int adis16080_spi_read(struct device *dev,
+static int adis16080_spi_read(struct device *dev,
u16 *val)
{
int ret;
@@ -55,10 +72,10 @@ int adis16080_spi_read(struct device *dev,
mutex_lock(&st->buf_lock);
- ret = spi_read(st->us, st->rx, 2);
+ ret = spi_read(st->us, st->buf, 2);
if (ret == 0)
- *val = ((st->rx[0] & 0xF) << 8) | st->rx[1];
+ *val = ((st->buf[0] & 0xF) << 8) | st->buf[1];
mutex_unlock(&st->buf_lock);
return ret;
@@ -68,13 +85,19 @@ static ssize_t adis16080_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- u16 val;
+ u16 val = 0;
ssize_t ret;
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
+ ret = adis16080_spi_write(dev,
+ this_attr->address | ADIS16080_DIN_WRITE);
+ if (ret < 0)
+ goto error_ret;
ret = adis16080_spi_read(dev, &val);
+error_ret:
mutex_unlock(&indio_dev->mlock);
if (ret == 0)
@@ -82,46 +105,18 @@ static ssize_t adis16080_read(struct device *dev,
else
return ret;
}
-
-static ssize_t adis16080_write(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- long val;
-
- ret = strict_strtol(buf, 16, &val);
- if (ret)
- goto error_ret;
- ret = adis16080_spi_write(dev, val);
-
-error_ret:
- return ret ? ret : len;
-}
-
-#define IIO_DEV_ATTR_IN(_show) \
- IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
-
-#define IIO_DEV_ATTR_OUT(_store) \
- IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
-
-static IIO_DEV_ATTR_IN(adis16080_read);
-static IIO_DEV_ATTR_OUT(adis16080_write);
-
+static IIO_DEV_ATTR_GYRO_Z(adis16080_read, ADIS16080_DIN_GYRO);
+static IIO_DEVICE_ATTR(temp_raw, S_IRUGO, adis16080_read, NULL,
+ ADIS16080_DIN_TEMP);
+static IIO_DEV_ATTR_IN_RAW(0, adis16080_read, ADIS16080_DIN_AIN1);
+static IIO_DEV_ATTR_IN_RAW(1, adis16080_read, ADIS16080_DIN_AIN2);
static IIO_CONST_ATTR(name, "adis16080");
-static struct attribute *adis16080_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group adis16080_event_attribute_group = {
- .attrs = adis16080_event_attributes,
-};
-
static struct attribute *adis16080_attributes[] = {
- &iio_dev_attr_in.dev_attr.attr,
- &iio_dev_attr_out.dev_attr.attr,
+ &iio_dev_attr_gyro_z_raw.dev_attr.attr,
+ &iio_dev_attr_temp_raw.dev_attr.attr,
+ &iio_dev_attr_in0_raw.dev_attr.attr,
+ &iio_dev_attr_in1_raw.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
NULL
};
@@ -142,81 +137,33 @@ static int __devinit adis16080_probe(struct spi_device *spi)
spi_set_drvdata(spi, st);
/* Allocate the comms buffers */
- st->rx = kzalloc(sizeof(*st->rx)*ADIS16080_MAX_RX, GFP_KERNEL);
- if (st->rx == NULL) {
- ret = -ENOMEM;
- goto error_free_st;
- }
- st->tx = kzalloc(sizeof(*st->tx)*ADIS16080_MAX_TX, GFP_KERNEL);
- if (st->tx == NULL) {
- ret = -ENOMEM;
- goto error_free_rx;
- }
st->us = spi;
mutex_init(&st->buf_lock);
/* setup the industrialio driver allocated elements */
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_tx;
+ goto error_free_st;
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &adis16080_event_attribute_group;
st->indio_dev->attrs = &adis16080_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis16080_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
+ goto error_free_dev;
regdone = 1;
- ret = adis16080_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_RISING,
- "adis16080");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = adis16080_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
-
- adis16080_st = st;
return 0;
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- adis16080_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- adis16080_unconfigure_ring(st->indio_dev);
error_free_dev:
if (regdone)
iio_device_unregister(st->indio_dev);
else
iio_free_device(st->indio_dev);
-error_free_tx:
- kfree(st->tx);
-error_free_rx:
- kfree(st->rx);
error_free_st:
kfree(st);
error_ret:
@@ -229,17 +176,7 @@ static int adis16080_remove(struct spi_device *spi)
struct adis16080_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->indio_dev;
- flush_scheduled_work();
-
- adis16080_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- adis16080_uninitialize_ring(indio_dev->ring);
- adis16080_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
- kfree(st->tx);
- kfree(st->rx);
kfree(st);
return 0;
@@ -267,5 +204,5 @@ static __exit void adis16080_exit(void)
module_exit(adis16080_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16130.h b/drivers/staging/iio/gyro/adis16130.h
deleted file mode 100644
index ab80ef6a8961..000000000000
--- a/drivers/staging/iio/gyro/adis16130.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef SPI_ADIS16130_H_
-#define SPI_ADIS16130_H_
-
-#define ADIS16130_CON 0x0
-#define ADIS16130_CON_RD (1 << 6)
-#define ADIS16130_IOP 0x1
-#define ADIS16130_IOP_ALL_RDY (1 << 3) /* 1 = data-ready signal low when unread data on all channels; */
-#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
-#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
-#define ADIS16130_TEMPDATA 0xA /* Temperature output */
-#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
-#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
-#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
-#define ADIS16130_TEMPCS_EN (1 << 3)
-#define ADIS16130_RATECONV 0x30
-#define ADIS16130_TEMPCONV 0x32
-#define ADIS16130_MODE 0x38
-#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
-
-#define ADIS16130_MAX_TX 4
-#define ADIS16130_MAX_RX 4
-
-/**
- * struct adis16130_state - device instance specific data
- * @us: actual spi_device to write data
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
- * @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: recieve buffer
- * @buf_lock: mutex to protect tx and rx
- **/
-struct adis16130_state {
- struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
- struct iio_dev *indio_dev;
- struct iio_trigger *trig;
- u8 *tx;
- u8 *rx;
- u32 mode; /* 1: 24bits mode 0:16bits mode */
- struct mutex buf_lock;
-};
-
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum adis16130_scan {
- ADIS16130_SCAN_GYRO,
- ADIS16130_SCAN_TEMP,
-};
-
-void adis16130_remove_trigger(struct iio_dev *indio_dev);
-int adis16130_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t adis16130_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int adis16130_configure_ring(struct iio_dev *indio_dev);
-void adis16130_unconfigure_ring(struct iio_dev *indio_dev);
-
-int adis16130_initialize_ring(struct iio_ring_buffer *ring);
-void adis16130_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void adis16130_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16130_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16130_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16130_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16130_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16130_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16130_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
-#endif /* CONFIG_IIO_RING_BUFFER */
-#endif /* SPI_ADIS16130_H_ */
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index 49ffc7b26e8a..70e2831f8fb8 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -6,9 +6,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
@@ -23,13 +20,41 @@
#include "gyro.h"
#include "../adc/adc.h"
-#include "adis16130.h"
-
-#define DRIVER_NAME "adis16130"
-
-struct adis16130_state *adis16130_st;
+#define ADIS16130_CON 0x0
+#define ADIS16130_CON_RD (1 << 6)
+#define ADIS16130_IOP 0x1
+
+/* 1 = data-ready signal low when unread data on all channels; */
+#define ADIS16130_IOP_ALL_RDY (1 << 3)
+#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
+#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
+#define ADIS16130_TEMPDATA 0xA /* Temperature output */
+#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
+#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
+#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
+#define ADIS16130_TEMPCS_EN (1 << 3)
+#define ADIS16130_RATECONV 0x30
+#define ADIS16130_TEMPCONV 0x32
+#define ADIS16130_MODE 0x38
+#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
+
+/**
+ * struct adis16130_state - device instance specific data
+ * @us: actual spi_device to write data
+ * @indio_dev: industrial I/O device structure
+ * @mode: 24 bits (1) or 16 bits (0)
+ * @buf_lock: mutex to protect tx and rx
+ * @buf: unified tx/rx buffer
+ **/
+struct adis16130_state {
+ struct spi_device *us;
+ struct iio_dev *indio_dev;
+ u32 mode;
+ struct mutex buf_lock;
+ u8 buf[4] ____cacheline_aligned;
+};
-int adis16130_spi_write(struct device *dev, u8 reg_addr,
+static int adis16130_spi_write(struct device *dev, u8 reg_addr,
u8 val)
{
int ret;
@@ -37,16 +62,16 @@ int adis16130_spi_write(struct device *dev, u8 reg_addr,
struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
mutex_lock(&st->buf_lock);
- st->tx[0] = reg_addr;
- st->tx[1] = val;
+ st->buf[0] = reg_addr;
+ st->buf[1] = val;
- ret = spi_write(st->us, st->tx, 2);
+ ret = spi_write(st->us, st->buf, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
-int adis16130_spi_read(struct device *dev, u8 reg_addr,
+static int adis16130_spi_read(struct device *dev, u8 reg_addr,
u32 *val)
{
int ret;
@@ -55,17 +80,19 @@ int adis16130_spi_read(struct device *dev, u8 reg_addr,
mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16130_CON_RD | reg_addr;
+ st->buf[0] = ADIS16130_CON_RD | reg_addr;
if (st->mode)
- ret = spi_read(st->us, st->rx, 4);
+ ret = spi_read(st->us, st->buf, 4);
else
- ret = spi_read(st->us, st->rx, 3);
+ ret = spi_read(st->us, st->buf, 3);
if (ret == 0) {
if (st->mode)
- *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+ *val = (st->buf[1] << 16) |
+ (st->buf[2] << 8) |
+ st->buf[3];
else
- *val = (st->rx[1] << 8) | st->rx[2];
+ *val = (st->buf[1] << 8) | st->buf[2];
}
mutex_unlock(&st->buf_lock);
@@ -73,36 +100,18 @@ int adis16130_spi_read(struct device *dev, u8 reg_addr,
return ret;
}
-static ssize_t adis16130_gyro_read(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- u32 val;
- ssize_t ret;
-
- /* Take the iio_dev status lock */
- mutex_lock(&indio_dev->mlock);
- ret = adis16130_spi_read(dev, ADIS16130_RATEDATA, &val);
- mutex_unlock(&indio_dev->mlock);
-
- if (ret == 0)
- return sprintf(buf, "%d\n", val);
- else
- return ret;
-}
-
-static ssize_t adis16130_temp_read(struct device *dev,
+static ssize_t adis16130_val_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
u32 val;
ssize_t ret;
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
- ret = adis16130_spi_read(dev, ADIS16130_TEMPDATA, &val);
+ ret = adis16130_spi_read(dev, this_attr->address, &val);
mutex_unlock(&indio_dev->mlock);
if (ret == 0)
@@ -118,7 +127,10 @@ static ssize_t adis16130_bitsmode_read(struct device *dev,
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
- return sprintf(buf, "%d\n", st->mode);
+ if (st->mode == 1)
+ return sprintf(buf, "s24\n");
+ else
+ return sprintf(buf, "s16\n");
}
static ssize_t adis16130_bitsmode_write(struct device *dev,
@@ -127,43 +139,38 @@ static ssize_t adis16130_bitsmode_write(struct device *dev,
size_t len)
{
int ret;
- long val;
+ u8 val;
- ret = strict_strtol(buf, 16, &val);
- if (ret)
- goto error_ret;
- ret = adis16130_spi_write(dev, ADIS16130_MODE, !!val);
+ if (sysfs_streq(buf, "s16"))
+ val = 0;
+ else if (sysfs_streq(buf, "s24"))
+ val = 1;
+ else
+ return -EINVAL;
+
+ ret = adis16130_spi_write(dev, ADIS16130_MODE, val);
-error_ret:
return ret ? ret : len;
}
-
-static IIO_DEV_ATTR_TEMP_RAW(adis16130_temp_read);
+static IIO_DEVICE_ATTR(temp_raw, S_IRUGO, adis16130_val_read, NULL,
+ ADIS16130_TEMPDATA);
static IIO_CONST_ATTR(name, "adis16130");
-static IIO_DEV_ATTR_GYRO(adis16130_gyro_read,
- ADIS16130_RATEDATA);
-
-#define IIO_DEV_ATTR_BITS_MODE(_mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(bits_mode, _mode, _show, _store, _addr)
+static IIO_DEV_ATTR_GYRO_Z(adis16130_val_read, ADIS16130_RATEDATA);
-static IIO_DEV_ATTR_BITS_MODE(S_IWUSR | S_IRUGO, adis16130_bitsmode_read, adis16130_bitsmode_write,
+static IIO_DEVICE_ATTR(gyro_z_type, S_IWUSR | S_IRUGO, adis16130_bitsmode_read,
+ adis16130_bitsmode_write,
ADIS16130_MODE);
-static struct attribute *adis16130_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group adis16130_event_attribute_group = {
- .attrs = adis16130_event_attributes,
-};
+static IIO_CONST_ATTR(gyro_z_type_available, "s16 s24");
static struct attribute *adis16130_attributes[] = {
&iio_dev_attr_temp_raw.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
- &iio_dev_attr_gyro_raw.dev_attr.attr,
- &iio_dev_attr_bits_mode.dev_attr.attr,
+ &iio_dev_attr_gyro_z_raw.dev_attr.attr,
+ &iio_dev_attr_gyro_z_type.dev_attr.attr,
+ &iio_const_attr_gyro_z_type_available.dev_attr.attr,
NULL
};
@@ -173,7 +180,7 @@ static const struct attribute_group adis16130_attribute_group = {
static int __devinit adis16130_probe(struct spi_device *spi)
{
- int ret, regdone = 0;
+ int ret;
struct adis16130_state *st = kzalloc(sizeof *st, GFP_KERNEL);
if (!st) {
ret = -ENOMEM;
@@ -181,84 +188,30 @@ static int __devinit adis16130_probe(struct spi_device *spi)
}
/* this is only used for removal purposes */
spi_set_drvdata(spi, st);
-
- /* Allocate the comms buffers */
- st->rx = kzalloc(sizeof(*st->rx)*ADIS16130_MAX_RX, GFP_KERNEL);
- if (st->rx == NULL) {
- ret = -ENOMEM;
- goto error_free_st;
- }
- st->tx = kzalloc(sizeof(*st->tx)*ADIS16130_MAX_TX, GFP_KERNEL);
- if (st->tx == NULL) {
- ret = -ENOMEM;
- goto error_free_rx;
- }
st->us = spi;
mutex_init(&st->buf_lock);
/* setup the industrialio driver allocated elements */
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_tx;
+ goto error_free_st;
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &adis16130_event_attribute_group;
st->indio_dev->attrs = &adis16130_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
st->mode = 1;
- ret = adis16130_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
- regdone = 1;
-
- ret = adis16130_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_RISING,
- "adis16130");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = adis16130_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
+ goto error_free_dev;
- adis16130_st = st;
return 0;
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- adis16130_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- adis16130_unconfigure_ring(st->indio_dev);
error_free_dev:
- if (regdone)
- iio_device_unregister(st->indio_dev);
- else
- iio_free_device(st->indio_dev);
-error_free_tx:
- kfree(st->tx);
-error_free_rx:
- kfree(st->rx);
+ iio_free_device(st->indio_dev);
error_free_st:
kfree(st);
error_ret:
@@ -271,17 +224,7 @@ static int adis16130_remove(struct spi_device *spi)
struct adis16130_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->indio_dev;
- flush_scheduled_work();
-
- adis16130_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- adis16130_uninitialize_ring(indio_dev->ring);
- adis16130_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
- kfree(st->tx);
- kfree(st->rx);
kfree(st);
return 0;
@@ -309,5 +252,5 @@ static __exit void adis16130_exit(void)
module_exit(adis16130_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate Sensor driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16251.h b/drivers/staging/iio/gyro/adis16251.h
deleted file mode 100644
index d23852cf78e8..000000000000
--- a/drivers/staging/iio/gyro/adis16251.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef SPI_ADIS16251_H_
-#define SPI_ADIS16251_H_
-
-#define ADIS16251_STARTUP_DELAY 220 /* ms */
-
-#define ADIS16251_READ_REG(a) a
-#define ADIS16251_WRITE_REG(a) ((a) | 0x80)
-
-#define ADIS16251_ENDURANCE 0x00 /* Flash memory write count */
-#define ADIS16251_SUPPLY_OUT 0x02 /* Power supply measurement */
-#define ADIS16251_GYRO_OUT 0x04 /* X-axis gyroscope output */
-#define ADIS16251_AUX_ADC 0x0A /* analog input channel measurement */
-#define ADIS16251_TEMP_OUT 0x0C /* internal temperature measurement */
-#define ADIS16251_ANGL_OUT 0x0E /* angle displacement */
-#define ADIS16251_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */
-#define ADIS16251_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
-#define ADIS16251_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */
-#define ADIS16251_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */
-#define ADIS16251_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */
-#define ADIS16251_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */
-#define ADIS16251_ALM_CTRL 0x28 /* Alarm control */
-#define ADIS16251_AUX_DAC 0x30 /* Auxiliary DAC data */
-#define ADIS16251_GPIO_CTRL 0x32 /* Control, digital I/O line */
-#define ADIS16251_MSC_CTRL 0x34 /* Control, data ready, self-test settings */
-#define ADIS16251_SMPL_PRD 0x36 /* Control, internal sample rate */
-#define ADIS16251_SENS_AVG 0x38 /* Control, dynamic range, filtering */
-#define ADIS16251_SLP_CNT 0x3A /* Control, sleep mode initiation */
-#define ADIS16251_DIAG_STAT 0x3C /* Diagnostic, error flags */
-#define ADIS16251_GLOB_CMD 0x3E /* Control, global commands */
-
-#define ADIS16251_ERROR_ACTIVE (1<<14)
-#define ADIS16251_NEW_DATA (1<<14)
-
-/* MSC_CTRL */
-#define ADIS16251_MSC_CTRL_INT_SELF_TEST (1<<10) /* Internal self-test enable */
-#define ADIS16251_MSC_CTRL_NEG_SELF_TEST (1<<9)
-#define ADIS16251_MSC_CTRL_POS_SELF_TEST (1<<8)
-#define ADIS16251_MSC_CTRL_DATA_RDY_EN (1<<2)
-#define ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
-#define ADIS16251_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
-
-/* SMPL_PRD */
-#define ADIS16251_SMPL_PRD_TIME_BASE (1<<7) /* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
-#define ADIS16251_SMPL_PRD_DIV_MASK 0x7F
-
-/* SLP_CNT */
-#define ADIS16251_SLP_CNT_POWER_OFF 0x80
-
-/* DIAG_STAT */
-#define ADIS16251_DIAG_STAT_ALARM2 (1<<9)
-#define ADIS16251_DIAG_STAT_ALARM1 (1<<8)
-#define ADIS16251_DIAG_STAT_SELF_TEST (1<<5)
-#define ADIS16251_DIAG_STAT_OVERFLOW (1<<4)
-#define ADIS16251_DIAG_STAT_SPI_FAIL (1<<3)
-#define ADIS16251_DIAG_STAT_FLASH_UPT (1<<2)
-#define ADIS16251_DIAG_STAT_POWER_HIGH (1<<1)
-#define ADIS16251_DIAG_STAT_POWER_LOW (1<<0)
-
-#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16251_DIAG_STAT_ALARM2 | \
- ADIS16251_DIAG_STAT_ALARM1 | \
- ADIS16251_DIAG_STAT_SELF_TEST | \
- ADIS16251_DIAG_STAT_OVERFLOW | \
- ADIS16251_DIAG_STAT_SPI_FAIL | \
- ADIS16251_DIAG_STAT_FLASH_UPT | \
- ADIS16251_DIAG_STAT_POWER_HIGH | \
- ADIS16251_DIAG_STAT_POWER_LOW)
-
-/* GLOB_CMD */
-#define ADIS16251_GLOB_CMD_SW_RESET (1<<7)
-#define ADIS16251_GLOB_CMD_FLASH_UPD (1<<3)
-#define ADIS16251_GLOB_CMD_DAC_LATCH (1<<2)
-#define ADIS16251_GLOB_CMD_FAC_CALIB (1<<1)
-#define ADIS16251_GLOB_CMD_AUTO_NULL (1<<0)
-
-#define ADIS16251_MAX_TX 24
-#define ADIS16251_MAX_RX 24
-
-#define ADIS16251_SPI_SLOW (u32)(300 * 1000)
-#define ADIS16251_SPI_BURST (u32)(1000 * 1000)
-#define ADIS16251_SPI_FAST (u32)(2000 * 1000)
-
-/**
- * struct adis16251_state - device instance specific data
- * @us: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
- * @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: recieve buffer
- * @buf_lock: mutex to protect tx and rx
- **/
-struct adis16251_state {
- struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
- struct iio_dev *indio_dev;
- struct iio_trigger *trig;
- u8 *tx;
- u8 *rx;
- struct mutex buf_lock;
-};
-
-int adis16251_spi_write_reg_8(struct device *dev,
- u8 reg_address,
- u8 val);
-
-int adis16251_spi_read_burst(struct device *dev, u8 *rx);
-
-int adis16251_spi_read_sequence(struct device *dev,
- u8 *tx, u8 *rx, int num);
-
-int adis16251_set_irq(struct device *dev, bool enable);
-
-int adis16251_reset(struct device *dev);
-
-int adis16251_stop_device(struct device *dev);
-
-int adis16251_check_status(struct device *dev);
-
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum adis16251_scan {
- ADIS16251_SCAN_SUPPLY,
- ADIS16251_SCAN_GYRO,
- ADIS16251_SCAN_TEMP,
- ADIS16251_SCAN_ADC_0,
-};
-
-void adis16251_remove_trigger(struct iio_dev *indio_dev);
-int adis16251_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t adis16251_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int adis16251_configure_ring(struct iio_dev *indio_dev);
-void adis16251_unconfigure_ring(struct iio_dev *indio_dev);
-
-int adis16251_initialize_ring(struct iio_ring_buffer *ring);
-void adis16251_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void adis16251_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16251_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16251_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16251_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16251_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16251_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16251_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
-#endif /* CONFIG_IIO_RING_BUFFER */
-#endif /* SPI_ADIS16251_H_ */
diff --git a/drivers/staging/iio/gyro/adis16251_core.c b/drivers/staging/iio/gyro/adis16251_core.c
deleted file mode 100644
index a0d400f7ee62..000000000000
--- a/drivers/staging/iio/gyro/adis16251_core.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- * ADIS16251 Programmable Digital Gyroscope Sensor Driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-#include "gyro.h"
-#include "../adc/adc.h"
-
-#include "adis16251.h"
-
-#define DRIVER_NAME "adis16251"
-
-/* At the moment the spi framework doesn't allow global setting of cs_change.
- * It's in the likely to be added comment at the top of spi.h.
- * This means that use cannot be made of spi_write etc.
- */
-
-/**
- * adis16251_spi_write_reg_8() - write single byte to a register
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the register to be written
- * @val: the value to write
- **/
-int adis16251_spi_write_reg_8(struct device *dev,
- u8 reg_address,
- u8 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16251_WRITE_REG(reg_address);
- st->tx[1] = val;
-
- ret = spi_write(st->us, st->tx, 2);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-/**
- * adis16251_spi_write_reg_16() - write 2 bytes to a pair of registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the lower of the two registers. Second register
- * is assumed to have address one greater.
- * @val: value to be written
- **/
-static int adis16251_spi_write_reg_16(struct device *dev,
- u8 lower_reg_address,
- u16 value)
-{
- int ret;
- struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- }, {
- .tx_buf = st->tx + 2,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16251_WRITE_REG(lower_reg_address);
- st->tx[1] = value & 0xFF;
- st->tx[2] = ADIS16251_WRITE_REG(lower_reg_address + 1);
- st->tx[3] = (value >> 8) & 0xFF;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(st->us, &msg);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-/**
- * adis16251_spi_read_reg_16() - read 2 bytes from a 16-bit register
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the lower of the two registers. Second register
- * is assumed to have address one greater.
- * @val: somewhere to pass back the value read
- **/
-static int adis16251_spi_read_reg_16(struct device *dev,
- u8 lower_reg_address,
- u16 *val)
-{
- struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- }, {
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 1,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16251_READ_REG(lower_reg_address);
- st->tx[1] = 0;
- st->tx[2] = 0;
- st->tx[3] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
- dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
- lower_reg_address);
- goto error_ret;
- }
- *val = (st->rx[0] << 8) | st->rx[1];
-
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-/**
- * adis16251_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @rx: somewhere to pass back the value read (min size is 24 bytes)
- **/
-int adis16251_spi_read_burst(struct device *dev, u8 *rx)
-{
- struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
- u32 old_speed_hz = st->us->max_speed_hz;
- int ret;
-
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 0,
- }, {
- .rx_buf = rx,
- .bits_per_word = 8,
- .len = 24,
- .cs_change = 1,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16251_READ_REG(ADIS16251_GLOB_CMD);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
-
- st->us->max_speed_hz = min(ADIS16251_SPI_BURST, old_speed_hz);
- spi_setup(st->us);
-
- ret = spi_sync(st->us, &msg);
- if (ret)
- dev_err(&st->us->dev, "problem when burst reading");
-
- st->us->max_speed_hz = old_speed_hz;
- spi_setup(st->us);
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-/**
- * adis16251_spi_read_sequence() - read a sequence of 16-bit registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @tx: register addresses in bytes 0,2,4,6... (min size is 2*num bytes)
- * @rx: somewhere to pass back the value read (min size is 2*num bytes)
- **/
-int adis16251_spi_read_sequence(struct device *dev,
- u8 *tx, u8 *rx, int num)
-{
- struct spi_message msg;
- struct spi_transfer *xfers;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
- int ret, i;
-
- xfers = kzalloc(num + 1, GFP_KERNEL);
- if (xfers == NULL) {
- dev_err(&st->us->dev, "memory alloc failed");
- ret = -ENOMEM;
- goto error_ret;
- }
-
- /* tx: |add1|addr2|addr3|...|addrN |zero|
- * rx: |zero|res1 |res2 |...|resN-1|resN| */
- spi_message_init(&msg);
- for (i = 0; i < num + 1; i++) {
- if (i > 0)
- xfers[i].rx_buf = st->rx + 2*(i - 1);
- if (i < num)
- xfers[i].tx_buf = st->tx + 2*i;
- xfers[i].bits_per_word = 8;
- xfers[i].len = 2;
- xfers[i].cs_change = 1;
- spi_message_add_tail(&xfers[i], &msg);
- }
-
- mutex_lock(&st->buf_lock);
-
- ret = spi_sync(st->us, &msg);
- if (ret)
- dev_err(&st->us->dev, "problem when reading sequence");
-
- mutex_unlock(&st->buf_lock);
- kfree(xfers);
-
-error_ret:
- return ret;
-}
-
-static ssize_t adis16251_spi_read_signed(struct device *dev,
- struct device_attribute *attr,
- char *buf,
- unsigned bits)
-{
- int ret;
- s16 val = 0;
- unsigned shift = 16 - bits;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = adis16251_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
- if (ret)
- return ret;
-
- if (val & ADIS16251_ERROR_ACTIVE)
- adis16251_check_status(dev);
- val = ((s16)(val << shift) >> shift);
- return sprintf(buf, "%d\n", val);
-}
-
-static ssize_t adis16251_read_12bit_unsigned(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int ret;
- u16 val = 0;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = adis16251_spi_read_reg_16(dev, this_attr->address, &val);
- if (ret)
- return ret;
-
- if (val & ADIS16251_ERROR_ACTIVE)
- adis16251_check_status(dev);
-
- return sprintf(buf, "%u\n", val & 0x0FFF);
-}
-
-static ssize_t adis16251_read_14bit_signed(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- ssize_t ret;
-
- /* Take the iio_dev status lock */
- mutex_lock(&indio_dev->mlock);
- ret = adis16251_spi_read_signed(dev, attr, buf, 14);
- mutex_unlock(&indio_dev->mlock);
-
- return ret;
-}
-
-static ssize_t adis16251_read_12bit_signed(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- ssize_t ret;
-
- /* Take the iio_dev status lock */
- mutex_lock(&indio_dev->mlock);
- ret = adis16251_spi_read_signed(dev, attr, buf, 12);
- mutex_unlock(&indio_dev->mlock);
-
- return ret;
-}
-
-static ssize_t adis16251_write_16bit(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int ret;
- long val;
-
- ret = strict_strtol(buf, 10, &val);
- if (ret)
- goto error_ret;
- ret = adis16251_spi_write_reg_16(dev, this_attr->address, val);
-
-error_ret:
- return ret ? ret : len;
-}
-
-static ssize_t adis16251_read_frequency(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int ret, len = 0;
- u16 t;
- int sps;
- ret = adis16251_spi_read_reg_16(dev,
- ADIS16251_SMPL_PRD,
- &t);
- if (ret)
- return ret;
- sps = (t & ADIS16251_SMPL_PRD_TIME_BASE) ? 8 : 256;
- sps /= (t & ADIS16251_SMPL_PRD_DIV_MASK) + 1;
- len = sprintf(buf, "%d SPS\n", sps);
- return len;
-}
-
-static ssize_t adis16251_write_frequency(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
- long val;
- int ret;
- u8 t;
-
- ret = strict_strtol(buf, 10, &val);
- if (ret)
- return ret;
-
- mutex_lock(&indio_dev->mlock);
-
- t = (256 / val);
- if (t > 0)
- t--;
- t &= ADIS16251_SMPL_PRD_DIV_MASK;
- if ((t & ADIS16251_SMPL_PRD_DIV_MASK) >= 0x0A)
- st->us->max_speed_hz = ADIS16251_SPI_SLOW;
- else
- st->us->max_speed_hz = ADIS16251_SPI_FAST;
-
- ret = adis16251_spi_write_reg_8(dev,
- ADIS16251_SMPL_PRD,
- t);
-
- mutex_unlock(&indio_dev->mlock);
-
- return ret ? ret : len;
-}
-
-static ssize_t adis16251_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return adis16251_reset(dev);
- }
- return -1;
-}
-
-
-
-int adis16251_set_irq(struct device *dev, bool enable)
-{
- int ret;
- u16 msc;
- ret = adis16251_spi_read_reg_16(dev, ADIS16251_MSC_CTRL, &msc);
- if (ret)
- goto error_ret;
-
- msc |= ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH;
- if (enable)
- msc |= ADIS16251_MSC_CTRL_DATA_RDY_EN;
- else
- msc &= ~ADIS16251_MSC_CTRL_DATA_RDY_EN;
-
- ret = adis16251_spi_write_reg_16(dev, ADIS16251_MSC_CTRL, msc);
- if (ret)
- goto error_ret;
-
-error_ret:
- return ret;
-}
-
-int adis16251_reset(struct device *dev)
-{
- int ret;
- ret = adis16251_spi_write_reg_8(dev,
- ADIS16251_GLOB_CMD,
- ADIS16251_GLOB_CMD_SW_RESET);
- if (ret)
- dev_err(dev, "problem resetting device");
-
- return ret;
-}
-
-/* Power down the device */
-int adis16251_stop_device(struct device *dev)
-{
- int ret;
- u16 val = ADIS16251_SLP_CNT_POWER_OFF;
-
- ret = adis16251_spi_write_reg_16(dev, ADIS16251_SLP_CNT, val);
- if (ret)
- dev_err(dev, "problem with turning device off: SLP_CNT");
-
- return ret;
-}
-
-static int adis16251_self_test(struct device *dev)
-{
- int ret;
-
- ret = adis16251_spi_write_reg_16(dev,
- ADIS16251_MSC_CTRL,
- ADIS16251_MSC_CTRL_INT_SELF_TEST);
- if (ret) {
- dev_err(dev, "problem starting self test");
- goto err_ret;
- }
-
- adis16251_check_status(dev);
-
-err_ret:
- return ret;
-}
-
-int adis16251_check_status(struct device *dev)
-{
- u16 status;
- int ret;
-
- ret = adis16251_spi_read_reg_16(dev, ADIS16251_DIAG_STAT, &status);
-
- if (ret < 0) {
- dev_err(dev, "Reading status failed\n");
- goto error_ret;
- }
-
- if (!(status & ADIS16251_DIAG_STAT_ERR_MASK)) {
- ret = 0;
- goto error_ret;
- }
-
- ret = -EFAULT;
-
- if (status & ADIS16251_DIAG_STAT_ALARM2)
- dev_err(dev, "Alarm 2 active\n");
- if (status & ADIS16251_DIAG_STAT_ALARM1)
- dev_err(dev, "Alarm 1 active\n");
- if (status & ADIS16251_DIAG_STAT_SELF_TEST)
- dev_err(dev, "Self test error\n");
- if (status & ADIS16251_DIAG_STAT_OVERFLOW)
- dev_err(dev, "Sensor overrange\n");
- if (status & ADIS16251_DIAG_STAT_SPI_FAIL)
- dev_err(dev, "SPI failure\n");
- if (status & ADIS16251_DIAG_STAT_FLASH_UPT)
- dev_err(dev, "Flash update failed\n");
- if (status & ADIS16251_DIAG_STAT_POWER_HIGH)
- dev_err(dev, "Power supply above 5.25V\n");
- if (status & ADIS16251_DIAG_STAT_POWER_LOW)
- dev_err(dev, "Power supply below 4.75V\n");
-
-error_ret:
- return ret;
-}
-
-static int adis16251_initial_setup(struct adis16251_state *st)
-{
- int ret;
- u16 smp_prd;
- struct device *dev = &st->indio_dev->dev;
-
- /* use low spi speed for init */
- st->us->max_speed_hz = ADIS16251_SPI_SLOW;
- st->us->mode = SPI_MODE_3;
- spi_setup(st->us);
-
- /* Disable IRQ */
- ret = adis16251_set_irq(dev, false);
- if (ret) {
- dev_err(dev, "disable irq failed");
- goto err_ret;
- }
-
- /* Do self test */
-
- /* Read status register to check the result */
- ret = adis16251_check_status(dev);
- if (ret) {
- adis16251_reset(dev);
- dev_err(dev, "device not playing ball -> reset");
- msleep(ADIS16251_STARTUP_DELAY);
- ret = adis16251_check_status(dev);
- if (ret) {
- dev_err(dev, "giving up");
- goto err_ret;
- }
- }
-
- printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
- st->us->chip_select, st->us->irq);
-
- /* use high spi speed if possible */
- ret = adis16251_spi_read_reg_16(dev, ADIS16251_SMPL_PRD, &smp_prd);
- if (!ret && (smp_prd & ADIS16251_SMPL_PRD_DIV_MASK) < 0x0A) {
- st->us->max_speed_hz = ADIS16251_SPI_SLOW;
- spi_setup(st->us);
- }
-
-err_ret:
- return ret;
-}
-
-static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16251_read_12bit_signed,
- ADIS16251_SUPPLY_OUT);
-static IIO_CONST_ATTR(in0_supply_scale, "0.0018315");
-
-static IIO_DEV_ATTR_GYRO(adis16251_read_14bit_signed,
- ADIS16251_GYRO_OUT);
-static IIO_DEV_ATTR_GYRO_SCALE(S_IWUSR | S_IRUGO,
- adis16251_read_12bit_signed,
- adis16251_write_16bit,
- ADIS16251_GYRO_SCALE);
-static IIO_DEV_ATTR_GYRO_OFFSET(S_IWUSR | S_IRUGO,
- adis16251_read_12bit_signed,
- adis16251_write_16bit,
- ADIS16251_GYRO_OFF);
-
-static IIO_DEV_ATTR_TEMP_RAW(adis16251_read_12bit_signed);
-static IIO_CONST_ATTR(temp_offset, "25 K");
-static IIO_CONST_ATTR(temp_scale, "0.1453 K");
-
-static IIO_DEV_ATTR_IN_NAMED_RAW(1, aux, adis16251_read_12bit_unsigned,
- ADIS16251_AUX_ADC);
-static IIO_CONST_ATTR(in1_aux_scale, "0.0006105");
-
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
- adis16251_read_frequency,
- adis16251_write_frequency);
-static IIO_DEV_ATTR_ANGL(adis16251_read_14bit_signed,
- ADIS16251_ANGL_OUT);
-
-static IIO_DEV_ATTR_RESET(adis16251_write_reset);
-
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.129 ~ 256");
-
-static IIO_CONST_ATTR(name, "adis16251");
-
-static struct attribute *adis16251_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group adis16251_event_attribute_group = {
- .attrs = adis16251_event_attributes,
-};
-
-static struct attribute *adis16251_attributes[] = {
- &iio_dev_attr_in0_supply_raw.dev_attr.attr,
- &iio_const_attr_in0_supply_scale.dev_attr.attr,
- &iio_dev_attr_gyro_raw.dev_attr.attr,
- &iio_dev_attr_gyro_scale.dev_attr.attr,
- &iio_dev_attr_gyro_offset.dev_attr.attr,
- &iio_dev_attr_angl_raw.dev_attr.attr,
- &iio_dev_attr_temp_raw.dev_attr.attr,
- &iio_const_attr_temp_offset.dev_attr.attr,
- &iio_const_attr_temp_scale.dev_attr.attr,
- &iio_dev_attr_in1_aux_raw.dev_attr.attr,
- &iio_const_attr_in1_aux_scale.dev_attr.attr,
- &iio_dev_attr_sampling_frequency.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
- &iio_const_attr_name.dev_attr.attr,
- NULL
-};
-
-static const struct attribute_group adis16251_attribute_group = {
- .attrs = adis16251_attributes,
-};
-
-static int __devinit adis16251_probe(struct spi_device *spi)
-{
- int ret, regdone = 0;
- struct adis16251_state *st = kzalloc(sizeof *st, GFP_KERNEL);
- if (!st) {
- ret = -ENOMEM;
- goto error_ret;
- }
- /* this is only used for removal purposes */
- spi_set_drvdata(spi, st);
-
- /* Allocate the comms buffers */
- st->rx = kzalloc(sizeof(*st->rx)*ADIS16251_MAX_RX, GFP_KERNEL);
- if (st->rx == NULL) {
- ret = -ENOMEM;
- goto error_free_st;
- }
- st->tx = kzalloc(sizeof(*st->tx)*ADIS16251_MAX_TX, GFP_KERNEL);
- if (st->tx == NULL) {
- ret = -ENOMEM;
- goto error_free_rx;
- }
- st->us = spi;
- mutex_init(&st->buf_lock);
- /* setup the industrialio driver allocated elements */
- st->indio_dev = iio_allocate_device();
- if (st->indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_free_tx;
- }
-
- st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &adis16251_event_attribute_group;
- st->indio_dev->attrs = &adis16251_attribute_group;
- st->indio_dev->dev_data = (void *)(st);
- st->indio_dev->driver_module = THIS_MODULE;
- st->indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = adis16251_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
- ret = iio_device_register(st->indio_dev);
- if (ret)
- goto error_unreg_ring_funcs;
- regdone = 1;
-
- ret = adis16251_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_RISING,
- "adis16251");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = adis16251_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
-
- /* Get the device into a sane initial state */
- ret = adis16251_initial_setup(st);
- if (ret)
- goto error_remove_trigger;
- return 0;
-
-error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- adis16251_remove_trigger(st->indio_dev);
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- adis16251_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- adis16251_unconfigure_ring(st->indio_dev);
-error_free_dev:
- if (regdone)
- iio_device_unregister(st->indio_dev);
- else
- iio_free_device(st->indio_dev);
-error_free_tx:
- kfree(st->tx);
-error_free_rx:
- kfree(st->rx);
-error_free_st:
- kfree(st);
-error_ret:
- return ret;
-}
-
-/* fixme, confirm ordering in this function */
-static int adis16251_remove(struct spi_device *spi)
-{
- int ret;
- struct adis16251_state *st = spi_get_drvdata(spi);
- struct iio_dev *indio_dev = st->indio_dev;
-
- ret = adis16251_stop_device(&(indio_dev->dev));
- if (ret)
- goto err_ret;
-
- flush_scheduled_work();
-
- adis16251_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- adis16251_uninitialize_ring(indio_dev->ring);
- adis16251_unconfigure_ring(indio_dev);
- iio_device_unregister(indio_dev);
- kfree(st->tx);
- kfree(st->rx);
- kfree(st);
-
- return 0;
-
-err_ret:
- return ret;
-}
-
-static struct spi_driver adis16251_driver = {
- .driver = {
- .name = "adis16251",
- .owner = THIS_MODULE,
- },
- .probe = adis16251_probe,
- .remove = __devexit_p(adis16251_remove),
-};
-
-static __init int adis16251_init(void)
-{
- return spi_register_driver(&adis16251_driver);
-}
-module_init(adis16251_init);
-
-static __exit void adis16251_exit(void)
-{
- spi_unregister_driver(&adis16251_driver);
-}
-module_exit(adis16251_exit);
-
-MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 045e27da980a..69a29ec93101 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -238,10 +238,24 @@ error_ret:
return ret ? ret : len;
}
+static ssize_t adis16260_read_frequency_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16260_state *st = iio_dev_get_devdata(indio_dev);
+ if (spi_get_device_id(st->us)->driver_data)
+ return sprintf(buf, "%s\n", "0.129 ~ 256");
+ else
+ return sprintf(buf, "%s\n", "256 2048");
+}
+
static ssize_t adis16260_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16260_state *st = iio_dev_get_devdata(indio_dev);
int ret, len = 0;
u16 t;
int sps;
@@ -250,7 +264,11 @@ static ssize_t adis16260_read_frequency(struct device *dev,
&t);
if (ret)
return ret;
- sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
+
+ if (spi_get_device_id(st->us)->driver_data) /* If an adis16251 */
+ sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
+ else
+ sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
len = sprintf(buf, "%d SPS\n", sps);
return len;
@@ -272,16 +290,21 @@ static ssize_t adis16260_write_frequency(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
-
- t = (2048 / val);
- if (t > 0)
- t--;
- t &= ADIS16260_SMPL_PRD_DIV_MASK;
+ if (spi_get_device_id(st->us)) {
+ t = (256 / val);
+ if (t > 0)
+ t--;
+ t &= ADIS16260_SMPL_PRD_DIV_MASK;
+ } else {
+ t = (2048 / val);
+ if (t > 0)
+ t--;
+ t &= ADIS16260_SMPL_PRD_DIV_MASK;
+ }
if ((t & ADIS16260_SMPL_PRD_DIV_MASK) >= 0x0A)
st->us->max_speed_hz = ADIS16260_SPI_SLOW;
else
st->us->max_speed_hz = ADIS16260_SPI_FAST;
-
ret = adis16260_spi_write_reg_8(dev,
ADIS16260_SMPL_PRD,
t);
@@ -302,7 +325,10 @@ static ssize_t adis16260_read_gyro_scale(struct device *dev,
if (st->negate)
ret = sprintf(buf, "-");
/* Take the iio_dev status lock */
- ret += sprintf(buf + ret, "%s\n", "0.00127862821");
+ if (spi_get_device_id(st->us)->driver_data)
+ ret += sprintf(buf + ret, "%s\n", "0.00031974432");
+ else
+ ret += sprintf(buf + ret, "%s\n", "0.00127862821");
return ret;
}
@@ -475,7 +501,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16260_write_reset, 0);
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("256 2048");
+
+static IIO_DEVICE_ATTR(sampling_frequency_available,
+ S_IRUGO, adis16260_read_frequency_available, NULL, 0);
static IIO_CONST_ATTR_NAME("adis16260");
@@ -525,7 +553,7 @@ static ADIS16260_GYRO_ATTR_SET(_Z);
&iio_dev_attr_in1_raw.dev_attr.attr, \
&iio_const_attr_in1_scale.dev_attr.attr, \
&iio_dev_attr_sampling_frequency.dev_attr.attr, \
- &iio_const_attr_sampling_frequency_available.dev_attr.attr, \
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr, \
&iio_dev_attr_reset.dev_attr.attr, \
&iio_const_attr_name.dev_attr.attr, \
NULL \
@@ -693,6 +721,7 @@ static const struct spi_device_id adis16260_id[] = {
{"adis16265", 0},
{"adis16250", 0},
{"adis16255", 0},
+ {"adis16251", 1},
{}
};
diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c
index 9a98fcdbe109..bd4373ae066b 100644
--- a/drivers/staging/iio/industrialio-ring.c
+++ b/drivers/staging/iio/industrialio-ring.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/fs.h>
-#include <linux/poll.h>
#include <linux/cdev.h>
#include <linux/slab.h>
@@ -98,31 +97,13 @@ static ssize_t iio_ring_rip_outer(struct file *filp, char __user *buf,
size_t count, loff_t *f_ps)
{
struct iio_ring_buffer *rb = filp->private_data;
- int ret, dead_offset, copied;
- u8 *data;
+ int ret, dead_offset;
+
/* rip lots must exist. */
if (!rb->access.rip_lots)
return -EINVAL;
- copied = rb->access.rip_lots(rb, count, &data, &dead_offset);
+ ret = rb->access.rip_lots(rb, count, buf, &dead_offset);
- if (copied <= 0) {
- ret = copied;
- goto error_ret;
- }
- if (copy_to_user(buf, data + dead_offset, copied)) {
- ret = -EFAULT;
- goto error_free_data_cpy;
- }
- /* In clever ring buffer designs this may not need to be freed.
- * When such a design exists I'll add this to ring access funcs.
- */
- kfree(data);
-
- return copied;
-
-error_free_data_cpy:
- kfree(data);
-error_ret:
return ret;
}
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/staging/iio/kfifo_buf.c
new file mode 100644
index 000000000000..a56c0cbba94b
--- /dev/null
+++ b/drivers/staging/iio/kfifo_buf.c
@@ -0,0 +1,196 @@
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/mutex.h>
+
+#include "kfifo_buf.h"
+
+static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
+ int bytes_per_datum, int length)
+{
+ if ((length == 0) || (bytes_per_datum == 0))
+ return -EINVAL;
+
+ __iio_update_ring_buffer(&buf->ring, bytes_per_datum, length);
+ return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL);
+}
+
+int iio_request_update_kfifo(struct iio_ring_buffer *r)
+{
+ int ret = 0;
+ struct iio_kfifo *buf = iio_to_kfifo(r);
+
+ mutex_lock(&buf->use_lock);
+ if (!buf->update_needed)
+ goto error_ret;
+ if (buf->use_count) {
+ ret = -EAGAIN;
+ goto error_ret;
+ }
+ kfifo_free(&buf->kf);
+ ret = __iio_allocate_kfifo(buf, buf->ring.bytes_per_datum,
+ buf->ring.length);
+error_ret:
+ mutex_unlock(&buf->use_lock);
+ return ret;
+}
+EXPORT_SYMBOL(iio_request_update_kfifo);
+
+void iio_mark_kfifo_in_use(struct iio_ring_buffer *r)
+{
+ struct iio_kfifo *buf = iio_to_kfifo(r);
+ mutex_lock(&buf->use_lock);
+ buf->use_count++;
+ mutex_unlock(&buf->use_lock);
+}
+EXPORT_SYMBOL(iio_mark_kfifo_in_use);
+
+void iio_unmark_kfifo_in_use(struct iio_ring_buffer *r)
+{
+ struct iio_kfifo *buf = iio_to_kfifo(r);
+ mutex_lock(&buf->use_lock);
+ buf->use_count--;
+ mutex_unlock(&buf->use_lock);
+}
+EXPORT_SYMBOL(iio_unmark_kfifo_in_use);
+
+int iio_get_length_kfifo(struct iio_ring_buffer *r)
+{
+ return r->length;
+}
+EXPORT_SYMBOL(iio_get_length_kfifo);
+
+static inline void __iio_init_kfifo(struct iio_kfifo *kf)
+{
+ mutex_init(&kf->use_lock);
+}
+
+static IIO_RING_ENABLE_ATTR;
+static IIO_RING_BYTES_PER_DATUM_ATTR;
+static IIO_RING_LENGTH_ATTR;
+
+static struct attribute *iio_kfifo_attributes[] = {
+ &dev_attr_length.attr,
+ &dev_attr_bytes_per_datum.attr,
+ &dev_attr_enable.attr,
+ NULL,
+};
+
+static struct attribute_group iio_kfifo_attribute_group = {
+ .attrs = iio_kfifo_attributes,
+};
+
+static const struct attribute_group *iio_kfifo_attribute_groups[] = {
+ &iio_kfifo_attribute_group,
+ NULL
+};
+
+static void iio_kfifo_release(struct device *dev)
+{
+ struct iio_ring_buffer *r = to_iio_ring_buffer(dev);
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ kfifo_free(&kf->kf);
+ kfree(kf);
+}
+
+static struct device_type iio_kfifo_type = {
+ .release = iio_kfifo_release,
+ .groups = iio_kfifo_attribute_groups,
+};
+
+struct iio_ring_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
+{
+ struct iio_kfifo *kf;
+
+ kf = kzalloc(sizeof *kf, GFP_KERNEL);
+ if (!kf)
+ return NULL;
+ iio_ring_buffer_init(&kf->ring, indio_dev);
+ __iio_init_kfifo(kf);
+ kf->ring.dev.type = &iio_kfifo_type;
+ device_initialize(&kf->ring.dev);
+ kf->ring.dev.parent = &indio_dev->dev;
+ kf->ring.dev.bus = &iio_bus_type;
+ dev_set_drvdata(&kf->ring.dev, (void *)&(kf->ring));
+
+ return &kf->ring;
+}
+EXPORT_SYMBOL(iio_kfifo_allocate);
+
+int iio_get_bytes_per_datum_kfifo(struct iio_ring_buffer *r)
+{
+ return r->bytes_per_datum;
+}
+EXPORT_SYMBOL(iio_get_bytes_per_datum_kfifo);
+
+int iio_set_bytes_per_datum_kfifo(struct iio_ring_buffer *r, size_t bpd)
+{
+ if (r->bytes_per_datum != bpd) {
+ r->bytes_per_datum = bpd;
+ if (r->access.mark_param_change)
+ r->access.mark_param_change(r);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iio_set_bytes_per_datum_kfifo);
+
+int iio_mark_update_needed_kfifo(struct iio_ring_buffer *r)
+{
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ kf->update_needed = true;
+ return 0;
+}
+EXPORT_SYMBOL(iio_mark_update_needed_kfifo);
+
+int iio_set_length_kfifo(struct iio_ring_buffer *r, int length)
+{
+ if (r->length != length) {
+ r->length = length;
+ if (r->access.mark_param_change)
+ r->access.mark_param_change(r);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iio_set_length_kfifo);
+
+void iio_kfifo_free(struct iio_ring_buffer *r)
+{
+ if (r)
+ iio_put_ring_buffer(r);
+}
+EXPORT_SYMBOL(iio_kfifo_free);
+
+int iio_store_to_kfifo(struct iio_ring_buffer *r, u8 *data, s64 timestamp)
+{
+ int ret;
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ u8 *datal = kmalloc(r->bytes_per_datum, GFP_KERNEL);
+ memcpy(datal, data, r->bytes_per_datum - sizeof(timestamp));
+ memcpy(datal + r->bytes_per_datum - sizeof(timestamp),
+ &timestamp, sizeof(timestamp));
+ ret = kfifo_in(&kf->kf, data, r->bytes_per_datum);
+ if (ret != r->bytes_per_datum) {
+ kfree(datal);
+ return -EBUSY;
+ }
+ kfree(datal);
+ return 0;
+}
+EXPORT_SYMBOL(iio_store_to_kfifo);
+
+int iio_rip_kfifo(struct iio_ring_buffer *r,
+ size_t count, char __user *buf, int *deadoffset)
+{
+ int ret, copied;
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+
+ *deadoffset = 0;
+ ret = kfifo_to_user(&kf->kf, buf, r->bytes_per_datum*count, &copied);
+
+ return copied;
+}
+EXPORT_SYMBOL(iio_rip_kfifo);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h
new file mode 100644
index 000000000000..8064383bf7c3
--- /dev/null
+++ b/drivers/staging/iio/kfifo_buf.h
@@ -0,0 +1,56 @@
+
+#include <linux/kfifo.h>
+#include "iio.h"
+#include "ring_generic.h"
+
+struct iio_kfifo {
+ struct iio_ring_buffer ring;
+ struct kfifo kf;
+ int use_count;
+ int update_needed;
+ struct mutex use_lock;
+};
+
+#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, ring)
+
+int iio_create_kfifo(struct iio_ring_buffer **r);
+int iio_init_kfifo(struct iio_ring_buffer *r, struct iio_dev *indio_dev);
+void iio_exit_kfifo(struct iio_ring_buffer *r);
+void iio_free_kfifo(struct iio_ring_buffer *r);
+void iio_mark_kfifo_in_use(struct iio_ring_buffer *r);
+void iio_unmark_kfifo_in_use(struct iio_ring_buffer *r);
+
+int iio_store_to_kfifo(struct iio_ring_buffer *r, u8 *data, s64 timestamp);
+int iio_rip_kfifo(struct iio_ring_buffer *r,
+ size_t count,
+ char __user *buf,
+ int *dead_offset);
+
+int iio_request_update_kfifo(struct iio_ring_buffer *r);
+int iio_mark_update_needed_kfifo(struct iio_ring_buffer *r);
+
+int iio_get_bytes_per_datum_kfifo(struct iio_ring_buffer *r);
+int iio_set_bytes_per_datum_kfifo(struct iio_ring_buffer *r, size_t bpd);
+int iio_get_length_kfifo(struct iio_ring_buffer *r);
+int iio_set_length_kfifo(struct iio_ring_buffer *r, int length);
+
+static inline void iio_kfifo_register_funcs(struct iio_ring_access_funcs *ra)
+{
+ ra->mark_in_use = &iio_mark_kfifo_in_use;
+ ra->unmark_in_use = &iio_unmark_kfifo_in_use;
+
+ ra->store_to = &iio_store_to_kfifo;
+ ra->rip_lots = &iio_rip_kfifo;
+
+ ra->mark_param_change = &iio_mark_update_needed_kfifo;
+ ra->request_update = &iio_request_update_kfifo;
+
+ ra->get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo;
+ ra->set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo;
+ ra->get_length = &iio_get_length_kfifo;
+ ra->set_length = &iio_set_length_kfifo;
+};
+
+struct iio_ring_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
+void iio_kfifo_free(struct iio_ring_buffer *r);
+
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index e72afbd2b841..8b86d82c3b32 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -1,5 +1,5 @@
/*
- * ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface Driver
+ * ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface
*
* Copyright 2010 Analog Devices Inc.
*
@@ -23,9 +23,9 @@
#include "meter.h"
#include "ade7753.h"
-int ade7753_spi_write_reg_8(struct device *dev,
- u8 reg_address,
- u8 val)
+static int ade7753_spi_write_reg_8(struct device *dev,
+ u8 reg_address,
+ u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -46,25 +46,14 @@ static int ade7753_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }
- };
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
+ ret = spi_write(st->us, st->tx, 3);
mutex_unlock(&st->buf_lock);
return ret;
@@ -74,73 +63,40 @@ static int ade7753_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7753_READ_REG(reg_address);
- st->tx[1] = 0;
+ ssize_t ret;
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r8(st->us, ADE7753_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
- goto error_ret;
+ return ret;
}
- *val = st->rx[1];
+ *val = ret;
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ return 0;
}
static int ade7753_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 3,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7753_READ_REG(reg_address);
- st->tx[1] = 0;
- st->tx[2] = 0;
+ ssize_t ret;
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r16(st->us, ADE7753_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
- reg_address);
- goto error_ret;
+ reg_address);
+ return ret;
}
- *val = (st->rx[1] << 8) | st->rx[2];
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ *val = ret;
+ *val = be16_to_cpup(val);
+
+ return 0;
}
static int ade7753_spi_read_reg_24(struct device *dev,
@@ -154,27 +110,28 @@ static int ade7753_spi_read_reg_24(struct device *dev,
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
- .rx_buf = st->rx,
.bits_per_word = 8,
- .len = 4,
- },
+ .len = 1,
+ }, {
+ .rx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_READ_REG(reg_address);
- st->tx[1] = 0;
- st->tx[2] = 0;
- st->tx[3] = 0;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
reg_address);
goto error_ret;
}
- *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+ *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
error_ret:
mutex_unlock(&st->buf_lock);
@@ -186,7 +143,7 @@ static ssize_t ade7753_read_8bit(struct device *dev,
char *buf)
{
int ret;
- u8 val = 0;
+ u8 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_8(dev, this_attr->address, &val);
@@ -201,7 +158,7 @@ static ssize_t ade7753_read_16bit(struct device *dev,
char *buf)
{
int ret;
- u16 val = 0;
+ u16 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_16(dev, this_attr->address, &val);
@@ -216,14 +173,14 @@ static ssize_t ade7753_read_24bit(struct device *dev,
char *buf)
{
int ret;
- u32 val = 0;
+ u32 val;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = ade7753_spi_read_reg_24(dev, this_attr->address, &val);
if (ret)
return ret;
- return sprintf(buf, "%u\n", val & 0xFFFFFF);
+ return sprintf(buf, "%u\n", val);
}
static ssize_t ade7753_write_8bit(struct device *dev,
@@ -264,17 +221,12 @@ error_ret:
static int ade7753_reset(struct device *dev)
{
- int ret;
u16 val;
- ade7753_spi_read_reg_16(dev,
- ADE7753_MODE,
- &val);
+
+ ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
val |= 1 << 6; /* Software Chip Reset */
- ret = ade7753_spi_write_reg_16(dev,
- ADE7753_MODE,
- val);
- return ret;
+ return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
}
static ssize_t ade7753_write_reset(struct device *dev,
@@ -401,27 +353,20 @@ static int ade7753_set_irq(struct device *dev, bool enable)
irqen &= ~(1 << 3);
ret = ade7753_spi_write_reg_8(dev, ADE7753_IRQEN, irqen);
- if (ret)
- goto error_ret;
error_ret:
return ret;
}
/* Power down the device */
-int ade7753_stop_device(struct device *dev)
+static int ade7753_stop_device(struct device *dev)
{
- int ret;
u16 val;
- ade7753_spi_read_reg_16(dev,
- ADE7753_MODE,
- &val);
+
+ ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
val |= 1 << 4; /* AD converters can be turned off */
- ret = ade7753_spi_write_reg_16(dev,
- ADE7753_MODE,
- val);
- return ret;
+ return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
}
static int ade7753_initial_setup(struct ade7753_state *st)
@@ -454,16 +399,14 @@ static ssize_t ade7753_read_frequency(struct device *dev,
int ret, len = 0;
u8 t;
int sps;
- ret = ade7753_spi_read_reg_8(dev,
- ADE7753_MODE,
- &t);
+ ret = ade7753_spi_read_reg_8(dev, ADE7753_MODE, &t);
if (ret)
return ret;
t = (t >> 11) & 0x3;
sps = 27900 / (1 + t);
- len = sprintf(buf, "%d SPS\n", sps);
+ len = sprintf(buf, "%d\n", sps);
return len;
}
@@ -493,24 +436,21 @@ static ssize_t ade7753_write_frequency(struct device *dev,
else
st->us->max_speed_hz = ADE7753_SPI_FAST;
- ret = ade7753_spi_read_reg_16(dev,
- ADE7753_MODE,
- &reg);
+ ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 11);
reg |= t << 11;
- ret = ade7753_spi_write_reg_16(dev,
- ADE7753_MODE,
- reg);
+ ret = ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
out:
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
+
static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit);
static IIO_CONST_ATTR(temp_offset, "-25 C");
static IIO_CONST_ATTR(temp_scale, "0.67 C");
@@ -525,14 +465,6 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static IIO_CONST_ATTR(name, "ade7753");
-static struct attribute *ade7753_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group ade7753_event_attribute_group = {
- .attrs = ade7753_event_attributes,
-};
-
static struct attribute *ade7753_attributes[] = {
&iio_dev_attr_temp_raw.dev_attr.attr,
&iio_const_attr_temp_offset.dev_attr.attr,
@@ -607,58 +539,22 @@ static int __devinit ade7753_probe(struct spi_device *spi)
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &ade7753_event_attribute_group;
st->indio_dev->attrs = &ade7753_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = ade7753_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
+ goto error_free_dev;
regdone = 1;
- ret = ade7753_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_FALLING,
- "ade7753");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = ade7753_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
-
/* Get the device into a sane initial state */
ret = ade7753_initial_setup(st);
if (ret)
- goto error_remove_trigger;
+ goto error_free_dev;
return 0;
-error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- ade7753_remove_trigger(st->indio_dev);
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- ade7753_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- ade7753_unconfigure_ring(st->indio_dev);
error_free_dev:
if (regdone)
iio_device_unregister(st->indio_dev);
@@ -685,14 +581,6 @@ static int ade7753_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- flush_scheduled_work();
-
- ade7753_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- ade7753_uninitialize_ring(indio_dev->ring);
- ade7753_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
kfree(st->rx);
@@ -726,5 +614,5 @@ static __exit void ade7753_exit(void)
module_exit(ade7753_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver");
+MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Meter");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h
index a3722b8c90fa..70dabae6efe9 100644
--- a/drivers/staging/iio/meter/ade7753.h
+++ b/drivers/staging/iio/meter/ade7753.h
@@ -60,81 +60,17 @@
/**
* struct ade7753_state - device instance specific data
* @us: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
**/
struct ade7753_state {
struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
struct iio_dev *indio_dev;
- struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
};
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum ade7753_scan {
- ADE7753_SCAN_ACTIVE_POWER,
- ADE7753_SCAN_CH1,
- ADE7753_SCAN_CH2,
-};
-
-void ade7753_remove_trigger(struct iio_dev *indio_dev);
-int ade7753_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t ade7753_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int ade7753_configure_ring(struct iio_dev *indio_dev);
-void ade7753_unconfigure_ring(struct iio_dev *indio_dev);
-
-int ade7753_initialize_ring(struct iio_ring_buffer *ring);
-void ade7753_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void ade7753_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7753_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-ade7753_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int ade7753_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-static inline void ade7753_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7753_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-static inline void ade7753_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-#endif /* CONFIG_IIO_RING_BUFFER */
#endif
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 23dedfa7a270..4272818e7dc4 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -46,25 +46,14 @@ static int ade7754_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }
- };
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7754_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
+ ret = spi_write(st->us, st->tx, 3);
mutex_unlock(&st->buf_lock);
return ret;
@@ -74,73 +63,40 @@ static int ade7754_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7754_READ_REG(reg_address);
- st->tx[1] = 0;
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r8(st->us, ADE7754_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
- goto error_ret;
+ return ret;
}
- *val = st->rx[1];
+ *val = ret;
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ return 0;
}
static int ade7754_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 3,
- },
- };
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7754_READ_REG(reg_address);
- st->tx[1] = 0;
- st->tx[2] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r16(st->us, ADE7754_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
- reg_address);
- goto error_ret;
+ reg_address);
+ return ret;
}
- *val = (st->rx[1] << 8) | st->rx[2];
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ *val = ret;
+ *val = be16_to_cpup(val);
+
+ return 0;
}
static int ade7754_spi_read_reg_24(struct device *dev,
@@ -264,17 +220,11 @@ error_ret:
static int ade7754_reset(struct device *dev)
{
- int ret;
u8 val;
- ade7754_spi_read_reg_8(dev,
- ADE7754_OPMODE,
- &val);
- val |= 1 << 6; /* Software Chip Reset */
- ret = ade7754_spi_write_reg_8(dev,
- ADE7754_OPMODE,
- val);
- return ret;
+ ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val);
+ val |= 1 << 6; /* Software Chip Reset */
+ return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
}
@@ -431,17 +381,11 @@ error_ret:
/* Power down the device */
static int ade7754_stop_device(struct device *dev)
{
- int ret;
u8 val;
- ade7754_spi_read_reg_8(dev,
- ADE7754_OPMODE,
- &val);
- val |= 7 << 3; /* ADE7754 powered down */
- ret = ade7754_spi_write_reg_8(dev,
- ADE7754_OPMODE,
- val);
- return ret;
+ ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val);
+ val |= 7 << 3; /* ADE7754 powered down */
+ return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
}
static int ade7754_initial_setup(struct ade7754_state *st)
@@ -471,7 +415,7 @@ static ssize_t ade7754_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int ret, len = 0;
+ int ret;
u8 t;
int sps;
ret = ade7754_spi_read_reg_8(dev,
@@ -483,8 +427,7 @@ static ssize_t ade7754_read_frequency(struct device *dev,
t = (t >> 3) & 0x3;
sps = 26000 / (1 + t);
- len = sprintf(buf, "%d SPS\n", sps);
- return len;
+ return sprintf(buf, "%d\n", sps);
}
static ssize_t ade7754_write_frequency(struct device *dev,
@@ -513,18 +456,14 @@ static ssize_t ade7754_write_frequency(struct device *dev,
else
st->us->max_speed_hz = ADE7754_SPI_FAST;
- ret = ade7754_spi_read_reg_8(dev,
- ADE7754_WAVMODE,
- &reg);
+ ret = ade7754_spi_read_reg_8(dev, ADE7754_WAVMODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 3);
reg |= t << 3;
- ret = ade7754_spi_write_reg_8(dev,
- ADE7754_WAVMODE,
- reg);
+ ret = ade7754_spi_write_reg_8(dev, ADE7754_WAVMODE, reg);
out:
mutex_unlock(&indio_dev->mlock);
@@ -545,14 +484,6 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
static IIO_CONST_ATTR(name, "ade7754");
-static struct attribute *ade7754_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group ade7754_event_attribute_group = {
- .attrs = ade7754_event_attributes,
-};
-
static struct attribute *ade7754_attributes[] = {
&iio_dev_attr_temp_raw.dev_attr.attr,
&iio_const_attr_temp_offset.dev_attr.attr,
@@ -633,58 +564,22 @@ static int __devinit ade7754_probe(struct spi_device *spi)
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &ade7754_event_attribute_group;
st->indio_dev->attrs = &ade7754_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = ade7754_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
+ goto error_free_dev;
regdone = 1;
- ret = ade7754_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_FALLING,
- "ade7754");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = ade7754_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
-
/* Get the device into a sane initial state */
ret = ade7754_initial_setup(st);
if (ret)
- goto error_remove_trigger;
+ goto error_free_dev;
return 0;
-error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- ade7754_remove_trigger(st->indio_dev);
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- ade7754_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- ade7754_unconfigure_ring(st->indio_dev);
error_free_dev:
if (regdone)
iio_device_unregister(st->indio_dev);
@@ -711,14 +606,6 @@ static int ade7754_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- flush_scheduled_work();
-
- ade7754_remove_trigger(indio_dev);
- if (spi->irq)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- ade7754_uninitialize_ring(indio_dev->ring);
- ade7754_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
kfree(st->rx);
diff --git a/drivers/staging/iio/meter/ade7754.h b/drivers/staging/iio/meter/ade7754.h
index f6a3e4b926cf..8faa9b3b48b6 100644
--- a/drivers/staging/iio/meter/ade7754.h
+++ b/drivers/staging/iio/meter/ade7754.h
@@ -78,84 +78,17 @@
/**
* struct ade7754_state - device instance specific data
* @us: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
**/
struct ade7754_state {
struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
struct iio_dev *indio_dev;
- struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
};
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum ade7754_scan {
- ADE7754_SCAN_PHA_V,
- ADE7754_SCAN_PHB_V,
- ADE7754_SCAN_PHC_V,
- ADE7754_SCAN_PHA_I,
- ADE7754_SCAN_PHB_I,
- ADE7754_SCAN_PHC_I,
-};
-
-void ade7754_remove_trigger(struct iio_dev *indio_dev);
-int ade7754_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t ade7754_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int ade7754_configure_ring(struct iio_dev *indio_dev);
-void ade7754_unconfigure_ring(struct iio_dev *indio_dev);
-
-int ade7754_initialize_ring(struct iio_ring_buffer *ring);
-void ade7754_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void ade7754_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7754_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-ade7754_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int ade7754_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-static inline void ade7754_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7754_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-static inline void ade7754_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-#endif /* CONFIG_IIO_RING_BUFFER */
#endif
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index fafc3c1e5aaa..a9d3203b2e1c 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -23,7 +23,7 @@
#include "meter.h"
#include "ade7759.h"
-int ade7759_spi_write_reg_8(struct device *dev,
+static int ade7759_spi_write_reg_8(struct device *dev,
u8 reg_address,
u8 val)
{
@@ -46,25 +46,14 @@ static int ade7759_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }
- };
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7759_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
+ ret = spi_write(st->us, st->tx, 3);
mutex_unlock(&st->buf_lock);
return ret;
@@ -74,73 +63,40 @@ static int ade7759_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- },
- };
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7759_READ_REG(reg_address);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r8(st->us, ADE7759_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
- goto error_ret;
+ return ret;
}
- *val = st->rx[1];
+ *val = ret;
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ return 0;
}
static int ade7759_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 3,
- },
- };
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7759_READ_REG(reg_address);
- st->tx[1] = 0;
- st->tx[2] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
- ret = spi_sync(st->us, &msg);
- if (ret) {
+ ret = spi_w8r16(st->us, ADE7759_READ_REG(reg_address));
+ if (ret < 0) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
- reg_address);
- goto error_ret;
+ reg_address);
+ return ret;
}
- *val = (st->rx[1] << 8) | st->rx[2];
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
+ *val = ret;
+ *val = be16_to_cpup(val);
+
+ return 0;
}
static int ade7759_spi_read_reg_40(struct device *dev,
@@ -354,27 +310,22 @@ static int ade7759_set_irq(struct device *dev, bool enable)
irqen &= ~(1 << 3);
ret = ade7759_spi_write_reg_8(dev, ADE7759_IRQEN, irqen);
- if (ret)
- goto error_ret;
error_ret:
return ret;
}
/* Power down the device */
-int ade7759_stop_device(struct device *dev)
+static int ade7759_stop_device(struct device *dev)
{
- int ret;
u16 val;
+
ade7759_spi_read_reg_16(dev,
ADE7759_MODE,
&val);
val |= 1 << 4; /* AD converters can be turned off */
- ret = ade7759_spi_write_reg_16(dev,
- ADE7759_MODE,
- val);
- return ret;
+ return ade7759_spi_write_reg_16(dev, ADE7759_MODE, val);
}
static int ade7759_initial_setup(struct ade7759_state *st)
@@ -404,7 +355,7 @@ static ssize_t ade7759_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int ret, len = 0;
+ int ret;
u16 t;
int sps;
ret = ade7759_spi_read_reg_16(dev,
@@ -416,8 +367,7 @@ static ssize_t ade7759_read_frequency(struct device *dev,
t = (t >> 3) & 0x3;
sps = 27900 / (1 + t);
- len = sprintf(buf, "%d SPS\n", sps);
- return len;
+ return sprintf(buf, "%d\n", sps);
}
static ssize_t ade7759_write_frequency(struct device *dev,
@@ -446,18 +396,14 @@ static ssize_t ade7759_write_frequency(struct device *dev,
else
st->us->max_speed_hz = ADE7759_SPI_FAST;
- ret = ade7759_spi_read_reg_16(dev,
- ADE7759_MODE,
- &reg);
+ ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &reg);
if (ret)
goto out;
reg &= ~(3 << 13);
reg |= t << 13;
- ret = ade7759_spi_write_reg_16(dev,
- ADE7759_MODE,
- reg);
+ ret = ade7759_spi_write_reg_16(dev, ADE7759_MODE, reg);
out:
mutex_unlock(&indio_dev->mlock);
@@ -478,14 +424,6 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static IIO_CONST_ATTR(name, "ade7759");
-static struct attribute *ade7759_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group ade7759_event_attribute_group = {
- .attrs = ade7759_event_attributes,
-};
-
static struct attribute *ade7759_attributes[] = {
&iio_dev_attr_temp_raw.dev_attr.attr,
&iio_const_attr_temp_offset.dev_attr.attr,
@@ -517,7 +455,7 @@ static const struct attribute_group ade7759_attribute_group = {
static int __devinit ade7759_probe(struct spi_device *spi)
{
- int ret, regdone = 0;
+ int ret;
struct ade7759_state *st = kzalloc(sizeof *st, GFP_KERNEL);
if (!st) {
ret = -ENOMEM;
@@ -548,62 +486,27 @@ static int __devinit ade7759_probe(struct spi_device *spi)
st->indio_dev->dev.parent = &spi->dev;
st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &ade7759_event_attribute_group;
+
st->indio_dev->attrs = &ade7759_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = ade7759_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
- regdone = 1;
-
- ret = ade7759_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
- if (spi->irq) {
- ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_FALLING,
- "ade7759");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = ade7759_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
+ goto error_free_dev;
/* Get the device into a sane initial state */
ret = ade7759_initial_setup(st);
if (ret)
- goto error_remove_trigger;
+ goto error_unreg_dev;
return 0;
-error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- ade7759_remove_trigger(st->indio_dev);
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- ade7759_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- ade7759_unconfigure_ring(st->indio_dev);
+
+error_unreg_dev:
+ iio_device_unregister(st->indio_dev);
error_free_dev:
- if (regdone)
- iio_device_unregister(st->indio_dev);
- else
- iio_free_device(st->indio_dev);
+ iio_free_device(st->indio_dev);
error_free_tx:
kfree(st->tx);
error_free_rx:
@@ -625,14 +528,6 @@ static int ade7759_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- flush_scheduled_work();
-
- ade7759_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- ade7759_uninitialize_ring(indio_dev->ring);
- ade7759_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
kfree(st->rx);
diff --git a/drivers/staging/iio/meter/ade7759.h b/drivers/staging/iio/meter/ade7759.h
index 813dea2676a9..e9d1c43336fe 100644
--- a/drivers/staging/iio/meter/ade7759.h
+++ b/drivers/staging/iio/meter/ade7759.h
@@ -41,82 +41,17 @@
/**
* struct ade7759_state - device instance specific data
* @us: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
**/
struct ade7759_state {
struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
struct iio_dev *indio_dev;
- struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
};
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum ade7759_scan {
- ADE7759_SCAN_ACTIVE_POWER,
- ADE7759_SCAN_CH1_CH2,
- ADE7759_SCAN_CH1,
- ADE7759_SCAN_CH2,
-};
-
-void ade7759_remove_trigger(struct iio_dev *indio_dev);
-int ade7759_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t ade7759_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int ade7759_configure_ring(struct iio_dev *indio_dev);
-void ade7759_unconfigure_ring(struct iio_dev *indio_dev);
-
-int ade7759_initialize_ring(struct iio_ring_buffer *ring);
-void ade7759_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void ade7759_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7759_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-ade7759_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int ade7759_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-static inline void ade7759_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7759_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-static inline void ade7759_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-#endif /* CONFIG_IIO_RING_BUFFER */
#endif
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index fe58103ed4ca..84da8fbde022 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -22,12 +22,10 @@ static int ade7854_spi_write_reg_8(struct device *dev,
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 4,
- }
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 4,
};
mutex_lock(&st->buf_lock);
@@ -37,7 +35,7 @@ static int ade7854_spi_write_reg_8(struct device *dev,
st->tx[3] = value & 0xFF;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->spi, &msg);
mutex_unlock(&st->buf_lock);
@@ -52,12 +50,10 @@ static int ade7854_spi_write_reg_16(struct device *dev,
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 5,
- }
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 5,
};
mutex_lock(&st->buf_lock);
@@ -68,7 +64,7 @@ static int ade7854_spi_write_reg_16(struct device *dev,
st->tx[4] = value & 0xFF;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->spi, &msg);
mutex_unlock(&st->buf_lock);
@@ -83,12 +79,10 @@ static int ade7854_spi_write_reg_24(struct device *dev,
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 6,
- }
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 6,
};
mutex_lock(&st->buf_lock);
@@ -100,7 +94,7 @@ static int ade7854_spi_write_reg_24(struct device *dev,
st->tx[5] = value & 0xFF;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->spi, &msg);
mutex_unlock(&st->buf_lock);
@@ -115,12 +109,10 @@ static int ade7854_spi_write_reg_32(struct device *dev,
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 7,
- }
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 7,
};
mutex_lock(&st->buf_lock);
@@ -133,7 +125,7 @@ static int ade7854_spi_write_reg_32(struct device *dev,
st->tx[6] = value & 0xFF;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->spi, &msg);
mutex_unlock(&st->buf_lock);
@@ -152,8 +144,12 @@ static int ade7854_spi_read_reg_8(struct device *dev,
{
.tx_buf = st->tx,
.bits_per_word = 8,
- .len = 4,
- },
+ .len = 3,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 1,
+ }
};
mutex_lock(&st->buf_lock);
@@ -161,17 +157,17 @@ static int ade7854_spi_read_reg_8(struct device *dev,
st->tx[0] = ADE7854_READ_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = 0;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->spi, &msg);
if (ret) {
dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X",
reg_address);
goto error_ret;
}
- *val = st->rx[3];
+ *val = st->rx[0];
error_ret:
mutex_unlock(&st->buf_lock);
@@ -190,26 +186,29 @@ static int ade7854_spi_read_reg_16(struct device *dev,
{
.tx_buf = st->tx,
.bits_per_word = 8,
- .len = 5,
- },
+ .len = 3,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ }
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7854_READ_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = 0;
- st->tx[4] = 0;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->spi, &msg);
if (ret) {
dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X",
reg_address);
goto error_ret;
}
- *val = (st->rx[3] << 8) | st->rx[4];
+ *val = be16_to_cpup((const __be16 *)st->rx);
error_ret:
mutex_unlock(&st->buf_lock);
@@ -228,8 +227,12 @@ static int ade7854_spi_read_reg_24(struct device *dev,
{
.tx_buf = st->tx,
.bits_per_word = 8,
- .len = 6,
- },
+ .len = 3,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 3,
+ }
};
mutex_lock(&st->buf_lock);
@@ -237,19 +240,17 @@ static int ade7854_spi_read_reg_24(struct device *dev,
st->tx[0] = ADE7854_READ_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = 0;
- st->tx[4] = 0;
- st->tx[5] = 0;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->spi, &msg);
if (ret) {
dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X",
reg_address);
goto error_ret;
}
- *val = (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
+ *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
error_ret:
mutex_unlock(&st->buf_lock);
@@ -268,8 +269,12 @@ static int ade7854_spi_read_reg_32(struct device *dev,
{
.tx_buf = st->tx,
.bits_per_word = 8,
- .len = 7,
- },
+ .len = 3,
+ }, {
+ .rx_buf = st->rx,
+ .bits_per_word = 8,
+ .len = 4,
+ }
};
mutex_lock(&st->buf_lock);
@@ -277,20 +282,17 @@ static int ade7854_spi_read_reg_32(struct device *dev,
st->tx[0] = ADE7854_READ_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = 0;
- st->tx[4] = 0;
- st->tx[5] = 0;
- st->tx[6] = 0;
spi_message_init(&msg);
- spi_message_add_tail(xfers, &msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->spi, &msg);
if (ret) {
dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X",
reg_address);
goto error_ret;
}
- *val = (st->rx[3] << 24) | (st->rx[4] << 16) | (st->rx[5] << 8) | st->rx[6];
+ *val = be32_to_cpup((const __be32 *)st->rx);
error_ret:
mutex_unlock(&st->buf_lock);
@@ -333,6 +335,13 @@ static int ade7854_spi_remove(struct spi_device *spi)
return 0;
}
+static const struct spi_device_id ade7854_id[] = {
+ { "ade7854", 0 },
+ { "ade7858", 0 },
+ { "ade7868", 0 },
+ { "ade7878", 0 },
+ { }
+};
static struct spi_driver ade7854_driver = {
.driver = {
@@ -341,6 +350,7 @@ static struct spi_driver ade7854_driver = {
},
.probe = ade7854_spi_probe,
.remove = __devexit_p(ade7854_spi_remove),
+ .id_table = ade7854_id,
};
static __init int ade7854_init(void)
@@ -356,5 +366,5 @@ static __exit void ade7854_exit(void)
module_exit(ade7854_exit);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC SPI Driver");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 SPI Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index a13d5048cf42..866e585451f0 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -61,7 +61,7 @@ static ssize_t ade7854_read_24bit(struct device *dev,
char *buf)
{
int ret;
- u32 val = 0;
+ u32 val;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -70,7 +70,7 @@ static ssize_t ade7854_read_24bit(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%u\n", val & 0xFFFFFF);
+ return sprintf(buf, "%u\n", val);
}
static ssize_t ade7854_read_32bit(struct device *dev,
@@ -178,15 +178,12 @@ static int ade7854_reset(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
-
- int ret;
u16 val;
st->read_reg_16(dev, ADE7854_CONFIG, &val);
val |= 1 << 7; /* Software Chip Reset */
- ret = st->write_reg_16(dev, ADE7854_CONFIG, val);
- return ret;
+ return st->write_reg_16(dev, ADE7854_CONFIG, val);
}
@@ -477,14 +474,6 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
static IIO_CONST_ATTR(name, "ade7854");
-static struct attribute *ade7854_event_attributes[] = {
- NULL
-};
-
-static struct attribute_group ade7854_event_attribute_group = {
- .attrs = ade7854_event_attributes,
-};
-
static struct attribute *ade7854_attributes[] = {
&iio_dev_attr_aigain.dev_attr.attr,
&iio_dev_attr_bigain.dev_attr.attr,
@@ -564,7 +553,7 @@ static const struct attribute_group ade7854_attribute_group = {
int ade7854_probe(struct ade7854_state *st, struct device *dev)
{
- int ret, regdone = 0;
+ int ret;
/* Allocate the comms buffers */
st->rx = kzalloc(sizeof(*st->rx)*ADE7854_MAX_RX, GFP_KERNEL);
@@ -586,71 +575,34 @@ int ade7854_probe(struct ade7854_state *st, struct device *dev)
}
st->indio_dev->dev.parent = dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &ade7854_event_attribute_group;
st->indio_dev->attrs = &ade7854_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
- ret = ade7854_configure_ring(st->indio_dev);
- if (ret)
- goto error_free_dev;
-
ret = iio_device_register(st->indio_dev);
if (ret)
- goto error_unreg_ring_funcs;
- regdone = 1;
-
- ret = ade7854_initialize_ring(st->indio_dev->ring);
- if (ret) {
- printk(KERN_ERR "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
+ goto error_free_dev;
- if (st->irq) {
- ret = iio_register_interrupt_line(st->irq,
- st->indio_dev,
- 0,
- IRQF_TRIGGER_FALLING,
- "ade7854");
- if (ret)
- goto error_uninitialize_ring;
-
- ret = ade7854_probe_trigger(st->indio_dev);
- if (ret)
- goto error_unregister_line;
- }
/* Get the device into a sane initial state */
ret = ade7854_initial_setup(st);
if (ret)
- goto error_remove_trigger;
+ goto error_unreg_dev;
return 0;
-error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- ade7854_remove_trigger(st->indio_dev);
-error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
-error_uninitialize_ring:
- ade7854_uninitialize_ring(st->indio_dev->ring);
-error_unreg_ring_funcs:
- ade7854_unconfigure_ring(st->indio_dev);
+error_unreg_dev:
+ iio_device_unregister(st->indio_dev);
error_free_dev:
- if (regdone)
- iio_device_unregister(st->indio_dev);
- else
- iio_free_device(st->indio_dev);
+ iio_free_device(st->indio_dev);
error_free_tx:
kfree(st->tx);
error_free_rx:
kfree(st->rx);
error_free_st:
kfree(st);
- return ret;
+ return ret;
}
EXPORT_SYMBOL(ade7854_probe);
@@ -658,14 +610,6 @@ int ade7854_remove(struct ade7854_state *st)
{
struct iio_dev *indio_dev = st->indio_dev;
- flush_scheduled_work();
-
- ade7854_remove_trigger(indio_dev);
- if (st->irq)
- iio_unregister_interrupt_line(indio_dev, 0);
-
- ade7854_uninitialize_ring(indio_dev->ring);
- ade7854_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
kfree(st->rx);
@@ -676,5 +620,5 @@ int ade7854_remove(struct ade7854_state *st)
EXPORT_SYMBOL(ade7854_remove);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Energy Meter");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h
index 47690e521ec1..4ad84a3bb462 100644
--- a/drivers/staging/iio/meter/ade7854.h
+++ b/drivers/staging/iio/meter/ade7854.h
@@ -147,11 +147,7 @@
/**
* struct ade7854_state - device instance specific data
* @spi: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
- * @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
@@ -159,10 +155,7 @@
struct ade7854_state {
struct spi_device *spi;
struct i2c_client *i2c;
- struct work_struct work_trigger_to_ring;
- s64 last_timestamp;
struct iio_dev *indio_dev;
- struct iio_trigger *trig;
u8 *tx;
u8 *rx;
int (*read_reg_8) (struct device *, u16, u8 *);
@@ -180,66 +173,4 @@ struct ade7854_state {
extern int ade7854_probe(struct ade7854_state *st, struct device *dev);
extern int ade7854_remove(struct ade7854_state *st);
-#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-enum ade7854_scan {
- ADE7854_SCAN_PHA_V,
- ADE7854_SCAN_PHB_V,
- ADE7854_SCAN_PHC_V,
- ADE7854_SCAN_PHA_I,
- ADE7854_SCAN_PHB_I,
- ADE7854_SCAN_PHC_I,
-};
-
-void ade7854_remove_trigger(struct iio_dev *indio_dev);
-int ade7854_probe_trigger(struct iio_dev *indio_dev);
-
-ssize_t ade7854_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-
-int ade7854_configure_ring(struct iio_dev *indio_dev);
-void ade7854_unconfigure_ring(struct iio_dev *indio_dev);
-
-int ade7854_initialize_ring(struct iio_ring_buffer *ring);
-void ade7854_uninitialize_ring(struct iio_ring_buffer *ring);
-#else /* CONFIG_IIO_RING_BUFFER */
-
-static inline void ade7854_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7854_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-ade7854_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static inline int ade7854_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void ade7854_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
-static inline int ade7854_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-static inline void ade7854_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-#endif /* CONFIG_IIO_RING_BUFFER */
-
#endif
diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h
index 8ecb1895cec2..f21ac09373cf 100644
--- a/drivers/staging/iio/ring_generic.h
+++ b/drivers/staging/iio/ring_generic.h
@@ -73,7 +73,7 @@ struct iio_ring_access_funcs {
int (*read_last)(struct iio_ring_buffer *ring, u8 *data);
int (*rip_lots)(struct iio_ring_buffer *ring,
size_t count,
- u8 **data,
+ char __user *buf,
int *dead_offset);
int (*mark_param_change)(struct iio_ring_buffer *ring);
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 52624ace0bc5..b71ce3900649 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/workqueue.h>
+#include <linux/poll.h>
#include "ring_sw.h"
#include "trigger.h"
@@ -152,11 +153,12 @@ error_ret:
}
int iio_rip_sw_rb(struct iio_ring_buffer *r,
- size_t count, u8 **data, int *dead_offset)
+ size_t count, char __user *buf, int *dead_offset)
{
struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r);
u8 *initial_read_p, *initial_write_p, *current_read_p, *end_read_p;
+ u8 *data;
int ret, max_copied;
int bytes_to_rip;
@@ -174,8 +176,8 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r,
/* Limit size to whole of ring buffer */
bytes_to_rip = min((size_t)(ring->buf.bytes_per_datum*ring->buf.length), count);
- *data = kmalloc(bytes_to_rip, GFP_KERNEL);
- if (*data == NULL) {
+ data = kmalloc(bytes_to_rip, GFP_KERNEL);
+ if (data == NULL) {
ret = -ENOMEM;
goto error_ret;
}
@@ -204,30 +206,30 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r,
if (initial_write_p >= initial_read_p + bytes_to_rip) {
/* write_p is greater than necessary, all is easy */
max_copied = bytes_to_rip;
- memcpy(*data, initial_read_p, max_copied);
+ memcpy(data, initial_read_p, max_copied);
end_read_p = initial_read_p + max_copied;
} else if (initial_write_p > initial_read_p) {
/*not enough data to cpy */
max_copied = initial_write_p - initial_read_p;
- memcpy(*data, initial_read_p, max_copied);
+ memcpy(data, initial_read_p, max_copied);
end_read_p = initial_write_p;
} else {
/* going through 'end' of ring buffer */
max_copied = ring->data
+ ring->buf.length*ring->buf.bytes_per_datum - initial_read_p;
- memcpy(*data, initial_read_p, max_copied);
+ memcpy(data, initial_read_p, max_copied);
/* possible we are done if we align precisely with end */
if (max_copied == bytes_to_rip)
end_read_p = ring->data;
else if (initial_write_p
> ring->data + bytes_to_rip - max_copied) {
/* enough data to finish */
- memcpy(*data + max_copied, ring->data,
+ memcpy(data + max_copied, ring->data,
bytes_to_rip - max_copied);
max_copied = bytes_to_rip;
end_read_p = ring->data + (bytes_to_rip - max_copied);
} else { /* not enough data */
- memcpy(*data + max_copied, ring->data,
+ memcpy(data + max_copied, ring->data,
initial_write_p - ring->data);
max_copied += initial_write_p - ring->data;
end_read_p = initial_write_p;
@@ -264,11 +266,16 @@ int iio_rip_sw_rb(struct iio_ring_buffer *r,
while (ring->read_p != end_read_p)
ring->read_p = end_read_p;
- return max_copied - *dead_offset;
+ ret = max_copied - *dead_offset;
+ if (copy_to_user(buf, data + *dead_offset, ret)) {
+ ret = -EFAULT;
+ goto error_free_data_cpy;
+ }
error_free_data_cpy:
- kfree(*data);
+ kfree(data);
error_ret:
+
return ret;
}
EXPORT_SYMBOL(iio_rip_sw_rb);
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index ad03d832c1b9..13341c1e35f2 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -96,13 +96,13 @@ int iio_store_to_sw_rb(struct iio_ring_buffer *r, u8 *data, s64 timestamp);
* iio_rip_sw_rb() - attempt to read data from the ring buffer
* @r: ring buffer instance
* @count: number of datum's to try and read
- * @data: where the data will be stored.
+ * @buf: userspace buffer into which data is copied
* @dead_offset: how much of the stored data was possibly invalidated by
* the end of the copy.
**/
int iio_rip_sw_rb(struct iio_ring_buffer *r,
size_t count,
- u8 **data,
+ char __user *buf,
int *dead_offset);
/**
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
index d842a584a3af..c33777e0a8b3 100644
--- a/drivers/staging/iio/trigger/Kconfig
+++ b/drivers/staging/iio/trigger/Kconfig
@@ -18,4 +18,24 @@ config IIO_GPIO_TRIGGER
help
Provides support for using GPIO pins as IIO triggers.
+config IIO_SYSFS_TRIGGER
+ tristate "SYSFS trigger"
+ depends on SYSFS
+ help
+ Provides support for using SYSFS entry as IIO triggers.
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-trig-sysfs.
+
+config IIO_BFIN_TMR_TRIGGER
+ tristate "Blackfin TIMER trigger"
+ depends on BLACKFIN
+ help
+ Provides support for using a Blackfin timer as IIO triggers.
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-trig-bfin-timer.
+
endif # IIO_TRIGGER
diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile
index 10aeca5e347a..b088b57da335 100644
--- a/drivers/staging/iio/trigger/Makefile
+++ b/drivers/staging/iio/trigger/Makefile
@@ -4,3 +4,5 @@
obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o
obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
+obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
+obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
new file mode 100644
index 000000000000..583bef0936e8
--- /dev/null
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <asm/gptimers.h>
+
+#include "../iio.h"
+#include "../trigger.h"
+
+struct bfin_timer {
+ unsigned short id, bit;
+ unsigned long irqbit;
+ int irq;
+};
+
+/*
+ * this covers all hardware timer configurations on
+ * all Blackfin derivatives out there today
+ */
+
+static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
+ {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0},
+ {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1},
+ {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2},
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+ {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3},
+ {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4},
+ {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5},
+ {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6},
+ {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7},
+#endif
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+ {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8},
+ {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9},
+ {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10},
+#if (MAX_BLACKFIN_GPTIMERS > 11)
+ {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11},
+#endif
+#endif
+};
+
+struct bfin_tmr_state {
+ struct iio_trigger *trig;
+ struct bfin_timer *t;
+ unsigned timer_num;
+ int irq;
+};
+
+static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_trigger *trig = dev_get_drvdata(dev);
+ struct bfin_tmr_state *st = trig->private_data;
+ long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+
+ if (val > 100000) {
+ ret = -EINVAL;
+ goto error_ret;
+ }
+
+ disable_gptimers(st->t->bit);
+
+ if (!val)
+ goto error_ret;
+
+ val = get_sclk() / val;
+ if (val <= 4) {
+ ret = -EINVAL;
+ goto error_ret;
+ }
+
+ set_gptimer_period(st->t->id, val);
+ set_gptimer_pwidth(st->t->id, 1);
+ enable_gptimers(st->t->bit);
+
+error_ret:
+ return ret ? ret : count;
+}
+
+static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_trigger *trig = dev_get_drvdata(dev);
+ struct bfin_tmr_state *st = trig->private_data;
+
+ return sprintf(buf, "%lu\n",
+ get_sclk() / get_gptimer_period(st->t->id));
+}
+
+static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
+ iio_bfin_tmr_frequency_store);
+static IIO_TRIGGER_NAME_ATTR;
+
+static struct attribute *iio_bfin_tmr_trigger_attrs[] = {
+ &dev_attr_frequency.attr,
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group iio_bfin_tmr_trigger_attr_group = {
+ .attrs = iio_bfin_tmr_trigger_attrs,
+};
+
+
+static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
+{
+ struct bfin_tmr_state *st = devid;
+
+ clear_gptimer_intr(st->t->id);
+ iio_trigger_poll(st->trig, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int iio_bfin_tmr_get_number(int irq)
+{
+ int i;
+
+ for (i = 0; i < MAX_BLACKFIN_GPTIMERS; i++)
+ if (iio_bfin_timer_code[i].irq == irq)
+ return i;
+
+ return -ENODEV;
+}
+
+static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
+{
+ struct bfin_tmr_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ st->irq = platform_get_irq(pdev, 0);
+ if (!st->irq) {
+ dev_err(&pdev->dev, "No IRQs specified");
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ ret = iio_bfin_tmr_get_number(st->irq);
+ if (ret < 0)
+ goto out1;
+
+ st->timer_num = ret;
+ st->t = &iio_bfin_timer_code[st->timer_num];
+
+ st->trig = iio_allocate_trigger();
+ if (!st->trig) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ st->trig->private_data = st;
+ st->trig->control_attrs = &iio_bfin_tmr_trigger_attr_group;
+ st->trig->owner = THIS_MODULE;
+ st->trig->name = kasprintf(GFP_KERNEL, "bfintmr%d", st->timer_num);
+ if (st->trig->name == NULL) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ ret = iio_trigger_register(st->trig);
+ if (ret)
+ goto out3;
+
+ ret = request_irq(st->irq, iio_bfin_tmr_trigger_isr,
+ 0, st->trig->name, st);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "request IRQ-%d failed", st->irq);
+ goto out4;
+ }
+
+ set_gptimer_config(st->t->id, OUT_DIS | PWM_OUT | PERIOD_CNT | IRQ_ENA);
+
+ dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
+ st->timer_num, st->irq);
+ platform_set_drvdata(pdev, st);
+
+ return 0;
+out4:
+ iio_trigger_unregister(st->trig);
+out3:
+ kfree(st->trig->name);
+out2:
+ iio_put_trigger(st->trig);
+out1:
+ kfree(st);
+out:
+ return ret;
+}
+
+static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
+{
+ struct bfin_tmr_state *st = platform_get_drvdata(pdev);
+
+ disable_gptimers(st->t->bit);
+ free_irq(st->irq, st);
+ iio_trigger_unregister(st->trig);
+ kfree(st->trig->name);
+ iio_put_trigger(st->trig);
+ kfree(st);
+
+ return 0;
+}
+
+static struct platform_driver iio_bfin_tmr_trigger_driver = {
+ .driver = {
+ .name = "iio_bfin_tmr_trigger",
+ .owner = THIS_MODULE,
+ },
+ .probe = iio_bfin_tmr_trigger_probe,
+ .remove = __devexit_p(iio_bfin_tmr_trigger_remove),
+};
+
+static int __init iio_bfin_tmr_trig_init(void)
+{
+ return platform_driver_register(&iio_bfin_tmr_trigger_driver);
+}
+module_init(iio_bfin_tmr_trig_init);
+
+static void __exit iio_bfin_tmr_trig_exit(void)
+{
+ platform_driver_unregister(&iio_bfin_tmr_trigger_driver);
+}
+module_exit(iio_bfin_tmr_trig_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Blackfin system timer based trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:iio-trig-bfin-timer");
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
new file mode 100644
index 000000000000..127a2a33e4db
--- /dev/null
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../iio.h"
+#include "../trigger.h"
+
+static ssize_t iio_sysfs_trigger_poll(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_trigger *trig = dev_get_drvdata(dev);
+ iio_trigger_poll(trig, 0);
+
+ return count;
+}
+
+static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll);
+static IIO_TRIGGER_NAME_ATTR;
+
+static struct attribute *iio_sysfs_trigger_attrs[] = {
+ &dev_attr_trigger_now.attr,
+ &dev_attr_name.attr,
+ NULL,
+};
+
+static const struct attribute_group iio_sysfs_trigger_attr_group = {
+ .attrs = iio_sysfs_trigger_attrs,
+};
+
+static int __devinit iio_sysfs_trigger_probe(struct platform_device *pdev)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = iio_allocate_trigger();
+ if (!trig) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ trig->control_attrs = &iio_sysfs_trigger_attr_group;
+ trig->owner = THIS_MODULE;
+ trig->name = kasprintf(GFP_KERNEL, "sysfstrig%d", pdev->id);
+ if (trig->name == NULL) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ goto out3;
+
+ platform_set_drvdata(pdev, trig);
+
+ return 0;
+out3:
+ kfree(trig->name);
+out2:
+ iio_put_trigger(trig);
+out1:
+
+ return ret;
+}
+
+static int __devexit iio_sysfs_trigger_remove(struct platform_device *pdev)
+{
+ struct iio_trigger *trig = platform_get_drvdata(pdev);
+
+ iio_trigger_unregister(trig);
+ kfree(trig->name);
+ iio_put_trigger(trig);
+
+ return 0;
+}
+
+static struct platform_driver iio_sysfs_trigger_driver = {
+ .driver = {
+ .name = "iio_sysfs_trigger",
+ .owner = THIS_MODULE,
+ },
+ .probe = iio_sysfs_trigger_probe,
+ .remove = __devexit_p(iio_sysfs_trigger_remove),
+};
+
+static int __init iio_sysfs_trig_init(void)
+{
+ return platform_driver_register(&iio_sysfs_trigger_driver);
+}
+module_init(iio_sysfs_trig_init);
+
+static void __exit iio_sysfs_trig_exit(void)
+{
+ platform_driver_unregister(&iio_sysfs_trigger_driver);
+}
+module_exit(iio_sysfs_trig_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:iio-trig-sysfs");