Commit 0b2a740b authored by Liam Beguin's avatar Liam Beguin Committed by Jonathan Cameron

iio: adc: ad7949: enable use with non 14/16-bit controllers

This driver supports devices with 14-bit and 16-bit sample sizes.
This implies different SPI transfer lengths which are not always handled
properly by some SPI controllers.

To work around this limitation, define a big endian buffer used to split
the buffer into two 8-bit messages in the event that the controller
doesn't support 14-bit or 16-bit transfers.
A separate buffer is introduced here to avoid performing operations on
types of different endianness.

Since all transfers use the same bits_per_word value, move that logic to
the probe function, and let transfers default to the value defined in
the struct spi_device.
Signed-off-by: default avatarLiam Beguin <lvb@xiphos.com>
Link: https://lore.kernel.org/r/20210815213309.2847711-3-liambeguin@gmail.comSigned-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 595a0590
......@@ -14,7 +14,6 @@
#include <linux/bitfield.h>
#define AD7949_CFG_MASK_TOTAL GENMASK(13, 0)
#define AD7949_CFG_REG_SIZE_BITS 14
/* CFG: Configuration Update */
#define AD7949_CFG_MASK_OVERWRITE BIT(13)
......@@ -71,6 +70,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
* @cfg: copy of the configuration register
* @current_channel: current channel in use
* @buffer: buffer to send / receive data to / from device
* @buf8b: be16 buffer to exchange data with the device in 8-bit transfers
*/
struct ad7949_adc_chip {
struct mutex lock;
......@@ -81,27 +81,34 @@ struct ad7949_adc_chip {
u16 cfg;
unsigned int current_channel;
u16 buffer ____cacheline_aligned;
__be16 buf8b;
};
static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
u16 mask)
{
int ret;
int bits_per_word = ad7949_adc->resolution;
int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
struct spi_message msg;
struct spi_transfer tx[] = {
{
.tx_buf = &ad7949_adc->buffer,
.len = 2,
.bits_per_word = bits_per_word,
},
};
ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
ad7949_adc->buffer = ad7949_adc->cfg << shift;
spi_message_init_with_transfers(&msg, tx, 1);
ret = spi_sync(ad7949_adc->spi, &msg);
switch (ad7949_adc->spi->bits_per_word) {
case 16:
ad7949_adc->buffer = ad7949_adc->cfg << 2;
ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2);
break;
case 14:
ad7949_adc->buffer = ad7949_adc->cfg;
ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2);
break;
case 8:
/* Here, type is big endian as it must be sent in two transfers */
ad7949_adc->buf8b = cpu_to_be16(ad7949_adc->cfg << 2);
ret = spi_write(ad7949_adc->spi, &ad7949_adc->buf8b, 2);
break;
default:
dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n");
return -EINVAL;
}
/*
* This delay is to avoid a new request before the required time to
......@@ -116,16 +123,6 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
{
int ret;
int i;
int bits_per_word = ad7949_adc->resolution;
int mask = GENMASK(ad7949_adc->resolution - 1, 0);
struct spi_message msg;
struct spi_transfer tx[] = {
{
.rx_buf = &ad7949_adc->buffer,
.len = 2,
.bits_per_word = bits_per_word,
},
};
/*
* 1: write CFG for sample N and read old data (sample N-2)
......@@ -144,9 +141,11 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
}
/* 3: write something and read actual data */
ad7949_adc->buffer = 0;
spi_message_init_with_transfers(&msg, tx, 1);
ret = spi_sync(ad7949_adc->spi, &msg);
if (ad7949_adc->spi->bits_per_word == 8)
ret = spi_read(ad7949_adc->spi, &ad7949_adc->buf8b, 2);
else
ret = spi_read(ad7949_adc->spi, &ad7949_adc->buffer, 2);
if (ret)
return ret;
......@@ -158,7 +157,25 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
ad7949_adc->current_channel = channel;
*val = ad7949_adc->buffer & mask;
switch (ad7949_adc->spi->bits_per_word) {
case 16:
*val = ad7949_adc->buffer;
/* Shift-out padding bits */
*val >>= 16 - ad7949_adc->resolution;
break;
case 14:
*val = ad7949_adc->buffer & GENMASK(13, 0);
break;
case 8:
/* Here, type is big endian as data was sent in two transfers */
*val = be16_to_cpu(ad7949_adc->buf8b);
/* Shift-out padding bits */
*val >>= 16 - ad7949_adc->resolution;
break;
default:
dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n");
return -EINVAL;
}
return 0;
}
......@@ -266,6 +283,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
static int ad7949_spi_probe(struct spi_device *spi)
{
u32 spi_ctrl_mask = spi->controller->bits_per_word_mask;
struct device *dev = &spi->dev;
const struct ad7949_adc_spec *spec;
struct ad7949_adc_chip *ad7949_adc;
......@@ -292,6 +310,18 @@ static int ad7949_spi_probe(struct spi_device *spi)
indio_dev->num_channels = spec->num_channels;
ad7949_adc->resolution = spec->resolution;
/* Set SPI bits per word */
if (spi_ctrl_mask & SPI_BPW_MASK(ad7949_adc->resolution)) {
spi->bits_per_word = ad7949_adc->resolution;
} else if (spi_ctrl_mask == SPI_BPW_MASK(16)) {
spi->bits_per_word = 16;
} else if (spi_ctrl_mask == SPI_BPW_MASK(8)) {
spi->bits_per_word = 8;
} else {
dev_err(dev, "unable to find common BPW with spi controller\n");
return -EINVAL;
}
ad7949_adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(ad7949_adc->vref)) {
dev_err(dev, "fail to request regulator\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment