1
linux/drivers/iio/adc/max34408.c

277 lines
7.0 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* IIO driver for Maxim MAX34409/34408 ADC, 4-Channels/2-Channels, 8bits, I2C
*
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf
*
* TODO: ALERT interrupt, Overcurrent delay, Shutdown delay
*/
#include <linux/bitfield.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#define MAX34408_STATUS_REG 0x0
#define MAX34408_CONTROL_REG 0x1
#define MAX34408_OCDELAY_REG 0x2
#define MAX34408_SDDELAY_REG 0x3
#define MAX34408_ADC1_REG 0x4
#define MAX34408_ADC2_REG 0x5
/* ADC3 & ADC4 always returns 0x0 on 34408 */
#define MAX34409_ADC3_REG 0x6
#define MAX34409_ADC4_REG 0x7
#define MAX34408_OCT1_REG 0x8
#define MAX34408_OCT2_REG 0x9
#define MAX34409_OCT3_REG 0xA
#define MAX34409_OCT4_REG 0xB
#define MAX34408_DID_REG 0xC
#define MAX34408_DCYY_REG 0xD
#define MAX34408_DCWW_REG 0xE
/* Bit masks for status register */
#define MAX34408_STATUS_OC_MSK GENMASK(1, 0)
#define MAX34409_STATUS_OC_MSK GENMASK(3, 0)
#define MAX34408_STATUS_SHTDN BIT(4)
#define MAX34408_STATUS_ENA BIT(5)
/* Bit masks for control register */
#define MAX34408_CONTROL_AVG0 BIT(0)
#define MAX34408_CONTROL_AVG1 BIT(1)
#define MAX34408_CONTROL_AVG2 BIT(2)
#define MAX34408_CONTROL_ALERT BIT(3)
#define MAX34408_DEFAULT_AVG 0x4
/* Bit masks for over current delay */
#define MAX34408_OCDELAY_OCD_MSK GENMASK(6, 0)
#define MAX34408_OCDELAY_RESET BIT(7)
/* Bit masks for shutdown delay */
#define MAX34408_SDDELAY_SHD_MSK GENMASK(6, 0)
#define MAX34408_SDDELAY_RESET BIT(7)
#define MAX34408_DEFAULT_RSENSE 1000
/**
* struct max34408_data - max34408/max34409 specific data.
* @regmap: device register map.
* @dev: max34408 device.
* @lock: lock for protecting access to device hardware registers, mostly
* for read modify write cycles for control registers.
* @input_rsense: Rsense values in uOhm, will be overwritten by
* values from channel nodes.
*/
struct max34408_data {
struct regmap *regmap;
struct device *dev;
struct mutex lock;
u32 input_rsense[4];
};
static const struct regmap_config max34408_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX34408_DCWW_REG,
};
struct max34408_adc_model_data {
const char *model_name;
const struct iio_chan_spec *channels;
const int num_channels;
};
#define MAX34008_CHANNEL(_index, _address) \
{ \
.type = IIO_CURRENT, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.channel = (_index), \
.address = (_address), \
.indexed = 1, \
}
static const struct iio_chan_spec max34408_channels[] = {
MAX34008_CHANNEL(0, MAX34408_ADC1_REG),
MAX34008_CHANNEL(1, MAX34408_ADC2_REG),
};
static const struct iio_chan_spec max34409_channels[] = {
MAX34008_CHANNEL(0, MAX34408_ADC1_REG),
MAX34008_CHANNEL(1, MAX34408_ADC2_REG),
MAX34008_CHANNEL(2, MAX34409_ADC3_REG),
MAX34008_CHANNEL(3, MAX34409_ADC4_REG),
};
static int max34408_read_adc_avg(struct max34408_data *max34408,
const struct iio_chan_spec *chan, int *val)
{
unsigned int ctrl;
int rc;
guard(mutex)(&max34408->lock);
rc = regmap_read(max34408->regmap, MAX34408_CONTROL_REG, (u32 *)&ctrl);
if (rc)
return rc;
/* set averaging (0b100) default values*/
rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG,
MAX34408_DEFAULT_AVG);
if (rc) {
dev_err(max34408->dev,
"Error (%d) writing control register\n", rc);
return rc;
}
rc = regmap_read(max34408->regmap, chan->address, val);
if (rc)
return rc;
/* back to old values */
rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, ctrl);
if (rc)
dev_err(max34408->dev,
"Error (%d) writing control register\n", rc);
return rc;
}
static int max34408_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct max34408_data *max34408 = iio_priv(indio_dev);
int rc;
switch (mask) {
case IIO_CHAN_INFO_RAW:
rc = max34408_read_adc_avg(max34408, chan, val);
if (rc)
return rc;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/*
* calcluate current for 8bit ADC with Rsense
* value.
* 10 mV * 1000 / Rsense uOhm = max current
* (max current * adc val * 1000) / (2^8 - 1) mA
*/
*val = 10000 / max34408->input_rsense[chan->channel];
*val2 = 8;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static const struct iio_info max34408_info = {
.read_raw = max34408_read_raw,
};
static const struct max34408_adc_model_data max34408_model_data = {
.model_name = "max34408",
.channels = max34408_channels,
.num_channels = 2,
};
static const struct max34408_adc_model_data max34409_model_data = {
.model_name = "max34409",
.channels = max34409_channels,
.num_channels = 4,
};
static int max34408_probe(struct i2c_client *client)
{
const struct max34408_adc_model_data *model_data;
struct device *dev = &client->dev;
struct max34408_data *max34408;
struct fwnode_handle *node;
struct iio_dev *indio_dev;
struct regmap *regmap;
int rc, i = 0;
model_data = i2c_get_match_data(client);
if (!model_data)
return -EINVAL;
regmap = devm_regmap_init_i2c(client, &max34408_regmap_config);
if (IS_ERR(regmap)) {
dev_err_probe(dev, PTR_ERR(regmap),
"regmap_init failed\n");
return PTR_ERR(regmap);
}
indio_dev = devm_iio_device_alloc(dev, sizeof(*max34408));
if (!indio_dev)
return -ENOMEM;
max34408 = iio_priv(indio_dev);
max34408->regmap = regmap;
max34408->dev = dev;
mutex_init(&max34408->lock);
device_for_each_child_node(dev, node) {
fwnode_property_read_u32(node, "maxim,rsense-val-micro-ohms",
&max34408->input_rsense[i]);
i++;
}
/* disable ALERT and averaging */
rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, 0x0);
if (rc)
return rc;
indio_dev->channels = model_data->channels;
indio_dev->num_channels = model_data->num_channels;
indio_dev->name = model_data->model_name;
indio_dev->info = &max34408_info;
indio_dev->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id max34408_of_match[] = {
{
.compatible = "maxim,max34408",
.data = &max34408_model_data,
},
{
.compatible = "maxim,max34409",
.data = &max34409_model_data,
},
{ }
};
MODULE_DEVICE_TABLE(of, max34408_of_match);
static const struct i2c_device_id max34408_id[] = {
{ "max34408", (kernel_ulong_t)&max34408_model_data },
{ "max34409", (kernel_ulong_t)&max34409_model_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, max34408_id);
static struct i2c_driver max34408_driver = {
.driver = {
.name = "max34408",
.of_match_table = max34408_of_match,
},
.probe = max34408_probe,
.id_table = max34408_id,
};
module_i2c_driver(max34408_driver);
MODULE_AUTHOR("Ivan Mikhaylov <fr0st61te@gmail.com>");
MODULE_DESCRIPTION("Maxim MAX34408/34409 ADC driver");
MODULE_LICENSE("GPL");