162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AD5421 Digital to analog converters  driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2011 Analog Devices Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/device.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/sysfs.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/iio/iio.h>
1962306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2062306a36Sopenharmony_ci#include <linux/iio/events.h>
2162306a36Sopenharmony_ci#include <linux/iio/dac/ad5421.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define AD5421_REG_DAC_DATA		0x1
2562306a36Sopenharmony_ci#define AD5421_REG_CTRL			0x2
2662306a36Sopenharmony_ci#define AD5421_REG_OFFSET		0x3
2762306a36Sopenharmony_ci#define AD5421_REG_GAIN			0x4
2862306a36Sopenharmony_ci/* load dac and fault shared the same register number. Writing to it will cause
2962306a36Sopenharmony_ci * a dac load command, reading from it will return the fault status register */
3062306a36Sopenharmony_ci#define AD5421_REG_LOAD_DAC		0x5
3162306a36Sopenharmony_ci#define AD5421_REG_FAULT		0x5
3262306a36Sopenharmony_ci#define AD5421_REG_FORCE_ALARM_CURRENT	0x6
3362306a36Sopenharmony_ci#define AD5421_REG_RESET		0x7
3462306a36Sopenharmony_ci#define AD5421_REG_START_CONVERSION	0x8
3562306a36Sopenharmony_ci#define AD5421_REG_NOOP			0x9
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define AD5421_CTRL_WATCHDOG_DISABLE	BIT(12)
3862306a36Sopenharmony_ci#define AD5421_CTRL_AUTO_FAULT_READBACK	BIT(11)
3962306a36Sopenharmony_ci#define AD5421_CTRL_MIN_CURRENT		BIT(9)
4062306a36Sopenharmony_ci#define AD5421_CTRL_ADC_SOURCE_TEMP	BIT(8)
4162306a36Sopenharmony_ci#define AD5421_CTRL_ADC_ENABLE		BIT(7)
4262306a36Sopenharmony_ci#define AD5421_CTRL_PWR_DOWN_INT_VREF	BIT(6)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define AD5421_FAULT_SPI			BIT(15)
4562306a36Sopenharmony_ci#define AD5421_FAULT_PEC			BIT(14)
4662306a36Sopenharmony_ci#define AD5421_FAULT_OVER_CURRENT		BIT(13)
4762306a36Sopenharmony_ci#define AD5421_FAULT_UNDER_CURRENT		BIT(12)
4862306a36Sopenharmony_ci#define AD5421_FAULT_TEMP_OVER_140		BIT(11)
4962306a36Sopenharmony_ci#define AD5421_FAULT_TEMP_OVER_100		BIT(10)
5062306a36Sopenharmony_ci#define AD5421_FAULT_UNDER_VOLTAGE_6V		BIT(9)
5162306a36Sopenharmony_ci#define AD5421_FAULT_UNDER_VOLTAGE_12V		BIT(8)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* These bits will cause the fault pin to go high */
5462306a36Sopenharmony_ci#define AD5421_FAULT_TRIGGER_IRQ \
5562306a36Sopenharmony_ci	(AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
5662306a36Sopenharmony_ci	AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * struct ad5421_state - driver instance specific data
6062306a36Sopenharmony_ci * @spi:		spi_device
6162306a36Sopenharmony_ci * @ctrl:		control register cache
6262306a36Sopenharmony_ci * @current_range:	current range which the device is configured for
6362306a36Sopenharmony_ci * @data:		spi transfer buffers
6462306a36Sopenharmony_ci * @fault_mask:		software masking of events
6562306a36Sopenharmony_ci * @lock:		lock to protect the data buffer during SPI ops
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistruct ad5421_state {
6862306a36Sopenharmony_ci	struct spi_device		*spi;
6962306a36Sopenharmony_ci	unsigned int			ctrl;
7062306a36Sopenharmony_ci	enum ad5421_current_range	current_range;
7162306a36Sopenharmony_ci	unsigned int			fault_mask;
7262306a36Sopenharmony_ci	struct mutex			lock;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/*
7562306a36Sopenharmony_ci	 * DMA (thus cache coherency maintenance) may require the
7662306a36Sopenharmony_ci	 * transfer buffers to live in their own cache lines.
7762306a36Sopenharmony_ci	 */
7862306a36Sopenharmony_ci	union {
7962306a36Sopenharmony_ci		__be32 d32;
8062306a36Sopenharmony_ci		u8 d8[4];
8162306a36Sopenharmony_ci	} data[2] __aligned(IIO_DMA_MINALIGN);
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic const struct iio_event_spec ad5421_current_event[] = {
8562306a36Sopenharmony_ci	{
8662306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
8762306a36Sopenharmony_ci		.dir = IIO_EV_DIR_RISING,
8862306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
8962306a36Sopenharmony_ci			BIT(IIO_EV_INFO_ENABLE),
9062306a36Sopenharmony_ci	}, {
9162306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
9262306a36Sopenharmony_ci		.dir = IIO_EV_DIR_FALLING,
9362306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
9462306a36Sopenharmony_ci			BIT(IIO_EV_INFO_ENABLE),
9562306a36Sopenharmony_ci	},
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic const struct iio_event_spec ad5421_temp_event[] = {
9962306a36Sopenharmony_ci	{
10062306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
10162306a36Sopenharmony_ci		.dir = IIO_EV_DIR_RISING,
10262306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
10362306a36Sopenharmony_ci			BIT(IIO_EV_INFO_ENABLE),
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const struct iio_chan_spec ad5421_channels[] = {
10862306a36Sopenharmony_ci	{
10962306a36Sopenharmony_ci		.type = IIO_CURRENT,
11062306a36Sopenharmony_ci		.indexed = 1,
11162306a36Sopenharmony_ci		.output = 1,
11262306a36Sopenharmony_ci		.channel = 0,
11362306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
11462306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBSCALE) |
11562306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS),
11662306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
11762306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OFFSET),
11862306a36Sopenharmony_ci		.scan_type = {
11962306a36Sopenharmony_ci			.sign = 'u',
12062306a36Sopenharmony_ci			.realbits = 16,
12162306a36Sopenharmony_ci			.storagebits = 16,
12262306a36Sopenharmony_ci		},
12362306a36Sopenharmony_ci		.event_spec = ad5421_current_event,
12462306a36Sopenharmony_ci		.num_event_specs = ARRAY_SIZE(ad5421_current_event),
12562306a36Sopenharmony_ci	},
12662306a36Sopenharmony_ci	{
12762306a36Sopenharmony_ci		.type = IIO_TEMP,
12862306a36Sopenharmony_ci		.channel = -1,
12962306a36Sopenharmony_ci		.event_spec = ad5421_temp_event,
13062306a36Sopenharmony_ci		.num_event_specs = ARRAY_SIZE(ad5421_temp_event),
13162306a36Sopenharmony_ci	},
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int ad5421_write_unlocked(struct iio_dev *indio_dev,
13562306a36Sopenharmony_ci	unsigned int reg, unsigned int val)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return spi_write(st->spi, &st->data[0].d8[1], 3);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
14562306a36Sopenharmony_ci	unsigned int val)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
14862306a36Sopenharmony_ci	int ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	mutex_lock(&st->lock);
15162306a36Sopenharmony_ci	ret = ad5421_write_unlocked(indio_dev, reg, val);
15262306a36Sopenharmony_ci	mutex_unlock(&st->lock);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return ret;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
16062306a36Sopenharmony_ci	int ret;
16162306a36Sopenharmony_ci	struct spi_transfer t[] = {
16262306a36Sopenharmony_ci		{
16362306a36Sopenharmony_ci			.tx_buf = &st->data[0].d8[1],
16462306a36Sopenharmony_ci			.len = 3,
16562306a36Sopenharmony_ci			.cs_change = 1,
16662306a36Sopenharmony_ci		}, {
16762306a36Sopenharmony_ci			.rx_buf = &st->data[1].d8[1],
16862306a36Sopenharmony_ci			.len = 3,
16962306a36Sopenharmony_ci		},
17062306a36Sopenharmony_ci	};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	mutex_lock(&st->lock);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
17762306a36Sopenharmony_ci	if (ret >= 0)
17862306a36Sopenharmony_ci		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	mutex_unlock(&st->lock);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return ret;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
18662306a36Sopenharmony_ci	unsigned int clr)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
18962306a36Sopenharmony_ci	unsigned int ret;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mutex_lock(&st->lock);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	st->ctrl &= ~clr;
19462306a36Sopenharmony_ci	st->ctrl |= set;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	mutex_unlock(&st->lock);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return ret;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic irqreturn_t ad5421_fault_handler(int irq, void *data)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct iio_dev *indio_dev = data;
20662306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
20762306a36Sopenharmony_ci	unsigned int fault;
20862306a36Sopenharmony_ci	unsigned int old_fault = 0;
20962306a36Sopenharmony_ci	unsigned int events;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
21262306a36Sopenharmony_ci	if (!fault)
21362306a36Sopenharmony_ci		return IRQ_NONE;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* If we had a fault, this might mean that the DAC has lost its state
21662306a36Sopenharmony_ci	 * and has been reset. Make sure that the control register actually
21762306a36Sopenharmony_ci	 * contains what we expect it to contain. Otherwise the watchdog might
21862306a36Sopenharmony_ci	 * be enabled and we get watchdog timeout faults, which will render the
21962306a36Sopenharmony_ci	 * DAC unusable. */
22062306a36Sopenharmony_ci	ad5421_update_ctrl(indio_dev, 0, 0);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* The fault pin stays high as long as a fault condition is present and
22462306a36Sopenharmony_ci	 * it is not possible to mask fault conditions. For certain fault
22562306a36Sopenharmony_ci	 * conditions for example like over-temperature it takes some time
22662306a36Sopenharmony_ci	 * until the fault condition disappears. If we would exit the interrupt
22762306a36Sopenharmony_ci	 * handler immediately after handling the event it would be entered
22862306a36Sopenharmony_ci	 * again instantly. Thus we fall back to polling in case we detect that
22962306a36Sopenharmony_ci	 * a interrupt condition is still present.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci	do {
23262306a36Sopenharmony_ci		/* 0xffff is a invalid value for the register and will only be
23362306a36Sopenharmony_ci		 * read if there has been a communication error */
23462306a36Sopenharmony_ci		if (fault == 0xffff)
23562306a36Sopenharmony_ci			fault = 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* we are only interested in new events */
23862306a36Sopenharmony_ci		events = (old_fault ^ fault) & fault;
23962306a36Sopenharmony_ci		events &= st->fault_mask;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		if (events & AD5421_FAULT_OVER_CURRENT) {
24262306a36Sopenharmony_ci			iio_push_event(indio_dev,
24362306a36Sopenharmony_ci				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
24462306a36Sopenharmony_ci					0,
24562306a36Sopenharmony_ci					IIO_EV_TYPE_THRESH,
24662306a36Sopenharmony_ci					IIO_EV_DIR_RISING),
24762306a36Sopenharmony_ci			iio_get_time_ns(indio_dev));
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		if (events & AD5421_FAULT_UNDER_CURRENT) {
25162306a36Sopenharmony_ci			iio_push_event(indio_dev,
25262306a36Sopenharmony_ci				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
25362306a36Sopenharmony_ci					0,
25462306a36Sopenharmony_ci					IIO_EV_TYPE_THRESH,
25562306a36Sopenharmony_ci					IIO_EV_DIR_FALLING),
25662306a36Sopenharmony_ci				iio_get_time_ns(indio_dev));
25762306a36Sopenharmony_ci		}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		if (events & AD5421_FAULT_TEMP_OVER_140) {
26062306a36Sopenharmony_ci			iio_push_event(indio_dev,
26162306a36Sopenharmony_ci				IIO_UNMOD_EVENT_CODE(IIO_TEMP,
26262306a36Sopenharmony_ci					0,
26362306a36Sopenharmony_ci					IIO_EV_TYPE_MAG,
26462306a36Sopenharmony_ci					IIO_EV_DIR_RISING),
26562306a36Sopenharmony_ci				iio_get_time_ns(indio_dev));
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		old_fault = fault;
26962306a36Sopenharmony_ci		fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		/* still active? go to sleep for some time */
27262306a36Sopenharmony_ci		if (fault & AD5421_FAULT_TRIGGER_IRQ)
27362306a36Sopenharmony_ci			msleep(1000);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	} while (fault & AD5421_FAULT_TRIGGER_IRQ);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return IRQ_HANDLED;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void ad5421_get_current_min_max(struct ad5421_state *st,
28262306a36Sopenharmony_ci	unsigned int *min, unsigned int *max)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	/* The current range is configured using external pins, which are
28562306a36Sopenharmony_ci	 * usually hard-wired and not run-time switchable. */
28662306a36Sopenharmony_ci	switch (st->current_range) {
28762306a36Sopenharmony_ci	case AD5421_CURRENT_RANGE_4mA_20mA:
28862306a36Sopenharmony_ci		*min = 4000;
28962306a36Sopenharmony_ci		*max = 20000;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	case AD5421_CURRENT_RANGE_3mA8_21mA:
29262306a36Sopenharmony_ci		*min = 3800;
29362306a36Sopenharmony_ci		*max = 21000;
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	case AD5421_CURRENT_RANGE_3mA2_24mA:
29662306a36Sopenharmony_ci		*min = 3200;
29762306a36Sopenharmony_ci		*max = 24000;
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	default:
30062306a36Sopenharmony_ci		*min = 0;
30162306a36Sopenharmony_ci		*max = 1;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic inline unsigned int ad5421_get_offset(struct ad5421_state *st)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	unsigned int min, max;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ad5421_get_current_min_max(st, &min, &max);
31162306a36Sopenharmony_ci	return (min * (1 << 16)) / (max - min);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int ad5421_read_raw(struct iio_dev *indio_dev,
31562306a36Sopenharmony_ci	struct iio_chan_spec const *chan, int *val, int *val2, long m)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
31862306a36Sopenharmony_ci	unsigned int min, max;
31962306a36Sopenharmony_ci	int ret;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (chan->type != IIO_CURRENT)
32262306a36Sopenharmony_ci		return -EINVAL;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	switch (m) {
32562306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
32662306a36Sopenharmony_ci		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
32762306a36Sopenharmony_ci		if (ret < 0)
32862306a36Sopenharmony_ci			return ret;
32962306a36Sopenharmony_ci		*val = ret;
33062306a36Sopenharmony_ci		return IIO_VAL_INT;
33162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
33262306a36Sopenharmony_ci		ad5421_get_current_min_max(st, &min, &max);
33362306a36Sopenharmony_ci		*val = max - min;
33462306a36Sopenharmony_ci		*val2 = (1 << 16) * 1000;
33562306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL;
33662306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
33762306a36Sopenharmony_ci		*val = ad5421_get_offset(st);
33862306a36Sopenharmony_ci		return IIO_VAL_INT;
33962306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
34062306a36Sopenharmony_ci		ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
34162306a36Sopenharmony_ci		if (ret < 0)
34262306a36Sopenharmony_ci			return ret;
34362306a36Sopenharmony_ci		*val = ret - 32768;
34462306a36Sopenharmony_ci		return IIO_VAL_INT;
34562306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
34662306a36Sopenharmony_ci		ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
34762306a36Sopenharmony_ci		if (ret < 0)
34862306a36Sopenharmony_ci			return ret;
34962306a36Sopenharmony_ci		*val = ret;
35062306a36Sopenharmony_ci		return IIO_VAL_INT;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return -EINVAL;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int ad5421_write_raw(struct iio_dev *indio_dev,
35762306a36Sopenharmony_ci	struct iio_chan_spec const *chan, int val, int val2, long mask)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	const unsigned int max_val = 1 << 16;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	switch (mask) {
36262306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
36362306a36Sopenharmony_ci		if (val >= max_val || val < 0)
36462306a36Sopenharmony_ci			return -EINVAL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
36762306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
36862306a36Sopenharmony_ci		val += 32768;
36962306a36Sopenharmony_ci		if (val >= max_val || val < 0)
37062306a36Sopenharmony_ci			return -EINVAL;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
37362306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
37462306a36Sopenharmony_ci		if (val >= max_val || val < 0)
37562306a36Sopenharmony_ci			return -EINVAL;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
37862306a36Sopenharmony_ci	default:
37962306a36Sopenharmony_ci		break;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return -EINVAL;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic int ad5421_write_event_config(struct iio_dev *indio_dev,
38662306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
38762306a36Sopenharmony_ci	enum iio_event_direction dir, int state)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
39062306a36Sopenharmony_ci	unsigned int mask;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	switch (chan->type) {
39362306a36Sopenharmony_ci	case IIO_CURRENT:
39462306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
39562306a36Sopenharmony_ci			mask = AD5421_FAULT_OVER_CURRENT;
39662306a36Sopenharmony_ci		else
39762306a36Sopenharmony_ci			mask = AD5421_FAULT_UNDER_CURRENT;
39862306a36Sopenharmony_ci		break;
39962306a36Sopenharmony_ci	case IIO_TEMP:
40062306a36Sopenharmony_ci		mask = AD5421_FAULT_TEMP_OVER_140;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	default:
40362306a36Sopenharmony_ci		return -EINVAL;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	mutex_lock(&st->lock);
40762306a36Sopenharmony_ci	if (state)
40862306a36Sopenharmony_ci		st->fault_mask |= mask;
40962306a36Sopenharmony_ci	else
41062306a36Sopenharmony_ci		st->fault_mask &= ~mask;
41162306a36Sopenharmony_ci	mutex_unlock(&st->lock);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic int ad5421_read_event_config(struct iio_dev *indio_dev,
41762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
41862306a36Sopenharmony_ci	enum iio_event_direction dir)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct ad5421_state *st = iio_priv(indio_dev);
42162306a36Sopenharmony_ci	unsigned int mask;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	switch (chan->type) {
42462306a36Sopenharmony_ci	case IIO_CURRENT:
42562306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
42662306a36Sopenharmony_ci			mask = AD5421_FAULT_OVER_CURRENT;
42762306a36Sopenharmony_ci		else
42862306a36Sopenharmony_ci			mask = AD5421_FAULT_UNDER_CURRENT;
42962306a36Sopenharmony_ci		break;
43062306a36Sopenharmony_ci	case IIO_TEMP:
43162306a36Sopenharmony_ci		mask = AD5421_FAULT_TEMP_OVER_140;
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	default:
43462306a36Sopenharmony_ci		return -EINVAL;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return (bool)(st->fault_mask & mask);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int ad5421_read_event_value(struct iio_dev *indio_dev,
44162306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
44262306a36Sopenharmony_ci	enum iio_event_direction dir, enum iio_event_info info, int *val,
44362306a36Sopenharmony_ci	int *val2)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	int ret;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	switch (chan->type) {
44862306a36Sopenharmony_ci	case IIO_CURRENT:
44962306a36Sopenharmony_ci		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
45062306a36Sopenharmony_ci		if (ret < 0)
45162306a36Sopenharmony_ci			return ret;
45262306a36Sopenharmony_ci		*val = ret;
45362306a36Sopenharmony_ci		break;
45462306a36Sopenharmony_ci	case IIO_TEMP:
45562306a36Sopenharmony_ci		*val = 140000;
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	default:
45862306a36Sopenharmony_ci		return -EINVAL;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return IIO_VAL_INT;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic const struct iio_info ad5421_info = {
46562306a36Sopenharmony_ci	.read_raw =		ad5421_read_raw,
46662306a36Sopenharmony_ci	.write_raw =		ad5421_write_raw,
46762306a36Sopenharmony_ci	.read_event_config =	ad5421_read_event_config,
46862306a36Sopenharmony_ci	.write_event_config =	ad5421_write_event_config,
46962306a36Sopenharmony_ci	.read_event_value =	ad5421_read_event_value,
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic int ad5421_probe(struct spi_device *spi)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
47562306a36Sopenharmony_ci	struct iio_dev *indio_dev;
47662306a36Sopenharmony_ci	struct ad5421_state *st;
47762306a36Sopenharmony_ci	int ret;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
48062306a36Sopenharmony_ci	if (indio_dev == NULL) {
48162306a36Sopenharmony_ci		dev_err(&spi->dev, "Failed to allocate iio device\n");
48262306a36Sopenharmony_ci		return  -ENOMEM;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	st = iio_priv(indio_dev);
48662306a36Sopenharmony_ci	spi_set_drvdata(spi, indio_dev);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	st->spi = spi;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	indio_dev->name = "ad5421";
49162306a36Sopenharmony_ci	indio_dev->info = &ad5421_info;
49262306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
49362306a36Sopenharmony_ci	indio_dev->channels = ad5421_channels;
49462306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	mutex_init(&st->lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
49962306a36Sopenharmony_ci			AD5421_CTRL_AUTO_FAULT_READBACK;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (pdata) {
50262306a36Sopenharmony_ci		st->current_range = pdata->current_range;
50362306a36Sopenharmony_ci		if (pdata->external_vref)
50462306a36Sopenharmony_ci			st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
50562306a36Sopenharmony_ci	} else {
50662306a36Sopenharmony_ci		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* write initial ctrl register value */
51062306a36Sopenharmony_ci	ad5421_update_ctrl(indio_dev, 0, 0);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (spi->irq) {
51362306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&spi->dev, spi->irq,
51462306a36Sopenharmony_ci					   NULL,
51562306a36Sopenharmony_ci					   ad5421_fault_handler,
51662306a36Sopenharmony_ci					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
51762306a36Sopenharmony_ci					   "ad5421 fault",
51862306a36Sopenharmony_ci					   indio_dev);
51962306a36Sopenharmony_ci		if (ret)
52062306a36Sopenharmony_ci			return ret;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return devm_iio_device_register(&spi->dev, indio_dev);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic struct spi_driver ad5421_driver = {
52762306a36Sopenharmony_ci	.driver = {
52862306a36Sopenharmony_ci		   .name = "ad5421",
52962306a36Sopenharmony_ci	},
53062306a36Sopenharmony_ci	.probe = ad5421_probe,
53162306a36Sopenharmony_ci};
53262306a36Sopenharmony_cimodule_spi_driver(ad5421_driver);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
53562306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5421 DAC");
53662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
53762306a36Sopenharmony_ciMODULE_ALIAS("spi:ad5421");
538