File Index
Files and directories
Sign in
FILE

admv8818.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/filter/admv8818.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * ADMV8818 driver
  4 *
  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/property.h>
 18#include <linux/regmap.h>
 19#include <linux/spi/spi.h>
 20#include <linux/units.h>
 21
 22/* ADMV8818 Register Map */
 23#define ADMV8818_REG_SPI_CONFIG_A		0x0
 24#define ADMV8818_REG_SPI_CONFIG_B		0x1
 25#define ADMV8818_REG_CHIPTYPE			0x3
 26#define ADMV8818_REG_PRODUCT_ID_L		0x4
 27#define ADMV8818_REG_PRODUCT_ID_H		0x5
 28#define ADMV8818_REG_FAST_LATCH_POINTER		0x10
 29#define ADMV8818_REG_FAST_LATCH_STOP		0x11
 30#define ADMV8818_REG_FAST_LATCH_START		0x12
 31#define ADMV8818_REG_FAST_LATCH_DIRECTION	0x13
 32#define ADMV8818_REG_FAST_LATCH_STATE		0x14
 33#define ADMV8818_REG_WR0_SW			0x20
 34#define ADMV8818_REG_WR0_FILTER			0x21
 35#define ADMV8818_REG_WR1_SW			0x22
 36#define ADMV8818_REG_WR1_FILTER			0x23
 37#define ADMV8818_REG_WR2_SW			0x24
 38#define ADMV8818_REG_WR2_FILTER			0x25
 39#define ADMV8818_REG_WR3_SW			0x26
 40#define ADMV8818_REG_WR3_FILTER			0x27
 41#define ADMV8818_REG_WR4_SW			0x28
 42#define ADMV8818_REG_WR4_FILTER			0x29
 43#define ADMV8818_REG_LUT0_SW			0x100
 44#define ADMV8818_REG_LUT0_FILTER		0x101
 45#define ADMV8818_REG_LUT127_SW			0x1FE
 46#define ADMV8818_REG_LUT127_FILTER		0x1FF
 47
 48/* ADMV8818_REG_SPI_CONFIG_A Map */
 49#define ADMV8818_SOFTRESET_N_MSK		BIT(7)
 50#define ADMV8818_LSB_FIRST_N_MSK		BIT(6)
 51#define ADMV8818_ENDIAN_N_MSK			BIT(5)
 52#define ADMV8818_SDOACTIVE_N_MSK		BIT(4)
 53#define ADMV8818_SDOACTIVE_MSK			BIT(3)
 54#define ADMV8818_ENDIAN_MSK			BIT(2)
 55#define ADMV8818_LSBFIRST_MSK			BIT(1)
 56#define ADMV8818_SOFTRESET_MSK			BIT(0)
 57
 58/* ADMV8818_REG_SPI_CONFIG_B Map */
 59#define ADMV8818_SINGLE_INSTRUCTION_MSK		BIT(7)
 60#define ADMV8818_CSB_STALL_MSK			BIT(6)
 61#define ADMV8818_MASTER_SLAVE_RB_MSK		BIT(5)
 62#define ADMV8818_MASTER_SLAVE_TRANSFER_MSK	BIT(0)
 63
 64/* ADMV8818_REG_WR0_SW Map */
 65#define ADMV8818_SW_IN_SET_WR0_MSK		BIT(7)
 66#define ADMV8818_SW_OUT_SET_WR0_MSK		BIT(6)
 67#define ADMV8818_SW_IN_WR0_MSK			GENMASK(5, 3)
 68#define ADMV8818_SW_OUT_WR0_MSK			GENMASK(2, 0)
 69
 70/* ADMV8818_REG_WR0_FILTER Map */
 71#define ADMV8818_HPF_WR0_MSK			GENMASK(7, 4)
 72#define ADMV8818_LPF_WR0_MSK			GENMASK(3, 0)
 73
 74#define ADMV8818_BAND_BYPASS       0
 75#define ADMV8818_BAND_MIN          1
 76#define ADMV8818_BAND_MAX          4
 77#define ADMV8818_BAND_CORNER_LOW   0
 78#define ADMV8818_BAND_CORNER_HIGH  1
 79
 80#define ADMV8818_STATE_MIN   0
 81#define ADMV8818_STATE_MAX   15
 82#define ADMV8818_NUM_STATES  16
 83
 84enum {
 85	ADMV8818_BW_FREQ,
 86	ADMV8818_CENTER_FREQ
 87};
 88
 89enum {
 90	ADMV8818_AUTO_MODE,
 91	ADMV8818_MANUAL_MODE,
 92	ADMV8818_BYPASS_MODE,
 93};
 94
 95struct admv8818_state {
 96	struct spi_device	*spi;
 97	struct regmap		*regmap;
 98	struct clk		*clkin;
 99	struct notifier_block	nb;
100	/* Protect against concurrent accesses to the device and data content*/
101	struct mutex		lock;
102	unsigned int		filter_mode;
103	u64			cf_hz;
104	u64			lpf_margin_hz;
105	u64			hpf_margin_hz;
106};
107
108static const unsigned long long freq_range_hpf[5][2] = {
109	{0ULL, 0ULL}, /* bypass */
110	{1750000000ULL, 3550000000ULL},
111	{3400000000ULL, 7250000000ULL},
112	{6600000000, 12000000000},
113	{12500000000, 19900000000}
114};
115
116static const unsigned long long freq_range_lpf[5][2] = {
117	{U64_MAX, U64_MAX}, /* bypass */
118	{2050000000ULL, 3850000000ULL},
119	{3350000000ULL, 7250000000ULL},
120	{7000000000, 13000000000},
121	{12550000000, 18850000000}
122};
123
124static const struct regmap_config admv8818_regmap_config = {
125	.reg_bits = 16,
126	.val_bits = 8,
127	.read_flag_mask = 0x80,
128	.max_register = 0x1FF,
129};
130
131static const char * const admv8818_modes[] = {
132	[0] = "auto",
133	[1] = "manual",
134	[2] = "bypass"
135};
136
137static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq)
138{
139	int band, state, ret;
140	unsigned int hpf_state = ADMV8818_STATE_MIN, hpf_band = ADMV8818_BAND_BYPASS;
141	u64 freq_error, min_freq_error, freq_corner, freq_step;
142
143	if (freq < freq_range_hpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW])
144		goto hpf_write;
145
146	if (freq >= freq_range_hpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH]) {
147		hpf_state = ADMV8818_STATE_MAX;
148		hpf_band = ADMV8818_BAND_MAX;
149		goto hpf_write;
150	}
151
152	/* Close HPF frequency gap between 12 and 12.5 GHz */
153	if (freq >= 12000ULL * HZ_PER_MHZ && freq < 12500ULL * HZ_PER_MHZ) {
154		hpf_state = ADMV8818_STATE_MAX;
155		hpf_band = 3;
156		goto hpf_write;
157	}
158
159	min_freq_error = U64_MAX;
160	for (band = ADMV8818_BAND_MIN; band <= ADMV8818_BAND_MAX; band++) {
161		/*
162		 * This (and therefore all other ranges) have a corner
163		 * frequency higher than the target frequency.
164		 */
165		if (freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] > freq)
166			break;
167
168		freq_step = freq_range_hpf[band][ADMV8818_BAND_CORNER_HIGH] -
169			    freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW];
170		freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
171
172		for (state = ADMV8818_STATE_MIN; state <= ADMV8818_STATE_MAX; state++) {
173			freq_corner = freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] +
174				      freq_step * state;
175
176			/*
177			 * This (and therefore all other states) have a corner
178			 * frequency higher than the target frequency.
179			 */
180			if (freq_corner > freq)
181				break;
182
183			freq_error = freq - freq_corner;
184			if (freq_error < min_freq_error) {
185				min_freq_error = freq_error;
186				hpf_state = state;
187				hpf_band = band;
188			}
189		}
190	}
191
192hpf_write:
193	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
194				 ADMV8818_SW_IN_SET_WR0_MSK |
195				 ADMV8818_SW_IN_WR0_MSK,
196				 FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) |
197				 FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, hpf_band));
198	if (ret)
199		return ret;
200
201	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
202				  ADMV8818_HPF_WR0_MSK,
203				  FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_state));
204}
205
206static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
207{
208	int ret;
209
210	mutex_lock(&st->lock);
211	ret = __admv8818_hpf_select(st, freq);
212	mutex_unlock(&st->lock);
213
214	return ret;
215}
216
217static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq)
218{
219	int band, state, ret;
220	unsigned int lpf_state = ADMV8818_STATE_MIN, lpf_band = ADMV8818_BAND_BYPASS;
221	u64 freq_error, min_freq_error, freq_corner, freq_step;
222
223	if (freq > freq_range_lpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH])
224		goto lpf_write;
225
226	if (freq < freq_range_lpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW]) {
227		lpf_state = ADMV8818_STATE_MIN;
228		lpf_band = ADMV8818_BAND_MIN;
229		goto lpf_write;
230	}
231
232	min_freq_error = U64_MAX;
233	for (band = ADMV8818_BAND_MAX; band >= ADMV8818_BAND_MIN; --band) {
234		/*
235		 * At this point the highest corner frequency of
236		 * all remaining ranges is below the target.
237		 * LPF corner should be >= the target.
238		 */
239		if (freq > freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH])
240			break;
241
242		freq_step = freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH] -
243			    freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW];
244		freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
245
246		for (state = ADMV8818_STATE_MAX; state >= ADMV8818_STATE_MIN; --state) {
247
248			freq_corner = freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW] +
249				      state * freq_step;
250
251			/*
252			 * At this point all other states in range will
253			 * place the corner frequency below the target
254			 * LPF corner should >= the target.
255			 */
256			if (freq > freq_corner)
257				break;
258
259			freq_error = freq_corner - freq;
260			if (freq_error < min_freq_error) {
261				min_freq_error = freq_error;
262				lpf_state = state;
263				lpf_band = band;
264			}
265		}
266	}
267
268lpf_write:
269	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
270				 ADMV8818_SW_OUT_SET_WR0_MSK |
271				 ADMV8818_SW_OUT_WR0_MSK,
272				 FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) |
273				 FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, lpf_band));
274	if (ret)
275		return ret;
276
277	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
278				  ADMV8818_LPF_WR0_MSK,
279				  FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_state));
280}
281
282static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
283{
284	int ret;
285
286	mutex_lock(&st->lock);
287	ret = __admv8818_lpf_select(st, freq);
288	mutex_unlock(&st->lock);
289
290	return ret;
291}
292
293static int admv8818_rfin_band_select(struct admv8818_state *st)
294{
295	int ret;
296	u64 hpf_corner_target, lpf_corner_target;
297
298	st->cf_hz = clk_get_rate(st->clkin);
299
300	/* Check for underflow */
301	if (st->cf_hz > st->hpf_margin_hz)
302		hpf_corner_target = st->cf_hz - st->hpf_margin_hz;
303	else
304		hpf_corner_target = 0;
305
306	/* Check for overflow */
307	lpf_corner_target = st->cf_hz + st->lpf_margin_hz;
308	if (lpf_corner_target < st->cf_hz)
309		lpf_corner_target = U64_MAX;
310
311	mutex_lock(&st->lock);
312
313	ret = __admv8818_hpf_select(st, hpf_corner_target);
314	if (ret)
315		goto exit;
316
317	ret = __admv8818_lpf_select(st, lpf_corner_target);
318exit:
319	mutex_unlock(&st->lock);
320	return ret;
321}
322
323static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
324{
325	unsigned int data, hpf_band, hpf_state;
326	int ret;
327
328	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);
329	if (ret)
330		return ret;
331
332	hpf_band = FIELD_GET(ADMV8818_SW_IN_WR0_MSK, data);
333	if (!hpf_band || hpf_band > 4) {
334		*hpf_freq = 0;
335		return ret;
336	}
337
338	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);
339	if (ret)
340		return ret;
341
342	hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data);
343
344	*hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_HIGH] -
345		    freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW];
346	*hpf_freq = div_u64(*hpf_freq, ADMV8818_NUM_STATES - 1);
347	*hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW] +
348		    (*hpf_freq * hpf_state);
349
350	return ret;
351}
352
353static int admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
354{
355	int ret;
356
357	mutex_lock(&st->lock);
358	ret = __admv8818_read_hpf_freq(st, hpf_freq);
359	mutex_unlock(&st->lock);
360
361	return ret;
362}
363
364static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
365{
366	unsigned int data, lpf_band, lpf_state;
367	int ret;
368
369	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);
370	if (ret)
371		return ret;
372
373	lpf_band = FIELD_GET(ADMV8818_SW_OUT_WR0_MSK, data);
374	if (!lpf_band || lpf_band > 4) {
375		*lpf_freq = 0;
376		return ret;
377	}
378
379	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);
380	if (ret)
381		return ret;
382
383	lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data);
384
385	*lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_HIGH] -
386		    freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW];
387	*lpf_freq = div_u64(*lpf_freq, ADMV8818_NUM_STATES - 1);
388	*lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW] +
389		    (*lpf_freq * lpf_state);
390
391	return ret;
392}
393
394static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
395{
396	int ret;
397
398	mutex_lock(&st->lock);
399	ret = __admv8818_read_lpf_freq(st, lpf_freq);
400	mutex_unlock(&st->lock);
401
402	return ret;
403}
404
405static int admv8818_write_raw_get_fmt(struct iio_dev *indio_dev,
406								struct iio_chan_spec const *chan,
407								long mask)
408{
409	switch (mask) {
410	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
411	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
412		return IIO_VAL_INT_64;
413	default:
414		return -EINVAL;
415	}
416}
417
418static int admv8818_write_raw(struct iio_dev *indio_dev,
419			      struct iio_chan_spec const *chan,
420			      int val, int val2, long info)
421{
422	struct admv8818_state *st = iio_priv(indio_dev);
423
424	u64 freq = ((u64)val2 << 32 | (u32)val);
425
426	if ((s64)freq < 0)
427		return -EINVAL;
428
429	switch (info) {
430	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
431		return admv8818_lpf_select(st, freq);
432	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
433		return admv8818_hpf_select(st, freq);
434	default:
435		return -EINVAL;
436	}
437}
438
439static int admv8818_read_raw(struct iio_dev *indio_dev,
440			     struct iio_chan_spec const *chan,
441			     int *val, int *val2, long info)
442{
443	struct admv8818_state *st = iio_priv(indio_dev);
444	int ret;
445	u64 freq;
446
447	switch (info) {
448	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
449		ret = admv8818_read_lpf_freq(st, &freq);
450		if (ret)
451			return ret;
452
453		*val = (u32)freq;
454		*val2 = (u32)(freq >> 32);
455
456		return IIO_VAL_INT_64;
457	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
458		ret = admv8818_read_hpf_freq(st, &freq);
459		if (ret)
460			return ret;
461
462		*val = (u32)freq;
463		*val2 = (u32)(freq >> 32);
464
465		return IIO_VAL_INT_64;
466	default:
467		return -EINVAL;
468	}
469}
470
471static int admv8818_reg_access(struct iio_dev *indio_dev,
472			       unsigned int reg,
473			       unsigned int write_val,
474			       unsigned int *read_val)
475{
476	struct admv8818_state *st = iio_priv(indio_dev);
477
478	if (read_val)
479		return regmap_read(st->regmap, reg, read_val);
480	else
481		return regmap_write(st->regmap, reg, write_val);
482}
483
484static int admv8818_filter_bypass(struct admv8818_state *st)
485{
486	int ret;
487
488	mutex_lock(&st->lock);
489
490	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
491				 ADMV8818_SW_IN_SET_WR0_MSK |
492				 ADMV8818_SW_IN_WR0_MSK |
493				 ADMV8818_SW_OUT_SET_WR0_MSK |
494				 ADMV8818_SW_OUT_WR0_MSK,
495				 FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) |
496				 FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, 0) |
497				 FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) |
498				 FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, 0));
499	if (ret)
500		goto exit;
501
502	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
503				 ADMV8818_HPF_WR0_MSK |
504				 ADMV8818_LPF_WR0_MSK,
505				 FIELD_PREP(ADMV8818_HPF_WR0_MSK, 0) |
506				 FIELD_PREP(ADMV8818_LPF_WR0_MSK, 0));
507
508exit:
509	mutex_unlock(&st->lock);
510
511	return ret;
512}
513
514static int admv8818_get_mode(struct iio_dev *indio_dev,
515			     const struct iio_chan_spec *chan)
516{
517	struct admv8818_state *st = iio_priv(indio_dev);
518
519	return st->filter_mode;
520}
521
522static int admv8818_set_mode(struct iio_dev *indio_dev,
523			     const struct iio_chan_spec *chan,
524			     unsigned int mode)
525{
526	struct admv8818_state *st = iio_priv(indio_dev);
527	int ret = 0;
528
529	if (!st->clkin) {
530		if (mode == ADMV8818_MANUAL_MODE)
531			goto set_mode;
532
533		if (mode == ADMV8818_BYPASS_MODE) {
534			ret = admv8818_filter_bypass(st);
535			if (ret)
536				return ret;
537
538			goto set_mode;
539		}
540
541		return -EINVAL;
542	}
543
544	switch (mode) {
545	case ADMV8818_AUTO_MODE:
546		if (st->filter_mode == ADMV8818_AUTO_MODE)
547			return 0;
548
549		ret = clk_prepare_enable(st->clkin);
550		if (ret)
551			return ret;
552
553		ret = clk_notifier_register(st->clkin, &st->nb);
554		if (ret) {
555			clk_disable_unprepare(st->clkin);
556
557			return ret;
558		}
559
560		break;
561	case ADMV8818_MANUAL_MODE:
562	case ADMV8818_BYPASS_MODE:
563		if (st->filter_mode == ADMV8818_AUTO_MODE) {
564			clk_disable_unprepare(st->clkin);
565
566			ret = clk_notifier_unregister(st->clkin, &st->nb);
567			if (ret)
568				return ret;
569		}
570
571		if (mode == ADMV8818_BYPASS_MODE) {
572			ret = admv8818_filter_bypass(st);
573			if (ret)
574				return ret;
575		}
576
577		break;
578	default:
579		return -EINVAL;
580	}
581
582set_mode:
583	st->filter_mode = mode;
584
585	return ret;
586}
587
588static const struct iio_info admv8818_info = {
589	.write_raw = admv8818_write_raw,
590	.write_raw_get_fmt = admv8818_write_raw_get_fmt,
591	.read_raw = admv8818_read_raw,
592	.debugfs_reg_access = &admv8818_reg_access,
593};
594
595static const struct iio_enum admv8818_mode_enum = {
596	.items = admv8818_modes,
597	.num_items = ARRAY_SIZE(admv8818_modes),
598	.get = admv8818_get_mode,
599	.set = admv8818_set_mode,
600};
601
602static const struct iio_chan_spec_ext_info admv8818_ext_info[] = {
603	IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
604	IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
605	{ }
606};
607
608#define ADMV8818_CHAN(_channel) {				\
609	.type = IIO_ALTVOLTAGE,					\
610	.output = 1,						\
611	.indexed = 1,						\
612	.channel = _channel,					\
613	.info_mask_separate =					\
614		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
615		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) \
616}
617
618#define ADMV8818_CHAN_BW_CF(_channel, _admv8818_ext_info) {	\
619	.type = IIO_ALTVOLTAGE,					\
620	.output = 1,						\
621	.indexed = 1,						\
622	.channel = _channel,					\
623	.ext_info = _admv8818_ext_info,				\
624}
625
626static const struct iio_chan_spec admv8818_channels[] = {
627	ADMV8818_CHAN(0),
628	ADMV8818_CHAN_BW_CF(0, admv8818_ext_info),
629};
630
631static int admv8818_freq_change(struct notifier_block *nb, unsigned long action, void *data)
632{
633	struct admv8818_state *st = container_of(nb, struct admv8818_state, nb);
634
635	if (action == POST_RATE_CHANGE)
636		return notifier_from_errno(admv8818_rfin_band_select(st));
637
638	return NOTIFY_OK;
639}
640
641static void admv8818_clk_notifier_unreg(void *data)
642{
643	struct admv8818_state *st = data;
644
645	if (st->filter_mode == 0)
646		clk_notifier_unregister(st->clkin, &st->nb);
647}
648
649static void admv8818_clk_disable(void *data)
650{
651	struct admv8818_state *st = data;
652
653	if (st->filter_mode == 0)
654		clk_disable_unprepare(st->clkin);
655}
656
657static int admv8818_init(struct admv8818_state *st)
658{
659	int ret;
660	struct spi_device *spi = st->spi;
661	unsigned int chip_id;
662
663	ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
664			   ADMV8818_SOFTRESET_N_MSK | ADMV8818_SOFTRESET_MSK);
665	if (ret) {
666		dev_err(&spi->dev, "ADMV8818 Soft Reset failed.\n");
667		return ret;
668	}
669
670	ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
671			   ADMV8818_SDOACTIVE_N_MSK | ADMV8818_SDOACTIVE_MSK);
672	if (ret) {
673		dev_err(&spi->dev, "ADMV8818 SDO Enable failed.\n");
674		return ret;
675	}
676
677	ret = regmap_read(st->regmap, ADMV8818_REG_CHIPTYPE, &chip_id);
678	if (ret) {
679		dev_err(&spi->dev, "ADMV8818 Chip ID read failed.\n");
680		return ret;
681	}
682
683	if (chip_id != 0x1) {
684		dev_err(&spi->dev, "ADMV8818 Invalid Chip ID.\n");
685		return -EINVAL;
686	}
687
688	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_B,
689				 ADMV8818_SINGLE_INSTRUCTION_MSK,
690				 FIELD_PREP(ADMV8818_SINGLE_INSTRUCTION_MSK, 1));
691	if (ret) {
692		dev_err(&spi->dev, "ADMV8818 Single Instruction failed.\n");
693		return ret;
694	}
695
696	if (st->clkin)
697		return admv8818_rfin_band_select(st);
698	else
699		return 0;
700}
701
702static int admv8818_clk_setup(struct admv8818_state *st)
703{
704	struct spi_device *spi = st->spi;
705	int ret;
706
707	st->clkin = devm_clk_get_optional(&spi->dev, "rf_in");
708	if (IS_ERR(st->clkin))
709		return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
710				     "failed to get the input clock\n");
711	else if (!st->clkin)
712		return 0;
713
714	ret = clk_prepare_enable(st->clkin);
715	if (ret)
716		return ret;
717
718	ret = devm_add_action_or_reset(&spi->dev, admv8818_clk_disable, st);
719	if (ret)
720		return ret;
721
722	st->nb.notifier_call = admv8818_freq_change;
723	ret = clk_notifier_register(st->clkin, &st->nb);
724	if (ret < 0)
725		return ret;
726
727	return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);
728}
729
730static int admv8818_read_properties(struct admv8818_state *st)
731{
732	struct spi_device *spi = st->spi;
733	u32 mhz;
734	int ret;
735
736	ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz);
737	if (ret == 0)
738		st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
739	else if (ret == -EINVAL)
740		st->lpf_margin_hz = 0;
741	else
742		return ret;
743
744
745	ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz);
746	if (ret == 0)
747		st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
748	else if (ret == -EINVAL)
749		st->hpf_margin_hz = 0;
750	else if (ret < 0)
751		return ret;
752
753	return 0;
754}
755
756static int admv8818_probe(struct spi_device *spi)
757{
758	struct iio_dev *indio_dev;
759	struct regmap *regmap;
760	struct admv8818_state *st;
761	int ret;
762
763	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
764	if (!indio_dev)
765		return -ENOMEM;
766
767	regmap = devm_regmap_init_spi(spi, &admv8818_regmap_config);
768	if (IS_ERR(regmap))
769		return PTR_ERR(regmap);
770
771	st = iio_priv(indio_dev);
772	st->regmap = regmap;
773
774	indio_dev->info = &admv8818_info;
775	indio_dev->name = "admv8818";
776	indio_dev->channels = admv8818_channels;
777	indio_dev->num_channels = ARRAY_SIZE(admv8818_channels);
778
779	st->spi = spi;
780
781	ret = admv8818_clk_setup(st);
782	if (ret)
783		return ret;
784
785	mutex_init(&st->lock);
786
787	ret = admv8818_read_properties(st);
788	if (ret)
789		return ret;
790
791	ret = admv8818_init(st);
792	if (ret)
793		return ret;
794
795	return devm_iio_device_register(&spi->dev, indio_dev);
796}
797
798static const struct spi_device_id admv8818_id[] = {
799	{ "admv8818", 0 },
800	{ }
801};
802MODULE_DEVICE_TABLE(spi, admv8818_id);
803
804static const struct of_device_id admv8818_of_match[] = {
805	{ .compatible = "adi,admv8818" },
806	{ }
807};
808MODULE_DEVICE_TABLE(of, admv8818_of_match);
809
810static struct spi_driver admv8818_driver = {
811	.driver = {
812		.name = "admv8818",
813		.of_match_table = admv8818_of_match,
814	},
815	.probe = admv8818_probe,
816	.id_table = admv8818_id,
817};
818module_spi_driver(admv8818_driver);
819
820MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
821MODULE_DESCRIPTION("Analog Devices ADMV8818");
822MODULE_LICENSE("GPL v2");
~/ Read-only file preview.