ltc2497-core.c (6137B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ltc2497-core.c - Common code for Analog Devices/Linear Technology 4 * LTC2496 and LTC2497 ADCs 5 * 6 * Copyright (C) 2017 Analog Devices Inc. 7 */ 8 9#include <linux/delay.h> 10#include <linux/iio/iio.h> 11#include <linux/iio/driver.h> 12#include <linux/module.h> 13#include <linux/regulator/consumer.h> 14 15#include "ltc2497.h" 16 17#define LTC2497_SGL BIT(4) 18#define LTC2497_DIFF 0 19#define LTC2497_SIGN BIT(3) 20 21static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata) 22{ 23 s64 time_elapsed; 24 25 time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev); 26 27 if (time_elapsed < LTC2497_CONVERSION_TIME_MS) { 28 /* delay if conversion time not passed 29 * since last read or write 30 */ 31 if (msleep_interruptible( 32 LTC2497_CONVERSION_TIME_MS - time_elapsed)) 33 return -ERESTARTSYS; 34 35 return 0; 36 } 37 38 if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) { 39 /* We're in automatic mode - 40 * so the last reading is still not outdated 41 */ 42 return 0; 43 } 44 45 return 1; 46} 47 48static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val) 49{ 50 int ret; 51 52 ret = ltc2497core_wait_conv(ddata); 53 if (ret < 0) 54 return ret; 55 56 if (ret || ddata->addr_prev != address) { 57 ret = ddata->result_and_measure(ddata, address, NULL); 58 if (ret < 0) 59 return ret; 60 ddata->addr_prev = address; 61 62 if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS)) 63 return -ERESTARTSYS; 64 } 65 66 ret = ddata->result_and_measure(ddata, address, val); 67 if (ret < 0) 68 return ret; 69 70 ddata->time_prev = ktime_get(); 71 72 return ret; 73} 74 75static int ltc2497core_read_raw(struct iio_dev *indio_dev, 76 struct iio_chan_spec const *chan, 77 int *val, int *val2, long mask) 78{ 79 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev); 80 int ret; 81 82 switch (mask) { 83 case IIO_CHAN_INFO_RAW: 84 mutex_lock(&indio_dev->mlock); 85 ret = ltc2497core_read(ddata, chan->address, val); 86 mutex_unlock(&indio_dev->mlock); 87 if (ret < 0) 88 return ret; 89 90 return IIO_VAL_INT; 91 92 case IIO_CHAN_INFO_SCALE: 93 ret = regulator_get_voltage(ddata->ref); 94 if (ret < 0) 95 return ret; 96 97 *val = ret / 1000; 98 *val2 = 17; 99 100 return IIO_VAL_FRACTIONAL_LOG2; 101 102 default: 103 return -EINVAL; 104 } 105} 106 107#define LTC2497_CHAN(_chan, _addr, _ds_name) { \ 108 .type = IIO_VOLTAGE, \ 109 .indexed = 1, \ 110 .channel = (_chan), \ 111 .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \ 112 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 113 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 114 .datasheet_name = (_ds_name), \ 115} 116 117#define LTC2497_CHAN_DIFF(_chan, _addr) { \ 118 .type = IIO_VOLTAGE, \ 119 .indexed = 1, \ 120 .channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \ 121 .channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\ 122 .address = (_addr | _chan), \ 123 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 124 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 125 .differential = 1, \ 126} 127 128static const struct iio_chan_spec ltc2497core_channel[] = { 129 LTC2497_CHAN(0, LTC2497_SGL, "CH0"), 130 LTC2497_CHAN(1, LTC2497_SGL, "CH1"), 131 LTC2497_CHAN(2, LTC2497_SGL, "CH2"), 132 LTC2497_CHAN(3, LTC2497_SGL, "CH3"), 133 LTC2497_CHAN(4, LTC2497_SGL, "CH4"), 134 LTC2497_CHAN(5, LTC2497_SGL, "CH5"), 135 LTC2497_CHAN(6, LTC2497_SGL, "CH6"), 136 LTC2497_CHAN(7, LTC2497_SGL, "CH7"), 137 LTC2497_CHAN(8, LTC2497_SGL, "CH8"), 138 LTC2497_CHAN(9, LTC2497_SGL, "CH9"), 139 LTC2497_CHAN(10, LTC2497_SGL, "CH10"), 140 LTC2497_CHAN(11, LTC2497_SGL, "CH11"), 141 LTC2497_CHAN(12, LTC2497_SGL, "CH12"), 142 LTC2497_CHAN(13, LTC2497_SGL, "CH13"), 143 LTC2497_CHAN(14, LTC2497_SGL, "CH14"), 144 LTC2497_CHAN(15, LTC2497_SGL, "CH15"), 145 LTC2497_CHAN_DIFF(0, LTC2497_DIFF), 146 LTC2497_CHAN_DIFF(1, LTC2497_DIFF), 147 LTC2497_CHAN_DIFF(2, LTC2497_DIFF), 148 LTC2497_CHAN_DIFF(3, LTC2497_DIFF), 149 LTC2497_CHAN_DIFF(4, LTC2497_DIFF), 150 LTC2497_CHAN_DIFF(5, LTC2497_DIFF), 151 LTC2497_CHAN_DIFF(6, LTC2497_DIFF), 152 LTC2497_CHAN_DIFF(7, LTC2497_DIFF), 153 LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN), 154 LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN), 155 LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN), 156 LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN), 157 LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN), 158 LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN), 159 LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN), 160 LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN), 161}; 162 163static const struct iio_info ltc2497core_info = { 164 .read_raw = ltc2497core_read_raw, 165}; 166 167int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev) 168{ 169 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev); 170 int ret; 171 172 indio_dev->name = dev_name(dev); 173 indio_dev->info = <c2497core_info; 174 indio_dev->modes = INDIO_DIRECT_MODE; 175 indio_dev->channels = ltc2497core_channel; 176 indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel); 177 178 ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL); 179 if (ret < 0) 180 return ret; 181 182 ddata->ref = devm_regulator_get(dev, "vref"); 183 if (IS_ERR(ddata->ref)) 184 return dev_err_probe(dev, PTR_ERR(ddata->ref), 185 "Failed to get vref regulator\n"); 186 187 ret = regulator_enable(ddata->ref); 188 if (ret < 0) { 189 dev_err(dev, "Failed to enable vref regulator: %pe\n", 190 ERR_PTR(ret)); 191 return ret; 192 } 193 194 if (dev->platform_data) { 195 struct iio_map *plat_data; 196 197 plat_data = (struct iio_map *)dev->platform_data; 198 199 ret = iio_map_array_register(indio_dev, plat_data); 200 if (ret) { 201 dev_err(&indio_dev->dev, "iio map err: %d\n", ret); 202 goto err_regulator_disable; 203 } 204 } 205 206 ddata->addr_prev = LTC2497_CONFIG_DEFAULT; 207 ddata->time_prev = ktime_get(); 208 209 ret = iio_device_register(indio_dev); 210 if (ret < 0) 211 goto err_array_unregister; 212 213 return 0; 214 215err_array_unregister: 216 iio_map_array_unregister(indio_dev); 217 218err_regulator_disable: 219 regulator_disable(ddata->ref); 220 221 return ret; 222} 223EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497); 224 225void ltc2497core_remove(struct iio_dev *indio_dev) 226{ 227 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev); 228 229 iio_device_unregister(indio_dev); 230 231 iio_map_array_unregister(indio_dev); 232 233 regulator_disable(ddata->ref); 234} 235EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497); 236 237MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers"); 238MODULE_LICENSE("GPL v2");