1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 202b829f9SMaxime Roussin-Belanger /* 302b829f9SMaxime Roussin-Belanger * LTC2632 Digital to analog convertors spi driver 402b829f9SMaxime Roussin-Belanger * 53723c632SArnd Bergmann * Copyright 2017 Maxime Roussin-Bélanger 69ff1d500SSilvan Murer * expanded by Silvan Murer <silvan.murer@gmail.com> 702b829f9SMaxime Roussin-Belanger */ 802b829f9SMaxime Roussin-Belanger 902b829f9SMaxime Roussin-Belanger #include <linux/device.h> 1002b829f9SMaxime Roussin-Belanger #include <linux/spi/spi.h> 1102b829f9SMaxime Roussin-Belanger #include <linux/module.h> 1202b829f9SMaxime Roussin-Belanger #include <linux/iio/iio.h> 13*a9d1a34fSAndy Shevchenko #include <linux/property.h> 149ff1d500SSilvan Murer #include <linux/regulator/consumer.h> 1502b829f9SMaxime Roussin-Belanger 168b26ab33SAndy Shevchenko #include <asm/unaligned.h> 178b26ab33SAndy Shevchenko 1802b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N 0x0 1902b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_UPDATE_DAC_N 0x1 2002b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 2102b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N 0x3 2202b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_POWERDOWN_DAC_N 0x4 2302b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_POWERDOWN_CHIP 0x5 2402b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_INTERNAL_REFER 0x6 2502b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_EXTERNAL_REFER 0x7 2602b829f9SMaxime Roussin-Belanger 2702b829f9SMaxime Roussin-Belanger /** 2802b829f9SMaxime Roussin-Belanger * struct ltc2632_chip_info - chip specific information 2902b829f9SMaxime Roussin-Belanger * @channels: channel spec for the DAC 30aefa5bc8SChris Ruehl * @num_channels: DAC channel count of the chip 319ff1d500SSilvan Murer * @vref_mv: internal reference voltage 3202b829f9SMaxime Roussin-Belanger */ 3302b829f9SMaxime Roussin-Belanger struct ltc2632_chip_info { 3402b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *channels; 359f15a4a0SUwe Kleine-König const size_t num_channels; 3602b829f9SMaxime Roussin-Belanger const int vref_mv; 3702b829f9SMaxime Roussin-Belanger }; 3802b829f9SMaxime Roussin-Belanger 3902b829f9SMaxime Roussin-Belanger /** 4002b829f9SMaxime Roussin-Belanger * struct ltc2632_state - driver instance specific data 4102b829f9SMaxime Roussin-Belanger * @spi_dev: pointer to the spi_device struct 420f2a3461SLee Jones * @powerdown_cache_mask: used to show current channel powerdown state 430f2a3461SLee Jones * @vref_mv: used reference voltage (internal or external) 440f2a3461SLee Jones * @vref_reg: regulator for the reference voltage 4502b829f9SMaxime Roussin-Belanger */ 4602b829f9SMaxime Roussin-Belanger struct ltc2632_state { 4702b829f9SMaxime Roussin-Belanger struct spi_device *spi_dev; 4802b829f9SMaxime Roussin-Belanger unsigned int powerdown_cache_mask; 499ff1d500SSilvan Murer int vref_mv; 509ff1d500SSilvan Murer struct regulator *vref_reg; 5102b829f9SMaxime Roussin-Belanger }; 5202b829f9SMaxime Roussin-Belanger 5302b829f9SMaxime Roussin-Belanger enum ltc2632_supported_device_ids { 5402b829f9SMaxime Roussin-Belanger ID_LTC2632L12, 5502b829f9SMaxime Roussin-Belanger ID_LTC2632L10, 5602b829f9SMaxime Roussin-Belanger ID_LTC2632L8, 5702b829f9SMaxime Roussin-Belanger ID_LTC2632H12, 5802b829f9SMaxime Roussin-Belanger ID_LTC2632H10, 5902b829f9SMaxime Roussin-Belanger ID_LTC2632H8, 606f1c9e0dSChris Ruehl ID_LTC2634L12, 616f1c9e0dSChris Ruehl ID_LTC2634L10, 626f1c9e0dSChris Ruehl ID_LTC2634L8, 636f1c9e0dSChris Ruehl ID_LTC2634H12, 646f1c9e0dSChris Ruehl ID_LTC2634H10, 656f1c9e0dSChris Ruehl ID_LTC2634H8, 669f15a4a0SUwe Kleine-König ID_LTC2636L12, 679f15a4a0SUwe Kleine-König ID_LTC2636L10, 689f15a4a0SUwe Kleine-König ID_LTC2636L8, 699f15a4a0SUwe Kleine-König ID_LTC2636H12, 709f15a4a0SUwe Kleine-König ID_LTC2636H10, 719f15a4a0SUwe Kleine-König ID_LTC2636H8, 7202b829f9SMaxime Roussin-Belanger }; 7302b829f9SMaxime Roussin-Belanger 7402b829f9SMaxime Roussin-Belanger static int ltc2632_spi_write(struct spi_device *spi, 7502b829f9SMaxime Roussin-Belanger u8 cmd, u8 addr, u16 val, u8 shift) 7602b829f9SMaxime Roussin-Belanger { 7702b829f9SMaxime Roussin-Belanger u32 data; 7802b829f9SMaxime Roussin-Belanger u8 msg[3]; 7902b829f9SMaxime Roussin-Belanger 8002b829f9SMaxime Roussin-Belanger /* 8102b829f9SMaxime Roussin-Belanger * The input shift register is 24 bits wide. 8202b829f9SMaxime Roussin-Belanger * The next four are the command bits, C3 to C0, 8302b829f9SMaxime Roussin-Belanger * followed by the 4-bit DAC address, A3 to A0, and then the 8402b829f9SMaxime Roussin-Belanger * 12-, 10-, 8-bit data-word. The data-word comprises the 12-, 8502b829f9SMaxime Roussin-Belanger * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits. 8602b829f9SMaxime Roussin-Belanger */ 8702b829f9SMaxime Roussin-Belanger data = (cmd << 20) | (addr << 16) | (val << shift); 888b26ab33SAndy Shevchenko put_unaligned_be24(data, &msg[0]); 8902b829f9SMaxime Roussin-Belanger 9002b829f9SMaxime Roussin-Belanger return spi_write(spi, msg, sizeof(msg)); 9102b829f9SMaxime Roussin-Belanger } 9202b829f9SMaxime Roussin-Belanger 9302b829f9SMaxime Roussin-Belanger static int ltc2632_read_raw(struct iio_dev *indio_dev, 9402b829f9SMaxime Roussin-Belanger struct iio_chan_spec const *chan, 9502b829f9SMaxime Roussin-Belanger int *val, 9602b829f9SMaxime Roussin-Belanger int *val2, 9702b829f9SMaxime Roussin-Belanger long m) 9802b829f9SMaxime Roussin-Belanger { 9902b829f9SMaxime Roussin-Belanger const struct ltc2632_state *st = iio_priv(indio_dev); 10002b829f9SMaxime Roussin-Belanger 10102b829f9SMaxime Roussin-Belanger switch (m) { 10202b829f9SMaxime Roussin-Belanger case IIO_CHAN_INFO_SCALE: 1039ff1d500SSilvan Murer *val = st->vref_mv; 10402b829f9SMaxime Roussin-Belanger *val2 = chan->scan_type.realbits; 10502b829f9SMaxime Roussin-Belanger return IIO_VAL_FRACTIONAL_LOG2; 10602b829f9SMaxime Roussin-Belanger } 10702b829f9SMaxime Roussin-Belanger return -EINVAL; 10802b829f9SMaxime Roussin-Belanger } 10902b829f9SMaxime Roussin-Belanger 11002b829f9SMaxime Roussin-Belanger static int ltc2632_write_raw(struct iio_dev *indio_dev, 11102b829f9SMaxime Roussin-Belanger struct iio_chan_spec const *chan, 11202b829f9SMaxime Roussin-Belanger int val, 11302b829f9SMaxime Roussin-Belanger int val2, 11402b829f9SMaxime Roussin-Belanger long mask) 11502b829f9SMaxime Roussin-Belanger { 11602b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 11702b829f9SMaxime Roussin-Belanger 11802b829f9SMaxime Roussin-Belanger switch (mask) { 11902b829f9SMaxime Roussin-Belanger case IIO_CHAN_INFO_RAW: 12002b829f9SMaxime Roussin-Belanger if (val >= (1 << chan->scan_type.realbits) || val < 0) 12102b829f9SMaxime Roussin-Belanger return -EINVAL; 12202b829f9SMaxime Roussin-Belanger 12302b829f9SMaxime Roussin-Belanger return ltc2632_spi_write(st->spi_dev, 12402b829f9SMaxime Roussin-Belanger LTC2632_CMD_WRITE_INPUT_N_UPDATE_N, 12502b829f9SMaxime Roussin-Belanger chan->address, val, 12602b829f9SMaxime Roussin-Belanger chan->scan_type.shift); 12702b829f9SMaxime Roussin-Belanger default: 12802b829f9SMaxime Roussin-Belanger return -EINVAL; 12902b829f9SMaxime Roussin-Belanger } 13002b829f9SMaxime Roussin-Belanger } 13102b829f9SMaxime Roussin-Belanger 13202b829f9SMaxime Roussin-Belanger static ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev, 13302b829f9SMaxime Roussin-Belanger uintptr_t private, 13402b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *chan, 13502b829f9SMaxime Roussin-Belanger char *buf) 13602b829f9SMaxime Roussin-Belanger { 13702b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 13802b829f9SMaxime Roussin-Belanger 139f46ac009SLars-Peter Clausen return sysfs_emit(buf, "%d\n", 14002b829f9SMaxime Roussin-Belanger !!(st->powerdown_cache_mask & (1 << chan->channel))); 14102b829f9SMaxime Roussin-Belanger } 14202b829f9SMaxime Roussin-Belanger 14302b829f9SMaxime Roussin-Belanger static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev, 14402b829f9SMaxime Roussin-Belanger uintptr_t private, 14502b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *chan, 14602b829f9SMaxime Roussin-Belanger const char *buf, 14702b829f9SMaxime Roussin-Belanger size_t len) 14802b829f9SMaxime Roussin-Belanger { 14902b829f9SMaxime Roussin-Belanger bool pwr_down; 15002b829f9SMaxime Roussin-Belanger int ret; 15102b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 15202b829f9SMaxime Roussin-Belanger 15374f582ecSLars-Peter Clausen ret = kstrtobool(buf, &pwr_down); 15402b829f9SMaxime Roussin-Belanger if (ret) 15502b829f9SMaxime Roussin-Belanger return ret; 15602b829f9SMaxime Roussin-Belanger 15702b829f9SMaxime Roussin-Belanger if (pwr_down) 15802b829f9SMaxime Roussin-Belanger st->powerdown_cache_mask |= (1 << chan->channel); 15902b829f9SMaxime Roussin-Belanger else 16002b829f9SMaxime Roussin-Belanger st->powerdown_cache_mask &= ~(1 << chan->channel); 16102b829f9SMaxime Roussin-Belanger 16202b829f9SMaxime Roussin-Belanger ret = ltc2632_spi_write(st->spi_dev, 16302b829f9SMaxime Roussin-Belanger LTC2632_CMD_POWERDOWN_DAC_N, 16402b829f9SMaxime Roussin-Belanger chan->channel, 0, 0); 16502b829f9SMaxime Roussin-Belanger 16602b829f9SMaxime Roussin-Belanger return ret ? ret : len; 16702b829f9SMaxime Roussin-Belanger } 16802b829f9SMaxime Roussin-Belanger 16902b829f9SMaxime Roussin-Belanger static const struct iio_info ltc2632_info = { 17002b829f9SMaxime Roussin-Belanger .write_raw = ltc2632_write_raw, 17102b829f9SMaxime Roussin-Belanger .read_raw = ltc2632_read_raw, 17202b829f9SMaxime Roussin-Belanger }; 17302b829f9SMaxime Roussin-Belanger 17402b829f9SMaxime Roussin-Belanger static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = { 17502b829f9SMaxime Roussin-Belanger { 17602b829f9SMaxime Roussin-Belanger .name = "powerdown", 17702b829f9SMaxime Roussin-Belanger .read = ltc2632_read_dac_powerdown, 17802b829f9SMaxime Roussin-Belanger .write = ltc2632_write_dac_powerdown, 17902b829f9SMaxime Roussin-Belanger .shared = IIO_SEPARATE, 18002b829f9SMaxime Roussin-Belanger }, 18102b829f9SMaxime Roussin-Belanger { }, 18202b829f9SMaxime Roussin-Belanger }; 18302b829f9SMaxime Roussin-Belanger 18402b829f9SMaxime Roussin-Belanger #define LTC2632_CHANNEL(_chan, _bits) { \ 18502b829f9SMaxime Roussin-Belanger .type = IIO_VOLTAGE, \ 18602b829f9SMaxime Roussin-Belanger .indexed = 1, \ 18702b829f9SMaxime Roussin-Belanger .output = 1, \ 18802b829f9SMaxime Roussin-Belanger .channel = (_chan), \ 18902b829f9SMaxime Roussin-Belanger .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 19002b829f9SMaxime Roussin-Belanger .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 19102b829f9SMaxime Roussin-Belanger .address = (_chan), \ 19202b829f9SMaxime Roussin-Belanger .scan_type = { \ 19302b829f9SMaxime Roussin-Belanger .realbits = (_bits), \ 19402b829f9SMaxime Roussin-Belanger .shift = 16 - (_bits), \ 19502b829f9SMaxime Roussin-Belanger }, \ 19602b829f9SMaxime Roussin-Belanger .ext_info = ltc2632_ext_info, \ 19702b829f9SMaxime Roussin-Belanger } 19802b829f9SMaxime Roussin-Belanger 19902b829f9SMaxime Roussin-Belanger #define DECLARE_LTC2632_CHANNELS(_name, _bits) \ 20002b829f9SMaxime Roussin-Belanger const struct iio_chan_spec _name ## _channels[] = { \ 20102b829f9SMaxime Roussin-Belanger LTC2632_CHANNEL(0, _bits), \ 20202b829f9SMaxime Roussin-Belanger LTC2632_CHANNEL(1, _bits), \ 2039f15a4a0SUwe Kleine-König LTC2632_CHANNEL(2, _bits), \ 2049f15a4a0SUwe Kleine-König LTC2632_CHANNEL(3, _bits), \ 2059f15a4a0SUwe Kleine-König LTC2632_CHANNEL(4, _bits), \ 2069f15a4a0SUwe Kleine-König LTC2632_CHANNEL(5, _bits), \ 2079f15a4a0SUwe Kleine-König LTC2632_CHANNEL(6, _bits), \ 2089f15a4a0SUwe Kleine-König LTC2632_CHANNEL(7, _bits), \ 20902b829f9SMaxime Roussin-Belanger } 21002b829f9SMaxime Roussin-Belanger 211f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12); 212f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10); 213f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8); 21402b829f9SMaxime Roussin-Belanger 21502b829f9SMaxime Roussin-Belanger static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = { 21602b829f9SMaxime Roussin-Belanger [ID_LTC2632L12] = { 217f243d0f0SUwe Kleine-König .channels = ltc2632x12_channels, 2189f15a4a0SUwe Kleine-König .num_channels = 2, 21902b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 22002b829f9SMaxime Roussin-Belanger }, 22102b829f9SMaxime Roussin-Belanger [ID_LTC2632L10] = { 222f243d0f0SUwe Kleine-König .channels = ltc2632x10_channels, 2239f15a4a0SUwe Kleine-König .num_channels = 2, 22402b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 22502b829f9SMaxime Roussin-Belanger }, 22602b829f9SMaxime Roussin-Belanger [ID_LTC2632L8] = { 227f243d0f0SUwe Kleine-König .channels = ltc2632x8_channels, 2289f15a4a0SUwe Kleine-König .num_channels = 2, 22902b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 23002b829f9SMaxime Roussin-Belanger }, 23102b829f9SMaxime Roussin-Belanger [ID_LTC2632H12] = { 232f243d0f0SUwe Kleine-König .channels = ltc2632x12_channels, 2339f15a4a0SUwe Kleine-König .num_channels = 2, 23402b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 23502b829f9SMaxime Roussin-Belanger }, 23602b829f9SMaxime Roussin-Belanger [ID_LTC2632H10] = { 237f243d0f0SUwe Kleine-König .channels = ltc2632x10_channels, 2389f15a4a0SUwe Kleine-König .num_channels = 2, 23902b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 24002b829f9SMaxime Roussin-Belanger }, 24102b829f9SMaxime Roussin-Belanger [ID_LTC2632H8] = { 242f243d0f0SUwe Kleine-König .channels = ltc2632x8_channels, 2439f15a4a0SUwe Kleine-König .num_channels = 2, 2449f15a4a0SUwe Kleine-König .vref_mv = 4096, 2459f15a4a0SUwe Kleine-König }, 2466f1c9e0dSChris Ruehl [ID_LTC2634L12] = { 2476f1c9e0dSChris Ruehl .channels = ltc2632x12_channels, 2486f1c9e0dSChris Ruehl .num_channels = 4, 2496f1c9e0dSChris Ruehl .vref_mv = 2500, 2506f1c9e0dSChris Ruehl }, 2516f1c9e0dSChris Ruehl [ID_LTC2634L10] = { 2526f1c9e0dSChris Ruehl .channels = ltc2632x10_channels, 2536f1c9e0dSChris Ruehl .num_channels = 4, 2546f1c9e0dSChris Ruehl .vref_mv = 2500, 2556f1c9e0dSChris Ruehl }, 2566f1c9e0dSChris Ruehl [ID_LTC2634L8] = { 2576f1c9e0dSChris Ruehl .channels = ltc2632x8_channels, 2586f1c9e0dSChris Ruehl .num_channels = 4, 2596f1c9e0dSChris Ruehl .vref_mv = 2500, 2606f1c9e0dSChris Ruehl }, 2616f1c9e0dSChris Ruehl [ID_LTC2634H12] = { 2626f1c9e0dSChris Ruehl .channels = ltc2632x12_channels, 2636f1c9e0dSChris Ruehl .num_channels = 4, 2646f1c9e0dSChris Ruehl .vref_mv = 4096, 2656f1c9e0dSChris Ruehl }, 2666f1c9e0dSChris Ruehl [ID_LTC2634H10] = { 2676f1c9e0dSChris Ruehl .channels = ltc2632x10_channels, 2686f1c9e0dSChris Ruehl .num_channels = 4, 2696f1c9e0dSChris Ruehl .vref_mv = 4096, 2706f1c9e0dSChris Ruehl }, 2716f1c9e0dSChris Ruehl [ID_LTC2634H8] = { 2726f1c9e0dSChris Ruehl .channels = ltc2632x8_channels, 2736f1c9e0dSChris Ruehl .num_channels = 4, 2746f1c9e0dSChris Ruehl .vref_mv = 4096, 2756f1c9e0dSChris Ruehl }, 2769f15a4a0SUwe Kleine-König [ID_LTC2636L12] = { 2779f15a4a0SUwe Kleine-König .channels = ltc2632x12_channels, 2789f15a4a0SUwe Kleine-König .num_channels = 8, 2799f15a4a0SUwe Kleine-König .vref_mv = 2500, 2809f15a4a0SUwe Kleine-König }, 2819f15a4a0SUwe Kleine-König [ID_LTC2636L10] = { 2829f15a4a0SUwe Kleine-König .channels = ltc2632x10_channels, 2839f15a4a0SUwe Kleine-König .num_channels = 8, 2849f15a4a0SUwe Kleine-König .vref_mv = 2500, 2859f15a4a0SUwe Kleine-König }, 2869f15a4a0SUwe Kleine-König [ID_LTC2636L8] = { 2879f15a4a0SUwe Kleine-König .channels = ltc2632x8_channels, 2889f15a4a0SUwe Kleine-König .num_channels = 8, 2899f15a4a0SUwe Kleine-König .vref_mv = 2500, 2909f15a4a0SUwe Kleine-König }, 2919f15a4a0SUwe Kleine-König [ID_LTC2636H12] = { 2929f15a4a0SUwe Kleine-König .channels = ltc2632x12_channels, 2939f15a4a0SUwe Kleine-König .num_channels = 8, 2949f15a4a0SUwe Kleine-König .vref_mv = 4096, 2959f15a4a0SUwe Kleine-König }, 2969f15a4a0SUwe Kleine-König [ID_LTC2636H10] = { 2979f15a4a0SUwe Kleine-König .channels = ltc2632x10_channels, 2989f15a4a0SUwe Kleine-König .num_channels = 8, 2999f15a4a0SUwe Kleine-König .vref_mv = 4096, 3009f15a4a0SUwe Kleine-König }, 3019f15a4a0SUwe Kleine-König [ID_LTC2636H8] = { 3029f15a4a0SUwe Kleine-König .channels = ltc2632x8_channels, 3039f15a4a0SUwe Kleine-König .num_channels = 8, 30402b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 30502b829f9SMaxime Roussin-Belanger }, 30602b829f9SMaxime Roussin-Belanger }; 30702b829f9SMaxime Roussin-Belanger 30802b829f9SMaxime Roussin-Belanger static int ltc2632_probe(struct spi_device *spi) 30902b829f9SMaxime Roussin-Belanger { 31002b829f9SMaxime Roussin-Belanger struct ltc2632_state *st; 31102b829f9SMaxime Roussin-Belanger struct iio_dev *indio_dev; 31202b829f9SMaxime Roussin-Belanger struct ltc2632_chip_info *chip_info; 31302b829f9SMaxime Roussin-Belanger int ret; 31402b829f9SMaxime Roussin-Belanger 31502b829f9SMaxime Roussin-Belanger indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 31602b829f9SMaxime Roussin-Belanger if (!indio_dev) 31702b829f9SMaxime Roussin-Belanger return -ENOMEM; 31802b829f9SMaxime Roussin-Belanger 31902b829f9SMaxime Roussin-Belanger st = iio_priv(indio_dev); 32002b829f9SMaxime Roussin-Belanger 32102b829f9SMaxime Roussin-Belanger spi_set_drvdata(spi, indio_dev); 32202b829f9SMaxime Roussin-Belanger st->spi_dev = spi; 32302b829f9SMaxime Roussin-Belanger 32402b829f9SMaxime Roussin-Belanger chip_info = (struct ltc2632_chip_info *) 32502b829f9SMaxime Roussin-Belanger spi_get_device_id(spi)->driver_data; 32602b829f9SMaxime Roussin-Belanger 3279ff1d500SSilvan Murer st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); 3289ff1d500SSilvan Murer if (PTR_ERR(st->vref_reg) == -ENODEV) { 3299ff1d500SSilvan Murer /* use internal reference voltage */ 3309ff1d500SSilvan Murer st->vref_reg = NULL; 3319ff1d500SSilvan Murer st->vref_mv = chip_info->vref_mv; 3329ff1d500SSilvan Murer 3339ff1d500SSilvan Murer ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, 3349ff1d500SSilvan Murer 0, 0, 0); 3359ff1d500SSilvan Murer if (ret) { 3369ff1d500SSilvan Murer dev_err(&spi->dev, 3379ff1d500SSilvan Murer "Set internal reference command failed, %d\n", 3389ff1d500SSilvan Murer ret); 3399ff1d500SSilvan Murer return ret; 3409ff1d500SSilvan Murer } 3419ff1d500SSilvan Murer } else if (IS_ERR(st->vref_reg)) { 3429ff1d500SSilvan Murer dev_err(&spi->dev, 3439ff1d500SSilvan Murer "Error getting voltage reference regulator\n"); 3449ff1d500SSilvan Murer return PTR_ERR(st->vref_reg); 3459ff1d500SSilvan Murer } else { 3469ff1d500SSilvan Murer /* use external reference voltage */ 3479ff1d500SSilvan Murer ret = regulator_enable(st->vref_reg); 3489ff1d500SSilvan Murer if (ret) { 3499ff1d500SSilvan Murer dev_err(&spi->dev, 3509ff1d500SSilvan Murer "enable reference regulator failed, %d\n", 3519ff1d500SSilvan Murer ret); 3529ff1d500SSilvan Murer return ret; 3539ff1d500SSilvan Murer } 3549ff1d500SSilvan Murer st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000; 3559ff1d500SSilvan Murer 3569ff1d500SSilvan Murer ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER, 3579ff1d500SSilvan Murer 0, 0, 0); 3589ff1d500SSilvan Murer if (ret) { 3599ff1d500SSilvan Murer dev_err(&spi->dev, 3609ff1d500SSilvan Murer "Set external reference command failed, %d\n", 3619ff1d500SSilvan Murer ret); 3629ff1d500SSilvan Murer return ret; 3639ff1d500SSilvan Murer } 3649ff1d500SSilvan Murer } 3659ff1d500SSilvan Murer 366*a9d1a34fSAndy Shevchenko indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name; 36702b829f9SMaxime Roussin-Belanger indio_dev->info = <c2632_info; 36802b829f9SMaxime Roussin-Belanger indio_dev->modes = INDIO_DIRECT_MODE; 36902b829f9SMaxime Roussin-Belanger indio_dev->channels = chip_info->channels; 3709f15a4a0SUwe Kleine-König indio_dev->num_channels = chip_info->num_channels; 37102b829f9SMaxime Roussin-Belanger 3729ff1d500SSilvan Murer return iio_device_register(indio_dev); 37302b829f9SMaxime Roussin-Belanger } 37402b829f9SMaxime Roussin-Belanger 375a0386bbaSUwe Kleine-König static void ltc2632_remove(struct spi_device *spi) 3769ff1d500SSilvan Murer { 3779ff1d500SSilvan Murer struct iio_dev *indio_dev = spi_get_drvdata(spi); 3789ff1d500SSilvan Murer struct ltc2632_state *st = iio_priv(indio_dev); 3799ff1d500SSilvan Murer 3809ff1d500SSilvan Murer iio_device_unregister(indio_dev); 3819ff1d500SSilvan Murer 3829ff1d500SSilvan Murer if (st->vref_reg) 3839ff1d500SSilvan Murer regulator_disable(st->vref_reg); 38402b829f9SMaxime Roussin-Belanger } 38502b829f9SMaxime Roussin-Belanger 38602b829f9SMaxime Roussin-Belanger static const struct spi_device_id ltc2632_id[] = { 38702b829f9SMaxime Roussin-Belanger { "ltc2632-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L12] }, 38802b829f9SMaxime Roussin-Belanger { "ltc2632-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L10] }, 38902b829f9SMaxime Roussin-Belanger { "ltc2632-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L8] }, 39002b829f9SMaxime Roussin-Belanger { "ltc2632-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H12] }, 39102b829f9SMaxime Roussin-Belanger { "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] }, 39202b829f9SMaxime Roussin-Belanger { "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] }, 3936f1c9e0dSChris Ruehl { "ltc2634-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L12] }, 3946f1c9e0dSChris Ruehl { "ltc2634-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L10] }, 3956f1c9e0dSChris Ruehl { "ltc2634-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L8] }, 3966f1c9e0dSChris Ruehl { "ltc2634-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H12] }, 3976f1c9e0dSChris Ruehl { "ltc2634-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H10] }, 3986f1c9e0dSChris Ruehl { "ltc2634-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H8] }, 3999f15a4a0SUwe Kleine-König { "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] }, 4009f15a4a0SUwe Kleine-König { "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] }, 4019f15a4a0SUwe Kleine-König { "ltc2636-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L8] }, 4029f15a4a0SUwe Kleine-König { "ltc2636-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H12] }, 4039f15a4a0SUwe Kleine-König { "ltc2636-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H10] }, 4049f15a4a0SUwe Kleine-König { "ltc2636-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H8] }, 40502b829f9SMaxime Roussin-Belanger {} 40602b829f9SMaxime Roussin-Belanger }; 40702b829f9SMaxime Roussin-Belanger MODULE_DEVICE_TABLE(spi, ltc2632_id); 40802b829f9SMaxime Roussin-Belanger 40902b829f9SMaxime Roussin-Belanger static const struct of_device_id ltc2632_of_match[] = { 41002b829f9SMaxime Roussin-Belanger { 41102b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l12", 41202b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L12] 41302b829f9SMaxime Roussin-Belanger }, { 41402b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l10", 41502b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L10] 41602b829f9SMaxime Roussin-Belanger }, { 41702b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l8", 41802b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L8] 41902b829f9SMaxime Roussin-Belanger }, { 42002b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h12", 42102b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H12] 42202b829f9SMaxime Roussin-Belanger }, { 42302b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h10", 42402b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H10] 42502b829f9SMaxime Roussin-Belanger }, { 42602b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h8", 42702b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H8] 4289f15a4a0SUwe Kleine-König }, { 4296f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l12", 4306f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L12] 4316f1c9e0dSChris Ruehl }, { 4326f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l10", 4336f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L10] 4346f1c9e0dSChris Ruehl }, { 4356f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l8", 4366f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L8] 4376f1c9e0dSChris Ruehl }, { 4386f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h12", 4396f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H12] 4406f1c9e0dSChris Ruehl }, { 4416f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h10", 4426f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H10] 4436f1c9e0dSChris Ruehl }, { 4446f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h8", 4456f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H8] 4466f1c9e0dSChris Ruehl }, { 4479f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l12", 4489f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L12] 4499f15a4a0SUwe Kleine-König }, { 4509f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l10", 4519f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L10] 4529f15a4a0SUwe Kleine-König }, { 4539f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l8", 4549f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L8] 4559f15a4a0SUwe Kleine-König }, { 4569f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h12", 4579f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H12] 4589f15a4a0SUwe Kleine-König }, { 4599f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h10", 4609f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H10] 4619f15a4a0SUwe Kleine-König }, { 4629f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h8", 4639f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H8] 46402b829f9SMaxime Roussin-Belanger }, 46502b829f9SMaxime Roussin-Belanger {} 46602b829f9SMaxime Roussin-Belanger }; 46702b829f9SMaxime Roussin-Belanger MODULE_DEVICE_TABLE(of, ltc2632_of_match); 46802b829f9SMaxime Roussin-Belanger 4690f6a2165SSilvan Murer static struct spi_driver ltc2632_driver = { 4700f6a2165SSilvan Murer .driver = { 4710f6a2165SSilvan Murer .name = "ltc2632", 472*a9d1a34fSAndy Shevchenko .of_match_table = ltc2632_of_match, 4730f6a2165SSilvan Murer }, 4740f6a2165SSilvan Murer .probe = ltc2632_probe, 4759ff1d500SSilvan Murer .remove = ltc2632_remove, 4760f6a2165SSilvan Murer .id_table = ltc2632_id, 4770f6a2165SSilvan Murer }; 4780f6a2165SSilvan Murer module_spi_driver(ltc2632_driver); 4790f6a2165SSilvan Murer 48002b829f9SMaxime Roussin-Belanger MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); 48102b829f9SMaxime Roussin-Belanger MODULE_DESCRIPTION("LTC2632 DAC SPI driver"); 48202b829f9SMaxime Roussin-Belanger MODULE_LICENSE("GPL v2"); 483