diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2012-04-27 08:58:33 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-30 01:25:04 (GMT) |
commit | e4e8d1ce81bad2c39cf738186ec559b0bebbbdde (patch) | |
tree | dd12f540d156b26b38d8a3bd1a65b705d7f95e8e /drivers/staging/iio/frequency | |
parent | 7cbb753701d11f3c71e8543e1ae0fc0772edac06 (diff) | |
download | linux-e4e8d1ce81bad2c39cf738186ec559b0bebbbdde.tar.xz |
iio: Rename iio/dds to iio/frequency
Generalize naming to allow other frequency synthesis techniques as well.
No functional changes.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/iio/frequency')
-rw-r--r-- | drivers/staging/iio/frequency/Kconfig | 61 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/Makefile | 11 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad5930.c | 151 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9832.c | 362 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9832.h | 126 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9834.c | 464 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9834.h | 112 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9850.c | 137 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9852.c | 288 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9910.c | 421 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/ad9951.c | 232 | ||||
-rw-r--r-- | drivers/staging/iio/frequency/dds.h | 110 |
12 files changed, 2475 insertions, 0 deletions
diff --git a/drivers/staging/iio/frequency/Kconfig b/drivers/staging/iio/frequency/Kconfig new file mode 100644 index 0000000..93b7141 --- /dev/null +++ b/drivers/staging/iio/frequency/Kconfig @@ -0,0 +1,61 @@ +# +# Direct Digital Synthesis drivers +# +menu "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. + + To compile this driver as a module, choose M here: the + module will be called ad9832. + +config AD9834 + tristate "Analog Devices AD9833/4/7/8 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + AD9833, AD9834, AD9837 and AD9838, 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. + +endmenu diff --git a/drivers/staging/iio/frequency/Makefile b/drivers/staging/iio/frequency/Makefile new file mode 100644 index 0000000..1477461 --- /dev/null +++ b/drivers/staging/iio/frequency/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/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c new file mode 100644 index 0000000..97542fc --- /dev/null +++ b/drivers/staging/iio/frequency/ad5930.c @@ -0,0 +1,151 @@ +/* + * 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 <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 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 = iio_priv(idev); + + 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 = { + .attrs = ad5930_attributes, +}; + +static const struct iio_info ad5930_info = { + .attrs = &ad5930_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5930_probe(struct spi_device *spi) +{ + struct ad5930_state *st; + struct iio_dev *idev; + int ret = 0; + + idev = iio_device_alloc(sizeof(*st)); + if (idev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, idev); + st = iio_priv(idev); + + mutex_init(&st->lock); + st->sdev = spi; + idev->dev.parent = &spi->dev; + idev->info = &ad5930_info; + idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(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_device_free(idev); +error_ret: + return ret; +} + +static int __devexit ad5930_remove(struct spi_device *spi) +{ + iio_device_unregister(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ad5930_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad5930_probe, + .remove = __devexit_p(ad5930_remove), +}; +module_spi_driver(ad5930_driver); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad5930 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c new file mode 100644 index 0000000..7a9b723 --- /dev/null +++ b/drivers/staging/iio/frequency/ad9832.c @@ -0,0 +1,362 @@ +/* + * AD9832 SPI DDS driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#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/module.h> +#include <asm/div64.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include "dds.h" + +#include "ad9832.h" + +static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout) +{ + unsigned long long freqreg = (u64) fout * + (u64) ((u64) 1L << AD9832_FREQ_BITS); + do_div(freqreg, mclk); + return freqreg; +} + +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 int ad9832_write_phase(struct ad9832_state *st, + unsigned long addr, unsigned long phase) +{ + if (phase > (1 << AD9832_PHASE_BITS)) + return -EINVAL; + + 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)); + + return spi_sync(st->spi, &st->phase_msg); +} + +static ssize_t ad9832_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad9832_state *st = iio_priv(indio_dev); + 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(&indio_dev->mlock); + switch ((u32) 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(&indio_dev->mlock); + +error_ret: + return ret ? ret : len; +} + +/** + * see dds.h for further information + */ + +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 */ + +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, + NULL, +}; + +static const struct attribute_group ad9832_attribute_group = { + .attrs = ad9832_attributes, +}; + +static const struct iio_info ad9832_info = { + .attrs = &ad9832_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9832_probe(struct spi_device *spi) +{ + struct ad9832_platform_data *pdata = spi->dev.platform_data; + struct iio_dev *indio_dev; + struct ad9832_state *st; + struct regulator *reg; + int ret; + + if (!pdata) { + dev_dbg(&spi->dev, "no platform data?\n"); + return -ENODEV; + } + + reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(reg)) { + ret = regulator_enable(reg); + if (ret) + goto error_put_reg; + } + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + spi_set_drvdata(spi, indio_dev); + st = iio_priv(indio_dev); + st->reg = reg; + st->mclk = pdata->mclk; + st->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &ad9832_info; + 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 = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2); + if (ret) + goto error_free_device; + + ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3); + if (ret) + goto error_free_device; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_free_device; + + return 0; + +error_free_device: + iio_device_free(indio_dev); +error_disable_reg: + if (!IS_ERR(reg)) + regulator_disable(reg); +error_put_reg: + if (!IS_ERR(reg)) + regulator_put(reg); + + return ret; +} + +static int __devexit ad9832_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad9832_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad9832_id[] = { + {"ad9832", 0}, + {"ad9835", 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad9832_id); + +static struct spi_driver ad9832_driver = { + .driver = { + .name = "ad9832", + .owner = THIS_MODULE, + }, + .probe = ad9832_probe, + .remove = __devexit_p(ad9832_remove), + .id_table = ad9832_id, +}; +module_spi_driver(ad9832_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/frequency/ad9832.h b/drivers/staging/iio/frequency/ad9832.h new file mode 100644 index 0000000..c5b701f --- /dev/null +++ b/drivers/staging/iio/frequency/ad9832.h @@ -0,0 +1,126 @@ +/* + * 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 + * @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 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/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c new file mode 100644 index 0000000..b8ef8d9 --- /dev/null +++ b/drivers/staging/iio/frequency/ad9834.c @@ -0,0 +1,464 @@ +/* + * AD9833/AD9834/AD9837/AD9838 SPI DDS driver + * + * Copyright 2010-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/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/module.h> +#include <asm/div64.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 *indio_dev = dev_get_drvdata(dev); + struct ad9834_state *st = iio_priv(indio_dev); + 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(&indio_dev->mlock); + switch ((u32) 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(&indio_dev->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 *indio_dev = dev_get_drvdata(dev); + struct ad9834_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret = 0; + bool is_ad9833_7 = (st->devid == ID_AD9833) || (st->devid == ID_AD9837); + + mutex_lock(&indio_dev->mlock); + + switch ((u32) this_attr->address) { + case 0: + if (sysfs_streq(buf, "sine")) { + st->control &= ~AD9834_MODE; + if (is_ad9833_7) + st->control &= ~AD9834_OPBITEN; + } else if (sysfs_streq(buf, "triangle")) { + if (is_ad9833_7) { + 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_7 && 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(&indio_dev->mlock); + + return ret ? ret : len; +} + +static ssize_t ad9834_show_out0_wavetype_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad9834_state *st = iio_priv(indio_dev); + char *str; + + if ((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) + 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 *indio_dev = dev_get_drvdata(dev); + struct ad9834_state *st = iio_priv(indio_dev); + 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, + NULL, +}; + +static struct attribute *ad9833_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_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_out0_wavetype.dev_attr.attr, + &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9834_attribute_group = { + .attrs = ad9834_attributes, +}; + +static const struct attribute_group ad9833_attribute_group = { + .attrs = ad9833_attributes, +}; + +static const struct iio_info ad9834_info = { + .attrs = &ad9834_attribute_group, + .driver_module = THIS_MODULE, +}; + +static const struct iio_info ad9833_info = { + .attrs = &ad9833_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9834_probe(struct spi_device *spi) +{ + struct ad9834_platform_data *pdata = spi->dev.platform_data; + struct ad9834_state *st; + struct iio_dev *indio_dev; + struct regulator *reg; + int ret; + + if (!pdata) { + dev_dbg(&spi->dev, "no platform data?\n"); + return -ENODEV; + } + + reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(reg)) { + ret = regulator_enable(reg); + if (ret) + goto error_put_reg; + } + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + spi_set_drvdata(spi, indio_dev); + st = iio_priv(indio_dev); + st->mclk = pdata->mclk; + st->spi = spi; + st->devid = spi_get_device_id(spi)->driver_data; + st->reg = reg; + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + switch (st->devid) { + case ID_AD9833: + case ID_AD9837: + indio_dev->info = &ad9833_info; + break; + default: + indio_dev->info = &ad9834_info; + break; + } + 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(indio_dev); + if (ret) + goto error_free_device; + + return 0; + +error_free_device: + iio_device_free(indio_dev); +error_disable_reg: + if (!IS_ERR(reg)) + regulator_disable(reg); +error_put_reg: + if (!IS_ERR(reg)) + regulator_put(reg); + return ret; +} + +static int __devexit ad9834_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad9834_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad9834_id[] = { + {"ad9833", ID_AD9833}, + {"ad9834", ID_AD9834}, + {"ad9837", ID_AD9837}, + {"ad9838", ID_AD9838}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad9834_id); + +static struct spi_driver ad9834_driver = { + .driver = { + .name = "ad9834", + .owner = THIS_MODULE, + }, + .probe = ad9834_probe, + .remove = __devexit_p(ad9834_remove), + .id_table = ad9834_id, +}; +module_spi_driver(ad9834_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/frequency/ad9834.h b/drivers/staging/iio/frequency/ad9834.h new file mode 100644 index 0000000..ed5ed8d --- /dev/null +++ b/drivers/staging/iio/frequency/ad9834.h @@ -0,0 +1,112 @@ +/* + * AD9833/AD9834/AD9837/AD9838 SPI DDS driver + * + * Copyright 2010-2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ +#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 + * @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 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, + ID_AD9837, + ID_AD9838, +}; + +#endif /* IIO_DDS_AD9834_H_ */ diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c new file mode 100644 index 0000000..39f12a6 --- /dev/null +++ b/drivers/staging/iio/frequency/ad9850.c @@ -0,0 +1,137 @@ +/* + * 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 <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 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 = iio_priv(idev); + + 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 = { + .attrs = ad9850_attributes, +}; + +static const struct iio_info ad9850_info = { + .attrs = &ad9850_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9850_probe(struct spi_device *spi) +{ + struct ad9850_state *st; + struct iio_dev *idev; + int ret = 0; + + idev = iio_device_alloc(sizeof(*st)); + if (idev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, idev); + st = iio_priv(idev); + mutex_init(&st->lock); + st->sdev = spi; + + idev->dev.parent = &spi->dev; + idev->info = &ad9850_info; + idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(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_device_free(idev); +error_ret: + return ret; +} + +static int __devexit ad9850_remove(struct spi_device *spi) +{ + iio_device_unregister(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ad9850_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9850_probe, + .remove = __devexit_p(ad9850_remove), +}; +module_spi_driver(ad9850_driver); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9850 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c new file mode 100644 index 0000000..58d4bf8 --- /dev/null +++ b/drivers/staging/iio/frequency/ad9852.c @@ -0,0 +1,288 @@ +/* + * 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 <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 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 = iio_priv(idev); + + 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 = { + .attrs = ad9852_attributes, +}; + +static const struct iio_info ad9852_info = { + .attrs = &ad9852_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9852_probe(struct spi_device *spi) +{ + struct ad9852_state *st; + struct iio_dev *idev; + int ret = 0; + + idev = iio_device_alloc(sizeof(*st)); + if (idev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + st = iio_priv(idev); + spi_set_drvdata(spi, idev); + mutex_init(&st->lock); + st->sdev = spi; + + idev->dev.parent = &spi->dev; + idev->info = &ad9852_info; + idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(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_device_free(idev); + +error_ret: + return ret; +} + +static int __devexit ad9852_remove(struct spi_device *spi) +{ + iio_device_unregister(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ad9852_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9852_probe, + .remove = __devexit_p(ad9852_remove), +}; +module_spi_driver(ad9852_driver); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9852 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9910.c b/drivers/staging/iio/frequency/ad9910.c new file mode 100644 index 0000000..6e7a97e --- /dev/null +++ b/drivers/staging/iio/frequency/ad9910.c @@ -0,0 +1,421 @@ +/* + * 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 <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 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 = iio_priv(idev); + + 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 = 𝔠 + + 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 = 𝔠 + + 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 = 𝔠 + + 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 = { + .attrs = ad9910_attributes, +}; + +static const struct iio_info ad9910_info = { + .attrs = &ad9910_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9910_probe(struct spi_device *spi) +{ + struct ad9910_state *st; + struct iio_dev *idev; + int ret = 0; + + idev = iio_device_alloc(sizeof(*st)); + if (idev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, idev); + st = iio_priv(idev); + mutex_init(&st->lock); + st->sdev = spi; + + idev->dev.parent = &spi->dev; + idev->info = &ad9910_info; + idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(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_device_free(idev); +error_ret: + return ret; +} + +static int __devexit ad9910_remove(struct spi_device *spi) +{ + iio_device_unregister(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ad9910_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9910_probe, + .remove = __devexit_p(ad9910_remove), +}; +module_spi_driver(ad9910_driver); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9910 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9951.c b/drivers/staging/iio/frequency/ad9951.c new file mode 100644 index 0000000..19ba721 --- /dev/null +++ b/drivers/staging/iio/frequency/ad9951.c @@ -0,0 +1,232 @@ +/* + * 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 <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/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 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 = iio_priv(idev); + + 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 = 𝔠 + + 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 = 𝔠 + + 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 = { + .attrs = ad9951_attributes, +}; + +static const struct iio_info ad9951_info = { + .attrs = &ad9951_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad9951_probe(struct spi_device *spi) +{ + struct ad9951_state *st; + struct iio_dev *idev; + int ret = 0; + + idev = iio_device_alloc(sizeof(*st)); + if (idev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, idev); + st = iio_priv(idev); + mutex_init(&st->lock); + st->sdev = spi; + + idev->dev.parent = &spi->dev; + + idev->info = &ad9951_info; + idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(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_device_free(idev); + +error_ret: + return ret; +} + +static int __devexit ad9951_remove(struct spi_device *spi) +{ + iio_device_unregister(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ad9951_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9951_probe, + .remove = __devexit_p(ad9951_remove), +}; +module_spi_driver(ad9951_driver); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9951 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h new file mode 100644 index 0000000..d8ac3a9 --- /dev/null +++ b/drivers/staging/iio/frequency/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); |