xref: /openbmc/linux/drivers/iio/dac/ad5592r-base.c (revision 56ca9db8)
156ca9db8SPaul Cercueil /*
256ca9db8SPaul Cercueil  * AD5592R Digital <-> Analog converters driver
356ca9db8SPaul Cercueil  *
456ca9db8SPaul Cercueil  * Copyright 2014-2016 Analog Devices Inc.
556ca9db8SPaul Cercueil  * Author: Paul Cercueil <paul.cercueil@analog.com>
656ca9db8SPaul Cercueil  *
756ca9db8SPaul Cercueil  * Licensed under the GPL-2.
856ca9db8SPaul Cercueil  */
956ca9db8SPaul Cercueil 
1056ca9db8SPaul Cercueil #include <linux/bitops.h>
1156ca9db8SPaul Cercueil #include <linux/delay.h>
1256ca9db8SPaul Cercueil #include <linux/iio/iio.h>
1356ca9db8SPaul Cercueil #include <linux/module.h>
1456ca9db8SPaul Cercueil #include <linux/mutex.h>
1556ca9db8SPaul Cercueil #include <linux/of.h>
1656ca9db8SPaul Cercueil #include <linux/regulator/consumer.h>
1756ca9db8SPaul Cercueil #include <linux/gpio/consumer.h>
1856ca9db8SPaul Cercueil #include <linux/gpio/driver.h>
1956ca9db8SPaul Cercueil #include <linux/gpio.h>
2056ca9db8SPaul Cercueil #include <linux/property.h>
2156ca9db8SPaul Cercueil 
2256ca9db8SPaul Cercueil #include <dt-bindings/iio/adi,ad5592r.h>
2356ca9db8SPaul Cercueil 
2456ca9db8SPaul Cercueil #include "ad5592r-base.h"
2556ca9db8SPaul Cercueil 
2656ca9db8SPaul Cercueil static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
2756ca9db8SPaul Cercueil {
2856ca9db8SPaul Cercueil 	struct ad5592r_state *st = gpiochip_get_data(chip);
2956ca9db8SPaul Cercueil 	int ret = 0;
3056ca9db8SPaul Cercueil 	u8 val;
3156ca9db8SPaul Cercueil 
3256ca9db8SPaul Cercueil 	mutex_lock(&st->gpio_lock);
3356ca9db8SPaul Cercueil 
3456ca9db8SPaul Cercueil 	if (st->gpio_out & BIT(offset))
3556ca9db8SPaul Cercueil 		val = st->gpio_val;
3656ca9db8SPaul Cercueil 	else
3756ca9db8SPaul Cercueil 		ret = st->ops->gpio_read(st, &val);
3856ca9db8SPaul Cercueil 
3956ca9db8SPaul Cercueil 	mutex_unlock(&st->gpio_lock);
4056ca9db8SPaul Cercueil 
4156ca9db8SPaul Cercueil 	if (ret < 0)
4256ca9db8SPaul Cercueil 		return ret;
4356ca9db8SPaul Cercueil 
4456ca9db8SPaul Cercueil 	return !!(val & BIT(offset));
4556ca9db8SPaul Cercueil }
4656ca9db8SPaul Cercueil 
4756ca9db8SPaul Cercueil static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
4856ca9db8SPaul Cercueil {
4956ca9db8SPaul Cercueil 	struct ad5592r_state *st = gpiochip_get_data(chip);
5056ca9db8SPaul Cercueil 
5156ca9db8SPaul Cercueil 	mutex_lock(&st->gpio_lock);
5256ca9db8SPaul Cercueil 
5356ca9db8SPaul Cercueil 	if (value)
5456ca9db8SPaul Cercueil 		st->gpio_val |= BIT(offset);
5556ca9db8SPaul Cercueil 	else
5656ca9db8SPaul Cercueil 		st->gpio_val &= ~BIT(offset);
5756ca9db8SPaul Cercueil 
5856ca9db8SPaul Cercueil 	st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
5956ca9db8SPaul Cercueil 
6056ca9db8SPaul Cercueil 	mutex_unlock(&st->gpio_lock);
6156ca9db8SPaul Cercueil }
6256ca9db8SPaul Cercueil 
6356ca9db8SPaul Cercueil static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
6456ca9db8SPaul Cercueil {
6556ca9db8SPaul Cercueil 	struct ad5592r_state *st = gpiochip_get_data(chip);
6656ca9db8SPaul Cercueil 	int ret;
6756ca9db8SPaul Cercueil 
6856ca9db8SPaul Cercueil 	mutex_lock(&st->gpio_lock);
6956ca9db8SPaul Cercueil 
7056ca9db8SPaul Cercueil 	st->gpio_out &= ~BIT(offset);
7156ca9db8SPaul Cercueil 	st->gpio_in |= BIT(offset);
7256ca9db8SPaul Cercueil 
7356ca9db8SPaul Cercueil 	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
7456ca9db8SPaul Cercueil 	if (ret < 0)
7556ca9db8SPaul Cercueil 		goto err_unlock;
7656ca9db8SPaul Cercueil 
7756ca9db8SPaul Cercueil 	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
7856ca9db8SPaul Cercueil 
7956ca9db8SPaul Cercueil err_unlock:
8056ca9db8SPaul Cercueil 	mutex_unlock(&st->gpio_lock);
8156ca9db8SPaul Cercueil 
8256ca9db8SPaul Cercueil 	return ret;
8356ca9db8SPaul Cercueil }
8456ca9db8SPaul Cercueil 
8556ca9db8SPaul Cercueil static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
8656ca9db8SPaul Cercueil 					 unsigned offset, int value)
8756ca9db8SPaul Cercueil {
8856ca9db8SPaul Cercueil 	struct ad5592r_state *st = gpiochip_get_data(chip);
8956ca9db8SPaul Cercueil 	int ret;
9056ca9db8SPaul Cercueil 
9156ca9db8SPaul Cercueil 	mutex_lock(&st->gpio_lock);
9256ca9db8SPaul Cercueil 
9356ca9db8SPaul Cercueil 	if (value)
9456ca9db8SPaul Cercueil 		st->gpio_val |= BIT(offset);
9556ca9db8SPaul Cercueil 	else
9656ca9db8SPaul Cercueil 		st->gpio_val &= ~BIT(offset);
9756ca9db8SPaul Cercueil 
9856ca9db8SPaul Cercueil 	st->gpio_in &= ~BIT(offset);
9956ca9db8SPaul Cercueil 	st->gpio_out |= BIT(offset);
10056ca9db8SPaul Cercueil 
10156ca9db8SPaul Cercueil 	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
10256ca9db8SPaul Cercueil 	if (ret < 0)
10356ca9db8SPaul Cercueil 		goto err_unlock;
10456ca9db8SPaul Cercueil 
10556ca9db8SPaul Cercueil 	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
10656ca9db8SPaul Cercueil 	if (ret < 0)
10756ca9db8SPaul Cercueil 		goto err_unlock;
10856ca9db8SPaul Cercueil 
10956ca9db8SPaul Cercueil 	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
11056ca9db8SPaul Cercueil 
11156ca9db8SPaul Cercueil err_unlock:
11256ca9db8SPaul Cercueil 	mutex_unlock(&st->gpio_lock);
11356ca9db8SPaul Cercueil 
11456ca9db8SPaul Cercueil 	return ret;
11556ca9db8SPaul Cercueil }
11656ca9db8SPaul Cercueil 
11756ca9db8SPaul Cercueil static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
11856ca9db8SPaul Cercueil {
11956ca9db8SPaul Cercueil 	struct ad5592r_state *st = gpiochip_get_data(chip);
12056ca9db8SPaul Cercueil 
12156ca9db8SPaul Cercueil 	if (!(st->gpio_map & BIT(offset))) {
12256ca9db8SPaul Cercueil 		dev_err(st->dev, "GPIO %d is reserved by alternate function\n",
12356ca9db8SPaul Cercueil 			offset);
12456ca9db8SPaul Cercueil 		return -ENODEV;
12556ca9db8SPaul Cercueil 	}
12656ca9db8SPaul Cercueil 
12756ca9db8SPaul Cercueil 	return 0;
12856ca9db8SPaul Cercueil }
12956ca9db8SPaul Cercueil 
13056ca9db8SPaul Cercueil static int ad5592r_gpio_init(struct ad5592r_state *st)
13156ca9db8SPaul Cercueil {
13256ca9db8SPaul Cercueil 	if (!st->gpio_map)
13356ca9db8SPaul Cercueil 		return 0;
13456ca9db8SPaul Cercueil 
13556ca9db8SPaul Cercueil 	st->gpiochip.label = dev_name(st->dev);
13656ca9db8SPaul Cercueil 	st->gpiochip.base = -1;
13756ca9db8SPaul Cercueil 	st->gpiochip.ngpio = 8;
13856ca9db8SPaul Cercueil 	st->gpiochip.parent = st->dev;
13956ca9db8SPaul Cercueil 	st->gpiochip.can_sleep = true;
14056ca9db8SPaul Cercueil 	st->gpiochip.direction_input = ad5592r_gpio_direction_input;
14156ca9db8SPaul Cercueil 	st->gpiochip.direction_output = ad5592r_gpio_direction_output;
14256ca9db8SPaul Cercueil 	st->gpiochip.get = ad5592r_gpio_get;
14356ca9db8SPaul Cercueil 	st->gpiochip.set = ad5592r_gpio_set;
14456ca9db8SPaul Cercueil 	st->gpiochip.request = ad5592r_gpio_request;
14556ca9db8SPaul Cercueil 	st->gpiochip.owner = THIS_MODULE;
14656ca9db8SPaul Cercueil 
14756ca9db8SPaul Cercueil 	mutex_init(&st->gpio_lock);
14856ca9db8SPaul Cercueil 
14956ca9db8SPaul Cercueil 	return gpiochip_add_data(&st->gpiochip, st);
15056ca9db8SPaul Cercueil }
15156ca9db8SPaul Cercueil 
15256ca9db8SPaul Cercueil static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
15356ca9db8SPaul Cercueil {
15456ca9db8SPaul Cercueil 	if (st->gpio_map)
15556ca9db8SPaul Cercueil 		gpiochip_remove(&st->gpiochip);
15656ca9db8SPaul Cercueil }
15756ca9db8SPaul Cercueil 
15856ca9db8SPaul Cercueil static int ad5592r_reset(struct ad5592r_state *st)
15956ca9db8SPaul Cercueil {
16056ca9db8SPaul Cercueil 	struct gpio_desc *gpio;
16156ca9db8SPaul Cercueil 	struct iio_dev *iio_dev = iio_priv_to_dev(st);
16256ca9db8SPaul Cercueil 
16356ca9db8SPaul Cercueil 	gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
16456ca9db8SPaul Cercueil 	if (IS_ERR(gpio))
16556ca9db8SPaul Cercueil 		return PTR_ERR(gpio);
16656ca9db8SPaul Cercueil 
16756ca9db8SPaul Cercueil 	if (gpio) {
16856ca9db8SPaul Cercueil 		udelay(1);
16956ca9db8SPaul Cercueil 		gpiod_set_value(gpio, 1);
17056ca9db8SPaul Cercueil 	} else {
17156ca9db8SPaul Cercueil 		mutex_lock(&iio_dev->mlock);
17256ca9db8SPaul Cercueil 		/* Writing this magic value resets the device */
17356ca9db8SPaul Cercueil 		st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
17456ca9db8SPaul Cercueil 		mutex_unlock(&iio_dev->mlock);
17556ca9db8SPaul Cercueil 	}
17656ca9db8SPaul Cercueil 
17756ca9db8SPaul Cercueil 	udelay(250);
17856ca9db8SPaul Cercueil 
17956ca9db8SPaul Cercueil 	return 0;
18056ca9db8SPaul Cercueil }
18156ca9db8SPaul Cercueil 
18256ca9db8SPaul Cercueil static int ad5592r_get_vref(struct ad5592r_state *st)
18356ca9db8SPaul Cercueil {
18456ca9db8SPaul Cercueil 	int ret;
18556ca9db8SPaul Cercueil 
18656ca9db8SPaul Cercueil 	if (st->reg) {
18756ca9db8SPaul Cercueil 		ret = regulator_get_voltage(st->reg);
18856ca9db8SPaul Cercueil 		if (ret < 0)
18956ca9db8SPaul Cercueil 			return ret;
19056ca9db8SPaul Cercueil 
19156ca9db8SPaul Cercueil 		return ret / 1000;
19256ca9db8SPaul Cercueil 	} else {
19356ca9db8SPaul Cercueil 		return 2500;
19456ca9db8SPaul Cercueil 	}
19556ca9db8SPaul Cercueil }
19656ca9db8SPaul Cercueil 
19756ca9db8SPaul Cercueil static int ad5592r_set_channel_modes(struct ad5592r_state *st)
19856ca9db8SPaul Cercueil {
19956ca9db8SPaul Cercueil 	const struct ad5592r_rw_ops *ops = st->ops;
20056ca9db8SPaul Cercueil 	int ret;
20156ca9db8SPaul Cercueil 	unsigned i;
20256ca9db8SPaul Cercueil 	struct iio_dev *iio_dev = iio_priv_to_dev(st);
20356ca9db8SPaul Cercueil 	u8 pulldown = 0, tristate = 0, dac = 0, adc = 0;
20456ca9db8SPaul Cercueil 	u16 read_back;
20556ca9db8SPaul Cercueil 
20656ca9db8SPaul Cercueil 	for (i = 0; i < st->num_channels; i++) {
20756ca9db8SPaul Cercueil 		switch (st->channel_modes[i]) {
20856ca9db8SPaul Cercueil 		case CH_MODE_DAC:
20956ca9db8SPaul Cercueil 			dac |= BIT(i);
21056ca9db8SPaul Cercueil 			break;
21156ca9db8SPaul Cercueil 
21256ca9db8SPaul Cercueil 		case CH_MODE_ADC:
21356ca9db8SPaul Cercueil 			adc |= BIT(i);
21456ca9db8SPaul Cercueil 			break;
21556ca9db8SPaul Cercueil 
21656ca9db8SPaul Cercueil 		case CH_MODE_DAC_AND_ADC:
21756ca9db8SPaul Cercueil 			dac |= BIT(i);
21856ca9db8SPaul Cercueil 			adc |= BIT(i);
21956ca9db8SPaul Cercueil 			break;
22056ca9db8SPaul Cercueil 
22156ca9db8SPaul Cercueil 		case CH_MODE_GPIO:
22256ca9db8SPaul Cercueil 			st->gpio_map |= BIT(i);
22356ca9db8SPaul Cercueil 			st->gpio_in |= BIT(i); /* Default to input */
22456ca9db8SPaul Cercueil 			break;
22556ca9db8SPaul Cercueil 
22656ca9db8SPaul Cercueil 		case CH_MODE_UNUSED:
22756ca9db8SPaul Cercueil 			/* fall-through */
22856ca9db8SPaul Cercueil 		default:
22956ca9db8SPaul Cercueil 			switch (st->channel_offstate[i]) {
23056ca9db8SPaul Cercueil 			case CH_OFFSTATE_OUT_TRISTATE:
23156ca9db8SPaul Cercueil 				tristate |= BIT(i);
23256ca9db8SPaul Cercueil 				break;
23356ca9db8SPaul Cercueil 
23456ca9db8SPaul Cercueil 			case CH_OFFSTATE_OUT_LOW:
23556ca9db8SPaul Cercueil 				st->gpio_out |= BIT(i);
23656ca9db8SPaul Cercueil 				break;
23756ca9db8SPaul Cercueil 
23856ca9db8SPaul Cercueil 			case CH_OFFSTATE_OUT_HIGH:
23956ca9db8SPaul Cercueil 				st->gpio_out |= BIT(i);
24056ca9db8SPaul Cercueil 				st->gpio_val |= BIT(i);
24156ca9db8SPaul Cercueil 				break;
24256ca9db8SPaul Cercueil 
24356ca9db8SPaul Cercueil 			case CH_OFFSTATE_PULLDOWN:
24456ca9db8SPaul Cercueil 				/* fall-through */
24556ca9db8SPaul Cercueil 			default:
24656ca9db8SPaul Cercueil 				pulldown |= BIT(i);
24756ca9db8SPaul Cercueil 				break;
24856ca9db8SPaul Cercueil 			}
24956ca9db8SPaul Cercueil 		}
25056ca9db8SPaul Cercueil 	}
25156ca9db8SPaul Cercueil 
25256ca9db8SPaul Cercueil 	mutex_lock(&iio_dev->mlock);
25356ca9db8SPaul Cercueil 
25456ca9db8SPaul Cercueil 	/* Pull down unused pins to GND */
25556ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
25656ca9db8SPaul Cercueil 	if (ret)
25756ca9db8SPaul Cercueil 		goto err_unlock;
25856ca9db8SPaul Cercueil 
25956ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate);
26056ca9db8SPaul Cercueil 	if (ret)
26156ca9db8SPaul Cercueil 		goto err_unlock;
26256ca9db8SPaul Cercueil 
26356ca9db8SPaul Cercueil 	/* Configure pins that we use */
26456ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac);
26556ca9db8SPaul Cercueil 	if (ret)
26656ca9db8SPaul Cercueil 		goto err_unlock;
26756ca9db8SPaul Cercueil 
26856ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc);
26956ca9db8SPaul Cercueil 	if (ret)
27056ca9db8SPaul Cercueil 		goto err_unlock;
27156ca9db8SPaul Cercueil 
27256ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
27356ca9db8SPaul Cercueil 	if (ret)
27456ca9db8SPaul Cercueil 		goto err_unlock;
27556ca9db8SPaul Cercueil 
27656ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
27756ca9db8SPaul Cercueil 	if (ret)
27856ca9db8SPaul Cercueil 		goto err_unlock;
27956ca9db8SPaul Cercueil 
28056ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
28156ca9db8SPaul Cercueil 	if (ret)
28256ca9db8SPaul Cercueil 		goto err_unlock;
28356ca9db8SPaul Cercueil 
28456ca9db8SPaul Cercueil 	/* Verify that we can read back at least one register */
28556ca9db8SPaul Cercueil 	ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back);
28656ca9db8SPaul Cercueil 	if (!ret && (read_back & 0xff) != adc)
28756ca9db8SPaul Cercueil 		ret = -EIO;
28856ca9db8SPaul Cercueil 
28956ca9db8SPaul Cercueil err_unlock:
29056ca9db8SPaul Cercueil 	mutex_unlock(&iio_dev->mlock);
29156ca9db8SPaul Cercueil 	return ret;
29256ca9db8SPaul Cercueil }
29356ca9db8SPaul Cercueil 
29456ca9db8SPaul Cercueil static int ad5592r_reset_channel_modes(struct ad5592r_state *st)
29556ca9db8SPaul Cercueil {
29656ca9db8SPaul Cercueil 	int i;
29756ca9db8SPaul Cercueil 
29856ca9db8SPaul Cercueil 	for (i = 0; i < ARRAY_SIZE(st->channel_modes); i++)
29956ca9db8SPaul Cercueil 		st->channel_modes[i] = CH_MODE_UNUSED;
30056ca9db8SPaul Cercueil 
30156ca9db8SPaul Cercueil 	return ad5592r_set_channel_modes(st);
30256ca9db8SPaul Cercueil }
30356ca9db8SPaul Cercueil 
30456ca9db8SPaul Cercueil static int ad5592r_write_raw(struct iio_dev *iio_dev,
30556ca9db8SPaul Cercueil 	struct iio_chan_spec const *chan, int val, int val2, long mask)
30656ca9db8SPaul Cercueil {
30756ca9db8SPaul Cercueil 	struct ad5592r_state *st = iio_priv(iio_dev);
30856ca9db8SPaul Cercueil 	int ret;
30956ca9db8SPaul Cercueil 
31056ca9db8SPaul Cercueil 	switch (mask) {
31156ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_RAW:
31256ca9db8SPaul Cercueil 
31356ca9db8SPaul Cercueil 		if (val >= (1 << chan->scan_type.realbits) || val < 0)
31456ca9db8SPaul Cercueil 			return -EINVAL;
31556ca9db8SPaul Cercueil 
31656ca9db8SPaul Cercueil 		if (!chan->output)
31756ca9db8SPaul Cercueil 			return -EINVAL;
31856ca9db8SPaul Cercueil 
31956ca9db8SPaul Cercueil 		mutex_lock(&iio_dev->mlock);
32056ca9db8SPaul Cercueil 		ret = st->ops->write_dac(st, chan->channel, val);
32156ca9db8SPaul Cercueil 		if (!ret)
32256ca9db8SPaul Cercueil 			st->cached_dac[chan->channel] = val;
32356ca9db8SPaul Cercueil 		mutex_unlock(&iio_dev->mlock);
32456ca9db8SPaul Cercueil 		return ret;
32556ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_SCALE:
32656ca9db8SPaul Cercueil 		if (chan->type == IIO_VOLTAGE) {
32756ca9db8SPaul Cercueil 			bool gain;
32856ca9db8SPaul Cercueil 
32956ca9db8SPaul Cercueil 			if (val == st->scale_avail[0][0] &&
33056ca9db8SPaul Cercueil 				val2 == st->scale_avail[0][1])
33156ca9db8SPaul Cercueil 				gain = false;
33256ca9db8SPaul Cercueil 			else if (val == st->scale_avail[1][0] &&
33356ca9db8SPaul Cercueil 				 val2 == st->scale_avail[1][1])
33456ca9db8SPaul Cercueil 				gain = true;
33556ca9db8SPaul Cercueil 			else
33656ca9db8SPaul Cercueil 				return -EINVAL;
33756ca9db8SPaul Cercueil 
33856ca9db8SPaul Cercueil 			mutex_lock(&iio_dev->mlock);
33956ca9db8SPaul Cercueil 
34056ca9db8SPaul Cercueil 			ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
34156ca9db8SPaul Cercueil 						&st->cached_gp_ctrl);
34256ca9db8SPaul Cercueil 			if (ret < 0) {
34356ca9db8SPaul Cercueil 				mutex_unlock(&iio_dev->mlock);
34456ca9db8SPaul Cercueil 				return ret;
34556ca9db8SPaul Cercueil 			}
34656ca9db8SPaul Cercueil 
34756ca9db8SPaul Cercueil 			if (chan->output) {
34856ca9db8SPaul Cercueil 				if (gain)
34956ca9db8SPaul Cercueil 					st->cached_gp_ctrl |=
35056ca9db8SPaul Cercueil 						AD5592R_REG_CTRL_DAC_RANGE;
35156ca9db8SPaul Cercueil 				else
35256ca9db8SPaul Cercueil 					st->cached_gp_ctrl &=
35356ca9db8SPaul Cercueil 						~AD5592R_REG_CTRL_DAC_RANGE;
35456ca9db8SPaul Cercueil 			} else {
35556ca9db8SPaul Cercueil 				if (gain)
35656ca9db8SPaul Cercueil 					st->cached_gp_ctrl |=
35756ca9db8SPaul Cercueil 						AD5592R_REG_CTRL_ADC_RANGE;
35856ca9db8SPaul Cercueil 				else
35956ca9db8SPaul Cercueil 					st->cached_gp_ctrl &=
36056ca9db8SPaul Cercueil 						~AD5592R_REG_CTRL_ADC_RANGE;
36156ca9db8SPaul Cercueil 			}
36256ca9db8SPaul Cercueil 
36356ca9db8SPaul Cercueil 			ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
36456ca9db8SPaul Cercueil 						 st->cached_gp_ctrl);
36556ca9db8SPaul Cercueil 			mutex_unlock(&iio_dev->mlock);
36656ca9db8SPaul Cercueil 
36756ca9db8SPaul Cercueil 			return ret;
36856ca9db8SPaul Cercueil 		}
36956ca9db8SPaul Cercueil 		break;
37056ca9db8SPaul Cercueil 	default:
37156ca9db8SPaul Cercueil 		return -EINVAL;
37256ca9db8SPaul Cercueil 	}
37356ca9db8SPaul Cercueil 
37456ca9db8SPaul Cercueil 	return 0;
37556ca9db8SPaul Cercueil }
37656ca9db8SPaul Cercueil 
37756ca9db8SPaul Cercueil static int ad5592r_read_raw(struct iio_dev *iio_dev,
37856ca9db8SPaul Cercueil 			   struct iio_chan_spec const *chan,
37956ca9db8SPaul Cercueil 			   int *val, int *val2, long m)
38056ca9db8SPaul Cercueil {
38156ca9db8SPaul Cercueil 	struct ad5592r_state *st = iio_priv(iio_dev);
38256ca9db8SPaul Cercueil 	u16 read_val;
38356ca9db8SPaul Cercueil 	int ret;
38456ca9db8SPaul Cercueil 
38556ca9db8SPaul Cercueil 	switch (m) {
38656ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_RAW:
38756ca9db8SPaul Cercueil 		mutex_lock(&iio_dev->mlock);
38856ca9db8SPaul Cercueil 
38956ca9db8SPaul Cercueil 		if (!chan->output) {
39056ca9db8SPaul Cercueil 			ret = st->ops->read_adc(st, chan->channel, &read_val);
39156ca9db8SPaul Cercueil 			if (ret)
39256ca9db8SPaul Cercueil 				goto unlock;
39356ca9db8SPaul Cercueil 
39456ca9db8SPaul Cercueil 			if ((read_val >> 12 & 0x7) != (chan->channel & 0x7)) {
39556ca9db8SPaul Cercueil 				dev_err(st->dev, "Error while reading channel %u\n",
39656ca9db8SPaul Cercueil 						chan->channel);
39756ca9db8SPaul Cercueil 				ret = -EIO;
39856ca9db8SPaul Cercueil 				goto unlock;
39956ca9db8SPaul Cercueil 			}
40056ca9db8SPaul Cercueil 
40156ca9db8SPaul Cercueil 			read_val &= GENMASK(11, 0);
40256ca9db8SPaul Cercueil 
40356ca9db8SPaul Cercueil 		} else {
40456ca9db8SPaul Cercueil 			read_val = st->cached_dac[chan->channel];
40556ca9db8SPaul Cercueil 		}
40656ca9db8SPaul Cercueil 
40756ca9db8SPaul Cercueil 		dev_dbg(st->dev, "Channel %u read: 0x%04hX\n",
40856ca9db8SPaul Cercueil 				chan->channel, read_val);
40956ca9db8SPaul Cercueil 
41056ca9db8SPaul Cercueil 		*val = (int) read_val;
41156ca9db8SPaul Cercueil 		ret = IIO_VAL_INT;
41256ca9db8SPaul Cercueil 		break;
41356ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_SCALE:
41456ca9db8SPaul Cercueil 		*val = ad5592r_get_vref(st);
41556ca9db8SPaul Cercueil 
41656ca9db8SPaul Cercueil 		if (chan->type == IIO_TEMP) {
41756ca9db8SPaul Cercueil 			s64 tmp = *val * (3767897513LL / 25LL);
41856ca9db8SPaul Cercueil 			*val = div_s64_rem(tmp, 1000000000LL, val2);
41956ca9db8SPaul Cercueil 
42056ca9db8SPaul Cercueil 			ret = IIO_VAL_INT_PLUS_MICRO;
42156ca9db8SPaul Cercueil 		} else {
42256ca9db8SPaul Cercueil 			int mult;
42356ca9db8SPaul Cercueil 
42456ca9db8SPaul Cercueil 			mutex_lock(&iio_dev->mlock);
42556ca9db8SPaul Cercueil 
42656ca9db8SPaul Cercueil 			if (chan->output)
42756ca9db8SPaul Cercueil 				mult = !!(st->cached_gp_ctrl &
42856ca9db8SPaul Cercueil 					AD5592R_REG_CTRL_DAC_RANGE);
42956ca9db8SPaul Cercueil 			else
43056ca9db8SPaul Cercueil 				mult = !!(st->cached_gp_ctrl &
43156ca9db8SPaul Cercueil 					AD5592R_REG_CTRL_ADC_RANGE);
43256ca9db8SPaul Cercueil 
43356ca9db8SPaul Cercueil 			*val *= ++mult;
43456ca9db8SPaul Cercueil 
43556ca9db8SPaul Cercueil 			*val2 = chan->scan_type.realbits;
43656ca9db8SPaul Cercueil 			ret = IIO_VAL_FRACTIONAL_LOG2;
43756ca9db8SPaul Cercueil 		}
43856ca9db8SPaul Cercueil 		break;
43956ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_OFFSET:
44056ca9db8SPaul Cercueil 		ret = ad5592r_get_vref(st);
44156ca9db8SPaul Cercueil 
44256ca9db8SPaul Cercueil 		mutex_lock(&iio_dev->mlock);
44356ca9db8SPaul Cercueil 
44456ca9db8SPaul Cercueil 		if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
44556ca9db8SPaul Cercueil 			*val = (-34365 * 25) / ret;
44656ca9db8SPaul Cercueil 		else
44756ca9db8SPaul Cercueil 			*val = (-75365 * 25) / ret;
44856ca9db8SPaul Cercueil 		ret =  IIO_VAL_INT;
44956ca9db8SPaul Cercueil 		break;
45056ca9db8SPaul Cercueil 	default:
45156ca9db8SPaul Cercueil 		ret = -EINVAL;
45256ca9db8SPaul Cercueil 	}
45356ca9db8SPaul Cercueil 
45456ca9db8SPaul Cercueil unlock:
45556ca9db8SPaul Cercueil 	mutex_unlock(&iio_dev->mlock);
45656ca9db8SPaul Cercueil 	return ret;
45756ca9db8SPaul Cercueil }
45856ca9db8SPaul Cercueil 
45956ca9db8SPaul Cercueil static int ad5592r_write_raw_get_fmt(struct iio_dev *indio_dev,
46056ca9db8SPaul Cercueil 				 struct iio_chan_spec const *chan, long mask)
46156ca9db8SPaul Cercueil {
46256ca9db8SPaul Cercueil 	switch (mask) {
46356ca9db8SPaul Cercueil 	case IIO_CHAN_INFO_SCALE:
46456ca9db8SPaul Cercueil 		return IIO_VAL_INT_PLUS_NANO;
46556ca9db8SPaul Cercueil 
46656ca9db8SPaul Cercueil 	default:
46756ca9db8SPaul Cercueil 		return IIO_VAL_INT_PLUS_MICRO;
46856ca9db8SPaul Cercueil 	}
46956ca9db8SPaul Cercueil 
47056ca9db8SPaul Cercueil 	return -EINVAL;
47156ca9db8SPaul Cercueil }
47256ca9db8SPaul Cercueil 
47356ca9db8SPaul Cercueil static const struct iio_info ad5592r_info = {
47456ca9db8SPaul Cercueil 	.read_raw = ad5592r_read_raw,
47556ca9db8SPaul Cercueil 	.write_raw = ad5592r_write_raw,
47656ca9db8SPaul Cercueil 	.write_raw_get_fmt = ad5592r_write_raw_get_fmt,
47756ca9db8SPaul Cercueil 	.driver_module = THIS_MODULE,
47856ca9db8SPaul Cercueil };
47956ca9db8SPaul Cercueil 
48056ca9db8SPaul Cercueil static ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev,
48156ca9db8SPaul Cercueil 					   uintptr_t private,
48256ca9db8SPaul Cercueil 					   const struct iio_chan_spec *chan,
48356ca9db8SPaul Cercueil 					   char *buf)
48456ca9db8SPaul Cercueil {
48556ca9db8SPaul Cercueil 	struct ad5592r_state *st = iio_priv(iio_dev);
48656ca9db8SPaul Cercueil 
48756ca9db8SPaul Cercueil 	return sprintf(buf, "%d.%09u %d.%09u\n",
48856ca9db8SPaul Cercueil 		st->scale_avail[0][0], st->scale_avail[0][1],
48956ca9db8SPaul Cercueil 		st->scale_avail[1][0], st->scale_avail[1][1]);
49056ca9db8SPaul Cercueil }
49156ca9db8SPaul Cercueil 
49256ca9db8SPaul Cercueil static struct iio_chan_spec_ext_info ad5592r_ext_info[] = {
49356ca9db8SPaul Cercueil 	{
49456ca9db8SPaul Cercueil 	 .name = "scale_available",
49556ca9db8SPaul Cercueil 	 .read = ad5592r_show_scale_available,
49656ca9db8SPaul Cercueil 	 .shared = true,
49756ca9db8SPaul Cercueil 	 },
49856ca9db8SPaul Cercueil 	{},
49956ca9db8SPaul Cercueil };
50056ca9db8SPaul Cercueil 
50156ca9db8SPaul Cercueil static void ad5592r_setup_channel(struct iio_dev *iio_dev,
50256ca9db8SPaul Cercueil 		struct iio_chan_spec *chan, bool output, unsigned id)
50356ca9db8SPaul Cercueil {
50456ca9db8SPaul Cercueil 	chan->type = IIO_VOLTAGE;
50556ca9db8SPaul Cercueil 	chan->indexed = 1;
50656ca9db8SPaul Cercueil 	chan->output = output;
50756ca9db8SPaul Cercueil 	chan->channel = id;
50856ca9db8SPaul Cercueil 	chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
50956ca9db8SPaul Cercueil 	chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
51056ca9db8SPaul Cercueil 	chan->scan_type.sign = 'u';
51156ca9db8SPaul Cercueil 	chan->scan_type.realbits = 12;
51256ca9db8SPaul Cercueil 	chan->scan_type.storagebits = 16;
51356ca9db8SPaul Cercueil 	chan->ext_info = ad5592r_ext_info;
51456ca9db8SPaul Cercueil }
51556ca9db8SPaul Cercueil 
51656ca9db8SPaul Cercueil static int ad5592r_alloc_channels(struct ad5592r_state *st)
51756ca9db8SPaul Cercueil {
51856ca9db8SPaul Cercueil 	unsigned i, curr_channel = 0,
51956ca9db8SPaul Cercueil 		 num_channels = st->num_channels;
52056ca9db8SPaul Cercueil 	struct iio_dev *iio_dev = iio_priv_to_dev(st);
52156ca9db8SPaul Cercueil 	struct iio_chan_spec *channels;
52256ca9db8SPaul Cercueil 	struct fwnode_handle *child;
52356ca9db8SPaul Cercueil 	u32 reg, tmp;
52456ca9db8SPaul Cercueil 	int ret;
52556ca9db8SPaul Cercueil 
52656ca9db8SPaul Cercueil 	device_for_each_child_node(st->dev, child) {
52756ca9db8SPaul Cercueil 		ret = fwnode_property_read_u32(child, "reg", &reg);
52856ca9db8SPaul Cercueil 		if (ret || reg > ARRAY_SIZE(st->channel_modes))
52956ca9db8SPaul Cercueil 			continue;
53056ca9db8SPaul Cercueil 
53156ca9db8SPaul Cercueil 		ret = fwnode_property_read_u32(child, "adi,mode", &tmp);
53256ca9db8SPaul Cercueil 		if (!ret)
53356ca9db8SPaul Cercueil 			st->channel_modes[reg] = tmp;
53456ca9db8SPaul Cercueil 
53556ca9db8SPaul Cercueil 		fwnode_property_read_u32(child, "adi,off-state", &tmp);
53656ca9db8SPaul Cercueil 		if (!ret)
53756ca9db8SPaul Cercueil 			st->channel_offstate[reg] = tmp;
53856ca9db8SPaul Cercueil 	}
53956ca9db8SPaul Cercueil 
54056ca9db8SPaul Cercueil 	channels = devm_kzalloc(st->dev,
54156ca9db8SPaul Cercueil 			(1 + 2 * num_channels) * sizeof(*channels), GFP_KERNEL);
54256ca9db8SPaul Cercueil 	if (!channels)
54356ca9db8SPaul Cercueil 		return -ENOMEM;
54456ca9db8SPaul Cercueil 
54556ca9db8SPaul Cercueil 	for (i = 0; i < num_channels; i++) {
54656ca9db8SPaul Cercueil 		switch (st->channel_modes[i]) {
54756ca9db8SPaul Cercueil 		case CH_MODE_DAC:
54856ca9db8SPaul Cercueil 			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
54956ca9db8SPaul Cercueil 					true, i);
55056ca9db8SPaul Cercueil 			curr_channel++;
55156ca9db8SPaul Cercueil 			break;
55256ca9db8SPaul Cercueil 
55356ca9db8SPaul Cercueil 		case CH_MODE_ADC:
55456ca9db8SPaul Cercueil 			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
55556ca9db8SPaul Cercueil 					false, i);
55656ca9db8SPaul Cercueil 			curr_channel++;
55756ca9db8SPaul Cercueil 			break;
55856ca9db8SPaul Cercueil 
55956ca9db8SPaul Cercueil 		case CH_MODE_DAC_AND_ADC:
56056ca9db8SPaul Cercueil 			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
56156ca9db8SPaul Cercueil 					true, i);
56256ca9db8SPaul Cercueil 			curr_channel++;
56356ca9db8SPaul Cercueil 			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
56456ca9db8SPaul Cercueil 					false, i);
56556ca9db8SPaul Cercueil 			curr_channel++;
56656ca9db8SPaul Cercueil 			break;
56756ca9db8SPaul Cercueil 
56856ca9db8SPaul Cercueil 		default:
56956ca9db8SPaul Cercueil 			continue;
57056ca9db8SPaul Cercueil 		}
57156ca9db8SPaul Cercueil 	}
57256ca9db8SPaul Cercueil 
57356ca9db8SPaul Cercueil 	channels[curr_channel].type = IIO_TEMP;
57456ca9db8SPaul Cercueil 	channels[curr_channel].channel = 8;
57556ca9db8SPaul Cercueil 	channels[curr_channel].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
57656ca9db8SPaul Cercueil 				   BIT(IIO_CHAN_INFO_SCALE) |
57756ca9db8SPaul Cercueil 				   BIT(IIO_CHAN_INFO_OFFSET);
57856ca9db8SPaul Cercueil 	curr_channel++;
57956ca9db8SPaul Cercueil 
58056ca9db8SPaul Cercueil 	iio_dev->num_channels = curr_channel;
58156ca9db8SPaul Cercueil 	iio_dev->channels = channels;
58256ca9db8SPaul Cercueil 
58356ca9db8SPaul Cercueil 	return 0;
58456ca9db8SPaul Cercueil }
58556ca9db8SPaul Cercueil 
58656ca9db8SPaul Cercueil static void ad5592r_init_scales(struct ad5592r_state *st, int vref_mV)
58756ca9db8SPaul Cercueil {
58856ca9db8SPaul Cercueil 	s64 tmp = (s64)vref_mV * 1000000000LL >> 12;
58956ca9db8SPaul Cercueil 
59056ca9db8SPaul Cercueil 	st->scale_avail[0][0] =
59156ca9db8SPaul Cercueil 		div_s64_rem(tmp, 1000000000LL, &st->scale_avail[0][1]);
59256ca9db8SPaul Cercueil 	st->scale_avail[1][0] =
59356ca9db8SPaul Cercueil 		div_s64_rem(tmp * 2, 1000000000LL, &st->scale_avail[1][1]);
59456ca9db8SPaul Cercueil }
59556ca9db8SPaul Cercueil 
59656ca9db8SPaul Cercueil int ad5592r_probe(struct device *dev, const char *name,
59756ca9db8SPaul Cercueil 		const struct ad5592r_rw_ops *ops)
59856ca9db8SPaul Cercueil {
59956ca9db8SPaul Cercueil 	struct iio_dev *iio_dev;
60056ca9db8SPaul Cercueil 	struct ad5592r_state *st;
60156ca9db8SPaul Cercueil 	int ret;
60256ca9db8SPaul Cercueil 
60356ca9db8SPaul Cercueil 	iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
60456ca9db8SPaul Cercueil 	if (!iio_dev)
60556ca9db8SPaul Cercueil 		return -ENOMEM;
60656ca9db8SPaul Cercueil 
60756ca9db8SPaul Cercueil 	st = iio_priv(iio_dev);
60856ca9db8SPaul Cercueil 	st->dev = dev;
60956ca9db8SPaul Cercueil 	st->ops = ops;
61056ca9db8SPaul Cercueil 	st->num_channels = 8;
61156ca9db8SPaul Cercueil 	dev_set_drvdata(dev, iio_dev);
61256ca9db8SPaul Cercueil 
61356ca9db8SPaul Cercueil 	st->reg = devm_regulator_get_optional(dev, "vref");
61456ca9db8SPaul Cercueil 	if (IS_ERR(st->reg)) {
61556ca9db8SPaul Cercueil 		if ((PTR_ERR(st->reg) != -ENODEV) && dev->of_node)
61656ca9db8SPaul Cercueil 			return PTR_ERR(st->reg);
61756ca9db8SPaul Cercueil 
61856ca9db8SPaul Cercueil 		st->reg = NULL;
61956ca9db8SPaul Cercueil 	} else {
62056ca9db8SPaul Cercueil 		ret = regulator_enable(st->reg);
62156ca9db8SPaul Cercueil 		if (ret)
62256ca9db8SPaul Cercueil 			return ret;
62356ca9db8SPaul Cercueil 	}
62456ca9db8SPaul Cercueil 
62556ca9db8SPaul Cercueil 	iio_dev->dev.parent = dev;
62656ca9db8SPaul Cercueil 	iio_dev->name = name;
62756ca9db8SPaul Cercueil 	iio_dev->info = &ad5592r_info;
62856ca9db8SPaul Cercueil 	iio_dev->modes = INDIO_DIRECT_MODE;
62956ca9db8SPaul Cercueil 
63056ca9db8SPaul Cercueil 	ad5592r_init_scales(st, ad5592r_get_vref(st));
63156ca9db8SPaul Cercueil 
63256ca9db8SPaul Cercueil 	ret = ad5592r_reset(st);
63356ca9db8SPaul Cercueil 	if (ret)
63456ca9db8SPaul Cercueil 		goto error_disable_reg;
63556ca9db8SPaul Cercueil 
63656ca9db8SPaul Cercueil 	ret = ops->reg_write(st, AD5592R_REG_PD,
63756ca9db8SPaul Cercueil 		     (st->reg == NULL) ? AD5592R_REG_PD_EN_REF : 0);
63856ca9db8SPaul Cercueil 	if (ret)
63956ca9db8SPaul Cercueil 		goto error_disable_reg;
64056ca9db8SPaul Cercueil 
64156ca9db8SPaul Cercueil 	ret = ad5592r_alloc_channels(st);
64256ca9db8SPaul Cercueil 	if (ret)
64356ca9db8SPaul Cercueil 		goto error_disable_reg;
64456ca9db8SPaul Cercueil 
64556ca9db8SPaul Cercueil 	ret = ad5592r_set_channel_modes(st);
64656ca9db8SPaul Cercueil 	if (ret)
64756ca9db8SPaul Cercueil 		goto error_reset_ch_modes;
64856ca9db8SPaul Cercueil 
64956ca9db8SPaul Cercueil 	ret = iio_device_register(iio_dev);
65056ca9db8SPaul Cercueil 	if (ret)
65156ca9db8SPaul Cercueil 		goto error_reset_ch_modes;
65256ca9db8SPaul Cercueil 
65356ca9db8SPaul Cercueil 	ret = ad5592r_gpio_init(st);
65456ca9db8SPaul Cercueil 	if (ret)
65556ca9db8SPaul Cercueil 		goto error_dev_unregister;
65656ca9db8SPaul Cercueil 
65756ca9db8SPaul Cercueil 	return 0;
65856ca9db8SPaul Cercueil 
65956ca9db8SPaul Cercueil error_dev_unregister:
66056ca9db8SPaul Cercueil 	iio_device_unregister(iio_dev);
66156ca9db8SPaul Cercueil 
66256ca9db8SPaul Cercueil error_reset_ch_modes:
66356ca9db8SPaul Cercueil 	ad5592r_reset_channel_modes(st);
66456ca9db8SPaul Cercueil 
66556ca9db8SPaul Cercueil error_disable_reg:
66656ca9db8SPaul Cercueil 	if (st->reg)
66756ca9db8SPaul Cercueil 		regulator_disable(st->reg);
66856ca9db8SPaul Cercueil 
66956ca9db8SPaul Cercueil 	return ret;
67056ca9db8SPaul Cercueil }
67156ca9db8SPaul Cercueil EXPORT_SYMBOL_GPL(ad5592r_probe);
67256ca9db8SPaul Cercueil 
67356ca9db8SPaul Cercueil int ad5592r_remove(struct device *dev)
67456ca9db8SPaul Cercueil {
67556ca9db8SPaul Cercueil 	struct iio_dev *iio_dev = dev_get_drvdata(dev);
67656ca9db8SPaul Cercueil 	struct ad5592r_state *st = iio_priv(iio_dev);
67756ca9db8SPaul Cercueil 
67856ca9db8SPaul Cercueil 	iio_device_unregister(iio_dev);
67956ca9db8SPaul Cercueil 	ad5592r_reset_channel_modes(st);
68056ca9db8SPaul Cercueil 	ad5592r_gpio_cleanup(st);
68156ca9db8SPaul Cercueil 
68256ca9db8SPaul Cercueil 	if (st->reg)
68356ca9db8SPaul Cercueil 		regulator_disable(st->reg);
68456ca9db8SPaul Cercueil 
68556ca9db8SPaul Cercueil 	return 0;
68656ca9db8SPaul Cercueil }
68756ca9db8SPaul Cercueil EXPORT_SYMBOL_GPL(ad5592r_remove);
68856ca9db8SPaul Cercueil 
68956ca9db8SPaul Cercueil MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
69056ca9db8SPaul Cercueil MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
69156ca9db8SPaul Cercueil MODULE_LICENSE("GPL v2");
692