Commit 0152a058 authored by Cliff Cai's avatar Cliff Cai Committed by Greg Kroah-Hartman

staging: iio: dds: new driver for AD9951 devices

Signed-off-by: default avatarCliff Cai <cliff.cai@analog.com>
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Acked-by: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2996a2dc
...@@ -37,3 +37,10 @@ config AD9910 ...@@ -37,3 +37,10 @@ config AD9910
help help
Say yes here to build support for Analog Devices DDS chip Say yes here to build support for Analog Devices DDS chip
ad9910, provides direct access via sysfs. 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.
...@@ -7,3 +7,4 @@ obj-$(CONFIG_AD9832) += ad9832.o ...@@ -7,3 +7,4 @@ obj-$(CONFIG_AD9832) += ad9832.o
obj-$(CONFIG_AD9850) += ad9850.o obj-$(CONFIG_AD9850) += ad9850.o
obj-$(CONFIG_AD9852) += ad9852.o obj-$(CONFIG_AD9852) += ad9852.o
obj-$(CONFIG_AD9910) += ad9910.o obj-$(CONFIG_AD9910) += ad9910.o
obj-$(CONFIG_AD9951) += ad9951.o
/*
* 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];
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->ftw0[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->ftw1[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;
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;
mutex_lock(&st->lock);
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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment