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 @@ ...@@ -14,7 +14,6 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#define AD7949_CFG_MASK_TOTAL GENMASK(13, 0) #define AD7949_CFG_MASK_TOTAL GENMASK(13, 0)
#define AD7949_CFG_REG_SIZE_BITS 14
/* CFG: Configuration Update */ /* CFG: Configuration Update */
#define AD7949_CFG_MASK_OVERWRITE BIT(13) #define AD7949_CFG_MASK_OVERWRITE BIT(13)
...@@ -71,6 +70,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = { ...@@ -71,6 +70,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
* @cfg: copy of the configuration register * @cfg: copy of the configuration register
* @current_channel: current channel in use * @current_channel: current channel in use
* @buffer: buffer to send / receive data to / from device * @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 ad7949_adc_chip {
struct mutex lock; struct mutex lock;
...@@ -81,27 +81,34 @@ struct ad7949_adc_chip { ...@@ -81,27 +81,34 @@ struct ad7949_adc_chip {
u16 cfg; u16 cfg;
unsigned int current_channel; unsigned int current_channel;
u16 buffer ____cacheline_aligned; u16 buffer ____cacheline_aligned;
__be16 buf8b;
}; };
static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val, static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
u16 mask) u16 mask)
{ {
int ret; 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->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
ad7949_adc->buffer = ad7949_adc->cfg << shift;
spi_message_init_with_transfers(&msg, tx, 1); switch (ad7949_adc->spi->bits_per_word) {
ret = spi_sync(ad7949_adc->spi, &msg); 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 * 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, ...@@ -116,16 +123,6 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
{ {
int ret; int ret;
int i; 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) * 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, ...@@ -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 */ /* 3: write something and read actual data */
ad7949_adc->buffer = 0; if (ad7949_adc->spi->bits_per_word == 8)
spi_message_init_with_transfers(&msg, tx, 1); ret = spi_read(ad7949_adc->spi, &ad7949_adc->buf8b, 2);
ret = spi_sync(ad7949_adc->spi, &msg); else
ret = spi_read(ad7949_adc->spi, &ad7949_adc->buffer, 2);
if (ret) if (ret)
return ret; return ret;
...@@ -158,7 +157,25 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, ...@@ -158,7 +157,25 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
ad7949_adc->current_channel = channel; 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; return 0;
} }
...@@ -266,6 +283,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc) ...@@ -266,6 +283,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
static int ad7949_spi_probe(struct spi_device *spi) static int ad7949_spi_probe(struct spi_device *spi)
{ {
u32 spi_ctrl_mask = spi->controller->bits_per_word_mask;
struct device *dev = &spi->dev; struct device *dev = &spi->dev;
const struct ad7949_adc_spec *spec; const struct ad7949_adc_spec *spec;
struct ad7949_adc_chip *ad7949_adc; struct ad7949_adc_chip *ad7949_adc;
...@@ -292,6 +310,18 @@ static int ad7949_spi_probe(struct spi_device *spi) ...@@ -292,6 +310,18 @@ static int ad7949_spi_probe(struct spi_device *spi)
indio_dev->num_channels = spec->num_channels; indio_dev->num_channels = spec->num_channels;
ad7949_adc->resolution = spec->resolution; 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"); ad7949_adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(ad7949_adc->vref)) { if (IS_ERR(ad7949_adc->vref)) {
dev_err(dev, "fail to request regulator\n"); 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