aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/dds
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/dds')
-rw-r--r--drivers/staging/iio/dds/Kconfig56
-rw-r--r--drivers/staging/iio/dds/Makefile11
-rw-r--r--drivers/staging/iio/dds/ad5930.c170
-rw-r--r--drivers/staging/iio/dds/ad9832.c264
-rw-r--r--drivers/staging/iio/dds/ad9834.c477
-rw-r--r--drivers/staging/iio/dds/ad9834.h112
-rw-r--r--drivers/staging/iio/dds/ad9850.c156
-rw-r--r--drivers/staging/iio/dds/ad9852.c305
-rw-r--r--drivers/staging/iio/dds/ad9910.c440
-rw-r--r--drivers/staging/iio/dds/ad9951.c249
-rw-r--r--drivers/staging/iio/dds/dds.h110
11 files changed, 2350 insertions, 0 deletions
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig
new file mode 100644
index 000000000000..a047da62daf0
--- /dev/null
+++ b/drivers/staging/iio/dds/Kconfig
@@ -0,0 +1,56 @@
+#
+# Direct Digital Synthesis drivers
+#
+comment "Direct Digital Synthesis"
+
+config AD5930
+ tristate "Analog Devices ad5930/5932 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad5930/ad5932, provides direct access via sysfs.
+
+config AD9832
+ tristate "Analog Devices ad9832/5 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9832 and ad9835, provides direct access via sysfs.
+
+config AD9834
+ tristate "Analog Devices ad9833/4/ driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ AD9833 and AD9834, provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad9834.
+
+config AD9850
+ tristate "Analog Devices ad9850/1 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9850/1, provides direct access via sysfs.
+
+config AD9852
+ tristate "Analog Devices ad9852/4 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9852/4, provides direct access via sysfs.
+
+config AD9910
+ tristate "Analog Devices ad9910 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9910, provides direct access via sysfs.
+
+config AD9951
+ tristate "Analog Devices ad9951 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices DDS chip
+ ad9951, provides direct access via sysfs.
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile
new file mode 100644
index 000000000000..147746176b9b
--- /dev/null
+++ b/drivers/staging/iio/dds/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for Direct Digital Synthesis drivers
+#
+
+obj-$(CONFIG_AD5930) += ad5930.o
+obj-$(CONFIG_AD9832) += ad9832.o
+obj-$(CONFIG_AD9834) += ad9834.o
+obj-$(CONFIG_AD9850) += ad9850.o
+obj-$(CONFIG_AD9852) += ad9852.o
+obj-$(CONFIG_AD9910) += ad9910.o
+obj-$(CONFIG_AD9951) += ad9951.o
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c
new file mode 100644
index 000000000000..f80039c5d539
--- /dev/null
+++ b/drivers/staging/iio/dds/ad5930.c
@@ -0,0 +1,170 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad5930
+ *
+ * Copyright (c) 2010-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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad5930"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad5903_config {
+ u16 control;
+ u16 incnum;
+ u16 frqdelt[2];
+ u16 incitvl;
+ u16 buritvl;
+ u16 strtfrq[2];
+};
+
+struct ad5930_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad5930_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad5903_config *config = (struct ad5903_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad5930_state *st = idev->dev_data;
+
+ config->control = (config->control & ~value_mask);
+ config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
+ config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
+ config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
+ config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
+ config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
+ config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
+ config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
+
+ xfer.len = 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
+
+static struct attribute *ad5930_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad5930_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad5930_attributes,
+};
+
+static int __devinit ad5930_probe(struct spi_device *spi)
+{
+ struct ad5930_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad5930_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 16;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad5930_remove(struct spi_device *spi)
+{
+ struct ad5930_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad5930_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad5930_probe,
+ .remove = __devexit_p(ad5930_remove),
+};
+
+static __init int ad5930_spi_init(void)
+{
+ return spi_register_driver(&ad5930_driver);
+}
+module_init(ad5930_spi_init);
+
+static __exit void ad5930_spi_exit(void)
+{
+ spi_unregister_driver(&ad5930_driver);
+}
+module_exit(ad5930_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad5930 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
new file mode 100644
index 000000000000..e911893b3db0
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9832.c
@@ -0,0 +1,264 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9832
+ *
+ * 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.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];
+};
+
+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)
+{
+ 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9832_set_parameter, 0);
+
+static struct attribute *ad9832_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9832_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9832_attributes,
+};
+
+static void ad9832_init(struct ad9832_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u16 config = 0;
+
+ config = 0x3 << 14 | AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+
+ 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);
+ if (ret)
+ goto error_ret;
+
+ config = 0x2 << 14 | AD9832_SYNC | AD9832_SELSRC;
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ config = CMD_SELBITSCTL << cmd_shift;
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ config = 0x3 << 14;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config;
+
+ 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 int __devinit ad9832_probe(struct spi_device *spi)
+{
+ struct ad9832_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ 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;
+
+ ret = iio_device_register(st->idev);
+ 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);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9832_remove(struct spi_device *spi)
+{
+ struct ad9832_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9832_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9832_probe,
+ .remove = __devexit_p(ad9832_remove),
+};
+
+static __init int ad9832_spi_init(void)
+{
+ return spi_register_driver(&ad9832_driver);
+}
+module_init(ad9832_spi_init);
+
+static __exit void ad9832_spi_exit(void)
+{
+ spi_unregister_driver(&ad9832_driver);
+}
+module_exit(ad9832_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9832 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c
new file mode 100644
index 000000000000..eb1a681874f9
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9834.c
@@ -0,0 +1,477 @@
+/*
+ * AD9834 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#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/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"
+
+#include "ad9834.h"
+
+static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout)
+{
+ unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS);
+ do_div(freqreg, mclk);
+ return freqreg;
+}
+
+static int ad9834_write_frequency(struct ad9834_state *st,
+ unsigned long addr, unsigned long fout)
+{
+ unsigned long regval;
+
+ if (fout > (st->mclk / 2))
+ return -EINVAL;
+
+ regval = ad9834_calc_freqreg(st->mclk, fout);
+
+ st->freq_data[0] = cpu_to_be16(addr | (regval &
+ RES_MASK(AD9834_FREQ_BITS / 2)));
+ st->freq_data[1] = cpu_to_be16(addr | ((regval >>
+ (AD9834_FREQ_BITS / 2)) &
+ RES_MASK(AD9834_FREQ_BITS / 2)));
+
+ return spi_sync(st->spi, &st->freq_msg);;
+}
+
+static int ad9834_write_phase(struct ad9834_state *st,
+ unsigned long addr, unsigned long phase)
+{
+ if (phase > (1 << AD9834_PHASE_BITS))
+ return -EINVAL;
+ st->data = cpu_to_be16(addr | phase);
+
+ return spi_sync(st->spi, &st->msg);
+}
+
+static ssize_t ad9834_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+ long val;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ goto error_ret;
+
+ mutex_lock(&dev_info->mlock);
+ switch (this_attr->address) {
+ case AD9834_REG_FREQ0:
+ case AD9834_REG_FREQ1:
+ ret = ad9834_write_frequency(st, this_attr->address, val);
+ break;
+ case AD9834_REG_PHASE0:
+ case AD9834_REG_PHASE1:
+ ret = ad9834_write_phase(st, this_attr->address, val);
+ break;
+ case AD9834_OPBITEN:
+ if (st->control & AD9834_MODE) {
+ ret = -EINVAL; /* AD9843 reserved mode */
+ break;
+ }
+
+ if (val)
+ st->control |= AD9834_OPBITEN;
+ else
+ st->control &= ~AD9834_OPBITEN;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_PIN_SW:
+ if (val)
+ st->control |= AD9834_PIN_SW;
+ else
+ st->control &= ~AD9834_PIN_SW;
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_FSEL:
+ case AD9834_PSEL:
+ if (val == 0)
+ st->control &= ~(this_attr->address | AD9834_PIN_SW);
+ else if (val == 1) {
+ st->control |= this_attr->address;
+ st->control &= ~AD9834_PIN_SW;
+ } else {
+ ret = -EINVAL;
+ break;
+ }
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ case AD9834_RESET:
+ if (val)
+ st->control &= ~AD9834_RESET;
+ else
+ st->control |= AD9834_RESET;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ mutex_unlock(&dev_info->mlock);
+
+error_ret:
+ return ret ? ret : len;
+}
+
+static ssize_t ad9834_store_wavetype(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret = 0;
+ bool is_ad9833 = st->devid == ID_AD9833;
+
+ mutex_lock(&dev_info->mlock);
+
+ switch (this_attr->address) {
+ case 0:
+ if (sysfs_streq(buf, "sine")) {
+ st->control &= ~AD9834_MODE;
+ if (is_ad9833)
+ st->control &= ~AD9834_OPBITEN;
+ } else if (sysfs_streq(buf, "triangle")) {
+ if (is_ad9833) {
+ st->control &= ~AD9834_OPBITEN;
+ st->control |= AD9834_MODE;
+ } else if (st->control & AD9834_OPBITEN) {
+ ret = -EINVAL; /* AD9843 reserved mode */
+ } else {
+ st->control |= AD9834_MODE;
+ }
+ } else if (is_ad9833 && sysfs_streq(buf, "square")) {
+ st->control &= ~AD9834_MODE;
+ st->control |= AD9834_OPBITEN;
+ } else {
+ ret = -EINVAL;
+ }
+
+ break;
+ case 1:
+ if (sysfs_streq(buf, "square") &&
+ !(st->control & AD9834_MODE)) {
+ st->control &= ~AD9834_MODE;
+ st->control |= AD9834_OPBITEN;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!ret) {
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ }
+ mutex_unlock(&dev_info->mlock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t ad9834_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_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, ad9834_show_name, NULL, 0);
+
+static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+ char *str;
+
+ if (st->devid == ID_AD9833)
+ str = "sine triangle square";
+ else if (st->control & AD9834_OPBITEN)
+ str = "sine";
+ else
+ str = "sine triangle";
+
+ return sprintf(buf, "%s\n", str);
+}
+
+
+static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO,
+ ad9834_show_out0_wavetype_available, NULL, 0);
+
+static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad9834_state *st = iio_dev_get_devdata(dev_info);
+ char *str;
+
+ if (st->control & AD9834_MODE)
+ str = "";
+ else
+ str = "square";
+
+ return sprintf(buf, "%s\n", str);
+}
+
+static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO,
+ ad9834_show_out1_wavetype_available, NULL, 0);
+
+/**
+ * see dds.h for further information
+ */
+
+static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0);
+static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1);
+static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL);
+static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
+
+static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0);
+static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1);
+static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL);
+static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
+
+static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+ ad9834_write, AD9834_PIN_SW);
+static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET);
+static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL,
+ ad9834_write, AD9834_OPBITEN);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
+
+static struct attribute *ad9834_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_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_dds0_out1_enable.dev_attr.attr,
+ &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr,
+ &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad9834_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 ad9834_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (st->devid == ID_AD9834)
+ return mode;
+
+ if ((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) ||
+ (attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) ||
+ (attr ==
+ &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group ad9834_attribute_group = {
+ .attrs = ad9834_attributes,
+ .is_visible = ad9834_attr_is_visible,
+};
+
+static int __devinit ad9834_probe(struct spi_device *spi)
+{
+ struct ad9834_platform_data *pdata = spi->dev.platform_data;
+ struct ad9834_state *st;
+ 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;
+ }
+
+ 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->devid = spi_get_device_id(spi)->driver_data;
+
+ 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 = &ad9834_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;
+
+ 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);
+
+ st->control = AD9834_B28 | AD9834_RESET;
+
+ if (!pdata->en_div2)
+ st->control |= AD9834_DIV2;
+
+ if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834))
+ st->control |= AD9834_SIGN_PIB;
+
+ st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret) {
+ dev_err(&spi->dev, "device init failed\n");
+ goto error_free_device;
+ }
+
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1);
+ if (ret)
+ goto error_free_device;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_device;
+
+ return 0;
+
+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 ad9834_remove(struct spi_device *spi)
+{
+ struct ad9834_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 ad9834_id[] = {
+ {"ad9833", ID_AD9833},
+ {"ad9834", ID_AD9834},
+ {}
+};
+
+static struct spi_driver ad9834_driver = {
+ .driver = {
+ .name = "ad9834",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9834_probe,
+ .remove = __devexit_p(ad9834_remove),
+ .id_table = ad9834_id,
+};
+
+static int __init ad9834_init(void)
+{
+ return spi_register_driver(&ad9834_driver);
+}
+module_init(ad9834_init);
+
+static void __exit ad9834_exit(void)
+{
+ spi_unregister_driver(&ad9834_driver);
+}
+module_exit(ad9834_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD9833/AD9834 DDS");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad9834");
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/dds/ad9834.h
new file mode 100644
index 000000000000..0fc3b8859e9e
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9834.h
@@ -0,0 +1,112 @@
+/*
+ * AD9834 SPI DDS driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DDS_AD9834_H_
+#define IIO_DDS_AD9834_H_
+
+/* Registers */
+
+#define AD9834_REG_CMD (0 << 14)
+#define AD9834_REG_FREQ0 (1 << 14)
+#define AD9834_REG_FREQ1 (2 << 14)
+#define AD9834_REG_PHASE0 (6 << 13)
+#define AD9834_REG_PHASE1 (7 << 13)
+
+/* Command Control Bits */
+
+#define AD9834_B28 (1 << 13)
+#define AD9834_HLB (1 << 12)
+#define AD9834_FSEL (1 << 11)
+#define AD9834_PSEL (1 << 10)
+#define AD9834_PIN_SW (1 << 9)
+#define AD9834_RESET (1 << 8)
+#define AD9834_SLEEP1 (1 << 7)
+#define AD9834_SLEEP12 (1 << 6)
+#define AD9834_OPBITEN (1 << 5)
+#define AD9834_SIGN_PIB (1 << 4)
+#define AD9834_DIV2 (1 << 3)
+#define AD9834_MODE (1 << 1)
+
+#define AD9834_FREQ_BITS 28
+#define AD9834_PHASE_BITS 12
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/**
+ * struct ad9834_state - driver instance specific data
+ * @indio_dev: the industrial I/O device
+ * @spi: spi_device
+ * @reg: supply regulator
+ * @mclk: external master clock
+ * @control: cached control word
+ * @xfer: default spi transfer
+ * @msg: default spi message
+ * @freq_xfer: tuning word spi transfer
+ * @freq_msg: tuning word spi message
+ * @data: spi transmit buffer
+ * @freq_data: tuning word spi transmit buffer
+ */
+
+struct ad9834_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned int mclk;
+ unsigned short control;
+ unsigned short devid;
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ struct spi_transfer freq_xfer[2];
+ struct spi_message freq_msg;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned short data ____cacheline_aligned;
+ unsigned short freq_data[2] ;
+};
+
+
+/*
+ * TODO: struct ad7887_platform_data needs to go into include/linux/iio
+ */
+
+/**
+ * struct ad9834_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
+ * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin
+ * @en_signbit_msb_out: the MSB (or MSB/2) of the DAC data is connected to the
+ * SIGN BIT OUT pin. en_div2 controls whether it is the MSB
+ * or MSB/2 that is output. if en_signbit_msb_out=false,
+ * the on-board comparator is connected to SIGN BIT OUT
+ */
+
+struct ad9834_platform_data {
+ unsigned int mclk;
+ unsigned int freq0;
+ unsigned int freq1;
+ unsigned short phase0;
+ unsigned short phase1;
+ bool en_div2;
+ bool en_signbit_msb_out;
+};
+
+/**
+ * ad9834_supported_device_ids:
+ */
+
+enum ad9834_supported_device_ids {
+ ID_AD9833,
+ ID_AD9834,
+};
+
+#endif /* IIO_DDS_AD9834_H_ */
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c
new file mode 100644
index 000000000000..b259bfeaf5aa
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9850.c
@@ -0,0 +1,156 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9850
+ *
+ * Copyright (c) 2010-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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9850"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad9850_config {
+ u8 control[5];
+};
+
+struct ad9850_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9850_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9850_config *config = (struct ad9850_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9850_state *st = idev->dev_data;
+
+ xfer.len = 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0);
+
+static struct attribute *ad9850_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9850_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9850_attributes,
+};
+
+static int __devinit ad9850_probe(struct spi_device *spi)
+{
+ struct ad9850_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9850_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 16;
+ spi_setup(spi);
+
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9850_remove(struct spi_device *spi)
+{
+ struct ad9850_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9850_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9850_probe,
+ .remove = __devexit_p(ad9850_remove),
+};
+
+static __init int ad9850_spi_init(void)
+{
+ return spi_register_driver(&ad9850_driver);
+}
+module_init(ad9850_spi_init);
+
+static __exit void ad9850_spi_exit(void)
+{
+ spi_unregister_driver(&ad9850_driver);
+}
+module_exit(ad9850_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9850 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c
new file mode 100644
index 000000000000..594fb6a94331
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9852.c
@@ -0,0 +1,305 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9852
+ *
+ * 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9852"
+
+#define addr_phaad1 0x0
+#define addr_phaad2 0x1
+#define addr_fretu1 0x2
+#define addr_fretu2 0x3
+#define addr_delfre 0x4
+#define addr_updclk 0x5
+#define addr_ramclk 0x6
+#define addr_contrl 0x7
+#define addr_optskm 0x8
+#define addr_optskr 0xa
+#define addr_dacctl 0xb
+
+#define COMPPD (1 << 4)
+#define REFMULT2 (1 << 2)
+#define BYPPLL (1 << 5)
+#define PLLRANG (1 << 6)
+#define IEUPCLK (1)
+#define OSKEN (1 << 5)
+
+#define read_bit (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9852_config {
+ u8 phajst0[3];
+ u8 phajst1[3];
+ u8 fretun1[6];
+ u8 fretun2[6];
+ u8 dltafre[6];
+ u8 updtclk[5];
+ u8 ramprat[4];
+ u8 control[5];
+ u8 outpskm[3];
+ u8 outpskr[2];
+ u8 daccntl[3];
+};
+
+struct ad9852_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9852_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9852_config *config = (struct ad9852_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9852_state *st = idev->dev_data;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->phajst0[0];
+ 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;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->phajst1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->fretun1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->fretun2[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 6;
+ xfer.tx_buf = &config->dltafre[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->updtclk[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 4;
+ xfer.tx_buf = &config->ramprat[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->control[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->outpskm[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config->outpskr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->daccntl[0];
+
+ 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0);
+
+static void ad9852_init(struct ad9852_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 config[5];
+
+ config[0] = addr_contrl;
+ config[1] = COMPPD;
+ config[2] = REFMULT2 | BYPPLL | PLLRANG;
+ config[3] = IEUPCLK;
+ config[4] = OSKEN;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &config;
+
+ 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 struct attribute *ad9852_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9852_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9852_attributes,
+};
+
+static int __devinit ad9852_probe(struct spi_device *spi)
+{
+ struct ad9852_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9852_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9852_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9852_remove(struct spi_device *spi)
+{
+ struct ad9852_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9852_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9852_probe,
+ .remove = __devexit_p(ad9852_remove),
+};
+
+static __init int ad9852_spi_init(void)
+{
+ return spi_register_driver(&ad9852_driver);
+}
+module_init(ad9852_spi_init);
+
+static __exit void ad9852_spi_exit(void)
+{
+ spi_unregister_driver(&ad9852_driver);
+}
+module_exit(ad9852_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9852 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c
new file mode 100644
index 000000000000..e8fb75cb66ec
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9910.c
@@ -0,0 +1,440 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9910
+ *
+ * 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9910"
+
+#define CFR1 0x0
+#define CFR2 0x1
+#define CFR3 0x2
+
+#define AUXDAC 0x3
+#define IOUPD 0x4
+#define FTW 0x7
+#define POW 0x8
+#define ASF 0x9
+#define MULTC 0x0A
+#define DIG_RAMPL 0x0B
+#define DIG_RAMPS 0x0C
+#define DIG_RAMPR 0x0D
+#define SIN_TONEP0 0x0E
+#define SIN_TONEP1 0x0F
+#define SIN_TONEP2 0x10
+#define SIN_TONEP3 0x11
+#define SIN_TONEP4 0x12
+#define SIN_TONEP5 0x13
+#define SIN_TONEP6 0x14
+#define SIN_TONEP7 0x15
+
+#define RAM_ENABLE (1 << 7)
+
+#define MANUAL_OSK (1 << 7)
+#define INVSIC (1 << 6)
+#define DDS_SINEOP (1)
+
+#define AUTO_OSK (1)
+#define OSKEN (1 << 1)
+#define LOAD_ARR (1 << 2)
+#define CLR_PHA (1 << 3)
+#define CLR_DIG (1 << 4)
+#define ACLR_PHA (1 << 5)
+#define ACLR_DIG (1 << 6)
+#define LOAD_LRR (1 << 7)
+
+#define LSB_FST (1)
+#define SDIO_IPT (1 << 1)
+#define EXT_PWD (1 << 3)
+#define ADAC_PWD (1 << 4)
+#define REFCLK_PWD (1 << 5)
+#define DAC_PWD (1 << 6)
+#define DIG_PWD (1 << 7)
+
+#define ENA_AMP (1)
+#define READ_FTW (1)
+#define DIGR_LOW (1 << 1)
+#define DIGR_HIGH (1 << 2)
+#define DIGR_ENA (1 << 3)
+#define SYNCCLK_ENA (1 << 6)
+#define ITER_IOUPD (1 << 7)
+
+#define TX_ENA (1 << 1)
+#define PDCLK_INV (1 << 2)
+#define PDCLK_ENB (1 << 3)
+
+#define PARA_ENA (1 << 4)
+#define SYNC_DIS (1 << 5)
+#define DATA_ASS (1 << 6)
+#define MATCH_ENA (1 << 7)
+
+#define PLL_ENA (1)
+#define PFD_RST (1 << 2)
+#define REFCLK_RST (1 << 6)
+#define REFCLK_BYP (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9910_config {
+ u8 auxdac[5];
+ u8 ioupd[5];
+ u8 ftw[5];
+ u8 pow[3];
+ u8 asf[5];
+ u8 multc[5];
+ u8 dig_rampl[9];
+ u8 dig_ramps[9];
+ u8 dig_rampr[5];
+ u8 sin_tonep0[9];
+ u8 sin_tonep1[9];
+ u8 sin_tonep2[9];
+ u8 sin_tonep3[9];
+ u8 sin_tonep4[9];
+ u8 sin_tonep5[9];
+ u8 sin_tonep6[9];
+ u8 sin_tonep7[9];
+};
+
+struct ad9910_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9910_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9910_config *config = (struct ad9910_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9910_state *st = idev->dev_data;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->auxdac[0];
+ 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;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ioupd[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ftw[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->pow[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->asf[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->multc[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->dig_rampl[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->dig_ramps[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->dig_rampr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep0[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep1[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep2[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep3[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep4[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep5[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep6[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 9;
+ xfer.tx_buf = &config->sin_tonep7[0];
+
+ 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
+
+static void ad9910_init(struct ad9910_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 cfr[5];
+
+ cfr[0] = CFR1;
+ cfr[1] = 0;
+ cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
+ cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
+ cfr[4] = 0;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR2;
+ cfr[1] = ENA_AMP;
+ cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
+ cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
+ cfr[4] = PARA_ENA;
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR3;
+ cfr[1] = PLL_ENA;
+ cfr[2] = 0;
+ cfr[3] = REFCLK_RST | REFCLK_BYP;
+ cfr[4] = 0;
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ 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 struct attribute *ad9910_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9910_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9910_attributes,
+};
+
+static int __devinit ad9910_probe(struct spi_device *spi)
+{
+ struct ad9910_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9910_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9910_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9910_remove(struct spi_device *spi)
+{
+ struct ad9910_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9910_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9910_probe,
+ .remove = __devexit_p(ad9910_remove),
+};
+
+static __init int ad9910_spi_init(void)
+{
+ return spi_register_driver(&ad9910_driver);
+}
+module_init(ad9910_spi_init);
+
+static __exit void ad9910_spi_exit(void)
+{
+ spi_unregister_driver(&ad9910_driver);
+}
+module_exit(ad9910_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9910 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c
new file mode 100644
index 000000000000..57eddf6d4713
--- /dev/null
+++ b/drivers/staging/iio/dds/ad9951.c
@@ -0,0 +1,249 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9951
+ *
+ * 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.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9951"
+
+#define CFR1 0x0
+#define CFR2 0x1
+
+#define AUTO_OSK (1)
+#define OSKEN (1 << 1)
+#define LOAD_ARR (1 << 2)
+
+#define AUTO_SYNC (1 << 7)
+
+#define LSB_FST (1)
+#define SDIO_IPT (1 << 1)
+#define CLR_PHA (1 << 2)
+#define SINE_OPT (1 << 4)
+#define ACLR_PHA (1 << 5)
+
+#define VCO_RANGE (1 << 2)
+
+#define CRS_OPT (1 << 1)
+#define HMANU_SYNC (1 << 2)
+#define HSPD_SYNC (1 << 3)
+
+/* Register format: 1 byte addr + value */
+struct ad9951_config {
+ u8 asf[3];
+ u8 arr[2];
+ u8 ftw0[5];
+ u8 ftw1[3];
+};
+
+struct ad9951_state {
+ struct mutex lock;
+ struct iio_dev *idev;
+ struct spi_device *sdev;
+};
+
+static ssize_t ad9951_set_parameter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ struct ad9951_config *config = (struct ad9951_config *)buf;
+ struct iio_dev *idev = dev_get_drvdata(dev);
+ struct ad9951_state *st = idev->dev_data;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->asf[0];
+ 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;
+
+ xfer.len = 2;
+ xfer.tx_buf = &config->arr[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 5;
+ xfer.tx_buf = &config->ftw0[0];
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ xfer.len = 3;
+ xfer.tx_buf = &config->ftw1[0];
+
+ 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);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
+
+static void ad9951_init(struct ad9951_state *st)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ int ret;
+ u8 cfr[5];
+
+ cfr[0] = CFR1;
+ cfr[1] = 0;
+ cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
+ cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
+ cfr[4] = 0;
+
+ mutex_lock(&st->lock);
+
+ xfer.len = 5;
+ xfer.tx_buf = &cfr;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(st->sdev, &msg);
+ if (ret)
+ goto error_ret;
+
+ cfr[0] = CFR2;
+ cfr[1] = VCO_RANGE;
+ cfr[2] = HSPD_SYNC;
+ cfr[3] = 0;
+
+ xfer.len = 4;
+ xfer.tx_buf = &cfr;
+
+ 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 struct attribute *ad9951_attributes[] = {
+ &iio_dev_attr_dds.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad9951_attribute_group = {
+ .name = DRV_NAME,
+ .attrs = ad9951_attributes,
+};
+
+static int __devinit ad9951_probe(struct spi_device *spi)
+{
+ struct ad9951_state *st;
+ int ret = 0;
+
+ 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->idev = iio_allocate_device();
+ if (st->idev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_st;
+ }
+ st->idev->dev.parent = &spi->dev;
+ st->idev->num_interrupt_lines = 0;
+ st->idev->event_attrs = NULL;
+
+ st->idev->attrs = &ad9951_attribute_group;
+ st->idev->dev_data = (void *)(st);
+ st->idev->driver_module = THIS_MODULE;
+ st->idev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(st->idev);
+ if (ret)
+ goto error_free_dev;
+ spi->max_speed_hz = 2000000;
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+ ad9951_init(st);
+ return 0;
+
+error_free_dev:
+ iio_free_device(st->idev);
+error_free_st:
+ kfree(st);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad9951_remove(struct spi_device *spi)
+{
+ struct ad9951_state *st = spi_get_drvdata(spi);
+
+ iio_device_unregister(st->idev);
+ kfree(st);
+
+ return 0;
+}
+
+static struct spi_driver ad9951_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad9951_probe,
+ .remove = __devexit_p(ad9951_remove),
+};
+
+static __init int ad9951_spi_init(void)
+{
+ return spi_register_driver(&ad9951_driver);
+}
+module_init(ad9951_spi_init);
+
+static __exit void ad9951_spi_exit(void)
+{
+ spi_unregister_driver(&ad9951_driver);
+}
+module_exit(ad9951_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9951 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h
new file mode 100644
index 000000000000..d8ac3a93baf6
--- /dev/null
+++ b/drivers/staging/iio/dds/dds.h
@@ -0,0 +1,110 @@
+/*
+ * dds.h - sysfs attributes associated with DDS devices
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqY
+ */
+
+#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqY_scale
+ */
+
+#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(dds##_channel##_freq_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_freqsymbol
+ */
+
+#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phaseY
+ */
+
+#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phaseY_scale
+ */
+
+#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(dds##_channel##_phase_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_phasesymbol
+ */
+
+#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_out_enable
+ */
+
+#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_enable
+ */
+
+#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
+ _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_wavetype
+ */
+
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
+ IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \
+ S_IWUSR, NULL, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+ */
+
+#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
+ IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\
+ _modes);