Files
linux/drivers/iio/adc/ad4062.c
Antoniu Miclaus 5bcbbcfb7c iio: adc: ad4062: use dev_err_probe()
Use dev_err_probe() instead of dev_err() in the probe path to ensure
proper handling of deferred probing and to simplify error handling.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2026-04-27 09:58:18 +01:00

1615 lines
41 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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)
return dev_err_probe(dev, -ENODEV,
"Vendor ID x%x does not match expected value\n", val);
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_irq(dev, ret, ad4062_irq_handler_drdy,
IRQF_NO_THREAD, 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 int 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);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
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;
ret = ad4062_sizeof_storagebits(st);
if (ret < 0)
return ret;
st->conv_sizeof = ret;
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");