Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d846263d authored by Michael Hennerich's avatar Michael Hennerich Committed by Greg Kroah-Hartman
Browse files

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: default avatarMichael Hennerich <michael.hennerich@analog.com>
Acked-by: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent f386caa3
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -11,11 +11,11 @@ config AD5624R_SPI
	  AD5664R convertors (DAC). This driver uses the common SPI interface.

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
	help
	  Say yes here to build support for Analog Devices AD5444, AD5446
	  and AD5541A, AD5512A DACs.
	  Say yes here to build support for Analog Devices AD5444, AD5446,
	  AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs.

	  To compile this driver as a module, choose M here: the
	  module will be called ad5446.
+102 −18
Original line number Diff line number Diff line
@@ -23,6 +23,31 @@

#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,
		struct device_attribute *attr,
		const char *buf,
@@ -43,18 +68,7 @@ static ssize_t ad5446_write(struct device *dev,
	}

	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;
	}

	st->chip_info->store_sample(st, val);
	ret = spi_sync(st->spi, &st->msg);
	mutex_unlock(&dev_info->mlock);

@@ -105,24 +119,76 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
		.storagebits = 16,
		.left_shift = 2,
		.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
		.store_sample = ad5446_store_sample,
	},
	[ID_AD5446] = {
		.bits = 14,
		.storagebits = 16,
		.left_shift = 0,
		.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
		.store_sample = ad5446_store_sample,
	},
	[ID_AD5542A] = {
		.bits = 16,
		.storagebits = 16,
		.left_shift = 0,
		.sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */
		.store_sample = ad5542_store_sample,
	},
	[ID_AD5512A] = {
		.bits = 12,
		.storagebits = 16,
		.left_shift = 4,
		.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 */

	st->xfer.tx_buf = &st->data,
	st->xfer.len = 2,
	st->xfer.tx_buf = &st->data;
	st->xfer.len = st->chip_info->storagebits / 8;

	spi_message_init(&st->msg);
	spi_message_add_tail(&st->xfer, &st->msg);

	switch (spi_get_device_id(spi)->driver_data) {
		case ID_AD5620_2500:
		case ID_AD5620_1250:
		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");
				dev_warn(&spi->dev,
					 "reference voltage unspecified\n");
	}

	ret = iio_device_register(st->indio_dev);
	if (ret)
@@ -217,6 +295,12 @@ static const struct spi_device_id ad5446_id[] = {
	{"ad5446", ID_AD5446},
	{"ad5542a", ID_AD5542A},
	{"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},
	{}
};

+62 −10
Original line number Diff line number Diff line
@@ -5,8 +5,8 @@
 *
 * Licensed under the GPL-2 or later.
 */
#ifndef IIO_ADC_AD5446_H_
#define IIO_ADC_AD5446_H_
#ifndef IIO_DAC_AD5446_H_
#define IIO_DAC_AD5446_H_

/* DAC Control Bits */

@@ -15,14 +15,30 @@
#define AD5446_NOP		(0x2 << 14) /* No operation */
#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)

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 - driver instance specific data
 * @indio_dev:		the industrial I/O device
 * @spi:		spi_device
 * @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 iio_dev			*indio_dev;
@@ -33,14 +49,50 @@ struct ad5446_state {
	unsigned short			vref_mv;
	struct spi_transfer		xfer;
	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 {
	ID_AD5444,
	ID_AD5446,
	ID_AD5542A,
	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_ */