brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · 848baa6 Raw
713 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ADMV8818 driver4 *5 * Copyright 2021 Analog Devices Inc.6 */7 8#include <linux/bitfield.h>9#include <linux/bits.h>10#include <linux/clk.h>11#include <linux/device.h>12#include <linux/iio/iio.h>13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/mutex.h>16#include <linux/notifier.h>17#include <linux/regmap.h>18#include <linux/spi/spi.h>19#include <linux/units.h>20 21/* ADMV8818 Register Map */22#define ADMV8818_REG_SPI_CONFIG_A		0x023#define ADMV8818_REG_SPI_CONFIG_B		0x124#define ADMV8818_REG_CHIPTYPE			0x325#define ADMV8818_REG_PRODUCT_ID_L		0x426#define ADMV8818_REG_PRODUCT_ID_H		0x527#define ADMV8818_REG_FAST_LATCH_POINTER		0x1028#define ADMV8818_REG_FAST_LATCH_STOP		0x1129#define ADMV8818_REG_FAST_LATCH_START		0x1230#define ADMV8818_REG_FAST_LATCH_DIRECTION	0x1331#define ADMV8818_REG_FAST_LATCH_STATE		0x1432#define ADMV8818_REG_WR0_SW			0x2033#define ADMV8818_REG_WR0_FILTER			0x2134#define ADMV8818_REG_WR1_SW			0x2235#define ADMV8818_REG_WR1_FILTER			0x2336#define ADMV8818_REG_WR2_SW			0x2437#define ADMV8818_REG_WR2_FILTER			0x2538#define ADMV8818_REG_WR3_SW			0x2639#define ADMV8818_REG_WR3_FILTER			0x2740#define ADMV8818_REG_WR4_SW			0x2841#define ADMV8818_REG_WR4_FILTER			0x2942#define ADMV8818_REG_LUT0_SW			0x10043#define ADMV8818_REG_LUT0_FILTER		0x10144#define ADMV8818_REG_LUT127_SW			0x1FE45#define ADMV8818_REG_LUT127_FILTER		0x1FF46 47/* ADMV8818_REG_SPI_CONFIG_A Map */48#define ADMV8818_SOFTRESET_N_MSK		BIT(7)49#define ADMV8818_LSB_FIRST_N_MSK		BIT(6)50#define ADMV8818_ENDIAN_N_MSK			BIT(5)51#define ADMV8818_SDOACTIVE_N_MSK		BIT(4)52#define ADMV8818_SDOACTIVE_MSK			BIT(3)53#define ADMV8818_ENDIAN_MSK			BIT(2)54#define ADMV8818_LSBFIRST_MSK			BIT(1)55#define ADMV8818_SOFTRESET_MSK			BIT(0)56 57/* ADMV8818_REG_SPI_CONFIG_B Map */58#define ADMV8818_SINGLE_INSTRUCTION_MSK		BIT(7)59#define ADMV8818_CSB_STALL_MSK			BIT(6)60#define ADMV8818_MASTER_SLAVE_RB_MSK		BIT(5)61#define ADMV8818_MASTER_SLAVE_TRANSFER_MSK	BIT(0)62 63/* ADMV8818_REG_WR0_SW Map */64#define ADMV8818_SW_IN_SET_WR0_MSK		BIT(7)65#define ADMV8818_SW_OUT_SET_WR0_MSK		BIT(6)66#define ADMV8818_SW_IN_WR0_MSK			GENMASK(5, 3)67#define ADMV8818_SW_OUT_WR0_MSK			GENMASK(2, 0)68 69/* ADMV8818_REG_WR0_FILTER Map */70#define ADMV8818_HPF_WR0_MSK			GENMASK(7, 4)71#define ADMV8818_LPF_WR0_MSK			GENMASK(3, 0)72 73enum {74	ADMV8818_BW_FREQ,75	ADMV8818_CENTER_FREQ76};77 78enum {79	ADMV8818_AUTO_MODE,80	ADMV8818_MANUAL_MODE,81	ADMV8818_BYPASS_MODE,82};83 84struct admv8818_state {85	struct spi_device	*spi;86	struct regmap		*regmap;87	struct clk		*clkin;88	struct notifier_block	nb;89	/* Protect against concurrent accesses to the device and data content*/90	struct mutex		lock;91	unsigned int		filter_mode;92	u64			cf_hz;93};94 95static const unsigned long long freq_range_hpf[4][2] = {96	{1750000000ULL, 3550000000ULL},97	{3400000000ULL, 7250000000ULL},98	{6600000000, 12000000000},99	{12500000000, 19900000000}100};101 102static const unsigned long long freq_range_lpf[4][2] = {103	{2050000000ULL, 3850000000ULL},104	{3350000000ULL, 7250000000ULL},105	{7000000000, 13000000000},106	{12550000000, 18500000000}107};108 109static const struct regmap_config admv8818_regmap_config = {110	.reg_bits = 16,111	.val_bits = 8,112	.read_flag_mask = 0x80,113	.max_register = 0x1FF,114};115 116static const char * const admv8818_modes[] = {117	[0] = "auto",118	[1] = "manual",119	[2] = "bypass"120};121 122static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq)123{124	unsigned int hpf_step = 0, hpf_band = 0, i, j;125	u64 freq_step;126	int ret;127 128	if (freq < freq_range_hpf[0][0])129		goto hpf_write;130 131	if (freq > freq_range_hpf[3][1]) {132		hpf_step = 15;133		hpf_band = 4;134 135		goto hpf_write;136	}137 138	for (i = 0; i < 4; i++) {139		freq_step = div_u64((freq_range_hpf[i][1] -140			freq_range_hpf[i][0]), 15);141 142		if (freq > freq_range_hpf[i][0] &&143		    (freq < freq_range_hpf[i][1] + freq_step)) {144			hpf_band = i + 1;145 146			for (j = 1; j <= 16; j++) {147				if (freq < (freq_range_hpf[i][0] + (freq_step * j))) {148					hpf_step = j - 1;149					break;150				}151			}152			break;153		}154	}155 156	/* Close HPF frequency gap between 12 and 12.5 GHz */157	if (freq >= 12000 * HZ_PER_MHZ && freq <= 12500 * HZ_PER_MHZ) {158		hpf_band = 3;159		hpf_step = 15;160	}161 162hpf_write:163	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,164				 ADMV8818_SW_IN_SET_WR0_MSK |165				 ADMV8818_SW_IN_WR0_MSK,166				 FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) |167				 FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, hpf_band));168	if (ret)169		return ret;170 171	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,172				  ADMV8818_HPF_WR0_MSK,173				  FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_step));174}175 176static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)177{178	int ret;179 180	mutex_lock(&st->lock);181	ret = __admv8818_hpf_select(st, freq);182	mutex_unlock(&st->lock);183 184	return ret;185}186 187static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq)188{189	unsigned int lpf_step = 0, lpf_band = 0, i, j;190	u64 freq_step;191	int ret;192 193	if (freq > freq_range_lpf[3][1])194		goto lpf_write;195 196	if (freq < freq_range_lpf[0][0]) {197		lpf_band = 1;198 199		goto lpf_write;200	}201 202	for (i = 0; i < 4; i++) {203		if (freq > freq_range_lpf[i][0] && freq < freq_range_lpf[i][1]) {204			lpf_band = i + 1;205			freq_step = div_u64((freq_range_lpf[i][1] - freq_range_lpf[i][0]), 15);206 207			for (j = 0; j <= 15; j++) {208				if (freq < (freq_range_lpf[i][0] + (freq_step * j))) {209					lpf_step = j;210					break;211				}212			}213			break;214		}215	}216 217lpf_write:218	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,219				 ADMV8818_SW_OUT_SET_WR0_MSK |220				 ADMV8818_SW_OUT_WR0_MSK,221				 FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) |222				 FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, lpf_band));223	if (ret)224		return ret;225 226	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,227				  ADMV8818_LPF_WR0_MSK,228				  FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_step));229}230 231static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)232{233	int ret;234 235	mutex_lock(&st->lock);236	ret = __admv8818_lpf_select(st, freq);237	mutex_unlock(&st->lock);238 239	return ret;240}241 242static int admv8818_rfin_band_select(struct admv8818_state *st)243{244	int ret;245 246	st->cf_hz = clk_get_rate(st->clkin);247 248	mutex_lock(&st->lock);249 250	ret = __admv8818_hpf_select(st, st->cf_hz);251	if (ret)252		goto exit;253 254	ret = __admv8818_lpf_select(st, st->cf_hz);255exit:256	mutex_unlock(&st->lock);257	return ret;258}259 260static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)261{262	unsigned int data, hpf_band, hpf_state;263	int ret;264 265	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);266	if (ret)267		return ret;268 269	hpf_band = FIELD_GET(ADMV8818_SW_IN_WR0_MSK, data);270	if (!hpf_band || hpf_band > 4) {271		*hpf_freq = 0;272		return ret;273	}274 275	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);276	if (ret)277		return ret;278 279	hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data);280 281	*hpf_freq = div_u64(freq_range_hpf[hpf_band - 1][1] - freq_range_hpf[hpf_band - 1][0], 15);282	*hpf_freq = freq_range_hpf[hpf_band - 1][0] + (*hpf_freq * hpf_state);283 284	return ret;285}286 287static int admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)288{289	int ret;290 291	mutex_lock(&st->lock);292	ret = __admv8818_read_hpf_freq(st, hpf_freq);293	mutex_unlock(&st->lock);294 295	return ret;296}297 298static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)299{300	unsigned int data, lpf_band, lpf_state;301	int ret;302 303	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);304	if (ret)305		return ret;306 307	lpf_band = FIELD_GET(ADMV8818_SW_OUT_WR0_MSK, data);308	if (!lpf_band || lpf_band > 4) {309		*lpf_freq = 0;310		return ret;311	}312 313	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);314	if (ret)315		return ret;316 317	lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data);318 319	*lpf_freq = div_u64(freq_range_lpf[lpf_band - 1][1] - freq_range_lpf[lpf_band - 1][0], 15);320	*lpf_freq = freq_range_lpf[lpf_band - 1][0] + (*lpf_freq * lpf_state);321 322	return ret;323}324 325static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)326{327	int ret;328 329	mutex_lock(&st->lock);330	ret = __admv8818_read_lpf_freq(st, lpf_freq);331	mutex_unlock(&st->lock);332 333	return ret;334}335 336static int admv8818_write_raw(struct iio_dev *indio_dev,337			      struct iio_chan_spec const *chan,338			      int val, int val2, long info)339{340	struct admv8818_state *st = iio_priv(indio_dev);341 342	u64 freq = ((u64)val2 << 32 | (u32)val);343 344	switch (info) {345	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:346		return admv8818_lpf_select(st, freq);347	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:348		return admv8818_hpf_select(st, freq);349	default:350		return -EINVAL;351	}352}353 354static int admv8818_read_raw(struct iio_dev *indio_dev,355			     struct iio_chan_spec const *chan,356			     int *val, int *val2, long info)357{358	struct admv8818_state *st = iio_priv(indio_dev);359	int ret;360	u64 freq;361 362	switch (info) {363	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:364		ret = admv8818_read_lpf_freq(st, &freq);365		if (ret)366			return ret;367 368		*val = (u32)freq;369		*val2 = (u32)(freq >> 32);370 371		return IIO_VAL_INT_64;372	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:373		ret = admv8818_read_hpf_freq(st, &freq);374		if (ret)375			return ret;376 377		*val = (u32)freq;378		*val2 = (u32)(freq >> 32);379 380		return IIO_VAL_INT_64;381	default:382		return -EINVAL;383	}384}385 386static int admv8818_reg_access(struct iio_dev *indio_dev,387			       unsigned int reg,388			       unsigned int write_val,389			       unsigned int *read_val)390{391	struct admv8818_state *st = iio_priv(indio_dev);392 393	if (read_val)394		return regmap_read(st->regmap, reg, read_val);395	else396		return regmap_write(st->regmap, reg, write_val);397}398 399static int admv8818_filter_bypass(struct admv8818_state *st)400{401	int ret;402 403	mutex_lock(&st->lock);404 405	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,406				 ADMV8818_SW_IN_SET_WR0_MSK |407				 ADMV8818_SW_IN_WR0_MSK |408				 ADMV8818_SW_OUT_SET_WR0_MSK |409				 ADMV8818_SW_OUT_WR0_MSK,410				 FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) |411				 FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, 0) |412				 FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) |413				 FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, 0));414	if (ret)415		goto exit;416 417	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,418				 ADMV8818_HPF_WR0_MSK |419				 ADMV8818_LPF_WR0_MSK,420				 FIELD_PREP(ADMV8818_HPF_WR0_MSK, 0) |421				 FIELD_PREP(ADMV8818_LPF_WR0_MSK, 0));422 423exit:424	mutex_unlock(&st->lock);425 426	return ret;427}428 429static int admv8818_get_mode(struct iio_dev *indio_dev,430			     const struct iio_chan_spec *chan)431{432	struct admv8818_state *st = iio_priv(indio_dev);433 434	return st->filter_mode;435}436 437static int admv8818_set_mode(struct iio_dev *indio_dev,438			     const struct iio_chan_spec *chan,439			     unsigned int mode)440{441	struct admv8818_state *st = iio_priv(indio_dev);442	int ret = 0;443 444	if (!st->clkin) {445		if (mode == ADMV8818_MANUAL_MODE)446			goto set_mode;447 448		if (mode == ADMV8818_BYPASS_MODE) {449			ret = admv8818_filter_bypass(st);450			if (ret)451				return ret;452 453			goto set_mode;454		}455 456		return -EINVAL;457	}458 459	switch (mode) {460	case ADMV8818_AUTO_MODE:461		if (st->filter_mode == ADMV8818_AUTO_MODE)462			return 0;463 464		ret = clk_prepare_enable(st->clkin);465		if (ret)466			return ret;467 468		ret = clk_notifier_register(st->clkin, &st->nb);469		if (ret) {470			clk_disable_unprepare(st->clkin);471 472			return ret;473		}474 475		break;476	case ADMV8818_MANUAL_MODE:477	case ADMV8818_BYPASS_MODE:478		if (st->filter_mode == ADMV8818_AUTO_MODE) {479			clk_disable_unprepare(st->clkin);480 481			ret = clk_notifier_unregister(st->clkin, &st->nb);482			if (ret)483				return ret;484		}485 486		if (mode == ADMV8818_BYPASS_MODE) {487			ret = admv8818_filter_bypass(st);488			if (ret)489				return ret;490		}491 492		break;493	default:494		return -EINVAL;495	}496 497set_mode:498	st->filter_mode = mode;499 500	return ret;501}502 503static const struct iio_info admv8818_info = {504	.write_raw = admv8818_write_raw,505	.read_raw = admv8818_read_raw,506	.debugfs_reg_access = &admv8818_reg_access,507};508 509static const struct iio_enum admv8818_mode_enum = {510	.items = admv8818_modes,511	.num_items = ARRAY_SIZE(admv8818_modes),512	.get = admv8818_get_mode,513	.set = admv8818_set_mode,514};515 516static const struct iio_chan_spec_ext_info admv8818_ext_info[] = {517	IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),518	IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),519	{ },520};521 522#define ADMV8818_CHAN(_channel) {				\523	.type = IIO_ALTVOLTAGE,					\524	.output = 1,						\525	.indexed = 1,						\526	.channel = _channel,					\527	.info_mask_separate =					\528		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \529		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) \530}531 532#define ADMV8818_CHAN_BW_CF(_channel, _admv8818_ext_info) {	\533	.type = IIO_ALTVOLTAGE,					\534	.output = 1,						\535	.indexed = 1,						\536	.channel = _channel,					\537	.ext_info = _admv8818_ext_info,				\538}539 540static const struct iio_chan_spec admv8818_channels[] = {541	ADMV8818_CHAN(0),542	ADMV8818_CHAN_BW_CF(0, admv8818_ext_info),543};544 545static int admv8818_freq_change(struct notifier_block *nb, unsigned long action, void *data)546{547	struct admv8818_state *st = container_of(nb, struct admv8818_state, nb);548 549	if (action == POST_RATE_CHANGE)550		return notifier_from_errno(admv8818_rfin_band_select(st));551 552	return NOTIFY_OK;553}554 555static void admv8818_clk_notifier_unreg(void *data)556{557	struct admv8818_state *st = data;558 559	if (st->filter_mode == 0)560		clk_notifier_unregister(st->clkin, &st->nb);561}562 563static void admv8818_clk_disable(void *data)564{565	struct admv8818_state *st = data;566 567	if (st->filter_mode == 0)568		clk_disable_unprepare(st->clkin);569}570 571static int admv8818_init(struct admv8818_state *st)572{573	int ret;574	struct spi_device *spi = st->spi;575	unsigned int chip_id;576 577	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_A,578				 ADMV8818_SOFTRESET_N_MSK |579				 ADMV8818_SOFTRESET_MSK,580				 FIELD_PREP(ADMV8818_SOFTRESET_N_MSK, 1) |581				 FIELD_PREP(ADMV8818_SOFTRESET_MSK, 1));582	if (ret) {583		dev_err(&spi->dev, "ADMV8818 Soft Reset failed.\n");584		return ret;585	}586 587	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_A,588				 ADMV8818_SDOACTIVE_N_MSK |589				 ADMV8818_SDOACTIVE_MSK,590				 FIELD_PREP(ADMV8818_SDOACTIVE_N_MSK, 1) |591				 FIELD_PREP(ADMV8818_SDOACTIVE_MSK, 1));592	if (ret) {593		dev_err(&spi->dev, "ADMV8818 SDO Enable failed.\n");594		return ret;595	}596 597	ret = regmap_read(st->regmap, ADMV8818_REG_CHIPTYPE, &chip_id);598	if (ret) {599		dev_err(&spi->dev, "ADMV8818 Chip ID read failed.\n");600		return ret;601	}602 603	if (chip_id != 0x1) {604		dev_err(&spi->dev, "ADMV8818 Invalid Chip ID.\n");605		return -EINVAL;606	}607 608	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_B,609				 ADMV8818_SINGLE_INSTRUCTION_MSK,610				 FIELD_PREP(ADMV8818_SINGLE_INSTRUCTION_MSK, 1));611	if (ret) {612		dev_err(&spi->dev, "ADMV8818 Single Instruction failed.\n");613		return ret;614	}615 616	if (st->clkin)617		return admv8818_rfin_band_select(st);618	else619		return 0;620}621 622static int admv8818_clk_setup(struct admv8818_state *st)623{624	struct spi_device *spi = st->spi;625	int ret;626 627	st->clkin = devm_clk_get_optional(&spi->dev, "rf_in");628	if (IS_ERR(st->clkin))629		return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),630				     "failed to get the input clock\n");631	else if (!st->clkin)632		return 0;633 634	ret = clk_prepare_enable(st->clkin);635	if (ret)636		return ret;637 638	ret = devm_add_action_or_reset(&spi->dev, admv8818_clk_disable, st);639	if (ret)640		return ret;641 642	st->nb.notifier_call = admv8818_freq_change;643	ret = clk_notifier_register(st->clkin, &st->nb);644	if (ret < 0)645		return ret;646 647	return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);648}649 650static int admv8818_probe(struct spi_device *spi)651{652	struct iio_dev *indio_dev;653	struct regmap *regmap;654	struct admv8818_state *st;655	int ret;656 657	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));658	if (!indio_dev)659		return -ENOMEM;660 661	regmap = devm_regmap_init_spi(spi, &admv8818_regmap_config);662	if (IS_ERR(regmap))663		return PTR_ERR(regmap);664 665	st = iio_priv(indio_dev);666	st->regmap = regmap;667 668	indio_dev->info = &admv8818_info;669	indio_dev->name = "admv8818";670	indio_dev->channels = admv8818_channels;671	indio_dev->num_channels = ARRAY_SIZE(admv8818_channels);672 673	st->spi = spi;674 675	ret = admv8818_clk_setup(st);676	if (ret)677		return ret;678 679	mutex_init(&st->lock);680 681	ret = admv8818_init(st);682	if (ret)683		return ret;684 685	return devm_iio_device_register(&spi->dev, indio_dev);686}687 688static const struct spi_device_id admv8818_id[] = {689	{ "admv8818", 0 },690	{}691};692MODULE_DEVICE_TABLE(spi, admv8818_id);693 694static const struct of_device_id admv8818_of_match[] = {695	{ .compatible = "adi,admv8818" },696	{}697};698MODULE_DEVICE_TABLE(of, admv8818_of_match);699 700static struct spi_driver admv8818_driver = {701	.driver = {702		.name = "admv8818",703		.of_match_table = admv8818_of_match,704	},705	.probe = admv8818_probe,706	.id_table = admv8818_id,707};708module_spi_driver(admv8818_driver);709 710MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");711MODULE_DESCRIPTION("Analog Devices ADMV8818");712MODULE_LICENSE("GPL v2");713