staging: iio: dac: Enable driver support for AD5444 and AD5446 DA converters

Enable support for AD5444 and AD5446:  12-/14-Bit High Bandwidth
Multiplying DACs with Serial Interface.

staging: iio: dac: Add support for AD5541A, AD5512A digital to analog convertors

staging: iio: dac: Fix according to review feedback

Review feedback by Jonathan Cameron:
	Remove spurious new line.
	Document struct members.
	Remove redundant variable initialization.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Michael Hennerich 2010-11-22 11:15:23 +01:00 committed by Greg Kroah-Hartman
parent 95bd48578b
commit b5a4948175
4 changed files with 306 additions and 0 deletions

View File

@ -9,3 +9,13 @@ config AD5624R_SPI
help
Say yes here to build support for Analog Devices AD5624R, AD5644R and
AD5664R convertors (DAC). This driver uses the common SPI interface.
config AD5446
tristate "Analog Devices AD5444, AD5446 and AD5541A, AD5512A DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5444, AD5446
and AD5541A, AD5512A DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.

View File

@ -3,3 +3,4 @@
#
obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5446) += ad5446.o

View File

@ -0,0 +1,249 @@
/*
* AD5446 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 "../iio.h"
#include "../sysfs.h"
#include "dac.h"
#include "ad5446.h"
static ssize_t ad5446_write(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad5446_state *st = dev_info->dev_data;
int ret;
long val;
ret = strict_strtol(buf, 10, &val);
if (ret)
goto error_ret;
if (val > RES_MASK(st->chip_info->bits)) {
ret = -EINVAL;
goto error_ret;
}
mutex_lock(&dev_info->mlock);
switch (spi_get_device_id(st->spi)->driver_data) {
case ID_AD5444:
case ID_AD5446:
st->data = cpu_to_be16(AD5446_LOAD |
(val << st->chip_info->left_shift));
break;
case ID_AD5542A:
case ID_AD5512A:
st->data = cpu_to_be16(val << st->chip_info->left_shift);
break;
}
ret = spi_sync(st->spi, &st->msg);
mutex_unlock(&dev_info->mlock);
error_ret:
return ret ? ret : len;
}
static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0);
static ssize_t ad5446_show_scale(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad5446_state *st = iio_dev_get_devdata(dev_info);
/* Corresponds to Vref / 2^(bits) */
unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
}
static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0);
static ssize_t ad5446_show_name(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad5446_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, ad5446_show_name, NULL, 0);
static struct attribute *ad5446_attributes[] = {
&iio_dev_attr_out0_raw.dev_attr.attr,
&iio_dev_attr_out_scale.dev_attr.attr,
&iio_dev_attr_name.dev_attr.attr,
NULL,
};
static const struct attribute_group ad5446_attribute_group = {
.attrs = ad5446_attributes,
};
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
[ID_AD5444] = {
.bits = 12,
.storagebits = 16,
.left_shift = 2,
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
},
[ID_AD5446] = {
.bits = 14,
.storagebits = 16,
.left_shift = 0,
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
},
[ID_AD5542A] = {
.bits = 16,
.storagebits = 16,
.left_shift = 0,
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
},
[ID_AD5512A] = {
.bits = 12,
.storagebits = 16,
.left_shift = 4,
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
},
};
static int __devinit ad5446_probe(struct spi_device *spi)
{
struct ad5446_state *st;
int ret, voltage_uv = 0;
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;
voltage_uv = regulator_get_voltage(st->reg);
}
st->chip_info =
&ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi_set_drvdata(spi, st);
st->spi = spi;
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
}
/* Estabilish that the iio_dev is a child of the spi device */
st->indio_dev->dev.parent = &spi->dev;
st->indio_dev->attrs = &ad5446_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
/* Setup default message */
st->xfer.tx_buf = &st->data,
st->xfer.len = 2,
spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &st->msg);
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
ret = iio_device_register(st->indio_dev);
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 ad5446_remove(struct spi_device *spi)
{
struct ad5446_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->indio_dev;
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg)) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
kfree(st);
return 0;
}
static const struct spi_device_id ad5446_id[] = {
{"ad5444", ID_AD5444},
{"ad5446", ID_AD5446},
{"ad5542a", ID_AD5542A},
{"ad5512a", ID_AD5512A},
{}
};
static struct spi_driver ad5446_driver = {
.driver = {
.name = "ad5446",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = ad5446_probe,
.remove = __devexit_p(ad5446_remove),
.id_table = ad5446_id,
};
static int __init ad5446_init(void)
{
return spi_register_driver(&ad5446_driver);
}
module_init(ad5446_init);
static void __exit ad5446_exit(void)
{
spi_unregister_driver(&ad5446_driver);
}
module_exit(ad5446_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ad5446");

View File

@ -0,0 +1,46 @@
/*
* AD5446 SPI DAC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef IIO_ADC_AD5446_H_
#define IIO_ADC_AD5446_H_
/* DAC Control Bits */
#define AD5446_LOAD (0x0 << 14) /* Load and update */
#define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */
#define AD5446_NOP (0x2 << 14) /* No operation */
#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */
#define RES_MASK(bits) ((1 << (bits)) - 1)
struct ad5446_chip_info {
u8 bits; /* number of DAC bits */
u8 storagebits; /* number of bits written to the DAC */
u8 left_shift; /* number of bits the datum must be shifted */
char sign; /* [s]igned or [u]nsigned */
};
struct ad5446_state {
struct iio_dev *indio_dev;
struct spi_device *spi;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
struct work_struct poll_work;
unsigned short vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
unsigned short data;
};
enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5542A,
ID_AD5512A,
};
#endif /* IIO_ADC_AD5446_H_ */