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

drivers: iio: adc: ltc2497: LTC2499 support

The LTC2499 is a 16-channel (eight differential), 24-bit,
ADC with Easy Drive technology and a 2-wire, I2C interface.

Implement support for the LTC2499 ADC by extending the LTC2497
driver. A new chip_info struct is added to differentiate between
chip types and resolutions when reading data from the device.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2499fe.pdf
Signed-off-by: Ciprian Regus <ciprian.regus@analog.com>
Link: https://lore.kernel.org/r/20220916140922.2506248-5-ciprian.regus@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Ciprian Regus and committed by
Jonathan Cameron
2187cfeb cc6fbf26

+70 -7
+7 -1
drivers/iio/adc/ltc2496.c
··· 15 15 #include <linux/iio/driver.h> 16 16 #include <linux/module.h> 17 17 #include <linux/mod_devicetable.h> 18 + #include <linux/property.h> 18 19 19 20 #include "ltc2497.h" 20 21 ··· 75 74 spi_set_drvdata(spi, indio_dev); 76 75 st->spi = spi; 77 76 st->common_ddata.result_and_measure = ltc2496_result_and_measure; 77 + st->common_ddata.chip_info = device_get_match_data(dev); 78 78 79 79 return ltc2497core_probe(dev, indio_dev); 80 80 } ··· 87 85 ltc2497core_remove(indio_dev); 88 86 } 89 87 88 + static const struct ltc2497_chip_info ltc2496_info = { 89 + .resolution = 16, 90 + }; 91 + 90 92 static const struct of_device_id ltc2496_of_match[] = { 91 - { .compatible = "lltc,ltc2496", }, 93 + { .compatible = "lltc,ltc2496", .data = &ltc2496_info, }, 92 94 {}, 93 95 }; 94 96 MODULE_DEVICE_TABLE(of, ltc2496_of_match);
+1 -1
drivers/iio/adc/ltc2497-core.c
··· 95 95 return ret; 96 96 97 97 *val = ret / 1000; 98 - *val2 = 17; 98 + *val2 = ddata->chip_info->resolution + 1; 99 99 100 100 return IIO_VAL_FRACTIONAL_LOG2; 101 101
+57 -5
drivers/iio/adc/ltc2497.c
··· 12 12 #include <linux/iio/driver.h> 13 13 #include <linux/module.h> 14 14 #include <linux/mod_devicetable.h> 15 + #include <linux/property.h> 16 + 17 + #include <asm/unaligned.h> 15 18 16 19 #include "ltc2497.h" 20 + 21 + enum ltc2497_chip_type { 22 + TYPE_LTC2497, 23 + TYPE_LTC2499, 24 + }; 17 25 18 26 struct ltc2497_driverdata { 19 27 /* this must be the first member */ 20 28 struct ltc2497core_driverdata common_ddata; 21 29 struct i2c_client *client; 30 + u32 recv_size; 31 + u32 sub_lsb; 22 32 /* 23 33 * DMA (thus cache coherency maintenance) may require the 24 34 * transfer buffers to live in their own cache lines. 25 35 */ 26 - __be32 buf __aligned(IIO_DMA_MINALIGN); 36 + union { 37 + __be32 d32; 38 + u8 d8[3]; 39 + } data __aligned(IIO_DMA_MINALIGN); 27 40 }; 28 41 29 42 static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata, ··· 47 34 int ret; 48 35 49 36 if (val) { 50 - ret = i2c_master_recv(st->client, (char *)&st->buf, 3); 37 + if (st->recv_size == 3) 38 + ret = i2c_master_recv(st->client, (char *)&st->data.d8, 39 + st->recv_size); 40 + else 41 + ret = i2c_master_recv(st->client, (char *)&st->data.d32, 42 + st->recv_size); 51 43 if (ret < 0) { 52 44 dev_err(&st->client->dev, "i2c_master_recv failed\n"); 53 45 return ret; 54 46 } 55 47 56 - *val = (be32_to_cpu(st->buf) >> 14) - (1 << 17); 48 + /* 49 + * The data format is 16/24 bit 2s complement, but with an upper sign bit on the 50 + * resolution + 1 position, which is set for positive values only. Given this 51 + * bit's value, subtracting BIT(resolution + 1) from the ADC's result is 52 + * equivalent to a sign extension. 53 + */ 54 + if (st->recv_size == 3) { 55 + *val = (get_unaligned_be24(st->data.d8) >> st->sub_lsb) 56 + - BIT(ddata->chip_info->resolution + 1); 57 + } else { 58 + *val = (be32_to_cpu(st->data.d32) >> st->sub_lsb) 59 + - BIT(ddata->chip_info->resolution + 1); 60 + } 57 61 58 62 /* 59 63 * The part started a new conversion at the end of the above i2c ··· 97 67 static int ltc2497_probe(struct i2c_client *client, 98 68 const struct i2c_device_id *id) 99 69 { 70 + const struct ltc2497_chip_info *chip_info; 100 71 struct iio_dev *indio_dev; 101 72 struct ltc2497_driverdata *st; 102 73 struct device *dev = &client->dev; 74 + u32 resolution; 103 75 104 76 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | 105 77 I2C_FUNC_SMBUS_WRITE_BYTE)) ··· 116 84 st->client = client; 117 85 st->common_ddata.result_and_measure = ltc2497_result_and_measure; 118 86 87 + chip_info = device_get_match_data(dev); 88 + if (!chip_info) 89 + chip_info = (const struct ltc2497_chip_info *)id->driver_data; 90 + st->common_ddata.chip_info = chip_info; 91 + 92 + resolution = chip_info->resolution; 93 + st->sub_lsb = 31 - (resolution + 1); 94 + st->recv_size = BITS_TO_BYTES(resolution) + 1; 95 + 119 96 return ltc2497core_probe(dev, indio_dev); 120 97 } 121 98 ··· 137 96 return 0; 138 97 } 139 98 99 + static const struct ltc2497_chip_info ltc2497_info[] = { 100 + [TYPE_LTC2497] = { 101 + .resolution = 16, 102 + }, 103 + [TYPE_LTC2499] = { 104 + .resolution = 24, 105 + }, 106 + }; 107 + 140 108 static const struct i2c_device_id ltc2497_id[] = { 141 - { "ltc2497", 0 }, 109 + { "ltc2497", (kernel_ulong_t)&ltc2497_info[TYPE_LTC2497] }, 110 + { "ltc2499", (kernel_ulong_t)&ltc2497_info[TYPE_LTC2499] }, 142 111 { } 143 112 }; 144 113 MODULE_DEVICE_TABLE(i2c, ltc2497_id); 145 114 146 115 static const struct of_device_id ltc2497_of_match[] = { 147 - { .compatible = "lltc,ltc2497", }, 116 + { .compatible = "lltc,ltc2497", .data = &ltc2497_info[TYPE_LTC2497] }, 117 + { .compatible = "lltc,ltc2499", .data = &ltc2497_info[TYPE_LTC2499] }, 148 118 {}, 149 119 }; 150 120 MODULE_DEVICE_TABLE(of, ltc2497_of_match);
+5
drivers/iio/adc/ltc2497.h
··· 4 4 #define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE 5 5 #define LTC2497_CONVERSION_TIME_MS 150ULL 6 6 7 + struct ltc2497_chip_info { 8 + u32 resolution; 9 + }; 10 + 7 11 struct ltc2497core_driverdata { 8 12 struct regulator *ref; 9 13 ktime_t time_prev; 14 + const struct ltc2497_chip_info *chip_info; 10 15 u8 addr_prev; 11 16 int (*result_and_measure)(struct ltc2497core_driverdata *ddata, 12 17 u8 address, int *val);