iio:dac:ad5686: Refactor the driver
In this patch restructures the existing ad5686 driver by adding a module for SPI and a header file, while the baseline module deals with the chip-logic. This is a necessary step, as this driver should support in the future similar devices which differ only in the type of interface used (I2C instead of SPI). Signed-off-by: Stefan Popa <stefan.popa@analog.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Родитель
98baf78e6d
Коммит
0357e488b8
|
@ -791,6 +791,13 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/macintosh/ams/
|
F: drivers/macintosh/ams/
|
||||||
|
|
||||||
|
ANALOG DEVICES INC AD5686 DRIVER
|
||||||
|
M: Stefan Popa <stefan.popa@analog.com>
|
||||||
|
L: linux-pm@vger.kernel.org
|
||||||
|
W: http://ez.analog.com/community/linux-device-drivers
|
||||||
|
S: Supported
|
||||||
|
F: drivers/iio/dac/ad5686*
|
||||||
|
|
||||||
ANALOG DEVICES INC AD9389B DRIVER
|
ANALOG DEVICES INC AD9389B DRIVER
|
||||||
M: Hans Verkuil <hans.verkuil@cisco.com>
|
M: Hans Verkuil <hans.verkuil@cisco.com>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
|
|
|
@ -131,16 +131,21 @@ config LTC2632
|
||||||
module will be called ltc2632.
|
module will be called ltc2632.
|
||||||
|
|
||||||
config AD5686
|
config AD5686
|
||||||
tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
|
tristate
|
||||||
|
|
||||||
|
config AD5686_SPI
|
||||||
|
tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)"
|
||||||
depends on SPI
|
depends on SPI
|
||||||
|
select AD5686
|
||||||
help
|
help
|
||||||
Say yes here to build support for Analog Devices AD5686R, AD5685R,
|
Say yes here to build support for Analog Devices AD5672R, AD5676,
|
||||||
AD5684R, AD5791 Voltage Output Digital to
|
AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R.
|
||||||
Analog Converter.
|
Voltage Output Digital to Analog Converter.
|
||||||
|
|
||||||
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 ad5686.
|
module will be called ad5686.
|
||||||
|
|
||||||
|
|
||||||
config AD5755
|
config AD5755
|
||||||
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
|
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
|
||||||
depends on SPI_MASTER
|
depends on SPI_MASTER
|
||||||
|
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_AD5761) += ad5761.o
|
||||||
obj-$(CONFIG_AD5764) += ad5764.o
|
obj-$(CONFIG_AD5764) += ad5764.o
|
||||||
obj-$(CONFIG_AD5791) += ad5791.o
|
obj-$(CONFIG_AD5791) += ad5791.o
|
||||||
obj-$(CONFIG_AD5686) += ad5686.o
|
obj-$(CONFIG_AD5686) += ad5686.o
|
||||||
|
obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o
|
||||||
obj-$(CONFIG_AD7303) += ad7303.o
|
obj-$(CONFIG_AD7303) += ad7303.o
|
||||||
obj-$(CONFIG_AD8801) += ad8801.o
|
obj-$(CONFIG_AD8801) += ad8801.o
|
||||||
obj-$(CONFIG_CIO_DAC) += cio-dac.o
|
obj-$(CONFIG_CIO_DAC) += cio-dac.o
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* AD5672R, AD5676, AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R
|
||||||
|
* Digital to analog converters driver
|
||||||
|
*
|
||||||
|
* Copyright 2018 Analog Devices Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ad5686.h"
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
|
static int ad5686_spi_write(struct ad5686_state *st,
|
||||||
|
u8 cmd, u8 addr, u16 val)
|
||||||
|
{
|
||||||
|
struct spi_device *spi = to_spi_device(st->dev);
|
||||||
|
|
||||||
|
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
|
||||||
|
AD5686_ADDR(addr) |
|
||||||
|
val);
|
||||||
|
|
||||||
|
return spi_write(spi, &st->data[0].d8[1], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
|
||||||
|
{
|
||||||
|
struct spi_transfer t[] = {
|
||||||
|
{
|
||||||
|
.tx_buf = &st->data[0].d8[1],
|
||||||
|
.len = 3,
|
||||||
|
.cs_change = 1,
|
||||||
|
}, {
|
||||||
|
.tx_buf = &st->data[1].d8[1],
|
||||||
|
.rx_buf = &st->data[2].d8[1],
|
||||||
|
.len = 3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
struct spi_device *spi = to_spi_device(st->dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
|
||||||
|
AD5686_ADDR(addr));
|
||||||
|
st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
|
||||||
|
|
||||||
|
ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return be32_to_cpu(st->data[2].d32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ad5686_spi_probe(struct spi_device *spi)
|
||||||
|
{
|
||||||
|
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||||
|
|
||||||
|
return ad5686_probe(&spi->dev, id->driver_data, id->name,
|
||||||
|
ad5686_spi_write, ad5686_spi_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ad5686_spi_remove(struct spi_device *spi)
|
||||||
|
{
|
||||||
|
return ad5686_remove(&spi->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct spi_device_id ad5686_spi_id[] = {
|
||||||
|
{"ad5672r", ID_AD5672R},
|
||||||
|
{"ad5676", ID_AD5676},
|
||||||
|
{"ad5676r", ID_AD5676R},
|
||||||
|
{"ad5684", ID_AD5684},
|
||||||
|
{"ad5684r", ID_AD5684R},
|
||||||
|
{"ad5685", ID_AD5685R}, /* Does not exist */
|
||||||
|
{"ad5685r", ID_AD5685R},
|
||||||
|
{"ad5686", ID_AD5686},
|
||||||
|
{"ad5686r", ID_AD5686R},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(spi, ad5686_spi_id);
|
||||||
|
|
||||||
|
static struct spi_driver ad5686_spi_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "ad5686",
|
||||||
|
},
|
||||||
|
.probe = ad5686_spi_probe,
|
||||||
|
.remove = ad5686_spi_remove,
|
||||||
|
.id_table = ad5686_spi_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_spi_driver(ad5686_spi_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||||
|
MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -10,7 +10,6 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/spi/spi.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
@ -18,121 +17,7 @@
|
||||||
#include <linux/iio/iio.h>
|
#include <linux/iio/iio.h>
|
||||||
#include <linux/iio/sysfs.h>
|
#include <linux/iio/sysfs.h>
|
||||||
|
|
||||||
#define AD5686_ADDR(x) ((x) << 16)
|
#include "ad5686.h"
|
||||||
#define AD5686_CMD(x) ((x) << 20)
|
|
||||||
|
|
||||||
#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
|
|
||||||
#define AD5686_ADDR_ALL_DAC 0xF
|
|
||||||
|
|
||||||
#define AD5686_CMD_NOOP 0x0
|
|
||||||
#define AD5686_CMD_WRITE_INPUT_N 0x1
|
|
||||||
#define AD5686_CMD_UPDATE_DAC_N 0x2
|
|
||||||
#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3
|
|
||||||
#define AD5686_CMD_POWERDOWN_DAC 0x4
|
|
||||||
#define AD5686_CMD_LDAC_MASK 0x5
|
|
||||||
#define AD5686_CMD_RESET 0x6
|
|
||||||
#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7
|
|
||||||
#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
|
|
||||||
#define AD5686_CMD_READBACK_ENABLE 0x9
|
|
||||||
|
|
||||||
#define AD5686_LDAC_PWRDN_NONE 0x0
|
|
||||||
#define AD5686_LDAC_PWRDN_1K 0x1
|
|
||||||
#define AD5686_LDAC_PWRDN_100K 0x2
|
|
||||||
#define AD5686_LDAC_PWRDN_3STATE 0x3
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct ad5686_chip_info - chip specific information
|
|
||||||
* @int_vref_mv: AD5620/40/60: the internal reference voltage
|
|
||||||
* @num_channels: number of channels
|
|
||||||
* @channel: channel specification
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct ad5686_chip_info {
|
|
||||||
u16 int_vref_mv;
|
|
||||||
unsigned int num_channels;
|
|
||||||
struct iio_chan_spec *channels;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct ad5446_state - driver instance specific data
|
|
||||||
* @spi: spi_device
|
|
||||||
* @chip_info: chip model specific constants, available modes etc
|
|
||||||
* @reg: supply regulator
|
|
||||||
* @vref_mv: actual reference voltage used
|
|
||||||
* @pwr_down_mask: power down mask
|
|
||||||
* @pwr_down_mode: current power down mode
|
|
||||||
* @data: spi transfer buffers
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct ad5686_state {
|
|
||||||
struct spi_device *spi;
|
|
||||||
const struct ad5686_chip_info *chip_info;
|
|
||||||
struct regulator *reg;
|
|
||||||
unsigned short vref_mv;
|
|
||||||
unsigned pwr_down_mask;
|
|
||||||
unsigned pwr_down_mode;
|
|
||||||
/*
|
|
||||||
* DMA (thus cache coherency maintenance) requires the
|
|
||||||
* transfer buffers to live in their own cache lines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
union {
|
|
||||||
__be32 d32;
|
|
||||||
u8 d8[4];
|
|
||||||
} data[3] ____cacheline_aligned;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ad5686_supported_device_ids:
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum ad5686_supported_device_ids {
|
|
||||||
ID_AD5672R,
|
|
||||||
ID_AD5676,
|
|
||||||
ID_AD5676R,
|
|
||||||
ID_AD5684,
|
|
||||||
ID_AD5684R,
|
|
||||||
ID_AD5685R,
|
|
||||||
ID_AD5686,
|
|
||||||
ID_AD5686R
|
|
||||||
};
|
|
||||||
static int ad5686_spi_write(struct ad5686_state *st,
|
|
||||||
u8 cmd, u8 addr, u16 val, u8 shift)
|
|
||||||
{
|
|
||||||
val <<= shift;
|
|
||||||
|
|
||||||
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
|
|
||||||
AD5686_ADDR(addr) |
|
|
||||||
val);
|
|
||||||
|
|
||||||
return spi_write(st->spi, &st->data[0].d8[1], 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
|
|
||||||
{
|
|
||||||
struct spi_transfer t[] = {
|
|
||||||
{
|
|
||||||
.tx_buf = &st->data[0].d8[1],
|
|
||||||
.len = 3,
|
|
||||||
.cs_change = 1,
|
|
||||||
}, {
|
|
||||||
.tx_buf = &st->data[1].d8[1],
|
|
||||||
.rx_buf = &st->data[2].d8[1],
|
|
||||||
.len = 3,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
|
|
||||||
AD5686_ADDR(addr));
|
|
||||||
st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
|
|
||||||
|
|
||||||
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return be32_to_cpu(st->data[2].d32);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char * const ad5686_powerdown_modes[] = {
|
static const char * const ad5686_powerdown_modes[] = {
|
||||||
"1kohm_to_gnd",
|
"1kohm_to_gnd",
|
||||||
|
@ -195,8 +80,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
|
||||||
else
|
else
|
||||||
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
|
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
|
||||||
|
|
||||||
ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
|
ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0,
|
||||||
st->pwr_down_mask & st->pwr_down_mode, 0);
|
st->pwr_down_mask & st->pwr_down_mode);
|
||||||
|
|
||||||
|
|
||||||
return ret ? ret : len;
|
return ret ? ret : len;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +99,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
|
||||||
switch (m) {
|
switch (m) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
mutex_lock(&indio_dev->mlock);
|
mutex_lock(&indio_dev->mlock);
|
||||||
ret = ad5686_spi_read(st, chan->address);
|
ret = st->read(st, chan->address);
|
||||||
mutex_unlock(&indio_dev->mlock);
|
mutex_unlock(&indio_dev->mlock);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -242,11 +128,10 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&indio_dev->mlock);
|
mutex_lock(&indio_dev->mlock);
|
||||||
ret = ad5686_spi_write(st,
|
ret = st->write(st,
|
||||||
AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
|
AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
|
||||||
chan->address,
|
chan->address,
|
||||||
val,
|
val << chan->scan_type.shift);
|
||||||
chan->scan_type.shift);
|
|
||||||
mutex_unlock(&indio_dev->mlock);
|
mutex_unlock(&indio_dev->mlock);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -356,20 +241,27 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ad5686_probe(struct spi_device *spi)
|
int ad5686_probe(struct device *dev,
|
||||||
|
enum ad5686_supported_device_ids chip_type,
|
||||||
|
const char *name, ad5686_write_func write,
|
||||||
|
ad5686_read_func read)
|
||||||
{
|
{
|
||||||
struct ad5686_state *st;
|
struct ad5686_state *st;
|
||||||
struct iio_dev *indio_dev;
|
struct iio_dev *indio_dev;
|
||||||
int ret, voltage_uv = 0;
|
int ret, voltage_uv = 0;
|
||||||
|
|
||||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||||
if (indio_dev == NULL)
|
if (indio_dev == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
st = iio_priv(indio_dev);
|
st = iio_priv(indio_dev);
|
||||||
spi_set_drvdata(spi, indio_dev);
|
dev_set_drvdata(dev, indio_dev);
|
||||||
|
|
||||||
st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
|
st->dev = dev;
|
||||||
|
st->write = write;
|
||||||
|
st->read = read;
|
||||||
|
|
||||||
|
st->reg = devm_regulator_get_optional(dev, "vcc");
|
||||||
if (!IS_ERR(st->reg)) {
|
if (!IS_ERR(st->reg)) {
|
||||||
ret = regulator_enable(st->reg);
|
ret = regulator_enable(st->reg);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -382,28 +274,25 @@ static int ad5686_probe(struct spi_device *spi)
|
||||||
voltage_uv = ret;
|
voltage_uv = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->chip_info =
|
st->chip_info = &ad5686_chip_info_tbl[chip_type];
|
||||||
&ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
|
||||||
|
|
||||||
if (voltage_uv)
|
if (voltage_uv)
|
||||||
st->vref_mv = voltage_uv / 1000;
|
st->vref_mv = voltage_uv / 1000;
|
||||||
else
|
else
|
||||||
st->vref_mv = st->chip_info->int_vref_mv;
|
st->vref_mv = st->chip_info->int_vref_mv;
|
||||||
|
|
||||||
st->spi = spi;
|
|
||||||
|
|
||||||
/* Set all the power down mode for all channels to 1K pulldown */
|
/* Set all the power down mode for all channels to 1K pulldown */
|
||||||
st->pwr_down_mode = 0x55;
|
st->pwr_down_mode = 0x55;
|
||||||
|
|
||||||
indio_dev->dev.parent = &spi->dev;
|
indio_dev->dev.parent = dev;
|
||||||
indio_dev->name = spi_get_device_id(spi)->name;
|
indio_dev->name = name;
|
||||||
indio_dev->info = &ad5686_info;
|
indio_dev->info = &ad5686_info;
|
||||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||||
indio_dev->channels = st->chip_info->channels;
|
indio_dev->channels = st->chip_info->channels;
|
||||||
indio_dev->num_channels = st->chip_info->num_channels;
|
indio_dev->num_channels = st->chip_info->num_channels;
|
||||||
|
|
||||||
ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
|
ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP,
|
||||||
!!voltage_uv, 0);
|
0, !!voltage_uv);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_disable_reg;
|
goto error_disable_reg;
|
||||||
|
|
||||||
|
@ -418,10 +307,11 @@ error_disable_reg:
|
||||||
regulator_disable(st->reg);
|
regulator_disable(st->reg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ad5686_probe);
|
||||||
|
|
||||||
static int ad5686_remove(struct spi_device *spi)
|
int ad5686_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
struct ad5686_state *st = iio_priv(indio_dev);
|
struct ad5686_state *st = iio_priv(indio_dev);
|
||||||
|
|
||||||
iio_device_unregister(indio_dev);
|
iio_device_unregister(indio_dev);
|
||||||
|
@ -430,30 +320,7 @@ static int ad5686_remove(struct spi_device *spi)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ad5686_remove);
|
||||||
static const struct spi_device_id ad5686_id[] = {
|
|
||||||
{"ad5672r", ID_AD5672R},
|
|
||||||
{"ad5676", ID_AD5676},
|
|
||||||
{"ad5676r", ID_AD5676R},
|
|
||||||
{"ad5684", ID_AD5684},
|
|
||||||
{"ad5684r", ID_AD5684R},
|
|
||||||
{"ad5685", ID_AD5685R}, /* Does not exist */
|
|
||||||
{"ad5685r", ID_AD5685R},
|
|
||||||
{"ad5686", ID_AD5686},
|
|
||||||
{"ad5686r", ID_AD5686R},
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(spi, ad5686_id);
|
|
||||||
|
|
||||||
static struct spi_driver ad5686_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "ad5686",
|
|
||||||
},
|
|
||||||
.probe = ad5686_probe,
|
|
||||||
.remove = ad5686_remove,
|
|
||||||
.id_table = ad5686_id,
|
|
||||||
};
|
|
||||||
module_spi_driver(ad5686_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||||
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
|
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* This file is part of AD5686 DAC driver
|
||||||
|
*
|
||||||
|
* Copyright 2018 Analog Devices Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_IIO_DAC_AD5686_H__
|
||||||
|
#define __DRIVERS_IIO_DAC_AD5686_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/cache.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#define AD5686_ADDR(x) ((x) << 16)
|
||||||
|
#define AD5686_CMD(x) ((x) << 20)
|
||||||
|
|
||||||
|
#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
|
||||||
|
#define AD5686_ADDR_ALL_DAC 0xF
|
||||||
|
|
||||||
|
#define AD5686_CMD_NOOP 0x0
|
||||||
|
#define AD5686_CMD_WRITE_INPUT_N 0x1
|
||||||
|
#define AD5686_CMD_UPDATE_DAC_N 0x2
|
||||||
|
#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3
|
||||||
|
#define AD5686_CMD_POWERDOWN_DAC 0x4
|
||||||
|
#define AD5686_CMD_LDAC_MASK 0x5
|
||||||
|
#define AD5686_CMD_RESET 0x6
|
||||||
|
#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7
|
||||||
|
#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
|
||||||
|
#define AD5686_CMD_READBACK_ENABLE 0x9
|
||||||
|
|
||||||
|
#define AD5686_LDAC_PWRDN_NONE 0x0
|
||||||
|
#define AD5686_LDAC_PWRDN_1K 0x1
|
||||||
|
#define AD5686_LDAC_PWRDN_100K 0x2
|
||||||
|
#define AD5686_LDAC_PWRDN_3STATE 0x3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ad5686_supported_device_ids:
|
||||||
|
*/
|
||||||
|
enum ad5686_supported_device_ids {
|
||||||
|
ID_AD5672R,
|
||||||
|
ID_AD5676,
|
||||||
|
ID_AD5676R,
|
||||||
|
ID_AD5684,
|
||||||
|
ID_AD5684R,
|
||||||
|
ID_AD5685R,
|
||||||
|
ID_AD5686,
|
||||||
|
ID_AD5686R,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ad5686_state;
|
||||||
|
|
||||||
|
typedef int (*ad5686_write_func)(struct ad5686_state *st,
|
||||||
|
u8 cmd, u8 addr, u16 val);
|
||||||
|
|
||||||
|
typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ad5686_chip_info - chip specific information
|
||||||
|
* @int_vref_mv: AD5620/40/60: the internal reference voltage
|
||||||
|
* @num_channels: number of channels
|
||||||
|
* @channel: channel specification
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ad5686_chip_info {
|
||||||
|
u16 int_vref_mv;
|
||||||
|
unsigned int num_channels;
|
||||||
|
struct iio_chan_spec *channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ad5446_state - driver instance specific data
|
||||||
|
* @spi: spi_device
|
||||||
|
* @chip_info: chip model specific constants, available modes etc
|
||||||
|
* @reg: supply regulator
|
||||||
|
* @vref_mv: actual reference voltage used
|
||||||
|
* @pwr_down_mask: power down mask
|
||||||
|
* @pwr_down_mode: current power down mode
|
||||||
|
* @data: spi transfer buffers
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ad5686_state {
|
||||||
|
struct device *dev;
|
||||||
|
const struct ad5686_chip_info *chip_info;
|
||||||
|
struct regulator *reg;
|
||||||
|
unsigned short vref_mv;
|
||||||
|
unsigned int pwr_down_mask;
|
||||||
|
unsigned int pwr_down_mode;
|
||||||
|
ad5686_write_func write;
|
||||||
|
ad5686_read_func read;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA (thus cache coherency maintenance) requires the
|
||||||
|
* transfer buffers to live in their own cache lines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
union {
|
||||||
|
__be32 d32;
|
||||||
|
__be16 d16;
|
||||||
|
u8 d8[4];
|
||||||
|
} data[3] ____cacheline_aligned;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int ad5686_probe(struct device *dev,
|
||||||
|
enum ad5686_supported_device_ids chip_type,
|
||||||
|
const char *name, ad5686_write_func write,
|
||||||
|
ad5686_read_func read);
|
||||||
|
|
||||||
|
int ad5686_remove(struct device *dev);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */
|
Загрузка…
Ссылка в новой задаче