#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/crc-itu-t.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/device/devres.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/unaligned.h>
#define ADS131M_MAX_CHANNELS 8
#define ADS131M_RESET_DELAY_US 5
#define ADS131M_WORD_SIZE_BYTES 3
#define ADS131M_RESPONSE_WORDS 1
#define ADS131M_CRC_WORDS 1
#define ADS131M_FRAME_WORDS(nch) \
((nch) + ADS131M_RESPONSE_WORDS + ADS131M_CRC_WORDS)
#define ADS131M_FRAME_BYTES(nch) \
(ADS131M_FRAME_WORDS(nch) * ADS131M_WORD_SIZE_BYTES)
#define ADS131M_CHANNEL_INDEX(x) \
((x) * ADS131M_WORD_SIZE_BYTES + ADS131M_WORD_SIZE_BYTES)
#define ADS131M_CMD_NULL 0x0000
#define ADS131M_CMD_RESET 0x0011
#define ADS131M_CMD_ADDR_MASK GENMASK(11, 7)
#define ADS131M_CMD_NUM_MASK GENMASK(6, 0)
#define ADS131M_CMD_RREG_OP 0xa000
#define ADS131M_CMD_WREG_OP 0x6000
#define ADS131M_CMD_RREG(a, n) \
(ADS131M_CMD_RREG_OP | \
FIELD_PREP(ADS131M_CMD_ADDR_MASK, a) | \
FIELD_PREP(ADS131M_CMD_NUM_MASK, n))
#define ADS131M_CMD_WREG(a, n) \
(ADS131M_CMD_WREG_OP | \
FIELD_PREP(ADS131M_CMD_ADDR_MASK, a) | \
FIELD_PREP(ADS131M_CMD_NUM_MASK, n))
#define ADS131M_STATUS_CRC_ERR BIT(12)
#define ADS131M_REG_MODE 0x02
#define ADS131M_MODE_RX_CRC_EN BIT(12)
#define ADS131M_MODE_CRC_TYPE_ANSI BIT(11)
#define ADS131M_MODE_RESET_FLAG BIT(10)
#define ADS131M_REG_CLOCK 0x03
#define ADS131M_CLOCK_XTAL_DIS BIT(7)
#define ADS131M_CLOCK_EXTREF_EN BIT(6)
#define ADS131M_VREF_INTERNAL_mV 1200
#define ADS131M_RESOLUTION_BITS 24
#define ADS131M_CODE_BITS (ADS131M_RESOLUTION_BITS - 1)
#define ADS131M_EXTREF_SCALE_NUM 96
#define ADS131M_EXTREF_SCALE_DEN 100
struct ads131m_configuration {
const struct iio_chan_spec *channels;
const char *name;
u16 reset_ack;
u8 num_channels;
u8 supports_extref:1;
u8 supports_xtal:1;
};
struct ads131m_priv {
struct iio_dev *indio_dev;
struct spi_device *spi;
const struct ads131m_configuration *config;
bool use_external_ref;
int scale_val;
int scale_val2;
struct spi_transfer xfer;
struct spi_message msg;
struct mutex lock;
u8 tx_buffer[ADS131M_FRAME_BYTES(ADS131M_MAX_CHANNELS)]
__aligned(IIO_DMA_MINALIGN);
u8 rx_buffer[ADS131M_FRAME_BYTES(ADS131M_MAX_CHANNELS)];
};
static int ads131m_tx_frame_unlocked(struct ads131m_priv *priv, u32 command)
{
struct iio_dev *indio_dev = priv->indio_dev;
u16 crc;
lockdep_assert_held(&priv->lock);
memset(priv->tx_buffer, 0, ADS131M_FRAME_BYTES(indio_dev->num_channels));
put_unaligned_be16(command, &priv->tx_buffer[0]);
crc = crc_itu_t(0xffff, priv->tx_buffer, 3);
put_unaligned_be16(crc, &priv->tx_buffer[3]);
return spi_sync(priv->spi, &priv->msg);
}
static int ads131m_rx_frame_unlocked(struct ads131m_priv *priv)
{
return ads131m_tx_frame_unlocked(priv, ADS131M_CMD_NULL);
}
static int ads131m_check_status_crc_err(struct ads131m_priv *priv)
{
struct device *dev = &priv->spi->dev;
u16 status;
int ret;
lockdep_assert_held(&priv->lock);
ret = ads131m_rx_frame_unlocked(priv);
if (ret < 0) {
dev_err_ratelimited(dev,
"SPI error on STATUS read for CRC check\n");
return ret;
}
status = get_unaligned_be16(&priv->rx_buffer[0]);
if (status & ADS131M_STATUS_CRC_ERR) {
dev_err_ratelimited(dev,
"Input CRC error reported in STATUS = 0x%04x\n",
status);
return -EIO;
}
return 0;
}
static int ads131m_write_reg_unlocked(struct ads131m_priv *priv, u8 reg, u16 val)
{
struct iio_dev *indio_dev = priv->indio_dev;
u16 command, expected_ack, response, crc;
struct device *dev = &priv->spi->dev;
int ret_crc_err = 0;
int ret;
lockdep_assert_held(&priv->lock);
command = ADS131M_CMD_WREG(reg, 0);
expected_ack = 0x4000 | (reg << 7);
memset(priv->tx_buffer, 0, ADS131M_FRAME_BYTES(indio_dev->num_channels));
put_unaligned_be16(command, &priv->tx_buffer[0]);
put_unaligned_be16(val, &priv->tx_buffer[3]);
crc = crc_itu_t(0xffff, priv->tx_buffer, 6);
put_unaligned_be16(crc, &priv->tx_buffer[6]);
ret = spi_sync(priv->spi, &priv->msg);
if (ret < 0) {
dev_err_ratelimited(dev, "SPI error on WREG (cycle 1)\n");
return ret;
}
ret = ads131m_rx_frame_unlocked(priv);
if (ret < 0) {
dev_err_ratelimited(dev, "SPI error on WREG ACK (cycle 2)\n");
return ret;
}
response = get_unaligned_be16(&priv->rx_buffer[0]);
if (response != expected_ack) {
dev_err_ratelimited(dev, "WREG(0x%02x) failed, expected ACK 0x%04x, got 0x%04x\n",
reg, expected_ack, response);
ret_crc_err = -EIO;
}
ret = ads131m_check_status_crc_err(priv);
if (ret < 0)
return ret;
return ret_crc_err;
}
static int ads131m_read_reg_unlocked(struct ads131m_priv *priv, u8 reg, u16 *val)
{
struct device *dev = &priv->spi->dev;
u16 command;
int ret;
lockdep_assert_held(&priv->lock);
command = ADS131M_CMD_RREG(reg, 0);
ret = ads131m_tx_frame_unlocked(priv, command);
if (ret < 0) {
dev_err_ratelimited(dev, "SPI error on RREG (cycle 1)\n");
return ret;
}
ret = ads131m_rx_frame_unlocked(priv);
if (ret < 0) {
dev_err_ratelimited(dev, "SPI error on RREG data (cycle 2)\n");
return ret;
}
*val = get_unaligned_be16(&priv->rx_buffer[0]);
return ads131m_check_status_crc_err(priv);
}
static int ads131m_rmw_reg(struct ads131m_priv *priv, u8 reg, u16 clear, u16 set)
{
u16 old_val, new_val;
int ret;
guard(mutex)(&priv->lock);
ret = ads131m_read_reg_unlocked(priv, reg, &old_val);
if (ret < 0)
return ret;
new_val = (old_val & ~clear) | set;
if (new_val == old_val)
return 0;
return ads131m_write_reg_unlocked(priv, reg, new_val);
}
static int ads131m_verify_output_crc(struct ads131m_priv *priv)
{
struct iio_dev *indio_dev = priv->indio_dev;
struct device *dev = &priv->spi->dev;
u16 calculated_crc, received_crc;
size_t data_len;
lockdep_assert_held(&priv->lock);
data_len = ADS131M_FRAME_BYTES(indio_dev->num_channels) - 3;
calculated_crc = crc_itu_t(0xffff, priv->rx_buffer, data_len);
received_crc = get_unaligned_be16(&priv->rx_buffer[data_len]);
if (calculated_crc != received_crc) {
dev_err_ratelimited(dev, "Output CRC error. Got %04x, expected %04x\n",
received_crc, calculated_crc);
return -EIO;
}
return 0;
}
static int ads131m_adc_read(struct ads131m_priv *priv, u8 channel, s32 *val)
{
struct device *dev = &priv->spi->dev;
u16 status;
int ret;
u8 *buf;
guard(mutex)(&priv->lock);
ret = ads131m_rx_frame_unlocked(priv);
if (ret < 0)
return ret;
status = get_unaligned_be16(&priv->rx_buffer[0]);
if (status & ADS131M_STATUS_CRC_ERR) {
dev_err_ratelimited(dev,
"Previous input CRC error reported in STATUS (0x%04x)\n",
status);
}
ret = ads131m_verify_output_crc(priv);
if (ret < 0)
return ret;
buf = &priv->rx_buffer[ADS131M_CHANNEL_INDEX(channel)];
*val = sign_extend32(get_unaligned_be24(buf), ADS131M_CODE_BITS);
return 0;
}
static int ads131m_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel,
int *val, int *val2, long mask)
{
struct ads131m_priv *priv = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = ads131m_adc_read(priv, channel->channel, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = priv->scale_val;
*val2 = priv->scale_val2;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
}
#define ADS131M_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.differential = 1, \
.indexed = 1, \
.channel = (num), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec ads131m02_channels[] = {
ADS131M_VOLTAGE_CHANNEL(0),
ADS131M_VOLTAGE_CHANNEL(1),
};
static const struct iio_chan_spec ads131m03_channels[] = {
ADS131M_VOLTAGE_CHANNEL(0),
ADS131M_VOLTAGE_CHANNEL(1),
ADS131M_VOLTAGE_CHANNEL(2),
};
static const struct iio_chan_spec ads131m04_channels[] = {
ADS131M_VOLTAGE_CHANNEL(0),
ADS131M_VOLTAGE_CHANNEL(1),
ADS131M_VOLTAGE_CHANNEL(2),
ADS131M_VOLTAGE_CHANNEL(3),
};
static const struct iio_chan_spec ads131m06_channels[] = {
ADS131M_VOLTAGE_CHANNEL(0),
ADS131M_VOLTAGE_CHANNEL(1),
ADS131M_VOLTAGE_CHANNEL(2),
ADS131M_VOLTAGE_CHANNEL(3),
ADS131M_VOLTAGE_CHANNEL(4),
ADS131M_VOLTAGE_CHANNEL(5),
};
static const struct iio_chan_spec ads131m08_channels[] = {
ADS131M_VOLTAGE_CHANNEL(0),
ADS131M_VOLTAGE_CHANNEL(1),
ADS131M_VOLTAGE_CHANNEL(2),
ADS131M_VOLTAGE_CHANNEL(3),
ADS131M_VOLTAGE_CHANNEL(4),
ADS131M_VOLTAGE_CHANNEL(5),
ADS131M_VOLTAGE_CHANNEL(6),
ADS131M_VOLTAGE_CHANNEL(7),
};
static const struct ads131m_configuration ads131m02_config = {
.channels = ads131m02_channels,
.num_channels = ARRAY_SIZE(ads131m02_channels),
.reset_ack = 0xff22,
.name = "ads131m02",
};
static const struct ads131m_configuration ads131m03_config = {
.channels = ads131m03_channels,
.num_channels = ARRAY_SIZE(ads131m03_channels),
.reset_ack = 0xff23,
.name = "ads131m03",
};
static const struct ads131m_configuration ads131m04_config = {
.channels = ads131m04_channels,
.num_channels = ARRAY_SIZE(ads131m04_channels),
.reset_ack = 0xff24,
.name = "ads131m04",
};
static const struct ads131m_configuration ads131m06_config = {
.channels = ads131m06_channels,
.num_channels = ARRAY_SIZE(ads131m06_channels),
.reset_ack = 0xff26,
.supports_extref = true,
.supports_xtal = true,
.name = "ads131m06",
};
static const struct ads131m_configuration ads131m08_config = {
.channels = ads131m08_channels,
.num_channels = ARRAY_SIZE(ads131m08_channels),
.reset_ack = 0xff28,
.supports_extref = true,
.supports_xtal = true,
.name = "ads131m08",
};
static const struct iio_info ads131m_info = {
.read_raw = ads131m_read_raw,
};
static int ads131m_prepare_message(struct ads131m_priv *priv)
{
struct iio_dev *indio_dev = priv->indio_dev;
struct device *dev = &priv->spi->dev;
int ret;
priv->xfer.tx_buf = priv->tx_buffer;
priv->xfer.rx_buf = priv->rx_buffer;
priv->xfer.len = ADS131M_FRAME_BYTES(indio_dev->num_channels);
spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
ret = devm_spi_optimize_message(dev, priv->spi, &priv->msg);
if (ret)
return dev_err_probe(dev, ret, "failed to optimize SPI message\n");
return 0;
}
static int ads131m_hw_reset(struct ads131m_priv *priv,
struct reset_control *rstc)
{
struct device *dev = &priv->spi->dev;
int ret;
ret = reset_control_assert(rstc);
if (ret)
return dev_err_probe(dev, ret, "Failed to assert reset\n");
fsleep(1);
ret = reset_control_deassert(rstc);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to deassert reset\n");
fsleep(ADS131M_RESET_DELAY_US);
return 0;
}
static int ads131m_sw_reset(struct ads131m_priv *priv)
{
u16 expected_ack = priv->config->reset_ack;
struct device *dev = &priv->spi->dev;
u16 response;
int ret;
guard(mutex)(&priv->lock);
ret = ads131m_tx_frame_unlocked(priv, ADS131M_CMD_RESET);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to send RESET command\n");
fsleep(ADS131M_RESET_DELAY_US);
ret = ads131m_rx_frame_unlocked(priv);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to read RESET ACK\n");
response = get_unaligned_be16(&priv->rx_buffer[0]);
if (response != expected_ack)
return dev_err_probe(dev, -EIO,
"RESET ACK mismatch, got 0x%04x, expected 0x%04x\n",
response, expected_ack);
return ads131m_check_status_crc_err(priv);
}
static int ads131m_reset(struct ads131m_priv *priv, struct reset_control *rstc)
{
if (rstc)
return ads131m_hw_reset(priv, rstc);
return ads131m_sw_reset(priv);
}
static int ads131m_power_init(struct ads131m_priv *priv)
{
static const char * const supply_ids[] = { "avdd", "dvdd" };
struct device *dev = &priv->spi->dev;
int vref_uV;
int ret;
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supply_ids), supply_ids);
if (ret < 0)
return dev_err_probe(dev, ret, "failed to enable regulators\n");
priv->scale_val = ADS131M_VREF_INTERNAL_mV;
priv->scale_val2 = BIT(ADS131M_CODE_BITS);
if (!priv->config->supports_extref)
return 0;
ret = devm_regulator_get_enable_read_voltage(dev, "refin");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to get refin supply\n");
if (ret == 0)
return dev_err_probe(dev, -EINVAL, "refin supply reports 0V\n");
if (ret == -ENODEV)
return 0;
vref_uV = ret;
priv->scale_val = div_s64((s64)vref_uV * ADS131M_EXTREF_SCALE_NUM, 1000);
priv->scale_val2 = ADS131M_EXTREF_SCALE_DEN * BIT(ADS131M_CODE_BITS);
priv->use_external_ref = true;
return 0;
}
static int ads131m_hw_init(struct ads131m_priv *priv,
struct reset_control *rstc, bool is_xtal)
{
struct device *dev = &priv->spi->dev;
u16 mode_clear, mode_set;
int ret;
ret = ads131m_reset(priv, rstc);
if (ret < 0)
return ret;
if (priv->config->supports_xtal || priv->config->supports_extref) {
u16 clk_set = 0;
if (priv->config->supports_xtal && !is_xtal)
clk_set |= ADS131M_CLOCK_XTAL_DIS;
if (priv->config->supports_extref && priv->use_external_ref)
clk_set |= ADS131M_CLOCK_EXTREF_EN;
ret = ads131m_rmw_reg(priv, ADS131M_REG_CLOCK,
ADS131M_CLOCK_EXTREF_EN | ADS131M_CLOCK_XTAL_DIS,
clk_set);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to configure CLOCK register\n");
}
mode_clear = ADS131M_MODE_CRC_TYPE_ANSI | ADS131M_MODE_RESET_FLAG;
mode_set = ADS131M_MODE_RX_CRC_EN;
ret = ads131m_rmw_reg(priv, ADS131M_REG_MODE, mode_clear, mode_set);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to configure MODE register\n");
return 0;
}
static int ads131m_parse_clock(struct ads131m_priv *priv, bool *is_xtal)
{
struct device *dev = &priv->spi->dev;
struct clk *clk;
int ret;
clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR_OR_NULL(clk)) {
if (IS_ERR(clk))
ret = PTR_ERR(clk);
else
ret = -ENODEV;
return dev_err_probe(dev, ret, "clk get enabled failed\n");
}
ret = device_property_match_string(dev, "clock-names", "xtal");
if (ret > 0)
return dev_err_probe(dev, -EINVAL,
"'xtal' must be the only or first clock name");
if (ret < 0 && ret != -ENODATA)
return dev_err_probe(dev, ret,
"failed to read 'clock-names' property");
if (ret == 0 && !priv->config->supports_xtal)
return dev_err_probe(dev, -EINVAL,
"'xtal' clock not supported on this device");
*is_xtal = !ret;
return 0;
}
static int ads131m_probe(struct spi_device *spi)
{
const struct ads131m_configuration *config;
struct device *dev = &spi->dev;
struct reset_control *rstc;
struct iio_dev *indio_dev;
struct ads131m_priv *priv;
bool is_xtal;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->indio_dev = indio_dev;
priv->spi = spi;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ads131m_info;
config = spi_get_device_match_data(spi);
priv->config = config;
indio_dev->name = config->name;
indio_dev->channels = config->channels;
indio_dev->num_channels = config->num_channels;
rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(dev, PTR_ERR(rstc),
"Failed to get reset controller\n");
ret = devm_mutex_init(dev, &priv->lock);
if (ret < 0)
return ret;
ret = ads131m_prepare_message(priv);
if (ret < 0)
return ret;
ret = ads131m_power_init(priv);
if (ret < 0)
return ret;
ret = ads131m_parse_clock(priv, &is_xtal);
if (ret < 0)
return ret;
ret = ads131m_hw_init(priv, rstc, is_xtal);
if (ret < 0)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ads131m_of_match[] = {
{ .compatible = "ti,ads131m02", .data = &ads131m02_config },
{ .compatible = "ti,ads131m03", .data = &ads131m03_config },
{ .compatible = "ti,ads131m04", .data = &ads131m04_config },
{ .compatible = "ti,ads131m06", .data = &ads131m06_config },
{ .compatible = "ti,ads131m08", .data = &ads131m08_config },
{ }
};
MODULE_DEVICE_TABLE(of, ads131m_of_match);
static const struct spi_device_id ads131m_id[] = {
{ "ads131m02", (kernel_ulong_t)&ads131m02_config },
{ "ads131m03", (kernel_ulong_t)&ads131m03_config },
{ "ads131m04", (kernel_ulong_t)&ads131m04_config },
{ "ads131m06", (kernel_ulong_t)&ads131m06_config },
{ "ads131m08", (kernel_ulong_t)&ads131m08_config },
{ }
};
MODULE_DEVICE_TABLE(spi, ads131m_id);
static struct spi_driver ads131m_driver = {
.driver = {
.name = "ads131m02",
.of_match_table = ads131m_of_match,
},
.probe = ads131m_probe,
.id_table = ads131m_id,
};
module_spi_driver(ads131m_driver);
MODULE_AUTHOR("David Jander <david@protonic.nl>");
MODULE_DESCRIPTION("Texas Instruments ADS131M02 ADC driver");
MODULE_LICENSE("GPL");