18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog 48c2ecf20Sopenharmony_ci * Converter driver. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2012 Analog Devices Inc. 78c2ecf20Sopenharmony_ci * Author: Lars-Peter Clausen <lars@metafoo.de> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 188c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 218c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/platform_data/ad5449.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define AD5449_MAX_CHANNELS 2 268c2ecf20Sopenharmony_ci#define AD5449_MAX_VREFS 2 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define AD5449_CMD_NOOP 0x0 298c2ecf20Sopenharmony_ci#define AD5449_CMD_LOAD_AND_UPDATE(x) (0x1 + (x) * 3) 308c2ecf20Sopenharmony_ci#define AD5449_CMD_READ(x) (0x2 + (x) * 3) 318c2ecf20Sopenharmony_ci#define AD5449_CMD_LOAD(x) (0x3 + (x) * 3) 328c2ecf20Sopenharmony_ci#define AD5449_CMD_CTRL 13 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define AD5449_CTRL_SDO_OFFSET 10 358c2ecf20Sopenharmony_ci#define AD5449_CTRL_DAISY_CHAIN BIT(9) 368c2ecf20Sopenharmony_ci#define AD5449_CTRL_HCLR_TO_MIDSCALE BIT(8) 378c2ecf20Sopenharmony_ci#define AD5449_CTRL_SAMPLE_RISING BIT(7) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * struct ad5449_chip_info - chip specific information 418c2ecf20Sopenharmony_ci * @channels: Channel specification 428c2ecf20Sopenharmony_ci * @num_channels: Number of channels 438c2ecf20Sopenharmony_ci * @has_ctrl: Chip has a control register 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct ad5449_chip_info { 468c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 478c2ecf20Sopenharmony_ci unsigned int num_channels; 488c2ecf20Sopenharmony_ci bool has_ctrl; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/** 528c2ecf20Sopenharmony_ci * struct ad5449 - driver instance specific data 538c2ecf20Sopenharmony_ci * @spi: the SPI device for this driver instance 548c2ecf20Sopenharmony_ci * @chip_info: chip model specific constants, available modes etc 558c2ecf20Sopenharmony_ci * @vref_reg: vref supply regulators 568c2ecf20Sopenharmony_ci * @has_sdo: whether the SDO line is connected 578c2ecf20Sopenharmony_ci * @dac_cache: Cache for the DAC values 588c2ecf20Sopenharmony_ci * @data: spi transfer buffers 598c2ecf20Sopenharmony_ci * @lock: lock to protect the data buffer during SPI ops 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistruct ad5449 { 628c2ecf20Sopenharmony_ci struct spi_device *spi; 638c2ecf20Sopenharmony_ci const struct ad5449_chip_info *chip_info; 648c2ecf20Sopenharmony_ci struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS]; 658c2ecf20Sopenharmony_ci struct mutex lock; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci bool has_sdo; 688c2ecf20Sopenharmony_ci uint16_t dac_cache[AD5449_MAX_CHANNELS]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* 718c2ecf20Sopenharmony_ci * DMA (thus cache coherency maintenance) requires the 728c2ecf20Sopenharmony_ci * transfer buffers to live in their own cache lines. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci __be16 data[2] ____cacheline_aligned; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cienum ad5449_type { 788c2ecf20Sopenharmony_ci ID_AD5426, 798c2ecf20Sopenharmony_ci ID_AD5429, 808c2ecf20Sopenharmony_ci ID_AD5432, 818c2ecf20Sopenharmony_ci ID_AD5439, 828c2ecf20Sopenharmony_ci ID_AD5443, 838c2ecf20Sopenharmony_ci ID_AD5449, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int ad5449_write(struct iio_dev *indio_dev, unsigned int addr, 878c2ecf20Sopenharmony_ci unsigned int val) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct ad5449 *st = iio_priv(indio_dev); 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 938c2ecf20Sopenharmony_ci st->data[0] = cpu_to_be16((addr << 12) | val); 948c2ecf20Sopenharmony_ci ret = spi_write(st->spi, st->data, 2); 958c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return ret; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int ad5449_read(struct iio_dev *indio_dev, unsigned int addr, 1018c2ecf20Sopenharmony_ci unsigned int *val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct ad5449 *st = iio_priv(indio_dev); 1048c2ecf20Sopenharmony_ci int ret; 1058c2ecf20Sopenharmony_ci struct spi_transfer t[] = { 1068c2ecf20Sopenharmony_ci { 1078c2ecf20Sopenharmony_ci .tx_buf = &st->data[0], 1088c2ecf20Sopenharmony_ci .len = 2, 1098c2ecf20Sopenharmony_ci .cs_change = 1, 1108c2ecf20Sopenharmony_ci }, { 1118c2ecf20Sopenharmony_ci .tx_buf = &st->data[1], 1128c2ecf20Sopenharmony_ci .rx_buf = &st->data[1], 1138c2ecf20Sopenharmony_ci .len = 2, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci }; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1188c2ecf20Sopenharmony_ci st->data[0] = cpu_to_be16(addr << 12); 1198c2ecf20Sopenharmony_ci st->data[1] = cpu_to_be16(AD5449_CMD_NOOP); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); 1228c2ecf20Sopenharmony_ci if (ret < 0) 1238c2ecf20Sopenharmony_ci goto out_unlock; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci *val = be16_to_cpu(st->data[1]); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciout_unlock: 1288c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int ad5449_read_raw(struct iio_dev *indio_dev, 1338c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int *val, int *val2, long info) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct ad5449 *st = iio_priv(indio_dev); 1368c2ecf20Sopenharmony_ci struct regulator_bulk_data *reg; 1378c2ecf20Sopenharmony_ci int scale_uv; 1388c2ecf20Sopenharmony_ci int ret; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci switch (info) { 1418c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1428c2ecf20Sopenharmony_ci if (st->has_sdo) { 1438c2ecf20Sopenharmony_ci ret = ad5449_read(indio_dev, 1448c2ecf20Sopenharmony_ci AD5449_CMD_READ(chan->address), val); 1458c2ecf20Sopenharmony_ci if (ret) 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci *val &= 0xfff; 1488c2ecf20Sopenharmony_ci } else { 1498c2ecf20Sopenharmony_ci *val = st->dac_cache[chan->address]; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return IIO_VAL_INT; 1538c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1548c2ecf20Sopenharmony_ci reg = &st->vref_reg[chan->channel]; 1558c2ecf20Sopenharmony_ci scale_uv = regulator_get_voltage(reg->consumer); 1568c2ecf20Sopenharmony_ci if (scale_uv < 0) 1578c2ecf20Sopenharmony_ci return scale_uv; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci *val = scale_uv / 1000; 1608c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 1638c2ecf20Sopenharmony_ci default: 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int ad5449_write_raw(struct iio_dev *indio_dev, 1718c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int val, int val2, long info) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct ad5449 *st = iio_priv(indio_dev); 1748c2ecf20Sopenharmony_ci int ret; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci switch (info) { 1778c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1788c2ecf20Sopenharmony_ci if (val < 0 || val >= (1 << chan->scan_type.realbits)) 1798c2ecf20Sopenharmony_ci return -EINVAL; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = ad5449_write(indio_dev, 1828c2ecf20Sopenharmony_ci AD5449_CMD_LOAD_AND_UPDATE(chan->address), 1838c2ecf20Sopenharmony_ci val << chan->scan_type.shift); 1848c2ecf20Sopenharmony_ci if (ret == 0) 1858c2ecf20Sopenharmony_ci st->dac_cache[chan->address] = val; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci default: 1888c2ecf20Sopenharmony_ci ret = -EINVAL; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return ret; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct iio_info ad5449_info = { 1958c2ecf20Sopenharmony_ci .read_raw = ad5449_read_raw, 1968c2ecf20Sopenharmony_ci .write_raw = ad5449_write_raw, 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#define AD5449_CHANNEL(chan, bits) { \ 2008c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 2018c2ecf20Sopenharmony_ci .indexed = 1, \ 2028c2ecf20Sopenharmony_ci .output = 1, \ 2038c2ecf20Sopenharmony_ci .channel = (chan), \ 2048c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 2058c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), \ 2068c2ecf20Sopenharmony_ci .address = (chan), \ 2078c2ecf20Sopenharmony_ci .scan_type = { \ 2088c2ecf20Sopenharmony_ci .sign = 'u', \ 2098c2ecf20Sopenharmony_ci .realbits = (bits), \ 2108c2ecf20Sopenharmony_ci .storagebits = 16, \ 2118c2ecf20Sopenharmony_ci .shift = 12 - (bits), \ 2128c2ecf20Sopenharmony_ci }, \ 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define DECLARE_AD5449_CHANNELS(name, bits) \ 2168c2ecf20Sopenharmony_ciconst struct iio_chan_spec name[] = { \ 2178c2ecf20Sopenharmony_ci AD5449_CHANNEL(0, bits), \ 2188c2ecf20Sopenharmony_ci AD5449_CHANNEL(1, bits), \ 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic DECLARE_AD5449_CHANNELS(ad5429_channels, 8); 2228c2ecf20Sopenharmony_cistatic DECLARE_AD5449_CHANNELS(ad5439_channels, 10); 2238c2ecf20Sopenharmony_cistatic DECLARE_AD5449_CHANNELS(ad5449_channels, 12); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const struct ad5449_chip_info ad5449_chip_info[] = { 2268c2ecf20Sopenharmony_ci [ID_AD5426] = { 2278c2ecf20Sopenharmony_ci .channels = ad5429_channels, 2288c2ecf20Sopenharmony_ci .num_channels = 1, 2298c2ecf20Sopenharmony_ci .has_ctrl = false, 2308c2ecf20Sopenharmony_ci }, 2318c2ecf20Sopenharmony_ci [ID_AD5429] = { 2328c2ecf20Sopenharmony_ci .channels = ad5429_channels, 2338c2ecf20Sopenharmony_ci .num_channels = 2, 2348c2ecf20Sopenharmony_ci .has_ctrl = true, 2358c2ecf20Sopenharmony_ci }, 2368c2ecf20Sopenharmony_ci [ID_AD5432] = { 2378c2ecf20Sopenharmony_ci .channels = ad5439_channels, 2388c2ecf20Sopenharmony_ci .num_channels = 1, 2398c2ecf20Sopenharmony_ci .has_ctrl = false, 2408c2ecf20Sopenharmony_ci }, 2418c2ecf20Sopenharmony_ci [ID_AD5439] = { 2428c2ecf20Sopenharmony_ci .channels = ad5439_channels, 2438c2ecf20Sopenharmony_ci .num_channels = 2, 2448c2ecf20Sopenharmony_ci .has_ctrl = true, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [ID_AD5443] = { 2478c2ecf20Sopenharmony_ci .channels = ad5449_channels, 2488c2ecf20Sopenharmony_ci .num_channels = 1, 2498c2ecf20Sopenharmony_ci .has_ctrl = false, 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci [ID_AD5449] = { 2528c2ecf20Sopenharmony_ci .channels = ad5449_channels, 2538c2ecf20Sopenharmony_ci .num_channels = 2, 2548c2ecf20Sopenharmony_ci .has_ctrl = true, 2558c2ecf20Sopenharmony_ci }, 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic const char *ad5449_vref_name(struct ad5449 *st, int n) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci if (st->chip_info->num_channels == 1) 2618c2ecf20Sopenharmony_ci return "VREF"; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (n == 0) 2648c2ecf20Sopenharmony_ci return "VREFA"; 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci return "VREFB"; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int ad5449_spi_probe(struct spi_device *spi) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct ad5449_platform_data *pdata = spi->dev.platform_data; 2728c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 2738c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 2748c2ecf20Sopenharmony_ci struct ad5449 *st; 2758c2ecf20Sopenharmony_ci unsigned int i; 2768c2ecf20Sopenharmony_ci int ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 2798c2ecf20Sopenharmony_ci if (indio_dev == NULL) 2808c2ecf20Sopenharmony_ci return -ENOMEM; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 2838c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci st->chip_info = &ad5449_chip_info[id->driver_data]; 2868c2ecf20Sopenharmony_ci st->spi = spi; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci for (i = 0; i < st->chip_info->num_channels; ++i) 2898c2ecf20Sopenharmony_ci st->vref_reg[i].supply = ad5449_vref_name(st, i); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels, 2928c2ecf20Sopenharmony_ci st->vref_reg); 2938c2ecf20Sopenharmony_ci if (ret) 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg); 2978c2ecf20Sopenharmony_ci if (ret) 2988c2ecf20Sopenharmony_ci return ret; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci indio_dev->name = id->name; 3018c2ecf20Sopenharmony_ci indio_dev->info = &ad5449_info; 3028c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 3038c2ecf20Sopenharmony_ci indio_dev->channels = st->chip_info->channels; 3048c2ecf20Sopenharmony_ci indio_dev->num_channels = st->chip_info->num_channels; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci mutex_init(&st->lock); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (st->chip_info->has_ctrl) { 3098c2ecf20Sopenharmony_ci unsigned int ctrl = 0x00; 3108c2ecf20Sopenharmony_ci if (pdata) { 3118c2ecf20Sopenharmony_ci if (pdata->hardware_clear_to_midscale) 3128c2ecf20Sopenharmony_ci ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE; 3138c2ecf20Sopenharmony_ci ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET; 3148c2ecf20Sopenharmony_ci st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED; 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci st->has_sdo = true; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto error_disable_reg; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cierror_disable_reg: 3288c2ecf20Sopenharmony_ci regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int ad5449_spi_remove(struct spi_device *spi) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 3368c2ecf20Sopenharmony_ci struct ad5449 *st = iio_priv(indio_dev); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5449_spi_ids[] = { 3468c2ecf20Sopenharmony_ci { "ad5415", ID_AD5449 }, 3478c2ecf20Sopenharmony_ci { "ad5426", ID_AD5426 }, 3488c2ecf20Sopenharmony_ci { "ad5429", ID_AD5429 }, 3498c2ecf20Sopenharmony_ci { "ad5432", ID_AD5432 }, 3508c2ecf20Sopenharmony_ci { "ad5439", ID_AD5439 }, 3518c2ecf20Sopenharmony_ci { "ad5443", ID_AD5443 }, 3528c2ecf20Sopenharmony_ci { "ad5449", ID_AD5449 }, 3538c2ecf20Sopenharmony_ci {} 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5449_spi_ids); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic struct spi_driver ad5449_spi_driver = { 3588c2ecf20Sopenharmony_ci .driver = { 3598c2ecf20Sopenharmony_ci .name = "ad5449", 3608c2ecf20Sopenharmony_ci }, 3618c2ecf20Sopenharmony_ci .probe = ad5449_spi_probe, 3628c2ecf20Sopenharmony_ci .remove = ad5449_spi_remove, 3638c2ecf20Sopenharmony_ci .id_table = ad5449_spi_ids, 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_cimodule_spi_driver(ad5449_spi_driver); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 3688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5449 and similar DACs"); 3698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 370