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> 20b49e6eb1SJonathan Cameron #include <linux/mod_devicetable.h> 21dbdc025bSLars-Peter Clausen 22dbdc025bSLars-Peter Clausen #include <linux/iio/iio.h> 23dbdc025bSLars-Peter Clausen #include <linux/iio/sysfs.h> 24dbdc025bSLars-Peter Clausen 256ef9d68bSAndy Shevchenko #include <asm/unaligned.h> 266ef9d68bSAndy Shevchenko 272e15c903SJean-Francois Dagenais #define MODE_PWRDWN_1k 0x1 282e15c903SJean-Francois Dagenais #define MODE_PWRDWN_100k 0x2 292e15c903SJean-Francois Dagenais #define MODE_PWRDWN_TRISTATE 0x3 302e15c903SJean-Francois Dagenais 312e15c903SJean-Francois Dagenais /** 322e15c903SJean-Francois Dagenais * struct ad5446_state - driver instance specific data 33af390b8cSLee Jones * @dev: this device 342e15c903SJean-Francois Dagenais * @chip_info: chip model specific constants, available modes etc 352e15c903SJean-Francois Dagenais * @reg: supply regulator 362e15c903SJean-Francois Dagenais * @vref_mv: actual reference voltage used 37af390b8cSLee Jones * @cached_val: store/retrieve values during power down 38af390b8cSLee Jones * @pwr_down_mode: power down mode (1k, 100k or tristate) 39af390b8cSLee Jones * @pwr_down: true if the device is in power down 40af390b8cSLee Jones * @lock: lock to protect the data buffer during write ops 412e15c903SJean-Francois Dagenais */ 422e15c903SJean-Francois Dagenais 432e15c903SJean-Francois Dagenais struct ad5446_state { 442e15c903SJean-Francois Dagenais struct device *dev; 452e15c903SJean-Francois Dagenais const struct ad5446_chip_info *chip_info; 462e15c903SJean-Francois Dagenais struct regulator *reg; 472e15c903SJean-Francois Dagenais unsigned short vref_mv; 482e15c903SJean-Francois Dagenais unsigned cached_val; 492e15c903SJean-Francois Dagenais unsigned pwr_down_mode; 502e15c903SJean-Francois Dagenais unsigned pwr_down; 510b4b5925SSergiu Cuciurean struct mutex lock; 522e15c903SJean-Francois Dagenais }; 532e15c903SJean-Francois Dagenais 542e15c903SJean-Francois Dagenais /** 552e15c903SJean-Francois Dagenais * struct ad5446_chip_info - chip specific information 562e15c903SJean-Francois Dagenais * @channel: channel spec for the DAC 572e15c903SJean-Francois Dagenais * @int_vref_mv: AD5620/40/60: the internal reference voltage 582e15c903SJean-Francois Dagenais * @write: chip specific helper function to write to the register 592e15c903SJean-Francois Dagenais */ 602e15c903SJean-Francois Dagenais 612e15c903SJean-Francois Dagenais struct ad5446_chip_info { 622e15c903SJean-Francois Dagenais struct iio_chan_spec channel; 632e15c903SJean-Francois Dagenais u16 int_vref_mv; 642e15c903SJean-Francois Dagenais int (*write)(struct ad5446_state *st, unsigned val); 652e15c903SJean-Francois Dagenais }; 66dbdc025bSLars-Peter Clausen 67dbdc025bSLars-Peter Clausen static const char * const ad5446_powerdown_modes[] = { 68dbdc025bSLars-Peter Clausen "1kohm_to_gnd", "100kohm_to_gnd", "three_state" 69dbdc025bSLars-Peter Clausen }; 70dbdc025bSLars-Peter Clausen 71dbdc025bSLars-Peter Clausen static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev, 72dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, unsigned int mode) 73dbdc025bSLars-Peter Clausen { 74dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 75dbdc025bSLars-Peter Clausen 76dbdc025bSLars-Peter Clausen st->pwr_down_mode = mode + 1; 77dbdc025bSLars-Peter Clausen 78dbdc025bSLars-Peter Clausen return 0; 79dbdc025bSLars-Peter Clausen } 80dbdc025bSLars-Peter Clausen 81dbdc025bSLars-Peter Clausen static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev, 82dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan) 83dbdc025bSLars-Peter Clausen { 84dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 85dbdc025bSLars-Peter Clausen 86dbdc025bSLars-Peter Clausen return st->pwr_down_mode - 1; 87dbdc025bSLars-Peter Clausen } 88dbdc025bSLars-Peter Clausen 89dbdc025bSLars-Peter Clausen static const struct iio_enum ad5446_powerdown_mode_enum = { 90dbdc025bSLars-Peter Clausen .items = ad5446_powerdown_modes, 91dbdc025bSLars-Peter Clausen .num_items = ARRAY_SIZE(ad5446_powerdown_modes), 92dbdc025bSLars-Peter Clausen .get = ad5446_get_powerdown_mode, 93dbdc025bSLars-Peter Clausen .set = ad5446_set_powerdown_mode, 94dbdc025bSLars-Peter Clausen }; 95dbdc025bSLars-Peter Clausen 96dbdc025bSLars-Peter Clausen static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, 97dbdc025bSLars-Peter Clausen uintptr_t private, 98dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, 99dbdc025bSLars-Peter Clausen char *buf) 100dbdc025bSLars-Peter Clausen { 101dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 102dbdc025bSLars-Peter Clausen 103f46ac009SLars-Peter Clausen return sysfs_emit(buf, "%d\n", st->pwr_down); 104dbdc025bSLars-Peter Clausen } 105dbdc025bSLars-Peter Clausen 106dbdc025bSLars-Peter Clausen static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, 107dbdc025bSLars-Peter Clausen uintptr_t private, 108dbdc025bSLars-Peter Clausen const struct iio_chan_spec *chan, 109dbdc025bSLars-Peter Clausen const char *buf, size_t len) 110dbdc025bSLars-Peter Clausen { 111dbdc025bSLars-Peter Clausen struct ad5446_state *st = iio_priv(indio_dev); 112dbdc025bSLars-Peter Clausen unsigned int shift; 113dbdc025bSLars-Peter Clausen unsigned int val; 114dbdc025bSLars-Peter Clausen bool powerdown; 115dbdc025bSLars-Peter Clausen int ret; 116dbdc025bSLars-Peter Clausen 117dbdc025bSLars-Peter Clausen ret = strtobool(buf, &powerdown); 118dbdc025bSLars-Peter Clausen if (ret) 119dbdc025bSLars-Peter Clausen return ret; 120dbdc025bSLars-Peter Clausen 1210b4b5925SSergiu Cuciurean mutex_lock(&st->lock); 122dbdc025bSLars-Peter Clausen st->pwr_down = powerdown; 123dbdc025bSLars-Peter Clausen 124dbdc025bSLars-Peter Clausen if (st->pwr_down) { 125dbdc025bSLars-Peter Clausen shift = chan->scan_type.realbits + chan->scan_type.shift; 126dbdc025bSLars-Peter Clausen val = st->pwr_down_mode << shift; 127dbdc025bSLars-Peter Clausen } else { 128dbdc025bSLars-Peter Clausen val = st->cached_val; 129dbdc025bSLars-Peter Clausen } 130dbdc025bSLars-Peter Clausen 131dbdc025bSLars-Peter Clausen ret = st->chip_info->write(st, val); 1320b4b5925SSergiu Cuciurean mutex_unlock(&st->lock); 133dbdc025bSLars-Peter Clausen 134dbdc025bSLars-Peter Clausen return ret ? ret : len; 135dbdc025bSLars-Peter Clausen } 136dbdc025bSLars-Peter Clausen 1373ec36a2cSJean-Francois Dagenais static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { 138dbdc025bSLars-Peter Clausen { 139dbdc025bSLars-Peter Clausen .name = "powerdown", 140dbdc025bSLars-Peter Clausen .read = ad5446_read_dac_powerdown, 141dbdc025bSLars-Peter Clausen .write = ad5446_write_dac_powerdown, 1423704432fSJonathan Cameron .shared = IIO_SEPARATE, 143dbdc025bSLars-Peter Clausen }, 1443704432fSJonathan Cameron IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), 145*ffc7c517SAntoniu Miclaus IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5446_powerdown_mode_enum), 146dbdc025bSLars-Peter Clausen { }, 147dbdc025bSLars-Peter Clausen }; 148dbdc025bSLars-Peter Clausen 149e3019c21SJonathan Cameron #define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ 150dbdc025bSLars-Peter Clausen .type = IIO_VOLTAGE, \ 151dbdc025bSLars-Peter Clausen .indexed = 1, \ 152dbdc025bSLars-Peter Clausen .output = 1, \ 153dbdc025bSLars-Peter Clausen .channel = 0, \ 1542f6a4a44SJonathan Cameron .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 1552f6a4a44SJonathan Cameron .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 156e3019c21SJonathan Cameron .scan_type = { \ 157e3019c21SJonathan Cameron .sign = 'u', \ 158e3019c21SJonathan Cameron .realbits = (bits), \ 159e3019c21SJonathan Cameron .storagebits = (storage), \ 160e3019c21SJonathan Cameron .shift = (_shift), \ 161e3019c21SJonathan Cameron }, \ 162dbdc025bSLars-Peter Clausen .ext_info = (ext), \ 163dbdc025bSLars-Peter Clausen } 164dbdc025bSLars-Peter Clausen 165dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL(bits, storage, shift) \ 166dbdc025bSLars-Peter Clausen _AD5446_CHANNEL(bits, storage, shift, NULL) 167dbdc025bSLars-Peter Clausen 168dbdc025bSLars-Peter Clausen #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ 1693ec36a2cSJean-Francois Dagenais _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) 170dbdc025bSLars-Peter Clausen 1713ec36a2cSJean-Francois Dagenais static int ad5446_read_raw(struct iio_dev *indio_dev, 1723ec36a2cSJean-Francois Dagenais struct iio_chan_spec const *chan, 1733ec36a2cSJean-Francois Dagenais int *val, 1743ec36a2cSJean-Francois Dagenais int *val2, 1753ec36a2cSJean-Francois Dagenais long m) 1763ec36a2cSJean-Francois Dagenais { 1773ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 1783ec36a2cSJean-Francois Dagenais 1793ec36a2cSJean-Francois Dagenais switch (m) { 1803ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_RAW: 1813ec36a2cSJean-Francois Dagenais *val = st->cached_val; 1823ec36a2cSJean-Francois Dagenais return IIO_VAL_INT; 1833ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_SCALE: 1840a99b601SLars-Peter Clausen *val = st->vref_mv; 1850a99b601SLars-Peter Clausen *val2 = chan->scan_type.realbits; 1860a99b601SLars-Peter Clausen return IIO_VAL_FRACTIONAL_LOG2; 1873ec36a2cSJean-Francois Dagenais } 1883ec36a2cSJean-Francois Dagenais return -EINVAL; 1893ec36a2cSJean-Francois Dagenais } 1903ec36a2cSJean-Francois Dagenais 1913ec36a2cSJean-Francois Dagenais static int ad5446_write_raw(struct iio_dev *indio_dev, 1923ec36a2cSJean-Francois Dagenais struct iio_chan_spec const *chan, 1933ec36a2cSJean-Francois Dagenais int val, 1943ec36a2cSJean-Francois Dagenais int val2, 1953ec36a2cSJean-Francois Dagenais long mask) 1963ec36a2cSJean-Francois Dagenais { 1973ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 1983ec36a2cSJean-Francois Dagenais int ret = 0; 1993ec36a2cSJean-Francois Dagenais 2003ec36a2cSJean-Francois Dagenais switch (mask) { 2013ec36a2cSJean-Francois Dagenais case IIO_CHAN_INFO_RAW: 2023ec36a2cSJean-Francois Dagenais if (val >= (1 << chan->scan_type.realbits) || val < 0) 2033ec36a2cSJean-Francois Dagenais return -EINVAL; 2043ec36a2cSJean-Francois Dagenais 2053ec36a2cSJean-Francois Dagenais val <<= chan->scan_type.shift; 2060b4b5925SSergiu Cuciurean mutex_lock(&st->lock); 2073ec36a2cSJean-Francois Dagenais st->cached_val = val; 2083ec36a2cSJean-Francois Dagenais if (!st->pwr_down) 2093ec36a2cSJean-Francois Dagenais ret = st->chip_info->write(st, val); 2100b4b5925SSergiu Cuciurean mutex_unlock(&st->lock); 2113ec36a2cSJean-Francois Dagenais break; 2123ec36a2cSJean-Francois Dagenais default: 2133ec36a2cSJean-Francois Dagenais ret = -EINVAL; 2143ec36a2cSJean-Francois Dagenais } 2153ec36a2cSJean-Francois Dagenais 2163ec36a2cSJean-Francois Dagenais return ret; 2173ec36a2cSJean-Francois Dagenais } 2183ec36a2cSJean-Francois Dagenais 2193ec36a2cSJean-Francois Dagenais static const struct iio_info ad5446_info = { 2203ec36a2cSJean-Francois Dagenais .read_raw = ad5446_read_raw, 2213ec36a2cSJean-Francois Dagenais .write_raw = ad5446_write_raw, 2223ec36a2cSJean-Francois Dagenais }; 2233ec36a2cSJean-Francois Dagenais 224fc52692cSGreg Kroah-Hartman static int ad5446_probe(struct device *dev, const char *name, 2253ec36a2cSJean-Francois Dagenais const struct ad5446_chip_info *chip_info) 2263ec36a2cSJean-Francois Dagenais { 2273ec36a2cSJean-Francois Dagenais struct ad5446_state *st; 2283ec36a2cSJean-Francois Dagenais struct iio_dev *indio_dev; 2293ec36a2cSJean-Francois Dagenais struct regulator *reg; 2303ec36a2cSJean-Francois Dagenais int ret, voltage_uv = 0; 2313ec36a2cSJean-Francois Dagenais 232ba727295SSachin Kamat reg = devm_regulator_get(dev, "vcc"); 2333ec36a2cSJean-Francois Dagenais if (!IS_ERR(reg)) { 2343ec36a2cSJean-Francois Dagenais ret = regulator_enable(reg); 2353ec36a2cSJean-Francois Dagenais if (ret) 236ba727295SSachin Kamat return ret; 2373ec36a2cSJean-Francois Dagenais 23813e57ee2SAxel Lin ret = regulator_get_voltage(reg); 23913e57ee2SAxel Lin if (ret < 0) 24013e57ee2SAxel Lin goto error_disable_reg; 24113e57ee2SAxel Lin 24213e57ee2SAxel Lin voltage_uv = ret; 2433ec36a2cSJean-Francois Dagenais } 2443ec36a2cSJean-Francois Dagenais 245ba727295SSachin Kamat indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 2463ec36a2cSJean-Francois Dagenais if (indio_dev == NULL) { 2473ec36a2cSJean-Francois Dagenais ret = -ENOMEM; 2483ec36a2cSJean-Francois Dagenais goto error_disable_reg; 2493ec36a2cSJean-Francois Dagenais } 2503ec36a2cSJean-Francois Dagenais st = iio_priv(indio_dev); 2513ec36a2cSJean-Francois Dagenais st->chip_info = chip_info; 2523ec36a2cSJean-Francois Dagenais 2533ec36a2cSJean-Francois Dagenais dev_set_drvdata(dev, indio_dev); 2543ec36a2cSJean-Francois Dagenais st->reg = reg; 2553ec36a2cSJean-Francois Dagenais st->dev = dev; 2563ec36a2cSJean-Francois Dagenais 2573ec36a2cSJean-Francois Dagenais indio_dev->name = name; 2583ec36a2cSJean-Francois Dagenais indio_dev->info = &ad5446_info; 2593ec36a2cSJean-Francois Dagenais indio_dev->modes = INDIO_DIRECT_MODE; 2603ec36a2cSJean-Francois Dagenais indio_dev->channels = &st->chip_info->channel; 2613ec36a2cSJean-Francois Dagenais indio_dev->num_channels = 1; 2623ec36a2cSJean-Francois Dagenais 2630b4b5925SSergiu Cuciurean mutex_init(&st->lock); 2640b4b5925SSergiu Cuciurean 2653ec36a2cSJean-Francois Dagenais st->pwr_down_mode = MODE_PWRDWN_1k; 2663ec36a2cSJean-Francois Dagenais 2673ec36a2cSJean-Francois Dagenais if (st->chip_info->int_vref_mv) 2683ec36a2cSJean-Francois Dagenais st->vref_mv = st->chip_info->int_vref_mv; 2693ec36a2cSJean-Francois Dagenais else if (voltage_uv) 2703ec36a2cSJean-Francois Dagenais st->vref_mv = voltage_uv / 1000; 2713ec36a2cSJean-Francois Dagenais else 2723ec36a2cSJean-Francois Dagenais dev_warn(dev, "reference voltage unspecified\n"); 2733ec36a2cSJean-Francois Dagenais 2743ec36a2cSJean-Francois Dagenais ret = iio_device_register(indio_dev); 2753ec36a2cSJean-Francois Dagenais if (ret) 276ba727295SSachin Kamat goto error_disable_reg; 2773ec36a2cSJean-Francois Dagenais 2783ec36a2cSJean-Francois Dagenais return 0; 2793ec36a2cSJean-Francois Dagenais 2803ec36a2cSJean-Francois Dagenais error_disable_reg: 2813ec36a2cSJean-Francois Dagenais if (!IS_ERR(reg)) 2823ec36a2cSJean-Francois Dagenais regulator_disable(reg); 2833ec36a2cSJean-Francois Dagenais return ret; 2843ec36a2cSJean-Francois Dagenais } 2853ec36a2cSJean-Francois Dagenais 2861f10848fSUwe Kleine-König static void ad5446_remove(struct device *dev) 2873ec36a2cSJean-Francois Dagenais { 2883ec36a2cSJean-Francois Dagenais struct iio_dev *indio_dev = dev_get_drvdata(dev); 2893ec36a2cSJean-Francois Dagenais struct ad5446_state *st = iio_priv(indio_dev); 2903ec36a2cSJean-Francois Dagenais 2913ec36a2cSJean-Francois Dagenais iio_device_unregister(indio_dev); 292ba727295SSachin Kamat if (!IS_ERR(st->reg)) 2933ec36a2cSJean-Francois Dagenais regulator_disable(st->reg); 2943ec36a2cSJean-Francois Dagenais } 2953ec36a2cSJean-Francois Dagenais 2963ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_SPI_MASTER) 2973ec36a2cSJean-Francois Dagenais 2983ec36a2cSJean-Francois Dagenais static int ad5446_write(struct ad5446_state *st, unsigned val) 2993ec36a2cSJean-Francois Dagenais { 3003ec36a2cSJean-Francois Dagenais struct spi_device *spi = to_spi_device(st->dev); 3013ec36a2cSJean-Francois Dagenais __be16 data = cpu_to_be16(val); 3023ec36a2cSJean-Francois Dagenais 3033ec36a2cSJean-Francois Dagenais return spi_write(spi, &data, sizeof(data)); 3043ec36a2cSJean-Francois Dagenais } 3053ec36a2cSJean-Francois Dagenais 3063ec36a2cSJean-Francois Dagenais static int ad5660_write(struct ad5446_state *st, unsigned val) 3073ec36a2cSJean-Francois Dagenais { 3083ec36a2cSJean-Francois Dagenais struct spi_device *spi = to_spi_device(st->dev); 3093ec36a2cSJean-Francois Dagenais uint8_t data[3]; 3103ec36a2cSJean-Francois Dagenais 3116ef9d68bSAndy Shevchenko put_unaligned_be24(val, &data[0]); 3123ec36a2cSJean-Francois Dagenais 3133ec36a2cSJean-Francois Dagenais return spi_write(spi, data, sizeof(data)); 3143ec36a2cSJean-Francois Dagenais } 3153ec36a2cSJean-Francois Dagenais 316af390b8cSLee Jones /* 3173ec36a2cSJean-Francois Dagenais * ad5446_supported_spi_device_ids: 3183ec36a2cSJean-Francois Dagenais * The AD5620/40/60 parts are available in different fixed internal reference 3193ec36a2cSJean-Francois Dagenais * voltage options. The actual part numbers may look differently 3203ec36a2cSJean-Francois Dagenais * (and a bit cryptic), however this style is used to make clear which 3213ec36a2cSJean-Francois Dagenais * parts are supported here. 3223ec36a2cSJean-Francois Dagenais */ 3233ec36a2cSJean-Francois Dagenais enum ad5446_supported_spi_device_ids { 3242fafbce2SLars-Peter Clausen ID_AD5300, 3252fafbce2SLars-Peter Clausen ID_AD5310, 3262fafbce2SLars-Peter Clausen ID_AD5320, 3273ec36a2cSJean-Francois Dagenais ID_AD5444, 3283ec36a2cSJean-Francois Dagenais ID_AD5446, 3293ec36a2cSJean-Francois Dagenais ID_AD5450, 3303ec36a2cSJean-Francois Dagenais ID_AD5451, 3313ec36a2cSJean-Francois Dagenais ID_AD5541A, 3323ec36a2cSJean-Francois Dagenais ID_AD5512A, 3333ec36a2cSJean-Francois Dagenais ID_AD5553, 3346376cbe5SStefan Popa ID_AD5600, 3353ec36a2cSJean-Francois Dagenais ID_AD5601, 3363ec36a2cSJean-Francois Dagenais ID_AD5611, 3373ec36a2cSJean-Francois Dagenais ID_AD5621, 3384fa2a9e4SAida Mynzhasova ID_AD5641, 3393ec36a2cSJean-Francois Dagenais ID_AD5620_2500, 3403ec36a2cSJean-Francois Dagenais ID_AD5620_1250, 3413ec36a2cSJean-Francois Dagenais ID_AD5640_2500, 3423ec36a2cSJean-Francois Dagenais ID_AD5640_1250, 3433ec36a2cSJean-Francois Dagenais ID_AD5660_2500, 3443ec36a2cSJean-Francois Dagenais ID_AD5660_1250, 3453ec36a2cSJean-Francois Dagenais ID_AD5662, 3463ec36a2cSJean-Francois Dagenais }; 3473ec36a2cSJean-Francois Dagenais 3483ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_spi_chip_info[] = { 3492fafbce2SLars-Peter Clausen [ID_AD5300] = { 3502fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 3512fafbce2SLars-Peter Clausen .write = ad5446_write, 3522fafbce2SLars-Peter Clausen }, 3532fafbce2SLars-Peter Clausen [ID_AD5310] = { 3542fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 3552fafbce2SLars-Peter Clausen .write = ad5446_write, 3562fafbce2SLars-Peter Clausen }, 3572fafbce2SLars-Peter Clausen [ID_AD5320] = { 3582fafbce2SLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 3592fafbce2SLars-Peter Clausen .write = ad5446_write, 3602fafbce2SLars-Peter Clausen }, 361dbdc025bSLars-Peter Clausen [ID_AD5444] = { 362dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(12, 16, 2), 363dbdc025bSLars-Peter Clausen .write = ad5446_write, 364dbdc025bSLars-Peter Clausen }, 365dbdc025bSLars-Peter Clausen [ID_AD5446] = { 366dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(14, 16, 0), 367dbdc025bSLars-Peter Clausen .write = ad5446_write, 368dbdc025bSLars-Peter Clausen }, 369779c0c46SLars-Peter Clausen [ID_AD5450] = { 370779c0c46SLars-Peter Clausen .channel = AD5446_CHANNEL(8, 16, 6), 371779c0c46SLars-Peter Clausen .write = ad5446_write, 372779c0c46SLars-Peter Clausen }, 373779c0c46SLars-Peter Clausen [ID_AD5451] = { 374779c0c46SLars-Peter Clausen .channel = AD5446_CHANNEL(10, 16, 4), 375779c0c46SLars-Peter Clausen .write = ad5446_write, 376779c0c46SLars-Peter Clausen }, 377dbdc025bSLars-Peter Clausen [ID_AD5541A] = { 378dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(16, 16, 0), 379dbdc025bSLars-Peter Clausen .write = ad5446_write, 380dbdc025bSLars-Peter Clausen }, 381dbdc025bSLars-Peter Clausen [ID_AD5512A] = { 382dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(12, 16, 4), 383dbdc025bSLars-Peter Clausen .write = ad5446_write, 384dbdc025bSLars-Peter Clausen }, 385dbdc025bSLars-Peter Clausen [ID_AD5553] = { 386dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL(14, 16, 0), 387dbdc025bSLars-Peter Clausen .write = ad5446_write, 388dbdc025bSLars-Peter Clausen }, 3896376cbe5SStefan Popa [ID_AD5600] = { 3906376cbe5SStefan Popa .channel = AD5446_CHANNEL(16, 16, 0), 3916376cbe5SStefan Popa .write = ad5446_write, 3926376cbe5SStefan Popa }, 393dbdc025bSLars-Peter Clausen [ID_AD5601] = { 394dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), 395dbdc025bSLars-Peter Clausen .write = ad5446_write, 396dbdc025bSLars-Peter Clausen }, 397dbdc025bSLars-Peter Clausen [ID_AD5611] = { 398dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), 399dbdc025bSLars-Peter Clausen .write = ad5446_write, 400dbdc025bSLars-Peter Clausen }, 401dbdc025bSLars-Peter Clausen [ID_AD5621] = { 402dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 403dbdc025bSLars-Peter Clausen .write = ad5446_write, 404dbdc025bSLars-Peter Clausen }, 4054fa2a9e4SAida Mynzhasova [ID_AD5641] = { 4064fa2a9e4SAida Mynzhasova .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 4074fa2a9e4SAida Mynzhasova .write = ad5446_write, 4084fa2a9e4SAida Mynzhasova }, 409dbdc025bSLars-Peter Clausen [ID_AD5620_2500] = { 410dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 411dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 412dbdc025bSLars-Peter Clausen .write = ad5446_write, 413dbdc025bSLars-Peter Clausen }, 414dbdc025bSLars-Peter Clausen [ID_AD5620_1250] = { 415dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), 416dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 417dbdc025bSLars-Peter Clausen .write = ad5446_write, 418dbdc025bSLars-Peter Clausen }, 419dbdc025bSLars-Peter Clausen [ID_AD5640_2500] = { 420dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 421dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 422dbdc025bSLars-Peter Clausen .write = ad5446_write, 423dbdc025bSLars-Peter Clausen }, 424dbdc025bSLars-Peter Clausen [ID_AD5640_1250] = { 425dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), 426dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 427dbdc025bSLars-Peter Clausen .write = ad5446_write, 428dbdc025bSLars-Peter Clausen }, 429dbdc025bSLars-Peter Clausen [ID_AD5660_2500] = { 430dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 431dbdc025bSLars-Peter Clausen .int_vref_mv = 2500, 432dbdc025bSLars-Peter Clausen .write = ad5660_write, 433dbdc025bSLars-Peter Clausen }, 434dbdc025bSLars-Peter Clausen [ID_AD5660_1250] = { 435dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 436dbdc025bSLars-Peter Clausen .int_vref_mv = 1250, 437dbdc025bSLars-Peter Clausen .write = ad5660_write, 438dbdc025bSLars-Peter Clausen }, 439dbdc025bSLars-Peter Clausen [ID_AD5662] = { 440dbdc025bSLars-Peter Clausen .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), 441dbdc025bSLars-Peter Clausen .write = ad5660_write, 442dbdc025bSLars-Peter Clausen }, 443dbdc025bSLars-Peter Clausen }; 444dbdc025bSLars-Peter Clausen 4453ec36a2cSJean-Francois Dagenais static const struct spi_device_id ad5446_spi_ids[] = { 4462fafbce2SLars-Peter Clausen {"ad5300", ID_AD5300}, 4472fafbce2SLars-Peter Clausen {"ad5310", ID_AD5310}, 4482fafbce2SLars-Peter Clausen {"ad5320", ID_AD5320}, 449dbdc025bSLars-Peter Clausen {"ad5444", ID_AD5444}, 450dbdc025bSLars-Peter Clausen {"ad5446", ID_AD5446}, 451779c0c46SLars-Peter Clausen {"ad5450", ID_AD5450}, 452779c0c46SLars-Peter Clausen {"ad5451", ID_AD5451}, 453779c0c46SLars-Peter Clausen {"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */ 454779c0c46SLars-Peter Clausen {"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */ 455dbdc025bSLars-Peter Clausen {"ad5512a", ID_AD5512A}, 456dbdc025bSLars-Peter Clausen {"ad5541a", ID_AD5541A}, 457dbdc025bSLars-Peter Clausen {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */ 458dbdc025bSLars-Peter Clausen {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */ 459dbdc025bSLars-Peter Clausen {"ad5553", ID_AD5553}, 4606376cbe5SStefan Popa {"ad5600", ID_AD5600}, 461dbdc025bSLars-Peter Clausen {"ad5601", ID_AD5601}, 462dbdc025bSLars-Peter Clausen {"ad5611", ID_AD5611}, 463dbdc025bSLars-Peter Clausen {"ad5621", ID_AD5621}, 4644fa2a9e4SAida Mynzhasova {"ad5641", ID_AD5641}, 465dbdc025bSLars-Peter Clausen {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ 466dbdc025bSLars-Peter Clausen {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ 467dbdc025bSLars-Peter Clausen {"ad5640-2500", ID_AD5640_2500}, 468dbdc025bSLars-Peter Clausen {"ad5640-1250", ID_AD5640_1250}, 469dbdc025bSLars-Peter Clausen {"ad5660-2500", ID_AD5660_2500}, 470dbdc025bSLars-Peter Clausen {"ad5660-1250", ID_AD5660_1250}, 471dbdc025bSLars-Peter Clausen {"ad5662", ID_AD5662}, 4729cad3b98SLukas Wunner {"dac081s101", ID_AD5300}, /* compatible Texas Instruments chips */ 4739cad3b98SLukas Wunner {"dac101s101", ID_AD5310}, 4749cad3b98SLukas Wunner {"dac121s101", ID_AD5320}, 47549b3f874SLukas Wunner {"dac7512", ID_AD5320}, 476dbdc025bSLars-Peter Clausen {} 477dbdc025bSLars-Peter Clausen }; 4783ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); 479dbdc025bSLars-Peter Clausen 48049b3f874SLukas Wunner static const struct of_device_id ad5446_of_ids[] = { 48149b3f874SLukas Wunner { .compatible = "ti,dac7512" }, 48249b3f874SLukas Wunner { } 48349b3f874SLukas Wunner }; 48449b3f874SLukas Wunner MODULE_DEVICE_TABLE(of, ad5446_of_ids); 48549b3f874SLukas Wunner 486fc52692cSGreg Kroah-Hartman static int ad5446_spi_probe(struct spi_device *spi) 4873ec36a2cSJean-Francois Dagenais { 4883ec36a2cSJean-Francois Dagenais const struct spi_device_id *id = spi_get_device_id(spi); 4893ec36a2cSJean-Francois Dagenais 4903ec36a2cSJean-Francois Dagenais return ad5446_probe(&spi->dev, id->name, 4913ec36a2cSJean-Francois Dagenais &ad5446_spi_chip_info[id->driver_data]); 4923ec36a2cSJean-Francois Dagenais } 4933ec36a2cSJean-Francois Dagenais 494fc52692cSGreg Kroah-Hartman static int ad5446_spi_remove(struct spi_device *spi) 4953ec36a2cSJean-Francois Dagenais { 4961f10848fSUwe Kleine-König ad5446_remove(&spi->dev); 4971f10848fSUwe Kleine-König 4981f10848fSUwe Kleine-König return 0; 4993ec36a2cSJean-Francois Dagenais } 5003ec36a2cSJean-Francois Dagenais 5013ec36a2cSJean-Francois Dagenais static struct spi_driver ad5446_spi_driver = { 502dbdc025bSLars-Peter Clausen .driver = { 503dbdc025bSLars-Peter Clausen .name = "ad5446", 504b49e6eb1SJonathan Cameron .of_match_table = ad5446_of_ids, 505dbdc025bSLars-Peter Clausen }, 5063ec36a2cSJean-Francois Dagenais .probe = ad5446_spi_probe, 507fc52692cSGreg Kroah-Hartman .remove = ad5446_spi_remove, 5083ec36a2cSJean-Francois Dagenais .id_table = ad5446_spi_ids, 509dbdc025bSLars-Peter Clausen }; 5103ec36a2cSJean-Francois Dagenais 5113ec36a2cSJean-Francois Dagenais static int __init ad5446_spi_register_driver(void) 5123ec36a2cSJean-Francois Dagenais { 5133ec36a2cSJean-Francois Dagenais return spi_register_driver(&ad5446_spi_driver); 5143ec36a2cSJean-Francois Dagenais } 5153ec36a2cSJean-Francois Dagenais 5163ec36a2cSJean-Francois Dagenais static void ad5446_spi_unregister_driver(void) 5173ec36a2cSJean-Francois Dagenais { 5183ec36a2cSJean-Francois Dagenais spi_unregister_driver(&ad5446_spi_driver); 5193ec36a2cSJean-Francois Dagenais } 5203ec36a2cSJean-Francois Dagenais 5213ec36a2cSJean-Francois Dagenais #else 5223ec36a2cSJean-Francois Dagenais 5233ec36a2cSJean-Francois Dagenais static inline int ad5446_spi_register_driver(void) { return 0; } 5243ec36a2cSJean-Francois Dagenais static inline void ad5446_spi_unregister_driver(void) { } 5253ec36a2cSJean-Francois Dagenais 5263ec36a2cSJean-Francois Dagenais #endif 5273ec36a2cSJean-Francois Dagenais 5283ec36a2cSJean-Francois Dagenais #if IS_ENABLED(CONFIG_I2C) 5293ec36a2cSJean-Francois Dagenais 5303ec36a2cSJean-Francois Dagenais static int ad5622_write(struct ad5446_state *st, unsigned val) 5313ec36a2cSJean-Francois Dagenais { 5323ec36a2cSJean-Francois Dagenais struct i2c_client *client = to_i2c_client(st->dev); 5333ec36a2cSJean-Francois Dagenais __be16 data = cpu_to_be16(val); 534558df982SPekka Korpinen int ret; 5353ec36a2cSJean-Francois Dagenais 536558df982SPekka Korpinen ret = i2c_master_send(client, (char *)&data, sizeof(data)); 537558df982SPekka Korpinen if (ret < 0) 538558df982SPekka Korpinen return ret; 539558df982SPekka Korpinen if (ret != sizeof(data)) 540558df982SPekka Korpinen return -EIO; 541558df982SPekka Korpinen 542558df982SPekka Korpinen return 0; 5433ec36a2cSJean-Francois Dagenais } 5443ec36a2cSJean-Francois Dagenais 545af390b8cSLee Jones /* 5463ec36a2cSJean-Francois Dagenais * ad5446_supported_i2c_device_ids: 5473ec36a2cSJean-Francois Dagenais * The AD5620/40/60 parts are available in different fixed internal reference 5483ec36a2cSJean-Francois Dagenais * voltage options. The actual part numbers may look differently 5493ec36a2cSJean-Francois Dagenais * (and a bit cryptic), however this style is used to make clear which 5503ec36a2cSJean-Francois Dagenais * parts are supported here. 5513ec36a2cSJean-Francois Dagenais */ 5523ec36a2cSJean-Francois Dagenais enum ad5446_supported_i2c_device_ids { 5533ec36a2cSJean-Francois Dagenais ID_AD5602, 5543ec36a2cSJean-Francois Dagenais ID_AD5612, 5553ec36a2cSJean-Francois Dagenais ID_AD5622, 5563ec36a2cSJean-Francois Dagenais }; 5573ec36a2cSJean-Francois Dagenais 5583ec36a2cSJean-Francois Dagenais static const struct ad5446_chip_info ad5446_i2c_chip_info[] = { 5593ec36a2cSJean-Francois Dagenais [ID_AD5602] = { 5603ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), 5613ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5623ec36a2cSJean-Francois Dagenais }, 5633ec36a2cSJean-Francois Dagenais [ID_AD5612] = { 5643ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), 5653ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5663ec36a2cSJean-Francois Dagenais }, 5673ec36a2cSJean-Francois Dagenais [ID_AD5622] = { 5683ec36a2cSJean-Francois Dagenais .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), 5693ec36a2cSJean-Francois Dagenais .write = ad5622_write, 5703ec36a2cSJean-Francois Dagenais }, 5713ec36a2cSJean-Francois Dagenais }; 5723ec36a2cSJean-Francois Dagenais 573fc52692cSGreg Kroah-Hartman static int ad5446_i2c_probe(struct i2c_client *i2c, 5743ec36a2cSJean-Francois Dagenais const struct i2c_device_id *id) 5753ec36a2cSJean-Francois Dagenais { 5763ec36a2cSJean-Francois Dagenais return ad5446_probe(&i2c->dev, id->name, 5773ec36a2cSJean-Francois Dagenais &ad5446_i2c_chip_info[id->driver_data]); 5783ec36a2cSJean-Francois Dagenais } 5793ec36a2cSJean-Francois Dagenais 580fc52692cSGreg Kroah-Hartman static int ad5446_i2c_remove(struct i2c_client *i2c) 5813ec36a2cSJean-Francois Dagenais { 5821f10848fSUwe Kleine-König ad5446_remove(&i2c->dev); 5831f10848fSUwe Kleine-König 5841f10848fSUwe Kleine-König return 0; 5853ec36a2cSJean-Francois Dagenais } 5863ec36a2cSJean-Francois Dagenais 5873ec36a2cSJean-Francois Dagenais static const struct i2c_device_id ad5446_i2c_ids[] = { 588bf832380SLars-Peter Clausen {"ad5301", ID_AD5602}, 589bf832380SLars-Peter Clausen {"ad5311", ID_AD5612}, 590bf832380SLars-Peter Clausen {"ad5321", ID_AD5622}, 5913ec36a2cSJean-Francois Dagenais {"ad5602", ID_AD5602}, 5923ec36a2cSJean-Francois Dagenais {"ad5612", ID_AD5612}, 5933ec36a2cSJean-Francois Dagenais {"ad5622", ID_AD5622}, 5943ec36a2cSJean-Francois Dagenais {} 5953ec36a2cSJean-Francois Dagenais }; 5963ec36a2cSJean-Francois Dagenais MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); 5973ec36a2cSJean-Francois Dagenais 5983ec36a2cSJean-Francois Dagenais static struct i2c_driver ad5446_i2c_driver = { 5993ec36a2cSJean-Francois Dagenais .driver = { 6003ec36a2cSJean-Francois Dagenais .name = "ad5446", 6013ec36a2cSJean-Francois Dagenais }, 6023ec36a2cSJean-Francois Dagenais .probe = ad5446_i2c_probe, 603fc52692cSGreg Kroah-Hartman .remove = ad5446_i2c_remove, 6043ec36a2cSJean-Francois Dagenais .id_table = ad5446_i2c_ids, 6053ec36a2cSJean-Francois Dagenais }; 6063ec36a2cSJean-Francois Dagenais 6073ec36a2cSJean-Francois Dagenais static int __init ad5446_i2c_register_driver(void) 6083ec36a2cSJean-Francois Dagenais { 6093ec36a2cSJean-Francois Dagenais return i2c_add_driver(&ad5446_i2c_driver); 6103ec36a2cSJean-Francois Dagenais } 6113ec36a2cSJean-Francois Dagenais 6123ec36a2cSJean-Francois Dagenais static void __exit ad5446_i2c_unregister_driver(void) 6133ec36a2cSJean-Francois Dagenais { 6143ec36a2cSJean-Francois Dagenais i2c_del_driver(&ad5446_i2c_driver); 6153ec36a2cSJean-Francois Dagenais } 6163ec36a2cSJean-Francois Dagenais 6173ec36a2cSJean-Francois Dagenais #else 6183ec36a2cSJean-Francois Dagenais 6193ec36a2cSJean-Francois Dagenais static inline int ad5446_i2c_register_driver(void) { return 0; } 6203ec36a2cSJean-Francois Dagenais static inline void ad5446_i2c_unregister_driver(void) { } 6213ec36a2cSJean-Francois Dagenais 6223ec36a2cSJean-Francois Dagenais #endif 6233ec36a2cSJean-Francois Dagenais 6243ec36a2cSJean-Francois Dagenais static int __init ad5446_init(void) 6253ec36a2cSJean-Francois Dagenais { 6263ec36a2cSJean-Francois Dagenais int ret; 6273ec36a2cSJean-Francois Dagenais 6283ec36a2cSJean-Francois Dagenais ret = ad5446_spi_register_driver(); 6293ec36a2cSJean-Francois Dagenais if (ret) 6303ec36a2cSJean-Francois Dagenais return ret; 6313ec36a2cSJean-Francois Dagenais 6323ec36a2cSJean-Francois Dagenais ret = ad5446_i2c_register_driver(); 6333ec36a2cSJean-Francois Dagenais if (ret) { 6343ec36a2cSJean-Francois Dagenais ad5446_spi_unregister_driver(); 6353ec36a2cSJean-Francois Dagenais return ret; 6363ec36a2cSJean-Francois Dagenais } 6373ec36a2cSJean-Francois Dagenais 6383ec36a2cSJean-Francois Dagenais return 0; 6393ec36a2cSJean-Francois Dagenais } 6403ec36a2cSJean-Francois Dagenais module_init(ad5446_init); 6413ec36a2cSJean-Francois Dagenais 6423ec36a2cSJean-Francois Dagenais static void __exit ad5446_exit(void) 6433ec36a2cSJean-Francois Dagenais { 6443ec36a2cSJean-Francois Dagenais ad5446_i2c_unregister_driver(); 6453ec36a2cSJean-Francois Dagenais ad5446_spi_unregister_driver(); 6463ec36a2cSJean-Francois Dagenais } 6473ec36a2cSJean-Francois Dagenais module_exit(ad5446_exit); 648dbdc025bSLars-Peter Clausen 6499920ed25SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 650dbdc025bSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); 651dbdc025bSLars-Peter Clausen MODULE_LICENSE("GPL v2"); 652