162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADMV1013 driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2021 Analog Devices Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci#include <linux/bits.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/iio/iio.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1562306a36Sopenharmony_ci#include <linux/notifier.h>
1662306a36Sopenharmony_ci#include <linux/property.h>
1762306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1862306a36Sopenharmony_ci#include <linux/spi/spi.h>
1962306a36Sopenharmony_ci#include <linux/units.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <asm/unaligned.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* ADMV1013 Register Map */
2462306a36Sopenharmony_ci#define ADMV1013_REG_SPI_CONTROL		0x00
2562306a36Sopenharmony_ci#define ADMV1013_REG_ALARM			0x01
2662306a36Sopenharmony_ci#define ADMV1013_REG_ALARM_MASKS		0x02
2762306a36Sopenharmony_ci#define ADMV1013_REG_ENABLE			0x03
2862306a36Sopenharmony_ci#define ADMV1013_REG_LO_AMP_I			0x05
2962306a36Sopenharmony_ci#define ADMV1013_REG_LO_AMP_Q			0x06
3062306a36Sopenharmony_ci#define ADMV1013_REG_OFFSET_ADJUST_I		0x07
3162306a36Sopenharmony_ci#define ADMV1013_REG_OFFSET_ADJUST_Q		0x08
3262306a36Sopenharmony_ci#define ADMV1013_REG_QUAD			0x09
3362306a36Sopenharmony_ci#define ADMV1013_REG_VVA_TEMP_COMP		0x0A
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* ADMV1013_REG_SPI_CONTROL Map */
3662306a36Sopenharmony_ci#define ADMV1013_PARITY_EN_MSK			BIT(15)
3762306a36Sopenharmony_ci#define ADMV1013_SPI_SOFT_RESET_MSK		BIT(14)
3862306a36Sopenharmony_ci#define ADMV1013_CHIP_ID_MSK			GENMASK(11, 4)
3962306a36Sopenharmony_ci#define ADMV1013_CHIP_ID			0xA
4062306a36Sopenharmony_ci#define ADMV1013_REVISION_ID_MSK		GENMASK(3, 0)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* ADMV1013_REG_ALARM Map */
4362306a36Sopenharmony_ci#define ADMV1013_PARITY_ERROR_MSK		BIT(15)
4462306a36Sopenharmony_ci#define ADMV1013_TOO_FEW_ERRORS_MSK		BIT(14)
4562306a36Sopenharmony_ci#define ADMV1013_TOO_MANY_ERRORS_MSK		BIT(13)
4662306a36Sopenharmony_ci#define ADMV1013_ADDRESS_RANGE_ERROR_MSK	BIT(12)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* ADMV1013_REG_ENABLE Map */
4962306a36Sopenharmony_ci#define ADMV1013_VGA_PD_MSK			BIT(15)
5062306a36Sopenharmony_ci#define ADMV1013_MIXER_PD_MSK			BIT(14)
5162306a36Sopenharmony_ci#define ADMV1013_QUAD_PD_MSK			GENMASK(13, 11)
5262306a36Sopenharmony_ci#define ADMV1013_BG_PD_MSK			BIT(10)
5362306a36Sopenharmony_ci#define ADMV1013_MIXER_IF_EN_MSK		BIT(7)
5462306a36Sopenharmony_ci#define ADMV1013_DET_EN_MSK			BIT(5)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* ADMV1013_REG_LO_AMP Map */
5762306a36Sopenharmony_ci#define ADMV1013_LOAMP_PH_ADJ_FINE_MSK		GENMASK(13, 7)
5862306a36Sopenharmony_ci#define ADMV1013_MIXER_VGATE_MSK		GENMASK(6, 0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* ADMV1013_REG_OFFSET_ADJUST Map */
6162306a36Sopenharmony_ci#define ADMV1013_MIXER_OFF_ADJ_P_MSK		GENMASK(15, 9)
6262306a36Sopenharmony_ci#define ADMV1013_MIXER_OFF_ADJ_N_MSK		GENMASK(8, 2)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* ADMV1013_REG_QUAD Map */
6562306a36Sopenharmony_ci#define ADMV1013_QUAD_SE_MODE_MSK		GENMASK(9, 6)
6662306a36Sopenharmony_ci#define ADMV1013_QUAD_FILTERS_MSK		GENMASK(3, 0)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* ADMV1013_REG_VVA_TEMP_COMP Map */
6962306a36Sopenharmony_ci#define ADMV1013_VVA_TEMP_COMP_MSK		GENMASK(15, 0)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* ADMV1013 Miscellaneous Defines */
7262306a36Sopenharmony_ci#define ADMV1013_READ				BIT(7)
7362306a36Sopenharmony_ci#define ADMV1013_REG_ADDR_READ_MSK		GENMASK(6, 1)
7462306a36Sopenharmony_ci#define ADMV1013_REG_ADDR_WRITE_MSK		GENMASK(22, 17)
7562306a36Sopenharmony_ci#define ADMV1013_REG_DATA_MSK			GENMASK(16, 1)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cienum {
7862306a36Sopenharmony_ci	ADMV1013_IQ_MODE,
7962306a36Sopenharmony_ci	ADMV1013_IF_MODE
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cienum {
8362306a36Sopenharmony_ci	ADMV1013_RFMOD_I_CALIBPHASE,
8462306a36Sopenharmony_ci	ADMV1013_RFMOD_Q_CALIBPHASE,
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cienum {
8862306a36Sopenharmony_ci	ADMV1013_SE_MODE_POS = 6,
8962306a36Sopenharmony_ci	ADMV1013_SE_MODE_NEG = 9,
9062306a36Sopenharmony_ci	ADMV1013_SE_MODE_DIFF = 12
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistruct admv1013_state {
9462306a36Sopenharmony_ci	struct spi_device	*spi;
9562306a36Sopenharmony_ci	struct clk		*clkin;
9662306a36Sopenharmony_ci	/* Protect against concurrent accesses to the device and to data */
9762306a36Sopenharmony_ci	struct mutex		lock;
9862306a36Sopenharmony_ci	struct regulator	*reg;
9962306a36Sopenharmony_ci	struct notifier_block	nb;
10062306a36Sopenharmony_ci	unsigned int		input_mode;
10162306a36Sopenharmony_ci	unsigned int		quad_se_mode;
10262306a36Sopenharmony_ci	bool			det_en;
10362306a36Sopenharmony_ci	u8			data[3] __aligned(IIO_DMA_MINALIGN);
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int __admv1013_spi_read(struct admv1013_state *st, unsigned int reg,
10762306a36Sopenharmony_ci			       unsigned int *val)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int ret;
11062306a36Sopenharmony_ci	struct spi_transfer t = {0};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	st->data[0] = ADMV1013_READ | FIELD_PREP(ADMV1013_REG_ADDR_READ_MSK, reg);
11362306a36Sopenharmony_ci	st->data[1] = 0x0;
11462306a36Sopenharmony_ci	st->data[2] = 0x0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	t.rx_buf = &st->data[0];
11762306a36Sopenharmony_ci	t.tx_buf = &st->data[0];
11862306a36Sopenharmony_ci	t.len = 3;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ret = spi_sync_transfer(st->spi, &t, 1);
12162306a36Sopenharmony_ci	if (ret)
12262306a36Sopenharmony_ci		return ret;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	*val = FIELD_GET(ADMV1013_REG_DATA_MSK, get_unaligned_be24(&st->data[0]));
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return ret;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int admv1013_spi_read(struct admv1013_state *st, unsigned int reg,
13062306a36Sopenharmony_ci			     unsigned int *val)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_lock(&st->lock);
13562306a36Sopenharmony_ci	ret = __admv1013_spi_read(st, reg, val);
13662306a36Sopenharmony_ci	mutex_unlock(&st->lock);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return ret;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int __admv1013_spi_write(struct admv1013_state *st,
14262306a36Sopenharmony_ci				unsigned int reg,
14362306a36Sopenharmony_ci				unsigned int val)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	put_unaligned_be24(FIELD_PREP(ADMV1013_REG_DATA_MSK, val) |
14662306a36Sopenharmony_ci			   FIELD_PREP(ADMV1013_REG_ADDR_WRITE_MSK, reg), &st->data[0]);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return spi_write(st->spi, &st->data[0], 3);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int admv1013_spi_write(struct admv1013_state *st, unsigned int reg,
15262306a36Sopenharmony_ci			      unsigned int val)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	mutex_lock(&st->lock);
15762306a36Sopenharmony_ci	ret = __admv1013_spi_write(st, reg, val);
15862306a36Sopenharmony_ci	mutex_unlock(&st->lock);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return ret;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int __admv1013_spi_update_bits(struct admv1013_state *st, unsigned int reg,
16462306a36Sopenharmony_ci				      unsigned int mask, unsigned int val)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int ret;
16762306a36Sopenharmony_ci	unsigned int data, temp;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	ret = __admv1013_spi_read(st, reg, &data);
17062306a36Sopenharmony_ci	if (ret)
17162306a36Sopenharmony_ci		return ret;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	temp = (data & ~mask) | (val & mask);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return __admv1013_spi_write(st, reg, temp);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int admv1013_spi_update_bits(struct admv1013_state *st, unsigned int reg,
17962306a36Sopenharmony_ci				    unsigned int mask, unsigned int val)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	int ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	mutex_lock(&st->lock);
18462306a36Sopenharmony_ci	ret = __admv1013_spi_update_bits(st, reg, mask, val);
18562306a36Sopenharmony_ci	mutex_unlock(&st->lock);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return ret;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int admv1013_read_raw(struct iio_dev *indio_dev,
19162306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
19262306a36Sopenharmony_ci			     int *val, int *val2, long info)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct admv1013_state *st = iio_priv(indio_dev);
19562306a36Sopenharmony_ci	unsigned int data, addr;
19662306a36Sopenharmony_ci	int ret;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	switch (info) {
19962306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
20062306a36Sopenharmony_ci		switch (chan->channel) {
20162306a36Sopenharmony_ci		case IIO_MOD_I:
20262306a36Sopenharmony_ci			addr = ADMV1013_REG_OFFSET_ADJUST_I;
20362306a36Sopenharmony_ci			break;
20462306a36Sopenharmony_ci		case IIO_MOD_Q:
20562306a36Sopenharmony_ci			addr = ADMV1013_REG_OFFSET_ADJUST_Q;
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		default:
20862306a36Sopenharmony_ci			return -EINVAL;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		ret = admv1013_spi_read(st, addr, &data);
21262306a36Sopenharmony_ci		if (ret)
21362306a36Sopenharmony_ci			return ret;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		if (!chan->channel)
21662306a36Sopenharmony_ci			*val = FIELD_GET(ADMV1013_MIXER_OFF_ADJ_P_MSK, data);
21762306a36Sopenharmony_ci		else
21862306a36Sopenharmony_ci			*val = FIELD_GET(ADMV1013_MIXER_OFF_ADJ_N_MSK, data);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		return IIO_VAL_INT;
22162306a36Sopenharmony_ci	default:
22262306a36Sopenharmony_ci		return -EINVAL;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int admv1013_write_raw(struct iio_dev *indio_dev,
22762306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
22862306a36Sopenharmony_ci			      int val, int val2, long info)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct admv1013_state *st = iio_priv(indio_dev);
23162306a36Sopenharmony_ci	unsigned int addr, data, msk;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	switch (info) {
23462306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
23562306a36Sopenharmony_ci		switch (chan->channel2) {
23662306a36Sopenharmony_ci		case IIO_MOD_I:
23762306a36Sopenharmony_ci			addr = ADMV1013_REG_OFFSET_ADJUST_I;
23862306a36Sopenharmony_ci			break;
23962306a36Sopenharmony_ci		case IIO_MOD_Q:
24062306a36Sopenharmony_ci			addr = ADMV1013_REG_OFFSET_ADJUST_Q;
24162306a36Sopenharmony_ci			break;
24262306a36Sopenharmony_ci		default:
24362306a36Sopenharmony_ci			return -EINVAL;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		if (!chan->channel) {
24762306a36Sopenharmony_ci			msk = ADMV1013_MIXER_OFF_ADJ_P_MSK;
24862306a36Sopenharmony_ci			data = FIELD_PREP(ADMV1013_MIXER_OFF_ADJ_P_MSK, val);
24962306a36Sopenharmony_ci		} else {
25062306a36Sopenharmony_ci			msk = ADMV1013_MIXER_OFF_ADJ_N_MSK;
25162306a36Sopenharmony_ci			data = FIELD_PREP(ADMV1013_MIXER_OFF_ADJ_N_MSK, val);
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		return admv1013_spi_update_bits(st, addr, msk, data);
25562306a36Sopenharmony_ci	default:
25662306a36Sopenharmony_ci		return -EINVAL;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic ssize_t admv1013_read(struct iio_dev *indio_dev,
26162306a36Sopenharmony_ci			     uintptr_t private,
26262306a36Sopenharmony_ci			     const struct iio_chan_spec *chan,
26362306a36Sopenharmony_ci			     char *buf)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct admv1013_state *st = iio_priv(indio_dev);
26662306a36Sopenharmony_ci	unsigned int data, addr;
26762306a36Sopenharmony_ci	int ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	switch ((u32)private) {
27062306a36Sopenharmony_ci	case ADMV1013_RFMOD_I_CALIBPHASE:
27162306a36Sopenharmony_ci		addr = ADMV1013_REG_LO_AMP_I;
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case ADMV1013_RFMOD_Q_CALIBPHASE:
27462306a36Sopenharmony_ci		addr = ADMV1013_REG_LO_AMP_Q;
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	default:
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = admv1013_spi_read(st, addr, &data);
28162306a36Sopenharmony_ci	if (ret)
28262306a36Sopenharmony_ci		return ret;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	data = FIELD_GET(ADMV1013_LOAMP_PH_ADJ_FINE_MSK, data);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", data);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic ssize_t admv1013_write(struct iio_dev *indio_dev,
29062306a36Sopenharmony_ci			      uintptr_t private,
29162306a36Sopenharmony_ci			      const struct iio_chan_spec *chan,
29262306a36Sopenharmony_ci			      const char *buf, size_t len)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct admv1013_state *st = iio_priv(indio_dev);
29562306a36Sopenharmony_ci	unsigned int data;
29662306a36Sopenharmony_ci	int ret;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ret = kstrtou32(buf, 10, &data);
29962306a36Sopenharmony_ci	if (ret)
30062306a36Sopenharmony_ci		return ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	data = FIELD_PREP(ADMV1013_LOAMP_PH_ADJ_FINE_MSK, data);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	switch ((u32)private) {
30562306a36Sopenharmony_ci	case ADMV1013_RFMOD_I_CALIBPHASE:
30662306a36Sopenharmony_ci		ret = admv1013_spi_update_bits(st, ADMV1013_REG_LO_AMP_I,
30762306a36Sopenharmony_ci					       ADMV1013_LOAMP_PH_ADJ_FINE_MSK,
30862306a36Sopenharmony_ci					       data);
30962306a36Sopenharmony_ci		if (ret)
31062306a36Sopenharmony_ci			return ret;
31162306a36Sopenharmony_ci		break;
31262306a36Sopenharmony_ci	case ADMV1013_RFMOD_Q_CALIBPHASE:
31362306a36Sopenharmony_ci		ret = admv1013_spi_update_bits(st, ADMV1013_REG_LO_AMP_Q,
31462306a36Sopenharmony_ci					       ADMV1013_LOAMP_PH_ADJ_FINE_MSK,
31562306a36Sopenharmony_ci					       data);
31662306a36Sopenharmony_ci		if (ret)
31762306a36Sopenharmony_ci			return ret;
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	default:
32062306a36Sopenharmony_ci		return -EINVAL;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return ret ? ret : len;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int admv1013_update_quad_filters(struct admv1013_state *st)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	unsigned int filt_raw;
32962306a36Sopenharmony_ci	u64 rate = clk_get_rate(st->clkin);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (rate >= (5400 * HZ_PER_MHZ) && rate <= (7000 * HZ_PER_MHZ))
33262306a36Sopenharmony_ci		filt_raw = 15;
33362306a36Sopenharmony_ci	else if (rate >= (5400 * HZ_PER_MHZ) && rate <= (8000 * HZ_PER_MHZ))
33462306a36Sopenharmony_ci		filt_raw = 10;
33562306a36Sopenharmony_ci	else if (rate >= (6600 * HZ_PER_MHZ) && rate <= (9200 * HZ_PER_MHZ))
33662306a36Sopenharmony_ci		filt_raw = 5;
33762306a36Sopenharmony_ci	else
33862306a36Sopenharmony_ci		filt_raw = 0;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD,
34162306a36Sopenharmony_ci					ADMV1013_QUAD_FILTERS_MSK,
34262306a36Sopenharmony_ci					FIELD_PREP(ADMV1013_QUAD_FILTERS_MSK, filt_raw));
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int admv1013_update_mixer_vgate(struct admv1013_state *st)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	unsigned int mixer_vgate;
34862306a36Sopenharmony_ci	int vcm;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	vcm = regulator_get_voltage(st->reg);
35162306a36Sopenharmony_ci	if (vcm < 0)
35262306a36Sopenharmony_ci		return vcm;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (vcm <= 1800000)
35562306a36Sopenharmony_ci		mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100;
35662306a36Sopenharmony_ci	else if (vcm > 1800000 && vcm <= 2600000)
35762306a36Sopenharmony_ci		mixer_vgate = (2375 * vcm / 1000000 + 125) / 100;
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		return -EINVAL;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return __admv1013_spi_update_bits(st, ADMV1013_REG_LO_AMP_I,
36262306a36Sopenharmony_ci				 ADMV1013_MIXER_VGATE_MSK,
36362306a36Sopenharmony_ci				 FIELD_PREP(ADMV1013_MIXER_VGATE_MSK, mixer_vgate));
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int admv1013_reg_access(struct iio_dev *indio_dev,
36762306a36Sopenharmony_ci			       unsigned int reg,
36862306a36Sopenharmony_ci			       unsigned int write_val,
36962306a36Sopenharmony_ci			       unsigned int *read_val)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct admv1013_state *st = iio_priv(indio_dev);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (read_val)
37462306a36Sopenharmony_ci		return admv1013_spi_read(st, reg, read_val);
37562306a36Sopenharmony_ci	else
37662306a36Sopenharmony_ci		return admv1013_spi_write(st, reg, write_val);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic const struct iio_info admv1013_info = {
38062306a36Sopenharmony_ci	.read_raw = admv1013_read_raw,
38162306a36Sopenharmony_ci	.write_raw = admv1013_write_raw,
38262306a36Sopenharmony_ci	.debugfs_reg_access = &admv1013_reg_access,
38362306a36Sopenharmony_ci};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic const char * const admv1013_vcc_regs[] = {
38662306a36Sopenharmony_ci	 "vcc-drv", "vcc2-drv", "vcc-vva", "vcc-amp1", "vcc-amp2",
38762306a36Sopenharmony_ci	 "vcc-env", "vcc-bg", "vcc-bg2", "vcc-mixer", "vcc-quad"
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int admv1013_freq_change(struct notifier_block *nb, unsigned long action, void *data)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct admv1013_state *st = container_of(nb, struct admv1013_state, nb);
39362306a36Sopenharmony_ci	int ret;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (action == POST_RATE_CHANGE) {
39662306a36Sopenharmony_ci		mutex_lock(&st->lock);
39762306a36Sopenharmony_ci		ret = notifier_from_errno(admv1013_update_quad_filters(st));
39862306a36Sopenharmony_ci		mutex_unlock(&st->lock);
39962306a36Sopenharmony_ci		return ret;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return NOTIFY_OK;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci#define _ADMV1013_EXT_INFO(_name, _shared, _ident) { \
40662306a36Sopenharmony_ci		.name = _name, \
40762306a36Sopenharmony_ci		.read = admv1013_read, \
40862306a36Sopenharmony_ci		.write = admv1013_write, \
40962306a36Sopenharmony_ci		.private = _ident, \
41062306a36Sopenharmony_ci		.shared = _shared, \
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info admv1013_ext_info[] = {
41462306a36Sopenharmony_ci	_ADMV1013_EXT_INFO("i_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_I_CALIBPHASE),
41562306a36Sopenharmony_ci	_ADMV1013_EXT_INFO("q_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_Q_CALIBPHASE),
41662306a36Sopenharmony_ci	{ },
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci#define ADMV1013_CHAN_PHASE(_channel, _channel2, _admv1013_ext_info) {		\
42062306a36Sopenharmony_ci	.type = IIO_ALTVOLTAGE,					\
42162306a36Sopenharmony_ci	.output = 0,						\
42262306a36Sopenharmony_ci	.indexed = 1,						\
42362306a36Sopenharmony_ci	.channel2 = _channel2,					\
42462306a36Sopenharmony_ci	.channel = _channel,					\
42562306a36Sopenharmony_ci	.differential = 1,					\
42662306a36Sopenharmony_ci	.ext_info = _admv1013_ext_info,				\
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci#define ADMV1013_CHAN_CALIB(_channel, rf_comp) {	\
43062306a36Sopenharmony_ci	.type = IIO_ALTVOLTAGE,					\
43162306a36Sopenharmony_ci	.output = 0,						\
43262306a36Sopenharmony_ci	.indexed = 1,						\
43362306a36Sopenharmony_ci	.channel = _channel,					\
43462306a36Sopenharmony_ci	.channel2 = IIO_MOD_##rf_comp,				\
43562306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_CALIBBIAS),	\
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic const struct iio_chan_spec admv1013_channels[] = {
43962306a36Sopenharmony_ci	ADMV1013_CHAN_PHASE(0, 1, admv1013_ext_info),
44062306a36Sopenharmony_ci	ADMV1013_CHAN_CALIB(0, I),
44162306a36Sopenharmony_ci	ADMV1013_CHAN_CALIB(0, Q),
44262306a36Sopenharmony_ci	ADMV1013_CHAN_CALIB(1, I),
44362306a36Sopenharmony_ci	ADMV1013_CHAN_CALIB(1, Q),
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int admv1013_init(struct admv1013_state *st)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	int ret;
44962306a36Sopenharmony_ci	unsigned int data;
45062306a36Sopenharmony_ci	struct spi_device *spi = st->spi;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Perform a software reset */
45362306a36Sopenharmony_ci	ret = __admv1013_spi_update_bits(st, ADMV1013_REG_SPI_CONTROL,
45462306a36Sopenharmony_ci					 ADMV1013_SPI_SOFT_RESET_MSK,
45562306a36Sopenharmony_ci					 FIELD_PREP(ADMV1013_SPI_SOFT_RESET_MSK, 1));
45662306a36Sopenharmony_ci	if (ret)
45762306a36Sopenharmony_ci		return ret;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	ret = __admv1013_spi_update_bits(st, ADMV1013_REG_SPI_CONTROL,
46062306a36Sopenharmony_ci					 ADMV1013_SPI_SOFT_RESET_MSK,
46162306a36Sopenharmony_ci					 FIELD_PREP(ADMV1013_SPI_SOFT_RESET_MSK, 0));
46262306a36Sopenharmony_ci	if (ret)
46362306a36Sopenharmony_ci		return ret;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	ret = __admv1013_spi_read(st, ADMV1013_REG_SPI_CONTROL, &data);
46662306a36Sopenharmony_ci	if (ret)
46762306a36Sopenharmony_ci		return ret;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	data = FIELD_GET(ADMV1013_CHIP_ID_MSK, data);
47062306a36Sopenharmony_ci	if (data != ADMV1013_CHIP_ID) {
47162306a36Sopenharmony_ci		dev_err(&spi->dev, "Invalid Chip ID.\n");
47262306a36Sopenharmony_ci		return -EINVAL;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ret = __admv1013_spi_write(st, ADMV1013_REG_VVA_TEMP_COMP, 0xE700);
47662306a36Sopenharmony_ci	if (ret)
47762306a36Sopenharmony_ci		return ret;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	data = FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, st->quad_se_mode);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	ret = __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD,
48262306a36Sopenharmony_ci					 ADMV1013_QUAD_SE_MODE_MSK, data);
48362306a36Sopenharmony_ci	if (ret)
48462306a36Sopenharmony_ci		return ret;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	ret = admv1013_update_mixer_vgate(st);
48762306a36Sopenharmony_ci	if (ret)
48862306a36Sopenharmony_ci		return ret;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ret = admv1013_update_quad_filters(st);
49162306a36Sopenharmony_ci	if (ret)
49262306a36Sopenharmony_ci		return ret;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return __admv1013_spi_update_bits(st, ADMV1013_REG_ENABLE,
49562306a36Sopenharmony_ci					  ADMV1013_DET_EN_MSK |
49662306a36Sopenharmony_ci					  ADMV1013_MIXER_IF_EN_MSK,
49762306a36Sopenharmony_ci					  st->det_en |
49862306a36Sopenharmony_ci					  st->input_mode);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void admv1013_reg_disable(void *data)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	regulator_disable(data);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic void admv1013_powerdown(void *data)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	unsigned int enable_reg, enable_reg_msk;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* Disable all components in the Enable Register */
51162306a36Sopenharmony_ci	enable_reg_msk = ADMV1013_VGA_PD_MSK |
51262306a36Sopenharmony_ci			ADMV1013_MIXER_PD_MSK |
51362306a36Sopenharmony_ci			ADMV1013_QUAD_PD_MSK |
51462306a36Sopenharmony_ci			ADMV1013_BG_PD_MSK |
51562306a36Sopenharmony_ci			ADMV1013_MIXER_IF_EN_MSK |
51662306a36Sopenharmony_ci			ADMV1013_DET_EN_MSK;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	enable_reg = FIELD_PREP(ADMV1013_VGA_PD_MSK, 1) |
51962306a36Sopenharmony_ci			FIELD_PREP(ADMV1013_MIXER_PD_MSK, 1) |
52062306a36Sopenharmony_ci			FIELD_PREP(ADMV1013_QUAD_PD_MSK, 7) |
52162306a36Sopenharmony_ci			FIELD_PREP(ADMV1013_BG_PD_MSK, 1) |
52262306a36Sopenharmony_ci			FIELD_PREP(ADMV1013_MIXER_IF_EN_MSK, 0) |
52362306a36Sopenharmony_ci			FIELD_PREP(ADMV1013_DET_EN_MSK, 0);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	admv1013_spi_update_bits(data, ADMV1013_REG_ENABLE, enable_reg_msk, enable_reg);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic int admv1013_properties_parse(struct admv1013_state *st)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int ret;
53162306a36Sopenharmony_ci	const char *str;
53262306a36Sopenharmony_ci	struct spi_device *spi = st->spi;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable");
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	ret = device_property_read_string(&spi->dev, "adi,input-mode", &str);
53762306a36Sopenharmony_ci	if (ret)
53862306a36Sopenharmony_ci		st->input_mode = ADMV1013_IQ_MODE;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (!strcmp(str, "iq"))
54162306a36Sopenharmony_ci		st->input_mode = ADMV1013_IQ_MODE;
54262306a36Sopenharmony_ci	else if (!strcmp(str, "if"))
54362306a36Sopenharmony_ci		st->input_mode = ADMV1013_IF_MODE;
54462306a36Sopenharmony_ci	else
54562306a36Sopenharmony_ci		return -EINVAL;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str);
54862306a36Sopenharmony_ci	if (ret)
54962306a36Sopenharmony_ci		st->quad_se_mode = ADMV1013_SE_MODE_DIFF;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (!strcmp(str, "diff"))
55262306a36Sopenharmony_ci		st->quad_se_mode = ADMV1013_SE_MODE_DIFF;
55362306a36Sopenharmony_ci	else if (!strcmp(str, "se-pos"))
55462306a36Sopenharmony_ci		st->quad_se_mode = ADMV1013_SE_MODE_POS;
55562306a36Sopenharmony_ci	else if (!strcmp(str, "se-neg"))
55662306a36Sopenharmony_ci		st->quad_se_mode = ADMV1013_SE_MODE_NEG;
55762306a36Sopenharmony_ci	else
55862306a36Sopenharmony_ci		return -EINVAL;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	st->reg = devm_regulator_get(&spi->dev, "vcm");
56162306a36Sopenharmony_ci	if (IS_ERR(st->reg))
56262306a36Sopenharmony_ci		return dev_err_probe(&spi->dev, PTR_ERR(st->reg),
56362306a36Sopenharmony_ci				     "failed to get the common-mode voltage\n");
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	ret = devm_regulator_bulk_get_enable(&st->spi->dev,
56662306a36Sopenharmony_ci					     ARRAY_SIZE(admv1013_vcc_regs),
56762306a36Sopenharmony_ci					     admv1013_vcc_regs);
56862306a36Sopenharmony_ci	if (ret) {
56962306a36Sopenharmony_ci		dev_err_probe(&spi->dev, ret,
57062306a36Sopenharmony_ci			      "Failed to request VCC regulators\n");
57162306a36Sopenharmony_ci		return ret;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return 0;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int admv1013_probe(struct spi_device *spi)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct iio_dev *indio_dev;
58062306a36Sopenharmony_ci	struct admv1013_state *st;
58162306a36Sopenharmony_ci	int ret;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
58462306a36Sopenharmony_ci	if (!indio_dev)
58562306a36Sopenharmony_ci		return -ENOMEM;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	st = iio_priv(indio_dev);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	indio_dev->info = &admv1013_info;
59062306a36Sopenharmony_ci	indio_dev->name = "admv1013";
59162306a36Sopenharmony_ci	indio_dev->channels = admv1013_channels;
59262306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(admv1013_channels);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	st->spi = spi;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ret = admv1013_properties_parse(st);
59762306a36Sopenharmony_ci	if (ret)
59862306a36Sopenharmony_ci		return ret;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	ret = regulator_enable(st->reg);
60162306a36Sopenharmony_ci	if (ret) {
60262306a36Sopenharmony_ci		dev_err(&spi->dev, "Failed to enable specified Common-Mode Voltage!\n");
60362306a36Sopenharmony_ci		return ret;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&spi->dev, admv1013_reg_disable,
60762306a36Sopenharmony_ci				       st->reg);
60862306a36Sopenharmony_ci	if (ret)
60962306a36Sopenharmony_ci		return ret;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in");
61262306a36Sopenharmony_ci	if (IS_ERR(st->clkin))
61362306a36Sopenharmony_ci		return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
61462306a36Sopenharmony_ci				     "failed to get the LO input clock\n");
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	st->nb.notifier_call = admv1013_freq_change;
61762306a36Sopenharmony_ci	ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
61862306a36Sopenharmony_ci	if (ret)
61962306a36Sopenharmony_ci		return ret;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	mutex_init(&st->lock);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	ret = admv1013_init(st);
62462306a36Sopenharmony_ci	if (ret) {
62562306a36Sopenharmony_ci		dev_err(&spi->dev, "admv1013 init failed\n");
62662306a36Sopenharmony_ci		return ret;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&spi->dev, admv1013_powerdown, st);
63062306a36Sopenharmony_ci	if (ret)
63162306a36Sopenharmony_ci		return ret;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return devm_iio_device_register(&spi->dev, indio_dev);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic const struct spi_device_id admv1013_id[] = {
63762306a36Sopenharmony_ci	{ "admv1013", 0 },
63862306a36Sopenharmony_ci	{}
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, admv1013_id);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic const struct of_device_id admv1013_of_match[] = {
64362306a36Sopenharmony_ci	{ .compatible = "adi,admv1013" },
64462306a36Sopenharmony_ci	{},
64562306a36Sopenharmony_ci};
64662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, admv1013_of_match);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic struct spi_driver admv1013_driver = {
64962306a36Sopenharmony_ci	.driver = {
65062306a36Sopenharmony_ci		.name = "admv1013",
65162306a36Sopenharmony_ci		.of_match_table = admv1013_of_match,
65262306a36Sopenharmony_ci	},
65362306a36Sopenharmony_ci	.probe = admv1013_probe,
65462306a36Sopenharmony_ci	.id_table = admv1013_id,
65562306a36Sopenharmony_ci};
65662306a36Sopenharmony_cimodule_spi_driver(admv1013_driver);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ciMODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
65962306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADMV1013");
66062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
661