Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: amplifiers: hmc425a: add support for LTC6373 Instrumentation Amplifier

This adds support for LTC6373 36 V Fully-Differential Programmable-Gain
Instrumentation Amplifier with 25 pA Input Bias Current.
The user can program the gain to one of seven available settings through
a 3-bit parallel interface (A2 to A0).

Signed-off-by: Dumitru Ceclan <mitrutzceclan@gmail.com>
Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20240220153553.2432-6-mitrutzceclan@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Dumitru Ceclan and committed by
Jonathan Cameron
a0e7a2b7 09ac57ac

+120 -4
+120 -4
drivers/iio/amplifiers/hmc425a.c
··· 2 2 /* 3 3 * HMC425A and similar Gain Amplifiers 4 4 * 5 - * Copyright 2020 Analog Devices Inc. 5 + * Copyright 2020, 2024 Analog Devices Inc. 6 6 */ 7 7 8 + #include <linux/bits.h> 8 9 #include <linux/bitops.h> 9 10 #include <linux/device.h> 10 11 #include <linux/err.h> ··· 13 12 #include <linux/iio/iio.h> 14 13 #include <linux/iio/sysfs.h> 15 14 #include <linux/kernel.h> 15 + #include <linux/math.h> 16 16 #include <linux/mod_devicetable.h> 17 17 #include <linux/module.h> 18 18 #include <linux/platform_device.h> ··· 22 20 #include <linux/regulator/consumer.h> 23 21 #include <linux/sysfs.h> 24 22 23 + /* 24 + * The LTC6373 amplifier supports configuring gain using GPIO's with the following 25 + * values (OUTPUT_V / INPUT_V): 0(shutdown), 0.25, 0.5, 1, 2, 4, 8, 16 26 + * 27 + * Except for the shutdown value, all can be converted to dB using 20 * log10(x) 28 + * From here, it is observed that all values are multiples of the '2' gain setting, 29 + * with the correspondent of 6.020dB. 30 + */ 31 + #define LTC6373_CONVERSION_CONSTANT 6020 32 + #define LTC6373_MIN_GAIN_CODE 0x6 33 + #define LTC6373_CONVERSION_MASK GENMASK(2, 0) 34 + #define LTC6373_SHUTDOWN GENMASK(2, 0) 35 + 25 36 enum hmc425a_type { 26 37 ID_HMC425A, 27 38 ID_HMC540S, 28 - ID_ADRF5740 39 + ID_ADRF5740, 40 + ID_LTC6373, 29 41 }; 30 42 31 43 struct hmc425a_chip_info { ··· 50 34 int gain_min; 51 35 int gain_max; 52 36 int default_gain; 37 + int powerdown_val; 38 + bool has_powerdown; 53 39 54 40 int (*gain_dB_to_code)(int gain, int *code); 55 41 int (*code_to_gain_dB)(int code, int *val, int *val2); ··· 62 44 const struct hmc425a_chip_info *chip_info; 63 45 struct gpio_descs *gpios; 64 46 u32 gain; 47 + bool powerdown; 65 48 }; 66 49 67 50 static int gain_dB_to_code(struct hmc425a_state *st, int val, int val2, int *code) ··· 77 58 78 59 if (gain > inf->gain_max || gain < inf->gain_min) 79 60 return -EINVAL; 61 + if (st->powerdown) 62 + return -EPERM; 80 63 81 64 return st->chip_info->gain_dB_to_code(gain, code); 82 65 } ··· 104 83 return 0; 105 84 } 106 85 86 + static int ltc6373_gain_dB_to_code(int gain, int *code) 87 + { 88 + *code = ~(DIV_ROUND_CLOSEST(gain, LTC6373_CONVERSION_CONSTANT) + 3) 89 + & LTC6373_CONVERSION_MASK; 90 + return 0; 91 + } 92 + 107 93 static int code_to_gain_dB(struct hmc425a_state *st, int *val, int *val2) 108 94 { 95 + if (st->powerdown) 96 + return -EPERM; 109 97 return st->chip_info->code_to_gain_dB(st->gain, val, val2); 110 98 } 111 99 ··· 141 111 code = code & BIT(3) ? code & ~BIT(2) : code; 142 112 *val = (code * -2000) / 1000; 143 113 *val2 = ((code * -2000) % 1000) * 1000; 114 + return 0; 115 + } 116 + 117 + static int ltc6373_code_to_gain_dB(int code, int *val, int *val2) 118 + { 119 + int gain = ((~code & LTC6373_CONVERSION_MASK) - 3) * 120 + LTC6373_CONVERSION_CONSTANT; 121 + 122 + *val = gain / 1000; 123 + *val2 = (gain % 1000) * 1000; 144 124 return 0; 145 125 } 146 126 ··· 232 192 .write_raw_get_fmt = &hmc425a_write_raw_get_fmt, 233 193 }; 234 194 195 + static ssize_t ltc6373_read_powerdown(struct iio_dev *indio_dev, 196 + uintptr_t private, 197 + const struct iio_chan_spec *chan, 198 + char *buf) 199 + { 200 + struct hmc425a_state *st = iio_priv(indio_dev); 201 + 202 + return sysfs_emit(buf, "%d\n", st->powerdown); 203 + } 204 + 205 + static ssize_t ltc6373_write_powerdown(struct iio_dev *indio_dev, 206 + uintptr_t private, 207 + const struct iio_chan_spec *chan, 208 + const char *buf, 209 + size_t len) 210 + { 211 + struct hmc425a_state *st = iio_priv(indio_dev); 212 + bool powerdown; 213 + int code, ret; 214 + 215 + ret = kstrtobool(buf, &powerdown); 216 + if (ret) 217 + return ret; 218 + 219 + mutex_lock(&st->lock); 220 + st->powerdown = powerdown; 221 + code = (powerdown) ? LTC6373_SHUTDOWN : st->gain; 222 + hmc425a_write(indio_dev, code); 223 + mutex_unlock(&st->lock); 224 + return len; 225 + } 226 + 227 + static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = { 228 + { 229 + .name = "powerdown", 230 + .read = ltc6373_read_powerdown, 231 + .write = ltc6373_write_powerdown, 232 + .shared = IIO_SEPARATE, 233 + }, 234 + {} 235 + }; 236 + 235 237 #define HMC425A_CHAN(_channel) \ 236 238 { \ 237 239 .type = IIO_VOLTAGE, \ ··· 283 201 .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 284 202 } 285 203 204 + #define LTC6373_CHAN(_channel) \ 205 + { \ 206 + .type = IIO_VOLTAGE, \ 207 + .output = 1, \ 208 + .indexed = 1, \ 209 + .channel = _channel, \ 210 + .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 211 + .ext_info = ltc6373_ext_info, \ 212 + } 213 + 286 214 static const struct iio_chan_spec hmc425a_channels[] = { 287 215 HMC425A_CHAN(0), 216 + }; 217 + 218 + static const struct iio_chan_spec ltc6373_channels[] = { 219 + LTC6373_CHAN(0), 288 220 }; 289 221 290 222 static const struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { ··· 334 238 .default_gain = 0xF, /* set default gain -22.0db*/ 335 239 .gain_dB_to_code = adrf5740_gain_dB_to_code, 336 240 .code_to_gain_dB = adrf5740_code_to_gain_dB, 241 + }, 242 + [ID_LTC6373] = { 243 + .name = "ltc6373", 244 + .channels = ltc6373_channels, 245 + .num_channels = ARRAY_SIZE(ltc6373_channels), 246 + .num_gpios = 3, 247 + .gain_min = -12041, /* gain setting x0.25*/ 248 + .gain_max = 24082, /* gain setting x16 */ 249 + .default_gain = LTC6373_MIN_GAIN_CODE, 250 + .powerdown_val = LTC6373_SHUTDOWN, 251 + .has_powerdown = true, 252 + .gain_dB_to_code = ltc6373_gain_dB_to_code, 253 + .code_to_gain_dB = ltc6373_code_to_gain_dB, 337 254 }, 338 255 }; 339 256 ··· 388 279 indio_dev->info = &hmc425a_info; 389 280 indio_dev->modes = INDIO_DIRECT_MODE; 390 281 391 - /* Set default gain */ 392 - hmc425a_write(indio_dev, st->gain); 282 + if (st->chip_info->has_powerdown) { 283 + st->powerdown = true; 284 + hmc425a_write(indio_dev, st->chip_info->powerdown_val); 285 + } else { 286 + /* Set default gain */ 287 + hmc425a_write(indio_dev, st->gain); 288 + } 393 289 394 290 return devm_iio_device_register(&pdev->dev, indio_dev); 395 291 } ··· 407 293 .data = &hmc425a_chip_info_tbl[ID_HMC540S]}, 408 294 { .compatible = "adi,adrf5740", 409 295 .data = &hmc425a_chip_info_tbl[ID_ADRF5740]}, 296 + { .compatible = "adi,ltc6373", 297 + .data = &hmc425a_chip_info_tbl[ID_LTC6373]}, 410 298 {} 411 299 }; 412 300 MODULE_DEVICE_TABLE(of, hmc425a_of_match);