blob: dd4ad32aa6f53c2662a1c085a94ec54a85b8cfa2 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices AD4062 I3C ADC driver
*
* Copyright 2025 Analog Devices Inc.
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/devm-helpers.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/i3c/device.h>
#include <linux/i3c/master.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/math.h>
#include <linux/minmax.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/unaligned.h>
#include <linux/util_macros.h>
#define AD4062_REG_INTERFACE_CONFIG_A 0x00
#define AD4062_REG_DEVICE_CONFIG 0x02
#define AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK GENMASK(1, 0)
#define AD4062_REG_DEVICE_CONFIG_LOW_POWER_MODE 3
#define AD4062_REG_PROD_ID_1 0x05
#define AD4062_REG_DEVICE_GRADE 0x06
#define AD4062_REG_SCRATCH_PAD 0x0A
#define AD4062_REG_VENDOR_H 0x0D
#define AD4062_REG_STREAM_MODE 0x0E
#define AD4062_REG_INTERFACE_STATUS 0x11
#define AD4062_REG_MODE_SET 0x20
#define AD4062_REG_MODE_SET_ENTER_ADC BIT(0)
#define AD4062_REG_ADC_MODES 0x21
#define AD4062_REG_ADC_MODES_MODE_MSK GENMASK(1, 0)
#define AD4062_REG_ADC_CONFIG 0x22
#define AD4062_REG_ADC_CONFIG_REF_EN_MSK BIT(5)
#define AD4062_REG_ADC_CONFIG_SCALE_EN_MSK BIT(4)
#define AD4062_REG_AVG_CONFIG 0x23
#define AD4062_REG_GP_CONF 0x24
#define AD4062_REG_GP_CONF_MODE_MSK_0 GENMASK(2, 0)
#define AD4062_REG_GP_CONF_MODE_MSK_1 GENMASK(6, 4)
#define AD4062_REG_INTR_CONF 0x25
#define AD4062_REG_INTR_CONF_EN_MSK_0 GENMASK(1, 0)
#define AD4062_REG_INTR_CONF_EN_MSK_1 GENMASK(5, 4)
#define AD4062_REG_TIMER_CONFIG 0x27
#define AD4062_REG_TIMER_CONFIG_FS_MASK GENMASK(7, 4)
#define AD4062_REG_MAX_LIMIT 0x29
#define AD4062_REG_MIN_LIMIT 0x2B
#define AD4062_REG_MAX_HYST 0x2C
#define AD4062_REG_MIN_HYST 0x2D
#define AD4062_REG_MON_VAL 0x2F
#define AD4062_REG_ADC_IBI_EN 0x31
#define AD4062_REG_ADC_IBI_EN_CONV_TRIGGER BIT(2)
#define AD4062_REG_ADC_IBI_EN_MAX BIT(1)
#define AD4062_REG_ADC_IBI_EN_MIN BIT(0)
#define AD4062_REG_FUSE_CRC 0x40
#define AD4062_REG_DEVICE_STATUS 0x41
#define AD4062_REG_DEVICE_STATUS_DEVICE_RESET BIT(6)
#define AD4062_REG_IBI_STATUS 0x48
#define AD4062_REG_CONV_READ_LSB 0x50
#define AD4062_REG_CONV_READ_16BITS 0x51
#define AD4062_REG_CONV_READ_32BITS 0x53
#define AD4062_REG_CONV_TRIGGER_16BITS 0x57
#define AD4062_REG_CONV_TRIGGER_32BITS 0x59
#define AD4062_REG_CONV_AUTO 0x61
#define AD4062_MAX_REG AD4062_REG_CONV_AUTO
#define AD4062_MON_VAL_MIDDLE_POINT 0x8000
#define AD4062_I3C_VENDOR 0x0177
#define AD4062_SOFT_RESET 0x81
#define AD4060_PROD_ID 0x7A
#define AD4062_PROD_ID 0x7C
#define AD4062_GP_DISABLED 0x0
#define AD4062_GP_INTR 0x1
#define AD4062_GP_DRDY 0x2
#define AD4062_GP_STATIC_LOW 0x5
#define AD4062_GP_STATIC_HIGH 0x6
#define AD4062_LIMIT_BITS 12
#define AD4062_INTR_EN_NEITHER 0x0
#define AD4062_INTR_EN_EITHER 0x3
#define AD4062_TCONV_NS 270
enum ad4062_operation_mode {
AD4062_SAMPLE_MODE = 0x0,
AD4062_BURST_AVERAGING_MODE = 0x1,
AD4062_MONITOR_MODE = 0x3,
};
struct ad4062_chip_info {
const struct iio_chan_spec channels[1];
const char *name;
u16 prod_id;
u16 avg_max;
};
enum {
AD4062_SCAN_TYPE_SAMPLE,
AD4062_SCAN_TYPE_BURST_AVG,
};
static const struct iio_scan_type ad4062_scan_type_12_s[] = {
[AD4062_SCAN_TYPE_SAMPLE] = {
.sign = 's',
.realbits = 12,
.storagebits = 16,
.endianness = IIO_BE,
},
[AD4062_SCAN_TYPE_BURST_AVG] = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
.endianness = IIO_BE,
},
};
static const struct iio_scan_type ad4062_scan_type_16_s[] = {
[AD4062_SCAN_TYPE_SAMPLE] = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_BE,
},
[AD4062_SCAN_TYPE_BURST_AVG] = {
.sign = 's',
.realbits = 20,
.storagebits = 32,
.endianness = IIO_BE,
},
};
static const unsigned int ad4062_conversion_freqs[] = {
2000000, 1000000, 300000, 100000, /* 0 - 3 */
33300, 10000, 3000, 500, /* 4 - 7 */
333, 250, 200, 166, /* 8 - 11 */
140, 124, 111, /* 12 - 15 */
};
struct ad4062_state {
const struct ad4062_chip_info *chip;
const struct ad4062_bus_ops *ops;
enum ad4062_operation_mode mode;
struct work_struct trig_conv;
struct completion completion;
struct iio_trigger *trigger;
struct iio_dev *indio_dev;
struct i3c_device *i3cdev;
struct regmap *regmap;
bool wait_event;
int vref_uV;
unsigned int samp_freqs[ARRAY_SIZE(ad4062_conversion_freqs)];
bool gpo_irq[2];
u16 sampling_frequency;
u16 events_frequency;
u8 oversamp_ratio;
u8 conv_sizeof;
u8 conv_addr;
union {
__be32 be32;
__be16 be16;
} buf __aligned(IIO_DMA_MINALIGN);
};
static const struct regmap_range ad4062_regmap_rd_ranges[] = {
regmap_reg_range(AD4062_REG_INTERFACE_CONFIG_A, AD4062_REG_DEVICE_GRADE),
regmap_reg_range(AD4062_REG_SCRATCH_PAD, AD4062_REG_INTERFACE_STATUS),
regmap_reg_range(AD4062_REG_MODE_SET, AD4062_REG_ADC_IBI_EN),
regmap_reg_range(AD4062_REG_FUSE_CRC, AD4062_REG_IBI_STATUS),
regmap_reg_range(AD4062_REG_CONV_READ_LSB, AD4062_REG_CONV_AUTO),
};
static const struct regmap_access_table ad4062_regmap_rd_table = {
.yes_ranges = ad4062_regmap_rd_ranges,
.n_yes_ranges = ARRAY_SIZE(ad4062_regmap_rd_ranges),
};
static const struct regmap_range ad4062_regmap_wr_ranges[] = {
regmap_reg_range(AD4062_REG_INTERFACE_CONFIG_A, AD4062_REG_DEVICE_CONFIG),
regmap_reg_range(AD4062_REG_SCRATCH_PAD, AD4062_REG_SCRATCH_PAD),
regmap_reg_range(AD4062_REG_STREAM_MODE, AD4062_REG_INTERFACE_STATUS),
regmap_reg_range(AD4062_REG_MODE_SET, AD4062_REG_ADC_IBI_EN),
regmap_reg_range(AD4062_REG_FUSE_CRC, AD4062_REG_DEVICE_STATUS),
};
static const struct regmap_access_table ad4062_regmap_wr_table = {
.yes_ranges = ad4062_regmap_wr_ranges,
.n_yes_ranges = ARRAY_SIZE(ad4062_regmap_wr_ranges),
};
static const struct iio_event_spec ad4062_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_shared_by_all = BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_HYSTERESIS),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define AD4062_CHAN(bits) { \
.type = IIO_VOLTAGE, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.indexed = 1, \
.channel = 0, \
.event_spec = ad4062_events, \
.num_event_specs = ARRAY_SIZE(ad4062_events), \
.has_ext_scan_type = 1, \
.ext_scan_type = ad4062_scan_type_##bits##_s, \
.num_ext_scan_type = ARRAY_SIZE(ad4062_scan_type_##bits##_s), \
}
static const struct ad4062_chip_info ad4060_chip_info = {
.name = "ad4060",
.channels = { AD4062_CHAN(12) },
.prod_id = AD4060_PROD_ID,
.avg_max = 256,
};
static const struct ad4062_chip_info ad4062_chip_info = {
.name = "ad4062",
.channels = { AD4062_CHAN(16) },
.prod_id = AD4062_PROD_ID,
.avg_max = 4096,
};
static ssize_t sampling_frequency_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad4062_state *st = iio_priv(dev_to_iio_dev(dev));
return sysfs_emit(buf, "%d\n", ad4062_conversion_freqs[st->events_frequency]);
}
static int sampling_frequency_store_dispatch(struct iio_dev *indio_dev,
const char *buf)
{
struct ad4062_state *st = iio_priv(indio_dev);
int val, ret;
if (st->wait_event)
return -EBUSY;
ret = kstrtoint(buf, 10, &val);
if (ret)
return ret;
st->events_frequency = find_closest_descending(val, ad4062_conversion_freqs,
ARRAY_SIZE(ad4062_conversion_freqs));
return 0;
}
static ssize_t sampling_frequency_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret;
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = sampling_frequency_store_dispatch(indio_dev, buf);
iio_device_release_direct(indio_dev);
return ret ?: len;
}
static IIO_DEVICE_ATTR_RW(sampling_frequency, 0);
static ssize_t sampling_frequency_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret = 0;
for (u8 i = 0; i < ARRAY_SIZE(ad4062_conversion_freqs); i++)
ret += sysfs_emit_at(buf, ret, "%d%s", ad4062_conversion_freqs[i],
i != (ARRAY_SIZE(ad4062_conversion_freqs) - 1) ? " " : "\n");
return ret;
}
static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0);
static struct attribute *ad4062_event_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad4062_event_attribute_group = {
.attrs = ad4062_event_attributes,
};
static int ad4062_set_oversampling_ratio(struct ad4062_state *st, int val, int val2)
{
const u32 _max = st->chip->avg_max;
const u32 _min = 1;
int ret;
if (!in_range(val, _min, _max) || val2 != 0)
return -EINVAL;
/* 1 disables oversampling */
val = ilog2(val);
if (val == 0) {
st->mode = AD4062_SAMPLE_MODE;
} else {
st->mode = AD4062_BURST_AVERAGING_MODE;
ret = regmap_write(st->regmap, AD4062_REG_AVG_CONFIG, val - 1);
if (ret)
return ret;
}
st->oversamp_ratio = val;
return 0;
}
static int ad4062_get_oversampling_ratio(struct ad4062_state *st, int *val)
{
int ret, buf;
if (st->mode == AD4062_SAMPLE_MODE) {
*val = 1;
return 0;
}
ret = regmap_read(st->regmap, AD4062_REG_AVG_CONFIG, &buf);
if (ret)
return ret;
*val = BIT(buf + 1);
return 0;
}
static int ad4062_calc_sampling_frequency(unsigned int fosc, unsigned int oversamp_ratio)
{
/* From datasheet p.31: (n_avg - 1)/fosc + tconv */
u32 n_avg = BIT(oversamp_ratio) - 1;
u32 period_ns = NSEC_PER_SEC / fosc;
/* Result is less than 1 Hz */
if (n_avg >= fosc)
return 1;
return NSEC_PER_SEC / (n_avg * period_ns + AD4062_TCONV_NS);
}
static int ad4062_populate_sampling_frequency(struct ad4062_state *st)
{
for (u8 i = 0; i < ARRAY_SIZE(ad4062_conversion_freqs); i++)
st->samp_freqs[i] =
ad4062_calc_sampling_frequency(ad4062_conversion_freqs[i],
st->oversamp_ratio);
return 0;
}
static int ad4062_get_sampling_frequency(struct ad4062_state *st, int *val)
{
int freq = ad4062_conversion_freqs[st->sampling_frequency];
*val = ad4062_calc_sampling_frequency(freq, st->oversamp_ratio);
return IIO_VAL_INT;
}
static int ad4062_set_sampling_frequency(struct ad4062_state *st, int val, int val2)
{
int ret;
if (val2 != 0)
return -EINVAL;
ret = ad4062_populate_sampling_frequency(st);
if (ret)
return ret;
st->sampling_frequency =
find_closest_descending(val, st->samp_freqs,
ARRAY_SIZE(ad4062_conversion_freqs));
return 0;
}
static int ad4062_check_ids(struct ad4062_state *st)
{
struct device *dev = &st->i3cdev->dev;
int ret;
u16 val;
ret = regmap_bulk_read(st->regmap, AD4062_REG_PROD_ID_1,
&st->buf.be16, sizeof(st->buf.be16));
if (ret)
return ret;
val = be16_to_cpu(st->buf.be16);
if (val != st->chip->prod_id)
dev_warn(dev, "Production ID x%x does not match known values", val);
ret = regmap_bulk_read(st->regmap, AD4062_REG_VENDOR_H,
&st->buf.be16, sizeof(st->buf.be16));
if (ret)
return ret;
val = be16_to_cpu(st->buf.be16);
if (val != AD4062_I3C_VENDOR) {
dev_err(dev, "Vendor ID x%x does not match expected value\n", val);
return -ENODEV;
}
return 0;
}
static int ad4062_conversion_frequency_set(struct ad4062_state *st, u8 val)
{
return regmap_write(st->regmap, AD4062_REG_TIMER_CONFIG,
FIELD_PREP(AD4062_REG_TIMER_CONFIG_FS_MASK, val));
}
static int ad4062_set_operation_mode(struct ad4062_state *st,
enum ad4062_operation_mode mode)
{
const unsigned int samp_freq = mode == AD4062_MONITOR_MODE ?
st->events_frequency : st->sampling_frequency;
int ret;
ret = ad4062_conversion_frequency_set(st, samp_freq);
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_MODES,
AD4062_REG_ADC_MODES_MODE_MSK, mode);
if (ret)
return ret;
if (mode == AD4062_MONITOR_MODE) {
/* Change address pointer to enter monitor mode */
struct i3c_xfer xfer_trigger = {
.data.out = &st->conv_addr,
.len = sizeof(st->conv_addr),
.rnw = false,
};
st->conv_addr = AD4062_REG_CONV_TRIGGER_32BITS;
return i3c_device_do_xfers(st->i3cdev, &xfer_trigger, 1, I3C_SDR);
}
return regmap_write(st->regmap, AD4062_REG_MODE_SET,
AD4062_REG_MODE_SET_ENTER_ADC);
}
static int ad4062_soft_reset(struct ad4062_state *st)
{
u8 val = AD4062_SOFT_RESET;
int ret;
ret = regmap_write(st->regmap, AD4062_REG_INTERFACE_CONFIG_A, val);
if (ret)
return ret;
/* Wait AD4062 treset time, datasheet p8 */
ndelay(60);
return 0;
}
static int ad4062_setup(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
const bool *ref_sel)
{
struct ad4062_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
int ret;
scan_type = iio_get_current_scan_type(indio_dev, chan);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
AD4062_REG_GP_CONF_MODE_MSK_0,
FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0,
AD4062_GP_INTR));
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
AD4062_REG_GP_CONF_MODE_MSK_1,
FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1,
AD4062_GP_DRDY));
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_CONFIG,
AD4062_REG_ADC_CONFIG_REF_EN_MSK,
FIELD_PREP(AD4062_REG_ADC_CONFIG_REF_EN_MSK,
*ref_sel));
if (ret)
return ret;
ret = regmap_write(st->regmap, AD4062_REG_DEVICE_STATUS,
AD4062_REG_DEVICE_STATUS_DEVICE_RESET);
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4062_REG_INTR_CONF,
AD4062_REG_INTR_CONF_EN_MSK_0,
FIELD_PREP(AD4062_REG_INTR_CONF_EN_MSK_0,
AD4062_INTR_EN_EITHER));
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4062_REG_INTR_CONF,
AD4062_REG_INTR_CONF_EN_MSK_1,
FIELD_PREP(AD4062_REG_INTR_CONF_EN_MSK_1,
AD4062_INTR_EN_NEITHER));
if (ret)
return ret;
st->buf.be16 = cpu_to_be16(AD4062_MON_VAL_MIDDLE_POINT);
return regmap_bulk_write(st->regmap, AD4062_REG_MON_VAL,
&st->buf.be16, sizeof(st->buf.be16));
}
static irqreturn_t ad4062_irq_handler_thresh(int irq, void *private)
{
struct iio_dev *indio_dev = private;
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_EITHER),
iio_get_time_ns(indio_dev));
return IRQ_HANDLED;
}
static irqreturn_t ad4062_irq_handler_drdy(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad4062_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev))
iio_trigger_poll(st->trigger);
else
complete(&st->completion);
return IRQ_HANDLED;
}
static void ad4062_ibi_handler(struct i3c_device *i3cdev,
const struct i3c_ibi_payload *payload)
{
struct ad4062_state *st = i3cdev_get_drvdata(i3cdev);
if (st->wait_event) {
iio_push_event(st->indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_EITHER),
iio_get_time_ns(st->indio_dev));
return;
}
if (iio_buffer_enabled(st->indio_dev))
iio_trigger_poll_nested(st->trigger);
else
complete(&st->completion);
}
static void ad4062_trigger_work(struct work_struct *work)
{
struct ad4062_state *st =
container_of(work, struct ad4062_state, trig_conv);
int ret;
/*
* Read current conversion, if at reg CONV_READ, stop bit triggers
* next sample and does not need writing the address.
*/
struct i3c_xfer xfer_sample = {
.data.in = &st->buf.be32,
.len = st->conv_sizeof,
.rnw = true,
};
struct i3c_xfer xfer_trigger = {
.data.out = &st->conv_addr,
.len = sizeof(st->conv_addr),
.rnw = false,
};
ret = i3c_device_do_xfers(st->i3cdev, &xfer_sample, 1, I3C_SDR);
if (ret)
return;
iio_push_to_buffers_with_ts(st->indio_dev, &st->buf.be32, st->conv_sizeof,
iio_get_time_ns(st->indio_dev));
if (st->gpo_irq[1])
return;
i3c_device_do_xfers(st->i3cdev, &xfer_trigger, 1, I3C_SDR);
}
static irqreturn_t ad4062_poll_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad4062_state *st = iio_priv(indio_dev);
iio_trigger_notify_done(indio_dev->trig);
schedule_work(&st->trig_conv);
return IRQ_HANDLED;
}
static void ad4062_disable_ibi(void *data)
{
struct i3c_device *i3cdev = data;
i3c_device_disable_ibi(i3cdev);
}
static void ad4062_free_ibi(void *data)
{
struct i3c_device *i3cdev = data;
i3c_device_free_ibi(i3cdev);
}
static int ad4062_request_ibi(struct i3c_device *i3cdev)
{
const struct i3c_ibi_setup ibireq = {
.max_payload_len = 1,
.num_slots = 1,
.handler = ad4062_ibi_handler,
};
int ret;
ret = i3c_device_request_ibi(i3cdev, &ibireq);
if (ret)
return ret;
ret = devm_add_action_or_reset(&i3cdev->dev, ad4062_free_ibi, i3cdev);
if (ret)
return ret;
ret = i3c_device_enable_ibi(i3cdev);
if (ret)
return ret;
return devm_add_action_or_reset(&i3cdev->dev, ad4062_disable_ibi, i3cdev);
}
static int ad4062_request_irq(struct iio_dev *indio_dev)
{
struct ad4062_state *st = iio_priv(indio_dev);
struct device *dev = &st->i3cdev->dev;
int ret;
ret = fwnode_irq_get_byname(dev_fwnode(&st->i3cdev->dev), "gp0");
if (ret == -EPROBE_DEFER)
return ret;
if (ret < 0) {
st->gpo_irq[0] = false;
ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_IBI_EN,
AD4062_REG_ADC_IBI_EN_MAX | AD4062_REG_ADC_IBI_EN_MIN,
AD4062_REG_ADC_IBI_EN_MAX | AD4062_REG_ADC_IBI_EN_MIN);
if (ret)
return ret;
} else {
st->gpo_irq[0] = true;
ret = devm_request_threaded_irq(dev, ret, NULL,
ad4062_irq_handler_thresh,
IRQF_ONESHOT, indio_dev->name,
indio_dev);
if (ret)
return ret;
}
ret = fwnode_irq_get_byname(dev_fwnode(&st->i3cdev->dev), "gp1");
if (ret == -EPROBE_DEFER)
return ret;
if (ret < 0) {
st->gpo_irq[1] = false;
return regmap_update_bits(st->regmap, AD4062_REG_ADC_IBI_EN,
AD4062_REG_ADC_IBI_EN_CONV_TRIGGER,
AD4062_REG_ADC_IBI_EN_CONV_TRIGGER);
}
st->gpo_irq[1] = true;
return devm_request_threaded_irq(dev, ret,
ad4062_irq_handler_drdy,
NULL, IRQF_ONESHOT, indio_dev->name,
indio_dev);
}
static const struct iio_trigger_ops ad4062_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
};
static int ad4062_request_trigger(struct iio_dev *indio_dev)
{
struct ad4062_state *st = iio_priv(indio_dev);
struct device *dev = &st->i3cdev->dev;
int ret;
st->trigger = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!st->trigger)
return -ENOMEM;
st->trigger->ops = &ad4062_trigger_ops;
iio_trigger_set_drvdata(st->trigger, indio_dev);
ret = devm_iio_trigger_register(dev, st->trigger);
if (ret)
return ret;
indio_dev->trig = iio_trigger_get(st->trigger);
return 0;
}
static const int ad4062_oversampling_avail[] = {
1, 2, 4, 8, 16, 32, 64, 128, /* 0 - 7 */
256, 512, 1024, 2048, 4096, /* 8 - 12 */
};
static int ad4062_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, const int **vals,
int *type, int *len, long mask)
{
struct ad4062_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = ad4062_oversampling_avail;
*len = ARRAY_SIZE(ad4062_oversampling_avail);
*len -= st->chip->avg_max == 256 ? 4 : 0;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = ad4062_populate_sampling_frequency(st);
if (ret)
return ret;
*vals = st->samp_freqs;
*len = st->oversamp_ratio ? ARRAY_SIZE(ad4062_conversion_freqs) : 1;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int ad4062_get_chan_scale(struct iio_dev *indio_dev, int *val, int *val2)
{
struct ad4062_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
/*
* In burst averaging mode the averaging filter accumulates resulting
* in a sample with increased precision.
*/
scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
*val = (st->vref_uV * 2) / (MICRO / MILLI); /* signed */
*val2 = scan_type->realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
}
static int ad4062_get_chan_calibscale(struct ad4062_state *st, int *val, int *val2)
{
int ret;
ret = regmap_bulk_read(st->regmap, AD4062_REG_MON_VAL,
&st->buf.be16, sizeof(st->buf.be16));
if (ret)
return ret;
/* From datasheet: code out = code in × mon_val/0x8000 */
*val = be16_to_cpu(st->buf.be16) * 2;
*val2 = 16;
return IIO_VAL_FRACTIONAL_LOG2;
}
static int ad4062_set_chan_calibscale(struct ad4062_state *st, int gain_int,
int gain_frac)
{
/* Divide numerator and denumerator by known great common divider */
const u32 mon_val = AD4062_MON_VAL_MIDDLE_POINT / 64;
const u32 micro = MICRO / 64;
const u32 gain_fp = gain_int * MICRO + gain_frac;
const u32 reg_val = DIV_ROUND_CLOSEST(gain_fp * mon_val, micro);
int ret;
/* Checks if the gain is in range and the value fits the field */
if (gain_int < 0 || gain_int > 1 || reg_val > BIT(16) - 1)
return -EINVAL;
st->buf.be16 = cpu_to_be16(reg_val);
ret = regmap_bulk_write(st->regmap, AD4062_REG_MON_VAL,
&st->buf.be16, sizeof(st->buf.be16));
if (ret)
return ret;
/* Enable scale if gain is not equal to one */
return regmap_update_bits(st->regmap, AD4062_REG_ADC_CONFIG,
AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
FIELD_PREP(AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
!(gain_int == 1 && gain_frac == 0)));
}
static int ad4062_read_chan_raw(struct ad4062_state *st, int *val)
{
struct i3c_device *i3cdev = st->i3cdev;
struct i3c_xfer xfer_trigger = {
.data.out = &st->conv_addr,
.len = sizeof(st->conv_addr),
.rnw = false,
};
struct i3c_xfer xfer_sample = {
.data.in = &st->buf.be32,
.len = sizeof(st->buf.be32),
.rnw = true,
};
int ret;
PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret)
return ret;
ret = ad4062_set_operation_mode(st, st->mode);
if (ret)
return ret;
reinit_completion(&st->completion);
/* Change address pointer to trigger conversion */
st->conv_addr = AD4062_REG_CONV_TRIGGER_32BITS;
ret = i3c_device_do_xfers(i3cdev, &xfer_trigger, 1, I3C_SDR);
if (ret)
return ret;
/*
* Single sample read should be used only for oversampling and
* sampling frequency pairs that take less than 1 sec.
*/
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000));
if (!ret)
return -ETIMEDOUT;
ret = i3c_device_do_xfers(i3cdev, &xfer_sample, 1, I3C_SDR);
if (ret)
return ret;
*val = be32_to_cpu(st->buf.be32);
return 0;
}
static int ad4062_read_raw_dispatch(struct ad4062_state *st,
int *val, int *val2, long info)
{
if (st->wait_event)
return -EBUSY;
switch (info) {
case IIO_CHAN_INFO_RAW:
return ad4062_read_chan_raw(st, val);
case IIO_CHAN_INFO_CALIBSCALE:
return ad4062_get_chan_calibscale(st, val, val2);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return ad4062_get_oversampling_ratio(st, val);
default:
return -EINVAL;
}
}
static int ad4062_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct ad4062_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_SCALE:
return ad4062_get_chan_scale(indio_dev, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return ad4062_get_sampling_frequency(st, val);
}
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad4062_read_raw_dispatch(st, val, val2, info);
iio_device_release_direct(indio_dev);
return ret ?: IIO_VAL_INT;
}
static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2,
long info)
{
if (st->wait_event)
return -EBUSY;
switch (info) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return ad4062_set_oversampling_ratio(st, val, val2);
case IIO_CHAN_INFO_CALIBSCALE:
return ad4062_set_chan_calibscale(st, val, val2);
default:
return -EINVAL;
}
};
static int ad4062_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long info)
{
struct ad4062_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
return ad4062_set_sampling_frequency(st, val, val2);
}
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad4062_write_raw_dispatch(st, val, val2, info);
iio_device_release_direct(indio_dev);
return ret;
}
static int pm_ad4062_monitor_mode_enable(struct ad4062_state *st)
{
int ret;
PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret)
return ret;
return ad4062_set_operation_mode(st, AD4062_MONITOR_MODE);
}
static int ad4062_monitor_mode_enable(struct ad4062_state *st)
{
int ret;
ret = pm_ad4062_monitor_mode_enable(st);
if (ret)
return ret;
pm_runtime_get_noresume(&st->i3cdev->dev);
return 0;
}
static int ad4062_monitor_mode_disable(struct ad4062_state *st)
{
pm_runtime_put_autosuspend(&st->i3cdev->dev);
return 0;
}
static int ad4062_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad4062_state *st = iio_priv(indio_dev);
return st->wait_event;
}
static int ad4062_write_event_config_dispatch(struct iio_dev *indio_dev,
bool state)
{
struct ad4062_state *st = iio_priv(indio_dev);
int ret;
if (st->wait_event == state)
ret = 0;
else if (state)
ret = ad4062_monitor_mode_enable(st);
else
ret = ad4062_monitor_mode_disable(st);
if (ret)
return ret;
st->wait_event = state;
return 0;
}
static int ad4062_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
bool state)
{
int ret;
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad4062_write_event_config_dispatch(indio_dev, state);
iio_device_release_direct(indio_dev);
return ret;
}
static int __ad4062_read_event_info_value(struct ad4062_state *st,
enum iio_event_direction dir, int *val)
{
int ret;
u8 reg;
if (dir == IIO_EV_DIR_RISING)
reg = AD4062_REG_MAX_LIMIT;
else
reg = AD4062_REG_MIN_LIMIT;
ret = regmap_bulk_read(st->regmap, reg, &st->buf.be16,
sizeof(st->buf.be16));
if (ret)
return ret;
*val = sign_extend32(be16_to_cpu(st->buf.be16), AD4062_LIMIT_BITS - 1);
return 0;
}
static int __ad4062_read_event_info_hysteresis(struct ad4062_state *st,
enum iio_event_direction dir, int *val)
{
u8 reg;
if (dir == IIO_EV_DIR_RISING)
reg = AD4062_REG_MAX_HYST;
else
reg = AD4062_REG_MIN_HYST;
return regmap_read(st->regmap, reg, val);
}
static int ad4062_read_event_config_dispatch(struct iio_dev *indio_dev,
enum iio_event_direction dir,
enum iio_event_info info, int *val)
{
struct ad4062_state *st = iio_priv(indio_dev);
if (st->wait_event)
return -EBUSY;
switch (info) {
case IIO_EV_INFO_VALUE:
return __ad4062_read_event_info_value(st, dir, val);
case IIO_EV_INFO_HYSTERESIS:
return __ad4062_read_event_info_hysteresis(st, dir, val);
default:
return -EINVAL;
}
}
static int ad4062_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info, int *val,
int *val2)
{
int ret;
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad4062_read_event_config_dispatch(indio_dev, dir, info, val);
iio_device_release_direct(indio_dev);
return ret ?: IIO_VAL_INT;
}
static int __ad4062_write_event_info_value(struct ad4062_state *st,
enum iio_event_direction dir, int val)
{
u8 reg;
if (val != sign_extend32(val, AD4062_LIMIT_BITS - 1))
return -EINVAL;
if (dir == IIO_EV_DIR_RISING)
reg = AD4062_REG_MAX_LIMIT;
else
reg = AD4062_REG_MIN_LIMIT;
st->buf.be16 = cpu_to_be16(val);
return regmap_bulk_write(st->regmap, reg, &st->buf.be16,
sizeof(st->buf.be16));
}
static int __ad4062_write_event_info_hysteresis(struct ad4062_state *st,
enum iio_event_direction dir, int val)
{
u8 reg;
if (val > BIT(7) - 1)
return -EINVAL;
if (dir == IIO_EV_DIR_RISING)
reg = AD4062_REG_MAX_HYST;
else
reg = AD4062_REG_MIN_HYST;
return regmap_write(st->regmap, reg, val);
}
static int ad4062_write_event_value_dispatch(struct iio_dev *indio_dev,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info, int val)
{
struct ad4062_state *st = iio_priv(indio_dev);
if (st->wait_event)
return -EBUSY;
switch (type) {
case IIO_EV_TYPE_THRESH:
switch (info) {
case IIO_EV_INFO_VALUE:
return __ad4062_write_event_info_value(st, dir, val);
case IIO_EV_INFO_HYSTERESIS:
return __ad4062_write_event_info_hysteresis(st, dir, val);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int ad4062_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info, int val,
int val2)
{
int ret;
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad4062_write_event_value_dispatch(indio_dev, type, dir, info, val);
iio_device_release_direct(indio_dev);
return ret;
}
/*
* The AD4062 in burst averaging mode increases realbits from 16-bits to
* 20-bits, increasing the storagebits from 16-bits to 32-bits.
*/
static inline size_t ad4062_sizeof_storagebits(struct ad4062_state *st)
{
const struct iio_scan_type *scan_type =
iio_get_current_scan_type(st->indio_dev, st->chip->channels);
return BITS_TO_BYTES(scan_type->storagebits);
}
/* Read registers only with realbits (no sign extension bytes) */
static inline size_t ad4062_get_conv_addr(struct ad4062_state *st, size_t _sizeof)
{
if (st->gpo_irq[1])
return _sizeof == sizeof(u32) ? AD4062_REG_CONV_READ_32BITS :
AD4062_REG_CONV_READ_16BITS;
return _sizeof == sizeof(u32) ? AD4062_REG_CONV_TRIGGER_32BITS :
AD4062_REG_CONV_TRIGGER_16BITS;
}
static int pm_ad4062_triggered_buffer_postenable(struct ad4062_state *st)
{
int ret;
PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret)
return ret;
if (st->wait_event)
return -EBUSY;
ret = ad4062_set_operation_mode(st, st->mode);
if (ret)
return ret;
st->conv_sizeof = ad4062_sizeof_storagebits(st);
st->conv_addr = ad4062_get_conv_addr(st, st->conv_sizeof);
/* CONV_READ requires read to trigger first sample. */
struct i3c_xfer xfer_sample[2] = {
{
.data.out = &st->conv_addr,
.len = sizeof(st->conv_addr),
.rnw = false,
},
{
.data.in = &st->buf.be32,
.len = sizeof(st->buf.be32),
.rnw = true,
}
};
return i3c_device_do_xfers(st->i3cdev, xfer_sample,
st->gpo_irq[1] ? 2 : 1, I3C_SDR);
}
static int ad4062_triggered_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad4062_state *st = iio_priv(indio_dev);
int ret;
ret = pm_ad4062_triggered_buffer_postenable(st);
if (ret)
return ret;
pm_runtime_get_noresume(&st->i3cdev->dev);
return 0;
}
static int ad4062_triggered_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad4062_state *st = iio_priv(indio_dev);
pm_runtime_put_autosuspend(&st->i3cdev->dev);
return 0;
}
static const struct iio_buffer_setup_ops ad4062_triggered_buffer_setup_ops = {
.postenable = &ad4062_triggered_buffer_postenable,
.predisable = &ad4062_triggered_buffer_predisable,
};
static int ad4062_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
struct ad4062_state *st = iio_priv(indio_dev);
if (readval)
return regmap_read(st->regmap, reg, readval);
else
return regmap_write(st->regmap, reg, writeval);
}
static int ad4062_get_current_scan_type(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad4062_state *st = iio_priv(indio_dev);
return st->mode == AD4062_BURST_AVERAGING_MODE ?
AD4062_SCAN_TYPE_BURST_AVG :
AD4062_SCAN_TYPE_SAMPLE;
}
static const struct iio_info ad4062_info = {
.read_raw = ad4062_read_raw,
.write_raw = ad4062_write_raw,
.read_avail = ad4062_read_avail,
.read_event_config = ad4062_read_event_config,
.write_event_config = ad4062_write_event_config,
.read_event_value = ad4062_read_event_value,
.write_event_value = ad4062_write_event_value,
.event_attrs = &ad4062_event_attribute_group,
.get_current_scan_type = ad4062_get_current_scan_type,
.debugfs_reg_access = ad4062_debugfs_reg_access,
};
static const struct regmap_config ad4062_regmap_config = {
.name = "ad4062",
.reg_bits = 8,
.val_bits = 8,
.max_register = AD4062_MAX_REG,
.rd_table = &ad4062_regmap_rd_table,
.wr_table = &ad4062_regmap_wr_table,
.can_sleep = true,
};
static int ad4062_regulators_get(struct ad4062_state *st, bool *ref_sel)
{
struct device *dev = &st->i3cdev->dev;
int ret;
ret = devm_regulator_get_enable(dev, "vio");
if (ret)
return dev_err_probe(dev, ret, "Failed to enable vio voltage\n");
st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref");
*ref_sel = st->vref_uV == -ENODEV;
if (st->vref_uV < 0 && !*ref_sel)
return dev_err_probe(dev, st->vref_uV,
"Failed to enable and read ref voltage\n");
if (*ref_sel) {
st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vdd");
if (st->vref_uV < 0)
return dev_err_probe(dev, st->vref_uV,
"Failed to enable and read vdd voltage\n");
} else {
ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
return dev_err_probe(dev, ret,
"Failed to enable vdd regulator\n");
}
return 0;
}
static int ad4062_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
return GPIO_LINE_DIRECTION_OUT;
}
static int ad4062_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct ad4062_state *st = gpiochip_get_data(gc);
unsigned int reg_val = value ? AD4062_GP_STATIC_HIGH : AD4062_GP_STATIC_LOW;
if (offset)
return regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
AD4062_REG_GP_CONF_MODE_MSK_1,
FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, reg_val));
else
return regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
AD4062_REG_GP_CONF_MODE_MSK_0,
FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, reg_val));
}
static int ad4062_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct ad4062_state *st = gpiochip_get_data(gc);
unsigned int reg_val;
int ret;
ret = regmap_read(st->regmap, AD4062_REG_GP_CONF, &reg_val);
if (ret)
return ret;
if (offset)
reg_val = FIELD_GET(AD4062_REG_GP_CONF_MODE_MSK_1, reg_val);
else
reg_val = FIELD_GET(AD4062_REG_GP_CONF_MODE_MSK_0, reg_val);
return reg_val == AD4062_GP_STATIC_HIGH;
}
static void ad4062_gpio_disable(void *data)
{
struct ad4062_state *st = data;
u8 val = FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, AD4062_GP_DISABLED) |
FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, AD4062_GP_DISABLED);
regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
AD4062_REG_GP_CONF_MODE_MSK_1 | AD4062_REG_GP_CONF_MODE_MSK_0,
val);
}
static int ad4062_gpio_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask,
unsigned int ngpios)
{
struct ad4062_state *st = gpiochip_get_data(gc);
bitmap_zero(valid_mask, ngpios);
for (unsigned int i = 0; i < ARRAY_SIZE(st->gpo_irq); i++)
__assign_bit(i, valid_mask, !st->gpo_irq[i]);
return 0;
}
static int ad4062_gpio_init(struct ad4062_state *st)
{
struct device *dev = &st->i3cdev->dev;
struct gpio_chip *gc;
u8 val, mask;
int ret;
if (!device_property_read_bool(dev, "gpio-controller"))
return 0;
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
val = 0;
mask = 0;
if (!st->gpo_irq[0]) {
mask |= AD4062_REG_GP_CONF_MODE_MSK_0;
val |= FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, AD4062_GP_STATIC_LOW);
}
if (!st->gpo_irq[1]) {
mask |= AD4062_REG_GP_CONF_MODE_MSK_1;
val |= FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, AD4062_GP_STATIC_LOW);
}
ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
mask, val);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ad4062_gpio_disable, st);
if (ret)
return ret;
gc->parent = dev;
gc->label = st->chip->name;
gc->owner = THIS_MODULE;
gc->base = -1;
gc->ngpio = 2;
gc->init_valid_mask = ad4062_gpio_init_valid_mask;
gc->get_direction = ad4062_gpio_get_direction;
gc->set = ad4062_gpio_set;
gc->get = ad4062_gpio_get;
gc->can_sleep = true;
ret = devm_gpiochip_add_data(dev, gc, st);
if (ret)
return dev_err_probe(dev, ret, "Unable to register GPIO chip\n");
return 0;
}
static const struct i3c_device_id ad4062_id_table[] = {
I3C_DEVICE(AD4062_I3C_VENDOR, AD4060_PROD_ID, &ad4060_chip_info),
I3C_DEVICE(AD4062_I3C_VENDOR, AD4062_PROD_ID, &ad4062_chip_info),
{ }
};
MODULE_DEVICE_TABLE(i3c, ad4062_id_table);
static int ad4062_probe(struct i3c_device *i3cdev)
{
const struct i3c_device_id *id = i3c_device_match_id(i3cdev, ad4062_id_table);
const struct ad4062_chip_info *chip = id->data;
struct device *dev = &i3cdev->dev;
struct iio_dev *indio_dev;
struct ad4062_state *st;
bool ref_sel;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->i3cdev = i3cdev;
i3cdev_set_drvdata(i3cdev, st);
init_completion(&st->completion);
ret = ad4062_regulators_get(st, &ref_sel);
if (ret)
return ret;
st->regmap = devm_regmap_init_i3c(i3cdev, &ad4062_regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to initialize regmap\n");
st->mode = AD4062_SAMPLE_MODE;
st->wait_event = false;
st->chip = chip;
st->sampling_frequency = 0;
st->events_frequency = 0;
st->oversamp_ratio = 0;
st->indio_dev = indio_dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = 1;
indio_dev->info = &ad4062_info;
indio_dev->name = chip->name;
indio_dev->channels = chip->channels;
ret = ad4062_soft_reset(st);
if (ret)
return dev_err_probe(dev, ret, "AD4062 failed to soft reset\n");
ret = ad4062_check_ids(st);
if (ret)
return ret;
ret = ad4062_setup(indio_dev, indio_dev->channels, &ref_sel);
if (ret)
return ret;
ret = ad4062_request_irq(indio_dev);
if (ret)
return ret;
ret = ad4062_request_trigger(indio_dev);
if (ret)
return ret;
ret = devm_iio_triggered_buffer_setup(&i3cdev->dev, indio_dev,
iio_pollfunc_store_time,
ad4062_poll_handler,
&ad4062_triggered_buffer_setup_ops);
if (ret)
return ret;
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n");
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
ret = ad4062_request_ibi(i3cdev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request i3c ibi\n");
ret = ad4062_gpio_init(st);
if (ret)
return ret;
ret = devm_work_autocancel(dev, &st->trig_conv, ad4062_trigger_work);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static int ad4062_runtime_suspend(struct device *dev)
{
struct ad4062_state *st = dev_get_drvdata(dev);
return regmap_write(st->regmap, AD4062_REG_DEVICE_CONFIG,
FIELD_PREP(AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK,
AD4062_REG_DEVICE_CONFIG_LOW_POWER_MODE));
}
static int ad4062_runtime_resume(struct device *dev)
{
struct ad4062_state *st = dev_get_drvdata(dev);
int ret;
ret = regmap_clear_bits(st->regmap, AD4062_REG_DEVICE_CONFIG,
AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK);
if (ret)
return ret;
/* Wait device functional blocks to power up */
fsleep(3 * USEC_PER_MSEC);
return 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(ad4062_pm_ops,
ad4062_runtime_suspend, ad4062_runtime_resume, NULL);
static struct i3c_driver ad4062_driver = {
.driver = {
.name = "ad4062",
.pm = pm_ptr(&ad4062_pm_ops),
},
.probe = ad4062_probe,
.id_table = ad4062_id_table,
};
module_i3c_driver(ad4062_driver);
MODULE_AUTHOR("Jorge Marques <jorge.marques@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD4062");
MODULE_LICENSE("GPL");