1 /*
2  * Copyright (C) 2016 Analog Devices, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  */
14 
15 #include "ad9361.h"
16 
17 #include <errno.h>
18 #include <iio.h>
19 #include <stdio.h>
20 #ifdef _WIN32
21 #include <windows.h>
22 #else
23 #include <unistd.h>
24 #endif
25 
26 #ifdef _MSC_BUILD
27 #define snprintf sprintf_s
28 #endif
29 
30 static int16_t fir_128_4[] = {
31 	-15,-27,-23,-6,17,33,31,9,-23,-47,-45,-13,34,69,67,21,-49,-102,-99,-32,69,146,143,48,-96,-204,-200,-69,129,278,275,97,-170,
32 	-372,-371,-135,222,494,497,187,-288,-654,-665,-258,376,875,902,363,-500,-1201,-1265,-530,699,1748,1906,845,-1089,-2922,-3424,
33 	-1697,2326,7714,12821,15921,15921,12821,7714,2326,-1697,-3424,-2922,-1089,845,1906,1748,699,-530,-1265,-1201,-500,363,902,875,
34 	376,-258,-665,-654,-288,187,497,494,222,-135,-371,-372,-170,97,275,278,129,-69,-200,-204,-96,48,143,146,69,-32,-99,-102,-49,21,
35 	67,69,34,-13,-45,-47,-23,9,31,33,17,-6,-23,-27,-15};
36 
37 static int16_t fir_128_2[] = {
38 	-0,0,1,-0,-2,0,3,-0,-5,0,8,-0,-11,0,17,-0,-24,0,33,-0,-45,0,61,-0,-80,0,104,-0,-134,0,169,-0,
39 	-213,0,264,-0,-327,0,401,-0,-489,0,595,-0,-724,0,880,-0,-1075,0,1323,-0,-1652,0,2114,-0,-2819,0,4056,-0,-6883,0,20837,32767,
40 	20837,0,-6883,-0,4056,0,-2819,-0,2114,0,-1652,-0,1323,0,-1075,-0,880,0,-724,-0,595,0,-489,-0,401,0,-327,-0,264,0,-213,-0,
41 	169,0,-134,-0,104,0,-80,-0,61,0,-45,-0,33,0,-24,-0,17,0,-11,-0,8,0,-5,-0,3,0,-2,-0,1,0,-0, 0 };
42 
43 static int16_t fir_96_2[] = {
44 	-4,0,8,-0,-14,0,23,-0,-36,0,52,-0,-75,0,104,-0,-140,0,186,-0,-243,0,314,-0,-400,0,505,-0,-634,0,793,-0,
45 	-993,0,1247,-0,-1585,0,2056,-0,-2773,0,4022,-0,-6862,0,20830,32767,20830,0,-6862,-0,4022,0,-2773,-0,2056,0,-1585,-0,1247,0,-993,-0,
46 	793,0,-634,-0,505,0,-400,-0,314,0,-243,-0,186,0,-140,-0,104,0,-75,-0,52,0,-36,-0,23,0,-14,-0,8,0,-4,0};
47 
48 static int16_t fir_64_2[] = {
49 	-58,0,83,-0,-127,0,185,-0,-262,0,361,-0,-488,0,648,-0,-853,0,1117,-0,-1466,0,1954,-0,-2689,0,3960,-0,-6825,0,20818,32767,
50 	20818,0,-6825,-0,3960,0,-2689,-0,1954,0,-1466,-0,1117,0,-853,-0,648,0,-488,-0,361,0,-262,-0,185,0,-127,-0,83,0,-58,0};
51 
52 #define FIR_BUF_SIZE	8192
53 
ad9361_set_trx_fir_enable(struct iio_device * dev,int enable)54 int ad9361_set_trx_fir_enable(struct iio_device *dev, int enable)
55 {
56 	int ret = iio_device_attr_write_bool(dev,
57 					 "in_out_voltage_filter_fir_en", !!enable);
58 	if (ret < 0)
59 		ret = iio_channel_attr_write_bool(iio_device_find_channel(dev, "out", false),
60 					    "voltage_filter_fir_en", !!enable);
61 	return ret;
62 }
63 
ad9361_get_trx_fir_enable(struct iio_device * dev,int * enable)64 int ad9361_get_trx_fir_enable(struct iio_device *dev, int *enable)
65 {
66 	bool value;
67 
68 	int ret = iio_device_attr_read_bool(dev, "in_out_voltage_filter_fir_en", &value);
69 
70 	if (ret < 0)
71 		ret = iio_channel_attr_read_bool(iio_device_find_channel(dev, "out", false),
72 						 "voltage_filter_fir_en", &value);
73 
74 	if (!ret)
75 		*enable	= value;
76 
77 	return ret;
78 }
79 
ad9361_set_bb_rate(struct iio_device * dev,unsigned long rate)80 int ad9361_set_bb_rate(struct iio_device *dev, unsigned long rate)
81 {
82 	struct iio_channel *chan;
83 	long long current_rate;
84 	int dec, taps, ret, i, enable, len = 0;
85 	int16_t *fir;
86 	char *buf;
87 
88 	if (rate <= 20000000UL) {
89 		dec = 4;
90 		taps = 128;
91 		fir = fir_128_4;
92 	} else if (rate <= 40000000UL) {
93 		dec = 2;
94 		fir = fir_128_2;
95 		taps = 128;
96 	} else if (rate <= 53333333UL) {
97 		dec = 2;
98 		fir = fir_96_2;
99 		taps = 96;
100 	} else {
101 		dec = 2;
102 		fir = fir_64_2;
103 		taps = 64;
104 	}
105 
106 	chan = iio_device_find_channel(dev, "voltage0", true);
107 	if (chan == NULL)
108 		return -ENODEV;
109 
110 	ret = iio_channel_attr_read_longlong(chan, "sampling_frequency", &current_rate);
111 	if (ret < 0)
112 		return ret;
113 
114 	ret = ad9361_get_trx_fir_enable(dev, &enable);
115 	if (ret < 0)
116 		return ret;
117 
118 	if (enable) {
119 		if (current_rate <= (25000000 / 12))
120 			iio_channel_attr_write_longlong(chan, "sampling_frequency", 3000000);
121 
122 		ret = ad9361_set_trx_fir_enable(dev, false);
123 		if (ret < 0)
124 			return ret;
125 	}
126 
127 	buf = malloc(FIR_BUF_SIZE);
128 	if (!buf)
129 		return -ENOMEM;
130 
131 	len += snprintf(buf + len, FIR_BUF_SIZE - len, "RX 3 GAIN -6 DEC %d\n", dec);
132 	len += snprintf(buf + len, FIR_BUF_SIZE - len, "TX 3 GAIN 0 INT %d\n", dec);
133 
134 	for (i = 0; i < taps; i++)
135 		len += snprintf(buf + len, FIR_BUF_SIZE - len, "%d,%d\n", fir[i], fir[i]);
136 
137 	len += snprintf(buf + len, FIR_BUF_SIZE - len, "\n");
138 
139 	ret = iio_device_attr_write_raw(dev, "filter_fir_config", buf, len);
140 	free (buf);
141 
142 	if (ret < 0)
143 		return ret;
144 
145 	if (rate <= (25000000 / 12))  {
146 		int dacrate, txrate, max;
147 		char readbuf[100];
148 
149 		ret = iio_device_attr_read(dev, "tx_path_rates", readbuf, sizeof(readbuf));
150 		if (ret < 0)
151 			return ret;
152 		ret = sscanf(readbuf, "BBPLL:%*d DAC:%d T2:%*d T1:%*d TF:%*d TXSAMP:%d", &dacrate, &txrate);
153 		if (ret != 2)
154 			return -EFAULT;
155 
156 		if (txrate == 0)
157 			return -EINVAL;
158 
159 		max = (dacrate / txrate) * 16;
160 		if (max < taps)
161 			iio_channel_attr_write_longlong(chan, "sampling_frequency", 3000000);
162 
163 		ret = ad9361_set_trx_fir_enable(dev, true);
164 		if (ret < 0)
165 			return ret;
166 		ret = iio_channel_attr_write_longlong(chan, "sampling_frequency", rate);
167 		if (ret < 0)
168 			return ret;
169 	} else {
170 		ret = iio_channel_attr_write_longlong(chan, "sampling_frequency", rate);
171 		if (ret < 0)
172 			return ret;
173 		ret = ad9361_set_trx_fir_enable(dev, true);
174 		if (ret < 0)
175 			return ret;
176 	}
177 
178 	return 0;
179 }
180