Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * ADS8344 16-bit 8-Channel ADC driver
0004  *
0005  * Author: Gregory CLEMENT <gregory.clement@bootlin.com>
0006  *
0007  * Datasheet: https://www.ti.com/lit/ds/symlink/ads8344.pdf
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/iio/buffer.h>
0012 #include <linux/iio/iio.h>
0013 #include <linux/module.h>
0014 #include <linux/regulator/consumer.h>
0015 #include <linux/spi/spi.h>
0016 
0017 #define ADS8344_START BIT(7)
0018 #define ADS8344_SINGLE_END BIT(2)
0019 #define ADS8344_CHANNEL(channel) ((channel) << 4)
0020 #define ADS8344_CLOCK_INTERNAL 0x2 /* PD1 = 1 and PD0 = 0 */
0021 
0022 struct ads8344 {
0023     struct spi_device *spi;
0024     struct regulator *reg;
0025     /*
0026      * Lock protecting access to adc->tx_buff and rx_buff,
0027      * especially from concurrent read on sysfs file.
0028      */
0029     struct mutex lock;
0030 
0031     u8 tx_buf __aligned(IIO_DMA_MINALIGN);
0032     u8 rx_buf[3];
0033 };
0034 
0035 #define ADS8344_VOLTAGE_CHANNEL(chan, addr)             \
0036     {                               \
0037         .type = IIO_VOLTAGE,                    \
0038         .indexed = 1,                       \
0039         .channel = chan,                    \
0040         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),       \
0041         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
0042         .address = addr,                    \
0043     }
0044 
0045 #define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, addr)        \
0046     {                               \
0047         .type = IIO_VOLTAGE,                    \
0048         .indexed = 1,                       \
0049         .channel = (chan1),                 \
0050         .channel2 = (chan2),                    \
0051         .differential = 1,                  \
0052         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),       \
0053         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
0054         .address = addr,                    \
0055     }
0056 
0057 static const struct iio_chan_spec ads8344_channels[] = {
0058     ADS8344_VOLTAGE_CHANNEL(0, 0),
0059     ADS8344_VOLTAGE_CHANNEL(1, 4),
0060     ADS8344_VOLTAGE_CHANNEL(2, 1),
0061     ADS8344_VOLTAGE_CHANNEL(3, 5),
0062     ADS8344_VOLTAGE_CHANNEL(4, 2),
0063     ADS8344_VOLTAGE_CHANNEL(5, 6),
0064     ADS8344_VOLTAGE_CHANNEL(6, 3),
0065     ADS8344_VOLTAGE_CHANNEL(7, 7),
0066     ADS8344_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
0067     ADS8344_VOLTAGE_CHANNEL_DIFF(2, 3, 9),
0068     ADS8344_VOLTAGE_CHANNEL_DIFF(4, 5, 10),
0069     ADS8344_VOLTAGE_CHANNEL_DIFF(6, 7, 11),
0070     ADS8344_VOLTAGE_CHANNEL_DIFF(1, 0, 12),
0071     ADS8344_VOLTAGE_CHANNEL_DIFF(3, 2, 13),
0072     ADS8344_VOLTAGE_CHANNEL_DIFF(5, 4, 14),
0073     ADS8344_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
0074 };
0075 
0076 static int ads8344_adc_conversion(struct ads8344 *adc, int channel,
0077                   bool differential)
0078 {
0079     struct spi_device *spi = adc->spi;
0080     int ret;
0081 
0082     adc->tx_buf = ADS8344_START;
0083     if (!differential)
0084         adc->tx_buf |= ADS8344_SINGLE_END;
0085     adc->tx_buf |= ADS8344_CHANNEL(channel);
0086     adc->tx_buf |= ADS8344_CLOCK_INTERNAL;
0087 
0088     ret = spi_write(spi, &adc->tx_buf, 1);
0089     if (ret)
0090         return ret;
0091 
0092     udelay(9);
0093 
0094     ret = spi_read(spi, adc->rx_buf, sizeof(adc->rx_buf));
0095     if (ret)
0096         return ret;
0097 
0098     return adc->rx_buf[0] << 9 | adc->rx_buf[1] << 1 | adc->rx_buf[2] >> 7;
0099 }
0100 
0101 static int ads8344_read_raw(struct iio_dev *iio,
0102                 struct iio_chan_spec const *channel, int *value,
0103                 int *shift, long mask)
0104 {
0105     struct ads8344 *adc = iio_priv(iio);
0106 
0107     switch (mask) {
0108     case IIO_CHAN_INFO_RAW:
0109         mutex_lock(&adc->lock);
0110         *value = ads8344_adc_conversion(adc, channel->address,
0111                         channel->differential);
0112         mutex_unlock(&adc->lock);
0113         if (*value < 0)
0114             return *value;
0115 
0116         return IIO_VAL_INT;
0117     case IIO_CHAN_INFO_SCALE:
0118         *value = regulator_get_voltage(adc->reg);
0119         if (*value < 0)
0120             return *value;
0121 
0122         /* convert regulator output voltage to mV */
0123         *value /= 1000;
0124         *shift = 16;
0125 
0126         return IIO_VAL_FRACTIONAL_LOG2;
0127     default:
0128         return -EINVAL;
0129     }
0130 }
0131 
0132 static const struct iio_info ads8344_info = {
0133     .read_raw = ads8344_read_raw,
0134 };
0135 
0136 static void ads8344_reg_disable(void *data)
0137 {
0138     regulator_disable(data);
0139 }
0140 
0141 static int ads8344_probe(struct spi_device *spi)
0142 {
0143     struct iio_dev *indio_dev;
0144     struct ads8344 *adc;
0145     int ret;
0146 
0147     indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
0148     if (!indio_dev)
0149         return -ENOMEM;
0150 
0151     adc = iio_priv(indio_dev);
0152     adc->spi = spi;
0153     mutex_init(&adc->lock);
0154 
0155     indio_dev->name = dev_name(&spi->dev);
0156     indio_dev->info = &ads8344_info;
0157     indio_dev->modes = INDIO_DIRECT_MODE;
0158     indio_dev->channels = ads8344_channels;
0159     indio_dev->num_channels = ARRAY_SIZE(ads8344_channels);
0160 
0161     adc->reg = devm_regulator_get(&spi->dev, "vref");
0162     if (IS_ERR(adc->reg))
0163         return PTR_ERR(adc->reg);
0164 
0165     ret = regulator_enable(adc->reg);
0166     if (ret)
0167         return ret;
0168 
0169     ret = devm_add_action_or_reset(&spi->dev, ads8344_reg_disable, adc->reg);
0170     if (ret)
0171         return ret;
0172 
0173     return devm_iio_device_register(&spi->dev, indio_dev);
0174 }
0175 
0176 static const struct of_device_id ads8344_of_match[] = {
0177     { .compatible = "ti,ads8344", },
0178     {}
0179 };
0180 MODULE_DEVICE_TABLE(of, ads8344_of_match);
0181 
0182 static struct spi_driver ads8344_driver = {
0183     .driver = {
0184         .name = "ads8344",
0185         .of_match_table = ads8344_of_match,
0186     },
0187     .probe = ads8344_probe,
0188 };
0189 module_spi_driver(ads8344_driver);
0190 
0191 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@bootlin.com>");
0192 MODULE_DESCRIPTION("ADS8344 driver");
0193 MODULE_LICENSE("GPL");