staging: iio: dac: ad5446: Enable driver support for AD5620/AD5640/AD5660 DA converters
Initial support for single channel, 12-/14-/16-Bit nanoDAC with On-Chip Reference staging: iio: dac: ad5446: Fix according to review feedback Review feedback by Jonathan Cameron: Use kernel doc style to document headers. Turn data into a union Add some comments for clarity 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:
Родитель
f386caa3cd
Коммит
d846263da4
|
@ -11,11 +11,11 @@ config AD5624R_SPI
|
||||||
AD5664R convertors (DAC). This driver uses the common SPI interface.
|
AD5664R convertors (DAC). This driver uses the common SPI interface.
|
||||||
|
|
||||||
config AD5446
|
config AD5446
|
||||||
tristate "Analog Devices AD5444, AD5446 and AD5541A, AD5512A DAC SPI driver"
|
tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5541A/12A DAC SPI driver"
|
||||||
depends on SPI
|
depends on SPI
|
||||||
help
|
help
|
||||||
Say yes here to build support for Analog Devices AD5444, AD5446
|
Say yes here to build support for Analog Devices AD5444, AD5446,
|
||||||
and AD5541A, AD5512A DACs.
|
AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called ad5446.
|
module will be called ad5446.
|
||||||
|
|
|
@ -23,6 +23,31 @@
|
||||||
|
|
||||||
#include "ad5446.h"
|
#include "ad5446.h"
|
||||||
|
|
||||||
|
static void ad5446_store_sample(struct ad5446_state *st, unsigned val)
|
||||||
|
{
|
||||||
|
st->data.d16 = cpu_to_be16(AD5446_LOAD |
|
||||||
|
(val << st->chip_info->left_shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ad5542_store_sample(struct ad5446_state *st, unsigned val)
|
||||||
|
{
|
||||||
|
st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ad5620_store_sample(struct ad5446_state *st, unsigned val)
|
||||||
|
{
|
||||||
|
st->data.d16 = cpu_to_be16(AD5620_LOAD |
|
||||||
|
(val << st->chip_info->left_shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
|
||||||
|
{
|
||||||
|
val |= AD5660_LOAD;
|
||||||
|
st->data.d24[0] = (val >> 16) & 0xFF;
|
||||||
|
st->data.d24[1] = (val >> 8) & 0xFF;
|
||||||
|
st->data.d24[2] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t ad5446_write(struct device *dev,
|
static ssize_t ad5446_write(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
|
@ -43,18 +68,7 @@ static ssize_t ad5446_write(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev_info->mlock);
|
mutex_lock(&dev_info->mlock);
|
||||||
switch (spi_get_device_id(st->spi)->driver_data) {
|
st->chip_info->store_sample(st, val);
|
||||||
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);
|
ret = spi_sync(st->spi, &st->msg);
|
||||||
mutex_unlock(&dev_info->mlock);
|
mutex_unlock(&dev_info->mlock);
|
||||||
|
|
||||||
|
@ -105,24 +119,76 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
|
||||||
.storagebits = 16,
|
.storagebits = 16,
|
||||||
.left_shift = 2,
|
.left_shift = 2,
|
||||||
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.store_sample = ad5446_store_sample,
|
||||||
},
|
},
|
||||||
[ID_AD5446] = {
|
[ID_AD5446] = {
|
||||||
.bits = 14,
|
.bits = 14,
|
||||||
.storagebits = 16,
|
.storagebits = 16,
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.store_sample = ad5446_store_sample,
|
||||||
},
|
},
|
||||||
[ID_AD5542A] = {
|
[ID_AD5542A] = {
|
||||||
.bits = 16,
|
.bits = 16,
|
||||||
.storagebits = 16,
|
.storagebits = 16,
|
||||||
.left_shift = 0,
|
.left_shift = 0,
|
||||||
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.store_sample = ad5542_store_sample,
|
||||||
},
|
},
|
||||||
[ID_AD5512A] = {
|
[ID_AD5512A] = {
|
||||||
.bits = 12,
|
.bits = 12,
|
||||||
.storagebits = 16,
|
.storagebits = 16,
|
||||||
.left_shift = 4,
|
.left_shift = 4,
|
||||||
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.store_sample = ad5542_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5620_2500] = {
|
||||||
|
.bits = 12,
|
||||||
|
.storagebits = 16,
|
||||||
|
.left_shift = 2,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 2500,
|
||||||
|
.store_sample = ad5620_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5620_1250] = {
|
||||||
|
.bits = 12,
|
||||||
|
.storagebits = 16,
|
||||||
|
.left_shift = 2,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 1250,
|
||||||
|
.store_sample = ad5620_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5640_2500] = {
|
||||||
|
.bits = 14,
|
||||||
|
.storagebits = 16,
|
||||||
|
.left_shift = 0,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 2500,
|
||||||
|
.store_sample = ad5620_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5640_1250] = {
|
||||||
|
.bits = 14,
|
||||||
|
.storagebits = 16,
|
||||||
|
.left_shift = 0,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 1250,
|
||||||
|
.store_sample = ad5620_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5660_2500] = {
|
||||||
|
.bits = 16,
|
||||||
|
.storagebits = 24,
|
||||||
|
.left_shift = 0,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 2500,
|
||||||
|
.store_sample = ad5660_store_sample,
|
||||||
|
},
|
||||||
|
[ID_AD5660_1250] = {
|
||||||
|
.bits = 16,
|
||||||
|
.storagebits = 24,
|
||||||
|
.left_shift = 0,
|
||||||
|
.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
|
||||||
|
.int_vref_mv = 1250,
|
||||||
|
.store_sample = ad5660_store_sample,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,16 +234,28 @@ static int __devinit ad5446_probe(struct spi_device *spi)
|
||||||
|
|
||||||
/* Setup default message */
|
/* Setup default message */
|
||||||
|
|
||||||
st->xfer.tx_buf = &st->data,
|
st->xfer.tx_buf = &st->data;
|
||||||
st->xfer.len = 2,
|
st->xfer.len = st->chip_info->storagebits / 8;
|
||||||
|
|
||||||
spi_message_init(&st->msg);
|
spi_message_init(&st->msg);
|
||||||
spi_message_add_tail(&st->xfer, &st->msg);
|
spi_message_add_tail(&st->xfer, &st->msg);
|
||||||
|
|
||||||
if (voltage_uv)
|
switch (spi_get_device_id(spi)->driver_data) {
|
||||||
st->vref_mv = voltage_uv / 1000;
|
case ID_AD5620_2500:
|
||||||
else
|
case ID_AD5620_1250:
|
||||||
dev_warn(&spi->dev, "reference voltage unspecified\n");
|
case ID_AD5640_2500:
|
||||||
|
case ID_AD5640_1250:
|
||||||
|
case ID_AD5660_2500:
|
||||||
|
case ID_AD5660_1250:
|
||||||
|
st->vref_mv = st->chip_info->int_vref_mv;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (voltage_uv)
|
||||||
|
st->vref_mv = voltage_uv / 1000;
|
||||||
|
else
|
||||||
|
dev_warn(&spi->dev,
|
||||||
|
"reference voltage unspecified\n");
|
||||||
|
}
|
||||||
|
|
||||||
ret = iio_device_register(st->indio_dev);
|
ret = iio_device_register(st->indio_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -217,6 +295,12 @@ static const struct spi_device_id ad5446_id[] = {
|
||||||
{"ad5446", ID_AD5446},
|
{"ad5446", ID_AD5446},
|
||||||
{"ad5542a", ID_AD5542A},
|
{"ad5542a", ID_AD5542A},
|
||||||
{"ad5512a", ID_AD5512A},
|
{"ad5512a", ID_AD5512A},
|
||||||
|
{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
|
||||||
|
{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
|
||||||
|
{"ad5640-2500", ID_AD5640_2500},
|
||||||
|
{"ad5640-1250", ID_AD5640_1250},
|
||||||
|
{"ad5660-2500", ID_AD5660_2500},
|
||||||
|
{"ad5660-1250", ID_AD5660_1250},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*
|
*
|
||||||
* Licensed under the GPL-2 or later.
|
* Licensed under the GPL-2 or later.
|
||||||
*/
|
*/
|
||||||
#ifndef IIO_ADC_AD5446_H_
|
#ifndef IIO_DAC_AD5446_H_
|
||||||
#define IIO_ADC_AD5446_H_
|
#define IIO_DAC_AD5446_H_
|
||||||
|
|
||||||
/* DAC Control Bits */
|
/* DAC Control Bits */
|
||||||
|
|
||||||
|
@ -15,14 +15,30 @@
|
||||||
#define AD5446_NOP (0x2 << 14) /* No operation */
|
#define AD5446_NOP (0x2 << 14) /* No operation */
|
||||||
#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */
|
#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */
|
||||||
|
|
||||||
|
#define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/
|
||||||
|
#define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */
|
||||||
|
#define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */
|
||||||
|
#define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */
|
||||||
|
|
||||||
|
#define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/
|
||||||
|
#define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */
|
||||||
|
#define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */
|
||||||
|
#define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */
|
||||||
|
|
||||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||||
|
|
||||||
struct ad5446_chip_info {
|
/**
|
||||||
u8 bits; /* number of DAC bits */
|
* struct ad5446_state - driver instance specific data
|
||||||
u8 storagebits; /* number of bits written to the DAC */
|
* @indio_dev: the industrial I/O device
|
||||||
u8 left_shift; /* number of bits the datum must be shifted */
|
* @spi: spi_device
|
||||||
char sign; /* [s]igned or [u]nsigned */
|
* @chip_info: chip model specific constants, available modes etc
|
||||||
};
|
* @reg: supply regulator
|
||||||
|
* @poll_work: bottom half of polling interrupt handler
|
||||||
|
* @vref_mv: actual reference voltage used
|
||||||
|
* @xfer: default spi transfer
|
||||||
|
* @msg: default spi message
|
||||||
|
* @data: spi transmit buffer
|
||||||
|
*/
|
||||||
|
|
||||||
struct ad5446_state {
|
struct ad5446_state {
|
||||||
struct iio_dev *indio_dev;
|
struct iio_dev *indio_dev;
|
||||||
|
@ -33,14 +49,50 @@ struct ad5446_state {
|
||||||
unsigned short vref_mv;
|
unsigned short vref_mv;
|
||||||
struct spi_transfer xfer;
|
struct spi_transfer xfer;
|
||||||
struct spi_message msg;
|
struct spi_message msg;
|
||||||
unsigned short data;
|
union {
|
||||||
|
unsigned short d16;
|
||||||
|
unsigned char d24[3];
|
||||||
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ad5446_chip_info - chip specifc information
|
||||||
|
* @bits: accuracy of the DAC in bits
|
||||||
|
* @storagebits: number of bits written to the DAC
|
||||||
|
* @left_shift: number of bits the datum must be shifted
|
||||||
|
* @sign: data representation [s]igned or [u]nsigned
|
||||||
|
* @int_vref_mv: AD5620/40/60: the internal reference voltage
|
||||||
|
* @store_sample: chip specifc helper function to store the datum
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ad5446_chip_info {
|
||||||
|
u8 bits;
|
||||||
|
u8 storagebits;
|
||||||
|
u8 left_shift;
|
||||||
|
char sign;
|
||||||
|
u16 int_vref_mv;
|
||||||
|
void (*store_sample) (struct ad5446_state *st, unsigned val);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ad5446_supported_device_ids:
|
||||||
|
* The AD5620/40/60 parts are available in different fixed internal reference
|
||||||
|
* voltage options. The actual part numbers may look differently
|
||||||
|
* (and a bit cryptic), however this style is used to make clear which
|
||||||
|
* parts are supported here.
|
||||||
|
*/
|
||||||
|
|
||||||
enum ad5446_supported_device_ids {
|
enum ad5446_supported_device_ids {
|
||||||
ID_AD5444,
|
ID_AD5444,
|
||||||
ID_AD5446,
|
ID_AD5446,
|
||||||
ID_AD5542A,
|
ID_AD5542A,
|
||||||
ID_AD5512A,
|
ID_AD5512A,
|
||||||
|
ID_AD5620_2500,
|
||||||
|
ID_AD5620_1250,
|
||||||
|
ID_AD5640_2500,
|
||||||
|
ID_AD5640_1250,
|
||||||
|
ID_AD5660_2500,
|
||||||
|
ID_AD5660_1250,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* IIO_ADC_AD5446_H_ */
|
#endif /* IIO_DAC_AD5446_H_ */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче