123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Analog Devices AD5766, AD5767
- * Digital to Analog Converters driver
- * Copyright 2019-2020 Analog Devices Inc.
- */
- #include <linux/bitfield.h>
- #include <linux/bitops.h>
- #include <linux/delay.h>
- #include <linux/device.h>
- #include <linux/gpio/consumer.h>
- #include <linux/iio/iio.h>
- #include <linux/iio/triggered_buffer.h>
- #include <linux/iio/trigger_consumer.h>
- #include <linux/module.h>
- #include <linux/spi/spi.h>
- #include <asm/unaligned.h>
- #define AD5766_UPPER_WORD_SPI_MASK GENMASK(31, 16)
- #define AD5766_LOWER_WORD_SPI_MASK GENMASK(15, 0)
- #define AD5766_DITHER_SOURCE_MASK(ch) GENMASK(((2 * ch) + 1), (2 * ch))
- #define AD5766_DITHER_SOURCE(ch, source) BIT((ch * 2) + source)
- #define AD5766_DITHER_SCALE_MASK(x) AD5766_DITHER_SOURCE_MASK(x)
- #define AD5766_DITHER_SCALE(ch, scale) (scale << (ch * 2))
- #define AD5766_DITHER_ENABLE_MASK(ch) BIT(ch)
- #define AD5766_DITHER_ENABLE(ch, state) ((!state) << ch)
- #define AD5766_DITHER_INVERT_MASK(ch) BIT(ch)
- #define AD5766_DITHER_INVERT(ch, state) (state << ch)
- #define AD5766_CMD_NOP_MUX_OUT 0x00
- #define AD5766_CMD_SDO_CNTRL 0x01
- #define AD5766_CMD_WR_IN_REG(x) (0x10 | ((x) & GENMASK(3, 0)))
- #define AD5766_CMD_WR_DAC_REG(x) (0x20 | ((x) & GENMASK(3, 0)))
- #define AD5766_CMD_SW_LDAC 0x30
- #define AD5766_CMD_SPAN_REG 0x40
- #define AD5766_CMD_WR_PWR_DITHER 0x51
- #define AD5766_CMD_WR_DAC_REG_ALL 0x60
- #define AD5766_CMD_SW_FULL_RESET 0x70
- #define AD5766_CMD_READBACK_REG(x) (0x80 | ((x) & GENMASK(3, 0)))
- #define AD5766_CMD_DITHER_SIG_1 0x90
- #define AD5766_CMD_DITHER_SIG_2 0xA0
- #define AD5766_CMD_INV_DITHER 0xB0
- #define AD5766_CMD_DITHER_SCALE_1 0xC0
- #define AD5766_CMD_DITHER_SCALE_2 0xD0
- #define AD5766_FULL_RESET_CODE 0x1234
- enum ad5766_type {
- ID_AD5766,
- ID_AD5767,
- };
- enum ad5766_voltage_range {
- AD5766_VOLTAGE_RANGE_M20V_0V,
- AD5766_VOLTAGE_RANGE_M16V_to_0V,
- AD5766_VOLTAGE_RANGE_M10V_to_0V,
- AD5766_VOLTAGE_RANGE_M12V_to_14V,
- AD5766_VOLTAGE_RANGE_M16V_to_10V,
- AD5766_VOLTAGE_RANGE_M10V_to_6V,
- AD5766_VOLTAGE_RANGE_M5V_to_5V,
- AD5766_VOLTAGE_RANGE_M10V_to_10V,
- };
- /**
- * struct ad5766_chip_info - chip specific information
- * @num_channels: number of channels
- * @channels: channel specification
- */
- struct ad5766_chip_info {
- unsigned int num_channels;
- const struct iio_chan_spec *channels;
- };
- enum {
- AD5766_DITHER_ENABLE,
- AD5766_DITHER_INVERT,
- AD5766_DITHER_SOURCE,
- };
- /*
- * Dither signal can also be scaled.
- * Available dither scale strings corresponding to "dither_scale" field in
- * "struct ad5766_state".
- */
- static const char * const ad5766_dither_scales[] = {
- "1",
- "0.75",
- "0.5",
- "0.25",
- };
- /**
- * struct ad5766_state - driver instance specific data
- * @spi: SPI device
- * @lock: Lock used to restrict concurrent access to SPI device
- * @chip_info: Chip model specific constants
- * @gpio_reset: Reset GPIO, used to reset the device
- * @crt_range: Current selected output range
- * @dither_enable: Power enable bit for each channel dither block (for
- * example, D15 = DAC 15,D8 = DAC 8, and D0 = DAC 0)
- * 0 - Normal operation, 1 - Power down
- * @dither_invert: Inverts the dither signal applied to the selected DAC
- * outputs
- * @dither_source: Selects between 2 possible sources:
- * 1: N0, 2: N1
- * Two bits are used for each channel
- * @dither_scale: Two bits are used for each of the 16 channels:
- * 0: 1 SCALING, 1: 0.75 SCALING, 2: 0.5 SCALING,
- * 3: 0.25 SCALING.
- * @data: SPI transfer buffers
- */
- struct ad5766_state {
- struct spi_device *spi;
- struct mutex lock;
- const struct ad5766_chip_info *chip_info;
- struct gpio_desc *gpio_reset;
- enum ad5766_voltage_range crt_range;
- u16 dither_enable;
- u16 dither_invert;
- u32 dither_source;
- u32 dither_scale;
- union {
- u32 d32;
- u16 w16[2];
- u8 b8[4];
- } data[3] __aligned(IIO_DMA_MINALIGN);
- };
- struct ad5766_span_tbl {
- int min;
- int max;
- };
- static const struct ad5766_span_tbl ad5766_span_tbl[] = {
- [AD5766_VOLTAGE_RANGE_M20V_0V] = {-20, 0},
- [AD5766_VOLTAGE_RANGE_M16V_to_0V] = {-16, 0},
- [AD5766_VOLTAGE_RANGE_M10V_to_0V] = {-10, 0},
- [AD5766_VOLTAGE_RANGE_M12V_to_14V] = {-12, 14},
- [AD5766_VOLTAGE_RANGE_M16V_to_10V] = {-16, 10},
- [AD5766_VOLTAGE_RANGE_M10V_to_6V] = {-10, 6},
- [AD5766_VOLTAGE_RANGE_M5V_to_5V] = {-5, 5},
- [AD5766_VOLTAGE_RANGE_M10V_to_10V] = {-10, 10},
- };
- static int __ad5766_spi_read(struct ad5766_state *st, u8 dac, int *val)
- {
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = &st->data[0].d32,
- .bits_per_word = 8,
- .len = 3,
- .cs_change = 1,
- }, {
- .tx_buf = &st->data[1].d32,
- .rx_buf = &st->data[2].d32,
- .bits_per_word = 8,
- .len = 3,
- },
- };
- st->data[0].d32 = AD5766_CMD_READBACK_REG(dac);
- st->data[1].d32 = AD5766_CMD_NOP_MUX_OUT;
- ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
- if (ret)
- return ret;
- *val = st->data[2].w16[1];
- return ret;
- }
- static int __ad5766_spi_write(struct ad5766_state *st, u8 command, u16 data)
- {
- st->data[0].b8[0] = command;
- put_unaligned_be16(data, &st->data[0].b8[1]);
- return spi_write(st->spi, &st->data[0].b8[0], 3);
- }
- static int ad5766_read(struct iio_dev *indio_dev, u8 dac, int *val)
- {
- struct ad5766_state *st = iio_priv(indio_dev);
- int ret;
- mutex_lock(&st->lock);
- ret = __ad5766_spi_read(st, dac, val);
- mutex_unlock(&st->lock);
- return ret;
- }
- static int ad5766_write(struct iio_dev *indio_dev, u8 dac, u16 data)
- {
- struct ad5766_state *st = iio_priv(indio_dev);
- int ret;
- mutex_lock(&st->lock);
- ret = __ad5766_spi_write(st, AD5766_CMD_WR_DAC_REG(dac), data);
- mutex_unlock(&st->lock);
- return ret;
- }
- static int ad5766_reset(struct ad5766_state *st)
- {
- int ret;
- if (st->gpio_reset) {
- gpiod_set_value_cansleep(st->gpio_reset, 1);
- ndelay(100); /* t_reset >= 100ns */
- gpiod_set_value_cansleep(st->gpio_reset, 0);
- } else {
- ret = __ad5766_spi_write(st, AD5766_CMD_SW_FULL_RESET,
- AD5766_FULL_RESET_CODE);
- if (ret < 0)
- return ret;
- }
- /*
- * Minimum time between a reset and the subsequent successful write is
- * typically 25 ns
- */
- ndelay(25);
- return 0;
- }
- static int ad5766_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val,
- int *val2,
- long m)
- {
- struct ad5766_state *st = iio_priv(indio_dev);
- int ret;
- switch (m) {
- case IIO_CHAN_INFO_RAW:
- ret = ad5766_read(indio_dev, chan->address, val);
- if (ret)
- return ret;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_OFFSET:
- *val = ad5766_span_tbl[st->crt_range].min;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- *val = ad5766_span_tbl[st->crt_range].max -
- ad5766_span_tbl[st->crt_range].min;
- *val2 = st->chip_info->channels[0].scan_type.realbits;
- return IIO_VAL_FRACTIONAL_LOG2;
- default:
- return -EINVAL;
- }
- }
- static int ad5766_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long info)
- {
- switch (info) {
- case IIO_CHAN_INFO_RAW:
- {
- const int max_val = GENMASK(chan->scan_type.realbits - 1, 0);
- if (val > max_val || val < 0)
- return -EINVAL;
- val <<= chan->scan_type.shift;
- return ad5766_write(indio_dev, chan->address, val);
- }
- default:
- return -EINVAL;
- }
- }
- static const struct iio_info ad5766_info = {
- .read_raw = ad5766_read_raw,
- .write_raw = ad5766_write_raw,
- };
- static int ad5766_get_dither_source(struct iio_dev *dev,
- const struct iio_chan_spec *chan)
- {
- struct ad5766_state *st = iio_priv(dev);
- u32 source;
- source = st->dither_source & AD5766_DITHER_SOURCE_MASK(chan->channel);
- source = source >> (chan->channel * 2);
- source -= 1;
- return source;
- }
- static int ad5766_set_dither_source(struct iio_dev *dev,
- const struct iio_chan_spec *chan,
- unsigned int source)
- {
- struct ad5766_state *st = iio_priv(dev);
- uint16_t val;
- int ret;
- st->dither_source &= ~AD5766_DITHER_SOURCE_MASK(chan->channel);
- st->dither_source |= AD5766_DITHER_SOURCE(chan->channel, source);
- val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_source);
- ret = ad5766_write(dev, AD5766_CMD_DITHER_SIG_1, val);
- if (ret)
- return ret;
- val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_source);
- return ad5766_write(dev, AD5766_CMD_DITHER_SIG_2, val);
- }
- static int ad5766_get_dither_scale(struct iio_dev *dev,
- const struct iio_chan_spec *chan)
- {
- struct ad5766_state *st = iio_priv(dev);
- u32 scale;
- scale = st->dither_scale & AD5766_DITHER_SCALE_MASK(chan->channel);
- return (scale >> (chan->channel * 2));
- }
- static int ad5766_set_dither_scale(struct iio_dev *dev,
- const struct iio_chan_spec *chan,
- unsigned int scale)
- {
- int ret;
- struct ad5766_state *st = iio_priv(dev);
- uint16_t val;
- st->dither_scale &= ~AD5766_DITHER_SCALE_MASK(chan->channel);
- st->dither_scale |= AD5766_DITHER_SCALE(chan->channel, scale);
- val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_scale);
- ret = ad5766_write(dev, AD5766_CMD_DITHER_SCALE_1, val);
- if (ret)
- return ret;
- val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_scale);
- return ad5766_write(dev, AD5766_CMD_DITHER_SCALE_2, val);
- }
- static const struct iio_enum ad5766_dither_scale_enum = {
- .items = ad5766_dither_scales,
- .num_items = ARRAY_SIZE(ad5766_dither_scales),
- .set = ad5766_set_dither_scale,
- .get = ad5766_get_dither_scale,
- };
- static ssize_t ad5766_read_ext(struct iio_dev *indio_dev,
- uintptr_t private,
- const struct iio_chan_spec *chan,
- char *buf)
- {
- struct ad5766_state *st = iio_priv(indio_dev);
- switch (private) {
- case AD5766_DITHER_ENABLE:
- return sprintf(buf, "%u\n",
- !(st->dither_enable & BIT(chan->channel)));
- break;
- case AD5766_DITHER_INVERT:
- return sprintf(buf, "%u\n",
- !!(st->dither_invert & BIT(chan->channel)));
- break;
- case AD5766_DITHER_SOURCE:
- return sprintf(buf, "%d\n",
- ad5766_get_dither_source(indio_dev, chan));
- default:
- return -EINVAL;
- }
- }
- static ssize_t ad5766_write_ext(struct iio_dev *indio_dev,
- uintptr_t private,
- const struct iio_chan_spec *chan,
- const char *buf, size_t len)
- {
- struct ad5766_state *st = iio_priv(indio_dev);
- bool readin;
- int ret;
- ret = kstrtobool(buf, &readin);
- if (ret)
- return ret;
- switch (private) {
- case AD5766_DITHER_ENABLE:
- st->dither_enable &= ~AD5766_DITHER_ENABLE_MASK(chan->channel);
- st->dither_enable |= AD5766_DITHER_ENABLE(chan->channel,
- readin);
- ret = ad5766_write(indio_dev, AD5766_CMD_WR_PWR_DITHER,
- st->dither_enable);
- break;
- case AD5766_DITHER_INVERT:
- st->dither_invert &= ~AD5766_DITHER_INVERT_MASK(chan->channel);
- st->dither_invert |= AD5766_DITHER_INVERT(chan->channel,
- readin);
- ret = ad5766_write(indio_dev, AD5766_CMD_INV_DITHER,
- st->dither_invert);
- break;
- case AD5766_DITHER_SOURCE:
- ret = ad5766_set_dither_source(indio_dev, chan, readin);
- break;
- default:
- return -EINVAL;
- }
- return ret ? ret : len;
- }
- #define _AD5766_CHAN_EXT_INFO(_name, _what, _shared) { \
- .name = _name, \
- .read = ad5766_read_ext, \
- .write = ad5766_write_ext, \
- .private = _what, \
- .shared = _shared, \
- }
- static const struct iio_chan_spec_ext_info ad5766_ext_info[] = {
- _AD5766_CHAN_EXT_INFO("dither_enable", AD5766_DITHER_ENABLE,
- IIO_SEPARATE),
- _AD5766_CHAN_EXT_INFO("dither_invert", AD5766_DITHER_INVERT,
- IIO_SEPARATE),
- _AD5766_CHAN_EXT_INFO("dither_source", AD5766_DITHER_SOURCE,
- IIO_SEPARATE),
- IIO_ENUM("dither_scale", IIO_SEPARATE, &ad5766_dither_scale_enum),
- IIO_ENUM_AVAILABLE("dither_scale", IIO_SEPARATE,
- &ad5766_dither_scale_enum),
- {}
- };
- #define AD576x_CHANNEL(_chan, _bits) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .output = 1, \
- .channel = (_chan), \
- .address = (_chan), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | \
- BIT(IIO_CHAN_INFO_SCALE), \
- .scan_index = (_chan), \
- .scan_type = { \
- .sign = 'u', \
- .realbits = (_bits), \
- .storagebits = 16, \
- .shift = 16 - (_bits), \
- }, \
- .ext_info = ad5766_ext_info, \
- }
- #define DECLARE_AD576x_CHANNELS(_name, _bits) \
- const struct iio_chan_spec _name[] = { \
- AD576x_CHANNEL(0, (_bits)), \
- AD576x_CHANNEL(1, (_bits)), \
- AD576x_CHANNEL(2, (_bits)), \
- AD576x_CHANNEL(3, (_bits)), \
- AD576x_CHANNEL(4, (_bits)), \
- AD576x_CHANNEL(5, (_bits)), \
- AD576x_CHANNEL(6, (_bits)), \
- AD576x_CHANNEL(7, (_bits)), \
- AD576x_CHANNEL(8, (_bits)), \
- AD576x_CHANNEL(9, (_bits)), \
- AD576x_CHANNEL(10, (_bits)), \
- AD576x_CHANNEL(11, (_bits)), \
- AD576x_CHANNEL(12, (_bits)), \
- AD576x_CHANNEL(13, (_bits)), \
- AD576x_CHANNEL(14, (_bits)), \
- AD576x_CHANNEL(15, (_bits)), \
- }
- static DECLARE_AD576x_CHANNELS(ad5766_channels, 16);
- static DECLARE_AD576x_CHANNELS(ad5767_channels, 12);
- static const struct ad5766_chip_info ad5766_chip_infos[] = {
- [ID_AD5766] = {
- .num_channels = ARRAY_SIZE(ad5766_channels),
- .channels = ad5766_channels,
- },
- [ID_AD5767] = {
- .num_channels = ARRAY_SIZE(ad5767_channels),
- .channels = ad5767_channels,
- },
- };
- static int ad5766_get_output_range(struct ad5766_state *st)
- {
- int i, ret, min, max, tmp[2];
- ret = device_property_read_u32_array(&st->spi->dev,
- "output-range-microvolts",
- tmp, 2);
- if (ret)
- return ret;
- min = tmp[0] / 1000000;
- max = tmp[1] / 1000000;
- for (i = 0; i < ARRAY_SIZE(ad5766_span_tbl); i++) {
- if (ad5766_span_tbl[i].min != min ||
- ad5766_span_tbl[i].max != max)
- continue;
- st->crt_range = i;
- return 0;
- }
- return -EINVAL;
- }
- static int ad5766_default_setup(struct ad5766_state *st)
- {
- uint16_t val;
- int ret, i;
- /* Always issue a reset before writing to the span register. */
- ret = ad5766_reset(st);
- if (ret)
- return ret;
- ret = ad5766_get_output_range(st);
- if (ret)
- return ret;
- /* Dither power down */
- st->dither_enable = GENMASK(15, 0);
- ret = __ad5766_spi_write(st, AD5766_CMD_WR_PWR_DITHER,
- st->dither_enable);
- if (ret)
- return ret;
- st->dither_source = 0;
- for (i = 0; i < ARRAY_SIZE(ad5766_channels); i++)
- st->dither_source |= AD5766_DITHER_SOURCE(i, 0);
- val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_source);
- ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SIG_1, val);
- if (ret)
- return ret;
- val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_source);
- ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SIG_2, val);
- if (ret)
- return ret;
- st->dither_scale = 0;
- val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_scale);
- ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SCALE_1, val);
- if (ret)
- return ret;
- val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_scale);
- ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SCALE_2, val);
- if (ret)
- return ret;
- st->dither_invert = 0;
- ret = __ad5766_spi_write(st, AD5766_CMD_INV_DITHER, st->dither_invert);
- if (ret)
- return ret;
- return __ad5766_spi_write(st, AD5766_CMD_SPAN_REG, st->crt_range);
- }
- static irqreturn_t ad5766_trigger_handler(int irq, void *p)
- {
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
- struct ad5766_state *st = iio_priv(indio_dev);
- int ret, ch, i;
- u16 data[ARRAY_SIZE(ad5766_channels)];
- ret = iio_pop_from_buffer(buffer, data);
- if (ret)
- goto done;
- i = 0;
- mutex_lock(&st->lock);
- for_each_set_bit(ch, indio_dev->active_scan_mask,
- st->chip_info->num_channels - 1)
- __ad5766_spi_write(st, AD5766_CMD_WR_IN_REG(ch), data[i++]);
- __ad5766_spi_write(st, AD5766_CMD_SW_LDAC,
- *indio_dev->active_scan_mask);
- mutex_unlock(&st->lock);
- done:
- iio_trigger_notify_done(indio_dev->trig);
- return IRQ_HANDLED;
- }
- static int ad5766_probe(struct spi_device *spi)
- {
- enum ad5766_type type;
- struct iio_dev *indio_dev;
- struct ad5766_state *st;
- int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (!indio_dev)
- return -ENOMEM;
- st = iio_priv(indio_dev);
- mutex_init(&st->lock);
- st->spi = spi;
- type = spi_get_device_id(spi)->driver_data;
- st->chip_info = &ad5766_chip_infos[type];
- indio_dev->channels = st->chip_info->channels;
- indio_dev->num_channels = st->chip_info->num_channels;
- indio_dev->info = &ad5766_info;
- indio_dev->name = spi_get_device_id(spi)->name;
- indio_dev->modes = INDIO_DIRECT_MODE;
- st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(st->gpio_reset))
- return PTR_ERR(st->gpio_reset);
- ret = ad5766_default_setup(st);
- if (ret)
- return ret;
- /* Configure trigger buffer */
- ret = devm_iio_triggered_buffer_setup_ext(&spi->dev, indio_dev, NULL,
- ad5766_trigger_handler,
- IIO_BUFFER_DIRECTION_OUT,
- NULL,
- NULL);
- if (ret)
- return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
- }
- static const struct of_device_id ad5766_dt_match[] = {
- { .compatible = "adi,ad5766" },
- { .compatible = "adi,ad5767" },
- {}
- };
- MODULE_DEVICE_TABLE(of, ad5766_dt_match);
- static const struct spi_device_id ad5766_spi_ids[] = {
- { "ad5766", ID_AD5766 },
- { "ad5767", ID_AD5767 },
- {}
- };
- MODULE_DEVICE_TABLE(spi, ad5766_spi_ids);
- static struct spi_driver ad5766_driver = {
- .driver = {
- .name = "ad5766",
- .of_match_table = ad5766_dt_match,
- },
- .probe = ad5766_probe,
- .id_table = ad5766_spi_ids,
- };
- module_spi_driver(ad5766_driver);
- MODULE_AUTHOR("Denis-Gabriel Gheorghescu <[email protected]>");
- MODULE_DESCRIPTION("Analog Devices AD5766/AD5767 DACs");
- MODULE_LICENSE("GPL v2");
|