linux/drivers/iio/adc/ti-ads8344.c
Lars-Peter Clausen 8cb631ccbb iio: Remove superfluous of_node assignments
If a driver does not assign an of_node to a IIO device to IIO core will
automatically assign the of_node of the parent device. This automatic
assignment is done in the iio_device_register() function.

There is a fair amount of drivers that currently manually assign the
of_node of the IIO device. All but 4 of them can make use of the automatic
assignment though.

The exceptions are:
 * mxs-lradc-adc: Which uses the of_node of the parent of the parent.
 * stm32-dfsdm-adc, stm32-adc and stm32-dac: Which reference the of_node
   assigned to the IIO device before iio_device_register() is called.

All other drivers are updated to use automatic assignment. This reduces
the amount of boilerplate code involved in setting up the IIO device.

The patch has mostly been auto-generated with the following semantic patch

// <smpl>
@exists@
expression indio_dev;
expression parent;
@@
indio_dev = \(devm_iio_device_alloc\|iio_device_alloc\)(&parent, ...)
...
-indio_dev->dev.of_node = parent.of_node;

@exists@
expression indio_dev;
expression parent;
@@
indio_dev = \(devm_iio_device_alloc\|iio_device_alloc\)(parent, ...)
...
-indio_dev->dev.of_node = parent->of_node;
// </smpl>

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2020-06-14 14:20:08 +01:00

205 lines
4.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* ADS8344 16-bit 8-Channel ADC driver
*
* Author: Gregory CLEMENT <gregory.clement@bootlin.com>
*
* Datasheet: http://www.ti.com/lit/ds/symlink/ads8344.pdf
*/
#include <linux/delay.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#define ADS8344_START BIT(7)
#define ADS8344_SINGLE_END BIT(2)
#define ADS8344_CHANNEL(channel) ((channel) << 4)
#define ADS8344_CLOCK_INTERNAL 0x2 /* PD1 = 1 and PD0 = 0 */
struct ads8344 {
struct spi_device *spi;
struct regulator *reg;
/*
* Lock protecting access to adc->tx_buff and rx_buff,
* especially from concurrent read on sysfs file.
*/
struct mutex lock;
u8 tx_buf ____cacheline_aligned;
u8 rx_buf[3];
};
#define ADS8344_VOLTAGE_CHANNEL(chan, addr) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = addr, \
}
#define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, addr) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan1), \
.channel2 = (chan2), \
.differential = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = addr, \
}
static const struct iio_chan_spec ads8344_channels[] = {
ADS8344_VOLTAGE_CHANNEL(0, 0),
ADS8344_VOLTAGE_CHANNEL(1, 4),
ADS8344_VOLTAGE_CHANNEL(2, 1),
ADS8344_VOLTAGE_CHANNEL(3, 5),
ADS8344_VOLTAGE_CHANNEL(4, 2),
ADS8344_VOLTAGE_CHANNEL(5, 6),
ADS8344_VOLTAGE_CHANNEL(6, 3),
ADS8344_VOLTAGE_CHANNEL(7, 7),
ADS8344_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
ADS8344_VOLTAGE_CHANNEL_DIFF(2, 3, 9),
ADS8344_VOLTAGE_CHANNEL_DIFF(4, 5, 10),
ADS8344_VOLTAGE_CHANNEL_DIFF(6, 7, 11),
ADS8344_VOLTAGE_CHANNEL_DIFF(1, 0, 12),
ADS8344_VOLTAGE_CHANNEL_DIFF(3, 2, 13),
ADS8344_VOLTAGE_CHANNEL_DIFF(5, 4, 14),
ADS8344_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
};
static int ads8344_adc_conversion(struct ads8344 *adc, int channel,
bool differential)
{
struct spi_device *spi = adc->spi;
int ret;
adc->tx_buf = ADS8344_START;
if (!differential)
adc->tx_buf |= ADS8344_SINGLE_END;
adc->tx_buf |= ADS8344_CHANNEL(channel);
adc->tx_buf |= ADS8344_CLOCK_INTERNAL;
ret = spi_write(spi, &adc->tx_buf, 1);
if (ret)
return ret;
udelay(9);
ret = spi_read(spi, adc->rx_buf, sizeof(adc->rx_buf));
if (ret)
return ret;
return adc->rx_buf[0] << 9 | adc->rx_buf[1] << 1 | adc->rx_buf[2] >> 7;
}
static int ads8344_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *value,
int *shift, long mask)
{
struct ads8344 *adc = iio_priv(iio);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
*value = ads8344_adc_conversion(adc, channel->address,
channel->differential);
mutex_unlock(&adc->lock);
if (*value < 0)
return *value;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*value = regulator_get_voltage(adc->reg);
if (*value < 0)
return *value;
/* convert regulator output voltage to mV */
*value /= 1000;
*shift = 16;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static const struct iio_info ads8344_info = {
.read_raw = ads8344_read_raw,
};
static int ads8344_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ads8344 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
mutex_init(&adc->lock);
indio_dev->name = dev_name(&spi->dev);
indio_dev->info = &ads8344_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ads8344_channels;
indio_dev->num_channels = ARRAY_SIZE(ads8344_channels);
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret)
return ret;
spi_set_drvdata(spi, indio_dev);
ret = iio_device_register(indio_dev);
if (ret) {
regulator_disable(adc->reg);
return ret;
}
return 0;
}
static int ads8344_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ads8344 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
static const struct of_device_id ads8344_of_match[] = {
{ .compatible = "ti,ads8344", },
{}
};
MODULE_DEVICE_TABLE(of, ads8344_of_match);
static struct spi_driver ads8344_driver = {
.driver = {
.name = "ads8344",
.of_match_table = ads8344_of_match,
},
.probe = ads8344_probe,
.remove = ads8344_remove,
};
module_spi_driver(ads8344_driver);
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@bootlin.com>");
MODULE_DESCRIPTION("ADS8344 driver");
MODULE_LICENSE("GPL");