mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: Liam Beguin <lvb@xiphos.com> Link: https://lore.kernel.org/r/20210815213309.2847711-3-liambeguin@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
595a0590f4
commit
0b2a740b42
1 changed files with 58 additions and 28 deletions
|
@ -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[] = {
|
||||||
* @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 {
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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");
|
||||||
|
|
Loading…
Add table
Reference in a new issue