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> 139ff1d500SSilvan Murer #include <linux/regulator/consumer.h> 1402b829f9SMaxime Roussin-Belanger 158b26ab33SAndy Shevchenko #include <asm/unaligned.h> 168b26ab33SAndy Shevchenko 1702b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N 0x0 1802b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_UPDATE_DAC_N 0x1 1902b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 2002b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N 0x3 2102b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_POWERDOWN_DAC_N 0x4 2202b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_POWERDOWN_CHIP 0x5 2302b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_INTERNAL_REFER 0x6 2402b829f9SMaxime Roussin-Belanger #define LTC2632_CMD_EXTERNAL_REFER 0x7 2502b829f9SMaxime Roussin-Belanger 2602b829f9SMaxime Roussin-Belanger /** 2702b829f9SMaxime Roussin-Belanger * struct ltc2632_chip_info - chip specific information 2802b829f9SMaxime Roussin-Belanger * @channels: channel spec for the DAC 29aefa5bc8SChris Ruehl * @num_channels: DAC channel count of the chip 309ff1d500SSilvan Murer * @vref_mv: internal reference voltage 3102b829f9SMaxime Roussin-Belanger */ 3202b829f9SMaxime Roussin-Belanger struct ltc2632_chip_info { 3302b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *channels; 349f15a4a0SUwe Kleine-König const size_t num_channels; 3502b829f9SMaxime Roussin-Belanger const int vref_mv; 3602b829f9SMaxime Roussin-Belanger }; 3702b829f9SMaxime Roussin-Belanger 3802b829f9SMaxime Roussin-Belanger /** 3902b829f9SMaxime Roussin-Belanger * struct ltc2632_state - driver instance specific data 4002b829f9SMaxime Roussin-Belanger * @spi_dev: pointer to the spi_device struct 41*0f2a3461SLee Jones * @powerdown_cache_mask: used to show current channel powerdown state 42*0f2a3461SLee Jones * @vref_mv: used reference voltage (internal or external) 43*0f2a3461SLee Jones * @vref_reg: regulator for the reference voltage 4402b829f9SMaxime Roussin-Belanger */ 4502b829f9SMaxime Roussin-Belanger struct ltc2632_state { 4602b829f9SMaxime Roussin-Belanger struct spi_device *spi_dev; 4702b829f9SMaxime Roussin-Belanger unsigned int powerdown_cache_mask; 489ff1d500SSilvan Murer int vref_mv; 499ff1d500SSilvan Murer struct regulator *vref_reg; 5002b829f9SMaxime Roussin-Belanger }; 5102b829f9SMaxime Roussin-Belanger 5202b829f9SMaxime Roussin-Belanger enum ltc2632_supported_device_ids { 5302b829f9SMaxime Roussin-Belanger ID_LTC2632L12, 5402b829f9SMaxime Roussin-Belanger ID_LTC2632L10, 5502b829f9SMaxime Roussin-Belanger ID_LTC2632L8, 5602b829f9SMaxime Roussin-Belanger ID_LTC2632H12, 5702b829f9SMaxime Roussin-Belanger ID_LTC2632H10, 5802b829f9SMaxime Roussin-Belanger ID_LTC2632H8, 596f1c9e0dSChris Ruehl ID_LTC2634L12, 606f1c9e0dSChris Ruehl ID_LTC2634L10, 616f1c9e0dSChris Ruehl ID_LTC2634L8, 626f1c9e0dSChris Ruehl ID_LTC2634H12, 636f1c9e0dSChris Ruehl ID_LTC2634H10, 646f1c9e0dSChris Ruehl ID_LTC2634H8, 659f15a4a0SUwe Kleine-König ID_LTC2636L12, 669f15a4a0SUwe Kleine-König ID_LTC2636L10, 679f15a4a0SUwe Kleine-König ID_LTC2636L8, 689f15a4a0SUwe Kleine-König ID_LTC2636H12, 699f15a4a0SUwe Kleine-König ID_LTC2636H10, 709f15a4a0SUwe Kleine-König ID_LTC2636H8, 7102b829f9SMaxime Roussin-Belanger }; 7202b829f9SMaxime Roussin-Belanger 7302b829f9SMaxime Roussin-Belanger static int ltc2632_spi_write(struct spi_device *spi, 7402b829f9SMaxime Roussin-Belanger u8 cmd, u8 addr, u16 val, u8 shift) 7502b829f9SMaxime Roussin-Belanger { 7602b829f9SMaxime Roussin-Belanger u32 data; 7702b829f9SMaxime Roussin-Belanger u8 msg[3]; 7802b829f9SMaxime Roussin-Belanger 7902b829f9SMaxime Roussin-Belanger /* 8002b829f9SMaxime Roussin-Belanger * The input shift register is 24 bits wide. 8102b829f9SMaxime Roussin-Belanger * The next four are the command bits, C3 to C0, 8202b829f9SMaxime Roussin-Belanger * followed by the 4-bit DAC address, A3 to A0, and then the 8302b829f9SMaxime Roussin-Belanger * 12-, 10-, 8-bit data-word. The data-word comprises the 12-, 8402b829f9SMaxime Roussin-Belanger * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits. 8502b829f9SMaxime Roussin-Belanger */ 8602b829f9SMaxime Roussin-Belanger data = (cmd << 20) | (addr << 16) | (val << shift); 878b26ab33SAndy Shevchenko put_unaligned_be24(data, &msg[0]); 8802b829f9SMaxime Roussin-Belanger 8902b829f9SMaxime Roussin-Belanger return spi_write(spi, msg, sizeof(msg)); 9002b829f9SMaxime Roussin-Belanger } 9102b829f9SMaxime Roussin-Belanger 9202b829f9SMaxime Roussin-Belanger static int ltc2632_read_raw(struct iio_dev *indio_dev, 9302b829f9SMaxime Roussin-Belanger struct iio_chan_spec const *chan, 9402b829f9SMaxime Roussin-Belanger int *val, 9502b829f9SMaxime Roussin-Belanger int *val2, 9602b829f9SMaxime Roussin-Belanger long m) 9702b829f9SMaxime Roussin-Belanger { 9802b829f9SMaxime Roussin-Belanger const struct ltc2632_state *st = iio_priv(indio_dev); 9902b829f9SMaxime Roussin-Belanger 10002b829f9SMaxime Roussin-Belanger switch (m) { 10102b829f9SMaxime Roussin-Belanger case IIO_CHAN_INFO_SCALE: 1029ff1d500SSilvan Murer *val = st->vref_mv; 10302b829f9SMaxime Roussin-Belanger *val2 = chan->scan_type.realbits; 10402b829f9SMaxime Roussin-Belanger return IIO_VAL_FRACTIONAL_LOG2; 10502b829f9SMaxime Roussin-Belanger } 10602b829f9SMaxime Roussin-Belanger return -EINVAL; 10702b829f9SMaxime Roussin-Belanger } 10802b829f9SMaxime Roussin-Belanger 10902b829f9SMaxime Roussin-Belanger static int ltc2632_write_raw(struct iio_dev *indio_dev, 11002b829f9SMaxime Roussin-Belanger struct iio_chan_spec const *chan, 11102b829f9SMaxime Roussin-Belanger int val, 11202b829f9SMaxime Roussin-Belanger int val2, 11302b829f9SMaxime Roussin-Belanger long mask) 11402b829f9SMaxime Roussin-Belanger { 11502b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 11602b829f9SMaxime Roussin-Belanger 11702b829f9SMaxime Roussin-Belanger switch (mask) { 11802b829f9SMaxime Roussin-Belanger case IIO_CHAN_INFO_RAW: 11902b829f9SMaxime Roussin-Belanger if (val >= (1 << chan->scan_type.realbits) || val < 0) 12002b829f9SMaxime Roussin-Belanger return -EINVAL; 12102b829f9SMaxime Roussin-Belanger 12202b829f9SMaxime Roussin-Belanger return ltc2632_spi_write(st->spi_dev, 12302b829f9SMaxime Roussin-Belanger LTC2632_CMD_WRITE_INPUT_N_UPDATE_N, 12402b829f9SMaxime Roussin-Belanger chan->address, val, 12502b829f9SMaxime Roussin-Belanger chan->scan_type.shift); 12602b829f9SMaxime Roussin-Belanger default: 12702b829f9SMaxime Roussin-Belanger return -EINVAL; 12802b829f9SMaxime Roussin-Belanger } 12902b829f9SMaxime Roussin-Belanger } 13002b829f9SMaxime Roussin-Belanger 13102b829f9SMaxime Roussin-Belanger static ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev, 13202b829f9SMaxime Roussin-Belanger uintptr_t private, 13302b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *chan, 13402b829f9SMaxime Roussin-Belanger char *buf) 13502b829f9SMaxime Roussin-Belanger { 13602b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 13702b829f9SMaxime Roussin-Belanger 13802b829f9SMaxime Roussin-Belanger return sprintf(buf, "%d\n", 13902b829f9SMaxime Roussin-Belanger !!(st->powerdown_cache_mask & (1 << chan->channel))); 14002b829f9SMaxime Roussin-Belanger } 14102b829f9SMaxime Roussin-Belanger 14202b829f9SMaxime Roussin-Belanger static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev, 14302b829f9SMaxime Roussin-Belanger uintptr_t private, 14402b829f9SMaxime Roussin-Belanger const struct iio_chan_spec *chan, 14502b829f9SMaxime Roussin-Belanger const char *buf, 14602b829f9SMaxime Roussin-Belanger size_t len) 14702b829f9SMaxime Roussin-Belanger { 14802b829f9SMaxime Roussin-Belanger bool pwr_down; 14902b829f9SMaxime Roussin-Belanger int ret; 15002b829f9SMaxime Roussin-Belanger struct ltc2632_state *st = iio_priv(indio_dev); 15102b829f9SMaxime Roussin-Belanger 15202b829f9SMaxime Roussin-Belanger ret = strtobool(buf, &pwr_down); 15302b829f9SMaxime Roussin-Belanger if (ret) 15402b829f9SMaxime Roussin-Belanger return ret; 15502b829f9SMaxime Roussin-Belanger 15602b829f9SMaxime Roussin-Belanger if (pwr_down) 15702b829f9SMaxime Roussin-Belanger st->powerdown_cache_mask |= (1 << chan->channel); 15802b829f9SMaxime Roussin-Belanger else 15902b829f9SMaxime Roussin-Belanger st->powerdown_cache_mask &= ~(1 << chan->channel); 16002b829f9SMaxime Roussin-Belanger 16102b829f9SMaxime Roussin-Belanger ret = ltc2632_spi_write(st->spi_dev, 16202b829f9SMaxime Roussin-Belanger LTC2632_CMD_POWERDOWN_DAC_N, 16302b829f9SMaxime Roussin-Belanger chan->channel, 0, 0); 16402b829f9SMaxime Roussin-Belanger 16502b829f9SMaxime Roussin-Belanger return ret ? ret : len; 16602b829f9SMaxime Roussin-Belanger } 16702b829f9SMaxime Roussin-Belanger 16802b829f9SMaxime Roussin-Belanger static const struct iio_info ltc2632_info = { 16902b829f9SMaxime Roussin-Belanger .write_raw = ltc2632_write_raw, 17002b829f9SMaxime Roussin-Belanger .read_raw = ltc2632_read_raw, 17102b829f9SMaxime Roussin-Belanger }; 17202b829f9SMaxime Roussin-Belanger 17302b829f9SMaxime Roussin-Belanger static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = { 17402b829f9SMaxime Roussin-Belanger { 17502b829f9SMaxime Roussin-Belanger .name = "powerdown", 17602b829f9SMaxime Roussin-Belanger .read = ltc2632_read_dac_powerdown, 17702b829f9SMaxime Roussin-Belanger .write = ltc2632_write_dac_powerdown, 17802b829f9SMaxime Roussin-Belanger .shared = IIO_SEPARATE, 17902b829f9SMaxime Roussin-Belanger }, 18002b829f9SMaxime Roussin-Belanger { }, 18102b829f9SMaxime Roussin-Belanger }; 18202b829f9SMaxime Roussin-Belanger 18302b829f9SMaxime Roussin-Belanger #define LTC2632_CHANNEL(_chan, _bits) { \ 18402b829f9SMaxime Roussin-Belanger .type = IIO_VOLTAGE, \ 18502b829f9SMaxime Roussin-Belanger .indexed = 1, \ 18602b829f9SMaxime Roussin-Belanger .output = 1, \ 18702b829f9SMaxime Roussin-Belanger .channel = (_chan), \ 18802b829f9SMaxime Roussin-Belanger .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 18902b829f9SMaxime Roussin-Belanger .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 19002b829f9SMaxime Roussin-Belanger .address = (_chan), \ 19102b829f9SMaxime Roussin-Belanger .scan_type = { \ 19202b829f9SMaxime Roussin-Belanger .realbits = (_bits), \ 19302b829f9SMaxime Roussin-Belanger .shift = 16 - (_bits), \ 19402b829f9SMaxime Roussin-Belanger }, \ 19502b829f9SMaxime Roussin-Belanger .ext_info = ltc2632_ext_info, \ 19602b829f9SMaxime Roussin-Belanger } 19702b829f9SMaxime Roussin-Belanger 19802b829f9SMaxime Roussin-Belanger #define DECLARE_LTC2632_CHANNELS(_name, _bits) \ 19902b829f9SMaxime Roussin-Belanger const struct iio_chan_spec _name ## _channels[] = { \ 20002b829f9SMaxime Roussin-Belanger LTC2632_CHANNEL(0, _bits), \ 20102b829f9SMaxime Roussin-Belanger LTC2632_CHANNEL(1, _bits), \ 2029f15a4a0SUwe Kleine-König LTC2632_CHANNEL(2, _bits), \ 2039f15a4a0SUwe Kleine-König LTC2632_CHANNEL(3, _bits), \ 2049f15a4a0SUwe Kleine-König LTC2632_CHANNEL(4, _bits), \ 2059f15a4a0SUwe Kleine-König LTC2632_CHANNEL(5, _bits), \ 2069f15a4a0SUwe Kleine-König LTC2632_CHANNEL(6, _bits), \ 2079f15a4a0SUwe Kleine-König LTC2632_CHANNEL(7, _bits), \ 20802b829f9SMaxime Roussin-Belanger } 20902b829f9SMaxime Roussin-Belanger 210f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12); 211f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10); 212f243d0f0SUwe Kleine-König static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8); 21302b829f9SMaxime Roussin-Belanger 21402b829f9SMaxime Roussin-Belanger static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = { 21502b829f9SMaxime Roussin-Belanger [ID_LTC2632L12] = { 216f243d0f0SUwe Kleine-König .channels = ltc2632x12_channels, 2179f15a4a0SUwe Kleine-König .num_channels = 2, 21802b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 21902b829f9SMaxime Roussin-Belanger }, 22002b829f9SMaxime Roussin-Belanger [ID_LTC2632L10] = { 221f243d0f0SUwe Kleine-König .channels = ltc2632x10_channels, 2229f15a4a0SUwe Kleine-König .num_channels = 2, 22302b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 22402b829f9SMaxime Roussin-Belanger }, 22502b829f9SMaxime Roussin-Belanger [ID_LTC2632L8] = { 226f243d0f0SUwe Kleine-König .channels = ltc2632x8_channels, 2279f15a4a0SUwe Kleine-König .num_channels = 2, 22802b829f9SMaxime Roussin-Belanger .vref_mv = 2500, 22902b829f9SMaxime Roussin-Belanger }, 23002b829f9SMaxime Roussin-Belanger [ID_LTC2632H12] = { 231f243d0f0SUwe Kleine-König .channels = ltc2632x12_channels, 2329f15a4a0SUwe Kleine-König .num_channels = 2, 23302b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 23402b829f9SMaxime Roussin-Belanger }, 23502b829f9SMaxime Roussin-Belanger [ID_LTC2632H10] = { 236f243d0f0SUwe Kleine-König .channels = ltc2632x10_channels, 2379f15a4a0SUwe Kleine-König .num_channels = 2, 23802b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 23902b829f9SMaxime Roussin-Belanger }, 24002b829f9SMaxime Roussin-Belanger [ID_LTC2632H8] = { 241f243d0f0SUwe Kleine-König .channels = ltc2632x8_channels, 2429f15a4a0SUwe Kleine-König .num_channels = 2, 2439f15a4a0SUwe Kleine-König .vref_mv = 4096, 2449f15a4a0SUwe Kleine-König }, 2456f1c9e0dSChris Ruehl [ID_LTC2634L12] = { 2466f1c9e0dSChris Ruehl .channels = ltc2632x12_channels, 2476f1c9e0dSChris Ruehl .num_channels = 4, 2486f1c9e0dSChris Ruehl .vref_mv = 2500, 2496f1c9e0dSChris Ruehl }, 2506f1c9e0dSChris Ruehl [ID_LTC2634L10] = { 2516f1c9e0dSChris Ruehl .channels = ltc2632x10_channels, 2526f1c9e0dSChris Ruehl .num_channels = 4, 2536f1c9e0dSChris Ruehl .vref_mv = 2500, 2546f1c9e0dSChris Ruehl }, 2556f1c9e0dSChris Ruehl [ID_LTC2634L8] = { 2566f1c9e0dSChris Ruehl .channels = ltc2632x8_channels, 2576f1c9e0dSChris Ruehl .num_channels = 4, 2586f1c9e0dSChris Ruehl .vref_mv = 2500, 2596f1c9e0dSChris Ruehl }, 2606f1c9e0dSChris Ruehl [ID_LTC2634H12] = { 2616f1c9e0dSChris Ruehl .channels = ltc2632x12_channels, 2626f1c9e0dSChris Ruehl .num_channels = 4, 2636f1c9e0dSChris Ruehl .vref_mv = 4096, 2646f1c9e0dSChris Ruehl }, 2656f1c9e0dSChris Ruehl [ID_LTC2634H10] = { 2666f1c9e0dSChris Ruehl .channels = ltc2632x10_channels, 2676f1c9e0dSChris Ruehl .num_channels = 4, 2686f1c9e0dSChris Ruehl .vref_mv = 4096, 2696f1c9e0dSChris Ruehl }, 2706f1c9e0dSChris Ruehl [ID_LTC2634H8] = { 2716f1c9e0dSChris Ruehl .channels = ltc2632x8_channels, 2726f1c9e0dSChris Ruehl .num_channels = 4, 2736f1c9e0dSChris Ruehl .vref_mv = 4096, 2746f1c9e0dSChris Ruehl }, 2759f15a4a0SUwe Kleine-König [ID_LTC2636L12] = { 2769f15a4a0SUwe Kleine-König .channels = ltc2632x12_channels, 2779f15a4a0SUwe Kleine-König .num_channels = 8, 2789f15a4a0SUwe Kleine-König .vref_mv = 2500, 2799f15a4a0SUwe Kleine-König }, 2809f15a4a0SUwe Kleine-König [ID_LTC2636L10] = { 2819f15a4a0SUwe Kleine-König .channels = ltc2632x10_channels, 2829f15a4a0SUwe Kleine-König .num_channels = 8, 2839f15a4a0SUwe Kleine-König .vref_mv = 2500, 2849f15a4a0SUwe Kleine-König }, 2859f15a4a0SUwe Kleine-König [ID_LTC2636L8] = { 2869f15a4a0SUwe Kleine-König .channels = ltc2632x8_channels, 2879f15a4a0SUwe Kleine-König .num_channels = 8, 2889f15a4a0SUwe Kleine-König .vref_mv = 2500, 2899f15a4a0SUwe Kleine-König }, 2909f15a4a0SUwe Kleine-König [ID_LTC2636H12] = { 2919f15a4a0SUwe Kleine-König .channels = ltc2632x12_channels, 2929f15a4a0SUwe Kleine-König .num_channels = 8, 2939f15a4a0SUwe Kleine-König .vref_mv = 4096, 2949f15a4a0SUwe Kleine-König }, 2959f15a4a0SUwe Kleine-König [ID_LTC2636H10] = { 2969f15a4a0SUwe Kleine-König .channels = ltc2632x10_channels, 2979f15a4a0SUwe Kleine-König .num_channels = 8, 2989f15a4a0SUwe Kleine-König .vref_mv = 4096, 2999f15a4a0SUwe Kleine-König }, 3009f15a4a0SUwe Kleine-König [ID_LTC2636H8] = { 3019f15a4a0SUwe Kleine-König .channels = ltc2632x8_channels, 3029f15a4a0SUwe Kleine-König .num_channels = 8, 30302b829f9SMaxime Roussin-Belanger .vref_mv = 4096, 30402b829f9SMaxime Roussin-Belanger }, 30502b829f9SMaxime Roussin-Belanger }; 30602b829f9SMaxime Roussin-Belanger 30702b829f9SMaxime Roussin-Belanger static int ltc2632_probe(struct spi_device *spi) 30802b829f9SMaxime Roussin-Belanger { 30902b829f9SMaxime Roussin-Belanger struct ltc2632_state *st; 31002b829f9SMaxime Roussin-Belanger struct iio_dev *indio_dev; 31102b829f9SMaxime Roussin-Belanger struct ltc2632_chip_info *chip_info; 31202b829f9SMaxime Roussin-Belanger int ret; 31302b829f9SMaxime Roussin-Belanger 31402b829f9SMaxime Roussin-Belanger indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 31502b829f9SMaxime Roussin-Belanger if (!indio_dev) 31602b829f9SMaxime Roussin-Belanger return -ENOMEM; 31702b829f9SMaxime Roussin-Belanger 31802b829f9SMaxime Roussin-Belanger st = iio_priv(indio_dev); 31902b829f9SMaxime Roussin-Belanger 32002b829f9SMaxime Roussin-Belanger spi_set_drvdata(spi, indio_dev); 32102b829f9SMaxime Roussin-Belanger st->spi_dev = spi; 32202b829f9SMaxime Roussin-Belanger 32302b829f9SMaxime Roussin-Belanger chip_info = (struct ltc2632_chip_info *) 32402b829f9SMaxime Roussin-Belanger spi_get_device_id(spi)->driver_data; 32502b829f9SMaxime Roussin-Belanger 3269ff1d500SSilvan Murer st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); 3279ff1d500SSilvan Murer if (PTR_ERR(st->vref_reg) == -ENODEV) { 3289ff1d500SSilvan Murer /* use internal reference voltage */ 3299ff1d500SSilvan Murer st->vref_reg = NULL; 3309ff1d500SSilvan Murer st->vref_mv = chip_info->vref_mv; 3319ff1d500SSilvan Murer 3329ff1d500SSilvan Murer ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, 3339ff1d500SSilvan Murer 0, 0, 0); 3349ff1d500SSilvan Murer if (ret) { 3359ff1d500SSilvan Murer dev_err(&spi->dev, 3369ff1d500SSilvan Murer "Set internal reference command failed, %d\n", 3379ff1d500SSilvan Murer ret); 3389ff1d500SSilvan Murer return ret; 3399ff1d500SSilvan Murer } 3409ff1d500SSilvan Murer } else if (IS_ERR(st->vref_reg)) { 3419ff1d500SSilvan Murer dev_err(&spi->dev, 3429ff1d500SSilvan Murer "Error getting voltage reference regulator\n"); 3439ff1d500SSilvan Murer return PTR_ERR(st->vref_reg); 3449ff1d500SSilvan Murer } else { 3459ff1d500SSilvan Murer /* use external reference voltage */ 3469ff1d500SSilvan Murer ret = regulator_enable(st->vref_reg); 3479ff1d500SSilvan Murer if (ret) { 3489ff1d500SSilvan Murer dev_err(&spi->dev, 3499ff1d500SSilvan Murer "enable reference regulator failed, %d\n", 3509ff1d500SSilvan Murer ret); 3519ff1d500SSilvan Murer return ret; 3529ff1d500SSilvan Murer } 3539ff1d500SSilvan Murer st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000; 3549ff1d500SSilvan Murer 3559ff1d500SSilvan Murer ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER, 3569ff1d500SSilvan Murer 0, 0, 0); 3579ff1d500SSilvan Murer if (ret) { 3589ff1d500SSilvan Murer dev_err(&spi->dev, 3599ff1d500SSilvan Murer "Set external reference command failed, %d\n", 3609ff1d500SSilvan Murer ret); 3619ff1d500SSilvan Murer return ret; 3629ff1d500SSilvan Murer } 3639ff1d500SSilvan Murer } 3649ff1d500SSilvan Murer 36502b829f9SMaxime Roussin-Belanger indio_dev->name = dev_of_node(&spi->dev) ? dev_of_node(&spi->dev)->name 36602b829f9SMaxime Roussin-Belanger : 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 3759ff1d500SSilvan Murer static int 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); 3849ff1d500SSilvan Murer 3859ff1d500SSilvan Murer return 0; 38602b829f9SMaxime Roussin-Belanger } 38702b829f9SMaxime Roussin-Belanger 38802b829f9SMaxime Roussin-Belanger static const struct spi_device_id ltc2632_id[] = { 38902b829f9SMaxime Roussin-Belanger { "ltc2632-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L12] }, 39002b829f9SMaxime Roussin-Belanger { "ltc2632-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L10] }, 39102b829f9SMaxime Roussin-Belanger { "ltc2632-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L8] }, 39202b829f9SMaxime Roussin-Belanger { "ltc2632-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H12] }, 39302b829f9SMaxime Roussin-Belanger { "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] }, 39402b829f9SMaxime Roussin-Belanger { "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] }, 3956f1c9e0dSChris Ruehl { "ltc2634-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L12] }, 3966f1c9e0dSChris Ruehl { "ltc2634-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L10] }, 3976f1c9e0dSChris Ruehl { "ltc2634-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L8] }, 3986f1c9e0dSChris Ruehl { "ltc2634-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H12] }, 3996f1c9e0dSChris Ruehl { "ltc2634-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H10] }, 4006f1c9e0dSChris Ruehl { "ltc2634-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H8] }, 4019f15a4a0SUwe Kleine-König { "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] }, 4029f15a4a0SUwe Kleine-König { "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] }, 4039f15a4a0SUwe Kleine-König { "ltc2636-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L8] }, 4049f15a4a0SUwe Kleine-König { "ltc2636-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H12] }, 4059f15a4a0SUwe Kleine-König { "ltc2636-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H10] }, 4069f15a4a0SUwe Kleine-König { "ltc2636-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H8] }, 40702b829f9SMaxime Roussin-Belanger {} 40802b829f9SMaxime Roussin-Belanger }; 40902b829f9SMaxime Roussin-Belanger MODULE_DEVICE_TABLE(spi, ltc2632_id); 41002b829f9SMaxime Roussin-Belanger 41102b829f9SMaxime Roussin-Belanger static const struct of_device_id ltc2632_of_match[] = { 41202b829f9SMaxime Roussin-Belanger { 41302b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l12", 41402b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L12] 41502b829f9SMaxime Roussin-Belanger }, { 41602b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l10", 41702b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L10] 41802b829f9SMaxime Roussin-Belanger }, { 41902b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-l8", 42002b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632L8] 42102b829f9SMaxime Roussin-Belanger }, { 42202b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h12", 42302b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H12] 42402b829f9SMaxime Roussin-Belanger }, { 42502b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h10", 42602b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H10] 42702b829f9SMaxime Roussin-Belanger }, { 42802b829f9SMaxime Roussin-Belanger .compatible = "lltc,ltc2632-h8", 42902b829f9SMaxime Roussin-Belanger .data = <c2632_chip_info_tbl[ID_LTC2632H8] 4309f15a4a0SUwe Kleine-König }, { 4316f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l12", 4326f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L12] 4336f1c9e0dSChris Ruehl }, { 4346f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l10", 4356f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L10] 4366f1c9e0dSChris Ruehl }, { 4376f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-l8", 4386f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634L8] 4396f1c9e0dSChris Ruehl }, { 4406f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h12", 4416f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H12] 4426f1c9e0dSChris Ruehl }, { 4436f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h10", 4446f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H10] 4456f1c9e0dSChris Ruehl }, { 4466f1c9e0dSChris Ruehl .compatible = "lltc,ltc2634-h8", 4476f1c9e0dSChris Ruehl .data = <c2632_chip_info_tbl[ID_LTC2634H8] 4486f1c9e0dSChris Ruehl }, { 4499f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l12", 4509f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L12] 4519f15a4a0SUwe Kleine-König }, { 4529f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l10", 4539f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L10] 4549f15a4a0SUwe Kleine-König }, { 4559f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-l8", 4569f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636L8] 4579f15a4a0SUwe Kleine-König }, { 4589f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h12", 4599f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H12] 4609f15a4a0SUwe Kleine-König }, { 4619f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h10", 4629f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H10] 4639f15a4a0SUwe Kleine-König }, { 4649f15a4a0SUwe Kleine-König .compatible = "lltc,ltc2636-h8", 4659f15a4a0SUwe Kleine-König .data = <c2632_chip_info_tbl[ID_LTC2636H8] 46602b829f9SMaxime Roussin-Belanger }, 46702b829f9SMaxime Roussin-Belanger {} 46802b829f9SMaxime Roussin-Belanger }; 46902b829f9SMaxime Roussin-Belanger MODULE_DEVICE_TABLE(of, ltc2632_of_match); 47002b829f9SMaxime Roussin-Belanger 4710f6a2165SSilvan Murer static struct spi_driver ltc2632_driver = { 4720f6a2165SSilvan Murer .driver = { 4730f6a2165SSilvan Murer .name = "ltc2632", 4740f6a2165SSilvan Murer .of_match_table = of_match_ptr(ltc2632_of_match), 4750f6a2165SSilvan Murer }, 4760f6a2165SSilvan Murer .probe = ltc2632_probe, 4779ff1d500SSilvan Murer .remove = ltc2632_remove, 4780f6a2165SSilvan Murer .id_table = ltc2632_id, 4790f6a2165SSilvan Murer }; 4800f6a2165SSilvan Murer module_spi_driver(ltc2632_driver); 4810f6a2165SSilvan Murer 48202b829f9SMaxime Roussin-Belanger MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); 48302b829f9SMaxime Roussin-Belanger MODULE_DESCRIPTION("LTC2632 DAC SPI driver"); 48402b829f9SMaxime Roussin-Belanger MODULE_LICENSE("GPL v2"); 485