18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * LTC2632 Digital to analog convertors spi driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2017 Maxime Roussin-Bélanger 68c2ecf20Sopenharmony_ci * expanded by Silvan Murer <silvan.murer@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N 0x0 188c2ecf20Sopenharmony_ci#define LTC2632_CMD_UPDATE_DAC_N 0x1 198c2ecf20Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 208c2ecf20Sopenharmony_ci#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N 0x3 218c2ecf20Sopenharmony_ci#define LTC2632_CMD_POWERDOWN_DAC_N 0x4 228c2ecf20Sopenharmony_ci#define LTC2632_CMD_POWERDOWN_CHIP 0x5 238c2ecf20Sopenharmony_ci#define LTC2632_CMD_INTERNAL_REFER 0x6 248c2ecf20Sopenharmony_ci#define LTC2632_CMD_EXTERNAL_REFER 0x7 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * struct ltc2632_chip_info - chip specific information 288c2ecf20Sopenharmony_ci * @channels: channel spec for the DAC 298c2ecf20Sopenharmony_ci * @num_channels: DAC channel count of the chip 308c2ecf20Sopenharmony_ci * @vref_mv: internal reference voltage 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistruct ltc2632_chip_info { 338c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 348c2ecf20Sopenharmony_ci const size_t num_channels; 358c2ecf20Sopenharmony_ci const int vref_mv; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/** 398c2ecf20Sopenharmony_ci * struct ltc2632_state - driver instance specific data 408c2ecf20Sopenharmony_ci * @spi_dev: pointer to the spi_device struct 418c2ecf20Sopenharmony_ci * @powerdown_cache_mask: used to show current channel powerdown state 428c2ecf20Sopenharmony_ci * @vref_mv: used reference voltage (internal or external) 438c2ecf20Sopenharmony_ci * @vref_reg: regulator for the reference voltage 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct ltc2632_state { 468c2ecf20Sopenharmony_ci struct spi_device *spi_dev; 478c2ecf20Sopenharmony_ci unsigned int powerdown_cache_mask; 488c2ecf20Sopenharmony_ci int vref_mv; 498c2ecf20Sopenharmony_ci struct regulator *vref_reg; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cienum ltc2632_supported_device_ids { 538c2ecf20Sopenharmony_ci ID_LTC2632L12, 548c2ecf20Sopenharmony_ci ID_LTC2632L10, 558c2ecf20Sopenharmony_ci ID_LTC2632L8, 568c2ecf20Sopenharmony_ci ID_LTC2632H12, 578c2ecf20Sopenharmony_ci ID_LTC2632H10, 588c2ecf20Sopenharmony_ci ID_LTC2632H8, 598c2ecf20Sopenharmony_ci ID_LTC2634L12, 608c2ecf20Sopenharmony_ci ID_LTC2634L10, 618c2ecf20Sopenharmony_ci ID_LTC2634L8, 628c2ecf20Sopenharmony_ci ID_LTC2634H12, 638c2ecf20Sopenharmony_ci ID_LTC2634H10, 648c2ecf20Sopenharmony_ci ID_LTC2634H8, 658c2ecf20Sopenharmony_ci ID_LTC2636L12, 668c2ecf20Sopenharmony_ci ID_LTC2636L10, 678c2ecf20Sopenharmony_ci ID_LTC2636L8, 688c2ecf20Sopenharmony_ci ID_LTC2636H12, 698c2ecf20Sopenharmony_ci ID_LTC2636H10, 708c2ecf20Sopenharmony_ci ID_LTC2636H8, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int ltc2632_spi_write(struct spi_device *spi, 748c2ecf20Sopenharmony_ci u8 cmd, u8 addr, u16 val, u8 shift) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci u32 data; 778c2ecf20Sopenharmony_ci u8 msg[3]; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * The input shift register is 24 bits wide. 818c2ecf20Sopenharmony_ci * The next four are the command bits, C3 to C0, 828c2ecf20Sopenharmony_ci * followed by the 4-bit DAC address, A3 to A0, and then the 838c2ecf20Sopenharmony_ci * 12-, 10-, 8-bit data-word. The data-word comprises the 12-, 848c2ecf20Sopenharmony_ci * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci data = (cmd << 20) | (addr << 16) | (val << shift); 878c2ecf20Sopenharmony_ci put_unaligned_be24(data, &msg[0]); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return spi_write(spi, msg, sizeof(msg)); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int ltc2632_read_raw(struct iio_dev *indio_dev, 938c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 948c2ecf20Sopenharmony_ci int *val, 958c2ecf20Sopenharmony_ci int *val2, 968c2ecf20Sopenharmony_ci long m) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci const struct ltc2632_state *st = iio_priv(indio_dev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci switch (m) { 1018c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 1028c2ecf20Sopenharmony_ci *val = st->vref_mv; 1038c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 1048c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci return -EINVAL; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int ltc2632_write_raw(struct iio_dev *indio_dev, 1108c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1118c2ecf20Sopenharmony_ci int val, 1128c2ecf20Sopenharmony_ci int val2, 1138c2ecf20Sopenharmony_ci long mask) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct ltc2632_state *st = iio_priv(indio_dev); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci switch (mask) { 1188c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 1198c2ecf20Sopenharmony_ci if (val >= (1 << chan->scan_type.realbits) || val < 0) 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return ltc2632_spi_write(st->spi_dev, 1238c2ecf20Sopenharmony_ci LTC2632_CMD_WRITE_INPUT_N_UPDATE_N, 1248c2ecf20Sopenharmony_ci chan->address, val, 1258c2ecf20Sopenharmony_ci chan->scan_type.shift); 1268c2ecf20Sopenharmony_ci default: 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev, 1328c2ecf20Sopenharmony_ci uintptr_t private, 1338c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1348c2ecf20Sopenharmony_ci char *buf) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct ltc2632_state *st = iio_priv(indio_dev); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 1398c2ecf20Sopenharmony_ci !!(st->powerdown_cache_mask & (1 << chan->channel))); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev, 1438c2ecf20Sopenharmony_ci uintptr_t private, 1448c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 1458c2ecf20Sopenharmony_ci const char *buf, 1468c2ecf20Sopenharmony_ci size_t len) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci bool pwr_down; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci struct ltc2632_state *st = iio_priv(indio_dev); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ret = strtobool(buf, &pwr_down); 1538c2ecf20Sopenharmony_ci if (ret) 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (pwr_down) 1578c2ecf20Sopenharmony_ci st->powerdown_cache_mask |= (1 << chan->channel); 1588c2ecf20Sopenharmony_ci else 1598c2ecf20Sopenharmony_ci st->powerdown_cache_mask &= ~(1 << chan->channel); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ret = ltc2632_spi_write(st->spi_dev, 1628c2ecf20Sopenharmony_ci LTC2632_CMD_POWERDOWN_DAC_N, 1638c2ecf20Sopenharmony_ci chan->channel, 0, 0); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return ret ? ret : len; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const struct iio_info ltc2632_info = { 1698c2ecf20Sopenharmony_ci .write_raw = ltc2632_write_raw, 1708c2ecf20Sopenharmony_ci .read_raw = ltc2632_read_raw, 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ltc2632_ext_info[] = { 1748c2ecf20Sopenharmony_ci { 1758c2ecf20Sopenharmony_ci .name = "powerdown", 1768c2ecf20Sopenharmony_ci .read = ltc2632_read_dac_powerdown, 1778c2ecf20Sopenharmony_ci .write = ltc2632_write_dac_powerdown, 1788c2ecf20Sopenharmony_ci .shared = IIO_SEPARATE, 1798c2ecf20Sopenharmony_ci }, 1808c2ecf20Sopenharmony_ci { }, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define LTC2632_CHANNEL(_chan, _bits) { \ 1848c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 1858c2ecf20Sopenharmony_ci .indexed = 1, \ 1868c2ecf20Sopenharmony_ci .output = 1, \ 1878c2ecf20Sopenharmony_ci .channel = (_chan), \ 1888c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 1898c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 1908c2ecf20Sopenharmony_ci .address = (_chan), \ 1918c2ecf20Sopenharmony_ci .scan_type = { \ 1928c2ecf20Sopenharmony_ci .realbits = (_bits), \ 1938c2ecf20Sopenharmony_ci .shift = 16 - (_bits), \ 1948c2ecf20Sopenharmony_ci }, \ 1958c2ecf20Sopenharmony_ci .ext_info = ltc2632_ext_info, \ 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define DECLARE_LTC2632_CHANNELS(_name, _bits) \ 1998c2ecf20Sopenharmony_ci const struct iio_chan_spec _name ## _channels[] = { \ 2008c2ecf20Sopenharmony_ci LTC2632_CHANNEL(0, _bits), \ 2018c2ecf20Sopenharmony_ci LTC2632_CHANNEL(1, _bits), \ 2028c2ecf20Sopenharmony_ci LTC2632_CHANNEL(2, _bits), \ 2038c2ecf20Sopenharmony_ci LTC2632_CHANNEL(3, _bits), \ 2048c2ecf20Sopenharmony_ci LTC2632_CHANNEL(4, _bits), \ 2058c2ecf20Sopenharmony_ci LTC2632_CHANNEL(5, _bits), \ 2068c2ecf20Sopenharmony_ci LTC2632_CHANNEL(6, _bits), \ 2078c2ecf20Sopenharmony_ci LTC2632_CHANNEL(7, _bits), \ 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x12, 12); 2118c2ecf20Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x10, 10); 2128c2ecf20Sopenharmony_cistatic DECLARE_LTC2632_CHANNELS(ltc2632x8, 8); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = { 2158c2ecf20Sopenharmony_ci [ID_LTC2632L12] = { 2168c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2178c2ecf20Sopenharmony_ci .num_channels = 2, 2188c2ecf20Sopenharmony_ci .vref_mv = 2500, 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci [ID_LTC2632L10] = { 2218c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2228c2ecf20Sopenharmony_ci .num_channels = 2, 2238c2ecf20Sopenharmony_ci .vref_mv = 2500, 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci [ID_LTC2632L8] = { 2268c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 2278c2ecf20Sopenharmony_ci .num_channels = 2, 2288c2ecf20Sopenharmony_ci .vref_mv = 2500, 2298c2ecf20Sopenharmony_ci }, 2308c2ecf20Sopenharmony_ci [ID_LTC2632H12] = { 2318c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2328c2ecf20Sopenharmony_ci .num_channels = 2, 2338c2ecf20Sopenharmony_ci .vref_mv = 4096, 2348c2ecf20Sopenharmony_ci }, 2358c2ecf20Sopenharmony_ci [ID_LTC2632H10] = { 2368c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2378c2ecf20Sopenharmony_ci .num_channels = 2, 2388c2ecf20Sopenharmony_ci .vref_mv = 4096, 2398c2ecf20Sopenharmony_ci }, 2408c2ecf20Sopenharmony_ci [ID_LTC2632H8] = { 2418c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 2428c2ecf20Sopenharmony_ci .num_channels = 2, 2438c2ecf20Sopenharmony_ci .vref_mv = 4096, 2448c2ecf20Sopenharmony_ci }, 2458c2ecf20Sopenharmony_ci [ID_LTC2634L12] = { 2468c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2478c2ecf20Sopenharmony_ci .num_channels = 4, 2488c2ecf20Sopenharmony_ci .vref_mv = 2500, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci [ID_LTC2634L10] = { 2518c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2528c2ecf20Sopenharmony_ci .num_channels = 4, 2538c2ecf20Sopenharmony_ci .vref_mv = 2500, 2548c2ecf20Sopenharmony_ci }, 2558c2ecf20Sopenharmony_ci [ID_LTC2634L8] = { 2568c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 2578c2ecf20Sopenharmony_ci .num_channels = 4, 2588c2ecf20Sopenharmony_ci .vref_mv = 2500, 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci [ID_LTC2634H12] = { 2618c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2628c2ecf20Sopenharmony_ci .num_channels = 4, 2638c2ecf20Sopenharmony_ci .vref_mv = 4096, 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci [ID_LTC2634H10] = { 2668c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2678c2ecf20Sopenharmony_ci .num_channels = 4, 2688c2ecf20Sopenharmony_ci .vref_mv = 4096, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci [ID_LTC2634H8] = { 2718c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 2728c2ecf20Sopenharmony_ci .num_channels = 4, 2738c2ecf20Sopenharmony_ci .vref_mv = 4096, 2748c2ecf20Sopenharmony_ci }, 2758c2ecf20Sopenharmony_ci [ID_LTC2636L12] = { 2768c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2778c2ecf20Sopenharmony_ci .num_channels = 8, 2788c2ecf20Sopenharmony_ci .vref_mv = 2500, 2798c2ecf20Sopenharmony_ci }, 2808c2ecf20Sopenharmony_ci [ID_LTC2636L10] = { 2818c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2828c2ecf20Sopenharmony_ci .num_channels = 8, 2838c2ecf20Sopenharmony_ci .vref_mv = 2500, 2848c2ecf20Sopenharmony_ci }, 2858c2ecf20Sopenharmony_ci [ID_LTC2636L8] = { 2868c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 2878c2ecf20Sopenharmony_ci .num_channels = 8, 2888c2ecf20Sopenharmony_ci .vref_mv = 2500, 2898c2ecf20Sopenharmony_ci }, 2908c2ecf20Sopenharmony_ci [ID_LTC2636H12] = { 2918c2ecf20Sopenharmony_ci .channels = ltc2632x12_channels, 2928c2ecf20Sopenharmony_ci .num_channels = 8, 2938c2ecf20Sopenharmony_ci .vref_mv = 4096, 2948c2ecf20Sopenharmony_ci }, 2958c2ecf20Sopenharmony_ci [ID_LTC2636H10] = { 2968c2ecf20Sopenharmony_ci .channels = ltc2632x10_channels, 2978c2ecf20Sopenharmony_ci .num_channels = 8, 2988c2ecf20Sopenharmony_ci .vref_mv = 4096, 2998c2ecf20Sopenharmony_ci }, 3008c2ecf20Sopenharmony_ci [ID_LTC2636H8] = { 3018c2ecf20Sopenharmony_ci .channels = ltc2632x8_channels, 3028c2ecf20Sopenharmony_ci .num_channels = 8, 3038c2ecf20Sopenharmony_ci .vref_mv = 4096, 3048c2ecf20Sopenharmony_ci }, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int ltc2632_probe(struct spi_device *spi) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct ltc2632_state *st; 3108c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 3118c2ecf20Sopenharmony_ci struct ltc2632_chip_info *chip_info; 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 3158c2ecf20Sopenharmony_ci if (!indio_dev) 3168c2ecf20Sopenharmony_ci return -ENOMEM; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 3218c2ecf20Sopenharmony_ci st->spi_dev = spi; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci chip_info = (struct ltc2632_chip_info *) 3248c2ecf20Sopenharmony_ci spi_get_device_id(spi)->driver_data; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); 3278c2ecf20Sopenharmony_ci if (PTR_ERR(st->vref_reg) == -ENODEV) { 3288c2ecf20Sopenharmony_ci /* use internal reference voltage */ 3298c2ecf20Sopenharmony_ci st->vref_reg = NULL; 3308c2ecf20Sopenharmony_ci st->vref_mv = chip_info->vref_mv; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, 3338c2ecf20Sopenharmony_ci 0, 0, 0); 3348c2ecf20Sopenharmony_ci if (ret) { 3358c2ecf20Sopenharmony_ci dev_err(&spi->dev, 3368c2ecf20Sopenharmony_ci "Set internal reference command failed, %d\n", 3378c2ecf20Sopenharmony_ci ret); 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } else if (IS_ERR(st->vref_reg)) { 3418c2ecf20Sopenharmony_ci dev_err(&spi->dev, 3428c2ecf20Sopenharmony_ci "Error getting voltage reference regulator\n"); 3438c2ecf20Sopenharmony_ci return PTR_ERR(st->vref_reg); 3448c2ecf20Sopenharmony_ci } else { 3458c2ecf20Sopenharmony_ci /* use external reference voltage */ 3468c2ecf20Sopenharmony_ci ret = regulator_enable(st->vref_reg); 3478c2ecf20Sopenharmony_ci if (ret) { 3488c2ecf20Sopenharmony_ci dev_err(&spi->dev, 3498c2ecf20Sopenharmony_ci "enable reference regulator failed, %d\n", 3508c2ecf20Sopenharmony_ci ret); 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER, 3568c2ecf20Sopenharmony_ci 0, 0, 0); 3578c2ecf20Sopenharmony_ci if (ret) { 3588c2ecf20Sopenharmony_ci dev_err(&spi->dev, 3598c2ecf20Sopenharmony_ci "Set external reference command failed, %d\n", 3608c2ecf20Sopenharmony_ci ret); 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci indio_dev->name = dev_of_node(&spi->dev) ? dev_of_node(&spi->dev)->name 3668c2ecf20Sopenharmony_ci : spi_get_device_id(spi)->name; 3678c2ecf20Sopenharmony_ci indio_dev->info = <c2632_info; 3688c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 3698c2ecf20Sopenharmony_ci indio_dev->channels = chip_info->channels; 3708c2ecf20Sopenharmony_ci indio_dev->num_channels = chip_info->num_channels; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return iio_device_register(indio_dev); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int ltc2632_remove(struct spi_device *spi) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = spi_get_drvdata(spi); 3788c2ecf20Sopenharmony_ci struct ltc2632_state *st = iio_priv(indio_dev); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (st->vref_reg) 3838c2ecf20Sopenharmony_ci regulator_disable(st->vref_reg); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic const struct spi_device_id ltc2632_id[] = { 3898c2ecf20Sopenharmony_ci { "ltc2632-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L12] }, 3908c2ecf20Sopenharmony_ci { "ltc2632-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L10] }, 3918c2ecf20Sopenharmony_ci { "ltc2632-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L8] }, 3928c2ecf20Sopenharmony_ci { "ltc2632-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H12] }, 3938c2ecf20Sopenharmony_ci { "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] }, 3948c2ecf20Sopenharmony_ci { "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] }, 3958c2ecf20Sopenharmony_ci { "ltc2634-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L12] }, 3968c2ecf20Sopenharmony_ci { "ltc2634-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L10] }, 3978c2ecf20Sopenharmony_ci { "ltc2634-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L8] }, 3988c2ecf20Sopenharmony_ci { "ltc2634-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H12] }, 3998c2ecf20Sopenharmony_ci { "ltc2634-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H10] }, 4008c2ecf20Sopenharmony_ci { "ltc2634-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H8] }, 4018c2ecf20Sopenharmony_ci { "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] }, 4028c2ecf20Sopenharmony_ci { "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] }, 4038c2ecf20Sopenharmony_ci { "ltc2636-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L8] }, 4048c2ecf20Sopenharmony_ci { "ltc2636-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H12] }, 4058c2ecf20Sopenharmony_ci { "ltc2636-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H10] }, 4068c2ecf20Sopenharmony_ci { "ltc2636-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H8] }, 4078c2ecf20Sopenharmony_ci {} 4088c2ecf20Sopenharmony_ci}; 4098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ltc2632_id); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic const struct of_device_id ltc2632_of_match[] = { 4128c2ecf20Sopenharmony_ci { 4138c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-l12", 4148c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632L12] 4158c2ecf20Sopenharmony_ci }, { 4168c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-l10", 4178c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632L10] 4188c2ecf20Sopenharmony_ci }, { 4198c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-l8", 4208c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632L8] 4218c2ecf20Sopenharmony_ci }, { 4228c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-h12", 4238c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632H12] 4248c2ecf20Sopenharmony_ci }, { 4258c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-h10", 4268c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632H10] 4278c2ecf20Sopenharmony_ci }, { 4288c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2632-h8", 4298c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2632H8] 4308c2ecf20Sopenharmony_ci }, { 4318c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-l12", 4328c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634L12] 4338c2ecf20Sopenharmony_ci }, { 4348c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-l10", 4358c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634L10] 4368c2ecf20Sopenharmony_ci }, { 4378c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-l8", 4388c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634L8] 4398c2ecf20Sopenharmony_ci }, { 4408c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-h12", 4418c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634H12] 4428c2ecf20Sopenharmony_ci }, { 4438c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-h10", 4448c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634H10] 4458c2ecf20Sopenharmony_ci }, { 4468c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2634-h8", 4478c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2634H8] 4488c2ecf20Sopenharmony_ci }, { 4498c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-l12", 4508c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636L12] 4518c2ecf20Sopenharmony_ci }, { 4528c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-l10", 4538c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636L10] 4548c2ecf20Sopenharmony_ci }, { 4558c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-l8", 4568c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636L8] 4578c2ecf20Sopenharmony_ci }, { 4588c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-h12", 4598c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636H12] 4608c2ecf20Sopenharmony_ci }, { 4618c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-h10", 4628c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636H10] 4638c2ecf20Sopenharmony_ci }, { 4648c2ecf20Sopenharmony_ci .compatible = "lltc,ltc2636-h8", 4658c2ecf20Sopenharmony_ci .data = <c2632_chip_info_tbl[ID_LTC2636H8] 4668c2ecf20Sopenharmony_ci }, 4678c2ecf20Sopenharmony_ci {} 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltc2632_of_match); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct spi_driver ltc2632_driver = { 4728c2ecf20Sopenharmony_ci .driver = { 4738c2ecf20Sopenharmony_ci .name = "ltc2632", 4748c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ltc2632_of_match), 4758c2ecf20Sopenharmony_ci }, 4768c2ecf20Sopenharmony_ci .probe = ltc2632_probe, 4778c2ecf20Sopenharmony_ci .remove = ltc2632_remove, 4788c2ecf20Sopenharmony_ci .id_table = ltc2632_id, 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_cimodule_spi_driver(ltc2632_driver); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); 4838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LTC2632 DAC SPI driver"); 4848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 485