180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2dbdc025bSLars-Peter Clausen /* 3dbdc025bSLars-Peter Clausen * AD5446 SPI DAC driver 4dbdc025bSLars-Peter Clausen * 5dbdc025bSLars-Peter Clausen * Copyright 2010 Analog Devices Inc. 6dbdc025bSLars-Peter Clausen */ 7dbdc025bSLars-Peter Clausen 8dbdc025bSLars-Peter Clausen #include <linux/interrupt.h> 9dbdc025bSLars-Peter Clausen #include <linux/workqueue.h> 10dbdc025bSLars-Peter Clausen #include <linux/device.h> 11dbdc025bSLars-Peter Clausen #include <linux/kernel.h> 12dbdc025bSLars-Peter Clausen #include <linux/slab.h> 13dbdc025bSLars-Peter Clausen #include <linux/sysfs.h> 14dbdc025bSLars-Peter Clausen #include <linux/list.h> 15dbdc025bSLars-Peter Clausen #include <linux/spi/spi.h> 163ec36a2cSJean-Francois Dagenais #include <linux/i2c.h> 17dbdc025bSLars-Peter Clausen #include <linux/regulator/consumer.h> 18dbdc025bSLars-Peter Clausen #include <linux/err.h> 19dbdc025bSLars-Peter Clausen #include <linux/module.h> 20dbdc025bSLars-Peter Clausen 21dbdc025bSLars-Peter Clausen #include <linux/iio/iio.h> 22dbdc025bSLars-Peter Clausen #include <linux/iio/sysfs.h> 23dbdc025bSLars-Peter Clausen 242e15c903SJean-Francois Dagenais #define MODE_PWRDWN_1k 0x1 252e15c903SJean-Francois Dagenais #define MODE_PWRDWN_100k 0x2 262e15c903SJean-Francois Dagenais #define MODE_PWRDWN_TRISTATE 0x3 272e15c903SJean-Francois Dagenais 282e15c903SJean-Francois Dagenais /** 292e15c903SJean-Francois Dagenais * struct ad5446_state - driver instance specific data 302e15c903SJean-Francois Dagenais * @spi: spi_device 312e15c903SJean-Francois Dagenais * @chip_info: chip model specific constants, available modes etc 322e15c903SJean-Francois Dagenais * @reg: supply regulator 332e15c903SJean-Francois Dagenais * @vref_mv: actual reference voltage used 342e15c903SJean-Francois Dagenais */ 352e15c903SJean-Francois Dagenais 362e15c903SJean-Francois Dagenais struct ad5446_state { 372e15c903SJean-Francois Dagenais struct device *dev; 382e15c903SJean-Francois Dagenais const struct ad5446_chip_info *chip_info; 392e15c903SJean-Francois Dagenais struct regulator *reg; 402e15c903SJean-Francois Dagenais unsigned short vref_mv; 412e15c903SJean-Francois Dagenais unsigned cached_val; 422e15c903SJean-Francois Dagenais unsigned pwr_down_mode; 432e15c903SJean-Francois Dagenais unsigned pwr_down; 442e15c903SJean-Francois Dagenais }; 452e15c903SJean-Francois Dagenais 462e15c903SJean-Francois Dagenais /** 472e15c903SJean-Francois Dagenais * struct ad5446_chip_info - chip specific information 482e15c903SJean-Francois Dagenais * @channel: channel spec for the DAC 492e15c903SJean-Francois Dagenais * @int_vref_mv: AD5620/40/60: the internal reference voltage 502e15c903SJean-Francois Dagenais * @write: chip specific helper function to write to the register 512e15c903SJean-Francois Dagenais */ 522e15c903SJean-Francois Dagenais 532e15c903SJean-Francois Dagenais struct ad5446_chip_info { 542e15c903SJean-Francois Dagenais struct iio_chan_spec channel; 552e15c903SJean-Francois Dagenais u16 int_vref_mv; 562e15c903SJean-Francois Dagenais int (*write)(struct ad5446_state *st, unsigned val); 572e15c903SJean-Francois Dagenais }; 58dbdc025bSLars-Peter Clausen 59dbdc025bSLars-Peter Clausen static const char * const ad5446_powerdown_modes[] = { 60dbdc025bSLars-Peter Clausen "1kohm_to_gnd", "100kohm_to_gnd", "three_state" 61dbdc025bSLars-Peter Clausen }; 62dbdc025bSLars-Peter Clausen 63dbdc025bSLars-Peter Clausen static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev, 64dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, unsigned int mode) 65dbdc025bSLars-Peter Clausen { 66dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 67dbdc025bSLars-Peter Clausen 68dbdc025bSLars-Peter Clausen st->pwr_down_mode = mode + 1; 69dbdc025bSLars-Peter Clausen 70dbdc025bSLars-Peter Clausen return 0; 71dbdc025bSLars-Peter Clausen } 72dbdc025bSLars-Peter Clausen 73dbdc025bSLars-Peter Clausen static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev, 74dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan) 75dbdc025bSLars-Peter Clausen { 76dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 77dbdc025bSLars-Peter Clausen 78dbdc025bSLars-Peter Clausen return st->pwr_down_mode - 1; 79dbdc025bSLars-Peter Clausen } 80dbdc025bSLars-Peter Clausen 81dbdc025bSLars-Peter Clausen static const struct iio_enum ad5446_powerdown_mode_enum = { 82dbdc025bSLars-Peter Clausen .items = ad5446_powerdown_modes, 83dbdc025bSLars-Peter Clausen .num_items = ARRAY_SIZE(ad5446_powerdown_modes), 84dbdc025bSLars-Peter Clausen .get = ad5446_get_powerdown_mode, 85dbdc025bSLars-Peter Clausen .set = ad5446_set_powerdown_mode, 86dbdc025bSLars-Peter Clausen }; 87dbdc025bSLars-Peter Clausen 88dbdc025bSLars-Peter Clausen static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, 89dbdc025bSLars-Peter Clausen uintptr_t private, 90dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, 91dbdc025bSLars-Peter Clausen char *buf) 92dbdc025bSLars-Peter Clausen { 93dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 94dbdc025bSLars-Peter Clausen 95dbdc025bSLars-Peter Clausen return sprintf(buf, "%d\n", st->pwr_down); 96dbdc025bSLars-Peter Clausen } 97dbdc025bSLars-Peter Clausen 98dbdc025bSLars-Peter Clausen static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, 99dbdc025bSLars-Peter Clausen uintptr_t private, 100dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, 101dbdc025bSLars-Peter Clausen const char *buf, size_t len) 102dbdc025bSLars-Peter Clausen { 103dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 104dbdc025bSLars-Peter Clausen unsigned int shift; 105dbdc025bSLars-Peter Clausen unsigned int val; 106dbdc025bSLars-Peter Clausen bool powerdown; 107dbdc025bSLars-Peter Clausen int ret; 108dbdc025bSLars-Peter Clausen 109dbdc025bSLars-Peter Clausen ret = strtobool(buf, &powerdown); 110dbdc025bSLars-Peter Clausen if (ret) 111dbdc025bSLars-Peter Clausen return ret; 112dbdc025bSLars-Peter Clausen 113dbdc025bSLars-Peter Clausen mutex_lock(&indio_dev->mlock); 114dbdc025bSLars-Peter Clausen st->pwr_down = powerdown; 115dbdc025bSLars-Peter Clausen 116dbdc025bSLars-Peter Clausen if (st->pwr_down) { 117dbdc025bSLars-Peter Clausen shift = chan->scan_type.realbits + chan->scan_type.shift; 118dbdc025bSLars-Peter Clausen val = st->pwr_down_mode << shift; 119dbdc025bSLars-Peter Clausen } else { 120dbdc025bSLars-Peter Clausen val = st->cached_val; 121dbdc025bSLars-Peter Clausen } 122dbdc025bSLars-Peter Clausen 123dbdc025bSLars-Peter Clausen ret = st->chip_info->write(st, val); 124dbdc025bSLars-Peter Clausen mutex_unlock(&indio_dev->mlock); 125dbdc025bSLars-Peter Clausen 126dbdc025bSLars-Peter Clausen return ret ? ret : len; 127dbdc025bSLars-Peter Clausen } 128dbdc025bSLars-Peter Clausen 1293ec36a2cSJean-Francois Dagenais static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { 130dbdc025bSLars-Peter Clausen { 131dbdc025bSLars-Peter Clausen .name = "powerdown", 132dbdc025bSLars-Peter Clausen .read = ad5446_read_dac_powerdown, 133dbdc025bSLars-Peter Clausen .write = ad5446_write_dac_powerdown, 1343704432fSJonathan Cameron .shared = IIO_SEPARATE, 135dbdc025bSLars-Peter Clausen }, 1363704432fSJonathan Cameron IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), 137dbdc025bSLars-Peter Clausen IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum), 138dbdc025bSLars-Peter Clausen { }, 139dbdc025bSLars-Peter Clausen }; 140dbdc025bSLars-Peter Clausen 141e3019c21SJonathan Cameron #define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ 142dbdc025bSLars-Peter Clausen .type = IIO_VOLTAGE, \ 143dbdc025bSLars-Peter Clausen .indexed = 1, \ 144dbdc025bSLars-Peter Clausen .output = 1, \ 145dbdc025bSLars-Peter Clausen .channel = 0, \ 1462f6a4a44SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 1472f6a4a44SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 148e3019c21SJonathan Cameron .scan_type = { \ 149e3019c21SJonathan Cameron .sign = 'u', \ 150e3019c21SJonathan Cameron .realbits = (bits), \ 151e3019c21SJonathan Cameron .storagebits = (storage), \ 152e3019c21SJonathan Cameron .shift = (_shift), \ 153e3019c21SJonathan Cameron }, \ 154dbdc025bSLars-Peter Clausen .ext_info = (ext), \ 155dbdc025bSLars-Peter Clausen } 156dbdc025bSLars-Peter Clausen 157dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL(bits, storage, shift) \ 158dbdc025bSLars-Peter Clausen _AD5446_CHANNEL(bits, storage, shift, NULL) 159dbdc025bSLars-Peter Clausen 160dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ 1613ec36a2cSJean-Francois Dagenais _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) 162dbdc025bSLars-Peter Clausen 1633ec36a2cSJean-Francois Dagenais static int ad5446_read_raw(struct iio_dev *indio_dev, 1643ec36a2cSJean-Francois Dagenais struct iio_chan_spec const *chan, 1653ec36a2cSJean-Francois Dagenais int *val, 1663ec36a2cSJean-Francois Dagenais int *val2, 1673ec36a2cSJean-Francois Dagenais long m) 1683ec36a2cSJean-Francois Dagenais { 1693ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 1703ec36a2cSJean-Francois Dagenais 1713ec36a2cSJean-Francois Dagenais switch (m) { 1723ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_RAW: 1733ec36a2cSJean-Francois Dagenais *val = st->cached_val; 1743ec36a2cSJean-Francois Dagenais return IIO_VAL_INT; 1753ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_SCALE: 1760a99b601SLars-Peter Clausen *val = st->vref_mv; 1770a99b601SLars-Peter Clausen *val2 = chan->scan_type.realbits; 1780a99b601SLars-Peter Clausen return IIO_VAL_FRACTIONAL_LOG2; 1793ec36a2cSJean-Francois Dagenais } 1803ec36a2cSJean-Francois Dagenais return -EINVAL; 1813ec36a2cSJean-Francois Dagenais } 1823ec36a2cSJean-Francois Dagenais 1833ec36a2cSJean-Francois Dagenais static int ad5446_write_raw(struct iio_dev *indio_dev, 1843ec36a2cSJean-Francois Dagenais struct iio_chan_spec const *chan, 1853ec36a2cSJean-Francois Dagenais int val, 1863ec36a2cSJean-Francois Dagenais int val2, 1873ec36a2cSJean-Francois Dagenais long mask) 1883ec36a2cSJean-Francois Dagenais { 1893ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 1903ec36a2cSJean-Francois Dagenais int ret = 0; 1913ec36a2cSJean-Francois Dagenais 1923ec36a2cSJean-Francois Dagenais switch (mask) { 1933ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_RAW: 1943ec36a2cSJean-Francois Dagenais if (val >= (1 << chan->scan_type.realbits) || val < 0) 1953ec36a2cSJean-Francois Dagenais return -EINVAL; 1963ec36a2cSJean-Francois Dagenais 1973ec36a2cSJean-Francois Dagenais val <<= chan->scan_type.shift; 1983ec36a2cSJean-Francois Dagenais mutex_lock(&indio_dev->mlock); 1993ec36a2cSJean-Francois Dagenais st->cached_val = val; 2003ec36a2cSJean-Francois Dagenais if (!st->pwr_down) 2013ec36a2cSJean-Francois Dagenais ret = st->chip_info->write(st, val); 2023ec36a2cSJean-Francois Dagenais mutex_unlock(&indio_dev->mlock); 2033ec36a2cSJean-Francois Dagenais break; 2043ec36a2cSJean-Francois Dagenais default: 2053ec36a2cSJean-Francois Dagenais ret = -EINVAL; 2063ec36a2cSJean-Francois Dagenais } 2073ec36a2cSJean-Francois Dagenais 2083ec36a2cSJean-Francois Dagenais return ret; 2093ec36a2cSJean-Francois Dagenais } 2103ec36a2cSJean-Francois Dagenais 2113ec36a2cSJean-Francois Dagenais static const struct iio_info ad5446_info = { 2123ec36a2cSJean-Francois Dagenais .read_raw = ad5446_read_raw, 2133ec36a2cSJean-Francois Dagenais .write_raw = ad5446_write_raw, 2143ec36a2cSJean-Francois Dagenais }; 2153ec36a2cSJean-Francois Dagenais 216fc52692cSGreg Kroah-Hartman static int ad5446_probe(struct device *dev, const char *name, 2173ec36a2cSJean-Francois Dagenais const struct ad5446_chip_info *chip_info) 2183ec36a2cSJean-Francois Dagenais { 2193ec36a2cSJean-Francois Dagenais struct ad5446_state *st; 2203ec36a2cSJean-Francois Dagenais struct iio_dev *indio_dev; 2213ec36a2cSJean-Francois Dagenais struct regulator *reg; 2223ec36a2cSJean-Francois Dagenais int ret, voltage_uv = 0; 2233ec36a2cSJean-Francois Dagenais 224ba727295SSachin Kamat reg = devm_regulator_get(dev, "vcc"); 2253ec36a2cSJean-Francois Dagenais if (!IS_ERR(reg)) { 2263ec36a2cSJean-Francois Dagenais ret = regulator_enable(reg); 2273ec36a2cSJean-Francois Dagenais if (ret) 228ba727295SSachin Kamat return ret; 2293ec36a2cSJean-Francois Dagenais 23013e57ee2SAxel Lin ret = regulator_get_voltage(reg); 23113e57ee2SAxel Lin if (ret < 0) 23213e57ee2SAxel Lin goto error_disable_reg; 23313e57ee2SAxel Lin 23413e57ee2SAxel Lin voltage_uv = ret; 2353ec36a2cSJean-Francois Dagenais } 2363ec36a2cSJean-Francois Dagenais 237ba727295SSachin Kamat indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 2383ec36a2cSJean-Francois Dagenais if (indio_dev == NULL) { 2393ec36a2cSJean-Francois Dagenais ret = -ENOMEM; 2403ec36a2cSJean-Francois Dagenais goto error_disable_reg; 2413ec36a2cSJean-Francois Dagenais } 2423ec36a2cSJean-Francois Dagenais st = iio_priv(indio_dev); 2433ec36a2cSJean-Francois Dagenais st->chip_info = chip_info; 2443ec36a2cSJean-Francois Dagenais 2453ec36a2cSJean-Francois Dagenais dev_set_drvdata(dev, indio_dev); 2463ec36a2cSJean-Francois Dagenais st->reg = reg; 2473ec36a2cSJean-Francois Dagenais st->dev = dev; 2483ec36a2cSJean-Francois Dagenais 2493ec36a2cSJean-Francois Dagenais /* Establish that the iio_dev is a child of the device */ 2503ec36a2cSJean-Francois Dagenais indio_dev->dev.parent = dev; 2513ec36a2cSJean-Francois Dagenais indio_dev->name = name; 2523ec36a2cSJean-Francois Dagenais indio_dev->info = &ad5446_info; 2533ec36a2cSJean-Francois Dagenais indio_dev->modes = INDIO_DIRECT_MODE; 2543ec36a2cSJean-Francois Dagenais indio_dev->channels = &st->chip_info->channel; 2553ec36a2cSJean-Francois Dagenais indio_dev->num_channels = 1; 2563ec36a2cSJean-Francois Dagenais 2573ec36a2cSJean-Francois Dagenais st->pwr_down_mode = MODE_PWRDWN_1k; 2583ec36a2cSJean-Francois Dagenais 2593ec36a2cSJean-Francois Dagenais if (st->chip_info->int_vref_mv) 2603ec36a2cSJean-Francois Dagenais st->vref_mv = st->chip_info->int_vref_mv; 2613ec36a2cSJean-Francois Dagenais else if (voltage_uv) 2623ec36a2cSJean-Francois Dagenais st->vref_mv = voltage_uv / 1000; 2633ec36a2cSJean-Francois Dagenais else 2643ec36a2cSJean-Francois Dagenais dev_warn(dev, "reference voltage unspecified\n"); 2653ec36a2cSJean-Francois Dagenais 2663ec36a2cSJean-Francois Dagenais ret = iio_device_register(indio_dev); 2673ec36a2cSJean-Francois Dagenais if (ret) 268ba727295SSachin Kamat goto error_disable_reg; 2693ec36a2cSJean-Francois Dagenais 2703ec36a2cSJean-Francois Dagenais return 0; 2713ec36a2cSJean-Francois Dagenais 2723ec36a2cSJean-Francois Dagenais error_disable_reg: 2733ec36a2cSJean-Francois Dagenais if (!IS_ERR(reg)) 2743ec36a2cSJean-Francois Dagenais regulator_disable(reg); 2753ec36a2cSJean-Francois Dagenais return ret; 2763ec36a2cSJean-Francois Dagenais } 2773ec36a2cSJean-Francois Dagenais 2783ec36a2cSJean-Francois Dagenais static int ad5446_remove(struct device *dev) 2793ec36a2cSJean-Francois Dagenais { 2803ec36a2cSJean-Francois Dagenais struct iio_dev *indio_dev = dev_get_drvdata(dev); 2813ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 2823ec36a2cSJean-Francois Dagenais 2833ec36a2cSJean-Francois Dagenais iio_device_unregister(indio_dev); 284ba727295SSachin Kamat if (!IS_ERR(st->reg)) 2853ec36a2cSJean-Francois Dagenais regulator_disable(st->reg); 2863ec36a2cSJean-Francois Dagenais 2873ec36a2cSJean-Francois Dagenais return 0; 2883ec36a2cSJean-Francois Dagenais } 2893ec36a2cSJean-Francois Dagenais 2903ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_SPI_MASTER) 2913ec36a2cSJean-Francois Dagenais 2923ec36a2cSJean-Francois Dagenais static int ad5446_write(struct ad5446_state *st, unsigned val) 2933ec36a2cSJean-Francois Dagenais { 2943ec36a2cSJean-Francois Dagenais struct spi_device *spi = to_spi_device(st->dev); 2953ec36a2cSJean-Francois Dagenais __be16 data = cpu_to_be16(val); 2963ec36a2cSJean-Francois Dagenais 2973ec36a2cSJean-Francois Dagenais return spi_write(spi, &data, sizeof(data)); 2983ec36a2cSJean-Francois Dagenais } 2993ec36a2cSJean-Francois Dagenais 3003ec36a2cSJean-Francois Dagenais static int ad5660_write(struct ad5446_state *st, unsigned val) 3013ec36a2cSJean-Francois Dagenais { 3023ec36a2cSJean-Francois Dagenais struct spi_device *spi = to_spi_device(st->dev); 3033ec36a2cSJean-Francois Dagenais uint8_t data[3]; 3043ec36a2cSJean-Francois Dagenais 3053ec36a2cSJean-Francois Dagenais data[0] = (val >> 16) & 0xFF; 3063ec36a2cSJean-Francois Dagenais data[1] = (val >> 8) & 0xFF; 3073ec36a2cSJean-Francois Dagenais data[2] = val & 0xFF; 3083ec36a2cSJean-Francois Dagenais 3093ec36a2cSJean-Francois Dagenais return spi_write(spi, data, sizeof(data)); 3103ec36a2cSJean-Francois Dagenais } 3113ec36a2cSJean-Francois Dagenais 3123ec36a2cSJean-Francois Dagenais /** 3133ec36a2cSJean-Francois Dagenais * ad5446_supported_spi_device_ids: 3143ec36a2cSJean-Francois Dagenais * The AD5620/40/60 parts are available in different fixed internal reference 3153ec36a2cSJean-Francois Dagenais * voltage options. The actual part numbers may look differently 3163ec36a2cSJean-Francois Dagenais * (and a bit cryptic), however this style is used to make clear which 3173ec36a2cSJean-Francois Dagenais * parts are supported here. 3183ec36a2cSJean-Francois Dagenais */ 3193ec36a2cSJean-Francois Dagenais enum ad5446_supported_spi_device_ids { 3202fafbce2SLars-Peter Clausen ID_AD5300, 3212fafbce2SLars-Peter Clausen ID_AD5310, 3222fafbce2SLars-Peter Clausen ID_AD5320, 3233ec36a2cSJean-Francois Dagenais ID_AD5444, 3243ec36a2cSJean-Francois Dagenais ID_AD5446, 3253ec36a2cSJean-Francois Dagenais ID_AD5450, 3263ec36a2cSJean-Francois Dagenais ID_AD5451, 3273ec36a2cSJean-Francois Dagenais ID_AD5541A, 3283ec36a2cSJean-Francois Dagenais ID_AD5512A, 3293ec36a2cSJean-Francois Dagenais ID_AD5553, 3303ec36a2cSJean-Francois Dagenais ID_AD5601, 3313ec36a2cSJean-Francois Dagenais ID_AD5611, 3323ec36a2cSJean-Francois Dagenais ID_AD5621, 3334fa2a9e4SAida Mynzhasova ID_AD5641, 3343ec36a2cSJean-Francois Dagenais ID_AD5620_2500, 3353ec36a2cSJean-Francois Dagenais ID_AD5620_1250, 3363ec36a2cSJean-Francois Dagenais ID_AD5640_2500, 3373ec36a2cSJean-Francois Dagenais ID_AD5640_1250, 3383ec36a2cSJean-Francois Dagenais ID_AD5660_2500, 3393ec36a2cSJean-Francois Dagenais ID_AD5660_1250, 3403ec36a2cSJean-Francois Dagenais ID_AD5662, 3413ec36a2cSJean-Francois Dagenais }; 3423ec36a2cSJean-Francois Dagenais 3433ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_spi_chip_info[] = { 3442fafbce2SLars-Peter Clausen [ID_AD5300] = { 3452fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 3462fafbce2SLars-Peter Clausen .write = ad5446_write, 3472fafbce2SLars-Peter Clausen }, 3482fafbce2SLars-Peter Clausen [ID_AD5310] = { 3492fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 3502fafbce2SLars-Peter Clausen .write = ad5446_write, 3512fafbce2SLars-Peter Clausen }, 3522fafbce2SLars-Peter Clausen [ID_AD5320] = { 3532fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 3542fafbce2SLars-Peter Clausen .write = ad5446_write, 3552fafbce2SLars-Peter Clausen }, 356dbdc025bSLars-Peter Clausen [ID_AD5444] = { 357dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(12, 16, 2), 358dbdc025bSLars-Peter Clausen .write = ad5446_write, 359dbdc025bSLars-Peter Clausen }, 360dbdc025bSLars-Peter Clausen [ID_AD5446] = { 361dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(14, 16, 0), 362dbdc025bSLars-Peter Clausen .write = ad5446_write, 363dbdc025bSLars-Peter Clausen }, 364779c0c46SLars-Peter Clausen [ID_AD5450] = { 365779c0c46SLars-Peter Clausen .channel = AD5446_CHANNEL(8, 16, 6), 366779c0c46SLars-Peter Clausen .write = ad5446_write, 367779c0c46SLars-Peter Clausen }, 368779c0c46SLars-Peter Clausen [ID_AD5451] = { 369779c0c46SLars-Peter Clausen .channel = AD5446_CHANNEL(10, 16, 4), 370779c0c46SLars-Peter Clausen .write = ad5446_write, 371779c0c46SLars-Peter Clausen }, 372dbdc025bSLars-Peter Clausen [ID_AD5541A] = { 373dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(16, 16, 0), 374dbdc025bSLars-Peter Clausen .write = ad5446_write, 375dbdc025bSLars-Peter Clausen }, 376dbdc025bSLars-Peter Clausen [ID_AD5512A] = { 377dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(12, 16, 4), 378dbdc025bSLars-Peter Clausen .write = ad5446_write, 379dbdc025bSLars-Peter Clausen }, 380dbdc025bSLars-Peter Clausen [ID_AD5553] = { 381dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(14, 16, 0), 382dbdc025bSLars-Peter Clausen .write = ad5446_write, 383dbdc025bSLars-Peter Clausen }, 384dbdc025bSLars-Peter Clausen [ID_AD5601] = { 385dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), 386dbdc025bSLars-Peter Clausen .write = ad5446_write, 387dbdc025bSLars-Peter Clausen }, 388dbdc025bSLars-Peter Clausen [ID_AD5611] = { 389dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), 390dbdc025bSLars-Peter Clausen .write = ad5446_write, 391dbdc025bSLars-Peter Clausen }, 392dbdc025bSLars-Peter Clausen [ID_AD5621] = { 393dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 394dbdc025bSLars-Peter Clausen .write = ad5446_write, 395dbdc025bSLars-Peter Clausen }, 3964fa2a9e4SAida Mynzhasova [ID_AD5641] = { 3974fa2a9e4SAida Mynzhasova .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 3984fa2a9e4SAida Mynzhasova .write = ad5446_write, 3994fa2a9e4SAida Mynzhasova }, 400dbdc025bSLars-Peter Clausen [ID_AD5620_2500] = { 401dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 402dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 403dbdc025bSLars-Peter Clausen .write = ad5446_write, 404dbdc025bSLars-Peter Clausen }, 405dbdc025bSLars-Peter Clausen [ID_AD5620_1250] = { 406dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 407dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 408dbdc025bSLars-Peter Clausen .write = ad5446_write, 409dbdc025bSLars-Peter Clausen }, 410dbdc025bSLars-Peter Clausen [ID_AD5640_2500] = { 411dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 412dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 413dbdc025bSLars-Peter Clausen .write = ad5446_write, 414dbdc025bSLars-Peter Clausen }, 415dbdc025bSLars-Peter Clausen [ID_AD5640_1250] = { 416dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 417dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 418dbdc025bSLars-Peter Clausen .write = ad5446_write, 419dbdc025bSLars-Peter Clausen }, 420dbdc025bSLars-Peter Clausen [ID_AD5660_2500] = { 421dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 422dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 423dbdc025bSLars-Peter Clausen .write = ad5660_write, 424dbdc025bSLars-Peter Clausen }, 425dbdc025bSLars-Peter Clausen [ID_AD5660_1250] = { 426dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 427dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 428dbdc025bSLars-Peter Clausen .write = ad5660_write, 429dbdc025bSLars-Peter Clausen }, 430dbdc025bSLars-Peter Clausen [ID_AD5662] = { 431dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 432dbdc025bSLars-Peter Clausen .write = ad5660_write, 433dbdc025bSLars-Peter Clausen }, 434dbdc025bSLars-Peter Clausen }; 435dbdc025bSLars-Peter Clausen 4363ec36a2cSJean-Francois Dagenais static const struct spi_device_id ad5446_spi_ids[] = { 4372fafbce2SLars-Peter Clausen {"ad5300", ID_AD5300}, 4382fafbce2SLars-Peter Clausen {"ad5310", ID_AD5310}, 4392fafbce2SLars-Peter Clausen {"ad5320", ID_AD5320}, 440dbdc025bSLars-Peter Clausen {"ad5444", ID_AD5444}, 441dbdc025bSLars-Peter Clausen {"ad5446", ID_AD5446}, 442779c0c46SLars-Peter Clausen {"ad5450", ID_AD5450}, 443779c0c46SLars-Peter Clausen {"ad5451", ID_AD5451}, 444779c0c46SLars-Peter Clausen {"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */ 445779c0c46SLars-Peter Clausen {"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */ 446dbdc025bSLars-Peter Clausen {"ad5512a", ID_AD5512A}, 447dbdc025bSLars-Peter Clausen {"ad5541a", ID_AD5541A}, 448dbdc025bSLars-Peter Clausen {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */ 449dbdc025bSLars-Peter Clausen {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */ 450dbdc025bSLars-Peter Clausen {"ad5553", ID_AD5553}, 451dbdc025bSLars-Peter Clausen {"ad5601", ID_AD5601}, 452dbdc025bSLars-Peter Clausen {"ad5611", ID_AD5611}, 453dbdc025bSLars-Peter Clausen {"ad5621", ID_AD5621}, 4544fa2a9e4SAida Mynzhasova {"ad5641", ID_AD5641}, 455dbdc025bSLars-Peter Clausen {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ 456dbdc025bSLars-Peter Clausen {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ 457dbdc025bSLars-Peter Clausen {"ad5640-2500", ID_AD5640_2500}, 458dbdc025bSLars-Peter Clausen {"ad5640-1250", ID_AD5640_1250}, 459dbdc025bSLars-Peter Clausen {"ad5660-2500", ID_AD5660_2500}, 460dbdc025bSLars-Peter Clausen {"ad5660-1250", ID_AD5660_1250}, 461dbdc025bSLars-Peter Clausen {"ad5662", ID_AD5662}, 4629cad3b98SLukas Wunner {"dac081s101", ID_AD5300}, /* compatible Texas Instruments chips */ 4639cad3b98SLukas Wunner {"dac101s101", ID_AD5310}, 4649cad3b98SLukas Wunner {"dac121s101", ID_AD5320}, 46549b3f874SLukas Wunner {"dac7512", ID_AD5320}, 466dbdc025bSLars-Peter Clausen {} 467dbdc025bSLars-Peter Clausen }; 4683ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); 469dbdc025bSLars-Peter Clausen 47049b3f874SLukas Wunner #ifdef CONFIG_OF 47149b3f874SLukas Wunner static const struct of_device_id ad5446_of_ids[] = { 47249b3f874SLukas Wunner { .compatible = "ti,dac7512" }, 47349b3f874SLukas Wunner { } 47449b3f874SLukas Wunner }; 47549b3f874SLukas Wunner MODULE_DEVICE_TABLE(of, ad5446_of_ids); 47649b3f874SLukas Wunner #endif 47749b3f874SLukas Wunner 478fc52692cSGreg Kroah-Hartman static int ad5446_spi_probe(struct spi_device *spi) 4793ec36a2cSJean-Francois Dagenais { 4803ec36a2cSJean-Francois Dagenais const struct spi_device_id *id = spi_get_device_id(spi); 4813ec36a2cSJean-Francois Dagenais 4823ec36a2cSJean-Francois Dagenais return ad5446_probe(&spi->dev, id->name, 4833ec36a2cSJean-Francois Dagenais &ad5446_spi_chip_info[id->driver_data]); 4843ec36a2cSJean-Francois Dagenais } 4853ec36a2cSJean-Francois Dagenais 486fc52692cSGreg Kroah-Hartman static int ad5446_spi_remove(struct spi_device *spi) 4873ec36a2cSJean-Francois Dagenais { 4883ec36a2cSJean-Francois Dagenais return ad5446_remove(&spi->dev); 4893ec36a2cSJean-Francois Dagenais } 4903ec36a2cSJean-Francois Dagenais 4913ec36a2cSJean-Francois Dagenais static struct spi_driver ad5446_spi_driver = { 492dbdc025bSLars-Peter Clausen .driver = { 493dbdc025bSLars-Peter Clausen .name = "ad5446", 49449b3f874SLukas Wunner .of_match_table = of_match_ptr(ad5446_of_ids), 495dbdc025bSLars-Peter Clausen }, 4963ec36a2cSJean-Francois Dagenais .probe = ad5446_spi_probe, 497fc52692cSGreg Kroah-Hartman .remove = ad5446_spi_remove, 4983ec36a2cSJean-Francois Dagenais .id_table = ad5446_spi_ids, 499dbdc025bSLars-Peter Clausen }; 5003ec36a2cSJean-Francois Dagenais 5013ec36a2cSJean-Francois Dagenais static int __init ad5446_spi_register_driver(void) 5023ec36a2cSJean-Francois Dagenais { 5033ec36a2cSJean-Francois Dagenais return spi_register_driver(&ad5446_spi_driver); 5043ec36a2cSJean-Francois Dagenais } 5053ec36a2cSJean-Francois Dagenais 5063ec36a2cSJean-Francois Dagenais static void ad5446_spi_unregister_driver(void) 5073ec36a2cSJean-Francois Dagenais { 5083ec36a2cSJean-Francois Dagenais spi_unregister_driver(&ad5446_spi_driver); 5093ec36a2cSJean-Francois Dagenais } 5103ec36a2cSJean-Francois Dagenais 5113ec36a2cSJean-Francois Dagenais #else 5123ec36a2cSJean-Francois Dagenais 5133ec36a2cSJean-Francois Dagenais static inline int ad5446_spi_register_driver(void) { return 0; } 5143ec36a2cSJean-Francois Dagenais static inline void ad5446_spi_unregister_driver(void) { } 5153ec36a2cSJean-Francois Dagenais 5163ec36a2cSJean-Francois Dagenais #endif 5173ec36a2cSJean-Francois Dagenais 5183ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_I2C) 5193ec36a2cSJean-Francois Dagenais 5203ec36a2cSJean-Francois Dagenais static int ad5622_write(struct ad5446_state *st, unsigned val) 5213ec36a2cSJean-Francois Dagenais { 5223ec36a2cSJean-Francois Dagenais struct i2c_client *client = to_i2c_client(st->dev); 5233ec36a2cSJean-Francois Dagenais __be16 data = cpu_to_be16(val); 5243ec36a2cSJean-Francois Dagenais 5253ec36a2cSJean-Francois Dagenais return i2c_master_send(client, (char *)&data, sizeof(data)); 5263ec36a2cSJean-Francois Dagenais } 5273ec36a2cSJean-Francois Dagenais 5283ec36a2cSJean-Francois Dagenais /** 5293ec36a2cSJean-Francois Dagenais * ad5446_supported_i2c_device_ids: 5303ec36a2cSJean-Francois Dagenais * The AD5620/40/60 parts are available in different fixed internal reference 5313ec36a2cSJean-Francois Dagenais * voltage options. The actual part numbers may look differently 5323ec36a2cSJean-Francois Dagenais * (and a bit cryptic), however this style is used to make clear which 5333ec36a2cSJean-Francois Dagenais * parts are supported here. 5343ec36a2cSJean-Francois Dagenais */ 5353ec36a2cSJean-Francois Dagenais enum ad5446_supported_i2c_device_ids { 5363ec36a2cSJean-Francois Dagenais ID_AD5602, 5373ec36a2cSJean-Francois Dagenais ID_AD5612, 5383ec36a2cSJean-Francois Dagenais ID_AD5622, 5393ec36a2cSJean-Francois Dagenais }; 5403ec36a2cSJean-Francois Dagenais 5413ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_i2c_chip_info[] = { 5423ec36a2cSJean-Francois Dagenais [ID_AD5602] = { 5433ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 5443ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5453ec36a2cSJean-Francois Dagenais }, 5463ec36a2cSJean-Francois Dagenais [ID_AD5612] = { 5473ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 5483ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5493ec36a2cSJean-Francois Dagenais }, 5503ec36a2cSJean-Francois Dagenais [ID_AD5622] = { 5513ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 5523ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5533ec36a2cSJean-Francois Dagenais }, 5543ec36a2cSJean-Francois Dagenais }; 5553ec36a2cSJean-Francois Dagenais 556fc52692cSGreg Kroah-Hartman static int ad5446_i2c_probe(struct i2c_client *i2c, 5573ec36a2cSJean-Francois Dagenais const struct i2c_device_id *id) 5583ec36a2cSJean-Francois Dagenais { 5593ec36a2cSJean-Francois Dagenais return ad5446_probe(&i2c->dev, id->name, 5603ec36a2cSJean-Francois Dagenais &ad5446_i2c_chip_info[id->driver_data]); 5613ec36a2cSJean-Francois Dagenais } 5623ec36a2cSJean-Francois Dagenais 563fc52692cSGreg Kroah-Hartman static int ad5446_i2c_remove(struct i2c_client *i2c) 5643ec36a2cSJean-Francois Dagenais { 5653ec36a2cSJean-Francois Dagenais return ad5446_remove(&i2c->dev); 5663ec36a2cSJean-Francois Dagenais } 5673ec36a2cSJean-Francois Dagenais 5683ec36a2cSJean-Francois Dagenais static const struct i2c_device_id ad5446_i2c_ids[] = { 569bf832380SLars-Peter Clausen {"ad5301", ID_AD5602}, 570bf832380SLars-Peter Clausen {"ad5311", ID_AD5612}, 571bf832380SLars-Peter Clausen {"ad5321", ID_AD5622}, 5723ec36a2cSJean-Francois Dagenais {"ad5602", ID_AD5602}, 5733ec36a2cSJean-Francois Dagenais {"ad5612", ID_AD5612}, 5743ec36a2cSJean-Francois Dagenais {"ad5622", ID_AD5622}, 5753ec36a2cSJean-Francois Dagenais {} 5763ec36a2cSJean-Francois Dagenais }; 5773ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); 5783ec36a2cSJean-Francois Dagenais 5793ec36a2cSJean-Francois Dagenais static struct i2c_driver ad5446_i2c_driver = { 5803ec36a2cSJean-Francois Dagenais .driver = { 5813ec36a2cSJean-Francois Dagenais .name = "ad5446", 5823ec36a2cSJean-Francois Dagenais }, 5833ec36a2cSJean-Francois Dagenais .probe = ad5446_i2c_probe, 584fc52692cSGreg Kroah-Hartman .remove = ad5446_i2c_remove, 5853ec36a2cSJean-Francois Dagenais .id_table = ad5446_i2c_ids, 5863ec36a2cSJean-Francois Dagenais }; 5873ec36a2cSJean-Francois Dagenais 5883ec36a2cSJean-Francois Dagenais static int __init ad5446_i2c_register_driver(void) 5893ec36a2cSJean-Francois Dagenais { 5903ec36a2cSJean-Francois Dagenais return i2c_add_driver(&ad5446_i2c_driver); 5913ec36a2cSJean-Francois Dagenais } 5923ec36a2cSJean-Francois Dagenais 5933ec36a2cSJean-Francois Dagenais static void __exit ad5446_i2c_unregister_driver(void) 5943ec36a2cSJean-Francois Dagenais { 5953ec36a2cSJean-Francois Dagenais i2c_del_driver(&ad5446_i2c_driver); 5963ec36a2cSJean-Francois Dagenais } 5973ec36a2cSJean-Francois Dagenais 5983ec36a2cSJean-Francois Dagenais #else 5993ec36a2cSJean-Francois Dagenais 6003ec36a2cSJean-Francois Dagenais static inline int ad5446_i2c_register_driver(void) { return 0; } 6013ec36a2cSJean-Francois Dagenais static inline void ad5446_i2c_unregister_driver(void) { } 6023ec36a2cSJean-Francois Dagenais 6033ec36a2cSJean-Francois Dagenais #endif 6043ec36a2cSJean-Francois Dagenais 6053ec36a2cSJean-Francois Dagenais static int __init ad5446_init(void) 6063ec36a2cSJean-Francois Dagenais { 6073ec36a2cSJean-Francois Dagenais int ret; 6083ec36a2cSJean-Francois Dagenais 6093ec36a2cSJean-Francois Dagenais ret = ad5446_spi_register_driver(); 6103ec36a2cSJean-Francois Dagenais if (ret) 6113ec36a2cSJean-Francois Dagenais return ret; 6123ec36a2cSJean-Francois Dagenais 6133ec36a2cSJean-Francois Dagenais ret = ad5446_i2c_register_driver(); 6143ec36a2cSJean-Francois Dagenais if (ret) { 6153ec36a2cSJean-Francois Dagenais ad5446_spi_unregister_driver(); 6163ec36a2cSJean-Francois Dagenais return ret; 6173ec36a2cSJean-Francois Dagenais } 6183ec36a2cSJean-Francois Dagenais 6193ec36a2cSJean-Francois Dagenais return 0; 6203ec36a2cSJean-Francois Dagenais } 6213ec36a2cSJean-Francois Dagenais module_init(ad5446_init); 6223ec36a2cSJean-Francois Dagenais 6233ec36a2cSJean-Francois Dagenais static void __exit ad5446_exit(void) 6243ec36a2cSJean-Francois Dagenais { 6253ec36a2cSJean-Francois Dagenais ad5446_i2c_unregister_driver(); 6263ec36a2cSJean-Francois Dagenais ad5446_spi_unregister_driver(); 6273ec36a2cSJean-Francois Dagenais } 6283ec36a2cSJean-Francois Dagenais module_exit(ad5446_exit); 629dbdc025bSLars-Peter Clausen 6309920ed25SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 631dbdc025bSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); 632dbdc025bSLars-Peter Clausen MODULE_LICENSE("GPL v2"); 633