1*733e0fedSLiam Beguin // SPDX-License-Identifier: GPL-2.0 2*733e0fedSLiam Beguin /* 3*733e0fedSLiam Beguin * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface. 4*733e0fedSLiam Beguin * 5*733e0fedSLiam Beguin * Datasheet: 6*733e0fedSLiam Beguin * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf 7*733e0fedSLiam Beguin * 8*733e0fedSLiam Beguin * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com> 9*733e0fedSLiam Beguin */ 10*733e0fedSLiam Beguin #include <linux/bitfield.h> 11*733e0fedSLiam Beguin #include <linux/i2c.h> 12*733e0fedSLiam Beguin #include <linux/iio/iio.h> 13*733e0fedSLiam Beguin #include <linux/kernel.h> 14*733e0fedSLiam Beguin #include <linux/module.h> 15*733e0fedSLiam Beguin #include <linux/mutex.h> 16*733e0fedSLiam Beguin #include <linux/regulator/consumer.h> 17*733e0fedSLiam Beguin 18*733e0fedSLiam Beguin #define LTC2309_ADC_RESOLUTION 12 19*733e0fedSLiam Beguin 20*733e0fedSLiam Beguin #define LTC2309_DIN_CH_MASK GENMASK(7, 4) 21*733e0fedSLiam Beguin #define LTC2309_DIN_SDN BIT(7) 22*733e0fedSLiam Beguin #define LTC2309_DIN_OSN BIT(6) 23*733e0fedSLiam Beguin #define LTC2309_DIN_S1 BIT(5) 24*733e0fedSLiam Beguin #define LTC2309_DIN_S0 BIT(4) 25*733e0fedSLiam Beguin #define LTC2309_DIN_UNI BIT(3) 26*733e0fedSLiam Beguin #define LTC2309_DIN_SLEEP BIT(2) 27*733e0fedSLiam Beguin 28*733e0fedSLiam Beguin /** 29*733e0fedSLiam Beguin * struct ltc2309 - internal device data structure 30*733e0fedSLiam Beguin * @dev: Device reference 31*733e0fedSLiam Beguin * @client: I2C reference 32*733e0fedSLiam Beguin * @vref: External reference source 33*733e0fedSLiam Beguin * @lock: Lock to serialize data access 34*733e0fedSLiam Beguin * @vref_mv: Internal voltage reference 35*733e0fedSLiam Beguin */ 36*733e0fedSLiam Beguin struct ltc2309 { 37*733e0fedSLiam Beguin struct device *dev; 38*733e0fedSLiam Beguin struct i2c_client *client; 39*733e0fedSLiam Beguin struct regulator *vref; 40*733e0fedSLiam Beguin struct mutex lock; /* serialize data access */ 41*733e0fedSLiam Beguin int vref_mv; 42*733e0fedSLiam Beguin }; 43*733e0fedSLiam Beguin 44*733e0fedSLiam Beguin /* Order matches expected channel address, See datasheet Table 1. */ 45*733e0fedSLiam Beguin enum ltc2309_channels { 46*733e0fedSLiam Beguin LTC2309_CH0_CH1 = 0, 47*733e0fedSLiam Beguin LTC2309_CH2_CH3, 48*733e0fedSLiam Beguin LTC2309_CH4_CH5, 49*733e0fedSLiam Beguin LTC2309_CH6_CH7, 50*733e0fedSLiam Beguin LTC2309_CH1_CH0, 51*733e0fedSLiam Beguin LTC2309_CH3_CH2, 52*733e0fedSLiam Beguin LTC2309_CH5_CH4, 53*733e0fedSLiam Beguin LTC2309_CH7_CH6, 54*733e0fedSLiam Beguin LTC2309_CH0, 55*733e0fedSLiam Beguin LTC2309_CH2, 56*733e0fedSLiam Beguin LTC2309_CH4, 57*733e0fedSLiam Beguin LTC2309_CH6, 58*733e0fedSLiam Beguin LTC2309_CH1, 59*733e0fedSLiam Beguin LTC2309_CH3, 60*733e0fedSLiam Beguin LTC2309_CH5, 61*733e0fedSLiam Beguin LTC2309_CH7, 62*733e0fedSLiam Beguin }; 63*733e0fedSLiam Beguin 64*733e0fedSLiam Beguin #define LTC2309_CHAN(_chan, _addr) { \ 65*733e0fedSLiam Beguin .type = IIO_VOLTAGE, \ 66*733e0fedSLiam Beguin .indexed = 1, \ 67*733e0fedSLiam Beguin .address = _addr, \ 68*733e0fedSLiam Beguin .channel = _chan, \ 69*733e0fedSLiam Beguin .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 70*733e0fedSLiam Beguin .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 71*733e0fedSLiam Beguin } 72*733e0fedSLiam Beguin 73*733e0fedSLiam Beguin #define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \ 74*733e0fedSLiam Beguin .type = IIO_VOLTAGE, \ 75*733e0fedSLiam Beguin .differential = 1, \ 76*733e0fedSLiam Beguin .indexed = 1, \ 77*733e0fedSLiam Beguin .address = _addr, \ 78*733e0fedSLiam Beguin .channel = _chan, \ 79*733e0fedSLiam Beguin .channel2 = _chan2, \ 80*733e0fedSLiam Beguin .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 81*733e0fedSLiam Beguin .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 82*733e0fedSLiam Beguin } 83*733e0fedSLiam Beguin 84*733e0fedSLiam Beguin static const struct iio_chan_spec ltc2309_channels[] = { 85*733e0fedSLiam Beguin LTC2309_CHAN(0, LTC2309_CH0), 86*733e0fedSLiam Beguin LTC2309_CHAN(1, LTC2309_CH1), 87*733e0fedSLiam Beguin LTC2309_CHAN(2, LTC2309_CH2), 88*733e0fedSLiam Beguin LTC2309_CHAN(3, LTC2309_CH3), 89*733e0fedSLiam Beguin LTC2309_CHAN(4, LTC2309_CH4), 90*733e0fedSLiam Beguin LTC2309_CHAN(5, LTC2309_CH5), 91*733e0fedSLiam Beguin LTC2309_CHAN(6, LTC2309_CH6), 92*733e0fedSLiam Beguin LTC2309_CHAN(7, LTC2309_CH7), 93*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1), 94*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3), 95*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5), 96*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7), 97*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0), 98*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2), 99*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4), 100*733e0fedSLiam Beguin LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6), 101*733e0fedSLiam Beguin }; 102*733e0fedSLiam Beguin 103*733e0fedSLiam Beguin static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, 104*733e0fedSLiam Beguin unsigned long address, int *val) 105*733e0fedSLiam Beguin { 106*733e0fedSLiam Beguin int ret; 107*733e0fedSLiam Beguin u16 buf; 108*733e0fedSLiam Beguin u8 din; 109*733e0fedSLiam Beguin 110*733e0fedSLiam Beguin din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) | 111*733e0fedSLiam Beguin FIELD_PREP(LTC2309_DIN_UNI, 1) | 112*733e0fedSLiam Beguin FIELD_PREP(LTC2309_DIN_SLEEP, 0); 113*733e0fedSLiam Beguin 114*733e0fedSLiam Beguin ret = i2c_smbus_write_byte(ltc2309->client, din); 115*733e0fedSLiam Beguin if (ret < 0) { 116*733e0fedSLiam Beguin dev_err(ltc2309->dev, "i2c command failed: %pe\n", 117*733e0fedSLiam Beguin ERR_PTR(ret)); 118*733e0fedSLiam Beguin return ret; 119*733e0fedSLiam Beguin } 120*733e0fedSLiam Beguin 121*733e0fedSLiam Beguin ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2); 122*733e0fedSLiam Beguin if (ret < 0) { 123*733e0fedSLiam Beguin dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret)); 124*733e0fedSLiam Beguin return ret; 125*733e0fedSLiam Beguin } 126*733e0fedSLiam Beguin 127*733e0fedSLiam Beguin *val = be16_to_cpu(buf) >> 4; 128*733e0fedSLiam Beguin 129*733e0fedSLiam Beguin return ret; 130*733e0fedSLiam Beguin } 131*733e0fedSLiam Beguin 132*733e0fedSLiam Beguin static int ltc2309_read_raw(struct iio_dev *indio_dev, 133*733e0fedSLiam Beguin struct iio_chan_spec const *chan, int *val, 134*733e0fedSLiam Beguin int *val2, long mask) 135*733e0fedSLiam Beguin { 136*733e0fedSLiam Beguin struct ltc2309 *ltc2309 = iio_priv(indio_dev); 137*733e0fedSLiam Beguin int ret; 138*733e0fedSLiam Beguin 139*733e0fedSLiam Beguin switch (mask) { 140*733e0fedSLiam Beguin case IIO_CHAN_INFO_RAW: 141*733e0fedSLiam Beguin mutex_lock(<c2309->lock); 142*733e0fedSLiam Beguin ret = ltc2309_read_raw_channel(ltc2309, chan->address, val); 143*733e0fedSLiam Beguin mutex_unlock(<c2309->lock); 144*733e0fedSLiam Beguin if (ret < 0) 145*733e0fedSLiam Beguin return -EINVAL; 146*733e0fedSLiam Beguin return IIO_VAL_INT; 147*733e0fedSLiam Beguin case IIO_CHAN_INFO_SCALE: 148*733e0fedSLiam Beguin *val = ltc2309->vref_mv; 149*733e0fedSLiam Beguin *val2 = LTC2309_ADC_RESOLUTION; 150*733e0fedSLiam Beguin return IIO_VAL_FRACTIONAL_LOG2; 151*733e0fedSLiam Beguin default: 152*733e0fedSLiam Beguin return -EINVAL; 153*733e0fedSLiam Beguin } 154*733e0fedSLiam Beguin } 155*733e0fedSLiam Beguin 156*733e0fedSLiam Beguin static const struct iio_info ltc2309_info = { 157*733e0fedSLiam Beguin .read_raw = ltc2309_read_raw, 158*733e0fedSLiam Beguin }; 159*733e0fedSLiam Beguin 160*733e0fedSLiam Beguin static void ltc2309_regulator_disable(void *regulator) 161*733e0fedSLiam Beguin { 162*733e0fedSLiam Beguin regulator_disable(regulator); 163*733e0fedSLiam Beguin } 164*733e0fedSLiam Beguin 165*733e0fedSLiam Beguin static int ltc2309_probe(struct i2c_client *client) 166*733e0fedSLiam Beguin { 167*733e0fedSLiam Beguin struct iio_dev *indio_dev; 168*733e0fedSLiam Beguin struct ltc2309 *ltc2309; 169*733e0fedSLiam Beguin int ret; 170*733e0fedSLiam Beguin 171*733e0fedSLiam Beguin indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309)); 172*733e0fedSLiam Beguin if (!indio_dev) 173*733e0fedSLiam Beguin return -ENOMEM; 174*733e0fedSLiam Beguin 175*733e0fedSLiam Beguin ltc2309 = iio_priv(indio_dev); 176*733e0fedSLiam Beguin ltc2309->dev = &indio_dev->dev; 177*733e0fedSLiam Beguin ltc2309->client = client; 178*733e0fedSLiam Beguin ltc2309->vref_mv = 4096; /* Default to the internal ref */ 179*733e0fedSLiam Beguin 180*733e0fedSLiam Beguin indio_dev->name = "ltc2309"; 181*733e0fedSLiam Beguin indio_dev->modes = INDIO_DIRECT_MODE; 182*733e0fedSLiam Beguin indio_dev->channels = ltc2309_channels; 183*733e0fedSLiam Beguin indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); 184*733e0fedSLiam Beguin indio_dev->info = <c2309_info; 185*733e0fedSLiam Beguin 186*733e0fedSLiam Beguin ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref"); 187*733e0fedSLiam Beguin if (IS_ERR(ltc2309->vref)) { 188*733e0fedSLiam Beguin ret = PTR_ERR(ltc2309->vref); 189*733e0fedSLiam Beguin if (ret == -ENODEV) 190*733e0fedSLiam Beguin ltc2309->vref = NULL; 191*733e0fedSLiam Beguin else 192*733e0fedSLiam Beguin return ret; 193*733e0fedSLiam Beguin } 194*733e0fedSLiam Beguin 195*733e0fedSLiam Beguin if (ltc2309->vref) { 196*733e0fedSLiam Beguin ret = regulator_enable(ltc2309->vref); 197*733e0fedSLiam Beguin if (ret) 198*733e0fedSLiam Beguin return dev_err_probe(ltc2309->dev, ret, 199*733e0fedSLiam Beguin "failed to enable vref\n"); 200*733e0fedSLiam Beguin 201*733e0fedSLiam Beguin ret = devm_add_action_or_reset(ltc2309->dev, 202*733e0fedSLiam Beguin ltc2309_regulator_disable, 203*733e0fedSLiam Beguin ltc2309->vref); 204*733e0fedSLiam Beguin if (ret) { 205*733e0fedSLiam Beguin return dev_err_probe(ltc2309->dev, ret, 206*733e0fedSLiam Beguin "failed to add regulator_disable action: %d\n", 207*733e0fedSLiam Beguin ret); 208*733e0fedSLiam Beguin } 209*733e0fedSLiam Beguin 210*733e0fedSLiam Beguin ret = regulator_get_voltage(ltc2309->vref); 211*733e0fedSLiam Beguin if (ret < 0) 212*733e0fedSLiam Beguin return ret; 213*733e0fedSLiam Beguin 214*733e0fedSLiam Beguin ltc2309->vref_mv = ret / 1000; 215*733e0fedSLiam Beguin } 216*733e0fedSLiam Beguin 217*733e0fedSLiam Beguin mutex_init(<c2309->lock); 218*733e0fedSLiam Beguin 219*733e0fedSLiam Beguin return devm_iio_device_register(&client->dev, indio_dev); 220*733e0fedSLiam Beguin } 221*733e0fedSLiam Beguin 222*733e0fedSLiam Beguin static const struct of_device_id ltc2309_of_match[] = { 223*733e0fedSLiam Beguin { .compatible = "lltc,ltc2309" }, 224*733e0fedSLiam Beguin { } 225*733e0fedSLiam Beguin }; 226*733e0fedSLiam Beguin MODULE_DEVICE_TABLE(of, ltc2309_of_match); 227*733e0fedSLiam Beguin 228*733e0fedSLiam Beguin static const struct i2c_device_id ltc2309_id[] = { 229*733e0fedSLiam Beguin { "ltc2309" }, 230*733e0fedSLiam Beguin { } 231*733e0fedSLiam Beguin }; 232*733e0fedSLiam Beguin MODULE_DEVICE_TABLE(i2c, ltc2309_id); 233*733e0fedSLiam Beguin 234*733e0fedSLiam Beguin static struct i2c_driver ltc2309_driver = { 235*733e0fedSLiam Beguin .driver = { 236*733e0fedSLiam Beguin .name = "ltc2309", 237*733e0fedSLiam Beguin .of_match_table = ltc2309_of_match, 238*733e0fedSLiam Beguin }, 239*733e0fedSLiam Beguin .probe = ltc2309_probe, 240*733e0fedSLiam Beguin .id_table = ltc2309_id, 241*733e0fedSLiam Beguin }; 242*733e0fedSLiam Beguin module_i2c_driver(ltc2309_driver); 243*733e0fedSLiam Beguin 244*733e0fedSLiam Beguin MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>"); 245*733e0fedSLiam Beguin MODULE_DESCRIPTION("Linear Technology LTC2309 ADC"); 246*733e0fedSLiam Beguin MODULE_LICENSE("GPL v2"); 247